• 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 group keys from group key output file
21  */
22 
23 #include <argtable3.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 
28 #include "epid/common/file_parser.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 "extractgrps"
36 #define ARGPARSE_ERROR_MAX 20
37 #define ARGTABLE_SIZE 5
38 
39 #pragma pack(1)
40 /// Intel(R) EPID Key Output File Entry
41 typedef struct EpidBinaryGroupCertificate {
42   EpidFileHeader header;     ///< Intel(R) EPID binary file header
43   GroupPubKey pubkey;        ///< Intel(R) EPID 2.0 group public key
44   EcdsaSignature signature;  ///< ECDSA Signature on SHA-256 of above values
45 } EpidBinaryGroupCertificate;
46 #pragma pack()
47 
48 /// Main entrypoint
main(int argc,char * argv[])49 int main(int argc, char* argv[]) {
50   // intermediate return value for C style functions
51   int ret_value = EXIT_SUCCESS;
52 
53   size_t keyfile_size = 0;
54   size_t num_keys_extracted = 0;
55   size_t num_keys_in_file = 0;
56 
57   FILE* file = NULL;
58 
59   int i = 0;
60   size_t bytes_read = 0;
61 
62   // Verbose flag parameter
63   static bool verbose_flag = false;
64 
65   struct arg_file* keyfile =
66       arg_file1(NULL, NULL, "FILE", "FILE containing keys to extract");
67   struct arg_int* num_keys_to_extract =
68       arg_int1(NULL, NULL, "NUM", "number of keys to extract");
69   struct arg_lit* help = arg_lit0(NULL, "help", "display this help and exit");
70   struct arg_lit* verbose =
71       arg_lit0("v", "verbose", "print status messages to stdout");
72   struct arg_end* end = arg_end(ARGPARSE_ERROR_MAX);
73   void* argtable[ARGTABLE_SIZE];
74   int nerrors;
75 
76   /* initialize the argtable array with ptrs to the arg_xxx structures
77    * constructed above */
78   argtable[0] = keyfile;
79   argtable[1] = num_keys_to_extract;
80   argtable[2] = help;
81   argtable[3] = verbose;
82   argtable[4] = end;
83 
84   // set program name for logging
85   set_prog_name(PROGRAM_NAME);
86   do {
87     /* verify the argtable[] entries were allocated sucessfully */
88     if (arg_nullcheck(argtable) != 0) {
89       /* NULL entries were detected, some allocations must have failed */
90       printf("%s: insufficient memory\n", PROGRAM_NAME);
91       ret_value = EXIT_FAILURE;
92       break;
93     }
94 
95     /* Parse the command line as defined by argtable[] */
96     nerrors = arg_parse(argc, argv, argtable);
97 
98     if (help->count > 0) {
99       log_fmt(
100           "Usage: %s [OPTION]... [FILE] [NUM]\n"
101           "Extract the first NUM group certs from FILE to current "
102           "directory\n"
103           "\n"
104           "Options:\n",
105           PROGRAM_NAME);
106       arg_print_glossary(stdout, argtable, "  %-25s %s\n");
107       ret_value = EXIT_SUCCESS;
108       break;
109     }
110     if (verbose->count > 0) {
111       verbose_flag = ToggleVerbosity();
112     }
113     /* If the parser returned any errors then display them and exit */
114     if (nerrors > 0) {
115       /* Display the error details contained in the arg_end struct.*/
116       arg_print_errors(stderr, end, PROGRAM_NAME);
117       fprintf(stderr, "Try '%s --help' for more information.\n", PROGRAM_NAME);
118       ret_value = EXIT_FAILURE;
119       break;
120     }
121 
122     if (num_keys_to_extract->ival[0] < 0) {
123       log_error("unable extract negative number of keys");
124       ret_value = EXIT_FAILURE;
125       break;
126     }
127 
128     // check file existence
129     if (!FileExists(keyfile->filename[0])) {
130       log_error("cannot access '%s'", keyfile->filename[0]);
131       ret_value = EXIT_FAILURE;
132       break;
133     }
134 
135     keyfile_size = GetFileSize(keyfile->filename[0]);
136     if (0 != keyfile_size % sizeof(EpidBinaryGroupCertificate)) {
137       log_error(
138           "input file '%s' is invalid: does not contain integral number of "
139           "group keys",
140           keyfile->filename[0]);
141       ret_value = EXIT_FAILURE;
142       break;
143     }
144     num_keys_in_file = keyfile_size / sizeof(EpidBinaryGroupCertificate);
145 
146     if ((unsigned int)num_keys_to_extract->ival[0] > num_keys_in_file) {
147       log_error("can not extract %d keys: only %d in file",
148                 num_keys_to_extract->ival[0], num_keys_in_file);
149       ret_value = EXIT_FAILURE;
150       break;
151     }
152 
153     file = fopen(keyfile->filename[0], "rb");
154     if (!file) {
155       log_error("failed read from '%s'", keyfile->filename[0]);
156       ret_value = EXIT_FAILURE;
157       break;
158     }
159 
160     // start extraction
161     for (i = 0; i < num_keys_to_extract->ival[0]; i++) {
162       EpidBinaryGroupCertificate temp;
163       int seek_failed = 0;
164       seek_failed = fseek(file, i * sizeof(temp), SEEK_SET);
165       bytes_read = fread(&temp, 1, sizeof(temp), file);
166       if (seek_failed || bytes_read != sizeof(temp)) {
167         log_error("failed to extract key #%lu from '%s'", i,
168                   keyfile->filename[0]);
169       } else {
170         // ulong max = 4294967295
171         char outkeyname[256] = {0};
172         if (memcmp(&kEpidVersionCode[kEpid2x], &temp.header.epid_version,
173                    sizeof(temp.header.epid_version)) ||
174             memcmp(&kEpidFileTypeCode[kGroupPubKeyFile], &temp.header.file_type,
175                    sizeof(temp.header.file_type))) {
176           log_error("failed to extract key #%lu from '%s': file is invalid", i,
177                     keyfile->filename[0]);
178           ret_value = EXIT_FAILURE;
179           break;
180         }
181         snprintf(outkeyname, sizeof(outkeyname), "pubkey%010u.bin", i);
182         if (FileExists(outkeyname)) {
183           log_error("file '%s' already exists", outkeyname);
184           ret_value = EXIT_FAILURE;
185           break;
186         }
187         if (0 != WriteLoud(&temp, sizeof(temp), outkeyname)) {
188           log_error("failed to write key #%lu from '%s'", i,
189                     keyfile->filename[0]);
190         } else {
191           num_keys_extracted++;
192         }
193       }
194     }
195     if (EXIT_FAILURE == ret_value) {
196       break;
197     }
198 
199     log_msg("extracted %lu of %lu keys", num_keys_extracted, num_keys_in_file);
200   } while (0);
201 
202   if (file) {
203     fclose(file);
204     file = NULL;
205   }
206 
207   arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
208 
209   return ret_value;
210 }
211