2 * Copyright (C) 2018 Tobias Brunner
3 * Copyright (C) 2016 Andreas Steffen
5 * Copyright (C) secunet Security Networks AG
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>.
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
18 #include "curve25519_public_key.h"
19 #include "ref10/ref10.h"
21 #include <asn1/asn1.h>
22 #include <asn1/asn1_parser.h>
25 typedef struct private_curve25519_public_key_t private_curve25519_public_key_t
;
28 * Private data structure with signing context.
30 struct private_curve25519_public_key_t
{
32 * Public interface for this signer.
34 curve25519_public_key_t
public;
47 METHOD(public_key_t
, get_type
, key_type_t
,
48 private_curve25519_public_key_t
*this)
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);
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
)
65 uint8_t d
= 0, k
[HASH_SIZE_SHA512
], r
[32], *sig
;
70 if (scheme
!= SIGN_ED25519
)
72 DBG1(DBG_LIB
, "signature scheme %N not supported by Ed25519",
73 signature_scheme_names
, scheme
);
77 if (signature
.len
!= 64)
79 DBG1(DBG_LIB
, "size of Ed25519 signature is not 64 bytes");
86 DBG1(DBG_LIB
, "the three most significant bits of Ed25519 signature "
91 if (ge_frombytes_negate_vartime(&A
, this->pubkey
.ptr
) != 0)
96 /* check for all-zeroes public key */
97 for (i
= 0; i
< 32; i
++)
99 d
|= this->pubkey
.ptr
[i
];
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 */
110 if (sig
[i
+32] < curve25519_order
.ptr
[i
])
114 else if (sig
[i
+32] > curve25519_order
.ptr
[i
] || i
== 0)
120 hasher
= lib
->crypto
->create_hasher(lib
->crypto
, HASH_SHA512
);
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
))
129 hasher
->destroy(hasher
);
132 hasher
->destroy(hasher
);
135 ge_double_scalarmult_vartime(&R
, k
, &A
, sig
+ 32);
138 return memeq_const(sig
, r
, 32);
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
)
145 DBG1(DBG_LIB
, "encryption scheme %N not supported", encryption_scheme_names
,
150 METHOD(public_key_t
, get_keysize
, int,
151 private_curve25519_public_key_t
*this)
153 return 8 * ED25519_KEY_LEN
;
156 METHOD(public_key_t
, get_encoding
, bool,
157 private_curve25519_public_key_t
*this, cred_encoding_type_t type
,
162 *encoding
= curve25519_public_key_info_encode(this->pubkey
);
164 if (type
!= PUBKEY_SPKI_ASN1_DER
)
166 chunk_t asn1_encoding
= *encoding
;
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
);
176 METHOD(public_key_t
, get_fingerprint
, bool,
177 private_curve25519_public_key_t
*this, cred_encoding_type_t type
,
182 if (lib
->encoding
->get_cache(lib
->encoding
, type
, this, fp
))
186 success
= curve25519_public_key_fingerprint(this->pubkey
, type
, fp
);
189 lib
->encoding
->cache(lib
->encoding
, type
, this, *fp
);
194 METHOD(public_key_t
, get_ref
, public_key_t
*,
195 private_curve25519_public_key_t
*this)
198 return &this->public.key
;
201 METHOD(public_key_t
, destroy
, void,
202 private_curve25519_public_key_t
*this)
204 if (ref_put(&this->ref
))
206 lib
->encoding
->clear_cache(lib
->encoding
, this);
207 free(this->pubkey
.ptr
);
213 * ASN.1 definition of an Ed25519 public key
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
}
222 #define ED25519_SUBJECT_PUBLIC_KEY_ALGORITHM 1
223 #define ED25519_SUBJECT_PUBLIC_KEY 2
226 * Parse the ASN.1-encoded subjectPublicKeyInfo
228 static bool parse_public_key_info(private_curve25519_public_key_t
*this,
231 asn1_parser_t
*parser
;
233 bool success
= FALSE
;
236 parser
= asn1_parser_create(pubkeyObjects
, blob
);
238 while (parser
->iterate(parser
, &objectID
, &object
))
242 case ED25519_SUBJECT_PUBLIC_KEY_ALGORITHM
:
244 oid
= asn1_parse_algorithmIdentifier(object
,
245 parser
->get_level(parser
) + 1, NULL
);
246 if (oid
!= OID_ED25519
)
252 case ED25519_SUBJECT_PUBLIC_KEY
:
254 /* encoded as an ASN1 BIT STRING */
255 if (object
.len
!= 1 + ED25519_KEY_LEN
)
259 this->pubkey
= chunk_clone(chunk_skip(object
, 1));
264 success
= parser
->success(parser
);
267 parser
->destroy(parser
);
274 curve25519_public_key_t
*curve25519_public_key_load(key_type_t type
,
277 private_curve25519_public_key_t
*this;
278 chunk_t asn1
= chunk_empty
, blob
= chunk_empty
;
282 switch (va_arg(args
, builder_part_t
))
284 case BUILD_BLOB_ASN1_DER
:
285 asn1
= va_arg(args
, chunk_t
);
287 case BUILD_EDDSA_PUB
:
288 blob
= va_arg(args
, chunk_t
);
301 .get_type
= _get_type
,
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
,
316 if (blob
.len
== ED25519_KEY_LEN
)
318 this->pubkey
= chunk_clone(blob
);
320 else if (!asn1
.len
|| !parse_public_key_info(this, asn1
))
325 return &this->public;
331 chunk_t
curve25519_public_key_info_encode(chunk_t pubkey
)
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
));
342 bool curve25519_public_key_fingerprint(chunk_t pubkey
,
343 cred_encoding_type_t type
, chunk_t
*fp
)
350 case KEYID_PUBKEY_SHA1
:
351 key
= chunk_clone(pubkey
);
353 case KEYID_PUBKEY_INFO_SHA1
:
354 key
= curve25519_public_key_info_encode(pubkey
);
360 hasher
= lib
->crypto
->create_hasher(lib
->crypto
, HASH_SHA1
);
361 if (!hasher
|| !hasher
->allocate_hash(hasher
, key
, fp
))
363 DBG1(DBG_LIB
, "SHA1 hash algorithm not supported, "
364 "fingerprinting failed");
369 hasher
->destroy(hasher
);