• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 Extract member private keys from key output file
21  *
22  * Not validating SHA hashes in key file
23  */
24 
25 #include <stdio.h>
26 #include <stdlib.h>
27 
28 #include <argtable3.h>
29 #include "epid/common/types.h"
30 #include "util/buffutil.h"
31 #include "util/envutil.h"
32 #include "util/stdtypes.h"
33 #include "util/strutil.h"
34 
35 #define PROGRAM_NAME "extractkeys"
36 #define ARGPARSE_ERROR_MAX 20
37 #define ARGTABLE_SIZE 6
38 
39 #pragma pack(1)
40 /// Intel(R) EPID Key Output File Entry
41 typedef struct EpidKeyOutputFileKey {
42   unsigned char product_id[2];  ///< 2-byte Product ID (Big Endian)
43   unsigned char key_id[8];      ///< 8-byte Key Unique Id(Big Endian)
44   unsigned char svn[4];  ///< 4-byte Security Version Number (SVN) (Big Endian)
45   PrivKey privkey;       ///< Intel(R) EPID 2.0 Private Key
46   unsigned char hash[20];  ///< 20-byte SHA-1 of above
47 } EpidKeyOutputFileKey;
48 
49 /// Intel(R) EPID Compressed Key Output File Entry
50 typedef struct EpidCompressedKeyOutputFileKey {
51   unsigned char product_id[2];  ///< 2-byte Product ID (Big Endian)
52   unsigned char key_id[8];      ///< 8-byte Key Unique Id(Big Endian)
53   unsigned char svn[4];  ///< 4-byte Security Version Number (SVN) (Big Endian)
54   CompressedPrivKey privkey;  ///< Intel(R) EPID 2.0 Compressed Private Key
55   unsigned char hash[20];     ///< 20-byte SHA-1 of above
56 } EpidCompressedKeyOutputFileKey;
57 #pragma pack()
58 
59 /// Main entrypoint
main(int argc,char * argv[])60 int main(int argc, char* argv[]) {
61   // intermediate return value for C style functions
62   int ret_value = EXIT_SUCCESS;
63   // Buffer to store read key
64   uint8_t temp[sizeof(EpidKeyOutputFileKey)] = {0};
65 
66   // Private key to extract
67   void* privkey = 0;
68   size_t privkey_size = 0;
69 
70   size_t keyfile_size = 0;
71   size_t keyfile_entry_size = 0;
72   size_t num_keys_extracted = 0;
73   size_t num_keys_in_file = 0;
74 
75   FILE* file = NULL;
76 
77   // Verbose flag parameter
78   static bool verbose_flag = false;
79 
80   int i = 0;
81   size_t bytes_read = 0;
82 
83   struct arg_file* keyfile =
84       arg_file1(NULL, NULL, "FILE", "FILE containing keys to extract");
85   struct arg_int* num_keys_to_extract =
86       arg_int1(NULL, NULL, "NUM", "number of keys to extract");
87   struct arg_lit* compressed =
88       arg_lit0("c", "compressed", "extract compressed keys");
89   struct arg_lit* help = arg_lit0(NULL, "help", "display this help and exit");
90   struct arg_lit* verbose =
91       arg_lit0("v", "verbose", "print status messages to stdout");
92   struct arg_end* end = arg_end(ARGPARSE_ERROR_MAX);
93   void* argtable[ARGTABLE_SIZE];
94   int nerrors;
95 
96   /* initialize the argtable array with ptrs to the arg_xxx structures
97    * constructed above */
98   argtable[0] = keyfile;
99   argtable[1] = num_keys_to_extract;
100   argtable[2] = compressed;
101   argtable[3] = help;
102   argtable[4] = verbose;
103   argtable[5] = end;
104 
105   // set program name for logging
106   set_prog_name(PROGRAM_NAME);
107   do {
108     /* verify the argtable[] entries were allocated sucessfully */
109     if (arg_nullcheck(argtable) != 0) {
110       /* NULL entries were detected, some allocations must have failed */
111       printf("%s: insufficient memory\n", PROGRAM_NAME);
112       ret_value = EXIT_FAILURE;
113       break;
114     }
115 
116     /* Parse the command line as defined by argtable[] */
117     nerrors = arg_parse(argc, argv, argtable);
118 
119     if (help->count > 0) {
120       log_fmt(
121           "Usage: %s [OPTION]... [FILE] [NUM]\n"
122           "Extract the first NUM private keys from FILE to current "
123           "directory.\n"
124           "\n"
125           "Options:\n",
126           PROGRAM_NAME);
127       arg_print_glossary(stdout, argtable, "  %-25s %s\n");
128       ret_value = EXIT_SUCCESS;
129       break;
130     }
131     if (verbose->count > 0) {
132       verbose_flag = ToggleVerbosity();
133     }
134     /* If the parser returned any errors then display them and exit */
135     if (nerrors > 0) {
136       /* Display the error details contained in the arg_end struct.*/
137       arg_print_errors(stderr, end, PROGRAM_NAME);
138       fprintf(stderr, "Try '%s --help' for more information.\n", PROGRAM_NAME);
139       ret_value = EXIT_FAILURE;
140       break;
141     }
142 
143     if (num_keys_to_extract->ival[0] < 0) {
144       log_error("unable extract negative number of keys");
145       ret_value = EXIT_FAILURE;
146       break;
147     }
148 
149     // check file existence
150     if (!FileExists(keyfile->filename[0])) {
151       log_error("cannot access '%s'", keyfile->filename[0]);
152       ret_value = EXIT_FAILURE;
153       break;
154     }
155 
156     keyfile_size = GetFileSize(keyfile->filename[0]);
157     if (compressed->count > 0) {
158       privkey_size = sizeof(CompressedPrivKey);
159       privkey = &(((EpidCompressedKeyOutputFileKey*)&temp[0])->privkey);
160       keyfile_entry_size = sizeof(EpidCompressedKeyOutputFileKey);
161     } else {
162       privkey_size = sizeof(PrivKey);
163       privkey = &(((EpidKeyOutputFileKey*)&temp[0])->privkey);
164       keyfile_entry_size = sizeof(EpidKeyOutputFileKey);
165     }
166 
167     if (0 != keyfile_size % keyfile_entry_size) {
168       log_error(
169           "input file '%s' is invalid: does not contain integral number of "
170           "keys",
171           keyfile->filename[0]);
172       ret_value = EXIT_FAILURE;
173       break;
174     }
175     num_keys_in_file = keyfile_size / keyfile_entry_size;
176 
177     if ((unsigned int)num_keys_to_extract->ival[0] > num_keys_in_file) {
178       log_error("can not extract %d keys: only %d in file",
179                 num_keys_to_extract->ival[0], num_keys_in_file);
180       ret_value = EXIT_FAILURE;
181       break;
182     }
183 
184     file = fopen(keyfile->filename[0], "rb");
185     if (!file) {
186       log_error("failed read from '%s'", keyfile->filename[0]);
187 
188       ret_value = EXIT_FAILURE;
189       break;
190     }
191 
192     // start extraction
193     for (i = 0; i < num_keys_to_extract->ival[0]; ++i) {
194       int seek_failed = 0;
195       seek_failed = fseek(file, (int)(i * keyfile_entry_size), SEEK_SET);
196       bytes_read = fread(&temp, 1, keyfile_entry_size, file);
197       if (seek_failed || bytes_read != keyfile_entry_size) {
198         log_error("failed to extract key #%lu from '%s'", i,
199                   keyfile->filename[0]);
200       } else {
201         char outkeyname[256] = {0};
202         snprintf(outkeyname, sizeof(outkeyname), "mprivkey%010u.dat", i);
203 
204         if (FileExists(outkeyname)) {
205           log_error("file '%s' already exists", outkeyname);
206           ret_value = EXIT_FAILURE;
207           break;
208         }
209         if (0 != WriteLoud(privkey, privkey_size, outkeyname)) {
210           log_error("failed to write key #%lu from '%s'", i,
211                     keyfile->filename[0]);
212         } else {
213           num_keys_extracted++;
214         }
215       }
216     }
217     if (EXIT_FAILURE == ret_value) {
218       break;
219     }
220 
221     log_msg("extracted %lu of %lu keys", num_keys_extracted, num_keys_in_file);
222   } while (0);
223 
224   if (file) {
225     fclose(file);
226     file = NULL;
227   }
228 
229   arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
230 
231   return ret_value;
232 }
233