• 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 signature based revocation list request
21  *
22  */
23 
24 #include <argtable3.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include "epid/common/file_parser.h"
28 #include "util/buffutil.h"
29 #include "util/envutil.h"
30 #include "util/stdtypes.h"
31 
32 // Defaults
33 #define PROGRAM_NAME "revokesig"
34 #define PUBKEYFILE_DEFAULT "pubkey.bin"
35 #define REQFILE_DEFAULT "sigrlreq.dat"
36 #define SIG_DEFAULT "sig.dat"
37 #define GROUP_PUB_KEY_SIZE \
38   (sizeof(EpidFileHeader) + sizeof(GroupPubKey) + sizeof(EcdsaSignature))
39 #define ARGPARSE_ERROR_MAX 20
40 #define ARGTABLE_SIZE 9
41 
42 #pragma pack(1)
43 /// Partial signature request, includes components through sig.
44 typedef struct SigRlRequestTop {
45   EpidFileHeader header;  ///< Intel(R) EPID File Header
46   GroupId gid;            ///< Intel(R) EPID Group ID
47   EpidSignature sig;      ///< Intel(R) EPID Signature
48 } SigRlRequestTop;
49 
50 /// Partial signature request, includes components after.
51 typedef struct SigRlRequestMid {
52   uint32_t be_msg_size;  ///< size of message in bytes (big endian)
53   uint8_t msg[1];        ///< message used to create signature (flexible array)
54 } SigRlRequestMid;
55 #pragma pack()
56 
57 /// convert host to network byte order
htonl(uint32_t hostlong)58 static uint32_t htonl(uint32_t hostlong) {
59   return (((hostlong & 0xFF) << 24) | ((hostlong & 0xFF00) << 8) |
60           ((hostlong & 0xFF0000) >> 8) | ((hostlong & 0xFF000000) >> 24));
61 }
62 
63 /// Fill a single SigRlRequest structure
64 /*!
65 \param[in] pubkey
66 Group public key.
67 \param[in] sig
68 Signature to append to request.
69 \param[in] sig_size
70 Size of the signature.
71 \param[in] msg_str
72 Message used to generate signature to revoke.
73 \param[in] msg_size
74 Length of the message.
75 \param[in out] req_buf
76 Pointer to request buffer.
77 \param[in] req_size
78 Size of request buffer.
79 \param[in out] req_top
80 Pointer to top structure of request.
81 */
82 void FillRequest(GroupPubKey const* pubkey, EpidSignature const* sig,
83                  size_t sig_size, char const* msg_str, size_t msg_size,
84                  uint8_t* req_buf, size_t req_size, SigRlRequestTop* req_top);
85 
86 /// Makes a request and appends it to file.
87 /*!
88 \param[in] cacert_file
89 Issuing CA certificate used to sign group public key file.
90 \param[in] sig_file
91 File containing signature to add to request.
92 \param[in] pubkey_file
93 File containing group public key.
94 \param[in] req_file
95 File to write a request.
96 \param[in] msg_str
97 Message used to generate signature to revoke.
98 \param[in] msg_size
99 Length of the message.
100 \param[in] verbose
101 If true function would print debug information to stdout.
102 */
103 int MakeRequest(char const* cacert_file, char const* sig_file,
104                 char const* pubkey_file, char const* req_file,
105                 char const* msg_str, size_t msg_size, bool verbose);
106 
107 /// Main entrypoint
main(int argc,char * argv[])108 int main(int argc, char* argv[]) {
109   // intermediate return value for C style functions
110   int ret_value = EXIT_FAILURE;
111 
112   // Message string parameter
113   static char* msg_str = NULL;
114   size_t msg_size = 0;
115   char* msg_buf = NULL;  // message loaded from msg_file
116 
117   // Verbose flag parameter
118   static bool verbose_flag = false;
119 
120   struct arg_file* sig_file = arg_file0(
121       NULL, "sig", "FILE",
122       "load signature to revoke from FILE (default: " SIG_DEFAULT ")");
123   struct arg_str* msg =
124       arg_str0(NULL, "msg", "MESSAGE",
125                "MESSAGE used to generate signature to revoke (default: empty)");
126   struct arg_file* msg_file =
127       arg_file0(NULL, "msgfile", "FILE",
128                 "FILE containing message used to generate signature to revoke");
129   struct arg_file* pubkey_file = arg_file0(
130       NULL, "gpubkey", "FILE",
131       "load group public key from FILE (default: " PUBKEYFILE_DEFAULT ")");
132   struct arg_file* cacert_file = arg_file1(
133       NULL, "capubkey", "FILE", "load IoT Issuing CA public key from FILE");
134   struct arg_file* req_file = arg_file0(
135       NULL, "req", "FILE",
136       "append signature revocation request to FILE (default: " REQFILE_DEFAULT
137       ")");
138   struct arg_lit* help = arg_lit0(NULL, "help", "display this help and exit");
139   struct arg_lit* verbose =
140       arg_lit0("v", "verbose", "print status messages to stdout");
141   struct arg_end* end = arg_end(ARGPARSE_ERROR_MAX);
142   void* argtable[ARGTABLE_SIZE];
143   int nerrors;
144 
145   /* initialize the argtable array with ptrs to the arg_xxx structures
146    * constructed above */
147   argtable[0] = sig_file;
148   argtable[1] = msg;
149   argtable[2] = msg_file;
150   argtable[3] = pubkey_file;
151   argtable[4] = cacert_file;
152   argtable[5] = req_file;
153   argtable[6] = help;
154   argtable[7] = verbose;
155   argtable[8] = end;
156 
157   // set program name for logging
158   set_prog_name(PROGRAM_NAME);
159   do {
160     /* verify the argtable[] entries were allocated sucessfully */
161     if (arg_nullcheck(argtable) != 0) {
162       /* NULL entries were detected, some allocations must have failed */
163       printf("%s: insufficient memory\n", PROGRAM_NAME);
164       ret_value = EXIT_FAILURE;
165       break;
166     }
167 
168     /* set any command line default values prior to parsing */
169     sig_file->filename[0] = SIG_DEFAULT;
170     pubkey_file->filename[0] = PUBKEYFILE_DEFAULT;
171     req_file->filename[0] = REQFILE_DEFAULT;
172 
173     /* Parse the command line as defined by argtable[] */
174     nerrors = arg_parse(argc, argv, argtable);
175 
176     if (help->count > 0) {
177       log_fmt(
178           "Usage: %s [OPTION]...\n"
179           "Revoke Intel(R) EPID signature\n"
180           "\n"
181           "Options:\n",
182           PROGRAM_NAME);
183       arg_print_glossary(stdout, argtable, "  %-25s %s\n");
184       ret_value = EXIT_SUCCESS;
185       break;
186     }
187     if (verbose->count > 0) {
188       verbose_flag = ToggleVerbosity();
189     }
190     /* If the parser returned any errors then display them and exit */
191     if (nerrors > 0) {
192       /* Display the error details contained in the arg_end struct.*/
193       arg_print_errors(stderr, end, PROGRAM_NAME);
194       fprintf(stderr, "Try '%s --help' for more information.\n", PROGRAM_NAME);
195       ret_value = EXIT_FAILURE;
196       break;
197     }
198 
199     if (msg->count > 0 && msg_file->count > 0) {
200       log_error("options --msg and --msgfile cannot be used together");
201       ret_value = EXIT_FAILURE;
202       break;
203     } else if (msg->count > 0) {
204       msg_str = (char*)msg->sval[0];
205       msg_size = strlen(msg_str);
206     } else if (msg_file->count > 0) {
207       msg_buf = NewBufferFromFile(msg_file->filename[0], &msg_size);
208       if (!msg_buf) {
209         ret_value = EXIT_FAILURE;
210         break;
211       }
212       msg_str = msg_buf;
213     } else {
214       msg_size = 0;
215     }
216 
217     if (verbose_flag) {
218       log_msg("\nOption values:");
219       log_msg(" sig_file      : %s", sig_file->filename[0]);
220       log_msg(" msg_str       : %s", msg_str);
221       log_msg(" pubkey_file   : %s", pubkey_file->filename[0]);
222       log_msg(" cacert_file   : %s", cacert_file->filename[0]);
223       log_msg(" req_file      : %s", req_file->filename[0]);
224       log_msg("");
225     }
226 
227     ret_value = MakeRequest(cacert_file->filename[0], sig_file->filename[0],
228                             pubkey_file->filename[0], req_file->filename[0],
229                             msg_str, msg_size, verbose_flag);
230   } while (0);
231 
232   if (msg_buf) {
233     free(msg_buf);
234     msg_buf = NULL;
235   }
236 
237   arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
238 
239   return ret_value;
240 }
241 
242 /// Fill a single SigRlRequest structure
243 /*!
244 
245   | Field                           | Size          |
246   |:--------------------------------|--------------:|
247   | Intel(R) EPID Version (0x0200)  |       2 bytes |
248   | File Type (0x000B)              |       2 bytes |
249   | Group ID Number                 |      16 bytes |
250   | Basic Signature                 |      52 bytes |
251   | SigRL Version                   |       4 bytes |
252   | Number of Non-Revoked Proofs    |       4 bytes |
253   | nNRP * Non-Revoked Proofs       |    160 * nNRP |
254   | Message Size in Bytes (msgSize) |       4 bytes |
255   | Message                         | msgSize bytes |
256 
257  */
FillRequest(GroupPubKey const * pubkey,EpidSignature const * sig,size_t sig_size,char const * msg_str,size_t msg_size,uint8_t * req_buf,size_t req_size,SigRlRequestTop * req_top)258 void FillRequest(GroupPubKey const* pubkey, EpidSignature const* sig,
259                  size_t sig_size, char const* msg_str, size_t msg_size,
260                  uint8_t* req_buf, size_t req_size, SigRlRequestTop* req_top) {
261   const OctStr16 kEpidFileVersion = {2, 0};
262   size_t i = 0;
263   size_t req_mid_size = sizeof(((SigRlRequestMid*)0)->be_msg_size) + msg_size;
264   SigRlRequestMid* req_mid =
265       (SigRlRequestMid*)(req_buf + req_size - req_mid_size);
266 
267   if (!pubkey || !sig || !req_buf || !req_top || (!msg_str && 0 != msg_size)) {
268     log_error("internal error: badarg to FillRequest()");
269     return;
270   }
271 
272   req_top->header.epid_version = kEpidFileVersion;
273   req_top->header.file_type = kEpidFileTypeCode[kSigRlRequestFile];
274   req_top->gid = pubkey->gid;
275   // copy signature
276   for (i = 0; i < sig_size; i++) {
277     ((uint8_t*)&req_top->sig)[i] = ((uint8_t*)sig)[i];
278   }
279   req_mid->be_msg_size = htonl((uint32_t)msg_size);
280   // copy msg
281   for (i = 0; i < msg_size; i++) {
282     req_mid->msg[i] = msg_str[i];
283   }
284 }
285 
MakeRequest(char const * cacert_file,char const * sig_file,char const * pubkey_file,char const * req_file,char const * msg_str,size_t msg_size,bool verbose)286 int MakeRequest(char const* cacert_file, char const* sig_file,
287                 char const* pubkey_file, char const* req_file,
288                 char const* msg_str, size_t msg_size, bool verbose) {
289   // Buffers and computed values
290   // Signature buffer
291   EpidSignature* sig = NULL;
292   size_t sig_size = 0;
293 
294   // Group public key file
295   unsigned char* pubkey_file_data = NULL;
296   size_t pubkey_file_size = 0;
297 
298   // CA certificate
299   EpidCaCertificate cacert = {0};
300 
301   // Group public key buffer
302   GroupPubKey pubkey = {0};
303 
304   // Request buffer
305   uint8_t* req_buf = NULL;
306   size_t req_size = 0;
307 
308   size_t req_extra_space = (sizeof(EpidFileHeader) + sizeof(GroupId));
309 
310   int ret_value = EXIT_FAILURE;
311   do {
312     SigRlRequestTop* req_top = NULL;
313     size_t req_file_size = 0;
314     const size_t kMsgSizeSize = sizeof(((SigRlRequestMid*)0)->be_msg_size);
315 
316     if (!cacert_file || !sig_file || !pubkey_file || !req_file ||
317         (!msg_str && 0 != msg_size)) {
318       log_error("internal error: badarg to MakeRequest()");
319       ret_value = EXIT_FAILURE;
320       break;
321     }
322 
323     // convert command line args to usable formats
324     // CA certificate
325     if (0 != ReadLoud(cacert_file, &cacert, sizeof(cacert))) {
326       ret_value = EXIT_FAILURE;
327       break;
328     }
329 
330     // Signature
331     sig = NewBufferFromFile(sig_file, &sig_size);
332     if (!sig) {
333       ret_value = EXIT_FAILURE;
334       break;
335     }
336 
337     // Group public key file
338     pubkey_file_data = NewBufferFromFile(pubkey_file, &pubkey_file_size);
339     if (!pubkey_file_data) {
340       ret_value = EXIT_FAILURE;
341       break;
342     }
343 
344     // Security note:
345     // Application must confirm group public key is
346     // authorized by the issuer, e.g., signed by the issuer.
347     if (GROUP_PUB_KEY_SIZE != pubkey_file_size) {
348       log_error("unexpected file size for '%s'. Expected: %d; got: %d",
349                 pubkey_file, (int)GROUP_PUB_KEY_SIZE, (int)pubkey_file_size);
350       ret_value = EXIT_FAILURE;
351       break;
352     }
353     if (kEpidNoErr != EpidParseGroupPubKeyFile(pubkey_file_data,
354                                                pubkey_file_size, &cacert,
355                                                &pubkey)) {
356       log_error("group public key is not authorized");
357       ret_value = EXIT_FAILURE;
358       break;
359     }
360 
361     // Report Settings
362     if (verbose) {
363       log_msg("==============================================");
364       log_msg("Creating SigRL revocation request:");
365       log_msg("");
366       log_msg(" [in]  Group ID: ");
367       PrintBuffer(&pubkey.gid, sizeof(pubkey.gid));
368       log_msg("");
369       log_msg(" [in]  Signature Len: %d", (int)sig_size);
370       log_msg(" [in]  Signature: ");
371       PrintBuffer(sig, sig_size);
372       log_msg("");
373       log_msg(" [in]  Message Len: %d", (int)msg_size);
374       log_msg(" [in]  Message: ");
375       PrintBuffer(msg_str, msg_size);
376       log_msg("==============================================");
377     }
378 
379     req_extra_space += sig_size + kMsgSizeSize + msg_size;
380 
381     if (FileExists(req_file)) {
382       req_file_size = GetFileSize_S(req_file, SIZE_MAX - req_extra_space);
383     } else {
384       log_msg("request file does not exsist, create new");
385     }
386 
387     req_size = req_file_size + req_extra_space;
388 
389     req_buf = AllocBuffer(req_size);
390     if (!req_buf) {
391       ret_value = EXIT_FAILURE;
392       break;
393     }
394 
395     if (req_file_size > 0) {
396       if (0 != ReadLoud(req_file, req_buf, req_file_size)) {
397         ret_value = EXIT_FAILURE;
398         break;
399       }
400     }
401 
402     req_top = (SigRlRequestTop*)(req_buf + req_file_size);
403 
404     FillRequest(&pubkey, sig, sig_size, msg_str, msg_size, req_buf, req_size,
405                 req_top);
406 
407     // Report Settings
408     if (verbose) {
409       log_msg("==============================================");
410       log_msg("Reqest generated:");
411       log_msg("");
412       log_msg(" [in]  Request Len: %d", sizeof(SigRlRequestTop));
413       log_msg(" [in]  Request: ");
414       PrintBuffer(req_top, sizeof(SigRlRequestTop));
415       log_msg("==============================================");
416     }
417 
418     // Store request
419     if (0 != WriteLoud(req_buf, req_size, req_file)) {
420       ret_value = EXIT_FAILURE;
421       break;
422     }
423 
424     // Success
425     ret_value = EXIT_SUCCESS;
426   } while (0);
427 
428   // Free allocated buffers
429   if (pubkey_file_data) free(pubkey_file_data);
430   if (sig) free(sig);
431   if (req_buf) free(req_buf);
432 
433   return ret_value;
434 }
435