1 /*############################################################################ 2 # Copyright 2016-2017 Intel Corporation 3 # 4 # Licensed under the Apache License, Version 2.0 (the "License"); 5 # you may not use this file except in compliance with the License. 6 # You may obtain a copy of the License at 7 # 8 # http://www.apache.org/licenses/LICENSE-2.0 9 # 10 # Unless required by applicable law or agreed to in writing, software 11 # distributed under the License is distributed on an "AS IS" BASIS, 12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 # See the License for the specific language governing permissions and 14 # limitations under the License. 15 ############################################################################*/ 16 17 /*! 18 * \file 19 * 20 * \brief Create private key revocation list request 21 * 22 */ 23 24 #include <argtable3.h> 25 #include <stdlib.h> 26 #include <string.h> 27 28 #include "epid/common/file_parser.h" 29 #include "epid/member/api.h" 30 #include "util/buffutil.h" 31 #include "util/envutil.h" 32 #include "util/stdtypes.h" 33 34 const OctStr16 kEpidFileVersion = {2, 0}; 35 36 // Defaults 37 #define PROGRAM_NAME "revokekey" 38 #define PRIVKEY_DEFAULT "mprivkey.dat" 39 #define REQFILE_DEFAULT "privreq.dat" 40 #define PUBKEYFILE_DEFAULT "pubkey.bin" 41 #define ARGPARSE_ERROR_MAX 20 42 #define ARGTABLE_SIZE 8 43 44 /// Partial signature request, includes all but message. 45 typedef struct PrivRlRequestTop { 46 EpidFileHeader header; ///< Intel(R) EPID File Header 47 PrivKey privkey; ///< Intel(R) EPID Private Key 48 } PrivRlRequestTop; 49 50 int OpenKey(char const* privkey_file, char const* gpubkey_file, 51 char const* cacert_file, PrivKey* priv_key) { 52 int retval = EXIT_FAILURE; 53 size_t file_size = GetFileSize(privkey_file); 54 55 if (0 == file_size && !FileExists(privkey_file)) { 56 log_error("cannot access '%s'", privkey_file); 57 return EXIT_FAILURE; 58 } 59 60 if (file_size == sizeof(PrivKey)) { 61 if (0 != ReadLoud(privkey_file, priv_key, sizeof(PrivKey))) { 62 return EXIT_FAILURE; 63 } 64 retval = EXIT_SUCCESS; 65 } else if (file_size == sizeof(CompressedPrivKey)) { 66 void* signed_pubkey = NULL; 67 if (!cacert_file) { 68 log_error("issuing CA public key must be specified for compressed key"); 69 return EXIT_FAILURE; 70 } 71 if (!gpubkey_file) { 72 log_error("group public key must be specified for compressed key"); 73 return EXIT_FAILURE; 74 } 75 76 do { 77 size_t signed_pubkey_size = 0; 78 CompressedPrivKey cmp_key; 79 EpidCaCertificate cacert; 80 GroupPubKey pub_key; 81 EpidStatus sts; 82 if (0 != ReadLoud(privkey_file, &cmp_key, sizeof(CompressedPrivKey))) { 83 retval = EXIT_FAILURE; 84 break; 85 } 86 signed_pubkey = NewBufferFromFile(gpubkey_file, &signed_pubkey_size); 87 if (!signed_pubkey) { 88 retval = EXIT_FAILURE; 89 break; 90 } 91 if (0 != ReadLoud(gpubkey_file, signed_pubkey, signed_pubkey_size)) { 92 retval = EXIT_FAILURE; 93 break; 94 } 95 if (0 != ReadLoud(cacert_file, &cacert, sizeof(cacert))) { 96 retval = EXIT_FAILURE; 97 break; 98 } 99 sts = EpidParseGroupPubKeyFile(signed_pubkey, signed_pubkey_size, &cacert, 100 &pub_key); 101 if (kEpidNoErr != sts) { 102 log_error("error while parsing group public key"); 103 retval = EXIT_FAILURE; 104 break; 105 } 106 sts = EpidDecompressPrivKey(&pub_key, &cmp_key, priv_key); 107 if (kEpidNoErr != sts) { 108 log_error("error while decompressing member private key"); 109 retval = EXIT_FAILURE; 110 break; 111 } 112 retval = EXIT_SUCCESS; 113 } while (0); 114 free(signed_pubkey); 115 } else { 116 log_error("unexpected file size for '%s'", privkey_file); 117 retval = EXIT_FAILURE; 118 } 119 return retval; 120 } 121 122 int MakeRequest(PrivKey const* priv_key, char const* req_file, bool verbose) { 123 // Request buffer 124 uint8_t* req_buf = NULL; 125 size_t req_size = 0; 126 size_t req_extra_space = 0; 127 int ret_value = EXIT_FAILURE; 128 do { 129 size_t entry_size = sizeof(EpidFileHeader) + sizeof(PrivKey); 130 size_t req_file_size = 0; 131 bool duplicate = false; 132 size_t i = 0; 133 PrivRlRequestTop* req_top = NULL; 134 135 if (!req_file) { 136 log_error("internal error: badarg to MakeRequest()"); 137 ret_value = EXIT_FAILURE; 138 break; 139 } 140 141 // convert command line args to usable formats 142 143 // Report Settings 144 if (verbose) { 145 log_msg("=============================================="); 146 log_msg("Input settings:"); 147 log_msg(""); 148 log_msg(" [in] Group ID: "); 149 PrintBuffer(&(priv_key->gid), sizeof(priv_key->gid)); 150 log_msg(""); 151 log_msg(" [in] Private Key Len: %d", sizeof(PrivKey)); 152 log_msg(" [in] Private Key: "); 153 PrintBuffer(priv_key, sizeof(PrivKey)); 154 log_msg(""); 155 log_msg("=============================================="); 156 } 157 158 req_extra_space += entry_size; 159 if (FileExists(req_file)) { 160 req_file_size = GetFileSize_S(req_file, SIZE_MAX - req_extra_space); 161 162 if (req_file_size < entry_size) { 163 log_error("output file smaller then size of one entry"); 164 ret_value = EXIT_FAILURE; 165 break; 166 } 167 168 if (req_file_size % entry_size != 0) { 169 log_error("size of output file is not multiple of the entry size"); 170 ret_value = EXIT_FAILURE; 171 break; 172 } 173 } else { 174 log_msg("request file does not exsist, create new"); 175 } 176 177 req_size = req_file_size + req_extra_space; 178 179 req_buf = AllocBuffer(req_size); 180 if (!req_buf) { 181 ret_value = EXIT_FAILURE; 182 break; 183 } 184 185 // Load existing request file 186 if (req_file_size > 0) { 187 if (0 != ReadLoud(req_file, req_buf, req_file_size)) { 188 ret_value = EXIT_FAILURE; 189 break; 190 } 191 192 for (i = 0; i < req_file_size / entry_size; i++) { 193 if (0 == memcmp(req_buf + entry_size * i + sizeof(EpidFileHeader), 194 priv_key, sizeof(PrivKey))) { 195 duplicate = true; 196 break; 197 } 198 } 199 if (duplicate) { 200 log_error("this private key already exists in output file"); 201 ret_value = EXIT_FAILURE; 202 break; 203 } 204 } 205 206 // Append to the request 207 req_top = (PrivRlRequestTop*)(req_buf + req_file_size); 208 req_top->header.epid_version = kEpidFileVersion; 209 req_top->header.file_type = kEpidFileTypeCode[kPrivRlRequestFile]; 210 req_top->privkey = *priv_key; 211 212 // Report Settings 213 if (verbose) { 214 log_msg("=============================================="); 215 log_msg("Request generated:"); 216 log_msg(""); 217 log_msg(" [in] Request Len: %d", sizeof(PrivRlRequestTop)); 218 log_msg(" [in] Request: "); 219 PrintBuffer(req_top, sizeof(PrivRlRequestTop)); 220 log_msg("=============================================="); 221 } 222 223 // Store request 224 if (0 != WriteLoud(req_buf, req_size, req_file)) { 225 ret_value = EXIT_FAILURE; 226 break; 227 } 228 229 ret_value = EXIT_SUCCESS; 230 } while (0); 231 232 // Free allocated buffers 233 if (req_buf) free(req_buf); 234 235 return ret_value; 236 } 237 238 /// Main entrypoint 239 int main(int argc, char* argv[]) { 240 int retval = EXIT_FAILURE; 241 242 // Verbose flag parameter 243 static bool verbose_flag = false; 244 245 // Private key 246 PrivKey priv_key; 247 248 struct arg_file* privkey_file = arg_file0( 249 NULL, "mprivkey", "FILE", 250 "load private key to revoke from FILE (default: " PRIVKEY_DEFAULT ")"); 251 struct arg_file* req_file = arg_file0( 252 NULL, "req", "FILE", 253 "append signature revocation request to FILE (default: " REQFILE_DEFAULT 254 ")"); 255 struct arg_lit* help = arg_lit0(NULL, "help", "display this help and exit"); 256 struct arg_lit* verbose = 257 arg_lit0("v", "verbose", "print status messages to stdout"); 258 struct arg_rem* comment_line = arg_rem( 259 NULL, "The following options are only needed for compressed keys:"); 260 struct arg_file* gpubkey_file = arg_file0( 261 NULL, "gpubkey", "FILE", 262 "load group public key from FILE (default: " PUBKEYFILE_DEFAULT ")"); 263 struct arg_file* capubkey_file = arg_file0( 264 NULL, "capubkey", "FILE", "load IoT Issuing CA public key from FILE"); 265 struct arg_end* end = arg_end(ARGPARSE_ERROR_MAX); 266 void* argtable[ARGTABLE_SIZE]; 267 int nerrors; 268 269 /* initialize the argtable array with ptrs to the arg_xxx structures 270 * constructed above */ 271 argtable[0] = privkey_file; 272 argtable[1] = req_file; 273 argtable[2] = help; 274 argtable[3] = verbose; 275 argtable[4] = comment_line; 276 argtable[5] = gpubkey_file; 277 argtable[6] = capubkey_file; 278 argtable[7] = end; 279 280 // set program name for logging 281 set_prog_name(PROGRAM_NAME); 282 do { 283 /* verify the argtable[] entries were allocated sucessfully */ 284 if (arg_nullcheck(argtable) != 0) { 285 /* NULL entries were detected, some allocations must have failed */ 286 printf("%s: insufficient memory\n", PROGRAM_NAME); 287 retval = EXIT_FAILURE; 288 break; 289 } 290 291 /* set any command line default values prior to parsing */ 292 privkey_file->filename[0] = PRIVKEY_DEFAULT; 293 gpubkey_file->filename[0] = PUBKEYFILE_DEFAULT; 294 req_file->filename[0] = REQFILE_DEFAULT; 295 capubkey_file->filename[0] = NULL; 296 297 /* Parse the command line as defined by argtable[] */ 298 nerrors = arg_parse(argc, argv, argtable); 299 300 if (help->count > 0) { 301 log_fmt( 302 "Usage: %s [OPTION]...\n" 303 "Revoke Intel(R) EPID signature\n" 304 "\n" 305 "Options:\n", 306 PROGRAM_NAME); 307 arg_print_glossary(stdout, argtable, " %-25s %s\n"); 308 retval = EXIT_SUCCESS; 309 break; 310 } 311 if (verbose->count > 0) { 312 verbose_flag = ToggleVerbosity(); 313 } 314 /* If the parser returned any errors then display them and exit */ 315 if (nerrors > 0) { 316 /* Display the error details contained in the arg_end struct.*/ 317 arg_print_errors(stderr, end, PROGRAM_NAME); 318 fprintf(stderr, "Try '%s --help' for more information.\n", PROGRAM_NAME); 319 retval = EXIT_FAILURE; 320 break; 321 } 322 if (verbose_flag) { 323 log_msg("\nOption values:"); 324 log_msg(" mprivkey : %s", privkey_file->filename[0]); 325 log_msg(" req : %s", req_file->filename[0]); 326 log_msg(" gpubkey : %s", gpubkey_file->filename[0]); 327 log_msg(" capubkey : %s", capubkey_file->filename[0]); 328 log_msg(""); 329 } 330 331 retval = OpenKey(privkey_file->filename[0], gpubkey_file->filename[0], 332 capubkey_file->filename[0], &priv_key); 333 if (EXIT_SUCCESS != retval) { 334 break; 335 } 336 retval = MakeRequest(&priv_key, req_file->filename[0], verbose_flag); 337 } while (0); 338 339 arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0])); 340 341 return retval; 342 } 343