• 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 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 
OpenKey(char const * privkey_file,char const * gpubkey_file,char const * cacert_file,PrivKey * priv_key)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 
MakeRequest(PrivKey const * priv_key,char const * req_file,bool verbose)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
main(int argc,char * argv[])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