/src/opensc/src/libopensc/pkcs15-pubkey.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * pkcs15-pubkey.c: PKCS #15 public key functions |
3 | | * |
4 | | * Copyright (C) 2002 Juha Yrjölä <juha.yrjola@iki.fi> |
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 | | #ifdef HAVE_CONFIG_H |
22 | | #include "config.h" |
23 | | #endif |
24 | | |
25 | | #include <assert.h> |
26 | | #include <fcntl.h> |
27 | | #include <stdio.h> |
28 | | #include <stdlib.h> |
29 | | #include <string.h> |
30 | | |
31 | | #ifdef _WIN32 |
32 | | #include <io.h> |
33 | | #else |
34 | | #include <unistd.h> |
35 | | #endif |
36 | | |
37 | | #ifdef ENABLE_OPENSSL |
38 | | #include <openssl/bn.h> |
39 | | #include <openssl/rsa.h> |
40 | | #include <openssl/evp.h> |
41 | | #include <openssl/err.h> |
42 | | #if OPENSSL_VERSION_NUMBER >= 0x30000000L |
43 | | # include <openssl/core_names.h> |
44 | | # include <openssl/param_build.h> |
45 | | #endif |
46 | | #ifndef OPENSSL_NO_EC |
47 | | #include <openssl/ec.h> |
48 | | #endif |
49 | | #endif |
50 | | |
51 | | #include "internal.h" |
52 | | #include "asn1.h" |
53 | | #include "pkcs15.h" |
54 | | |
55 | | |
56 | | #define C_ASN1_PKINFO_ATTR_SIZE 3 |
57 | | static const struct sc_asn1_entry c_asn1_pkinfo[C_ASN1_PKINFO_ATTR_SIZE] = { |
58 | | { "algorithm", SC_ASN1_ALGORITHM_ID, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL }, |
59 | | { "subjectPublicKey", SC_ASN1_BIT_STRING_NI, SC_ASN1_TAG_BIT_STRING, SC_ASN1_ALLOC, NULL, NULL}, |
60 | | { NULL, 0, 0, 0, NULL, NULL } |
61 | | }; |
62 | | |
63 | | #define C_ASN1_COM_KEY_ATTR_SIZE 6 |
64 | | static const struct sc_asn1_entry c_asn1_com_key_attr[C_ASN1_COM_KEY_ATTR_SIZE] = { |
65 | | { "iD", SC_ASN1_PKCS15_ID, SC_ASN1_TAG_OCTET_STRING, 0, NULL, NULL }, |
66 | | { "usage", SC_ASN1_BIT_FIELD, SC_ASN1_TAG_BIT_STRING, 0, NULL, NULL }, |
67 | | { "native", SC_ASN1_BOOLEAN, SC_ASN1_TAG_BOOLEAN, SC_ASN1_OPTIONAL, NULL, NULL }, |
68 | | { "accessFlags", SC_ASN1_BIT_FIELD, SC_ASN1_TAG_BIT_STRING, SC_ASN1_OPTIONAL, NULL, NULL }, |
69 | | { "keyReference",SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, |
70 | | { NULL, 0, 0, 0, NULL, NULL } |
71 | | }; |
72 | | |
73 | | #define C_ASN1_COM_PUBKEY_ATTR_SIZE 2 |
74 | | static const struct sc_asn1_entry c_asn1_com_pubkey_attr[C_ASN1_COM_PUBKEY_ATTR_SIZE] = { |
75 | | { "subjectName", SC_ASN1_OCTET_STRING, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, |
76 | | SC_ASN1_EMPTY_ALLOWED | SC_ASN1_ALLOC | SC_ASN1_OPTIONAL, NULL, NULL }, |
77 | | { NULL, 0, 0, 0, NULL, NULL } |
78 | | }; |
79 | | |
80 | | #define C_ASN1_RSAKEY_VALUE_CHOICE_SIZE 3 |
81 | | static const struct sc_asn1_entry c_asn1_rsakey_value_choice[C_ASN1_RSAKEY_VALUE_CHOICE_SIZE] = { |
82 | | { "path", SC_ASN1_PATH, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_EMPTY_ALLOWED, NULL, NULL }, |
83 | | { "direct", SC_ASN1_OCTET_STRING, SC_ASN1_CTX | 0 | SC_ASN1_CONS, SC_ASN1_OPTIONAL | SC_ASN1_ALLOC, NULL, NULL }, |
84 | | { NULL, 0, 0, 0, NULL, NULL } |
85 | | }; |
86 | | |
87 | | #define C_ASN1_RSAKEY_ATTR_SIZE 4 |
88 | | static const struct sc_asn1_entry c_asn1_rsakey_attr[C_ASN1_RSAKEY_ATTR_SIZE] = { |
89 | | { "value", SC_ASN1_CHOICE, 0, 0, NULL, NULL }, |
90 | | { "modulusLength", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, 0, NULL, NULL }, |
91 | | { "keyInfo", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, |
92 | | { NULL, 0, 0, 0, NULL, NULL } |
93 | | }; |
94 | | |
95 | | #define C_ASN1_ECKEY_VALUE_CHOICE_SIZE 3 |
96 | | static const struct sc_asn1_entry c_asn1_eckey_value_choice[C_ASN1_ECKEY_VALUE_CHOICE_SIZE] = { |
97 | | { "path", SC_ASN1_PATH, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_EMPTY_ALLOWED, NULL, NULL }, |
98 | | { "direct", SC_ASN1_OCTET_STRING, SC_ASN1_CTX | 0 | SC_ASN1_CONS, SC_ASN1_OPTIONAL | SC_ASN1_ALLOC, NULL, NULL }, |
99 | | { NULL, 0, 0, 0, NULL, NULL } |
100 | | }; |
101 | | |
102 | | #define C_ASN1_ECKEY_ATTR_SIZE 3 |
103 | | static const struct sc_asn1_entry c_asn1_eckey_attr[C_ASN1_ECKEY_ATTR_SIZE] = { |
104 | | { "value", SC_ASN1_CHOICE, 0, 0, NULL, NULL }, |
105 | | { "keyInfo", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, |
106 | | { NULL, 0, 0, 0, NULL, NULL } |
107 | | }; |
108 | | |
109 | | #define C_ASN1_RSA_TYPE_ATTR_SIZE 2 |
110 | | static const struct sc_asn1_entry c_asn1_rsa_type_attr[C_ASN1_RSA_TYPE_ATTR_SIZE] = { |
111 | | { "publicRSAKeyAttributes", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL }, |
112 | | { NULL, 0, 0, 0, NULL, NULL } |
113 | | }; |
114 | | |
115 | | #define C_ASN1_EC_TYPE_ATTR_SIZE 2 |
116 | | static const struct sc_asn1_entry c_asn1_ec_type_attr[C_ASN1_EC_TYPE_ATTR_SIZE] = { |
117 | | { "publicECKeyAttributes", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL }, |
118 | | { NULL, 0, 0, 0, NULL, NULL } |
119 | | }; |
120 | | |
121 | | #define C_ASN1_GOST3410KEY_ATTR_SIZE 5 |
122 | | static const struct sc_asn1_entry c_asn1_gostr3410key_attr[C_ASN1_GOST3410KEY_ATTR_SIZE] = { |
123 | | { "value", SC_ASN1_PATH, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL }, |
124 | | { "params_r3410", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, 0, NULL, NULL }, |
125 | | { "params_r3411", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, |
126 | | { "params_28147", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, |
127 | | { NULL, 0, 0, 0, NULL, NULL } |
128 | | }; |
129 | | |
130 | | #define C_ASN1_GOST3410_TYPE_ATTR_SIZE 2 |
131 | | static const struct sc_asn1_entry c_asn1_gostr3410_type_attr[C_ASN1_GOST3410_TYPE_ATTR_SIZE] = { |
132 | | { "publicGOSTR3410KeyAttributes", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL }, |
133 | | { NULL, 0, 0, 0, NULL, NULL } |
134 | | }; |
135 | | |
136 | | #define C_ASN1_PUBKEY_CHOICE_SIZE 4 |
137 | | static const struct sc_asn1_entry c_asn1_pubkey_choice[C_ASN1_PUBKEY_CHOICE_SIZE] = { |
138 | | { "publicRSAKey", SC_ASN1_PKCS15_OBJECT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL }, |
139 | | { "publicGOSTR3410Key", SC_ASN1_PKCS15_OBJECT, 4 | SC_ASN1_CTX | SC_ASN1_CONS, 0, NULL, NULL }, |
140 | | { "publicECKey", SC_ASN1_PKCS15_OBJECT, 0 | SC_ASN1_CTX | SC_ASN1_CONS, 0, NULL, NULL }, |
141 | | /*TODO: -DEE not clear EC is needed here as look like it is for pukdf */ |
142 | | { NULL, 0, 0, 0, NULL, NULL } |
143 | | }; |
144 | | |
145 | | #define C_ASN1_PUBKEY_SIZE 2 |
146 | | static const struct sc_asn1_entry c_asn1_pubkey[C_ASN1_PUBKEY_SIZE] = { |
147 | | { "publicKey", SC_ASN1_CHOICE, 0, 0, NULL, NULL }, |
148 | | { NULL, 0, 0, 0, NULL, NULL } |
149 | | }; |
150 | | |
151 | | int sc_pkcs15_pubkey_from_spki_sequence(sc_context_t *ctx, const u8 *buf, size_t buflen, sc_pkcs15_pubkey_t ** outpubkey); |
152 | | |
153 | | int |
154 | | sc_pkcs15_decode_pubkey_direct_value(struct sc_pkcs15_card *p15card, struct sc_pkcs15_object *obj) |
155 | 0 | { |
156 | 0 | struct sc_context *ctx = p15card->card->ctx; |
157 | 0 | struct sc_pkcs15_pubkey_info *info = (struct sc_pkcs15_pubkey_info *) obj->data; |
158 | |
|
159 | 0 | LOG_FUNC_CALLED(ctx); |
160 | 0 | if (obj->content.value == NULL || obj->content.len == 0) |
161 | 0 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
162 | | |
163 | 0 | if (*obj->content.value == (SC_ASN1_TAG_CONSTRUCTED | SC_ASN1_TAG_SEQUENCE)) { |
164 | | /* RAW direct value */ |
165 | 0 | sc_log(ctx, "Decoding 'RAW' direct value"); |
166 | 0 | info->direct.raw.value = malloc(obj->content.len); |
167 | 0 | if (!info->direct.raw.value) |
168 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); |
169 | 0 | memcpy(info->direct.raw.value, obj->content.value, obj->content.len); |
170 | 0 | info->direct.raw.len = obj->content.len; |
171 | | |
172 | | /* TODO: encode 'spki' direct value */ |
173 | 0 | } |
174 | | |
175 | 0 | if (*obj->content.value == (SC_ASN1_TAG_CONTEXT | SC_ASN1_TAG_CONSTRUCTED | 0x01)) { |
176 | 0 | struct sc_pkcs15_pubkey *pubkey = NULL; |
177 | 0 | int rv; |
178 | | |
179 | | /* SPKI direct value */ |
180 | 0 | sc_log(ctx, "Decoding 'SPKI' direct value"); |
181 | 0 | info->direct.spki.value = malloc(obj->content.len); |
182 | 0 | if (!info->direct.spki.value) |
183 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); |
184 | 0 | memcpy(info->direct.spki.value, obj->content.value, obj->content.len); |
185 | 0 | info->direct.spki.len = obj->content.len; |
186 | |
|
187 | 0 | rv = sc_pkcs15_pubkey_from_spki_sequence(ctx, info->direct.spki.value, info->direct.spki.len, &pubkey); |
188 | 0 | LOG_TEST_RET(ctx, rv, "Failed to decode 'SPKI' direct value"); |
189 | | |
190 | 0 | rv = sc_pkcs15_encode_pubkey(ctx, pubkey, &info->direct.raw.value, &info->direct.raw.len); |
191 | 0 | sc_pkcs15_free_pubkey(pubkey); |
192 | 0 | LOG_TEST_RET(ctx, rv, "Failed to encode 'RAW' direct value"); |
193 | 0 | } |
194 | | |
195 | 0 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
196 | 0 | } |
197 | | |
198 | | |
199 | | int sc_pkcs15_decode_pukdf_entry(struct sc_pkcs15_card *p15card, |
200 | | struct sc_pkcs15_object *obj, |
201 | | const u8 ** buf, size_t *buflen) |
202 | 0 | { |
203 | 0 | struct sc_context *ctx = p15card->card->ctx; |
204 | 0 | struct sc_pkcs15_pubkey_info *info; |
205 | 0 | int r, gostr3410_params[3]; |
206 | 0 | struct sc_pkcs15_keyinfo_gostparams *keyinfo_gostparams; |
207 | 0 | size_t usage_len, af_len; |
208 | 0 | struct sc_pkcs15_der *der = &obj->content; |
209 | 0 | struct sc_asn1_entry asn1_com_key_attr[C_ASN1_COM_KEY_ATTR_SIZE]; |
210 | 0 | struct sc_asn1_entry asn1_com_pubkey_attr[C_ASN1_COM_PUBKEY_ATTR_SIZE]; |
211 | 0 | struct sc_asn1_entry asn1_rsakey_value_choice[C_ASN1_RSAKEY_VALUE_CHOICE_SIZE]; |
212 | 0 | struct sc_asn1_entry asn1_rsakey_attr[C_ASN1_RSAKEY_ATTR_SIZE]; |
213 | 0 | struct sc_asn1_entry asn1_rsa_type_attr[C_ASN1_RSA_TYPE_ATTR_SIZE]; |
214 | 0 | struct sc_asn1_entry asn1_eckey_value_choice[C_ASN1_ECKEY_VALUE_CHOICE_SIZE]; |
215 | 0 | struct sc_asn1_entry asn1_eckey_attr[C_ASN1_ECKEY_ATTR_SIZE]; |
216 | 0 | struct sc_asn1_entry asn1_ec_type_attr[C_ASN1_EC_TYPE_ATTR_SIZE]; |
217 | 0 | struct sc_asn1_entry asn1_gostr3410key_attr[C_ASN1_GOST3410KEY_ATTR_SIZE]; |
218 | 0 | struct sc_asn1_entry asn1_gostr3410_type_attr[C_ASN1_GOST3410_TYPE_ATTR_SIZE]; |
219 | 0 | struct sc_asn1_entry asn1_pubkey_choice[C_ASN1_PUBKEY_CHOICE_SIZE]; |
220 | 0 | struct sc_asn1_entry asn1_pubkey[C_ASN1_PUBKEY_SIZE]; |
221 | 0 | struct sc_asn1_pkcs15_object rsakey_obj = { obj, asn1_com_key_attr, |
222 | 0 | asn1_com_pubkey_attr, asn1_rsa_type_attr }; |
223 | 0 | struct sc_asn1_pkcs15_object eckey_obj = { obj, asn1_com_key_attr, |
224 | 0 | asn1_com_pubkey_attr, asn1_ec_type_attr }; |
225 | 0 | struct sc_asn1_pkcs15_object gostr3410key_obj = { obj, asn1_com_key_attr, |
226 | 0 | asn1_com_pubkey_attr, asn1_gostr3410_type_attr }; |
227 | |
|
228 | 0 | info = calloc(1, sizeof *info); |
229 | 0 | if (info == NULL) { |
230 | 0 | r = SC_ERROR_OUT_OF_MEMORY; |
231 | 0 | goto err; |
232 | 0 | } |
233 | 0 | usage_len = sizeof(info->usage); |
234 | 0 | af_len = sizeof(info->access_flags); |
235 | |
|
236 | 0 | sc_copy_asn1_entry(c_asn1_pubkey, asn1_pubkey); |
237 | 0 | sc_copy_asn1_entry(c_asn1_pubkey_choice, asn1_pubkey_choice); |
238 | 0 | sc_copy_asn1_entry(c_asn1_rsa_type_attr, asn1_rsa_type_attr); |
239 | 0 | sc_copy_asn1_entry(c_asn1_rsakey_value_choice, asn1_rsakey_value_choice); |
240 | 0 | sc_copy_asn1_entry(c_asn1_rsakey_attr, asn1_rsakey_attr); |
241 | 0 | sc_copy_asn1_entry(c_asn1_ec_type_attr, asn1_ec_type_attr); |
242 | 0 | sc_copy_asn1_entry(c_asn1_eckey_value_choice, asn1_eckey_value_choice); |
243 | 0 | sc_copy_asn1_entry(c_asn1_eckey_attr, asn1_eckey_attr); |
244 | 0 | sc_copy_asn1_entry(c_asn1_gostr3410_type_attr, asn1_gostr3410_type_attr); |
245 | 0 | sc_copy_asn1_entry(c_asn1_gostr3410key_attr, asn1_gostr3410key_attr); |
246 | 0 | sc_copy_asn1_entry(c_asn1_com_pubkey_attr, asn1_com_pubkey_attr); |
247 | 0 | sc_copy_asn1_entry(c_asn1_com_key_attr, asn1_com_key_attr); |
248 | |
|
249 | 0 | sc_format_asn1_entry(asn1_com_pubkey_attr + 0, &info->subject.value, &info->subject.len, 0); |
250 | |
|
251 | 0 | sc_format_asn1_entry(asn1_pubkey_choice + 0, &rsakey_obj, NULL, 0); |
252 | 0 | sc_format_asn1_entry(asn1_pubkey_choice + 1, &gostr3410key_obj, NULL, 0); |
253 | 0 | sc_format_asn1_entry(asn1_pubkey_choice + 2, &eckey_obj, NULL, 0); |
254 | |
|
255 | 0 | sc_format_asn1_entry(asn1_rsa_type_attr + 0, asn1_rsakey_attr, NULL, 0); |
256 | |
|
257 | 0 | sc_format_asn1_entry(asn1_rsakey_value_choice + 0, &info->path, NULL, 0); |
258 | 0 | sc_format_asn1_entry(asn1_rsakey_value_choice + 1, &der->value, &der->len, 0); |
259 | |
|
260 | 0 | sc_format_asn1_entry(asn1_rsakey_attr + 0, asn1_rsakey_value_choice, NULL, 0); |
261 | 0 | sc_format_asn1_entry(asn1_rsakey_attr + 1, &info->modulus_length, NULL, 0); |
262 | |
|
263 | 0 | sc_format_asn1_entry(asn1_ec_type_attr + 0, asn1_eckey_attr, NULL, 0); |
264 | |
|
265 | 0 | sc_format_asn1_entry(asn1_eckey_value_choice + 0, &info->path, NULL, 0); |
266 | 0 | sc_format_asn1_entry(asn1_eckey_value_choice + 1, &der->value, &der->len, 0); |
267 | |
|
268 | 0 | sc_format_asn1_entry(asn1_eckey_attr + 0, asn1_eckey_value_choice, NULL, 0); |
269 | |
|
270 | 0 | sc_format_asn1_entry(asn1_gostr3410_type_attr + 0, asn1_gostr3410key_attr, NULL, 0); |
271 | |
|
272 | 0 | sc_format_asn1_entry(asn1_gostr3410key_attr + 0, &info->path, NULL, 0); |
273 | 0 | sc_format_asn1_entry(asn1_gostr3410key_attr + 1, &gostr3410_params[0], NULL, 0); |
274 | 0 | sc_format_asn1_entry(asn1_gostr3410key_attr + 2, &gostr3410_params[1], NULL, 0); |
275 | 0 | sc_format_asn1_entry(asn1_gostr3410key_attr + 3, &gostr3410_params[2], NULL, 0); |
276 | |
|
277 | 0 | sc_format_asn1_entry(asn1_com_key_attr + 0, &info->id, NULL, 0); |
278 | 0 | sc_format_asn1_entry(asn1_com_key_attr + 1, &info->usage, &usage_len, 0); |
279 | 0 | sc_format_asn1_entry(asn1_com_key_attr + 2, &info->native, NULL, 0); |
280 | 0 | sc_format_asn1_entry(asn1_com_key_attr + 3, &info->access_flags, &af_len, 0); |
281 | 0 | sc_format_asn1_entry(asn1_com_key_attr + 4, &info->key_reference, NULL, 0); |
282 | |
|
283 | 0 | sc_format_asn1_entry(asn1_pubkey + 0, asn1_pubkey_choice, NULL, 0); |
284 | | |
285 | | /* Fill in defaults */ |
286 | 0 | info->key_reference = -1; |
287 | 0 | info->native = 1; |
288 | 0 | memset(gostr3410_params, 0, sizeof(gostr3410_params)); |
289 | |
|
290 | 0 | r = sc_asn1_decode(ctx, asn1_pubkey, *buf, *buflen, buf, buflen); |
291 | 0 | if (r == SC_ERROR_ASN1_END_OF_CONTENTS) |
292 | 0 | goto err; |
293 | 0 | LOG_TEST_GOTO_ERR(ctx, r, "ASN.1 decoding failed"); |
294 | 0 | if (asn1_pubkey_choice[0].flags & SC_ASN1_PRESENT) { |
295 | 0 | obj->type = SC_PKCS15_TYPE_PUBKEY_RSA; |
296 | 0 | } else if (asn1_pubkey_choice[1].flags & SC_ASN1_PRESENT) { |
297 | 0 | obj->type = SC_PKCS15_TYPE_PUBKEY_GOSTR3410; |
298 | 0 | assert(info->modulus_length == 0); |
299 | 0 | info->modulus_length = SC_PKCS15_GOSTR3410_KEYSIZE; |
300 | 0 | assert(info->params.len == 0); |
301 | 0 | info->params.len = sizeof(struct sc_pkcs15_keyinfo_gostparams); |
302 | 0 | info->params.data = malloc(info->params.len); |
303 | 0 | if (info->params.data == NULL) { |
304 | 0 | r = SC_ERROR_OUT_OF_MEMORY; |
305 | 0 | goto err; |
306 | 0 | } |
307 | 0 | assert(sizeof(*keyinfo_gostparams) == info->params.len); |
308 | 0 | keyinfo_gostparams = info->params.data; |
309 | 0 | keyinfo_gostparams->gostr3410 = (unsigned int)gostr3410_params[0]; |
310 | 0 | keyinfo_gostparams->gostr3411 = (unsigned int)gostr3410_params[1]; |
311 | 0 | keyinfo_gostparams->gost28147 = (unsigned int)gostr3410_params[2]; |
312 | 0 | } |
313 | 0 | else if (asn1_pubkey_choice[2].flags & SC_ASN1_PRESENT) { |
314 | 0 | obj->type = SC_PKCS15_TYPE_PUBKEY_EC; |
315 | 0 | } |
316 | 0 | else { |
317 | 0 | goto err; |
318 | 0 | } |
319 | | |
320 | 0 | if (!p15card->app || !p15card->app->ddo.aid.len) { |
321 | 0 | if (!p15card->file_app) { |
322 | 0 | r = SC_ERROR_INTERNAL; |
323 | 0 | goto err; |
324 | 0 | } |
325 | 0 | r = sc_pkcs15_make_absolute_path(&p15card->file_app->path, &info->path); |
326 | 0 | if (r < 0) { |
327 | 0 | goto err; |
328 | 0 | } |
329 | 0 | } |
330 | 0 | else { |
331 | 0 | info->path.aid = p15card->app->ddo.aid; |
332 | 0 | } |
333 | 0 | sc_log(ctx, "PubKey path '%s'", sc_print_path(&info->path)); |
334 | | |
335 | | /* OpenSC 0.11.4 and older encoded "keyReference" as a negative |
336 | | value. Fixed in 0.11.5 we need to add a hack, so old cards |
337 | | continue to work. */ |
338 | 0 | if (info->key_reference < -1) |
339 | 0 | info->key_reference += 256; |
340 | |
|
341 | 0 | obj->data = info; |
342 | 0 | info = NULL; |
343 | |
|
344 | 0 | r = sc_pkcs15_decode_pubkey_direct_value(p15card, obj); |
345 | 0 | if (r < 0) { |
346 | 0 | info = obj->data; |
347 | 0 | obj->data = NULL; |
348 | 0 | } |
349 | 0 | LOG_TEST_GOTO_ERR(ctx, r, "Decode public key direct value failed"); |
350 | | |
351 | 0 | err: |
352 | 0 | if (r < 0) { |
353 | 0 | sc_pkcs15_free_pubkey_info(info); |
354 | 0 | if (der->len) { |
355 | 0 | free(der->value); |
356 | | /* der points to obj->content */ |
357 | 0 | obj->content.value = NULL; |
358 | 0 | obj->content.len = 0; |
359 | 0 | } |
360 | 0 | } |
361 | |
|
362 | 0 | LOG_FUNC_RETURN(ctx, r); |
363 | 0 | } |
364 | | |
365 | | |
366 | | int |
367 | | sc_pkcs15_encode_pukdf_entry(struct sc_context *ctx, const struct sc_pkcs15_object *obj, |
368 | | unsigned char **buf, size_t *buflen) |
369 | 0 | { |
370 | 0 | struct sc_asn1_entry asn1_com_key_attr[C_ASN1_COM_KEY_ATTR_SIZE]; |
371 | 0 | struct sc_asn1_entry asn1_com_pubkey_attr[C_ASN1_COM_PUBKEY_ATTR_SIZE]; |
372 | 0 | struct sc_asn1_entry asn1_rsakey_value_choice[C_ASN1_RSAKEY_VALUE_CHOICE_SIZE]; |
373 | 0 | struct sc_asn1_entry asn1_rsakey_attr[C_ASN1_RSAKEY_ATTR_SIZE]; |
374 | 0 | struct sc_asn1_entry asn1_rsa_type_attr[C_ASN1_RSA_TYPE_ATTR_SIZE]; |
375 | 0 | struct sc_asn1_entry asn1_eckey_value_choice[C_ASN1_ECKEY_VALUE_CHOICE_SIZE]; |
376 | 0 | struct sc_asn1_entry asn1_eckey_attr[C_ASN1_ECKEY_ATTR_SIZE]; |
377 | 0 | struct sc_asn1_entry asn1_ec_type_attr[C_ASN1_EC_TYPE_ATTR_SIZE]; |
378 | 0 | struct sc_asn1_entry asn1_gostr3410key_attr[C_ASN1_GOST3410KEY_ATTR_SIZE]; |
379 | 0 | struct sc_asn1_entry asn1_gostr3410_type_attr[C_ASN1_GOST3410_TYPE_ATTR_SIZE]; |
380 | 0 | struct sc_asn1_entry asn1_pubkey_choice[C_ASN1_PUBKEY_CHOICE_SIZE]; |
381 | 0 | struct sc_asn1_entry asn1_pubkey[C_ASN1_PUBKEY_SIZE]; |
382 | |
|
383 | 0 | struct sc_pkcs15_pubkey_info *pubkey = (struct sc_pkcs15_pubkey_info *) obj->data; |
384 | 0 | struct sc_asn1_pkcs15_object rsakey_obj = { |
385 | 0 | (struct sc_pkcs15_object *) obj, asn1_com_key_attr, asn1_com_pubkey_attr, asn1_rsa_type_attr |
386 | 0 | }; |
387 | 0 | struct sc_asn1_pkcs15_object eckey_obj = { (struct sc_pkcs15_object *) obj, |
388 | 0 | asn1_com_key_attr, |
389 | 0 | asn1_com_pubkey_attr, asn1_ec_type_attr }; |
390 | 0 | struct sc_asn1_pkcs15_object gostr3410key_obj = { (struct sc_pkcs15_object *) obj, |
391 | 0 | asn1_com_key_attr, |
392 | 0 | asn1_com_pubkey_attr, asn1_gostr3410_type_attr }; |
393 | 0 | struct sc_pkcs15_keyinfo_gostparams *keyinfo_gostparams; |
394 | 0 | int r; |
395 | 0 | size_t af_len, usage_len; |
396 | 0 | unsigned char *spki_value = NULL; |
397 | |
|
398 | 0 | sc_copy_asn1_entry(c_asn1_pubkey, asn1_pubkey); |
399 | 0 | sc_copy_asn1_entry(c_asn1_pubkey_choice, asn1_pubkey_choice); |
400 | 0 | sc_copy_asn1_entry(c_asn1_rsa_type_attr, asn1_rsa_type_attr); |
401 | 0 | sc_copy_asn1_entry(c_asn1_rsakey_value_choice, asn1_rsakey_value_choice); |
402 | 0 | sc_copy_asn1_entry(c_asn1_rsakey_attr, asn1_rsakey_attr); |
403 | 0 | sc_copy_asn1_entry(c_asn1_ec_type_attr, asn1_ec_type_attr); |
404 | 0 | sc_copy_asn1_entry(c_asn1_eckey_value_choice, asn1_eckey_value_choice); |
405 | 0 | sc_copy_asn1_entry(c_asn1_eckey_attr, asn1_eckey_attr); |
406 | 0 | sc_copy_asn1_entry(c_asn1_gostr3410_type_attr, asn1_gostr3410_type_attr); |
407 | 0 | sc_copy_asn1_entry(c_asn1_gostr3410key_attr, asn1_gostr3410key_attr); |
408 | 0 | sc_copy_asn1_entry(c_asn1_com_pubkey_attr, asn1_com_pubkey_attr); |
409 | 0 | sc_copy_asn1_entry(c_asn1_com_key_attr, asn1_com_key_attr); |
410 | |
|
411 | 0 | switch (obj->type) { |
412 | 0 | case SC_PKCS15_TYPE_PUBKEY_RSA: |
413 | 0 | sc_format_asn1_entry(asn1_pubkey_choice + 0, &rsakey_obj, NULL, 1); |
414 | |
|
415 | 0 | sc_format_asn1_entry(asn1_rsa_type_attr + 0, asn1_rsakey_attr, NULL, 1); |
416 | 0 | if (pubkey->path.len) { |
417 | 0 | sc_format_asn1_entry(asn1_rsakey_value_choice + 0, &pubkey->path, NULL, 1); |
418 | 0 | } |
419 | 0 | else if (pubkey->direct.raw.value && pubkey->direct.raw.len) { |
420 | | /* In RSAPublicKeyChoice 'raw' value keep it's SEQUENCE tag */ |
421 | 0 | sc_log(ctx, "Encode direct 'RAW' value"); |
422 | 0 | sc_format_asn1_entry(asn1_rsakey_value_choice + 1, pubkey->direct.raw.value, (void *)&pubkey->direct.raw.len, 1); |
423 | 0 | } |
424 | 0 | else if (pubkey->direct.spki.value && pubkey->direct.spki.len) { |
425 | | /* In RSAPublicKeyChoice 'spki' value changes initial SEQUENCE tag for |
426 | | * CONTEXT [1] constructed SEQUENCE */ |
427 | 0 | sc_log(ctx, "Encode direct 'SPKI' value"); |
428 | 0 | spki_value = malloc(pubkey->direct.spki.len); |
429 | 0 | if (!spki_value) |
430 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); |
431 | 0 | memcpy(spki_value, pubkey->direct.spki.value, pubkey->direct.spki.len); |
432 | 0 | *spki_value = (SC_ASN1_TAG_CONTEXT | SC_ASN1_TAG_CONSTRUCTED | 0x01); |
433 | |
|
434 | 0 | sc_format_asn1_entry(asn1_rsakey_value_choice + 1, spki_value, (void *)&pubkey->direct.spki.len, 1); |
435 | 0 | } |
436 | 0 | else if (obj->content.value && obj->content.len) { |
437 | 0 | sc_log(ctx, "Encode 'RAW' object content"); |
438 | 0 | sc_format_asn1_entry(asn1_rsakey_value_choice + 1, obj->content.value, (void *)&obj->content.len, 1); |
439 | 0 | } |
440 | 0 | else { |
441 | 0 | sc_log(ctx, "Use empty path"); |
442 | 0 | sc_format_asn1_entry(asn1_rsakey_value_choice + 0, &pubkey->path, NULL, 1); |
443 | 0 | } |
444 | | |
445 | 0 | sc_format_asn1_entry(asn1_rsakey_attr + 0, asn1_rsakey_value_choice, NULL, 1); |
446 | 0 | sc_format_asn1_entry(asn1_rsakey_attr + 1, &pubkey->modulus_length, NULL, 1); |
447 | 0 | break; |
448 | 0 | case SC_PKCS15_TYPE_PUBKEY_GOSTR3410: |
449 | 0 | sc_format_asn1_entry(asn1_pubkey_choice + 1, &gostr3410key_obj, NULL, 1); |
450 | |
|
451 | 0 | sc_format_asn1_entry(asn1_gostr3410_type_attr + 0, asn1_gostr3410key_attr, NULL, 1); |
452 | |
|
453 | 0 | sc_format_asn1_entry(asn1_gostr3410key_attr + 0, &pubkey->path, NULL, 1); |
454 | 0 | if (pubkey->params.len == sizeof(*keyinfo_gostparams)) { |
455 | 0 | keyinfo_gostparams = pubkey->params.data; |
456 | 0 | sc_format_asn1_entry(asn1_gostr3410key_attr + 1, |
457 | 0 | &keyinfo_gostparams->gostr3410, NULL, 1); |
458 | 0 | sc_format_asn1_entry(asn1_gostr3410key_attr + 2, |
459 | 0 | &keyinfo_gostparams->gostr3411, NULL, 1); |
460 | 0 | sc_format_asn1_entry(asn1_gostr3410key_attr + 3, |
461 | 0 | &keyinfo_gostparams->gost28147, NULL, 1); |
462 | 0 | } |
463 | 0 | break; |
464 | 0 | case SC_PKCS15_TYPE_PUBKEY_EC: |
465 | 0 | sc_format_asn1_entry(asn1_pubkey_choice + 2, &eckey_obj, NULL, 1); |
466 | |
|
467 | 0 | sc_format_asn1_entry(asn1_ec_type_attr + 0, asn1_eckey_attr, NULL, 1); |
468 | |
|
469 | 0 | if (pubkey->path.len) { |
470 | 0 | sc_format_asn1_entry(asn1_eckey_value_choice + 0, &pubkey->path, NULL, 1); |
471 | 0 | } |
472 | 0 | else if (pubkey->direct.spki.value) { |
473 | 0 | sc_format_asn1_entry(asn1_eckey_value_choice + 1, pubkey->direct.spki.value, (void *)&pubkey->direct.spki.len, 1); |
474 | 0 | } |
475 | 0 | else if (pubkey->direct.raw.value) { |
476 | 0 | sc_format_asn1_entry(asn1_eckey_value_choice + 1, pubkey->direct.raw.value, (void *)&pubkey->direct.raw.len, 1); |
477 | 0 | LOG_TEST_RET(ctx, SC_ERROR_NOT_IMPLEMENTED, "Needs KeyInfo with reference to algorithm in TokenInfo"); |
478 | 0 | } |
479 | 0 | else if (obj->content.value) { |
480 | 0 | sc_format_asn1_entry(asn1_eckey_value_choice + 1, obj->content.value, (void *)&obj->content.len, 1); |
481 | 0 | LOG_TEST_RET(ctx, SC_ERROR_NOT_IMPLEMENTED, "Needs KeyInfo with reference to algorithm in TokenInfo"); |
482 | 0 | } |
483 | | |
484 | 0 | sc_format_asn1_entry(asn1_eckey_attr + 0, asn1_eckey_value_choice, NULL, 1); |
485 | |
|
486 | 0 | break; |
487 | 0 | default: |
488 | 0 | sc_log(ctx, "Unsupported public key type: %X", obj->type); |
489 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_INTERNAL); |
490 | 0 | break; |
491 | 0 | } |
492 | | |
493 | 0 | sc_format_asn1_entry(asn1_com_key_attr + 0, &pubkey->id, NULL, 1); |
494 | 0 | usage_len = sizeof(pubkey->usage); |
495 | 0 | sc_format_asn1_entry(asn1_com_key_attr + 1, &pubkey->usage, &usage_len, 1); |
496 | 0 | if (pubkey->native == 0) |
497 | 0 | sc_format_asn1_entry(asn1_com_key_attr + 2, &pubkey->native, NULL, 1); |
498 | 0 | if (pubkey->access_flags) { |
499 | 0 | af_len = sizeof(pubkey->access_flags); |
500 | 0 | sc_format_asn1_entry(asn1_com_key_attr + 3, &pubkey->access_flags, &af_len, 1); |
501 | 0 | } |
502 | 0 | if (pubkey->key_reference >= 0) |
503 | 0 | sc_format_asn1_entry(asn1_com_key_attr + 4, &pubkey->key_reference, NULL, 1); |
504 | 0 | sc_format_asn1_entry(asn1_pubkey + 0, asn1_pubkey_choice, NULL, 1); |
505 | |
|
506 | 0 | if (pubkey->subject.value && pubkey->subject.len) |
507 | 0 | sc_format_asn1_entry(asn1_com_pubkey_attr + 0, pubkey->subject.value, &pubkey->subject.len, 1); |
508 | 0 | else |
509 | 0 | memset(asn1_com_pubkey_attr, 0, sizeof(asn1_com_pubkey_attr)); |
510 | |
|
511 | 0 | r = sc_asn1_encode(ctx, asn1_pubkey, buf, buflen); |
512 | |
|
513 | 0 | sc_log(ctx, "Key path %s", sc_print_path(&pubkey->path)); |
514 | |
|
515 | 0 | free(spki_value); |
516 | 0 | return r; |
517 | 0 | } |
518 | | |
519 | | // clang-format off |
520 | | #define C_ASN1_PUBLIC_KEY_SIZE 2 |
521 | | static struct sc_asn1_entry c_asn1_public_key[C_ASN1_PUBLIC_KEY_SIZE] = { |
522 | | { "publicKeyCoefficients", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL }, |
523 | | { NULL, 0, 0, 0, NULL, NULL } |
524 | | }; |
525 | | |
526 | | #define C_ASN1_RSA_PUB_COEFFICIENTS_SIZE 3 |
527 | | static struct sc_asn1_entry c_asn1_rsa_pub_coefficients[C_ASN1_RSA_PUB_COEFFICIENTS_SIZE] = { |
528 | | { "modulus", SC_ASN1_OCTET_STRING, SC_ASN1_TAG_INTEGER, SC_ASN1_ALLOC|SC_ASN1_UNSIGNED, NULL, NULL }, |
529 | | { "exponent", SC_ASN1_OCTET_STRING, SC_ASN1_TAG_INTEGER, SC_ASN1_ALLOC|SC_ASN1_UNSIGNED, NULL, NULL }, |
530 | | { NULL, 0, 0, 0, NULL, NULL } |
531 | | }; |
532 | | |
533 | | #define C_ASN1_GOSTR3410_PUB_COEFFICIENTS_SIZE 2 |
534 | | static struct sc_asn1_entry c_asn1_gostr3410_pub_coefficients[C_ASN1_GOSTR3410_PUB_COEFFICIENTS_SIZE] = { |
535 | | { "xy", SC_ASN1_OCTET_STRING, SC_ASN1_TAG_OCTET_STRING, SC_ASN1_ALLOC, NULL, NULL }, |
536 | | { NULL, 0, 0, 0, NULL, NULL } |
537 | | }; |
538 | | |
539 | | /* PKCS15 raw uses OCTET STRING, SPKI uses BIT STRING */ |
540 | | /* accept either */ |
541 | | #define C_ASN1_EC_POINTQ_SIZE 3 |
542 | | static struct sc_asn1_entry c_asn1_ec_pointQ[C_ASN1_EC_POINTQ_SIZE] = { |
543 | | { "ecpointQ-OS", SC_ASN1_OCTET_STRING, SC_ASN1_TAG_OCTET_STRING, SC_ASN1_OPTIONAL | SC_ASN1_ALLOC, NULL, NULL }, |
544 | | { "ecpointQ-BS", SC_ASN1_BIT_STRING_NI, SC_ASN1_TAG_BIT_STRING, SC_ASN1_OPTIONAL | SC_ASN1_ALLOC, NULL, NULL }, |
545 | | { NULL, 0, 0, 0, NULL, NULL } |
546 | | }; |
547 | | |
548 | | /* See RFC8410 */ |
549 | | #define C_ASN1_EDDSA_PUBKEY_SIZE 3 |
550 | | static struct sc_asn1_entry c_asn1_eddsa_pubkey[C_ASN1_EDDSA_PUBKEY_SIZE] = { |
551 | | { "ecpointQ-OS", SC_ASN1_OCTET_STRING, SC_ASN1_TAG_OCTET_STRING, SC_ASN1_OPTIONAL | SC_ASN1_ALLOC, NULL, NULL }, |
552 | | { "ecpointQ-BS", SC_ASN1_BIT_STRING_NI, SC_ASN1_TAG_BIT_STRING, SC_ASN1_OPTIONAL | SC_ASN1_ALLOC, NULL, NULL }, |
553 | | { NULL, 0, 0, 0, NULL, NULL } |
554 | | }; |
555 | | // clang-format on |
556 | | |
557 | | int |
558 | | sc_pkcs15_decode_pubkey_rsa(sc_context_t *ctx, struct sc_pkcs15_pubkey_rsa *key, |
559 | | const u8 *buf, size_t buflen) |
560 | 0 | { |
561 | 0 | struct sc_asn1_entry asn1_public_key[C_ASN1_PUBLIC_KEY_SIZE]; |
562 | 0 | struct sc_asn1_entry asn1_rsa_pub_coefficients[C_ASN1_RSA_PUB_COEFFICIENTS_SIZE]; |
563 | 0 | int r; |
564 | |
|
565 | 0 | LOG_FUNC_CALLED(ctx); |
566 | 0 | sc_copy_asn1_entry(c_asn1_public_key, asn1_public_key); |
567 | 0 | sc_format_asn1_entry(asn1_public_key + 0, asn1_rsa_pub_coefficients, NULL, 0); |
568 | |
|
569 | 0 | sc_copy_asn1_entry(c_asn1_rsa_pub_coefficients, asn1_rsa_pub_coefficients); |
570 | 0 | sc_format_asn1_entry(asn1_rsa_pub_coefficients + 0, &key->modulus.data, &key->modulus.len, 0); |
571 | 0 | sc_format_asn1_entry(asn1_rsa_pub_coefficients + 1, &key->exponent.data, &key->exponent.len, 0); |
572 | |
|
573 | 0 | r = sc_asn1_decode(ctx, asn1_public_key, buf, buflen, NULL, NULL); |
574 | 0 | LOG_TEST_RET(ctx, r, "ASN.1 parsing of public key failed"); |
575 | | |
576 | 0 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
577 | 0 | } |
578 | | |
579 | | |
580 | | int |
581 | | sc_pkcs15_encode_pubkey_rsa(sc_context_t *ctx, struct sc_pkcs15_pubkey_rsa *key, |
582 | | u8 **buf, size_t *buflen) |
583 | 0 | { |
584 | 0 | struct sc_asn1_entry asn1_public_key[C_ASN1_PUBLIC_KEY_SIZE]; |
585 | 0 | struct sc_asn1_entry asn1_rsa_pub_coefficients[C_ASN1_RSA_PUB_COEFFICIENTS_SIZE]; |
586 | 0 | int r; |
587 | |
|
588 | 0 | LOG_FUNC_CALLED(ctx); |
589 | 0 | sc_copy_asn1_entry(c_asn1_public_key, asn1_public_key); |
590 | 0 | sc_format_asn1_entry(asn1_public_key + 0, asn1_rsa_pub_coefficients, NULL, 1); |
591 | |
|
592 | 0 | sc_copy_asn1_entry(c_asn1_rsa_pub_coefficients, asn1_rsa_pub_coefficients); |
593 | 0 | sc_format_asn1_entry(asn1_rsa_pub_coefficients + 0, key->modulus.data, &key->modulus.len, 1); |
594 | 0 | sc_format_asn1_entry(asn1_rsa_pub_coefficients + 1, key->exponent.data, &key->exponent.len, 1); |
595 | |
|
596 | 0 | r = sc_asn1_encode(ctx, asn1_public_key, buf, buflen); |
597 | 0 | LOG_TEST_RET(ctx, r, "ASN.1 encoding failed"); |
598 | | |
599 | 0 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
600 | 0 | } |
601 | | |
602 | | |
603 | | int |
604 | | sc_pkcs15_decode_pubkey_gostr3410(sc_context_t *ctx, struct sc_pkcs15_pubkey_gostr3410 *key, |
605 | | const u8 *buf, size_t buflen) |
606 | 0 | { |
607 | 0 | struct sc_asn1_entry asn1_gostr3410_pub_coeff[C_ASN1_GOSTR3410_PUB_COEFFICIENTS_SIZE]; |
608 | 0 | int r; |
609 | 0 | struct sc_object_id param_key = {{ 1, 2, 643, 2, 2, 35, 1, -1}}; |
610 | 0 | struct sc_object_id param_hash = {{ 1, 2, 643, 2, 2, 30, 1, -1}}; |
611 | |
|
612 | 0 | LOG_FUNC_CALLED(ctx); |
613 | 0 | sc_copy_asn1_entry(c_asn1_gostr3410_pub_coefficients, asn1_gostr3410_pub_coeff); |
614 | 0 | sc_format_asn1_entry(asn1_gostr3410_pub_coeff + 0, &key->xy.data, &key->xy.len, 0); |
615 | |
|
616 | 0 | r = sc_asn1_decode(ctx, asn1_gostr3410_pub_coeff, buf, buflen, NULL, NULL); |
617 | 0 | LOG_TEST_RET(ctx, r, "ASN.1 parsing of public key failed"); |
618 | | |
619 | 0 | key->params.key = param_key; |
620 | 0 | key->params.hash = param_hash; |
621 | |
|
622 | 0 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
623 | 0 | } |
624 | | |
625 | | int |
626 | | sc_pkcs15_encode_pubkey_gostr3410(sc_context_t *ctx, |
627 | | struct sc_pkcs15_pubkey_gostr3410 *key, |
628 | | u8 **buf, size_t *buflen) |
629 | 0 | { |
630 | 0 | struct sc_asn1_entry asn1_gostr3410_pub_coeff[C_ASN1_GOSTR3410_PUB_COEFFICIENTS_SIZE]; |
631 | 0 | int r; |
632 | |
|
633 | 0 | LOG_FUNC_CALLED(ctx); |
634 | 0 | sc_copy_asn1_entry(c_asn1_gostr3410_pub_coefficients, asn1_gostr3410_pub_coeff); |
635 | 0 | sc_format_asn1_entry(asn1_gostr3410_pub_coeff + 0, key->xy.data, &key->xy.len, 1); |
636 | |
|
637 | 0 | r = sc_asn1_encode(ctx, asn1_gostr3410_pub_coeff, buf, buflen); |
638 | 0 | LOG_TEST_RET(ctx, r, "ASN.1 encoding failed"); |
639 | | |
640 | 0 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
641 | 0 | } |
642 | | |
643 | | /* |
644 | | * We are storing the ec_pointQ as u8 string not as DER |
645 | | * Will accept either BIT STRING or OCTET STRING |
646 | | */ |
647 | | int |
648 | | sc_pkcs15_decode_pubkey_ec(sc_context_t *ctx, |
649 | | struct sc_pkcs15_pubkey_ec *key, |
650 | | const u8 *buf, size_t buflen) |
651 | 0 | { |
652 | 0 | int r; |
653 | 0 | u8 * ecpoint_data = NULL; |
654 | 0 | size_t ecpoint_len = 0; |
655 | 0 | struct sc_asn1_entry asn1_ec_pointQ[C_ASN1_EC_POINTQ_SIZE]; |
656 | |
|
657 | 0 | LOG_FUNC_CALLED(ctx); |
658 | 0 | sc_copy_asn1_entry(c_asn1_ec_pointQ, asn1_ec_pointQ); |
659 | 0 | sc_format_asn1_entry(asn1_ec_pointQ + 0, &ecpoint_data, &ecpoint_len, 0); |
660 | 0 | sc_format_asn1_entry(asn1_ec_pointQ + 1, &ecpoint_data, &ecpoint_len, 0); |
661 | 0 | r = sc_asn1_decode_choice(ctx, asn1_ec_pointQ, buf, buflen, NULL, NULL); |
662 | 0 | if (r < 0 || ecpoint_len == 0 || ecpoint_data == NULL) { |
663 | 0 | free(ecpoint_data); |
664 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ASN1_OBJECT); |
665 | 0 | } |
666 | | |
667 | 0 | sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "ecpoint_len:%" SC_FORMAT_LEN_SIZE_T "u", ecpoint_len); |
668 | | /* if from bit string */ |
669 | 0 | if (asn1_ec_pointQ[1].flags & SC_ASN1_PRESENT) |
670 | 0 | ecpoint_len = BYTES4BITS(ecpoint_len); |
671 | 0 | sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "ecpoint_len:%" SC_FORMAT_LEN_SIZE_T "u", ecpoint_len); |
672 | |
|
673 | 0 | if (*ecpoint_data != 0x04) { |
674 | 0 | free(ecpoint_data); |
675 | 0 | LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Supported only uncompressed EC pointQ value"); |
676 | 0 | } |
677 | | |
678 | 0 | key->ecpointQ.len = ecpoint_len; |
679 | 0 | key->ecpointQ.value = ecpoint_data; |
680 | |
|
681 | 0 | key->params.field_length = (ecpoint_len - 1)/2 * 8; |
682 | 0 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
683 | 0 | } |
684 | | |
685 | | |
686 | | int |
687 | | sc_pkcs15_encode_pubkey_ec(sc_context_t *ctx, struct sc_pkcs15_pubkey_ec *key, |
688 | | u8 **buf, size_t *buflen) |
689 | 0 | { |
690 | 0 | struct sc_asn1_entry asn1_ec_pointQ[C_ASN1_EC_POINTQ_SIZE]; |
691 | 0 | size_t key_len; |
692 | | /* |
693 | | * PKCS15 uses RAW vs SPKI for pub key, and in raw uses OCTET STRING |
694 | | * PKCS11 does not define CKA_VALUE for a pub key |
695 | | * But some PKCS11 modules define a CKA_VALUE for a public key |
696 | | * and PKCS11 says ECPOINT is encoded as "DER-encoding of ANSI X9.62 ECPoint value Q" |
697 | | * But ANSI X9.62 (early draft at least) says encode as OCTET STRING |
698 | | * IETF encodes it in SubjectPublicKeyInfo (SPKI) in BIT STRING |
699 | | * For now return as OCTET STRING. |
700 | | */ |
701 | |
|
702 | 0 | LOG_FUNC_CALLED(ctx); |
703 | 0 | sc_copy_asn1_entry(c_asn1_ec_pointQ, asn1_ec_pointQ); |
704 | |
|
705 | 0 | key_len = key->ecpointQ.len; |
706 | 0 | sc_format_asn1_entry(asn1_ec_pointQ + 0, key->ecpointQ.value, &key_len, 1); |
707 | |
|
708 | 0 | LOG_FUNC_RETURN(ctx, |
709 | 0 | sc_asn1_encode(ctx, asn1_ec_pointQ, buf, buflen)); |
710 | 0 | } |
711 | | |
712 | | /* |
713 | | * all "ec" keys use same pubkey format, keep this external entrypoint |
714 | | * keys are just byte strings. |
715 | | * will accept in either BIT STRING or OCTET STRING |
716 | | */ |
717 | | int |
718 | | sc_pkcs15_decode_pubkey_eddsa(sc_context_t *ctx, |
719 | | struct sc_pkcs15_pubkey_ec *key, |
720 | | const u8 *buf, size_t buflen) |
721 | 0 | { |
722 | 0 | int r; |
723 | 0 | u8 *ecpoint_data = NULL; |
724 | 0 | size_t ecpoint_len = 0; |
725 | 0 | struct sc_asn1_entry asn1_ec_pointQ[C_ASN1_EC_POINTQ_SIZE]; |
726 | |
|
727 | 0 | LOG_FUNC_CALLED(ctx); |
728 | 0 | sc_copy_asn1_entry(c_asn1_ec_pointQ, asn1_ec_pointQ); |
729 | 0 | sc_format_asn1_entry(asn1_ec_pointQ + 0, &ecpoint_data, &ecpoint_len, 1); |
730 | 0 | sc_format_asn1_entry(asn1_ec_pointQ + 1, &ecpoint_data, &ecpoint_len, 1); |
731 | 0 | r = sc_asn1_decode_choice(ctx, asn1_ec_pointQ, buf, buflen, NULL, NULL); |
732 | 0 | if (r < 0 || ecpoint_len == 0 || ecpoint_data == NULL) { |
733 | 0 | free(ecpoint_data); |
734 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ASN1_OBJECT); |
735 | 0 | } |
736 | | |
737 | 0 | if (asn1_ec_pointQ[1].flags & SC_ASN1_PRESENT) |
738 | 0 | ecpoint_len = BYTES4BITS(ecpoint_len); |
739 | |
|
740 | 0 | key->ecpointQ.len = ecpoint_len; |
741 | 0 | key->ecpointQ.value = ecpoint_data; |
742 | 0 | key->params.field_length = ecpoint_len * 8; |
743 | |
|
744 | 0 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
745 | 0 | } |
746 | | |
747 | | int |
748 | | sc_pkcs15_encode_pubkey_eddsa(sc_context_t *ctx, struct sc_pkcs15_pubkey_ec *key, |
749 | | u8 **buf, size_t *buflen) |
750 | 0 | { |
751 | 0 | struct sc_asn1_entry asn1_eddsa_pubkey[C_ASN1_EDDSA_PUBKEY_SIZE]; |
752 | 0 | size_t key_len; |
753 | |
|
754 | 0 | LOG_FUNC_CALLED(ctx); |
755 | 0 | key_len = key->ecpointQ.len; /* in bytes */ |
756 | 0 | sc_copy_asn1_entry(c_asn1_eddsa_pubkey, asn1_eddsa_pubkey); |
757 | 0 | sc_format_asn1_entry(asn1_eddsa_pubkey + 0, key->ecpointQ.value, &key_len, 1); |
758 | |
|
759 | 0 | LOG_FUNC_RETURN(ctx, |
760 | 0 | sc_asn1_encode(ctx, asn1_eddsa_pubkey, buf, buflen)); |
761 | 0 | } |
762 | | |
763 | | int |
764 | | sc_pkcs15_encode_pubkey(sc_context_t *ctx, struct sc_pkcs15_pubkey *key, |
765 | | u8 **buf, size_t *len) |
766 | 0 | { |
767 | 0 | if (key->algorithm == SC_ALGORITHM_RSA) |
768 | 0 | return sc_pkcs15_encode_pubkey_rsa(ctx, &key->u.rsa, buf, len); |
769 | 0 | if (key->algorithm == SC_ALGORITHM_GOSTR3410) |
770 | 0 | return sc_pkcs15_encode_pubkey_gostr3410(ctx, &key->u.gostr3410, buf, len); |
771 | 0 | if (key->algorithm == SC_ALGORITHM_EC) |
772 | 0 | return sc_pkcs15_encode_pubkey_ec(ctx, &key->u.ec, buf, len); |
773 | 0 | if (key->algorithm == SC_ALGORITHM_EDDSA || key->algorithm == SC_ALGORITHM_XEDDSA) |
774 | 0 | return sc_pkcs15_encode_pubkey_eddsa(ctx, &key->u.ec, buf, len); |
775 | | |
776 | 0 | sc_log(ctx, "Encoding of public key type %lu not supported", key->algorithm); |
777 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); |
778 | 0 | } |
779 | | |
780 | | |
781 | | static const struct sc_asn1_entry c_asn1_spki_key_items[] = { |
782 | | { "algorithm", SC_ASN1_ALGORITHM_ID, SC_ASN1_CONS| SC_ASN1_TAG_SEQUENCE, 0, NULL, NULL}, |
783 | | { "key", SC_ASN1_BIT_STRING_NI, SC_ASN1_TAG_BIT_STRING, 0, NULL, NULL }, |
784 | | { NULL, 0, 0, 0, NULL, NULL } |
785 | | }; |
786 | | |
787 | | static const struct sc_asn1_entry c_asn1_spki_key[] = { |
788 | | { "publicKey", SC_ASN1_STRUCT, SC_ASN1_CONS | SC_ASN1_TAG_SEQUENCE, 0, NULL, NULL}, |
789 | | { NULL, 0, 0, 0, NULL, NULL } |
790 | | }; |
791 | | |
792 | | /* |
793 | | * Encode a pubkey as a SPKI, useful for pkcs15-tool, and for PKCS#15 files. |
794 | | */ |
795 | | int |
796 | | sc_pkcs15_encode_pubkey_as_spki(sc_context_t *ctx, struct sc_pkcs15_pubkey *pubkey, |
797 | | u8 **buf, size_t *len) |
798 | 0 | { |
799 | 0 | int r = 0; |
800 | 0 | struct sc_asn1_entry asn1_spki_key[2], asn1_spki_key_items[3]; |
801 | 0 | struct sc_pkcs15_u8 pkey; |
802 | 0 | size_t key_len; |
803 | |
|
804 | 0 | LOG_FUNC_CALLED(ctx); |
805 | 0 | pkey.value = NULL; |
806 | 0 | pkey.len = 0; |
807 | |
|
808 | 0 | sc_log(ctx, "Encoding public key with algorithm %lu", pubkey->algorithm); |
809 | 0 | if (!pubkey->alg_id) { |
810 | 0 | pubkey->alg_id = calloc(1, sizeof(struct sc_algorithm_id)); |
811 | 0 | if (!pubkey->alg_id) |
812 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); |
813 | | |
814 | 0 | sc_init_oid(&pubkey->alg_id->oid); |
815 | 0 | pubkey->alg_id->algorithm = pubkey->algorithm; |
816 | 0 | } |
817 | | |
818 | 0 | switch (pubkey->algorithm) { |
819 | 0 | case SC_ALGORITHM_EC: |
820 | 0 | case SC_ALGORITHM_EDDSA: |
821 | 0 | case SC_ALGORITHM_XEDDSA: |
822 | | /* |
823 | | * most keys, but not EC have only one encoding. |
824 | | * For a SPKI, the ecpoint is placed directly in the |
825 | | * BIT STRING |
826 | | */ |
827 | 0 | key_len = pubkey->u.ec.ecpointQ.len * 8; |
828 | 0 | pkey.value = pubkey->u.ec.ecpointQ.value; |
829 | 0 | pkey.len = 0; /* flag as do not delete */ |
830 | |
|
831 | 0 | if (pubkey->u.ec.params.named_curve || pubkey->u.ec.params.der.value) { |
832 | 0 | struct sc_ec_parameters *ec_params = NULL; |
833 | |
|
834 | 0 | r = sc_pkcs15_fix_ec_parameters(ctx, &pubkey->u.ec.params); |
835 | 0 | LOG_TEST_RET(ctx, r, "failed to fix EC parameters"); |
836 | | |
837 | | /* EDDSA and XEDDSA only have algo and no param in SPKI */ |
838 | 0 | if (pubkey->algorithm == SC_ALGORITHM_EC) { |
839 | 0 | ec_params = calloc(1, sizeof(struct sc_ec_parameters)); |
840 | 0 | if (!ec_params) |
841 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); |
842 | 0 | ec_params->type = 1; |
843 | 0 | ec_params->der.value = calloc(1, pubkey->u.ec.params.der.len); |
844 | 0 | if (!ec_params->der.value) { |
845 | 0 | free(ec_params); |
846 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); |
847 | 0 | } |
848 | 0 | memcpy(ec_params->der.value, pubkey->u.ec.params.der.value, pubkey->u.ec.params.der.len); |
849 | 0 | ec_params->der.len = pubkey->u.ec.params.der.len; |
850 | 0 | } |
851 | | /* This could have been already allocated: avoid memory leak */ |
852 | 0 | sc_asn1_clear_algorithm_id(pubkey->alg_id); |
853 | 0 | pubkey->alg_id->params = ec_params; /* NULL for EDDSA and XEDDSA */ |
854 | 0 | } |
855 | 0 | break; |
856 | 0 | case SC_ALGORITHM_GOSTR3410: |
857 | | /* TODO is this needed? does it cause mem leak? */ |
858 | 0 | pubkey->alg_id->params = &pubkey->u.gostr3410.params; |
859 | 0 | r = sc_pkcs15_encode_pubkey(ctx, pubkey, &pkey.value, &pkey.len); |
860 | 0 | key_len = pkey.len * 8; |
861 | 0 | break; |
862 | 0 | default: |
863 | 0 | r = sc_pkcs15_encode_pubkey(ctx, pubkey, &pkey.value, &pkey.len); |
864 | 0 | key_len = pkey.len * 8; |
865 | 0 | break; |
866 | 0 | } |
867 | | |
868 | 0 | if (r == 0) { |
869 | 0 | sc_copy_asn1_entry(c_asn1_spki_key, asn1_spki_key); |
870 | 0 | sc_copy_asn1_entry(c_asn1_spki_key_items, asn1_spki_key_items); |
871 | 0 | sc_format_asn1_entry(asn1_spki_key + 0, asn1_spki_key_items, NULL, 1); |
872 | 0 | sc_format_asn1_entry(asn1_spki_key_items + 0, pubkey->alg_id, NULL, 1); |
873 | 0 | sc_format_asn1_entry(asn1_spki_key_items + 1, pkey.value, &key_len, 1); |
874 | |
|
875 | 0 | r = sc_asn1_encode(ctx, asn1_spki_key, buf, len); |
876 | 0 | } |
877 | | |
878 | | /* pkey.len == 0 is flag to not delete */ |
879 | 0 | if (pkey.len && pkey.value) |
880 | 0 | free(pkey.value); |
881 | |
|
882 | 0 | LOG_FUNC_RETURN(ctx, r); |
883 | 0 | } |
884 | | |
885 | | |
886 | | int |
887 | | sc_pkcs15_decode_pubkey(sc_context_t *ctx, struct sc_pkcs15_pubkey *key, |
888 | | const u8 *buf, size_t len) |
889 | 0 | { |
890 | 0 | if (key->algorithm == SC_ALGORITHM_RSA) |
891 | 0 | return sc_pkcs15_decode_pubkey_rsa(ctx, &key->u.rsa, buf, len); |
892 | 0 | if (key->algorithm == SC_ALGORITHM_GOSTR3410) |
893 | 0 | return sc_pkcs15_decode_pubkey_gostr3410(ctx, &key->u.gostr3410, buf, len); |
894 | 0 | if (key->algorithm == SC_ALGORITHM_EC) |
895 | 0 | return sc_pkcs15_decode_pubkey_ec(ctx, &key->u.ec, buf, len); |
896 | 0 | if (key->algorithm == SC_ALGORITHM_EDDSA || key->algorithm == SC_ALGORITHM_XEDDSA) |
897 | 0 | return sc_pkcs15_decode_pubkey_eddsa(ctx, &key->u.ec, buf, len); |
898 | | |
899 | 0 | sc_log(ctx, "Decoding of public key type %lu not supported", key->algorithm); |
900 | 0 | return SC_ERROR_NOT_SUPPORTED; |
901 | 0 | } |
902 | | |
903 | | |
904 | | /* |
905 | | * Read public key. |
906 | | */ |
907 | | int |
908 | | sc_pkcs15_read_pubkey(struct sc_pkcs15_card *p15card, const struct sc_pkcs15_object *obj, |
909 | | struct sc_pkcs15_pubkey **out) |
910 | 0 | { |
911 | 0 | struct sc_context *ctx; |
912 | 0 | const struct sc_pkcs15_pubkey_info *info = NULL; |
913 | 0 | struct sc_pkcs15_pubkey *pubkey = NULL; |
914 | 0 | unsigned char *data = NULL; |
915 | 0 | size_t len; |
916 | 0 | int algorithm, r; |
917 | 0 | int private_obj; |
918 | |
|
919 | 0 | if (p15card == NULL || p15card->card == NULL || p15card->card->ops == NULL |
920 | 0 | || obj == NULL || out == NULL) { |
921 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
922 | 0 | } |
923 | 0 | ctx = p15card->card->ctx; |
924 | |
|
925 | 0 | LOG_FUNC_CALLED(ctx); |
926 | 0 | sc_log(ctx, "Public key type 0x%X", obj->type); |
927 | |
|
928 | 0 | switch (obj->type) { |
929 | 0 | case SC_PKCS15_TYPE_PUBKEY_RSA: |
930 | 0 | algorithm = SC_ALGORITHM_RSA; |
931 | 0 | break; |
932 | 0 | case SC_PKCS15_TYPE_PUBKEY_GOSTR3410: |
933 | 0 | algorithm = SC_ALGORITHM_GOSTR3410; |
934 | 0 | break; |
935 | 0 | case SC_PKCS15_TYPE_PUBKEY_EC: |
936 | 0 | algorithm = SC_ALGORITHM_EC; |
937 | 0 | break; |
938 | 0 | case SC_PKCS15_TYPE_PUBKEY_EDDSA: |
939 | 0 | algorithm = SC_ALGORITHM_EDDSA; |
940 | 0 | break; |
941 | 0 | case SC_PKCS15_TYPE_PUBKEY_XEDDSA: |
942 | 0 | algorithm = SC_ALGORITHM_XEDDSA; |
943 | 0 | break; |
944 | 0 | default: |
945 | 0 | LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Unsupported public key type."); |
946 | 0 | } |
947 | 0 | info = (const struct sc_pkcs15_pubkey_info *) obj->data; |
948 | |
|
949 | 0 | pubkey = calloc(1, sizeof(struct sc_pkcs15_pubkey)); |
950 | 0 | if (pubkey == NULL) { |
951 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); |
952 | 0 | } |
953 | 0 | pubkey->algorithm = algorithm; |
954 | | |
955 | | /* starting from SPKI direct value |
956 | | in a compact form it presents complete public key data */ |
957 | 0 | if (info->direct.spki.value && info->direct.spki.len) { |
958 | 0 | sc_log(ctx, "Using direct SPKI value, tag 0x%X", *(info->direct.spki.value)); |
959 | 0 | r = sc_pkcs15_pubkey_from_spki_sequence(ctx, info->direct.spki.value, info->direct.spki.len, &pubkey); |
960 | 0 | LOG_TEST_GOTO_ERR(ctx, r, "Failed to decode 'SPKI' direct value"); |
961 | 0 | } |
962 | 0 | else if (info->direct.raw.value && info->direct.raw.len) { |
963 | 0 | sc_log(ctx, "Using direct RAW value"); |
964 | 0 | r = sc_pkcs15_decode_pubkey(ctx, pubkey, info->direct.raw.value, info->direct.raw.len); |
965 | 0 | LOG_TEST_GOTO_ERR(ctx, r, "Failed to decode 'RAW' direct value"); |
966 | 0 | sc_log(ctx, "TODO: for EC keys 'raw' data needs to be completed with referenced algorithm from TokenInfo"); |
967 | 0 | } |
968 | 0 | else if (obj->content.value && obj->content.len) { |
969 | 0 | sc_log(ctx, "Using object content"); |
970 | 0 | r = sc_pkcs15_decode_pubkey(ctx, pubkey, obj->content.value, obj->content.len); |
971 | 0 | LOG_TEST_GOTO_ERR(ctx, r, "Failed to decode object content value"); |
972 | 0 | sc_log(ctx, "TODO: for EC keys 'raw' data needs to be completed with referenced algorithm from TokenInfo"); |
973 | 0 | } |
974 | 0 | else if (p15card->card->ops->read_public_key) { |
975 | 0 | sc_log(ctx, "Call card specific 'read-public-key' handle"); |
976 | 0 | r = p15card->card->ops->read_public_key(p15card->card, algorithm, |
977 | 0 | (struct sc_path *)&info->path, info->key_reference, (unsigned)info->modulus_length, |
978 | 0 | &data, &len); |
979 | 0 | LOG_TEST_GOTO_ERR(ctx, r, "Card specific 'read-public' procedure failed."); |
980 | | |
981 | 0 | r = sc_pkcs15_decode_pubkey(ctx, pubkey, data, len); |
982 | 0 | LOG_TEST_GOTO_ERR(ctx, r, "Decode public key error"); |
983 | 0 | } |
984 | 0 | else if (info->path.len) { |
985 | 0 | sc_log(ctx, "Read from EF and decode"); |
986 | 0 | private_obj = obj->flags & SC_PKCS15_CO_FLAG_PRIVATE; |
987 | 0 | r = sc_pkcs15_read_file(p15card, &info->path, &data, &len, private_obj); |
988 | 0 | LOG_TEST_GOTO_ERR(ctx, r, "Failed to read public key file."); |
989 | | |
990 | 0 | if ((algorithm == SC_ALGORITHM_EC || algorithm == SC_ALGORITHM_EDDSA || algorithm == SC_ALGORITHM_XEDDSA) |
991 | 0 | && *data == (SC_ASN1_TAG_SEQUENCE | SC_ASN1_TAG_CONSTRUCTED)) |
992 | 0 | r = sc_pkcs15_pubkey_from_spki_sequence(ctx, data, len, &pubkey); |
993 | 0 | else |
994 | 0 | r = sc_pkcs15_decode_pubkey(ctx, pubkey, data, len); |
995 | 0 | LOG_TEST_GOTO_ERR(ctx, r, "Decode public key error"); |
996 | 0 | } |
997 | 0 | else { |
998 | 0 | r = SC_ERROR_NOT_IMPLEMENTED; |
999 | 0 | LOG_TEST_GOTO_ERR(ctx, r, "No way to get public key"); |
1000 | 0 | } |
1001 | | |
1002 | 0 | err: |
1003 | 0 | if (r) { |
1004 | 0 | sc_pkcs15_free_pubkey(pubkey); |
1005 | 0 | } else |
1006 | 0 | *out = pubkey; |
1007 | 0 | free(data); |
1008 | |
|
1009 | 0 | LOG_FUNC_RETURN(ctx, r); |
1010 | 0 | } |
1011 | | |
1012 | | |
1013 | | static int |
1014 | | sc_pkcs15_dup_bignum (struct sc_pkcs15_bignum *dst, struct sc_pkcs15_bignum *src) |
1015 | 0 | { |
1016 | 0 | if (!dst || !src) { |
1017 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
1018 | 0 | } |
1019 | | |
1020 | 0 | if (src->data && src->len) { |
1021 | 0 | dst->data = calloc(1, src->len); |
1022 | 0 | if (!dst->data) |
1023 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
1024 | 0 | memcpy(dst->data, src->data, src->len); |
1025 | 0 | dst->len = src->len; |
1026 | 0 | } |
1027 | | |
1028 | 0 | return 0; |
1029 | 0 | } |
1030 | | |
1031 | | |
1032 | | int |
1033 | | sc_pkcs15_pubkey_from_prvkey(struct sc_context *ctx, struct sc_pkcs15_prkey *prvkey, |
1034 | | struct sc_pkcs15_pubkey **out) |
1035 | 0 | { |
1036 | 0 | struct sc_pkcs15_pubkey *pubkey = NULL; |
1037 | 0 | int rv = SC_SUCCESS; |
1038 | |
|
1039 | 0 | if (!prvkey || !out) { |
1040 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
1041 | 0 | } |
1042 | | |
1043 | 0 | *out = NULL; |
1044 | 0 | pubkey = calloc(1, sizeof(struct sc_pkcs15_pubkey)); |
1045 | 0 | if (!pubkey) |
1046 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
1047 | | |
1048 | 0 | pubkey->algorithm = prvkey->algorithm; |
1049 | 0 | switch (prvkey->algorithm) { |
1050 | 0 | case SC_ALGORITHM_RSA: |
1051 | 0 | rv = sc_pkcs15_dup_bignum(&pubkey->u.rsa.modulus, &prvkey->u.rsa.modulus); |
1052 | 0 | if (!rv) |
1053 | 0 | rv = sc_pkcs15_dup_bignum(&pubkey->u.rsa.exponent, &prvkey->u.rsa.exponent); |
1054 | 0 | break; |
1055 | 0 | case SC_ALGORITHM_GOSTR3410: |
1056 | 0 | break; |
1057 | 0 | case SC_ALGORITHM_EC: |
1058 | 0 | case SC_ALGORITHM_EDDSA: |
1059 | 0 | case SC_ALGORITHM_XEDDSA: |
1060 | | /* Copy pubkey */ |
1061 | 0 | if (prvkey->u.ec.ecpointQ.value == NULL || prvkey->u.ec.ecpointQ.len <= 0) { |
1062 | 0 | sc_pkcs15_free_pubkey(pubkey); |
1063 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA); |
1064 | 0 | } |
1065 | 0 | pubkey->u.ec.ecpointQ.value = malloc(prvkey->u.ec.ecpointQ.len); |
1066 | 0 | if (!pubkey->u.ec.ecpointQ.value) { |
1067 | 0 | sc_pkcs15_free_pubkey(pubkey); |
1068 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); |
1069 | 0 | } |
1070 | 0 | memcpy(pubkey->u.ec.ecpointQ.value, prvkey->u.ec.ecpointQ.value, prvkey->u.ec.ecpointQ.len); |
1071 | 0 | pubkey->u.ec.ecpointQ.len = prvkey->u.ec.ecpointQ.len; |
1072 | 0 | break; |
1073 | 0 | default: |
1074 | 0 | sc_log(ctx, "Unsupported private key algorithm"); |
1075 | 0 | rv = SC_ERROR_NOT_SUPPORTED; |
1076 | 0 | } |
1077 | | |
1078 | 0 | if (rv) |
1079 | 0 | sc_pkcs15_free_pubkey(pubkey); |
1080 | 0 | else |
1081 | 0 | *out = pubkey; |
1082 | |
|
1083 | 0 | return rv; |
1084 | 0 | } |
1085 | | |
1086 | | |
1087 | | int |
1088 | | sc_pkcs15_dup_pubkey(struct sc_context *ctx, struct sc_pkcs15_pubkey *key, struct sc_pkcs15_pubkey **out) |
1089 | 0 | { |
1090 | 0 | struct sc_pkcs15_pubkey *pubkey = NULL; |
1091 | 0 | int rv = SC_SUCCESS; |
1092 | 0 | u8* alg; |
1093 | 0 | size_t alglen; |
1094 | |
|
1095 | 0 | LOG_FUNC_CALLED(ctx); |
1096 | |
|
1097 | 0 | if (!key || !out) { |
1098 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
1099 | 0 | } |
1100 | | |
1101 | 0 | *out = NULL; |
1102 | 0 | pubkey = calloc(1, sizeof(struct sc_pkcs15_pubkey)); |
1103 | 0 | if (!pubkey) |
1104 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); |
1105 | | |
1106 | 0 | pubkey->algorithm = key->algorithm; |
1107 | |
|
1108 | 0 | if (key->alg_id) { |
1109 | 0 | rv = sc_asn1_encode_algorithm_id(ctx, &alg, &alglen,key->alg_id, 0); |
1110 | 0 | if (rv == SC_SUCCESS) { |
1111 | 0 | pubkey->alg_id = (struct sc_algorithm_id *)calloc(1, sizeof(struct sc_algorithm_id)); |
1112 | 0 | if (pubkey->alg_id == NULL) { |
1113 | 0 | free(pubkey); |
1114 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); |
1115 | 0 | } |
1116 | 0 | rv = sc_asn1_decode_algorithm_id(ctx, alg, alglen, pubkey->alg_id, 0); |
1117 | 0 | free(alg); |
1118 | 0 | } |
1119 | 0 | } |
1120 | | |
1121 | 0 | switch (key->algorithm) { |
1122 | 0 | case SC_ALGORITHM_RSA: |
1123 | 0 | rv = sc_pkcs15_dup_bignum(&pubkey->u.rsa.modulus, &key->u.rsa.modulus); |
1124 | 0 | if (!rv) |
1125 | 0 | rv = sc_pkcs15_dup_bignum(&pubkey->u.rsa.exponent, &key->u.rsa.exponent); |
1126 | 0 | break; |
1127 | 0 | case SC_ALGORITHM_GOSTR3410: |
1128 | 0 | break; |
1129 | 0 | case SC_ALGORITHM_EC: |
1130 | 0 | case SC_ALGORITHM_EDDSA: |
1131 | 0 | case SC_ALGORITHM_XEDDSA: |
1132 | 0 | pubkey->u.ec.ecpointQ.value = malloc(key->u.ec.ecpointQ.len); |
1133 | 0 | if (!pubkey->u.ec.ecpointQ.value) { |
1134 | 0 | rv = SC_ERROR_OUT_OF_MEMORY; |
1135 | 0 | break; |
1136 | 0 | } |
1137 | 0 | memcpy(pubkey->u.ec.ecpointQ.value, key->u.ec.ecpointQ.value, key->u.ec.ecpointQ.len); |
1138 | 0 | pubkey->u.ec.ecpointQ.len = key->u.ec.ecpointQ.len; |
1139 | |
|
1140 | 0 | if (key->u.ec.params.named_curve) { |
1141 | 0 | rv = sc_pkcs15_fix_ec_parameters(ctx, &key->u.ec.params); |
1142 | 0 | if (rv) |
1143 | 0 | break; |
1144 | 0 | } |
1145 | | |
1146 | 0 | pubkey->u.ec.params.der.value = malloc(key->u.ec.params.der.len); |
1147 | 0 | if (!pubkey->u.ec.params.der.value) { |
1148 | 0 | rv = SC_ERROR_OUT_OF_MEMORY; |
1149 | 0 | break; |
1150 | 0 | } |
1151 | 0 | memcpy(pubkey->u.ec.params.der.value, key->u.ec.params.der.value, key->u.ec.params.der.len); |
1152 | 0 | pubkey->u.ec.params.der.len = key->u.ec.params.der.len; |
1153 | | |
1154 | | /* RFC4810 no named_curve */ |
1155 | 0 | if ((key->algorithm != SC_ALGORITHM_EDDSA) && (key->algorithm != SC_ALGORITHM_XEDDSA)) { |
1156 | 0 | if (key->u.ec.params.named_curve) { |
1157 | 0 | pubkey->u.ec.params.named_curve = strdup(key->u.ec.params.named_curve); |
1158 | 0 | if (!pubkey->u.ec.params.named_curve) |
1159 | 0 | rv = SC_ERROR_OUT_OF_MEMORY; |
1160 | 0 | } else { |
1161 | 0 | sc_log(ctx, "named_curve parameter missing"); |
1162 | 0 | rv = SC_ERROR_NOT_SUPPORTED; |
1163 | 0 | } |
1164 | 0 | } |
1165 | |
|
1166 | 0 | break; |
1167 | 0 | default: |
1168 | 0 | sc_log(ctx, "Unsupported private key algorithm"); |
1169 | 0 | rv = SC_ERROR_NOT_SUPPORTED; |
1170 | 0 | } |
1171 | | |
1172 | 0 | if (rv) |
1173 | 0 | sc_pkcs15_free_pubkey(pubkey); |
1174 | 0 | else |
1175 | 0 | *out = pubkey; |
1176 | |
|
1177 | 0 | LOG_FUNC_RETURN(ctx, rv); |
1178 | 0 | } |
1179 | | |
1180 | | |
1181 | | |
1182 | | void |
1183 | | sc_pkcs15_erase_pubkey(struct sc_pkcs15_pubkey *key) |
1184 | 0 | { |
1185 | 0 | if (key == NULL) { |
1186 | 0 | return; |
1187 | 0 | } |
1188 | 0 | if (key->alg_id) { |
1189 | 0 | sc_asn1_clear_algorithm_id(key->alg_id); |
1190 | 0 | free(key->alg_id); |
1191 | 0 | } |
1192 | 0 | switch (key->algorithm) { |
1193 | 0 | case SC_ALGORITHM_RSA: |
1194 | 0 | free(key->u.rsa.modulus.data); |
1195 | 0 | free(key->u.rsa.exponent.data); |
1196 | 0 | break; |
1197 | 0 | case SC_ALGORITHM_GOSTR3410: |
1198 | 0 | free(key->u.gostr3410.xy.data); |
1199 | 0 | break; |
1200 | 0 | case SC_ALGORITHM_EC: |
1201 | 0 | case SC_ALGORITHM_EDDSA: |
1202 | 0 | case SC_ALGORITHM_XEDDSA: |
1203 | 0 | free(key->u.ec.params.der.value); |
1204 | 0 | free(key->u.ec.params.named_curve); |
1205 | 0 | free(key->u.ec.ecpointQ.value); |
1206 | 0 | break; |
1207 | 0 | } |
1208 | 0 | sc_mem_clear(key, sizeof(*key)); |
1209 | 0 | } |
1210 | | |
1211 | | |
1212 | | void |
1213 | | sc_pkcs15_free_pubkey(struct sc_pkcs15_pubkey *key) |
1214 | 0 | { |
1215 | 0 | if (!key) |
1216 | 0 | return; |
1217 | 0 | sc_pkcs15_erase_pubkey(key); |
1218 | 0 | free(key); |
1219 | 0 | } |
1220 | | |
1221 | | |
1222 | | void |
1223 | | sc_pkcs15_free_pubkey_info(sc_pkcs15_pubkey_info_t *info) |
1224 | 0 | { |
1225 | 0 | if (info) { |
1226 | 0 | free(info->subject.value); |
1227 | 0 | free(info->direct.spki.value); |
1228 | 0 | free(info->direct.raw.value); |
1229 | 0 | sc_pkcs15_free_key_params(&info->params); |
1230 | 0 | free(info); |
1231 | 0 | } |
1232 | 0 | } |
1233 | | |
1234 | | |
1235 | | static int |
1236 | | sc_pkcs15_read_der_file(sc_context_t *ctx, char * filename, |
1237 | | u8 ** buf, size_t * buflen) |
1238 | 0 | { |
1239 | 0 | int r; |
1240 | 0 | int f = -1; |
1241 | 0 | size_t len, offs; |
1242 | 0 | u8 tagbuf[16]; /* enough to read in the tag and length */ |
1243 | 0 | u8 * rbuf = NULL; |
1244 | 0 | size_t rbuflen = 0; |
1245 | 0 | const u8 * body = NULL; |
1246 | 0 | size_t bodylen; |
1247 | 0 | unsigned int cla_out, tag_out; |
1248 | 0 | ssize_t sz; |
1249 | |
|
1250 | 0 | LOG_FUNC_CALLED(ctx); |
1251 | 0 | if (!buf || !buflen) |
1252 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); |
1253 | | |
1254 | 0 | *buf = NULL; |
1255 | 0 | *buflen = 0; |
1256 | |
|
1257 | 0 | f = open(filename, O_RDONLY); |
1258 | 0 | if (f < 0) { |
1259 | 0 | r = SC_ERROR_FILE_NOT_FOUND; |
1260 | 0 | goto out; |
1261 | 0 | } |
1262 | | |
1263 | 0 | sz = read(f, tagbuf, sizeof(tagbuf)); /* get tag and length */ |
1264 | 0 | if (sz < 2) { |
1265 | 0 | sc_log(ctx, "Problem with '%s'", filename); |
1266 | 0 | r = SC_ERROR_DATA_OBJECT_NOT_FOUND; |
1267 | 0 | goto out; |
1268 | 0 | } |
1269 | 0 | len = sz; |
1270 | |
|
1271 | 0 | body = tagbuf; |
1272 | 0 | r = sc_asn1_read_tag(&body, len, &cla_out, &tag_out, &bodylen); |
1273 | 0 | if (r != SC_SUCCESS && r != SC_ERROR_ASN1_END_OF_CONTENTS) |
1274 | 0 | goto out; |
1275 | | |
1276 | 0 | if (body == NULL) { |
1277 | 0 | r = SC_SUCCESS; |
1278 | 0 | goto out; |
1279 | 0 | } |
1280 | | |
1281 | 0 | offs = body - tagbuf; |
1282 | 0 | if (offs > len || offs < 2 || offs > offs + bodylen) { |
1283 | 0 | r = SC_ERROR_INVALID_ASN1_OBJECT; |
1284 | 0 | goto out; |
1285 | 0 | } |
1286 | | |
1287 | 0 | rbuflen = offs + bodylen; |
1288 | 0 | rbuf = malloc(rbuflen); |
1289 | 0 | if (rbuf == NULL) { |
1290 | 0 | r = SC_ERROR_OUT_OF_MEMORY; |
1291 | 0 | goto out; |
1292 | 0 | } |
1293 | 0 | memcpy(rbuf, tagbuf, len); /* copy first or only part */ |
1294 | 0 | if (rbuflen > len) { |
1295 | | /* read rest of file */ |
1296 | 0 | sz = read(f, rbuf + len, rbuflen - len); |
1297 | 0 | if (sz < (ssize_t)(rbuflen - len)) { |
1298 | 0 | r = SC_ERROR_INVALID_ASN1_OBJECT; |
1299 | 0 | free (rbuf); |
1300 | 0 | rbuf = NULL; |
1301 | 0 | goto out; |
1302 | 0 | } |
1303 | 0 | } |
1304 | 0 | *buflen = rbuflen; |
1305 | 0 | *buf = rbuf; |
1306 | 0 | rbuf = NULL; |
1307 | 0 | r = (int)rbuflen; |
1308 | 0 | out: |
1309 | 0 | if (f >= 0) |
1310 | 0 | close(f); |
1311 | |
|
1312 | 0 | LOG_FUNC_RETURN(ctx, r); |
1313 | 0 | } |
1314 | | |
1315 | | /* |
1316 | | * can be used as an SC_ASN1_CALLBACK while parsing a certificate, |
1317 | | * or can be called from the sc_pkcs15_pubkey_from_spki_file |
1318 | | */ |
1319 | | int |
1320 | | sc_pkcs15_pubkey_from_spki_fields(struct sc_context *ctx, struct sc_pkcs15_pubkey **outpubkey, |
1321 | | unsigned char *buf, size_t buflen, int depth) |
1322 | 0 | { |
1323 | |
|
1324 | 0 | struct sc_pkcs15_pubkey *pubkey = NULL; |
1325 | 0 | struct sc_pkcs15_der pk = { NULL, 0 }; |
1326 | 0 | struct sc_algorithm_id pk_alg; |
1327 | 0 | struct sc_asn1_entry asn1_pkinfo[C_ASN1_PKINFO_ATTR_SIZE]; |
1328 | 0 | unsigned char *tmp_buf = NULL; |
1329 | 0 | int r; |
1330 | |
|
1331 | 0 | sc_log(ctx, |
1332 | 0 | "sc_pkcs15_pubkey_from_spki_fields() called: %p:%"SC_FORMAT_LEN_SIZE_T"u\n%s", |
1333 | 0 | buf, buflen, sc_dump_hex(buf, buflen)); |
1334 | |
|
1335 | 0 | tmp_buf = malloc(buflen); |
1336 | 0 | if (!tmp_buf) { |
1337 | 0 | r = SC_ERROR_OUT_OF_MEMORY; |
1338 | 0 | LOG_TEST_GOTO_ERR(ctx, r, ""); |
1339 | 0 | } |
1340 | 0 | memcpy(tmp_buf, buf, buflen); |
1341 | |
|
1342 | 0 | if ((*tmp_buf & SC_ASN1_TAG_CONTEXT)) |
1343 | 0 | *tmp_buf = SC_ASN1_TAG_CONSTRUCTED | SC_ASN1_TAG_SEQUENCE; |
1344 | |
|
1345 | 0 | memset(&pk_alg, 0, sizeof(pk_alg)); |
1346 | 0 | pubkey = calloc(1, sizeof(sc_pkcs15_pubkey_t)); |
1347 | 0 | if (pubkey == NULL) { |
1348 | 0 | r = SC_ERROR_OUT_OF_MEMORY; |
1349 | 0 | LOG_TEST_GOTO_ERR(ctx, r, ""); |
1350 | 0 | } |
1351 | | |
1352 | 0 | sc_copy_asn1_entry(c_asn1_pkinfo, asn1_pkinfo); |
1353 | |
|
1354 | 0 | sc_format_asn1_entry(asn1_pkinfo + 0, &pk_alg, NULL, 0); |
1355 | 0 | sc_format_asn1_entry(asn1_pkinfo + 1, &pk.value, &pk.len, 0); |
1356 | |
|
1357 | 0 | r = sc_asn1_decode(ctx, asn1_pkinfo, tmp_buf, buflen, NULL, NULL); |
1358 | 0 | if (r != SC_SUCCESS) { |
1359 | 0 | sc_asn1_clear_algorithm_id(&pk_alg); |
1360 | 0 | LOG_TEST_GOTO_ERR(ctx, r, "ASN.1 parsing of subjectPubkeyInfo failed"); |
1361 | 0 | } |
1362 | | |
1363 | 0 | pubkey->alg_id = calloc(1, sizeof(struct sc_algorithm_id)); |
1364 | 0 | if (pubkey->alg_id == NULL) { |
1365 | 0 | r = SC_ERROR_OUT_OF_MEMORY; |
1366 | 0 | LOG_TEST_GOTO_ERR(ctx, r, ""); |
1367 | 0 | } |
1368 | | |
1369 | 0 | memcpy(pubkey->alg_id, &pk_alg, sizeof(struct sc_algorithm_id)); |
1370 | 0 | pubkey->algorithm = pk_alg.algorithm; |
1371 | 0 | pk_alg.params = NULL; |
1372 | 0 | sc_log(ctx, "DEE pk_alg.algorithm=%lu", pk_alg.algorithm); |
1373 | |
|
1374 | 0 | if (pk.len == 0) |
1375 | 0 | LOG_TEST_GOTO_ERR(ctx, SC_ERROR_INTERNAL, "Incorrect length of key"); |
1376 | 0 | pk.len = BYTES4BITS(pk.len); /* convert number of bits to bytes */ |
1377 | |
|
1378 | 0 | if (pk_alg.algorithm == SC_ALGORITHM_EC) { |
1379 | | /* EC public key is not encapsulated into BIT STRING -- it's a BIT STRING */ |
1380 | | /* |
1381 | | * sc_pkcs15_fix_ec_parameters below will set field_length from curve. |
1382 | | * if no alg_id->params, assume field_length is multiple of 8 |
1383 | | */ |
1384 | 0 | pubkey->u.ec.params.field_length = (pk.len - 1) / 2 * 8; |
1385 | |
|
1386 | 0 | if (pubkey->alg_id->params) { |
1387 | 0 | struct sc_ec_parameters *ecp = (struct sc_ec_parameters *)pubkey->alg_id->params; |
1388 | |
|
1389 | 0 | pubkey->u.ec.params.der.value = malloc(ecp->der.len); |
1390 | 0 | if (pubkey->u.ec.params.der.value == NULL) { |
1391 | 0 | r = SC_ERROR_OUT_OF_MEMORY; |
1392 | 0 | LOG_TEST_GOTO_ERR(ctx, r, ""); |
1393 | 0 | } |
1394 | | |
1395 | 0 | memcpy(pubkey->u.ec.params.der.value, ecp->der.value, ecp->der.len); |
1396 | 0 | pubkey->u.ec.params.der.len = ecp->der.len; |
1397 | 0 | r = sc_pkcs15_fix_ec_parameters(ctx, &pubkey->u.ec.params); |
1398 | 0 | LOG_TEST_GOTO_ERR(ctx, r, "failed to fix EC parameters"); |
1399 | 0 | } |
1400 | | |
1401 | 0 | pubkey->u.ec.ecpointQ.value = malloc(pk.len); |
1402 | 0 | if (pubkey->u.ec.ecpointQ.value == NULL) { |
1403 | 0 | r = SC_ERROR_OUT_OF_MEMORY; |
1404 | 0 | LOG_TEST_GOTO_ERR(ctx, r, "failed to malloc() memory"); |
1405 | 0 | } |
1406 | 0 | memcpy(pubkey->u.ec.ecpointQ.value, pk.value, pk.len); |
1407 | 0 | pubkey->u.ec.ecpointQ.len = pk.len; |
1408 | 0 | } else if (pk_alg.algorithm == SC_ALGORITHM_EDDSA || |
1409 | 0 | pk_alg.algorithm == SC_ALGORITHM_XEDDSA) { |
1410 | | /* |
1411 | | * SPKI will have OID, EDDSA can have ED25519 or ED448 with different sizes |
1412 | | * EDDSA/XEDDSA public key is not encapsulated into BIT STRING -- it's a BIT STRING |
1413 | | * no params, but oid is the params. |
1414 | | */ |
1415 | 0 | r = sc_encode_oid(ctx, &pk_alg.oid, &pubkey->u.ec.params.der.value, &pubkey->u.ec.params.der.len); |
1416 | 0 | LOG_TEST_GOTO_ERR(ctx, r, "failed to encode (X)EDDSA oid"); |
1417 | 0 | r = sc_pkcs15_fix_ec_parameters(ctx, &pubkey->u.ec.params); |
1418 | 0 | LOG_TEST_GOTO_ERR(ctx, r, "failed to fix EC parameters"); |
1419 | | |
1420 | 0 | pubkey->u.ec.ecpointQ.value = malloc(pk.len); |
1421 | 0 | memcpy(pubkey->u.ec.ecpointQ.value, pk.value, pk.len); |
1422 | 0 | pubkey->u.ec.ecpointQ.len = pk.len; |
1423 | 0 | } else { |
1424 | | /* Public key is expected to be encapsulated into BIT STRING */ |
1425 | 0 | r = sc_pkcs15_decode_pubkey(ctx, pubkey, pk.value, pk.len); |
1426 | 0 | LOG_TEST_GOTO_ERR(ctx, r, "ASN.1 parsing of subjectPubkeyInfo failed"); |
1427 | 0 | } |
1428 | | |
1429 | 0 | *outpubkey = pubkey; |
1430 | 0 | pubkey = NULL; |
1431 | |
|
1432 | 0 | err: |
1433 | 0 | sc_pkcs15_free_pubkey(pubkey); |
1434 | 0 | free(pk.value); |
1435 | 0 | free(tmp_buf); |
1436 | |
|
1437 | 0 | LOG_FUNC_RETURN(ctx, r); |
1438 | 0 | } |
1439 | | |
1440 | | |
1441 | | int |
1442 | | sc_pkcs15_pubkey_from_spki_sequence(struct sc_context *ctx, const unsigned char *buf, size_t buflen, |
1443 | | struct sc_pkcs15_pubkey ** outpubkey) |
1444 | 0 | { |
1445 | 0 | struct sc_pkcs15_pubkey * pubkey = NULL; |
1446 | 0 | struct sc_asn1_entry asn1_spki[] = { |
1447 | 0 | { "subjectPublicKeyInfo", SC_ASN1_CALLBACK, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, sc_pkcs15_pubkey_from_spki_fields, &pubkey}, |
1448 | 0 | { NULL, 0, 0, 0, NULL, NULL } }; |
1449 | 0 | int r; |
1450 | |
|
1451 | 0 | LOG_FUNC_CALLED(ctx); |
1452 | |
|
1453 | 0 | r = sc_asn1_decode(ctx, asn1_spki, buf, buflen, NULL, NULL); |
1454 | 0 | LOG_TEST_RET(ctx, r, "ASN.1 cannot parse subjectPublicKeyInfo"); |
1455 | | |
1456 | 0 | if(outpubkey) { |
1457 | 0 | free(*outpubkey); |
1458 | 0 | *outpubkey = pubkey; |
1459 | 0 | } else |
1460 | 0 | free(pubkey); |
1461 | |
|
1462 | 0 | LOG_FUNC_RETURN(ctx, r); |
1463 | 0 | } |
1464 | | |
1465 | | |
1466 | | int |
1467 | | sc_pkcs15_pubkey_from_spki_file(struct sc_context *ctx, char * filename, |
1468 | | struct sc_pkcs15_pubkey ** outpubkey) |
1469 | 0 | { |
1470 | 0 | int r; |
1471 | 0 | u8 * buf = NULL; |
1472 | 0 | size_t buflen = 0; |
1473 | |
|
1474 | 0 | LOG_FUNC_CALLED(ctx); |
1475 | |
|
1476 | 0 | r = sc_pkcs15_read_der_file(ctx, filename, &buf, &buflen); |
1477 | 0 | LOG_TEST_RET(ctx, r, "Cannot read SPKI DER file"); |
1478 | | |
1479 | 0 | r = sc_pkcs15_pubkey_from_spki_sequence(ctx, buf, buflen, outpubkey); |
1480 | 0 | free(buf); |
1481 | |
|
1482 | 0 | LOG_FUNC_RETURN(ctx, r); |
1483 | 0 | } |
1484 | | |
1485 | | // clang-format off |
1486 | | static struct ec_curve_info { |
1487 | | const char *name; |
1488 | | const char *oid_str; |
1489 | | const struct sc_pkcs15_der oid_der; |
1490 | | size_t size; |
1491 | | const unsigned int key_type; |
1492 | | |
1493 | | } ec_curve_infos[] = { |
1494 | | {"secp192r1", "1.2.840.10045.3.1.1", {(u8 *)"\x06\x08\x2A\x86\x48\xCE\x3D\x03\x01\x01", 10}, 192, SC_ALGORITHM_EC}, |
1495 | | {"prime192v1", "1.2.840.10045.3.1.1", {(u8 *)"\x06\x08\x2A\x86\x48\xCE\x3D\x03\x01\x01", 10}, 192, SC_ALGORITHM_EC}, |
1496 | | {"nistp192", "1.2.840.10045.3.1.1", {(u8 *)"\x06\x08\x2A\x86\x48\xCE\x3D\x03\x01\x01", 10}, 192, SC_ALGORITHM_EC}, |
1497 | | {"ansiX9p192r1", "1.2.840.10045.3.1.1", {(u8 *)"\x06\x08\x2A\x86\x48\xCE\x3D\x03\x01\x01", 10}, 192, SC_ALGORITHM_EC}, |
1498 | | |
1499 | | {"secp224r1", "1.3.132.0.33", {(u8 *)"\x06\x05\x2b\x81\x04\x00\x21", 7}, 224, SC_ALGORITHM_EC}, |
1500 | | {"nistp224", "1.3.132.0.33", {(u8 *)"\x06\x05\x2b\x81\x04\x00\x21", 7}, 224, SC_ALGORITHM_EC}, |
1501 | | |
1502 | | {"prime256v1", "1.2.840.10045.3.1.7", {(u8 *)"\x06\x08\x2A\x86\x48\xCE\x3D\x03\x01\x07", 10}, 256, SC_ALGORITHM_EC}, |
1503 | | {"secp256r1", "1.2.840.10045.3.1.7", {(u8 *)"\x06\x08\x2A\x86\x48\xCE\x3D\x03\x01\x07", 10}, 256, SC_ALGORITHM_EC}, |
1504 | | {"nistp256", "1.2.840.10045.3.1.7", {(u8 *)"\x06\x08\x2A\x86\x48\xCE\x3D\x03\x01\x07", 10}, 256, SC_ALGORITHM_EC}, |
1505 | | {"ansiX9p256r1", "1.2.840.10045.3.1.7", {(u8 *)"\x06\x08\x2A\x86\x48\xCE\x3D\x03\x01\x07", 10}, 256, SC_ALGORITHM_EC}, |
1506 | | |
1507 | | {"secp384r1", "1.3.132.0.34", {(u8 *)"\x06\x05\x2B\x81\x04\x00\x22", 7}, 384, SC_ALGORITHM_EC}, |
1508 | | {"prime384v1", "1.3.132.0.34", {(u8 *)"\x06\x05\x2B\x81\x04\x00\x22", 7}, 384, SC_ALGORITHM_EC}, |
1509 | | {"nistp384", "1.3.132.0.34", {(u8 *)"\x06\x05\x2B\x81\x04\x00\x22", 7}, 384, SC_ALGORITHM_EC}, |
1510 | | {"ansiX9p384r1", "1.3.132.0.34", {(u8 *)"\x06\x05\x2B\x81\x04\x00\x22", 7}, 384, SC_ALGORITHM_EC}, |
1511 | | |
1512 | | {"secp521r1", "1.3.132.0.35", {(u8 *)"\x06\x05\x2B\x81\x04\x00\x23", 7}, 521, SC_ALGORITHM_EC}, |
1513 | | {"nistp521", "1.3.132.0.35", {(u8 *)"\x06\x05\x2B\x81\x04\x00\x23", 7}, 521, SC_ALGORITHM_EC}, |
1514 | | |
1515 | | {"brainpoolP192r1", "1.3.36.3.3.2.8.1.1.3", {(u8 *)"\x06\x09\x2B\x24\x03\x03\x02\x08\x01\x01\x03", 11}, 192, SC_ALGORITHM_EC}, |
1516 | | {"brainpoolP224r1", "1.3.36.3.3.2.8.1.1.5", {(u8 *)"\x06\x09\x2B\x24\x03\x03\x02\x08\x01\x01\x05", 11}, 224, SC_ALGORITHM_EC}, |
1517 | | {"brainpoolP256r1", "1.3.36.3.3.2.8.1.1.7", {(u8 *)"\x06\x09\x2B\x24\x03\x03\x02\x08\x01\x01\x07", 11}, 256, SC_ALGORITHM_EC}, |
1518 | | {"brainpoolP320r1", "1.3.36.3.3.2.8.1.1.9", {(u8 *)"\x06\x09\x2B\x24\x03\x03\x02\x08\x01\x01\x09", 11}, 320, SC_ALGORITHM_EC}, |
1519 | | {"brainpoolP384r1", "1.3.36.3.3.2.8.1.1.11", {(u8 *)"\x06\x09\x2B\x24\x03\x03\x02\x08\x01\x01\x0B", 11}, 384, SC_ALGORITHM_EC}, |
1520 | | {"brainpoolP512r1", "1.3.36.3.3.2.8.1.1.13", {(u8 *)"\x06\x09\x2B\x24\x03\x03\x02\x08\x01\x01\x0D", 11}, 512, SC_ALGORITHM_EC}, |
1521 | | |
1522 | | {"secp192k1", "1.3.132.0.31", {(u8 *)"\x06\x05\x2B\x81\x04\x00\x1F", 7}, 192, SC_ALGORITHM_EC}, |
1523 | | {"secp256k1", "1.3.132.0.10", {(u8 *)"\x06\x05\x2B\x81\x04\x00\x0A", 7}, 256, SC_ALGORITHM_EC}, |
1524 | | |
1525 | | /* OpenPGP extensions by Yubikey and GNUK are not defined in RFCs but we know the oid written to card */ |
1526 | | |
1527 | | {"edwards25519", "1.3.6.1.4.1.11591.15.1", {(u8 *)"\x06\x09\x2B\x06\x01\x04\x01\xDA\x47\x0F\x01", 11}, 256, SC_ALGORITHM_EDDSA}, |
1528 | | {"curve25519", "1.3.6.1.4.1.3029.1.5.1", {(u8 *)"\x06\x0A\x2B\x06\x01\x04\x01\x97\x55\x01\x05\x01", 12}, 256, SC_ALGORITHM_XEDDSA}, |
1529 | | |
1530 | | /* RFC 8410 defined curves */ |
1531 | | {"X25519", "1.3.101.110", {(u8 *)"\x06\x03\x2b\x65\x6e", 5}, 256, SC_ALGORITHM_XEDDSA}, |
1532 | | {"X448", "1.3.101.111", {(u8 *)"\x06\x03\x2b\x65\x6f", 5}, 448, SC_ALGORITHM_XEDDSA}, |
1533 | | {"Ed25519", "1.3.101.112", {(u8 *)"\x06\x03\x2b\x65\x70", 5}, 256, SC_ALGORITHM_EDDSA}, |
1534 | | /* Ed448 needs extra byte thus 456 */ |
1535 | | {"Ed448", "1.3.101.113", {(u8 *)"\x06\x03\x2b\x65\x71", 5}, 456, SC_ALGORITHM_EDDSA}, |
1536 | | /* GnuPG openpgp curves as used in gnupg-card are equivalent to RFC8410 OIDs */ |
1537 | | {"cv25519", "1.3.101.110", {(u8 *)"\x06\x03\x2b\x65\x6e", 5}, 256, SC_ALGORITHM_XEDDSA}, |
1538 | | {"ed25519", "1.3.101.112", {(u8 *)"\x06\x03\x2b\x65\x70", 5}, 256, SC_ALGORITHM_EDDSA}, |
1539 | | |
1540 | | {NULL, NULL, {NULL, 0}, 0, 0}, /* Do not touch this */ |
1541 | | }; |
1542 | | // clang-format on |
1543 | | |
1544 | | int |
1545 | | sc_pkcs15_fix_ec_parameters(struct sc_context *ctx, struct sc_ec_parameters *ecparams) |
1546 | 0 | { |
1547 | 0 | int rv, ii; |
1548 | 0 | int mapped_string = 0; /* der is printable string that can be replaced with der of OID */ |
1549 | |
|
1550 | 0 | LOG_FUNC_CALLED(ctx); |
1551 | | |
1552 | | /* In PKCS#11 EC parameters arrives in DER encoded form */ |
1553 | 0 | if (ecparams->der.value && ecparams->der.len && ecparams->der.len > 2) { |
1554 | |
|
1555 | 0 | switch (ecparams->der.value[0]) { |
1556 | 0 | case 0x06: /* der.value is an OID */ |
1557 | 0 | for (ii = 0; ec_curve_infos[ii].name; ii++) { |
1558 | 0 | size_t len = ec_curve_infos[ii].oid_der.len; |
1559 | |
|
1560 | 0 | if (ecparams->der.len == len && |
1561 | 0 | memcmp(ecparams->der.value, ec_curve_infos[ii].oid_der.value, len) == 0) |
1562 | 0 | break; /* found ec_curve_infos[ii] */ |
1563 | 0 | } |
1564 | 0 | break; |
1565 | | |
1566 | 0 | case 0x13: |
1567 | | /* printable string as per PKCS11 V 3.0 for experimental curves */ |
1568 | 0 | { |
1569 | 0 | int r_tag; |
1570 | 0 | const u8 *body = ecparams->der.value; |
1571 | 0 | size_t len = ecparams->der.len; |
1572 | 0 | unsigned int cla_out, tag_out; |
1573 | 0 | size_t bodylen; |
1574 | |
|
1575 | 0 | r_tag = sc_asn1_read_tag(&body, len, &cla_out, &tag_out, &bodylen); |
1576 | 0 | if (r_tag != SC_SUCCESS || tag_out != 0x13) { |
1577 | 0 | sc_log(ctx, "Invalid printable string"); |
1578 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); |
1579 | 0 | } |
1580 | 0 | for (ii = 0; ec_curve_infos[ii].name; ii++) { |
1581 | 0 | size_t len = strlen(ec_curve_infos[ii].name); |
1582 | 0 | if (bodylen != len || memcmp(ec_curve_infos[ii].name, body, len) != 0) |
1583 | 0 | continue; |
1584 | | /* found replacement of printable string to OID */ |
1585 | 0 | mapped_string = 1; |
1586 | 0 | break; |
1587 | 0 | } |
1588 | 0 | } |
1589 | 0 | break; |
1590 | | |
1591 | 0 | default: |
1592 | 0 | sc_log(ctx, "Unsupported ec params"); |
1593 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); |
1594 | 0 | } |
1595 | | |
1596 | 0 | if (ec_curve_infos[ii].name == NULL) /* end of ec_curve_info */ |
1597 | 0 | LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Unsupported named curve"); |
1598 | | |
1599 | | /* ii points to entry with matching oid_der or a mapped entry with replacement oid_der */ |
1600 | 0 | sc_log(ctx, "Found known curve '%s'", ec_curve_infos[ii].name); |
1601 | 0 | if (mapped_string) { /* free previous name if any replace below with new name */ |
1602 | 0 | free(ecparams->named_curve); |
1603 | 0 | ecparams->named_curve = NULL; |
1604 | 0 | } |
1605 | |
|
1606 | 0 | if (!ecparams->named_curve) { /* if present,keep the name as some curves have multiple names */ |
1607 | 0 | ecparams->named_curve = strdup(ec_curve_infos[ii].name); |
1608 | 0 | if (!ecparams->named_curve) |
1609 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); |
1610 | | |
1611 | 0 | sc_log(ctx, "Curve name: '%s'", ecparams->named_curve); |
1612 | 0 | } |
1613 | | |
1614 | | /* fill in object_id based on oid_der */ |
1615 | 0 | sc_format_oid(&ecparams->id, ec_curve_infos[ii].oid_str); |
1616 | |
|
1617 | 0 | ecparams->field_length = ec_curve_infos[ii].size; |
1618 | 0 | ecparams->key_type = ec_curve_infos[ii].key_type; |
1619 | 0 | sc_log(ctx, "Curve length %" SC_FORMAT_LEN_SIZE_T "u key_type %d", |
1620 | 0 | ecparams->field_length, ecparams->key_type); |
1621 | 0 | if (mapped_string) { |
1622 | | /* replace the printable string version with the oid */ |
1623 | 0 | if (ecparams->der.value) |
1624 | 0 | free(ecparams->der.value); |
1625 | 0 | ecparams->der.len = ec_curve_infos[ii].oid_der.len; |
1626 | 0 | ecparams->der.value = malloc(ecparams->der.len); |
1627 | 0 | if (ecparams->der.value == NULL) { |
1628 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); |
1629 | 0 | } |
1630 | 0 | memcpy(ecparams->der.value, ec_curve_infos[ii].oid_der.value, ecparams->der.len); |
1631 | 0 | } |
1632 | 0 | } else if (ecparams->named_curve) { /* it can be name of curve or OID in ASCII form */ |
1633 | | /* caller did not provide an OID, look for a name or oid_string */ |
1634 | 0 | for (ii = 0; ec_curve_infos[ii].name; ii++) { |
1635 | 0 | if (!strcmp(ec_curve_infos[ii].name, ecparams->named_curve)) |
1636 | 0 | break; |
1637 | 0 | if (!strcmp(ec_curve_infos[ii].oid_str, ecparams->named_curve)) |
1638 | 0 | break; |
1639 | 0 | } |
1640 | 0 | if (!ec_curve_infos[ii].name) { |
1641 | 0 | sc_log(ctx, "Named curve '%s' not supported", ecparams->named_curve); |
1642 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); |
1643 | 0 | } |
1644 | | |
1645 | 0 | rv = sc_format_oid(&ecparams->id, ec_curve_infos[ii].oid_str); |
1646 | 0 | LOG_TEST_RET(ctx, rv, "Invalid OID format"); |
1647 | | |
1648 | 0 | ecparams->field_length = ec_curve_infos[ii].size; |
1649 | 0 | ecparams->key_type = ec_curve_infos[ii].key_type; |
1650 | 0 | sc_log(ctx, "Curve length %" SC_FORMAT_LEN_SIZE_T "u key_type %d", |
1651 | 0 | ecparams->field_length, ecparams->key_type); |
1652 | |
|
1653 | 0 | if (ecparams->der.value == NULL || ecparams->der.len == 0) { |
1654 | 0 | free(ecparams->der.value); /* just in case */ |
1655 | 0 | ecparams->der.value = NULL; |
1656 | 0 | ecparams->der.len = 0; |
1657 | | /* if caller did not provide valid der OID, fill in */ |
1658 | 0 | rv = sc_encode_oid (ctx, &ecparams->id, &ecparams->der.value, &ecparams->der.len); |
1659 | 0 | LOG_TEST_RET(ctx, rv, "Cannot encode object ID"); |
1660 | 0 | } |
1661 | 0 | } else |
1662 | 0 | LOG_TEST_RET(ctx, SC_ERROR_NOT_IMPLEMENTED, "EC parameters has to be presented as a named curve or explicit data"); |
1663 | | |
1664 | 0 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
1665 | 0 | } |
1666 | | |
1667 | | |
1668 | | int |
1669 | | sc_pkcs15_convert_pubkey(struct sc_pkcs15_pubkey *pkcs15_key, void *evp_key) |
1670 | 0 | { |
1671 | 0 | #ifdef ENABLE_OPENSSL |
1672 | 0 | EVP_PKEY *pk = (EVP_PKEY *)evp_key; |
1673 | 0 | int pk_type; |
1674 | 0 | pk_type = EVP_PKEY_base_id(pk); |
1675 | |
|
1676 | 0 | switch (pk_type) { |
1677 | 0 | case EVP_PKEY_RSA: { |
1678 | 0 | struct sc_pkcs15_pubkey_rsa *dst = &pkcs15_key->u.rsa; |
1679 | | /* Get parameters */ |
1680 | 0 | #if OPENSSL_VERSION_NUMBER < 0x30000000L |
1681 | 0 | const BIGNUM *src_n, *src_e; |
1682 | 0 | RSA *src = NULL; |
1683 | 0 | if (!(src = EVP_PKEY_get1_RSA(pk))) |
1684 | 0 | return SC_ERROR_INCOMPATIBLE_KEY; |
1685 | 0 | RSA_get0_key(src, &src_n, &src_e, NULL); |
1686 | 0 | if (!src_n || !src_e) { |
1687 | 0 | RSA_free(src); |
1688 | 0 | return SC_ERROR_INTERNAL; |
1689 | 0 | } |
1690 | | #else |
1691 | | BIGNUM *src_n = NULL, *src_e = NULL; |
1692 | | if (EVP_PKEY_get_bn_param(pk, OSSL_PKEY_PARAM_RSA_N, &src_n) != 1 || |
1693 | | EVP_PKEY_get_bn_param(pk, OSSL_PKEY_PARAM_RSA_E, &src_e) != 1) { |
1694 | | BN_free(src_n); |
1695 | | return SC_ERROR_INTERNAL; |
1696 | | } |
1697 | | #endif |
1698 | | /* Convert */ |
1699 | 0 | pkcs15_key->algorithm = SC_ALGORITHM_RSA; |
1700 | 0 | if (!sc_pkcs15_convert_bignum(&dst->modulus, src_n) || |
1701 | 0 | !sc_pkcs15_convert_bignum(&dst->exponent, src_e)) { |
1702 | 0 | #if OPENSSL_VERSION_NUMBER < 0x30000000L |
1703 | 0 | RSA_free(src); |
1704 | | #else |
1705 | | BN_free(src_n); BN_free(src_e); |
1706 | | #endif |
1707 | 0 | return SC_ERROR_INVALID_DATA; |
1708 | 0 | } |
1709 | | |
1710 | 0 | #if OPENSSL_VERSION_NUMBER < 0x30000000L |
1711 | 0 | RSA_free(src); |
1712 | | #else |
1713 | | BN_free(src_n); BN_free(src_e); |
1714 | | #endif |
1715 | 0 | break; |
1716 | 0 | } |
1717 | 0 | #if !defined(OPENSSL_NO_EC) |
1718 | 0 | case NID_id_GostR3410_2001: { |
1719 | 0 | struct sc_pkcs15_pubkey_gostr3410 *dst = &pkcs15_key->u.gostr3410; |
1720 | 0 | BIGNUM *X, *Y; |
1721 | 0 | int r = 0; |
1722 | 0 | #if OPENSSL_VERSION_NUMBER < 0x30000000L |
1723 | 0 | const EC_KEY *eckey = NULL; |
1724 | 0 | const EC_POINT *point = NULL; |
1725 | 0 | const EC_GROUP *group = NULL; |
1726 | 0 | if (!(eckey = EVP_PKEY_get0(pk))) |
1727 | 0 | return SC_ERROR_INCOMPATIBLE_KEY; |
1728 | 0 | if (!(point = EC_KEY_get0_public_key(eckey)) || |
1729 | 0 | !(group = EC_KEY_get0_group(eckey))) |
1730 | 0 | return SC_ERROR_INTERNAL; |
1731 | | #else |
1732 | | EC_POINT *point = NULL; |
1733 | | EC_GROUP *group = NULL; |
1734 | | int nid = 0; |
1735 | | unsigned char *pub = NULL; |
1736 | | size_t pub_len = 0; |
1737 | | char *group_name = NULL; |
1738 | | size_t group_name_len = 0; |
1739 | | |
1740 | | if (EVP_PKEY_get_octet_string_param(pk, OSSL_PKEY_PARAM_PUB_KEY, NULL, 0, &pub_len) != 1) { |
1741 | | return SC_ERROR_INTERNAL; |
1742 | | } |
1743 | | if (EVP_PKEY_get_group_name(pk, NULL, 0, &group_name_len) != 1) { |
1744 | | return SC_ERROR_INTERNAL; |
1745 | | } |
1746 | | if (!(pub = malloc(pub_len)) || !(group_name = malloc(group_name_len))) { |
1747 | | free(pub); |
1748 | | return SC_ERROR_OUT_OF_MEMORY; |
1749 | | } |
1750 | | if (EVP_PKEY_get_octet_string_param(pk, OSSL_PKEY_PARAM_PUB_KEY, pub, pub_len, NULL) != 1 || |
1751 | | EVP_PKEY_get_group_name(pk, group_name, group_name_len, NULL) != 1) { |
1752 | | free(pub); |
1753 | | free(group_name); |
1754 | | return SC_ERROR_INTERNAL; |
1755 | | } |
1756 | | if ((nid = OBJ_sn2nid(group_name) == 0) || |
1757 | | !(group = EC_GROUP_new_by_curve_name(nid)) || |
1758 | | !(point = EC_POINT_new(group)) || |
1759 | | EC_POINT_oct2point(group, point, pub, pub_len, NULL) != 1) { |
1760 | | free(pub); |
1761 | | free(group_name); |
1762 | | EC_POINT_free(point); |
1763 | | EC_GROUP_free(group); |
1764 | | return SC_ERROR_INTERNAL; |
1765 | | } |
1766 | | free(pub); |
1767 | | free(group_name); |
1768 | | #endif |
1769 | 0 | X = BN_new(); |
1770 | 0 | Y = BN_new(); |
1771 | 0 | if (X && Y && group) |
1772 | 0 | r = EC_POINT_get_affine_coordinates(group, point, X, Y, NULL); |
1773 | 0 | if (r == 1) { |
1774 | 0 | dst->xy.len = BN_num_bytes(X) + BN_num_bytes(Y); |
1775 | 0 | dst->xy.data = malloc(dst->xy.len); |
1776 | 0 | if (dst->xy.data) { |
1777 | 0 | BN_bn2bin(Y, dst->xy.data); |
1778 | 0 | BN_bn2bin(X, dst->xy.data + BN_num_bytes(Y)); |
1779 | 0 | r = sc_mem_reverse(dst->xy.data, dst->xy.len); |
1780 | 0 | if (!r) |
1781 | 0 | r = 1; |
1782 | 0 | pkcs15_key->algorithm = SC_ALGORITHM_GOSTR3410; |
1783 | 0 | } |
1784 | 0 | else |
1785 | 0 | r = -1; |
1786 | 0 | } |
1787 | 0 | BN_free(X); |
1788 | 0 | BN_free(Y); |
1789 | |
|
1790 | | #if OPENSSL_VERSION_NUMBER >= 0x30000000L |
1791 | | EC_GROUP_free(group); |
1792 | | EC_POINT_free(point); |
1793 | | #endif |
1794 | 0 | if (r != 1) |
1795 | 0 | return SC_ERROR_INTERNAL; |
1796 | 0 | break; |
1797 | 0 | } |
1798 | 0 | case EVP_PKEY_EC: { |
1799 | 0 | struct sc_pkcs15_pubkey_ec *dst = &pkcs15_key->u.ec; |
1800 | 0 | pkcs15_key->algorithm = SC_ALGORITHM_EC; |
1801 | 0 | unsigned char buf[255]; size_t buflen = 255; |
1802 | 0 | #if OPENSSL_VERSION_NUMBER < 0x30000000L |
1803 | 0 | const EC_KEY *src = NULL; |
1804 | 0 | const EC_GROUP *grp = NULL; |
1805 | 0 | const EC_POINT *point = NULL; |
1806 | 0 | int nid = 0; |
1807 | |
|
1808 | 0 | if (!(src = EVP_PKEY_get0_EC_KEY(pk))) |
1809 | 0 | return SC_ERROR_INCOMPATIBLE_KEY; |
1810 | 0 | if (!(point = EC_KEY_get0_public_key(src)) || |
1811 | 0 | !(grp = EC_KEY_get0_group(src))) { |
1812 | 0 | return SC_ERROR_INCOMPATIBLE_KEY; |
1813 | 0 | } |
1814 | | |
1815 | | /* Decode EC_POINT from a octet string */ |
1816 | 0 | buflen = EC_POINT_point2oct(grp, point, |
1817 | 0 | POINT_CONVERSION_UNCOMPRESSED, buf, buflen, NULL); |
1818 | | |
1819 | | /* get curve name */ |
1820 | 0 | nid = EC_GROUP_get_curve_name(grp); |
1821 | 0 | if(nid != 0) { |
1822 | 0 | const char *group_name = OBJ_nid2sn(nid); |
1823 | 0 | if (group_name) |
1824 | 0 | dst->params.named_curve = strdup(group_name); |
1825 | 0 | } |
1826 | | #else |
1827 | | char group_name[256]; |
1828 | | if (EVP_PKEY_get_octet_string_param(pk, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, buf, buflen, NULL) != 1) |
1829 | | return SC_ERROR_INTERNAL; |
1830 | | if (EVP_PKEY_get_group_name(pk, group_name, sizeof(group_name), NULL) != 1) |
1831 | | return SC_ERROR_INTERNAL; |
1832 | | dst->params.named_curve = strdup(group_name); |
1833 | | |
1834 | | /* Decode EC_POINT from a octet string */ |
1835 | | if (EVP_PKEY_get_octet_string_param(pk, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, buf, buflen, &buflen) != 1) { |
1836 | | return SC_ERROR_INCOMPATIBLE_KEY; |
1837 | | } |
1838 | | #endif |
1839 | | |
1840 | | /* copy the public key */ |
1841 | 0 | if (buflen > 0) { |
1842 | 0 | dst->ecpointQ.value = malloc(buflen); |
1843 | 0 | if (!dst->ecpointQ.value) |
1844 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
1845 | 0 | memcpy(dst->ecpointQ.value, buf, buflen); |
1846 | 0 | dst->ecpointQ.len = buflen; |
1847 | | /* calculate the field length */ |
1848 | 0 | dst->params.field_length = (buflen - 1) / 2 * 8; |
1849 | 0 | } |
1850 | 0 | else |
1851 | 0 | return SC_ERROR_INCOMPATIBLE_KEY; |
1852 | | |
1853 | 0 | break; |
1854 | 0 | } |
1855 | 0 | #endif /* !defined(OPENSSL_NO_EC) */ |
1856 | 0 | #ifdef EVP_PKEY_ED25519 |
1857 | 0 | case EVP_PKEY_ED25519: { |
1858 | | /* TODO */ |
1859 | 0 | break; |
1860 | 0 | } |
1861 | 0 | #endif /* EVP_PKEY_ED25519 */ |
1862 | 0 | default: |
1863 | 0 | return SC_ERROR_NOT_SUPPORTED; |
1864 | 0 | } |
1865 | | |
1866 | 0 | return SC_SUCCESS; |
1867 | | #else |
1868 | | return SC_ERROR_NOT_IMPLEMENTED; |
1869 | | #endif |
1870 | 0 | } |