/src/opensc/src/tools/piv-tool.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * piv-tool.c: Tool for accessing smart cards with libopensc |
3 | | * |
4 | | * Copyright (C) 2001 Juha Yrjölä <juha.yrjola@iki.fi> |
5 | | * Copyright (C) 2005,2010 Douglas E. Engert <deengert@gmail.com> |
6 | | * |
7 | | * This library is free software; you can redistribute it and/or |
8 | | * modify it under the terms of the GNU Lesser General Public |
9 | | * License as published by the Free Software Foundation; either |
10 | | * version 2.1 of the License, or (at your option) any later version. |
11 | | * |
12 | | * This library is distributed in the hope that it will be useful, |
13 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | | * Lesser General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU Lesser General Public |
18 | | * License along with this library; if not, write to the Free Software |
19 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
20 | | */ |
21 | | |
22 | | #include "config.h" |
23 | | |
24 | | #include <stdio.h> |
25 | | #include <stdlib.h> |
26 | | #ifdef HAVE_UNISTD_H |
27 | | #include <unistd.h> |
28 | | #endif |
29 | | #include <string.h> |
30 | | #include <errno.h> |
31 | | #include <ctype.h> |
32 | | #include <sys/stat.h> |
33 | | |
34 | | /* Module only built if OPENSSL is enabled */ |
35 | | #include <openssl/opensslv.h> |
36 | | #include <openssl/opensslconf.h> |
37 | | #include <openssl/crypto.h> |
38 | | #include <openssl/conf.h> |
39 | | |
40 | | #include <openssl/rsa.h> |
41 | | #if OPENSSL_VERSION_NUMBER >= 0x30000000L |
42 | | # include <openssl/param_build.h> |
43 | | # include <openssl/params.h> |
44 | | #endif |
45 | | #if !defined(OPENSSL_NO_EC) && !defined(OPENSSL_NO_ECDSA) |
46 | | #include <openssl/ec.h> |
47 | | #include <openssl/ecdsa.h> |
48 | | #endif |
49 | | #include <openssl/evp.h> |
50 | | #include <openssl/x509.h> |
51 | | #include <openssl/bn.h> |
52 | | #include <openssl/bio.h> |
53 | | #include <openssl/pem.h> |
54 | | #include <openssl/err.h> |
55 | | #include <openssl/obj_mac.h> |
56 | | |
57 | | #include "libopensc/opensc.h" |
58 | | #include "libopensc/cardctl.h" |
59 | | #include "libopensc/cards.h" |
60 | | #include "libopensc/asn1.h" |
61 | | #include "libopensc/log.h" |
62 | | #include "util.h" |
63 | | #include "libopensc/sc-ossl-compat.h" |
64 | | |
65 | | static const char *app_name = "piv-tool"; |
66 | | |
67 | | static int opt_wait = 0; |
68 | | static char ** opt_apdus; |
69 | | static char * opt_reader; |
70 | | static int opt_apdu_count = 0; |
71 | | static int verbose = 0; |
72 | | |
73 | | enum { |
74 | | OPT_SERIAL = 0x100, |
75 | | }; |
76 | | |
77 | | static const struct option options[] = { |
78 | | { "serial", 0, NULL, OPT_SERIAL }, |
79 | | { "name", 0, NULL, 'n' }, |
80 | | { "admin", 1, NULL, 'A' }, |
81 | | { "genkey", 1, NULL, 'G' }, |
82 | | { "object", 1, NULL, 'O' }, |
83 | | { "cert", 1, NULL, 'C' }, |
84 | | { "compresscert", 1, NULL, 'Z' }, |
85 | | { "out", 1, NULL, 'o' }, |
86 | | { "in", 1, NULL, 'i' }, |
87 | | { "send-apdu", 1, NULL, 's' }, |
88 | | { "reader", 1, NULL, 'r' }, |
89 | | { "wait", 0, NULL, 'w' }, |
90 | | { "verbose", 0, NULL, 'v' }, |
91 | | { NULL, 0, NULL, 0 } |
92 | | }; |
93 | | |
94 | | static const char *option_help[] = { |
95 | | "Print the card serial number", |
96 | | "Identify the card and print its name", |
97 | | "Authenticate using default 3DES key", |
98 | | "Generate key <ref>:<alg> 9A:06 on card, and output pubkey", |
99 | | "Load an object <containerID> containerID as defined in 800-73 without leading 0x", |
100 | | "Load a cert <ref> where <ref> is 9A,9C,9D or 9E", |
101 | | "Load a cert that has been gzipped <ref>", |
102 | | "Output file for cert or key", |
103 | | "Input file for cert", |
104 | | "Sends an APDU in format AA:BB:CC:DD:EE:FF...", |
105 | | "Uses reader number <arg> [0]", |
106 | | "Wait for a card to be inserted", |
107 | | "Verbose operation, may be used several times", |
108 | | }; |
109 | | |
110 | | static sc_context_t *ctx = NULL; |
111 | | static sc_card_t *card = NULL; |
112 | | static BIO *bp = NULL; |
113 | | |
114 | | static int load_object(const char * object_id, const char * object_file) |
115 | 4 | { |
116 | 4 | FILE *fp = NULL; |
117 | 4 | sc_path_t path; |
118 | 4 | size_t derlen; |
119 | 4 | u8 *der = NULL; |
120 | 4 | u8 *body; |
121 | 4 | size_t bodylen; |
122 | 4 | int r = -1; |
123 | 4 | struct stat stat_buf; |
124 | | |
125 | 4 | if (!object_file || (fp = fopen(object_file, "rb")) == NULL) { |
126 | 3 | printf("Cannot open object file, %s %s\n", |
127 | 3 | (object_file) ? object_file : "", strerror(errno)); |
128 | 3 | goto err; |
129 | 3 | } |
130 | | |
131 | 1 | if (0 != stat(object_file, &stat_buf)) { |
132 | 0 | printf("unable to read file %s\n", object_file); |
133 | 0 | goto err; |
134 | 0 | } |
135 | 1 | derlen = stat_buf.st_size; |
136 | 1 | der = malloc(derlen); |
137 | 1 | if (der == NULL) { |
138 | 0 | printf("file %s is too big, %lu\n", |
139 | 0 | object_file, (unsigned long)derlen); |
140 | 0 | goto err; |
141 | 0 | } |
142 | 1 | if (1 != fread(der, derlen, 1, fp)) { |
143 | 1 | printf("unable to read file %s\n",object_file); |
144 | 1 | goto err; |
145 | 1 | } |
146 | | /* check if tag and length are valid */ |
147 | 0 | body = (u8 *)sc_asn1_find_tag(card->ctx, der, derlen, 0x53, &bodylen); |
148 | 0 | if (body == NULL || derlen != body - der + bodylen) { |
149 | 0 | fprintf(stderr, "object tag or length not valid\n"); |
150 | 0 | goto err; |
151 | 0 | } |
152 | | |
153 | 0 | sc_format_path(object_id, &path); |
154 | |
|
155 | 0 | r = sc_select_file(card, &path, NULL); |
156 | 0 | if (r < 0) { |
157 | 0 | fprintf(stderr, "select file failed\n"); |
158 | 0 | r = -1; |
159 | 0 | goto err; |
160 | 0 | } |
161 | | /* leave 8 bits for flags, and pass in total length */ |
162 | 0 | r = sc_write_binary(card, 0, der, derlen, derlen<<8); |
163 | |
|
164 | 4 | err: |
165 | 4 | free(der); |
166 | 4 | if (fp) |
167 | 1 | fclose(fp); |
168 | | |
169 | 4 | return r; |
170 | 0 | } |
171 | | |
172 | | |
173 | | static int load_cert(const char * cert_id, const char * cert_file, |
174 | | int compress) |
175 | 25 | { |
176 | 25 | X509 * cert = NULL; |
177 | 25 | FILE *fp = NULL; |
178 | 25 | u8 buf[1]; |
179 | 25 | size_t buflen = 1; |
180 | 25 | sc_path_t path; |
181 | 25 | u8 *der = NULL; |
182 | 25 | u8 *p; |
183 | 25 | size_t derlen; |
184 | 25 | int r = -1; |
185 | | |
186 | 25 | if (!cert_file) { |
187 | 22 | printf("Missing cert file\n"); |
188 | 22 | goto err; |
189 | 22 | } |
190 | | |
191 | 3 | if ((fp = fopen(cert_file, "rb")) == NULL) { |
192 | 1 | printf("Cannot open cert file, %s %s\n", |
193 | 1 | cert_file, strerror(errno)); |
194 | 1 | goto err; |
195 | 1 | } |
196 | 2 | if (compress) { /* file is gzipped already */ |
197 | 1 | struct stat stat_buf; |
198 | | |
199 | 1 | if (0 != stat(cert_file, &stat_buf)) { |
200 | 0 | printf("unable to read file %s\n", cert_file); |
201 | 0 | goto err; |
202 | 0 | } |
203 | 1 | derlen = stat_buf.st_size; |
204 | 1 | der = malloc(derlen); |
205 | 1 | if (der == NULL) { |
206 | 0 | printf("file %s is too big, %lu\n", |
207 | 0 | cert_file, (unsigned long)derlen); |
208 | 0 | goto err; |
209 | 0 | } |
210 | 1 | if (1 != fread(der, derlen, 1, fp)) { |
211 | 1 | printf("unable to read file %s\n", cert_file); |
212 | 1 | goto err; |
213 | 1 | } |
214 | 1 | } else { |
215 | 1 | cert = PEM_read_X509(fp, &cert, NULL, NULL); |
216 | 1 | if (cert == NULL) { |
217 | 1 | sc_log_openssl(ctx); |
218 | 1 | printf("file %s does not contain PEM-encoded certificate\n", cert_file); |
219 | 1 | goto err; |
220 | 1 | } |
221 | | |
222 | 0 | derlen = i2d_X509(cert, NULL); |
223 | 0 | der = malloc(derlen); |
224 | 0 | if (!der) { |
225 | 0 | goto err; |
226 | 0 | } |
227 | 0 | p = der; |
228 | 0 | i2d_X509(cert, &p); |
229 | 0 | } |
230 | 0 | sc_hex_to_bin(cert_id, buf,&buflen); |
231 | |
|
232 | 0 | switch (buf[0]) { |
233 | 0 | case 0x9a: sc_format_path("0101",&path); break; |
234 | 0 | case 0x9c: sc_format_path("0100",&path); break; |
235 | 0 | case 0x9d: sc_format_path("0102",&path); break; |
236 | 0 | case 0x9e: sc_format_path("0500",&path); break; |
237 | 0 | default: |
238 | 0 | fprintf(stderr,"cert must be 9A, 9C, 9D or 9E\n"); |
239 | 0 | r = 2; |
240 | 0 | goto err; |
241 | 0 | } |
242 | | |
243 | 0 | r = sc_select_file(card, &path, NULL); |
244 | 0 | if (r < 0) { |
245 | 0 | fprintf(stderr, "select file failed\n"); |
246 | 0 | goto err; |
247 | 0 | } |
248 | | /* we pass length and 8 bits of flag to card-piv.c write_binary */ |
249 | | /* pass in its a cert and if needs compress */ |
250 | 0 | r = sc_write_binary(card, 0, der, derlen, (derlen << 8) | (compress << 4) | 1); |
251 | |
|
252 | 25 | err: |
253 | 25 | free(der); |
254 | 25 | if (fp) |
255 | 2 | fclose(fp); |
256 | | |
257 | 25 | return r; |
258 | 0 | } |
259 | | static int admin_mode(const char* admin_info) |
260 | 235 | { |
261 | 235 | int r; |
262 | 235 | u8 opts[3]; |
263 | 235 | size_t buflen = 2; |
264 | | |
265 | | |
266 | 235 | if (admin_info && strlen(admin_info) == 7 && |
267 | 235 | (admin_info[0] == 'A' || admin_info[0] == 'M') && |
268 | 235 | admin_info[1] == ':' && |
269 | 235 | (sc_hex_to_bin(admin_info+2, opts+1, &buflen) == 0) && |
270 | 235 | buflen == 2) { |
271 | 183 | opts[0] = admin_info[0]; |
272 | 183 | } else { |
273 | 52 | fprintf(stderr, " admin_mode params <M|A>:<keyref>:<alg>\n"); |
274 | 52 | return -1; |
275 | 52 | } |
276 | | |
277 | 183 | r = sc_card_ctl(card, SC_CARDCTL_PIV_AUTHENTICATE, &opts); |
278 | 183 | if (r) |
279 | 183 | fprintf(stderr, " admin_mode failed %d\n", r); |
280 | 183 | return r; |
281 | 235 | } |
282 | | |
283 | | /* generate a new key pair, and save public key in newkey */ |
284 | | static int gen_key(const char * key_info) |
285 | 283 | { |
286 | 283 | int r = 1; |
287 | 283 | u8 buf[2]; |
288 | 283 | size_t buflen = 2; |
289 | 283 | sc_cardctl_piv_genkey_info_t |
290 | 283 | keydata = {0, 0, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0}; |
291 | 283 | EVP_PKEY *evpkey = NULL; |
292 | 283 | #if !defined(OPENSSL_NO_EC) |
293 | 283 | int nid = -1; |
294 | 283 | #endif |
295 | | |
296 | 283 | sc_hex_to_bin(key_info, buf, &buflen); |
297 | 283 | if (buflen != 2) { |
298 | 131 | fprintf(stderr, "<keyref>:<algid> invalid, example: 9A:06\n"); |
299 | 131 | return 2; |
300 | 131 | } |
301 | 152 | switch (buf[0]) { |
302 | 10 | case 0x9a: |
303 | 17 | case 0x9c: |
304 | 96 | case 0x9d: |
305 | 140 | case 0x9e: |
306 | 140 | keydata.key_num = buf[0]; |
307 | 140 | break; |
308 | 12 | default: |
309 | 12 | fprintf(stderr, "<keyref>:<algid> must be 9A, 9C, 9D or 9E\n"); |
310 | 12 | return 2; |
311 | 152 | } |
312 | | |
313 | 140 | switch (buf[1]) { |
314 | 28 | case 0x05: keydata.key_bits = 3072; break; |
315 | 23 | case 0x06: keydata.key_bits = 1024; break; |
316 | 10 | case 0x07: keydata.key_bits = 2048; break; |
317 | 0 | #if !defined(OPENSSL_NO_EC) |
318 | 42 | case 0x11: keydata.key_bits = 0; |
319 | 42 | nid = NID_X9_62_prime256v1; /* We only support one curve per algid */ |
320 | 42 | break; |
321 | 13 | case 0x14: keydata.key_bits = 0; |
322 | 13 | nid = NID_secp384r1; |
323 | 13 | break; |
324 | 9 | case 0xE0: |
325 | 9 | keydata.key_bits = 0; |
326 | 9 | nid = NID_ED25519; |
327 | 9 | break; |
328 | 5 | case 0xE1: |
329 | 5 | keydata.key_bits = 0; |
330 | 5 | nid = NID_X25519; |
331 | 5 | break; |
332 | 0 | #endif |
333 | 10 | default: |
334 | 10 | fprintf(stderr, "<keyref>:<algid> algid=RSA - 05, 06, 07 for 3072, 1024, 2048;EC - 11, 14 for 256, 384\n"); |
335 | 10 | return 2; |
336 | 140 | } |
337 | | |
338 | 130 | keydata.key_algid = buf[1]; |
339 | | |
340 | | |
341 | 130 | r = sc_card_ctl(card, SC_CARDCTL_PIV_GENERATE_KEY, &keydata); |
342 | 130 | if (r) { |
343 | 113 | fprintf(stderr, "gen_key failed %d\n", r); |
344 | 113 | return 1; |
345 | 113 | } |
346 | | |
347 | 17 | #if OPENSSL_VERSION_NUMBER < 0x30000000L |
348 | 17 | evpkey = EVP_PKEY_new(); |
349 | 17 | if (!evpkey) { |
350 | 0 | sc_log_openssl(ctx); |
351 | 0 | fprintf(stderr, "allocation of key failed\n"); |
352 | 0 | r = 1; |
353 | 0 | goto out; |
354 | 0 | } |
355 | 17 | #endif |
356 | | |
357 | 17 | if (keydata.key_bits > 0) { /* RSA key */ |
358 | 8 | BIGNUM *newkey_n, *newkey_e; |
359 | 8 | #if OPENSSL_VERSION_NUMBER < 0x30000000L |
360 | 8 | RSA *newkey = NULL; |
361 | | #else |
362 | | EVP_PKEY_CTX *cctx = NULL; |
363 | | OSSL_PARAM_BLD *bld = NULL; |
364 | | OSSL_PARAM *params = NULL; |
365 | | #endif |
366 | | |
367 | 8 | if (!keydata.pubkey || !keydata.exponent) { |
368 | 0 | fprintf(stderr, "gen_key failed %d\n", r); |
369 | 0 | r = 1; |
370 | 0 | goto out; |
371 | 0 | } |
372 | | |
373 | 8 | newkey_n = BN_bin2bn(keydata.pubkey, (int)keydata.pubkey_len, NULL); |
374 | 8 | newkey_e = BN_bin2bn(keydata.exponent, (int)keydata.exponent_len, NULL); |
375 | 8 | if (!newkey_n || !newkey_e) { |
376 | 0 | sc_log_openssl(ctx); |
377 | 0 | fprintf(stderr, "conversion or key params failed\n"); |
378 | 0 | r = 1; |
379 | 0 | goto out; |
380 | 0 | } |
381 | | |
382 | 8 | #if OPENSSL_VERSION_NUMBER < 0x30000000L |
383 | 8 | newkey = RSA_new(); |
384 | 8 | if (!newkey) { |
385 | 0 | sc_log_openssl(ctx); |
386 | 0 | fprintf(stderr, "gen_key RSA_new failed\n"); |
387 | 0 | r = 1; |
388 | 0 | goto out; |
389 | 0 | } |
390 | | |
391 | 8 | if (RSA_set0_key(newkey, newkey_n, newkey_e, NULL) != 1) { |
392 | 0 | sc_log_openssl(ctx); |
393 | 0 | RSA_free(newkey); |
394 | 0 | BN_free(newkey_n); |
395 | 0 | BN_free(newkey_e); |
396 | 0 | fprintf(stderr, "gen_key unable to set RSA values"); |
397 | 0 | r = 1; |
398 | 0 | goto out; |
399 | 0 | } |
400 | | |
401 | 8 | if (verbose) |
402 | 8 | RSA_print_fp(stdout, newkey, 0); |
403 | | |
404 | 8 | if (EVP_PKEY_assign_RSA(evpkey, newkey) != 1) { |
405 | 0 | sc_log_openssl(ctx); |
406 | 0 | RSA_free(newkey); |
407 | 0 | BN_free(newkey_n); |
408 | 0 | BN_free(newkey_e); |
409 | 0 | fprintf(stderr, "gen_key unable to set RSA values"); |
410 | 0 | r = 1; |
411 | 0 | goto out; |
412 | 0 | } |
413 | | #else |
414 | | if (!(bld = OSSL_PARAM_BLD_new()) || |
415 | | OSSL_PARAM_BLD_push_BN(bld, "n", newkey_n) != 1 || |
416 | | OSSL_PARAM_BLD_push_BN(bld, "e", newkey_e) != 1 || |
417 | | !(params = OSSL_PARAM_BLD_to_param(bld))) { |
418 | | sc_log_openssl(ctx); |
419 | | OSSL_PARAM_BLD_free(bld); |
420 | | BN_free(newkey_n); |
421 | | BN_free(newkey_e); |
422 | | r = 1; |
423 | | goto out; |
424 | | } |
425 | | |
426 | | OSSL_PARAM_BLD_free(bld); |
427 | | BN_free(newkey_n); |
428 | | BN_free(newkey_e); |
429 | | |
430 | | cctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL); |
431 | | if (!cctx || |
432 | | EVP_PKEY_fromdata_init(cctx) != 1 || |
433 | | EVP_PKEY_fromdata(cctx, &evpkey, EVP_PKEY_KEYPAIR, params) != 1) { |
434 | | sc_log_openssl(ctx); |
435 | | EVP_PKEY_CTX_free(cctx); |
436 | | OSSL_PARAM_free(params); |
437 | | fprintf(stderr, "gen_key unable to gen RSA"); |
438 | | r = 1; |
439 | | goto out; |
440 | | } |
441 | | if (verbose) |
442 | | EVP_PKEY_print_public_fp(stdout, evpkey, 0, NULL); |
443 | | |
444 | | EVP_PKEY_CTX_free(cctx); |
445 | | OSSL_PARAM_free(params); |
446 | | #endif |
447 | | |
448 | 8 | #ifdef EVP_PKEY_ED25519 |
449 | 9 | } else if (nid == NID_ED25519 || nid == NID_X25519) { |
450 | 7 | #if OPENSSL_VERSION_NUMBER < 0x30000000L |
451 | 7 | fprintf(stderr, "This build of OpenSSL does not support ED25519 or X25519 keys\n"); |
452 | 7 | r = 1; |
453 | 7 | goto out; |
454 | | #else |
455 | | if (!keydata.ecpoint) { |
456 | | fprintf(stderr, "gen_key failed\n"); |
457 | | r = 1; |
458 | | goto out; |
459 | | } |
460 | | evpkey = EVP_PKEY_new_raw_public_key(nid, NULL, keydata.ecpoint, keydata.ecpoint_len); |
461 | | if (!evpkey) { |
462 | | sc_log_openssl(ctx); |
463 | | fprintf(stderr, "gen key failed ti copy 25519 pubkey\n"); |
464 | | r = 1; |
465 | | goto out; |
466 | | } |
467 | | |
468 | | if (verbose) |
469 | | EVP_PKEY_print_public_fp(stdout, evpkey, 0, NULL); |
470 | | #endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ |
471 | | #else |
472 | | fprintf(stderr, "This build of OpenSSL does not support ED25519 or X25519 keys\n"); |
473 | | return -1; |
474 | | #endif /* EVP_PKEY_ED25519 */ |
475 | 7 | } else { /* EC key */ |
476 | 2 | #if !defined(OPENSSL_NO_EC) |
477 | 2 | int i; |
478 | 2 | BIGNUM *x = NULL; |
479 | 2 | BIGNUM *y = NULL; |
480 | 2 | EC_GROUP * ecgroup = NULL; |
481 | 2 | EC_POINT * ecpoint = NULL; |
482 | 2 | #if OPENSSL_VERSION_NUMBER < 0x30000000L |
483 | 2 | EC_KEY * eckey = NULL; |
484 | | #else |
485 | | EVP_PKEY_CTX *cctx = NULL; |
486 | | OSSL_PARAM_BLD *bld = NULL; |
487 | | OSSL_PARAM *params = NULL; |
488 | | size_t len = 0; |
489 | | unsigned char * buf = NULL; |
490 | | const char *group_name; |
491 | | #endif |
492 | | |
493 | 2 | if (!keydata.ecpoint) { |
494 | 0 | fprintf(stderr, "gen_key failed\n"); |
495 | 0 | r = 1; |
496 | 0 | goto out; |
497 | 0 | } |
498 | | |
499 | 2 | ecgroup = EC_GROUP_new_by_curve_name(nid); |
500 | 2 | EC_GROUP_set_asn1_flag(ecgroup, OPENSSL_EC_NAMED_CURVE); |
501 | 2 | ecpoint = EC_POINT_new(ecgroup); |
502 | | |
503 | | /* PIV returns 04||x||y and x and y are the same size */ |
504 | 2 | i = (int)(keydata.ecpoint_len - 1) / 2; |
505 | 2 | x = BN_bin2bn(keydata.ecpoint + 1, i, NULL); |
506 | 2 | y = BN_bin2bn(keydata.ecpoint + 1 + i, i, NULL); |
507 | 2 | if (!x || !y) { |
508 | 0 | sc_log_openssl(ctx); |
509 | 0 | BN_free(x); |
510 | 0 | BN_free(y); |
511 | 0 | EC_GROUP_free(ecgroup); |
512 | 0 | EC_POINT_free(ecpoint); |
513 | 0 | r = 1; |
514 | 0 | goto out; |
515 | 0 | } |
516 | 2 | r = EC_POINT_set_affine_coordinates(ecgroup, ecpoint, x, y, NULL); |
517 | | |
518 | 2 | BN_free(x); |
519 | 2 | BN_free(y); |
520 | | |
521 | 2 | if (r == 0) { |
522 | 2 | sc_log_openssl(ctx); |
523 | 2 | fprintf(stderr, "EC_POINT_set_affine_coordinates_GFp failed\n"); |
524 | 2 | EC_GROUP_free(ecgroup); |
525 | 2 | EC_POINT_free(ecpoint); |
526 | 2 | r = 1; |
527 | 2 | goto out; |
528 | 2 | } |
529 | 0 | #if OPENSSL_VERSION_NUMBER < 0x30000000L |
530 | 0 | eckey = EC_KEY_new(); |
531 | 0 | if (eckey == NULL) { |
532 | 0 | sc_log_openssl(ctx); |
533 | 0 | fprintf(stderr, "EC_KEY_new failed\n"); |
534 | 0 | EC_GROUP_free(ecgroup); |
535 | 0 | EC_POINT_free(ecpoint); |
536 | 0 | r = 1; |
537 | 0 | goto out; |
538 | 0 | } |
539 | 0 | r = EC_KEY_set_group(eckey, ecgroup); |
540 | 0 | EC_GROUP_free(ecgroup); |
541 | 0 | if (r == 0) { |
542 | 0 | sc_log_openssl(ctx); |
543 | 0 | fprintf(stderr, "EC_KEY_set_group failed\n"); |
544 | 0 | EC_POINT_free(ecpoint); |
545 | 0 | EC_KEY_free(eckey); |
546 | 0 | r = 1; |
547 | 0 | goto out; |
548 | 0 | } |
549 | 0 | r = EC_KEY_set_public_key(eckey, ecpoint); |
550 | 0 | EC_POINT_free(ecpoint); |
551 | 0 | if (r == 0) { |
552 | 0 | sc_log_openssl(ctx); |
553 | 0 | fprintf(stderr, "EC_KEY_set_public_key failed\n"); |
554 | 0 | EC_KEY_free(eckey); |
555 | 0 | r = 1; |
556 | 0 | goto out; |
557 | 0 | } |
558 | | |
559 | 0 | if (verbose) |
560 | 0 | EC_KEY_print_fp(stdout, eckey, 0); |
561 | |
|
562 | 0 | if (EVP_PKEY_assign_EC_KEY(evpkey, eckey) != 1) { |
563 | 0 | EC_KEY_free(eckey); |
564 | 0 | sc_log_openssl(ctx); |
565 | 0 | r = 1; |
566 | 0 | goto out; |
567 | 0 | } |
568 | | #else |
569 | | group_name = OBJ_nid2sn(nid); |
570 | | len = EC_POINT_point2oct(ecgroup, ecpoint, POINT_CONVERSION_COMPRESSED, NULL, 0, NULL); |
571 | | if (!(buf = malloc(len))) { |
572 | | sc_log_openssl(ctx); |
573 | | fprintf(stderr, "EC_KEY_set_public_key out of memory\n"); |
574 | | EC_GROUP_free(ecgroup); |
575 | | EC_POINT_free(ecpoint); |
576 | | r = 1; |
577 | | goto out; |
578 | | } |
579 | | if (EC_POINT_point2oct(ecgroup, ecpoint, POINT_CONVERSION_COMPRESSED, buf, len, NULL) == 0) { |
580 | | sc_log_openssl(ctx); |
581 | | fprintf(stderr, "EC_KEY_set_public_key failed\n"); |
582 | | EC_GROUP_free(ecgroup); |
583 | | EC_POINT_free(ecpoint); |
584 | | free(buf); |
585 | | r = 1; |
586 | | goto out; |
587 | | } |
588 | | |
589 | | EC_GROUP_free(ecgroup); |
590 | | EC_POINT_free(ecpoint); |
591 | | |
592 | | if (!(bld = OSSL_PARAM_BLD_new()) || |
593 | | OSSL_PARAM_BLD_push_utf8_string(bld, "group", group_name, strlen(group_name)) != 1 || |
594 | | OSSL_PARAM_BLD_push_octet_string(bld, "pub", buf, len) != 1 || |
595 | | !(params = OSSL_PARAM_BLD_to_param(bld))) { |
596 | | sc_log_openssl(ctx); |
597 | | OSSL_PARAM_BLD_free(bld); |
598 | | free(buf); |
599 | | r = 1; |
600 | | goto out; |
601 | | } |
602 | | free(buf); |
603 | | OSSL_PARAM_BLD_free(bld); |
604 | | |
605 | | cctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL); |
606 | | if (!cctx || |
607 | | EVP_PKEY_fromdata_init(cctx) != 1 || |
608 | | EVP_PKEY_fromdata(cctx, &evpkey, EVP_PKEY_KEYPAIR, params) != 1) { |
609 | | sc_log_openssl(ctx); |
610 | | fprintf(stderr, "gen_key unable to gen EC key"); |
611 | | EVP_PKEY_CTX_free(cctx); |
612 | | OSSL_PARAM_free(params); |
613 | | r = 1; |
614 | | goto out; |
615 | | } |
616 | | if (verbose) |
617 | | EVP_PKEY_print_public_fp(stdout, evpkey, 0, NULL); |
618 | | |
619 | | EVP_PKEY_CTX_free(cctx); |
620 | | OSSL_PARAM_free(params); |
621 | | #endif |
622 | | #else /* OPENSSL_NO_EC */ |
623 | | fprintf(stderr, "This build of OpenSSL does not support EC keys\n"); |
624 | | r = 1; |
625 | | #endif /* OPENSSL_NO_EC */ |
626 | |
|
627 | 0 | } |
628 | | |
629 | 8 | if (bp) { |
630 | 8 | r = i2d_PUBKEY_bio(bp, evpkey); |
631 | 8 | if (r != 1) { |
632 | 6 | sc_log_openssl(ctx); |
633 | 6 | fprintf(stderr, "Failed to encode public key"); |
634 | 6 | r = 1; |
635 | 6 | goto out; |
636 | 6 | } |
637 | 8 | } |
638 | 2 | r = SC_SUCCESS; |
639 | 17 | out: |
640 | 17 | free(keydata.pubkey); |
641 | 17 | free(keydata.exponent); |
642 | 17 | free(keydata.ecpoint); |
643 | | |
644 | 17 | EVP_PKEY_free(evpkey); |
645 | | |
646 | 17 | return r; |
647 | 2 | } |
648 | | |
649 | | |
650 | | static int send_apdu(void) |
651 | 885 | { |
652 | 885 | sc_apdu_t apdu; |
653 | 885 | u8 buf[SC_MAX_APDU_BUFFER_SIZE+3]; |
654 | 885 | u8 rbuf[8192]; |
655 | 885 | size_t len0, i; |
656 | 885 | int r; |
657 | 885 | int c; |
658 | | |
659 | 42.5k | for (c = 0; c < opt_apdu_count; c++) { |
660 | 42.1k | len0 = sizeof(buf); |
661 | 42.1k | sc_hex_to_bin(opt_apdus[c], buf, &len0); |
662 | | |
663 | 42.1k | r = sc_bytes2apdu(card->ctx, buf, len0, &apdu); |
664 | 42.1k | if (r) { |
665 | 422 | fprintf(stderr, "Invalid APDU: %s\n", sc_strerror(r)); |
666 | 422 | return 2; |
667 | 422 | } |
668 | | |
669 | 41.7k | apdu.resp = rbuf; |
670 | 41.7k | apdu.resplen = sizeof(rbuf); |
671 | | |
672 | 41.7k | printf("Sending: "); |
673 | 215k | for (i = 0; i < len0; i++) |
674 | 174k | printf("%02X ", buf[i]); |
675 | 41.7k | printf("\n"); |
676 | 41.7k | r = sc_transmit_apdu(card, &apdu); |
677 | 41.7k | if (r) { |
678 | 67 | fprintf(stderr, "APDU transmit failed: %s\n", sc_strerror(r)); |
679 | 67 | return 1; |
680 | 67 | } |
681 | 41.6k | printf("Received (SW1=0x%02X, SW2=0x%02X)%s\n", apdu.sw1, apdu.sw2, |
682 | 41.6k | apdu.resplen ? ":" : ""); |
683 | 41.6k | if (apdu.resplen) |
684 | 2.36k | util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1); |
685 | 41.6k | } |
686 | 396 | return 0; |
687 | 885 | } |
688 | | |
689 | | static void print_serial(sc_card_t *in_card) |
690 | 223 | { |
691 | 223 | int r; |
692 | 223 | sc_serial_number_t serial; |
693 | | |
694 | 223 | r = sc_card_ctl(in_card, SC_CARDCTL_GET_SERIALNR, &serial); |
695 | 223 | if (r < 0) |
696 | 180 | fprintf(stderr, "sc_card_ctl(*, SC_CARDCTL_GET_SERIALNR, *) failed %d\n", r); |
697 | 43 | else |
698 | 43 | util_hex_dump_asc(stdout, serial.value, serial.len, -1); |
699 | 223 | } |
700 | | |
701 | | int main(int argc, char *argv[]) |
702 | 3.12k | { |
703 | 3.12k | int err = 0, r, c; |
704 | 3.12k | int do_send_apdu = 0; |
705 | 3.12k | int do_admin_mode = 0; |
706 | 3.12k | int do_gen_key = 0; |
707 | 3.12k | int do_load_cert = 0; |
708 | 3.12k | int do_load_object = 0; |
709 | 3.12k | int compress_cert = 0; |
710 | 3.12k | int do_print_serial = 0; |
711 | 3.12k | int do_print_name = 0; |
712 | 3.12k | int action_count = 0; |
713 | 3.12k | const char *out_file = NULL; |
714 | 3.12k | const char *in_file = NULL; |
715 | 3.12k | const char *cert_id = NULL; |
716 | 3.12k | const char *object_id = NULL; |
717 | 3.12k | const char *key_info = NULL; |
718 | 3.12k | const char *admin_info = NULL; |
719 | 3.12k | sc_context_param_t ctx_param; |
720 | 3.12k | char **old_apdus = NULL; |
721 | | |
722 | 1.17M | while ((c = getopt_long(argc, argv, "nA:G:O:Z:C:i:o:r:fvs:c:w", options, (int *) 0)) != -1) { |
723 | 1.17M | switch (c) { |
724 | 436 | case OPT_SERIAL: |
725 | 436 | do_print_serial = 1; |
726 | 436 | action_count++; |
727 | 436 | break; |
728 | 74.2k | case 's': |
729 | 74.2k | old_apdus = opt_apdus; |
730 | 74.2k | opt_apdus = (char **) realloc(opt_apdus, |
731 | 74.2k | (opt_apdu_count + 1) * sizeof(char *)); |
732 | 74.2k | if (!opt_apdus) { |
733 | 0 | free(old_apdus); |
734 | 0 | err = 1; |
735 | 0 | goto end; |
736 | 0 | } |
737 | 74.2k | opt_apdus[opt_apdu_count] = optarg; |
738 | 74.2k | do_send_apdu++; |
739 | 74.2k | if (opt_apdu_count == 0) |
740 | 1.03k | action_count++; |
741 | 74.2k | opt_apdu_count++; |
742 | 74.2k | break; |
743 | 164k | case 'n': |
744 | 164k | do_print_name = 1; |
745 | 164k | action_count++; |
746 | 164k | break; |
747 | 437 | case 'A': |
748 | 437 | do_admin_mode = 1; |
749 | 437 | admin_info = optarg; |
750 | 437 | action_count++; |
751 | 437 | break; |
752 | 560 | case 'G': |
753 | 560 | do_gen_key = 1; |
754 | 560 | key_info = optarg; |
755 | 560 | action_count++; |
756 | 560 | break; |
757 | 369 | case 'O': |
758 | 369 | do_load_object = 1; |
759 | 369 | object_id = optarg; |
760 | 369 | action_count++; |
761 | 369 | break; |
762 | 197 | case 'Z': |
763 | 197 | compress_cert = 1; |
764 | | /* fall through */ |
765 | 534 | case 'C': |
766 | 534 | do_load_cert = 1; |
767 | 534 | cert_id = optarg; |
768 | 534 | action_count++; |
769 | 534 | break; |
770 | 206 | case 'i': |
771 | 206 | in_file = optarg; |
772 | 206 | break; |
773 | 198 | case 'o': |
774 | 198 | out_file = optarg; |
775 | 198 | break; |
776 | 900 | case 'r': |
777 | 900 | opt_reader = optarg; |
778 | 900 | break; |
779 | 918k | case 'v': |
780 | 918k | verbose++; |
781 | 918k | break; |
782 | 9.55k | case 'w': |
783 | 9.55k | opt_wait = 1; |
784 | 9.55k | break; |
785 | 6 | default: |
786 | 6 | util_print_usage(app_name, options, option_help, NULL); |
787 | 6 | if (opt_apdus) |
788 | 3 | free(opt_apdus); |
789 | 6 | return 2; |
790 | 1.17M | } |
791 | 1.17M | } |
792 | | |
793 | 3.11k | if (action_count == 0) { |
794 | 77 | util_print_usage(app_name, options, option_help, NULL); |
795 | 77 | if (opt_apdus) |
796 | 0 | free(opt_apdus); |
797 | 77 | return 2; |
798 | 77 | } |
799 | | |
800 | 3.04k | if (out_file) { |
801 | 11 | bp = BIO_new(BIO_s_file()); |
802 | 11 | if (!BIO_write_filename(bp, (char *)out_file)) |
803 | 5 | goto end; |
804 | 3.02k | } else { |
805 | 3.02k | bp = BIO_new(BIO_s_file()); |
806 | 3.02k | BIO_set_fp(bp,stdout,BIO_NOCLOSE); |
807 | 3.02k | } |
808 | | |
809 | 3.03k | memset(&ctx_param, 0, sizeof(sc_context_param_t)); |
810 | 3.03k | ctx_param.app_name = app_name; |
811 | 3.03k | ctx_param.debug = verbose; |
812 | 3.03k | if (verbose) |
813 | 3.03k | ctx_param.debug_file = stderr; |
814 | | |
815 | 3.03k | r = sc_context_create(&ctx, &ctx_param); |
816 | 3.03k | if (r != SC_SUCCESS) { |
817 | 0 | fprintf(stderr, "Failed to establish context: %s\n", sc_strerror(r)); |
818 | 0 | return 1; |
819 | 0 | } |
820 | | |
821 | 3.03k | if (action_count <= 0) |
822 | 0 | goto end; |
823 | | |
824 | | /* force PIV card driver */ |
825 | 3.03k | err = sc_set_card_driver(ctx, "PIV-II"); |
826 | 3.03k | if (err) { |
827 | 0 | fprintf(stderr, "PIV card driver not found!\n"); |
828 | 0 | err = 1; |
829 | 0 | goto end; |
830 | 0 | } |
831 | | |
832 | 3.03k | err = util_connect_card(ctx, &card, opt_reader, opt_wait); |
833 | 3.03k | if (err) |
834 | 1.33k | goto end; |
835 | | |
836 | | /* fail if card is not a PIV card */ |
837 | 1.70k | if (card->type < SC_CARD_TYPE_PIV_II_BASE || card->type >= SC_CARD_TYPE_PIV_II_BASE+1000) { |
838 | 0 | fprintf(stderr, "Card type %X: not a PIV card\n", card->type); |
839 | 0 | err = 1; |
840 | 0 | goto end; |
841 | 0 | } |
842 | | |
843 | 1.70k | if (do_admin_mode) { |
844 | 235 | if ((err = admin_mode(admin_info))) |
845 | 235 | goto end; |
846 | 0 | action_count--; |
847 | 0 | } |
848 | 1.46k | if (do_send_apdu) { /* can use pin before load cert for a beta card */ |
849 | 885 | if ((err = send_apdu())) |
850 | 489 | goto end; |
851 | 396 | action_count--; |
852 | 396 | } |
853 | 976 | if (do_gen_key) { |
854 | 283 | if ((err = gen_key(key_info))) |
855 | 281 | goto end; |
856 | 2 | action_count--; |
857 | 2 | } |
858 | 695 | if (do_load_object) { |
859 | 4 | if ((err = load_object(object_id, in_file))) |
860 | 4 | goto end; |
861 | 0 | action_count--; |
862 | 0 | } |
863 | 691 | if (do_load_cert) { |
864 | 25 | if ((err = load_cert(cert_id, in_file, compress_cert))) |
865 | 25 | goto end; |
866 | 0 | action_count--; |
867 | 0 | } |
868 | 666 | if (do_print_serial) { |
869 | 223 | if (verbose) |
870 | 223 | printf("Card serial number:"); |
871 | 223 | print_serial(card); |
872 | 223 | action_count--; |
873 | 223 | } |
874 | 666 | if (do_print_name) { |
875 | 152 | if (verbose) |
876 | 152 | printf("Card name: "); |
877 | 152 | printf("%s\n", card->name); |
878 | 152 | action_count--; |
879 | 152 | } |
880 | 3.04k | end: |
881 | 3.04k | if (bp) |
882 | 3.04k | BIO_free(bp); |
883 | 3.04k | if (card) { |
884 | 1.70k | sc_unlock(card); |
885 | 1.70k | sc_disconnect_card(card); |
886 | 1.70k | } |
887 | 3.04k | if (opt_apdus) |
888 | 1.03k | free(opt_apdus); |
889 | 3.04k | sc_release_context(ctx); |
890 | | |
891 | 3.04k | ERR_print_errors_fp(stderr); |
892 | 3.04k | return err; |
893 | 666 | } |