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