/src/opensc/src/libopensc/pkcs15-openpgp.c
Line | Count | Source |
1 | | /* |
2 | | * PKCS15 emulation layer for OpenPGP card. |
3 | | * To see how this works, run p15dump on your OpenPGP card. |
4 | | * |
5 | | * Copyright (C) 2003, Olaf Kirch <okir@suse.de> |
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 | | #ifdef HAVE_CONFIG_H |
23 | | #include "config.h" |
24 | | #endif |
25 | | |
26 | | #include <stdlib.h> |
27 | | #include <string.h> |
28 | | #include <stdio.h> |
29 | | #include <assert.h> |
30 | | |
31 | | #include "common/compat_strlcpy.h" |
32 | | #include "internal.h" |
33 | | #include "pkcs15.h" |
34 | | #include "log.h" |
35 | | #include "card-openpgp.h" |
36 | | |
37 | | static int sc_pkcs15emu_openpgp_add_data(sc_pkcs15_card_t *); |
38 | | |
39 | | |
40 | | #define PGP_USER_PIN_FLAGS (SC_PKCS15_PIN_FLAG_CASE_SENSITIVE \ |
41 | | | SC_PKCS15_PIN_FLAG_INITIALIZED \ |
42 | | | SC_PKCS15_PIN_FLAG_LOCAL) |
43 | | #define PGP_ADMIN_PIN_FLAGS (PGP_USER_PIN_FLAGS \ |
44 | | | SC_PKCS15_PIN_FLAG_UNBLOCK_DISABLED \ |
45 | | | SC_PKCS15_PIN_FLAG_SO_PIN) |
46 | | |
47 | 195 | #define PGP_NUM_PRIVDO 4 |
48 | 191 | #define PGP_MAX_NUM_CERTS 3 |
49 | | |
50 | | typedef struct _pgp_pin_cfg { |
51 | | const char *label; |
52 | | int reference; |
53 | | unsigned int flags; |
54 | | int min_length; |
55 | | int do_index; |
56 | | } pgp_pin_cfg_t; |
57 | | |
58 | | // clang-format off |
59 | | /* OpenPGP cards v1: |
60 | | * "Signature PIN2 & "Encryption PIN" are two different PINs - not sync'ed by hardware |
61 | | */ |
62 | | static const pgp_pin_cfg_t pin_cfg_v1[3] = { |
63 | | { "Encryption PIN", 0x02, PGP_USER_PIN_FLAGS, 6, 1 }, // used for PSO:DEC, INT-AUT, {GET,PUT} DATA |
64 | | { "Signature PIN", 0x01, PGP_USER_PIN_FLAGS, 6, 0 }, // used for PSO:CDS |
65 | | { "Admin PIN", 0x03, PGP_ADMIN_PIN_FLAGS, 8, 2 } |
66 | | }; |
67 | | /* OpenPGP cards v2: |
68 | | * "User PIN (sig)" & "User PIN" are the same PIN, but use different references depending on action |
69 | | */ |
70 | | static const pgp_pin_cfg_t pin_cfg_v2[3] = { |
71 | | { "User PIN", 0x02, PGP_USER_PIN_FLAGS, 6, 0 }, // used for PSO:DEC, INT-AUT, {GET,PUT} DATA |
72 | | { "User PIN (sig)", 0x01, PGP_USER_PIN_FLAGS, 6, 0 }, // used for PSO:CDS |
73 | | { "Admin PIN", 0x03, PGP_ADMIN_PIN_FLAGS, 8, 2 } |
74 | | }; |
75 | | // clang-format on |
76 | | |
77 | | static struct sc_object_id curve25519_oid = {{1, 3, 6, 1, 4, 1, 3029, 1, 5, 1, -1}}; |
78 | | |
79 | 0 | #define PGP_SIG_PRKEY_USAGE (SC_PKCS15_PRKEY_USAGE_SIGN \ |
80 | 0 | | SC_PKCS15_PRKEY_USAGE_SIGNRECOVER \ |
81 | 0 | | SC_PKCS15_PRKEY_USAGE_NONREPUDIATION) |
82 | 69 | #define PGP_ENC_PRKEY_USAGE (SC_PKCS15_PRKEY_USAGE_DECRYPT \ |
83 | 69 | | SC_PKCS15_PRKEY_USAGE_UNWRAP) |
84 | | #define PGP_AUTH_PRKEY_USAGE (SC_PKCS15_PRKEY_USAGE_NONREPUDIATION) |
85 | | |
86 | 0 | #define PGP_SIG_PUBKEY_USAGE (SC_PKCS15_PRKEY_USAGE_VERIFY \ |
87 | 0 | | SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER) |
88 | 69 | #define PGP_ENC_PUBKEY_USAGE (SC_PKCS15_PRKEY_USAGE_ENCRYPT \ |
89 | 69 | | SC_PKCS15_PRKEY_USAGE_WRAP) |
90 | | #define PGP_AUTH_PUBKEY_USAGE (SC_PKCS15_PRKEY_USAGE_VERIFY) |
91 | | |
92 | | typedef struct _pgp_key_cfg { |
93 | | const char *label; |
94 | | const char *pubkey_path; |
95 | | int prkey_pin; |
96 | | int prkey_usage; |
97 | | int pubkey_usage; |
98 | | } pgp_key_cfg_t; |
99 | | |
100 | | typedef struct cdata_st { |
101 | | const char *label; |
102 | | int authority; |
103 | | const char *path; |
104 | | const char *id; |
105 | | int obj_flags; |
106 | | } cdata; |
107 | | |
108 | | // clang-format off |
109 | | static const pgp_key_cfg_t key_cfg[3] = { |
110 | | { "Signature key", "B601", 1, PGP_SIG_PRKEY_USAGE, PGP_SIG_PUBKEY_USAGE }, |
111 | | { "Encryption key", "B801", 2, PGP_ENC_PRKEY_USAGE, PGP_ENC_PUBKEY_USAGE }, |
112 | | { "Authentication key", "A401", 2, PGP_AUTH_PRKEY_USAGE | PGP_ENC_PRKEY_USAGE, PGP_AUTH_PUBKEY_USAGE | PGP_ENC_PUBKEY_USAGE } |
113 | | }; |
114 | | |
115 | | static const cdata certs[PGP_MAX_NUM_CERTS] = { |
116 | | {"AUT certificate", 0, "3F007F21", "3", SC_PKCS15_CO_FLAG_MODIFIABLE}, |
117 | | {"DEC certificate", 0, "3F007F21", "2", SC_PKCS15_CO_FLAG_MODIFIABLE}, |
118 | | {"SIG certificate", 0, "3F007F21", "1", SC_PKCS15_CO_FLAG_MODIFIABLE} |
119 | | }; |
120 | | // clang-format on |
121 | | |
122 | | typedef struct _pgp_manuf_map { |
123 | | unsigned short id; |
124 | | const char *name; |
125 | | } pgp_manuf_map_t; |
126 | | |
127 | | // clang-format off |
128 | | static const pgp_manuf_map_t manuf_map[] = { |
129 | | { 0x0001, "PPC Card Systems" }, |
130 | | { 0x0002, "Prism" }, |
131 | | { 0x0003, "OpenFortress" }, |
132 | | { 0x0004, "Wewid AB" }, |
133 | | { 0x0005, "ZeitControl" }, |
134 | | { 0x0006, "Yubico" }, |
135 | | { 0x0007, "OpenKMS" }, |
136 | | { 0x0008, "LogoEmail" }, |
137 | | { 0x0009, "Fidesmo" }, |
138 | | { 0x000A, "Dangerous Things" }, |
139 | | { 0x000B, "Feitian Technologies" }, |
140 | | { 0x002A, "Magrathea" }, |
141 | | { 0x0042, "GnuPG e.V." }, |
142 | | { 0x1337, "Warsaw Hackerspace" }, |
143 | | { 0x2342, "warpzone" }, |
144 | | { 0x4354, "Confidential Technologies" }, |
145 | | { 0x5443, "TIF-IT e.V." }, |
146 | | { 0x63AF, "Trustica" }, |
147 | | { 0xBA53, "c-base e.V." }, |
148 | | { 0xBD0E, "Paranoidlabs" }, |
149 | | { 0xF517, "FSIJ" }, |
150 | | { 0xF5EC, "F-Secure" }, |
151 | | { 0x0000, "test card" }, |
152 | | { 0xffff, "test card" }, |
153 | | { 0, NULL } |
154 | | }; |
155 | | // clang-format on |
156 | | |
157 | | /* |
158 | | * This function pretty much follows what find_tlv in the GNUpg |
159 | | * code does. |
160 | | */ |
161 | | static int |
162 | | read_file(sc_card_t *card, const char *path_name, void *buf, size_t len) |
163 | 6.32k | { |
164 | 6.32k | sc_path_t path; |
165 | 6.32k | sc_file_t *file; |
166 | 6.32k | int r; |
167 | | |
168 | 6.32k | sc_format_path(path_name, &path); |
169 | 6.32k | if ((r = sc_select_file(card, &path, &file)) < 0) |
170 | 3.43k | return r; |
171 | | |
172 | 2.88k | if (file->size < len) |
173 | 2.76k | len = file->size; |
174 | | |
175 | 2.88k | sc_file_free(file); |
176 | | |
177 | 2.88k | return sc_read_binary(card, 0, (u8 *) buf, len, 0); |
178 | 6.32k | } |
179 | | |
180 | | static int |
181 | | sc_pkcs15emu_openpgp_init(sc_pkcs15_card_t *p15card) |
182 | 3.73k | { |
183 | 3.73k | sc_card_t *card = p15card->card; |
184 | 3.73k | sc_context_t *ctx = card->ctx; |
185 | 3.73k | struct pgp_priv_data *priv = DRVDATA(card); |
186 | 3.73k | char string[256]; |
187 | 3.73k | u8 c4data[10]; |
188 | 3.73k | u8 c5data[100]; |
189 | 3.73k | int r, i; |
190 | 3.73k | const pgp_pin_cfg_t *pin_cfg = (card->type == SC_CARD_TYPE_OPENPGP_V1) |
191 | 3.73k | ? pin_cfg_v1 : pin_cfg_v2; |
192 | 3.73k | sc_path_t path; |
193 | 3.73k | sc_file_t *file = NULL; |
194 | | |
195 | 3.73k | LOG_FUNC_CALLED(ctx); |
196 | | |
197 | 3.73k | set_string(&p15card->tokeninfo->label, "OpenPGP card"); |
198 | 3.73k | set_string(&p15card->tokeninfo->manufacturer_id, "OpenPGP project"); |
199 | | |
200 | | /* card->serialnr = 2 byte manufacturer_id + 4 byte serial_number */ |
201 | 3.73k | if (card->serialnr.len > 0) { |
202 | 2.75k | unsigned short manuf_id = bebytes2ushort(card->serialnr.value); |
203 | 2.75k | int j; |
204 | | |
205 | 2.75k | sc_bin_to_hex(card->serialnr.value, card->serialnr.len, string, sizeof(string), 0); |
206 | 2.75k | set_string(&p15card->tokeninfo->serial_number, string); |
207 | | |
208 | 65.0k | for (j = 0; manuf_map[j].name != NULL; j++) { |
209 | 62.7k | if (manuf_id == manuf_map[j].id) { |
210 | 476 | set_string(&p15card->tokeninfo->manufacturer_id, manuf_map[j].name); |
211 | 476 | break; |
212 | 476 | } |
213 | 62.7k | } |
214 | 2.75k | } |
215 | | |
216 | 3.73k | p15card->tokeninfo->flags = SC_PKCS15_TOKEN_PRN_GENERATION | SC_PKCS15_TOKEN_EID_COMPLIANT; |
217 | | |
218 | | /* Extract preferred language */ |
219 | 3.73k | r = read_file(card, "0065:5f2d", string, sizeof(string)-1); |
220 | 3.73k | if (r < 0) |
221 | 2.98k | goto failed; |
222 | 751 | string[r] = '\0'; |
223 | 751 | set_string(&p15card->tokeninfo->preferred_language, string); |
224 | | |
225 | | /* Get CHV status bytes from DO 006E/0073/00C4: |
226 | | * 00: 1 == user consent for signature PIN |
227 | | * (i.e. PIN still valid for next PSO:CDS command) |
228 | | * 01-03: max length of pins 1-3 |
229 | | * 04-07: tries left for pins 1-3 |
230 | | */ |
231 | 751 | sc_log(ctx, "Reading PW status bytes"); |
232 | 751 | if ((r = read_file(card, "006E:0073:00C4", c4data, sizeof(c4data))) < 0) |
233 | 330 | goto failed; |
234 | 421 | if (r != 7) { |
235 | 106 | sc_log(ctx, "CHV status bytes have unexpected length (expected 7, got %d)\n", r); |
236 | 106 | r = SC_ERROR_OBJECT_NOT_VALID; |
237 | 106 | goto failed; |
238 | 106 | } |
239 | | |
240 | | /* Add PIN codes */ |
241 | 1.26k | for (i = 0; i < 3; i++) { |
242 | 945 | sc_pkcs15_auth_info_t pin_info; |
243 | 945 | sc_pkcs15_object_t pin_obj; |
244 | | |
245 | 945 | memset(&pin_info, 0, sizeof(pin_info)); |
246 | 945 | memset(&pin_obj, 0, sizeof(pin_obj)); |
247 | | |
248 | 945 | pin_info.auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN; |
249 | 945 | pin_info.auth_id.len = 1; |
250 | 945 | pin_info.auth_id.value[0] = pin_cfg[i].reference; |
251 | 945 | pin_info.attrs.pin.reference = pin_cfg[i].reference; |
252 | 945 | pin_info.attrs.pin.flags = pin_cfg[i].flags; |
253 | 945 | pin_info.attrs.pin.type = SC_PKCS15_PIN_TYPE_UTF8; |
254 | 945 | pin_info.attrs.pin.min_length = pin_cfg[i].min_length; |
255 | 945 | pin_info.attrs.pin.stored_length = c4data[1 + pin_cfg[i].do_index]; |
256 | 945 | pin_info.attrs.pin.max_length = c4data[1 + pin_cfg[i].do_index]; |
257 | 945 | pin_info.attrs.pin.pad_char = '\0'; |
258 | 945 | pin_info.tries_left = c4data[4 + pin_cfg[i].do_index]; |
259 | 945 | pin_info.logged_in = SC_PIN_STATE_UNKNOWN; |
260 | | |
261 | 945 | sc_format_path("3F00", &pin_info.path); |
262 | | |
263 | 945 | strlcpy(pin_obj.label, pin_cfg[i].label, sizeof(pin_obj.label)); |
264 | 945 | pin_obj.flags = SC_PKCS15_CO_FLAG_MODIFIABLE | SC_PKCS15_CO_FLAG_PRIVATE; |
265 | 945 | if (i < 2) { |
266 | 630 | pin_obj.auth_id.len = 1; |
267 | 630 | pin_obj.auth_id.value[0] = 3; |
268 | 630 | } |
269 | | |
270 | 945 | r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info); |
271 | 945 | if (r < 0) { |
272 | 0 | r = SC_ERROR_INTERNAL; |
273 | 0 | goto failed; |
274 | 0 | } |
275 | 945 | } |
276 | | |
277 | | /* Get private key finger prints from DO 006E/0073/00C5: |
278 | | * 00-19: finger print for SIG key |
279 | | * 20-39: finger print for ENC key |
280 | | * 40-59: finger print for AUT key |
281 | | */ |
282 | 315 | sc_log(ctx, "Reading Fingerprints"); |
283 | 315 | if ((r = read_file(card, "006E:0073:00C5", c5data, sizeof(c5data))) < 0) |
284 | 12 | goto failed; |
285 | 303 | if (r < 60) { |
286 | 7 | sc_log(ctx, |
287 | 7 | "finger print bytes have unexpected length (expected 60, got %d)\n", r); |
288 | 7 | r = SC_ERROR_OBJECT_NOT_VALID; |
289 | 7 | goto failed; |
290 | 7 | } |
291 | | |
292 | 296 | sc_log(ctx, "Adding private keys"); |
293 | | /* XXX: check if "halfkeys" can be stored with gpg2. If not, add key pairs in one loop */ |
294 | 1.00k | for (i = 0; i < 3; i++) { |
295 | 827 | sc_pkcs15_prkey_info_t prkey_info; |
296 | 827 | sc_pkcs15_object_t prkey_obj; |
297 | 827 | u8 cxdata[12]; |
298 | 827 | int cxdata_len = sizeof(cxdata); |
299 | 827 | char path_template[] = "006E:0073:00Cx"; |
300 | 827 | int j; |
301 | | |
302 | 827 | memset(&prkey_info, 0, sizeof(prkey_info)); |
303 | 827 | memset(&prkey_obj, 0, sizeof(prkey_obj)); |
304 | 827 | memset(&cxdata, 0, sizeof(cxdata)); |
305 | | |
306 | 827 | path_template[13] = '1' + i; /* The needed tags are C1 C2 and C3 */ |
307 | 827 | if ((cxdata_len = read_file(card, path_template, cxdata, sizeof(cxdata))) < 1) |
308 | 110 | goto failed; |
309 | | |
310 | | /* check validity using finger prints */ |
311 | 2.79k | for (j = 19; j >= 0; j--) { |
312 | 2.76k | if (c5data[20 * i + j] != '\0') |
313 | 683 | break; |
314 | 2.76k | } |
315 | | |
316 | | /* only add valid keys, i.e. those with a legal algorithm identifier & finger print */ |
317 | 717 | if (j >= 0 && cxdata[0] != 0) { |
318 | 626 | struct sc_object_id oid = {0}; |
319 | 626 | struct sc_algorithm_info * algorithm_info; /* no need to free */ |
320 | | |
321 | 626 | algorithm_info = NULL; |
322 | 626 | prkey_info.id.len = 1; |
323 | 626 | prkey_info.id.value[0] = i + 1; |
324 | 626 | prkey_info.usage = key_cfg[i].prkey_usage; |
325 | 626 | prkey_info.native = 1; |
326 | 626 | prkey_info.key_reference = i; |
327 | | |
328 | 626 | strlcpy(prkey_obj.label, key_cfg[i].label, sizeof(prkey_obj.label)); |
329 | 626 | prkey_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE | SC_PKCS15_CO_FLAG_MODIFIABLE; |
330 | 626 | prkey_obj.auth_id.len = 1; |
331 | 626 | prkey_obj.auth_id.value[0] = key_cfg[i].prkey_pin; |
332 | | |
333 | | /* need to get size from algorithms using oid */ |
334 | 626 | if (cxdata[0] == SC_OPENPGP_KEYALGO_ECDH || |
335 | 553 | cxdata[0] == SC_OPENPGP_KEYALGO_ECDSA || |
336 | 502 | cxdata[0] == SC_OPENPGP_KEYALGO_EDDSA) { |
337 | | /* Last byte could be Import-Format of private key, let's ignore it, |
338 | | * as it is not part of OID */ |
339 | 146 | if (cxdata[cxdata_len-1] == SC_OPENPGP_KEYFORMAT_EC_STD || |
340 | 92 | cxdata[cxdata_len-1] == SC_OPENPGP_KEYFORMAT_EC_STDPUB) |
341 | 67 | cxdata_len--; |
342 | 146 | r = sc_asn1_decode_object_id(&cxdata[1], cxdata_len-1, &oid); |
343 | 146 | if (r != SC_SUCCESS) { |
344 | 68 | sc_log(ctx, "Failed to parse OID for elliptic curve algorithm"); |
345 | 68 | } |
346 | 146 | } |
347 | | |
348 | 626 | switch (cxdata[0]) { |
349 | 73 | case SC_OPENPGP_KEYALGO_ECDH: |
350 | 73 | if (sc_compare_oid(&oid, &curve25519_oid)) { |
351 | 0 | if ((algorithm_info = sc_card_find_xeddsa_alg(card, 0, &oid))) |
352 | 0 | prkey_info.field_length = algorithm_info->key_length; |
353 | 0 | else { |
354 | 0 | sc_log(ctx, "algorithm not found"); |
355 | 0 | continue; |
356 | 0 | } |
357 | 0 | break; |
358 | 0 | } |
359 | | /* Fall through */ |
360 | 124 | case SC_OPENPGP_KEYALGO_ECDSA: |
361 | 124 | if((algorithm_info = sc_card_find_ec_alg(card, 0, &oid))) |
362 | 0 | prkey_info.field_length = algorithm_info->key_length; |
363 | 124 | else { |
364 | 124 | sc_log(ctx, "algorithm not found"); |
365 | 124 | continue; |
366 | 124 | } |
367 | 0 | break; |
368 | 22 | case SC_OPENPGP_KEYALGO_EDDSA: |
369 | 22 | if ((algorithm_info = sc_card_find_eddsa_alg(card, 0, &oid))) |
370 | 0 | prkey_info.field_length = algorithm_info->key_length; |
371 | 22 | else { |
372 | 22 | sc_log(ctx, "algorithm not found"); |
373 | 22 | continue; |
374 | 22 | } |
375 | 0 | break; |
376 | 626 | } |
377 | | |
378 | 480 | switch (cxdata[0]) { |
379 | 0 | case SC_OPENPGP_KEYALGO_EDDSA: |
380 | | /* Filter out invalid usage: EdDSA does not support anything but sign */ |
381 | 0 | prkey_info.usage &= PGP_SIG_PRKEY_USAGE; |
382 | 0 | r = sc_pkcs15emu_add_eddsa_prkey(p15card, &prkey_obj, &prkey_info); |
383 | 0 | break; |
384 | | |
385 | 0 | case SC_OPENPGP_KEYALGO_ECDH: |
386 | | /* This can result in either ECDSA key or EC_MONTGOMERY |
387 | | * so we need to check OID */ |
388 | 0 | if (sc_compare_oid(&oid, &curve25519_oid)) { |
389 | | /* This can do only DERIVE */ |
390 | 0 | prkey_info.usage = SC_PKCS15_PRKEY_USAGE_DERIVE; |
391 | 0 | r = sc_pkcs15emu_add_xeddsa_prkey(p15card, &prkey_obj, &prkey_info); |
392 | 0 | break; |
393 | 0 | } |
394 | 0 | prkey_info.usage |= SC_PKCS15_PRKEY_USAGE_DERIVE; |
395 | 0 | prkey_info.usage &= ~PGP_ENC_PRKEY_USAGE; |
396 | 0 | r = sc_pkcs15emu_add_ec_prkey(p15card, &prkey_obj, &prkey_info); |
397 | 0 | break; |
398 | | |
399 | 0 | case SC_OPENPGP_KEYALGO_ECDSA: |
400 | 0 | prkey_info.usage = SC_PKCS15_PRKEY_USAGE_SIGN; |
401 | 0 | r = sc_pkcs15emu_add_ec_prkey(p15card, &prkey_obj, &prkey_info); |
402 | 0 | break; |
403 | | |
404 | 306 | case SC_OPENPGP_KEYALGO_RSA: |
405 | 306 | if (cxdata_len >= 3) { |
406 | | /* with Authentication key, can only decrypt if can change MSE */ |
407 | 290 | if (i == 2 && !(priv->ext_caps & EXT_CAP_MSE)) { |
408 | 69 | prkey_info.usage &= ~PGP_ENC_PRKEY_USAGE; |
409 | 69 | } |
410 | 290 | prkey_info.modulus_length = bebytes2ushort(cxdata + 1); |
411 | 290 | r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info); |
412 | 290 | break; |
413 | 290 | } |
414 | | /* Fallthrough */ |
415 | 190 | default: |
416 | 190 | sc_log(ctx, "Invalid algorithm identifier %x (length = %d)", |
417 | 480 | cxdata[0], r); |
418 | 480 | } |
419 | | |
420 | 480 | if (r < 0) { |
421 | 5 | r = SC_ERROR_INTERNAL; |
422 | 5 | goto failed; |
423 | 5 | } |
424 | 480 | } |
425 | 717 | } |
426 | | |
427 | 181 | sc_log(ctx, "Adding public keys"); |
428 | | /* Add public keys */ |
429 | 713 | for (i = 0; i < 3; i++) { |
430 | 536 | sc_pkcs15_pubkey_info_t pubkey_info; |
431 | 536 | sc_pkcs15_object_t pubkey_obj; |
432 | 536 | u8 cxdata[12]; |
433 | 536 | int cxdata_len = sizeof(cxdata); |
434 | 536 | char path_template[] = "006E:0073:00Cx"; |
435 | 536 | int j; |
436 | | |
437 | 536 | memset(&pubkey_info, 0, sizeof(pubkey_info)); |
438 | 536 | memset(&pubkey_obj, 0, sizeof(pubkey_obj)); |
439 | 536 | memset(&cxdata, 0, sizeof(cxdata)); |
440 | | |
441 | 536 | path_template[13] = '1' + i; /* The needed tags are C1 C2 and C3 */ |
442 | 536 | if ((cxdata_len = read_file(card, path_template, cxdata, sizeof(cxdata))) < 1) |
443 | 0 | goto failed; |
444 | | |
445 | | /* check validity using finger prints */ |
446 | 1.60k | for (j = 19; j >= 0; j--) { |
447 | 1.58k | if (c5data[20 * i + j] != '\0') |
448 | 520 | break; |
449 | 1.58k | } |
450 | | |
451 | | /* only add valid keys, i.e. those with a legal algorithm identifier & finger print */ |
452 | 536 | if (j >= 0 && cxdata[0] != 0) { |
453 | 470 | struct sc_object_id oid; |
454 | 470 | struct sc_algorithm_info * algorithm_info; /* no need to free */ |
455 | | |
456 | 470 | algorithm_info = NULL; |
457 | 470 | pubkey_info.id.len = 1; |
458 | 470 | pubkey_info.id.value[0] = i + 1; |
459 | 470 | pubkey_info.usage = key_cfg[i].pubkey_usage; |
460 | 470 | sc_format_path(key_cfg[i].pubkey_path, &pubkey_info.path); |
461 | | |
462 | 470 | strlcpy(pubkey_obj.label, key_cfg[i].label, sizeof(pubkey_obj.label)); |
463 | 470 | pubkey_obj.flags = SC_PKCS15_CO_FLAG_MODIFIABLE; |
464 | | |
465 | 470 | if (cxdata[0] == SC_OPENPGP_KEYALGO_ECDH || |
466 | 416 | cxdata[0] == SC_OPENPGP_KEYALGO_ECDSA || |
467 | 376 | cxdata[0] == SC_OPENPGP_KEYALGO_EDDSA) { |
468 | | /* Last byte could be Import-Format of private key, let's ignore it, |
469 | | * as it is not part of OID */ |
470 | 112 | if (cxdata[cxdata_len-1] == SC_OPENPGP_KEYFORMAT_EC_STD || |
471 | 68 | cxdata[cxdata_len-1] == SC_OPENPGP_KEYFORMAT_EC_STDPUB) |
472 | 53 | cxdata_len--; |
473 | 112 | r = sc_asn1_decode_object_id(&cxdata[1], cxdata_len-1, &oid); |
474 | 112 | if (r != SC_SUCCESS) { |
475 | 48 | sc_log(ctx, "Failed to parse OID for elliptic curve algorithm"); |
476 | 48 | } |
477 | 112 | } |
478 | | |
479 | 470 | switch (cxdata[0]) { |
480 | 54 | case SC_OPENPGP_KEYALGO_ECDH: |
481 | 54 | if (sc_compare_oid(&oid, &curve25519_oid)) { |
482 | 0 | if ((algorithm_info = sc_card_find_xeddsa_alg(card, 0, &oid))) |
483 | 0 | pubkey_info.field_length = algorithm_info->key_length; |
484 | 0 | else { |
485 | 0 | sc_log(ctx, "algorithm not found"); |
486 | 0 | continue; |
487 | 0 | } |
488 | 0 | break; |
489 | 0 | } |
490 | | /* Fall through */ |
491 | 94 | case SC_OPENPGP_KEYALGO_ECDSA: |
492 | 94 | if((algorithm_info = sc_card_find_ec_alg(card, 0, &oid))) |
493 | 0 | pubkey_info.field_length = algorithm_info->key_length; |
494 | 94 | else { |
495 | 94 | sc_log(ctx, "algorithm not found"); |
496 | 94 | continue; |
497 | 94 | } |
498 | 0 | break; |
499 | 18 | case SC_OPENPGP_KEYALGO_EDDSA: |
500 | 18 | if ((algorithm_info = sc_card_find_eddsa_alg(card, 0, &oid))) |
501 | 0 | pubkey_info.field_length = algorithm_info->key_length; |
502 | 18 | else { |
503 | 18 | sc_log(ctx, "algorithm not found"); |
504 | 18 | continue; |
505 | 18 | } |
506 | 0 | break; |
507 | 470 | } |
508 | | |
509 | 358 | switch (cxdata[0]) { |
510 | 0 | case SC_OPENPGP_KEYALGO_EDDSA: |
511 | | /* assuming Ed25519 as it is the only supported now */ |
512 | | /* Filter out invalid usage: ED does not support anything but sign */ |
513 | 0 | pubkey_info.usage &= PGP_SIG_PUBKEY_USAGE; |
514 | 0 | r = sc_pkcs15emu_add_eddsa_pubkey(p15card, &pubkey_obj, &pubkey_info); |
515 | 0 | break; |
516 | 0 | case SC_OPENPGP_KEYALGO_ECDH: |
517 | | /* This can result in either ECDSA key or EC_MONTGOMERY |
518 | | * so we need to check OID */ |
519 | 0 | if (sc_compare_oid(&oid, &curve25519_oid)) { |
520 | | /* XXX What can this key do? */ |
521 | 0 | pubkey_info.usage = SC_PKCS15_PRKEY_USAGE_DERIVE; |
522 | 0 | r = sc_pkcs15emu_add_xeddsa_pubkey(p15card, &pubkey_obj, &pubkey_info); |
523 | 0 | break; |
524 | 0 | } |
525 | 0 | pubkey_info.usage = SC_PKCS15_PRKEY_USAGE_DERIVE; |
526 | 0 | r = sc_pkcs15emu_add_ec_pubkey(p15card, &pubkey_obj, &pubkey_info); |
527 | 0 | break; |
528 | 0 | case SC_OPENPGP_KEYALGO_ECDSA: |
529 | 0 | pubkey_info.usage = PGP_SIG_PUBKEY_USAGE; |
530 | 0 | r = sc_pkcs15emu_add_ec_pubkey(p15card, &pubkey_obj, &pubkey_info); |
531 | 0 | break; |
532 | 227 | case SC_OPENPGP_KEYALGO_RSA: |
533 | 227 | if (cxdata_len >= 3) { |
534 | | /* with Authentication pubkey, can only encrypt if can change MSE */ |
535 | 213 | if (i == 2 && !(priv->ext_caps & EXT_CAP_MSE)) { |
536 | 69 | pubkey_info.usage &= ~PGP_ENC_PUBKEY_USAGE; |
537 | 69 | } |
538 | 213 | pubkey_info.modulus_length = bebytes2ushort(cxdata + 1); |
539 | 213 | r = sc_pkcs15emu_add_rsa_pubkey(p15card, &pubkey_obj, &pubkey_info); |
540 | 213 | break; |
541 | 213 | } |
542 | | /* Fall through */ |
543 | 145 | default: |
544 | 145 | sc_log(ctx, "Invalid algorithm identifier %x (length = %d)", |
545 | 358 | cxdata[0], r); |
546 | 358 | } |
547 | | |
548 | 358 | if (r < 0) { |
549 | 4 | r = SC_ERROR_INTERNAL; |
550 | 4 | goto failed; |
551 | 4 | } |
552 | 358 | } |
553 | 536 | } |
554 | | |
555 | | /* Check if certificate DO 7F21 holds data */ |
556 | 177 | sc_format_path("7F21", &path); |
557 | 177 | r = sc_select_file(card, &path, &file); |
558 | 177 | if (r < 0) |
559 | 37 | goto failed; |
560 | | |
561 | 191 | for(u8 i=0; i<PGP_MAX_NUM_CERTS; i++) { |
562 | 185 | struct sc_pkcs15_cert_info cert_info; |
563 | 185 | struct sc_pkcs15_object cert_obj; |
564 | 185 | u8* buffer = malloc(MAX_OPENPGP_DO_SIZE); |
565 | 185 | int resp_len = 0; |
566 | | |
567 | 185 | if (buffer == NULL) |
568 | 0 | goto failed; |
569 | | |
570 | 185 | memset(&cert_info, 0, sizeof(cert_info)); |
571 | 185 | memset(&cert_obj, 0, sizeof(cert_obj)); |
572 | | |
573 | | /* try to SELECT DATA. Will only work for OpenPGP >= v3, errors are non-critical */ |
574 | 185 | sc_card_ctl(card, SC_CARDCTL_OPENPGP_SELECT_DATA, &i); |
575 | | |
576 | 185 | sc_format_path(certs[i].path, &cert_info.path); |
577 | | |
578 | | /* Certificate ID. We use the same ID as the authentication key */ |
579 | 185 | sc_pkcs15_format_id(certs[i].id, &cert_info.id); |
580 | | |
581 | 185 | resp_len = sc_get_data(card, 0x7F21, buffer, MAX_OPENPGP_DO_SIZE); |
582 | | |
583 | | /* Response length => free buffer and continue with next id */ |
584 | 185 | if (resp_len == 0) { |
585 | 39 | free(buffer); |
586 | 39 | continue; |
587 | 39 | } |
588 | | |
589 | | /* Catch error during sc_get_data */ |
590 | 146 | if (resp_len < 0) { |
591 | 101 | free(buffer); |
592 | 101 | goto failed; |
593 | 101 | } |
594 | | |
595 | | /* Assemble certificate info struct, based on `certs` array */ |
596 | 45 | cert_info.value.len = resp_len; |
597 | 45 | cert_info.value.value = buffer; |
598 | 45 | cert_info.authority = certs[i].authority; |
599 | 45 | cert_obj.flags = certs[i].obj_flags; |
600 | | |
601 | | /* Object label */ |
602 | 45 | strlcpy(cert_obj.label, certs[i].label, sizeof(cert_obj.label)); |
603 | | |
604 | 45 | r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info); |
605 | 45 | if (r < 0) { |
606 | 0 | free(buffer); |
607 | 0 | goto failed; |
608 | 0 | } |
609 | | |
610 | | /* only iterate, for OpenPGP >= v3, thus break on < v3 */ |
611 | 45 | if (card->type < SC_CARD_TYPE_OPENPGP_V3) |
612 | 33 | break; |
613 | 45 | } |
614 | | |
615 | | /* Add PKCS#15 DATA objects from other OpenPGP card DOs. The return |
616 | | * value is ignored, so this will not cause initialization to fail. |
617 | | */ |
618 | 39 | sc_pkcs15emu_openpgp_add_data(p15card); |
619 | | |
620 | 3.73k | failed: |
621 | 3.73k | if (r < 0) { |
622 | 3.49k | sc_log(card->ctx, |
623 | 3.49k | "Failed to initialize OpenPGP emulation: %s\n", |
624 | 3.49k | sc_strerror(r)); |
625 | 3.49k | sc_pkcs15_card_clear(p15card); |
626 | 3.49k | } |
627 | 3.73k | sc_file_free(file); |
628 | 3.73k | LOG_FUNC_RETURN(ctx, r); |
629 | 3.73k | } |
630 | | |
631 | | // see https://stackoverflow.com/a/10536254 for explanation |
632 | | #define LEN_MAX_INT_AS_STR (3 * sizeof(int) + 2) |
633 | | |
634 | | static int |
635 | | sc_pkcs15emu_openpgp_add_data(sc_pkcs15_card_t *p15card) |
636 | 39 | { |
637 | 39 | sc_context_t *ctx = p15card->card->ctx; |
638 | 39 | int i, r; |
639 | | |
640 | 39 | LOG_FUNC_CALLED(ctx); |
641 | | /* Optional private use DOs 0101 to 0104 */ |
642 | 195 | for (i = 1; i <= PGP_NUM_PRIVDO; i++) { |
643 | 156 | sc_pkcs15_data_info_t dat_info; |
644 | 156 | sc_pkcs15_object_t dat_obj; |
645 | 156 | char name[6 + LEN_MAX_INT_AS_STR]; |
646 | 156 | char path[7 + LEN_MAX_INT_AS_STR]; |
647 | 156 | u8 content[254]; |
648 | 156 | memset(&dat_info, 0, sizeof(dat_info)); |
649 | 156 | memset(&dat_obj, 0, sizeof(dat_obj)); |
650 | | |
651 | 156 | snprintf(name, 8, "PrivDO%d", i); |
652 | 156 | snprintf(path, 9, "3F00010%d", i); |
653 | | |
654 | | /* Check if the DO can be read and is not empty. Otherwise we |
655 | | * won't expose a PKCS#15 DATA object. |
656 | | */ |
657 | 156 | r = read_file(p15card->card, path, content, sizeof(content)); |
658 | 156 | if (r <= 0 ) { |
659 | 85 | sc_log(ctx, "Cannot read DO 010%d or there is no data in it", i); |
660 | | /* Skip */ |
661 | 85 | continue; |
662 | 85 | } |
663 | 71 | sc_format_path(path, &dat_info.path); |
664 | 71 | strlcpy(dat_obj.label, name, sizeof(dat_obj.label)); |
665 | 71 | strlcpy(dat_info.app_label, name, sizeof(dat_info.app_label)); |
666 | | |
667 | | /* Add DATA object to slot protected by PIN2 (PW1 with Ref 0x82) */ |
668 | 71 | dat_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE | SC_PKCS15_CO_FLAG_MODIFIABLE; |
669 | 71 | dat_obj.auth_id.len = 1; |
670 | 71 | if (i == 1 || i == 3) |
671 | 37 | dat_obj.auth_id.value[0] = 2; |
672 | 34 | else |
673 | 34 | dat_obj.auth_id.value[0] = 3; |
674 | | |
675 | 71 | sc_log(ctx, "Add %s data object", name); |
676 | 71 | r = sc_pkcs15emu_add_data_object(p15card, &dat_obj, &dat_info); |
677 | 71 | LOG_TEST_RET(ctx, r, "Could not add data object to framework"); |
678 | 71 | } |
679 | 39 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
680 | 39 | } |
681 | | |
682 | | static int openpgp_detect_card(sc_pkcs15_card_t *p15card) |
683 | 65.4k | { |
684 | 65.4k | if (p15card->card->type == SC_CARD_TYPE_OPENPGP_BASE |
685 | 61.9k | || p15card->card->type == SC_CARD_TYPE_OPENPGP_V1 |
686 | 61.9k | || p15card->card->type == SC_CARD_TYPE_OPENPGP_V2 |
687 | 61.9k | || p15card->card->type == SC_CARD_TYPE_OPENPGP_GNUK |
688 | 61.7k | || p15card->card->type == SC_CARD_TYPE_OPENPGP_V3) |
689 | 3.73k | return SC_SUCCESS; |
690 | 61.7k | else |
691 | 61.7k | return SC_ERROR_WRONG_CARD; |
692 | 65.4k | } |
693 | | |
694 | | int sc_pkcs15emu_openpgp_init_ex(sc_pkcs15_card_t *p15card, struct sc_aid *aid) |
695 | 65.4k | { |
696 | 65.4k | if (openpgp_detect_card(p15card)) |
697 | 61.7k | return SC_ERROR_WRONG_CARD; |
698 | 3.73k | return sc_pkcs15emu_openpgp_init(p15card); |
699 | 65.4k | } |