]>
Commit | Line | Data |
---|---|---|
af26cc4d | 1 | /* |
72491b78 | 2 | * Copyright (C) 2018 Tobias Brunner |
72491b78 | 3 | * |
af26cc4d RK |
4 | * Copyright (C) 2018 René Korthaus |
5 | * Copyright (C) 2018 Konstantinos Kolelis | |
6 | * Rohde & Schwarz Cybersecurity GmbH | |
7 | * | |
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
9 | * of this software and associated documentation files (the "Software"), to deal | |
10 | * in the Software without restriction, including without limitation the rights | |
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
12 | * copies of the Software, and to permit persons to whom the Software is | |
13 | * furnished to do so, subject to the following conditions: | |
14 | * | |
15 | * The above copyright notice and this permission notice shall be included in | |
16 | * all copies or substantial portions of the Software. | |
17 | * | |
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
24 | * THE SOFTWARE. | |
25 | */ | |
26 | ||
27 | ||
28 | #include "botan_ec_private_key.h" | |
607f10dc | 29 | #include "botan_ec_public_key.h" |
de2a2431 | 30 | #include "botan_util.h" |
af26cc4d RK |
31 | |
32 | #include <botan/build.h> | |
33 | ||
34 | #ifdef BOTAN_HAS_ECDSA | |
35 | ||
36 | #include <asn1/asn1.h> | |
37 | #include <asn1/oid.h> | |
af26cc4d RK |
38 | |
39 | #include <utils/debug.h> | |
40 | ||
41 | #include <botan/ffi.h> | |
42 | ||
43 | typedef struct private_botan_ec_private_key_t private_botan_ec_private_key_t; | |
44 | ||
45 | /** | |
46 | * Private data of a botan_ec_private_key_t object. | |
47 | */ | |
48 | struct private_botan_ec_private_key_t { | |
de2a2431 | 49 | |
af26cc4d | 50 | /** |
de2a2431 | 51 | * Public interface |
af26cc4d RK |
52 | */ |
53 | botan_ec_private_key_t public; | |
54 | ||
55 | /** | |
56 | * Botan ec private key | |
57 | */ | |
58 | botan_privkey_t key; | |
59 | ||
72491b78 TB |
60 | /** |
61 | * OID of the curve | |
62 | */ | |
63 | int oid; | |
64 | ||
af26cc4d RK |
65 | /** |
66 | * Reference count | |
67 | */ | |
68 | refcount_t ref; | |
69 | }; | |
70 | ||
71 | #define SIG_FORMAT_IEEE_1363 0 | |
72 | #define SIG_FORMAT_DER_SEQUENCE 1 | |
73 | ||
af26cc4d RK |
74 | /** |
75 | * Build a DER encoded signature as in RFC 3279 or as in RFC 4754 | |
76 | */ | |
77 | static bool build_signature(botan_privkey_t key, const char *hash_and_padding, | |
78 | int signature_format, chunk_t data, | |
79 | chunk_t *signature) | |
80 | { | |
de2a2431 | 81 | if (!botan_get_signature(key, hash_and_padding, data, signature)) |
af26cc4d RK |
82 | { |
83 | return FALSE; | |
84 | } | |
85 | ||
af26cc4d RK |
86 | if (signature_format == SIG_FORMAT_DER_SEQUENCE) |
87 | { | |
88 | /* format as ASN.1 sequence of two integers r,s */ | |
de2a2431 TB |
89 | chunk_t r = chunk_empty, s = chunk_empty; |
90 | ||
af26cc4d | 91 | chunk_split(*signature, "aa", signature->len / 2, &r, |
de2a2431 | 92 | signature->len / 2, &s); |
af26cc4d RK |
93 | |
94 | chunk_free(signature); | |
de2a2431 TB |
95 | *signature = asn1_wrap(ASN1_SEQUENCE, "mm", asn1_integer("m", r), |
96 | asn1_integer("m", s)); | |
af26cc4d | 97 | } |
af26cc4d RK |
98 | return TRUE; |
99 | } | |
100 | ||
101 | METHOD(private_key_t, sign, bool, | |
102 | private_botan_ec_private_key_t *this, signature_scheme_t scheme, | |
103 | void *params, chunk_t data, chunk_t *signature) | |
104 | { | |
105 | switch (scheme) | |
106 | { | |
de2a2431 | 107 | /* r||s -> Botan::IEEE_1363, data is the hash already */ |
af26cc4d | 108 | case SIGN_ECDSA_WITH_NULL: |
af26cc4d | 109 | return build_signature(this->key, "Raw", |
de2a2431 TB |
110 | SIG_FORMAT_IEEE_1363, data, signature); |
111 | /* DER SEQUENCE of two INTEGERS r,s -> Botan::DER_SEQUENCE */ | |
af26cc4d | 112 | case SIGN_ECDSA_WITH_SHA1_DER: |
af26cc4d RK |
113 | return build_signature(this->key, "EMSA1(SHA-1)", |
114 | SIG_FORMAT_DER_SEQUENCE, data, signature); | |
115 | case SIGN_ECDSA_WITH_SHA256_DER: | |
116 | return build_signature(this->key, "EMSA1(SHA-256)", | |
117 | SIG_FORMAT_DER_SEQUENCE, data, signature); | |
118 | case SIGN_ECDSA_WITH_SHA384_DER: | |
119 | return build_signature(this->key, "EMSA1(SHA-384)", | |
120 | SIG_FORMAT_DER_SEQUENCE, data, signature); | |
121 | case SIGN_ECDSA_WITH_SHA512_DER: | |
122 | return build_signature(this->key, "EMSA1(SHA-512)", | |
123 | SIG_FORMAT_DER_SEQUENCE, data, signature); | |
de2a2431 | 124 | /* r||s -> Botan::IEEE_1363 */ |
af26cc4d | 125 | case SIGN_ECDSA_256: |
af26cc4d RK |
126 | return build_signature(this->key, "EMSA1(SHA-256)", |
127 | SIG_FORMAT_IEEE_1363, data, signature); | |
128 | case SIGN_ECDSA_384: | |
af26cc4d RK |
129 | return build_signature(this->key, "EMSA1(SHA-384)", |
130 | SIG_FORMAT_IEEE_1363, data, signature); | |
131 | case SIGN_ECDSA_521: | |
af26cc4d RK |
132 | return build_signature(this->key, "EMSA1(SHA-512)", |
133 | SIG_FORMAT_IEEE_1363, data, signature); | |
134 | default: | |
135 | DBG1(DBG_LIB, "signature scheme %N not supported via botan", | |
136 | signature_scheme_names, scheme); | |
137 | return FALSE; | |
138 | } | |
139 | } | |
140 | ||
141 | METHOD(private_key_t, decrypt, bool, | |
142 | private_botan_ec_private_key_t *this, encryption_scheme_t scheme, | |
4abb29f6 | 143 | void *params, chunk_t crypto, chunk_t *plain) |
af26cc4d RK |
144 | { |
145 | DBG1(DBG_LIB, "EC private key decryption not implemented"); | |
146 | return FALSE; | |
147 | } | |
148 | ||
149 | METHOD(private_key_t, get_keysize, int, | |
150 | private_botan_ec_private_key_t *this) | |
151 | { | |
152 | botan_mp_t p; | |
de2a2431 | 153 | size_t bits = 0; |
af26cc4d | 154 | |
de2a2431 | 155 | if (botan_mp_init(&p)) |
af26cc4d | 156 | { |
af26cc4d RK |
157 | return 0; |
158 | } | |
159 | ||
de2a2431 TB |
160 | if (botan_privkey_get_field(p, this->key, "p") || |
161 | botan_mp_num_bits(p, &bits)) | |
af26cc4d RK |
162 | { |
163 | botan_mp_destroy(p); | |
164 | return 0; | |
165 | } | |
166 | ||
167 | botan_mp_destroy(p); | |
168 | return bits; | |
169 | } | |
170 | ||
171 | METHOD(private_key_t, get_type, key_type_t, | |
172 | private_botan_ec_private_key_t *this) | |
173 | { | |
174 | return KEY_ECDSA; | |
175 | } | |
176 | ||
177 | METHOD(private_key_t, get_public_key, public_key_t*, | |
178 | private_botan_ec_private_key_t *this) | |
179 | { | |
de2a2431 | 180 | botan_pubkey_t pubkey; |
af26cc4d | 181 | |
af26cc4d RK |
182 | if (botan_privkey_export_pubkey(&pubkey, this->key)) |
183 | { | |
607f10dc | 184 | return NULL; |
af26cc4d | 185 | } |
607f10dc | 186 | return (public_key_t*)botan_ec_public_key_adopt(pubkey); |
af26cc4d RK |
187 | } |
188 | ||
189 | METHOD(private_key_t, get_fingerprint, bool, | |
190 | private_botan_ec_private_key_t *this, cred_encoding_type_t type, | |
191 | chunk_t *fingerprint) | |
192 | { | |
de2a2431 | 193 | botan_pubkey_t pubkey; |
af26cc4d RK |
194 | bool success = FALSE; |
195 | ||
de2a2431 TB |
196 | /* check the cache before doing the export */ |
197 | if (lib->encoding->get_cache(lib->encoding, type, this, fingerprint)) | |
198 | { | |
199 | return TRUE; | |
200 | } | |
201 | ||
af26cc4d RK |
202 | if (botan_privkey_export_pubkey(&pubkey, this->key)) |
203 | { | |
204 | return FALSE; | |
205 | } | |
de2a2431 | 206 | success = botan_get_fingerprint(pubkey, this, type, fingerprint); |
af26cc4d RK |
207 | botan_pubkey_destroy(pubkey); |
208 | return success; | |
209 | } | |
210 | ||
211 | METHOD(private_key_t, get_encoding, bool, | |
212 | private_botan_ec_private_key_t *this, cred_encoding_type_t type, | |
213 | chunk_t *encoding) | |
214 | { | |
bd267c86 | 215 | return botan_get_privkey_encoding(this->key, type, encoding); |
af26cc4d RK |
216 | } |
217 | ||
218 | METHOD(private_key_t, get_ref, private_key_t*, | |
219 | private_botan_ec_private_key_t *this) | |
220 | { | |
221 | ref_get(&this->ref); | |
222 | return &this->public.key; | |
223 | } | |
224 | ||
225 | METHOD(private_key_t, destroy, void, | |
226 | private_botan_ec_private_key_t *this) | |
227 | { | |
228 | if (ref_put(&this->ref)) | |
229 | { | |
de2a2431 TB |
230 | lib->encoding->clear_cache(lib->encoding, this); |
231 | botan_privkey_destroy(this->key); | |
af26cc4d RK |
232 | free(this); |
233 | } | |
234 | } | |
235 | ||
236 | /** | |
237 | * Internal generic constructor | |
238 | */ | |
72491b78 | 239 | static private_botan_ec_private_key_t *create_empty(int oid) |
af26cc4d RK |
240 | { |
241 | private_botan_ec_private_key_t *this; | |
242 | ||
243 | INIT(this, | |
244 | .public = { | |
245 | .key = { | |
246 | .get_type = _get_type, | |
247 | .sign = _sign, | |
248 | .decrypt = _decrypt, | |
249 | .get_keysize = _get_keysize, | |
250 | .get_public_key = _get_public_key, | |
251 | .equals = private_key_equals, | |
252 | .belongs_to = private_key_belongs_to, | |
253 | .get_fingerprint = _get_fingerprint, | |
254 | .has_fingerprint = private_key_has_fingerprint, | |
255 | .get_encoding = _get_encoding, | |
256 | .get_ref = _get_ref, | |
257 | .destroy = _destroy, | |
258 | }, | |
259 | }, | |
72491b78 | 260 | .oid = oid, |
af26cc4d RK |
261 | .ref = 1, |
262 | ); | |
263 | ||
264 | return this; | |
265 | } | |
266 | ||
607f10dc TB |
267 | /* |
268 | * Described in header | |
269 | */ | |
270 | botan_ec_private_key_t *botan_ec_private_key_adopt(botan_privkey_t key, int oid) | |
271 | { | |
272 | private_botan_ec_private_key_t *this; | |
273 | ||
274 | this = create_empty(oid); | |
275 | this->key = key; | |
276 | ||
277 | return &this->public; | |
278 | } | |
279 | ||
af26cc4d | 280 | /* |
de2a2431 | 281 | * Described in header |
af26cc4d RK |
282 | */ |
283 | botan_ec_private_key_t *botan_ec_private_key_gen(key_type_t type, va_list args) | |
284 | { | |
285 | private_botan_ec_private_key_t *this; | |
de2a2431 | 286 | botan_rng_t rng; |
af26cc4d | 287 | u_int key_size = 0; |
72491b78 | 288 | int oid; |
de2a2431 | 289 | const char *curve; |
af26cc4d RK |
290 | |
291 | while (TRUE) | |
292 | { | |
293 | switch (va_arg(args, builder_part_t)) | |
294 | { | |
295 | case BUILD_KEY_SIZE: | |
296 | key_size = va_arg(args, u_int); | |
297 | continue; | |
298 | case BUILD_END: | |
299 | break; | |
300 | default: | |
301 | return NULL; | |
302 | } | |
303 | break; | |
304 | } | |
305 | ||
306 | if (!key_size) | |
307 | { | |
308 | return NULL; | |
309 | } | |
310 | ||
311 | switch (key_size) | |
312 | { | |
313 | case 256: | |
314 | curve = "secp256r1"; | |
72491b78 | 315 | oid = OID_PRIME256V1; |
af26cc4d RK |
316 | break; |
317 | case 384: | |
318 | curve = "secp384r1"; | |
72491b78 | 319 | oid = OID_SECT384R1; |
af26cc4d RK |
320 | break; |
321 | case 521: | |
322 | curve = "secp521r1"; | |
72491b78 | 323 | oid = OID_SECT521R1; |
af26cc4d RK |
324 | break; |
325 | default: | |
326 | DBG1(DBG_LIB, "EC private key size %d not supported via botan", | |
327 | key_size); | |
328 | return NULL; | |
329 | } | |
330 | ||
4261fced | 331 | if (!botan_get_rng(&rng, RNG_TRUE)) |
af26cc4d RK |
332 | { |
333 | return NULL; | |
334 | } | |
335 | ||
72491b78 | 336 | this = create_empty(oid); |
af26cc4d | 337 | |
6051d9b5 | 338 | if (botan_privkey_create(&this->key, "ECDSA", curve, rng)) |
af26cc4d | 339 | { |
de2a2431 | 340 | DBG1(DBG_LIB, "EC private key generation failed"); |
af26cc4d | 341 | botan_rng_destroy(rng); |
de2a2431 | 342 | free(this); |
af26cc4d RK |
343 | return NULL; |
344 | } | |
345 | ||
346 | botan_rng_destroy(rng); | |
347 | return &this->public; | |
348 | } | |
349 | ||
de2a2431 TB |
350 | /* |
351 | * Described in header | |
af26cc4d RK |
352 | */ |
353 | botan_ec_private_key_t *botan_ec_private_key_load(key_type_t type, va_list args) | |
354 | { | |
355 | private_botan_ec_private_key_t *this; | |
356 | chunk_t params = chunk_empty, key = chunk_empty; | |
72491b78 | 357 | chunk_t alg_id = chunk_empty, pkcs8 = chunk_empty; |
de2a2431 | 358 | botan_rng_t rng; |
72491b78 | 359 | int oid = OID_UNKNOWN; |
af26cc4d RK |
360 | |
361 | while (TRUE) | |
362 | { | |
363 | switch (va_arg(args, builder_part_t)) | |
364 | { | |
365 | case BUILD_BLOB_ALGID_PARAMS: | |
366 | params = va_arg(args, chunk_t); | |
367 | continue; | |
368 | case BUILD_BLOB_ASN1_DER: | |
369 | key = va_arg(args, chunk_t); | |
370 | continue; | |
371 | case BUILD_END: | |
372 | break; | |
373 | default: | |
374 | return NULL; | |
375 | } | |
376 | break; | |
377 | } | |
378 | ||
af26cc4d | 379 | /* |
72491b78 TB |
380 | * Botan expects a PKCS#8 private key, so we build one, if necessary. |
381 | * RFC 5480 mandates ECParameters as part of the algorithmIdentifier, which | |
382 | * we should get from e.g. the pkcs8 plugin. | |
af26cc4d | 383 | */ |
72491b78 | 384 | if (params.len != 0 && type == KEY_ECDSA) |
af26cc4d | 385 | { |
72491b78 | 386 | /* if ECParameters is passed, just use it */ |
de2a2431 TB |
387 | alg_id = asn1_algorithmIdentifier_params(OID_EC_PUBLICKEY, |
388 | chunk_clone(params)); | |
72491b78 TB |
389 | if (asn1_unwrap(¶ms, ¶ms) == ASN1_OID) |
390 | { | |
391 | oid = asn1_known_oid(params); | |
392 | } | |
af26cc4d RK |
393 | } |
394 | else | |
395 | { | |
396 | /* | |
72491b78 TB |
397 | * no explicit ECParameters passed, try to extract them from the |
398 | * ECPrivateKey structure and create an algorithmIdentifier | |
af26cc4d | 399 | */ |
72491b78 TB |
400 | chunk_t unwrap = key, inner; |
401 | ||
402 | if (asn1_unwrap(&unwrap, &unwrap) == ASN1_SEQUENCE && | |
403 | asn1_unwrap(&unwrap, &inner) == ASN1_INTEGER && | |
404 | asn1_parse_integer_uint64(inner) == 1 && | |
405 | asn1_unwrap(&unwrap, &inner) == ASN1_OCTET_STRING && | |
406 | asn1_unwrap(&unwrap, &inner) == ASN1_CONTEXT_C_0 && | |
407 | asn1_unwrap(&inner, &inner) == ASN1_OID) | |
af26cc4d | 408 | { |
72491b78 TB |
409 | oid = asn1_known_oid(inner); |
410 | if (oid != OID_UNKNOWN) | |
af26cc4d | 411 | { |
72491b78 TB |
412 | alg_id = asn1_algorithmIdentifier_params(OID_EC_PUBLICKEY, |
413 | asn1_simple_object(ASN1_OID, inner)); | |
af26cc4d RK |
414 | } |
415 | } | |
72491b78 | 416 | } |
af26cc4d | 417 | |
72491b78 TB |
418 | if (oid == OID_UNKNOWN) |
419 | { | |
420 | chunk_free(&alg_id); | |
421 | return NULL; | |
af26cc4d RK |
422 | } |
423 | ||
de2a2431 | 424 | pkcs8 = asn1_wrap(ASN1_SEQUENCE, "mms", |
af26cc4d RK |
425 | asn1_integer("c", chunk_from_chars(0x00)), |
426 | alg_id, | |
427 | asn1_wrap(ASN1_OCTET_STRING, "c", key)); | |
428 | ||
72491b78 | 429 | this = create_empty(oid); |
de2a2431 | 430 | |
4261fced | 431 | if (!botan_get_rng(&rng, RNG_STRONG)) |
af26cc4d RK |
432 | { |
433 | chunk_clear(&pkcs8); | |
de2a2431 | 434 | free(this); |
af26cc4d RK |
435 | return NULL; |
436 | } | |
437 | ||
438 | if (botan_privkey_load(&this->key, rng, pkcs8.ptr, pkcs8.len, NULL)) | |
439 | { | |
440 | chunk_clear(&pkcs8); | |
441 | botan_rng_destroy(rng); | |
de2a2431 | 442 | free(this); |
af26cc4d RK |
443 | return NULL; |
444 | } | |
445 | ||
446 | chunk_clear(&pkcs8); | |
447 | botan_rng_destroy(rng); | |
448 | return &this->public; | |
449 | } | |
450 | ||
de2a2431 | 451 | #endif |