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