]> git.ipfire.org Git - thirdparty/strongswan.git/blob - src/libstrongswan/plugins/curve25519/curve25519_public_key.c
Update copyright headers after acquisition by secunet
[thirdparty/strongswan.git] / src / libstrongswan / plugins / curve25519 / curve25519_public_key.c
1 /*
2 * Copyright (C) 2018 Tobias Brunner
3 * Copyright (C) 2016 Andreas Steffen
4 *
5 * Copyright (C) secunet Security Networks AG
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 */
17
18 #include "curve25519_public_key.h"
19 #include "ref10/ref10.h"
20
21 #include <asn1/asn1.h>
22 #include <asn1/asn1_parser.h>
23 #include <asn1/oid.h>
24
25 typedef struct private_curve25519_public_key_t private_curve25519_public_key_t;
26
27 /**
28 * Private data structure with signing context.
29 */
30 struct private_curve25519_public_key_t {
31 /**
32 * Public interface for this signer.
33 */
34 curve25519_public_key_t public;
35
36 /**
37 * Ed25519 public key
38 */
39 chunk_t pubkey;
40
41 /**
42 * Reference counter
43 */
44 refcount_t ref;
45 };
46
47 METHOD(public_key_t, get_type, key_type_t,
48 private_curve25519_public_key_t *this)
49 {
50 return KEY_ED25519;
51 }
52
53 /* L = 2^252+27742317777372353535851937790883648493 in little-endian form */
54 static chunk_t curve25519_order = chunk_from_chars(
55 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58,
56 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14,
57 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
58 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10);
59
60 METHOD(public_key_t, verify, bool,
61 private_curve25519_public_key_t *this, signature_scheme_t scheme,
62 void *params, chunk_t data, chunk_t signature)
63 {
64 hasher_t *hasher;
65 uint8_t d = 0, k[HASH_SIZE_SHA512], r[32], *sig;
66 int i;
67 ge_p3 A;
68 ge_p2 R;
69
70 if (scheme != SIGN_ED25519)
71 {
72 DBG1(DBG_LIB, "signature scheme %N not supported by Ed25519",
73 signature_scheme_names, scheme);
74 return FALSE;
75 }
76
77 if (signature.len != 64)
78 {
79 DBG1(DBG_LIB, "size of Ed25519 signature is not 64 bytes");
80 return FALSE;
81 }
82 sig = signature.ptr;
83
84 if (sig[63] & 0xe0)
85 {
86 DBG1(DBG_LIB, "the three most significant bits of Ed25519 signature "
87 "are not zero");
88 return FALSE;
89 }
90
91 if (ge_frombytes_negate_vartime(&A, this->pubkey.ptr) != 0)
92 {
93 return FALSE;
94 }
95
96 /* check for all-zeroes public key */
97 for (i = 0; i < 32; i++)
98 {
99 d |= this->pubkey.ptr[i];
100 }
101 if (!d)
102 {
103 return FALSE;
104 }
105 /* make sure 0 <= s < L, as per RFC 8032, section 5.1.7 to prevent signature
106 * malleability. Due to the three-bit check above (forces s < 2^253) there
107 * is not that much room, but adding L once works with most signatures */
108 for (i = 31; ; i--)
109 {
110 if (sig[i+32] < curve25519_order.ptr[i])
111 {
112 break;
113 }
114 else if (sig[i+32] > curve25519_order.ptr[i] || i == 0)
115 {
116 return FALSE;
117 }
118 }
119
120 hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA512);
121 if (!hasher)
122 {
123 return FALSE;
124 }
125 if (!hasher->get_hash(hasher, chunk_create(sig, 32), NULL) ||
126 !hasher->get_hash(hasher, this->pubkey, NULL) ||
127 !hasher->get_hash(hasher, data, k))
128 {
129 hasher->destroy(hasher);
130 return FALSE;
131 }
132 hasher->destroy(hasher);
133
134 sc_reduce(k);
135 ge_double_scalarmult_vartime(&R, k, &A, sig + 32);
136 ge_tobytes(r, &R);
137
138 return memeq_const(sig, r, 32);
139 }
140
141 METHOD(public_key_t, encrypt_, bool,
142 private_curve25519_public_key_t *this, encryption_scheme_t scheme,
143 void *params, chunk_t plain, chunk_t *crypto)
144 {
145 DBG1(DBG_LIB, "encryption scheme %N not supported", encryption_scheme_names,
146 scheme);
147 return FALSE;
148 }
149
150 METHOD(public_key_t, get_keysize, int,
151 private_curve25519_public_key_t *this)
152 {
153 return 8 * ED25519_KEY_LEN;
154 }
155
156 METHOD(public_key_t, get_encoding, bool,
157 private_curve25519_public_key_t *this, cred_encoding_type_t type,
158 chunk_t *encoding)
159 {
160 bool success = TRUE;
161
162 *encoding = curve25519_public_key_info_encode(this->pubkey);
163
164 if (type != PUBKEY_SPKI_ASN1_DER)
165 {
166 chunk_t asn1_encoding = *encoding;
167
168 success = lib->encoding->encode(lib->encoding, type,
169 NULL, encoding, CRED_PART_EDDSA_PUB_ASN1_DER,
170 asn1_encoding, CRED_PART_END);
171 chunk_clear(&asn1_encoding);
172 }
173 return success;
174 }
175
176 METHOD(public_key_t, get_fingerprint, bool,
177 private_curve25519_public_key_t *this, cred_encoding_type_t type,
178 chunk_t *fp)
179 {
180 bool success;
181
182 if (lib->encoding->get_cache(lib->encoding, type, this, fp))
183 {
184 return TRUE;
185 }
186 success = curve25519_public_key_fingerprint(this->pubkey, type, fp);
187 if (success)
188 {
189 lib->encoding->cache(lib->encoding, type, this, *fp);
190 }
191 return success;
192 }
193
194 METHOD(public_key_t, get_ref, public_key_t*,
195 private_curve25519_public_key_t *this)
196 {
197 ref_get(&this->ref);
198 return &this->public.key;
199 }
200
201 METHOD(public_key_t, destroy, void,
202 private_curve25519_public_key_t *this)
203 {
204 if (ref_put(&this->ref))
205 {
206 lib->encoding->clear_cache(lib->encoding, this);
207 free(this->pubkey.ptr);
208 free(this);
209 }
210 }
211
212 /**
213 * ASN.1 definition of an Ed25519 public key
214 */
215 static const asn1Object_t pubkeyObjects[] = {
216 { 0, "subjectPublicKeyInfo",ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
217 { 1, "algorithm", ASN1_EOC, ASN1_RAW }, /* 1 */
218 { 1, "subjectPublicKey", ASN1_BIT_STRING, ASN1_BODY }, /* 2 */
219 { 0, "exit", ASN1_EOC, ASN1_EXIT }
220 };
221
222 #define ED25519_SUBJECT_PUBLIC_KEY_ALGORITHM 1
223 #define ED25519_SUBJECT_PUBLIC_KEY 2
224
225 /**
226 * Parse the ASN.1-encoded subjectPublicKeyInfo
227 */
228 static bool parse_public_key_info(private_curve25519_public_key_t *this,
229 chunk_t blob)
230 {
231 asn1_parser_t *parser;
232 chunk_t object;
233 bool success = FALSE;
234 int objectID, oid;
235
236 parser = asn1_parser_create(pubkeyObjects, blob);
237
238 while (parser->iterate(parser, &objectID, &object))
239 {
240 switch (objectID)
241 {
242 case ED25519_SUBJECT_PUBLIC_KEY_ALGORITHM:
243 {
244 oid = asn1_parse_algorithmIdentifier(object,
245 parser->get_level(parser) + 1, NULL);
246 if (oid != OID_ED25519)
247 {
248 goto end;
249 }
250 break;
251 }
252 case ED25519_SUBJECT_PUBLIC_KEY:
253 {
254 /* encoded as an ASN1 BIT STRING */
255 if (object.len != 1 + ED25519_KEY_LEN)
256 {
257 goto end;
258 }
259 this->pubkey = chunk_clone(chunk_skip(object, 1));
260 break;
261 }
262 }
263 }
264 success = parser->success(parser);
265
266 end:
267 parser->destroy(parser);
268 return success;
269 }
270
271 /**
272 * See header.
273 */
274 curve25519_public_key_t *curve25519_public_key_load(key_type_t type,
275 va_list args)
276 {
277 private_curve25519_public_key_t *this;
278 chunk_t asn1 = chunk_empty, blob = chunk_empty;
279
280 while (TRUE)
281 {
282 switch (va_arg(args, builder_part_t))
283 {
284 case BUILD_BLOB_ASN1_DER:
285 asn1 = va_arg(args, chunk_t);
286 continue;
287 case BUILD_EDDSA_PUB:
288 blob = va_arg(args, chunk_t);
289 continue;
290 case BUILD_END:
291 break;
292 default:
293 return NULL;
294 }
295 break;
296 }
297
298 INIT(this,
299 .public = {
300 .key = {
301 .get_type = _get_type,
302 .verify = _verify,
303 .encrypt = _encrypt_,
304 .equals = public_key_equals,
305 .get_keysize = _get_keysize,
306 .get_fingerprint = _get_fingerprint,
307 .has_fingerprint = public_key_has_fingerprint,
308 .get_encoding = _get_encoding,
309 .get_ref = _get_ref,
310 .destroy = _destroy,
311 },
312 },
313 .ref = 1,
314 );
315
316 if (blob.len == ED25519_KEY_LEN)
317 {
318 this->pubkey = chunk_clone(blob);
319 }
320 else if (!asn1.len || !parse_public_key_info(this, asn1))
321 {
322 destroy(this);
323 return NULL;
324 }
325 return &this->public;
326 }
327
328 /**
329 * See header.
330 */
331 chunk_t curve25519_public_key_info_encode(chunk_t pubkey)
332 {
333 return asn1_wrap(ASN1_SEQUENCE, "mm",
334 asn1_wrap(ASN1_SEQUENCE, "m",
335 asn1_build_known_oid(OID_ED25519)),
336 asn1_bitstring("c", pubkey));
337 }
338
339 /**
340 * See header.
341 */
342 bool curve25519_public_key_fingerprint(chunk_t pubkey,
343 cred_encoding_type_t type, chunk_t *fp)
344 {
345 hasher_t *hasher;
346 chunk_t key;
347
348 switch (type)
349 {
350 case KEYID_PUBKEY_SHA1:
351 key = chunk_clone(pubkey);
352 break;
353 case KEYID_PUBKEY_INFO_SHA1:
354 key = curve25519_public_key_info_encode(pubkey);
355 break;
356 default:
357 return FALSE;
358 }
359
360 hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
361 if (!hasher || !hasher->allocate_hash(hasher, key, fp))
362 {
363 DBG1(DBG_LIB, "SHA1 hash algorithm not supported, "
364 "fingerprinting failed");
365 DESTROY_IF(hasher);
366 free(key.ptr);
367 return FALSE;
368 }
369 hasher->destroy(hasher);
370 free(key.ptr);
371 return TRUE;
372 }