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