/src/opensc/src/libopensc/pkcs15-din-66291.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * PKCS15 emulation layer for DIN 66291–4 profile. |
3 | | * |
4 | | * Copyright (C) 2017, Frank Morgner |
5 | | * |
6 | | * This library is free software; you can redistribute it and/or |
7 | | * modify it under the terms of the GNU Lesser General Public |
8 | | * License as published by the Free Software Foundation; either |
9 | | * version 2.1 of the License, or (at your option) any later version. |
10 | | * |
11 | | * This library is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | | * Lesser General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU Lesser General Public |
17 | | * License along with this library; if not, write to the Free Software |
18 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
19 | | */ |
20 | | |
21 | | |
22 | | #ifdef HAVE_CONFIG_H |
23 | | #include <config.h> |
24 | | #endif |
25 | | |
26 | | #include "internal.h" |
27 | | #include "common/compat_strlcpy.h" |
28 | | #include "log.h" |
29 | | #include "pkcs15.h" |
30 | | #include <stdlib.h> |
31 | | #include <string.h> |
32 | | |
33 | | static const unsigned char aid_CIA[] = {0xE8, 0x28, 0xBD, 0x08, 0x0F, |
34 | | 0xA0, 0x00, 0x00, 0x01, 0x67, 0x45, 0x53, 0x49, 0x47, 0x4E}; |
35 | | static const unsigned char aid_ESIGN[] = {0xA0, 0x00, 0x00, 0x01, 0x67, |
36 | | 0x45, 0x53, 0x49, 0x47, 0x4E}; |
37 | | static const unsigned char aid_gematik_egk[] = {0xD2, 0x76, |
38 | | 0x00, 0x01, 0x44, 0x80, 0x00}; |
39 | | |
40 | | static int |
41 | | sc_pkcs15emu_din_66291_init(sc_pkcs15_card_t *p15card) |
42 | 0 | { |
43 | | /* EF.C.CH.AUT |
44 | | * fileIdentifier ´C5 00´ |
45 | | * shortFileIdentifier ´01´= 1 |
46 | | * PrK.CH.AUT |
47 | | * keyIdentifier ´02´ = 2 |
48 | | * privateKey …, Moduluslänge 2048 Bit |
49 | | * |
50 | | * EF.C.CH.ENC |
51 | | * fileIdentifier ´C2 00´ |
52 | | * shortFileIdentifier ´02´= 2 |
53 | | * PrK.CH.ENC |
54 | | * keyIdentifier ´03´ = 3 |
55 | | * privateKey …, Moduluslänge 2048 Bit |
56 | | */ |
57 | 0 | sc_path_t path; |
58 | 0 | size_t i; |
59 | 0 | struct sc_pin_cmd_data data; |
60 | 0 | const unsigned char user_pin_ref = 0x02; |
61 | |
|
62 | 0 | sc_path_set(&path, SC_PATH_TYPE_DF_NAME, aid_ESIGN, sizeof aid_ESIGN, 0, 0); |
63 | 0 | if (SC_SUCCESS != sc_select_file(p15card->card, &path, NULL)) |
64 | 0 | return SC_ERROR_WRONG_CARD; |
65 | | |
66 | 0 | memset(&data, 0, sizeof(data)); |
67 | 0 | data.cmd = SC_PIN_CMD_GET_INFO; |
68 | 0 | data.pin_type = SC_AC_CHV; |
69 | 0 | data.pin_reference = user_pin_ref; |
70 | |
|
71 | 0 | if (SC_SUCCESS == sc_pin_cmd(p15card->card, &data, NULL)) { |
72 | 0 | const unsigned char user_pin_id = 1; |
73 | |
|
74 | 0 | for (i = 0; i < 2; i++) { |
75 | 0 | const char *pin_names[3] = { "PIN", "PUK" }; |
76 | 0 | const int pin_min[] = {6, 10}; |
77 | 0 | const int pin_max[] = {8, 8}; |
78 | 0 | const unsigned char user_puk_id = 2; |
79 | 0 | const int pin_id[] = {user_pin_id, user_puk_id}; |
80 | 0 | const int pin_flags[] = {SC_PKCS15_PIN_FLAG_INITIALIZED, |
81 | 0 | SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN|SC_PKCS15_PIN_FLAG_UNBLOCK_DISABLED}; |
82 | 0 | const int max_tries[] = {3, 10}; |
83 | 0 | struct sc_pkcs15_auth_info pin_info; |
84 | 0 | struct sc_pkcs15_object pin_obj; |
85 | |
|
86 | 0 | memset(&pin_info, 0, sizeof(pin_info)); |
87 | 0 | memset(&pin_obj, 0, sizeof(pin_obj)); |
88 | |
|
89 | 0 | pin_info.auth_id.value[0] = pin_id[i]; |
90 | 0 | pin_info.auth_id.len = 1; |
91 | 0 | pin_info.auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN; |
92 | 0 | pin_info.attrs.pin.flags = pin_flags[i]; |
93 | 0 | pin_info.attrs.pin.type = SC_PKCS15_PIN_TYPE_ASCII_NUMERIC; |
94 | 0 | pin_info.attrs.pin.min_length = pin_min[i]; |
95 | 0 | pin_info.attrs.pin.stored_length = pin_max[i]; |
96 | 0 | pin_info.attrs.pin.max_length = pin_max[i]; |
97 | 0 | pin_info.max_tries = max_tries[i]; |
98 | |
|
99 | 0 | strlcpy(pin_obj.label, pin_names[i], sizeof(pin_obj.label)); |
100 | | |
101 | | /* catch the differences between PIN and PUK */ |
102 | 0 | if (pin_flags[i] & SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN) { |
103 | 0 | pin_info.tries_left = max_tries[i]; |
104 | 0 | } else { |
105 | 0 | pin_info.attrs.pin.reference = user_pin_ref; |
106 | 0 | pin_info.tries_left = data.pin1.tries_left; |
107 | 0 | pin_info.logged_in = data.pin1.logged_in; |
108 | 0 | pin_obj.auth_id.value[0] = user_puk_id; |
109 | 0 | pin_obj.auth_id.len = 1; |
110 | 0 | } |
111 | |
|
112 | 0 | if (0 > sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info)) { |
113 | 0 | sc_pkcs15_card_clear(p15card); |
114 | 0 | return SC_ERROR_INTERNAL; |
115 | 0 | } |
116 | 0 | } |
117 | | |
118 | 0 | for (i = 0; i < 2; i++) { |
119 | 0 | struct sc_aid aid; |
120 | 0 | const char *din_66291_cert_fids[] = { "C500", "C200"}; |
121 | 0 | const char prk_id[] = { 0x10, 0x11,}; |
122 | 0 | struct sc_pkcs15_cert_info cert_info; |
123 | 0 | struct sc_pkcs15_object cert_obj; |
124 | 0 | struct sc_pkcs15_prkey_info prkey_info; |
125 | 0 | struct sc_pkcs15_object prkey_obj; |
126 | 0 | const int prk_usage[2] = { |
127 | 0 | SC_PKCS15_PRKEY_USAGE_ENCRYPT |
128 | 0 | | SC_PKCS15_PRKEY_USAGE_DECRYPT |
129 | 0 | | SC_PKCS15_PRKEY_USAGE_SIGN, |
130 | 0 | SC_PKCS15_PRKEY_USAGE_NONREPUDIATION}; |
131 | |
|
132 | 0 | memcpy(aid.value, aid_CIA, sizeof aid_CIA); |
133 | 0 | aid.len = sizeof aid_CIA; |
134 | |
|
135 | 0 | memset(&prkey_info, 0, sizeof(prkey_info)); |
136 | 0 | memset(&prkey_obj, 0, sizeof(prkey_obj)); |
137 | 0 | memset(&cert_info, 0, sizeof(cert_info)); |
138 | 0 | memset(&cert_obj, 0, sizeof(cert_obj)); |
139 | | |
140 | |
|
141 | 0 | sc_format_path(din_66291_cert_fids[i], &cert_info.path); |
142 | 0 | if (SC_SUCCESS != sc_select_file(p15card->card, &cert_info.path, NULL)) |
143 | 0 | continue; |
144 | 0 | cert_info.path.aid = aid; |
145 | |
|
146 | 0 | cert_info.id.value[0] = prk_id[i]; |
147 | 0 | cert_info.id.len = 1; |
148 | |
|
149 | 0 | if (0 > sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info)) |
150 | 0 | continue; |
151 | | |
152 | 0 | if (i == 0) { |
153 | 0 | sc_pkcs15_cert_t *cert; |
154 | 0 | if (SC_SUCCESS == sc_pkcs15_read_certificate(p15card, &cert_info, 0, &cert)) { |
155 | 0 | static const struct sc_object_id cn_oid = {{ 2, 5, 4, 3, -1 }}; |
156 | 0 | u8 *cn_name = NULL; |
157 | 0 | size_t cn_len = 0; |
158 | 0 | sc_pkcs15_get_name_from_dn(p15card->card->ctx, cert->subject, |
159 | 0 | cert->subject_len, &cn_oid, &cn_name, &cn_len); |
160 | 0 | if (cn_len > 0) { |
161 | 0 | char *token_name = malloc(cn_len+1); |
162 | 0 | if (token_name) { |
163 | 0 | memcpy(token_name, cn_name, cn_len); |
164 | 0 | token_name[cn_len] = '\0'; |
165 | 0 | free(p15card->tokeninfo->label); |
166 | 0 | p15card->tokeninfo->label = token_name; |
167 | 0 | } |
168 | 0 | } |
169 | 0 | free(cn_name); |
170 | 0 | sc_pkcs15_free_certificate(cert); |
171 | 0 | } |
172 | 0 | } |
173 | |
|
174 | 0 | memset(&prkey_info, 0, sizeof(prkey_info)); |
175 | 0 | memset(&prkey_obj, 0, sizeof(prkey_obj)); |
176 | |
|
177 | 0 | prkey_info.id.value[0] = prk_id[i]; |
178 | 0 | prkey_info.id.len = 1; |
179 | 0 | prkey_info.usage = prk_usage[i]; |
180 | 0 | prkey_info.native = 1; |
181 | 0 | prkey_info.key_reference = prk_id[i]; |
182 | 0 | prkey_info.modulus_length = 2048; |
183 | 0 | prkey_obj.auth_id.value[0] = user_pin_id; |
184 | 0 | prkey_obj.auth_id.len = 1; |
185 | 0 | prkey_obj.user_consent = 0; |
186 | 0 | prkey_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE; |
187 | |
|
188 | 0 | if (0 > sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info)) |
189 | 0 | continue; |
190 | 0 | } |
191 | 0 | } |
192 | | |
193 | 0 | return SC_SUCCESS; |
194 | 0 | } |
195 | | |
196 | | int sc_pkcs15emu_din_66291_init_ex(sc_pkcs15_card_t *p15card, struct sc_aid *aid) |
197 | 3 | { |
198 | 3 | int r = SC_ERROR_WRONG_CARD; |
199 | 3 | sc_path_t path; |
200 | 3 | unsigned char *tokeninfo_content = NULL; |
201 | 3 | struct sc_file *file_tokeninfo = NULL; |
202 | 3 | struct sc_pkcs15_tokeninfo *tokeninfo = NULL; |
203 | 3 | sc_serial_number_t serial; |
204 | | |
205 | 3 | if (!p15card || ! p15card->card) |
206 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
207 | | |
208 | 3 | SC_FUNC_CALLED(p15card->card->ctx, 1); |
209 | | |
210 | 3 | tokeninfo = sc_pkcs15_tokeninfo_new(); |
211 | 3 | if (!p15card || !tokeninfo |
212 | 3 | || (aid && (aid->len != sizeof aid_CIA |
213 | 0 | || 0 != memcmp(aid->value, aid_CIA, sizeof aid_CIA)))) |
214 | 0 | goto err; |
215 | | |
216 | 3 | if (!p15card->tokeninfo |
217 | 3 | || !p15card->tokeninfo->profile_indication.name |
218 | 3 | || 0 != strcmp("DIN V 66291", |
219 | 3 | p15card->tokeninfo->profile_indication.name)) { |
220 | | /* it is possible that p15card->tokeninfo has not been touched yet */ |
221 | 3 | if (SC_SUCCESS == sc_path_set(&path, SC_PATH_TYPE_DF_NAME, |
222 | 3 | aid_CIA, sizeof aid_CIA, 0, 0) |
223 | 3 | && SC_SUCCESS == sc_select_file(p15card->card, &path, NULL)) { |
224 | 0 | sc_format_path("5032", &path); |
225 | 0 | if (SC_SUCCESS != sc_select_file(p15card->card, &path, &file_tokeninfo)) |
226 | 0 | goto err; |
227 | | |
228 | 0 | tokeninfo_content = malloc(file_tokeninfo->size); |
229 | 0 | if (!tokeninfo_content) |
230 | 0 | goto err; |
231 | 0 | r = sc_read_binary(p15card->card, 0, tokeninfo_content, file_tokeninfo->size, 0); |
232 | 0 | if (r < 0) |
233 | 0 | goto err; |
234 | 0 | r = sc_pkcs15_parse_tokeninfo(p15card->card->ctx, tokeninfo, tokeninfo_content, r); |
235 | 0 | if (r != SC_SUCCESS) |
236 | 0 | goto err; |
237 | | |
238 | 0 | if (!tokeninfo->profile_indication.name |
239 | 0 | || 0 != strcmp("DIN V 66291", |
240 | 0 | tokeninfo->profile_indication.name)) { |
241 | 0 | goto err; |
242 | 0 | } |
243 | 3 | } else { |
244 | | /* BARMER eGK doesn't include MF / DF.CIA_ESIGN / EF.CIA_Info |
245 | | * just detect it via its specific AID */ |
246 | 3 | if (SC_SUCCESS != sc_path_set(&path, SC_PATH_TYPE_DF_NAME, |
247 | 3 | aid_gematik_egk, sizeof aid_gematik_egk, 0, 0) |
248 | 3 | || SC_SUCCESS != sc_select_file(p15card->card, &path, NULL)) |
249 | 3 | goto err; |
250 | | |
251 | 0 | tokeninfo->profile_indication.name = strdup("DIN V 66291"); |
252 | 0 | } |
253 | 3 | } |
254 | | |
255 | 0 | if (SC_SUCCESS != sc_pkcs15emu_din_66291_init(p15card)) |
256 | 0 | goto err; |
257 | | |
258 | | /* save tokeninfo and file_tokeninfo */ |
259 | 0 | sc_pkcs15_free_tokeninfo(p15card->tokeninfo); |
260 | 0 | sc_file_free(p15card->file_tokeninfo); |
261 | 0 | p15card->tokeninfo = tokeninfo; |
262 | 0 | p15card->file_tokeninfo = file_tokeninfo; |
263 | 0 | tokeninfo = NULL; |
264 | 0 | file_tokeninfo = NULL; |
265 | | |
266 | | /* get the card serial number */ |
267 | 0 | if (!p15card->tokeninfo->serial_number |
268 | 0 | && SC_SUCCESS == sc_card_ctl(p15card->card, SC_CARDCTL_GET_SERIALNR, &serial)) { |
269 | 0 | char serial_hex[SC_MAX_SERIALNR*2+2]; |
270 | 0 | sc_bin_to_hex(serial.value, serial.len , serial_hex, sizeof serial_hex, 0); |
271 | 0 | set_string(&p15card->tokeninfo->serial_number, serial_hex); |
272 | 0 | } |
273 | |
|
274 | 0 | r = SC_SUCCESS; |
275 | |
|
276 | 3 | err: |
277 | 3 | sc_pkcs15_free_tokeninfo(tokeninfo); |
278 | 3 | sc_file_free(file_tokeninfo); |
279 | 3 | free(tokeninfo_content); |
280 | | |
281 | 3 | return r; |
282 | 0 | } |