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