diff --git a/crypto/err/evp.errordata b/crypto/err/evp.errordata index a482f769..991195cd 100644 --- a/crypto/err/evp.errordata +++ b/crypto/err/evp.errordata @@ -17,6 +17,7 @@ EVP,115,INVALID_PADDING_MODE EVP,116,INVALID_PSS_SALTLEN EVP,117,KEYS_NOT_SET EVP,118,MISSING_PARAMETERS +EVP,130,NOT_A_PRIVATE_KEY EVP,119,NO_DEFAULT_DIGEST EVP,120,NO_KEY_SET EVP,121,NO_MDC2_SUPPORT diff --git a/crypto/evp/CMakeLists.txt b/crypto/evp/CMakeLists.txt index 188c5807..fa26cfee 100644 --- a/crypto/evp/CMakeLists.txt +++ b/crypto/evp/CMakeLists.txt @@ -12,6 +12,7 @@ add_library( p_dsa_asn1.c p_ec.c p_ec_asn1.c + p_ed25519_asn1.c p_rsa.c p_rsa_asn1.c pbkdf.c diff --git a/crypto/evp/evp.c b/crypto/evp/evp.c index f8fe6ce8..117e774f 100644 --- a/crypto/evp/evp.c +++ b/crypto/evp/evp.c @@ -198,6 +198,8 @@ static const EVP_PKEY_ASN1_METHOD *evp_pkey_asn1_find(int nid) { return &ec_asn1_meth; case EVP_PKEY_DSA: return &dsa_asn1_meth; + case EVP_PKEY_ED25519: + return &ed25519_asn1_meth; default: return NULL; } diff --git a/crypto/evp/evp_asn1.c b/crypto/evp/evp_asn1.c index 6c905719..1f8d3eb0 100644 --- a/crypto/evp/evp_asn1.c +++ b/crypto/evp/evp_asn1.c @@ -72,6 +72,7 @@ static const EVP_PKEY_ASN1_METHOD *const kASN1Methods[] = { &rsa_asn1_meth, &ec_asn1_meth, &dsa_asn1_meth, + &ed25519_asn1_meth, }; static int parse_key_type(CBS *cbs, int *out_type) { @@ -80,8 +81,7 @@ static int parse_key_type(CBS *cbs, int *out_type) { return 0; } - unsigned i; - for (i = 0; i < OPENSSL_ARRAY_SIZE(kASN1Methods); i++) { + for (unsigned i = 0; i < OPENSSL_ARRAY_SIZE(kASN1Methods); i++) { const EVP_PKEY_ASN1_METHOD *method = kASN1Methods[i]; if (CBS_len(&oid) == method->oid_len && OPENSSL_memcmp(CBS_data(&oid), method->oid, method->oid_len) == 0) { diff --git a/crypto/evp/evp_extra_test.cc b/crypto/evp/evp_extra_test.cc index 0f8bb3b3..73a5c898 100644 --- a/crypto/evp/evp_extra_test.cc +++ b/crypto/evp/evp_extra_test.cc @@ -540,3 +540,85 @@ TEST(EVPExtraTest, d2i_PrivateKey) { sizeof(kExampleRSAKeyPKCS8))); ERR_clear_error(); } + +TEST(EVPExtraTest, Ed25519) { + static const uint8_t kPublicKey[32] = { + 0xd7, 0x5a, 0x98, 0x01, 0x82, 0xb1, 0x0a, 0xb7, 0xd5, 0x4b, 0xfe, + 0xd3, 0xc9, 0x64, 0x07, 0x3a, 0x0e, 0xe1, 0x72, 0xf3, 0xda, 0xa6, + 0x23, 0x25, 0xaf, 0x02, 0x1a, 0x68, 0xf7, 0x07, 0x51, 0x1a, + }; + + static const uint8_t kPublicKeySPKI[] = { + 0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x03, 0x21, + 0x00, 0xd7, 0x5a, 0x98, 0x01, 0x82, 0xb1, 0x0a, 0xb7, 0xd5, 0x4b, + 0xfe, 0xd3, 0xc9, 0x64, 0x07, 0x3a, 0x0e, 0xe1, 0x72, 0xf3, 0xda, + 0xa6, 0x23, 0x25, 0xaf, 0x02, 0x1a, 0x68, 0xf7, 0x07, 0x51, 0x1a, + }; + + static const uint8_t kPrivateKey[64] = { + 0x9d, 0x61, 0xb1, 0x9d, 0xef, 0xfd, 0x5a, 0x60, 0xba, 0x84, 0x4a, + 0xf4, 0x92, 0xec, 0x2c, 0xc4, 0x44, 0x49, 0xc5, 0x69, 0x7b, 0x32, + 0x69, 0x19, 0x70, 0x3b, 0xac, 0x03, 0x1c, 0xae, 0x7f, 0x60, 0xd7, + 0x5a, 0x98, 0x01, 0x82, 0xb1, 0x0a, 0xb7, 0xd5, 0x4b, 0xfe, 0xd3, + 0xc9, 0x64, 0x07, 0x3a, 0x0e, 0xe1, 0x72, 0xf3, 0xda, 0xa6, 0x23, + 0x25, 0xaf, 0x02, 0x1a, 0x68, 0xf7, 0x07, 0x51, 0x1a, + }; + + static const uint8_t kPrivateKeyPKCS8[] = { + 0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, + 0x04, 0x22, 0x04, 0x20, 0x9d, 0x61, 0xb1, 0x9d, 0xef, 0xfd, 0x5a, 0x60, + 0xba, 0x84, 0x4a, 0xf4, 0x92, 0xec, 0x2c, 0xc4, 0x44, 0x49, 0xc5, 0x69, + 0x7b, 0x32, 0x69, 0x19, 0x70, 0x3b, 0xac, 0x03, 0x1c, 0xae, 0x7f, 0x60, + }; + + // Create a public key. + bssl::UniquePtr pubkey(EVP_PKEY_new_ed25519_public(kPublicKey)); + ASSERT_TRUE(pubkey); + EXPECT_EQ(EVP_PKEY_ED25519, EVP_PKEY_id(pubkey.get())); + + // The public key must encode properly. + bssl::ScopedCBB cbb; + uint8_t *der; + size_t der_len; + ASSERT_TRUE(CBB_init(cbb.get(), 0)); + ASSERT_TRUE(EVP_marshal_public_key(cbb.get(), pubkey.get())); + ASSERT_TRUE(CBB_finish(cbb.get(), &der, &der_len)); + bssl::UniquePtr free_der(der); + EXPECT_EQ(Bytes(kPublicKeySPKI), Bytes(der, der_len)); + + // The public key must gracefully fail to encode as a private key. + ASSERT_TRUE(CBB_init(cbb.get(), 0)); + EXPECT_FALSE(EVP_marshal_private_key(cbb.get(), pubkey.get())); + uint32_t err = ERR_get_error(); + EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err)); + EXPECT_EQ(EVP_R_NOT_A_PRIVATE_KEY, ERR_GET_REASON(err)); + cbb.Reset(); + + // Create a private key. + bssl::UniquePtr privkey(EVP_PKEY_new_ed25519_private(kPrivateKey)); + ASSERT_TRUE(privkey); + EXPECT_EQ(EVP_PKEY_ED25519, EVP_PKEY_id(privkey.get())); + + // The public key must encode from the private key. + ASSERT_TRUE(CBB_init(cbb.get(), 0)); + ASSERT_TRUE(EVP_marshal_public_key(cbb.get(), privkey.get())); + ASSERT_TRUE(CBB_finish(cbb.get(), &der, &der_len)); + free_der.reset(der); + EXPECT_EQ(Bytes(kPublicKeySPKI), Bytes(der, der_len)); + + // The private key must encode properly. + ASSERT_TRUE(CBB_init(cbb.get(), 0)); + ASSERT_TRUE(EVP_marshal_private_key(cbb.get(), privkey.get())); + ASSERT_TRUE(CBB_finish(cbb.get(), &der, &der_len)); + free_der.reset(der); + EXPECT_EQ(Bytes(kPrivateKeyPKCS8), Bytes(der, der_len)); + + // Test EVP_PKEY_cmp. + EXPECT_TRUE(EVP_PKEY_cmp(pubkey.get(), privkey.get())); + + static const uint8_t kZeros[32] = {0}; + bssl::UniquePtr pubkey2(EVP_PKEY_new_ed25519_public(kZeros)); + ASSERT_TRUE(pubkey2); + EXPECT_FALSE(EVP_PKEY_cmp(pubkey.get(), pubkey2.get())); + EXPECT_FALSE(EVP_PKEY_cmp(privkey.get(), pubkey2.get())); +} diff --git a/crypto/evp/evp_test.cc b/crypto/evp/evp_test.cc index 0f34ad54..baf41fe9 100644 --- a/crypto/evp/evp_test.cc +++ b/crypto/evp/evp_test.cc @@ -110,6 +110,9 @@ static int GetKeyType(FileTest *t, const std::string &name) { if (name == "DSA") { return EVP_PKEY_DSA; } + if (name == "Ed25519") { + return EVP_PKEY_ED25519; + } t->PrintLine("Unknown key type: '%s'", name.c_str()); return EVP_PKEY_NONE; } diff --git a/crypto/evp/evp_tests.txt b/crypto/evp/evp_tests.txt index e0d43dd4..6fb15fab 100644 --- a/crypto/evp/evp_tests.txt +++ b/crypto/evp/evp_tests.txt @@ -84,6 +84,36 @@ PublicKey = DSA-1024-SPKI-No-Params Type = DSA Input = 308192300906072a8648ce38040103818400028180258c30ebbb7f34fdc873ce679f6cea373c7886d75d4421b90920db034daedd292c64d8edd8cdbdd7f3ad23d74cfa2135247d0cef6ecf2e14f99e19d22a8c1266bd8fb8719c0e5667c716c45c7adbdabe548085bdad2dfee636f8d52fd6adb2193df6c4f0520fbd171b91882e0e4f321f8250ffecf4dbea00e114427d3ef96c1a +# An Ed25519 private key. +PrivateKey = Ed25519 +Type = Ed25519 +Input = 302e020100300506032b6570042204209d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60 + +# The same as the above, but with an invalid NULL parameter. +PrivateKey = Ed25519-NULL +Input = 3030020100300706032b65700500042204209d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60 +Error = DECODE_ERROR + +# The above key as an SPKI. +PublicKey = Ed25519-SPKI +Type = Ed25519 +Input = 302a300506032b6570032100d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a + +# The same as the above, but with an invalid NULL parameter. +PublicKey = Ed25519-SPKI-NULL +Input = 302c300706032b65700500032100d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a +Error = DECODE_ERROR + +# Sample public key from draft-ietf-curdle-pkix-04. +PublicKey = Ed25519-SPKI-Spec +Type = Ed25519 +Input = 302a300506032b657003210019bf44096984cdfe8541bac167dc3b96c85086aa30b6b6cb0c5c38ad703166e1 + +# Sample private key from draft-ietf-curdle-pkix-04. +PrivateKey = Ed25519-Spec +Type = Ed25519 +Input = 302e020100300506032b657004220420d4ee72dbf913584ad5b6d8f1f769f8ad3afe7c28cbf1d4fbe097a88f44755842 + # RSA tests diff --git a/crypto/evp/internal.h b/crypto/evp/internal.h index cdbd56a7..8971f0de 100644 --- a/crypto/evp/internal.h +++ b/crypto/evp/internal.h @@ -219,6 +219,7 @@ struct evp_pkey_method_st { extern const EVP_PKEY_ASN1_METHOD dsa_asn1_meth; extern const EVP_PKEY_ASN1_METHOD ec_asn1_meth; extern const EVP_PKEY_ASN1_METHOD rsa_asn1_meth; +extern const EVP_PKEY_ASN1_METHOD ed25519_asn1_meth; extern const EVP_PKEY_METHOD rsa_pkey_meth; extern const EVP_PKEY_METHOD ec_pkey_meth; diff --git a/crypto/evp/p_ed25519_asn1.c b/crypto/evp/p_ed25519_asn1.c new file mode 100644 index 00000000..a4fcfcc4 --- /dev/null +++ b/crypto/evp/p_ed25519_asn1.c @@ -0,0 +1,207 @@ +/* Copyright (c) 2017, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include + +#include +#include +#include +#include + +#include "internal.h" +#include "../internal.h" + + +typedef struct { + union { + uint8_t priv[64]; + struct { + /* Shift the location of the public key to align with where it is in the + * private key representation. */ + uint8_t pad[32]; + uint8_t value[32]; + } pub; + } key; + char has_private; +} ED25519_KEY; + +static void ed25519_free(EVP_PKEY *pkey) { + if (pkey->pkey.ptr != NULL) { + ED25519_KEY *key = pkey->pkey.ptr; + OPENSSL_cleanse(key, sizeof(ED25519_KEY)); + OPENSSL_free(key); + pkey->pkey.ptr = NULL; + } +} + +static int set_pubkey(EVP_PKEY *pkey, const uint8_t pubkey[32]) { + ED25519_KEY *key = OPENSSL_malloc(sizeof(ED25519_KEY)); + if (key == NULL) { + OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); + return 0; + } + key->has_private = 0; + OPENSSL_memcpy(key->key.pub.value, pubkey, 32); + + ed25519_free(pkey); + pkey->pkey.ptr = key; + return 1; +} + +static int set_privkey(EVP_PKEY *pkey, const uint8_t privkey[64]) { + ED25519_KEY *key = OPENSSL_malloc(sizeof(ED25519_KEY)); + if (key == NULL) { + OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); + return 0; + } + key->has_private = 1; + OPENSSL_memcpy(key->key.priv, privkey, 64); + + ed25519_free(pkey); + pkey->pkey.ptr = key; + return 1; +} + +static int ed25519_pub_decode(EVP_PKEY *out, CBS *params, CBS *key) { + /* See draft-ietf-curdle-pkix-04, section 4. */ + + /* The parameters must be omitted. Public keys have length 32. */ + if (CBS_len(params) != 0 || + CBS_len(key) != 32) { + OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); + return 0; + } + + return set_pubkey(out, CBS_data(key)); +} + +static int ed25519_pub_encode(CBB *out, const EVP_PKEY *pkey) { + const ED25519_KEY *key = pkey->pkey.ptr; + + /* See draft-ietf-curdle-pkix-04, section 4. */ + CBB spki, algorithm, oid, key_bitstring; + if (!CBB_add_asn1(out, &spki, CBS_ASN1_SEQUENCE) || + !CBB_add_asn1(&spki, &algorithm, CBS_ASN1_SEQUENCE) || + !CBB_add_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) || + !CBB_add_bytes(&oid, ed25519_asn1_meth.oid, ed25519_asn1_meth.oid_len) || + !CBB_add_asn1(&spki, &key_bitstring, CBS_ASN1_BITSTRING) || + !CBB_add_u8(&key_bitstring, 0 /* padding */) || + !CBB_add_bytes(&key_bitstring, key->key.pub.value, 32) || + !CBB_flush(out)) { + OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR); + return 0; + } + + return 1; +} + +static int ed25519_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) { + const ED25519_KEY *a_key = a->pkey.ptr; + const ED25519_KEY *b_key = b->pkey.ptr; + return OPENSSL_memcmp(a_key->key.pub.value, b_key->key.pub.value, 32) == 0; +} + +static int ed25519_priv_decode(EVP_PKEY *out, CBS *params, CBS *key) { + /* See draft-ietf-curdle-pkix-04, section 7. */ + + /* Parameters must be empty. The key is a 32-byte value wrapped in an extra + * OCTET STRING layer. */ + CBS inner; + if (CBS_len(params) != 0 || + !CBS_get_asn1(key, &inner, CBS_ASN1_OCTETSTRING) || + CBS_len(key) != 0 || + CBS_len(&inner) != 32) { + OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); + return 0; + } + + /* The PKCS#8 encoding stores only the 32-byte seed, so we must recover the + * full representation which we use from it. */ + uint8_t pubkey[32], privkey[64]; + ED25519_keypair_from_seed(pubkey, privkey, CBS_data(&inner)); + return set_privkey(out, privkey); +} + +static int ed25519_priv_encode(CBB *out, const EVP_PKEY *pkey) { + ED25519_KEY *key = pkey->pkey.ptr; + if (!key->has_private) { + OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY); + return 0; + } + + /* See draft-ietf-curdle-pkix-04, section 7. */ + CBB pkcs8, algorithm, oid, private_key, inner; + if (!CBB_add_asn1(out, &pkcs8, CBS_ASN1_SEQUENCE) || + !CBB_add_asn1_uint64(&pkcs8, 0 /* version */) || + !CBB_add_asn1(&pkcs8, &algorithm, CBS_ASN1_SEQUENCE) || + !CBB_add_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) || + !CBB_add_bytes(&oid, ed25519_asn1_meth.oid, ed25519_asn1_meth.oid_len) || + !CBB_add_asn1(&pkcs8, &private_key, CBS_ASN1_OCTETSTRING) || + !CBB_add_asn1(&private_key, &inner, CBS_ASN1_OCTETSTRING) || + /* The PKCS#8 encoding stores only the 32-byte seed which is the first 32 + * bytes of the private key. */ + !CBB_add_bytes(&inner, key->key.priv, 32) || + !CBB_flush(out)) { + OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR); + return 0; + } + + return 1; +} + +static int ed25519_size(const EVP_PKEY *pkey) { return 64; } + +static int ed25519_bits(const EVP_PKEY *pkey) { return 256; } + +const EVP_PKEY_ASN1_METHOD ed25519_asn1_meth = { + EVP_PKEY_ED25519, + {0x2b, 0x65, 0x70}, + 3, + ed25519_pub_decode, + ed25519_pub_encode, + ed25519_pub_cmp, + ed25519_priv_decode, + ed25519_priv_encode, + NULL /* pkey_opaque */, + ed25519_size, + ed25519_bits, + NULL /* param_missing */, + NULL /* param_copy */, + NULL /* param_cmp */, + ed25519_free, +}; + +EVP_PKEY *EVP_PKEY_new_ed25519_public(const uint8_t public_key[32]) { + EVP_PKEY *ret = EVP_PKEY_new(); + if (ret == NULL || + !EVP_PKEY_set_type(ret, EVP_PKEY_ED25519) || + !set_pubkey(ret, public_key)) { + EVP_PKEY_free(ret); + return NULL; + } + + return ret; +} + +EVP_PKEY *EVP_PKEY_new_ed25519_private(const uint8_t private_key[64]) { + EVP_PKEY *ret = EVP_PKEY_new(); + if (ret == NULL || + !EVP_PKEY_set_type(ret, EVP_PKEY_ED25519) || + !set_privkey(ret, private_key)) { + EVP_PKEY_free(ret); + return NULL; + } + + return ret; +} diff --git a/crypto/obj/obj_dat.h b/crypto/obj/obj_dat.h index 4905f0d0..5f36d405 100644 --- a/crypto/obj/obj_dat.h +++ b/crypto/obj/obj_dat.h @@ -56,7 +56,7 @@ /* This file is generated by crypto/obj/objects.go. */ -#define NUM_NID 949 +#define NUM_NID 950 static const uint8_t kObjectData[] = { /* NID_rsadsi */ @@ -1811,6 +1811,8 @@ static const uint8_t kObjectData[] = { 0x2b, 0x81, 0x04, 0x01, 0x0e, 0x02, /* NID_dhSinglePass_cofactorDH_sha512kdf_scheme */ 0x2b, 0x81, 0x04, 0x01, 0x0e, 0x03, + /* NID_Ed25519 */ + 0x2b, 0x65, 0x70, }; static const ASN1_OBJECT kObjects[NUM_NID] = { @@ -3440,6 +3442,7 @@ static const ASN1_OBJECT kObjects[NUM_NID] = { {"dh-std-kdf", "dh-std-kdf", NID_dh_std_kdf, 0, NULL, 0}, {"dh-cofactor-kdf", "dh-cofactor-kdf", NID_dh_cofactor_kdf, 0, NULL, 0}, {"X25519", "X25519", NID_X25519, 0, NULL, 0}, + {"Ed25519", "Ed25519", NID_Ed25519, 3, &kObjectData[6175], 0}, }; static const unsigned kNIDsInShortNameOrder[] = { @@ -3528,6 +3531,7 @@ static const unsigned kNIDsInShortNameOrder[] = { 70 /* DSA-SHA1-old */, 67 /* DSA-old */, 297 /* DVCS */, + 949 /* Ed25519 */, 99 /* GN */, 855 /* HMAC */, 780 /* HMAC-MD5 */, @@ -4400,6 +4404,7 @@ static const unsigned kNIDsInLongNameOrder[] = { 382 /* Directory */, 392 /* Domain */, 132 /* E-mail Protection */, + 949 /* Ed25519 */, 389 /* Enterprises */, 384 /* Experimental */, 372 /* Extended OCSP Status */, @@ -5334,7 +5339,8 @@ static const unsigned kNIDsInOIDOrder[] = { 378 /* 2.5.8 (OBJ_X500algorithms) */, 81 /* 2.5.29 (OBJ_id_ce) */, 512 /* 2.23.42 (OBJ_id_set) */, 678 /* 2.23.43 (OBJ_wap) */, 435 /* 0.9.2342 (OBJ_pss) */, 183 /* 1.2.840 (OBJ_ISO_US) */, - 381 /* 1.3.6.1 (OBJ_iana) */, 677 /* 1.3.132 (OBJ_certicom_arc) */, + 381 /* 1.3.6.1 (OBJ_iana) */, 949 /* 1.3.101.112 (OBJ_Ed25519) */, + 677 /* 1.3.132 (OBJ_certicom_arc) */, 394 /* 2.5.1.5 (OBJ_selected_attribute_types) */, 13 /* 2.5.4.3 (OBJ_commonName) */, 100 /* 2.5.4.4 (OBJ_surname) */, 105 /* 2.5.4.5 (OBJ_serialNumber) */, 14 /* 2.5.4.6 (OBJ_countryName) */, diff --git a/crypto/obj/obj_mac.num b/crypto/obj/obj_mac.num index ef19a6d2..2f2a557f 100644 --- a/crypto/obj/obj_mac.num +++ b/crypto/obj/obj_mac.num @@ -937,3 +937,4 @@ dhSinglePass_cofactorDH_sha512kdf_scheme 945 dh_std_kdf 946 dh_cofactor_kdf 947 X25519 948 +Ed25519 949 diff --git a/crypto/obj/objects.txt b/crypto/obj/objects.txt index f3990d00..c2ddfbe2 100644 --- a/crypto/obj/objects.txt +++ b/crypto/obj/objects.txt @@ -1333,3 +1333,6 @@ secg-scheme 14 3 : dhSinglePass-cofactorDH-sha512kdf-scheme # NID for X25519 (no corresponding OID). : X25519 + +# See draft-ietf-curdle-pkix-04. +1 3 101 112 : Ed25519 diff --git a/include/openssl/evp.h b/include/openssl/evp.h index 951a1432..4ff84121 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -157,10 +157,21 @@ OPENSSL_EXPORT int EVP_PKEY_assign_EC_KEY(EVP_PKEY *pkey, EC_KEY *key); OPENSSL_EXPORT EC_KEY *EVP_PKEY_get0_EC_KEY(EVP_PKEY *pkey); OPENSSL_EXPORT EC_KEY *EVP_PKEY_get1_EC_KEY(EVP_PKEY *pkey); +/* EVP_PKEY_new_ed25519_public returns a newly allocated |EVP_PKEY| wrapping an + * Ed25519 public key, or NULL on allocation error. */ +OPENSSL_EXPORT EVP_PKEY *EVP_PKEY_new_ed25519_public( + const uint8_t public_key[32]); + +/* EVP_PKEY_new_ed25519_private returns a newly allocated |EVP_PKEY| wrapping an + * Ed25519 private key, or NULL on allocation error. */ +OPENSSL_EXPORT EVP_PKEY *EVP_PKEY_new_ed25519_private( + const uint8_t private_key[64]); + #define EVP_PKEY_NONE NID_undef #define EVP_PKEY_RSA NID_rsaEncryption #define EVP_PKEY_DSA NID_dsa #define EVP_PKEY_EC NID_X9_62_id_ecPublicKey +#define EVP_PKEY_ED25519 NID_Ed25519 /* EVP_PKEY_assign sets the underlying key of |pkey| to |key|, which must be of * the given type. The |type| argument should be one of the |EVP_PKEY_*| @@ -771,7 +782,7 @@ struct evp_pkey_st { int type; union { - char *ptr; + void *ptr; RSA *rsa; DSA *dsa; DH *dh; @@ -829,5 +840,6 @@ BORINGSSL_MAKE_DELETER(EVP_PKEY_CTX, EVP_PKEY_CTX_free) #define EVP_R_UNKNOWN_PUBLIC_KEY_TYPE 127 #define EVP_R_UNSUPPORTED_ALGORITHM 128 #define EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE 129 +#define EVP_R_NOT_A_PRIVATE_KEY 130 #endif /* OPENSSL_HEADER_EVP_H */ diff --git a/include/openssl/nid.h b/include/openssl/nid.h index 4270dc1b..f023c1fd 100644 --- a/include/openssl/nid.h +++ b/include/openssl/nid.h @@ -4192,6 +4192,11 @@ extern "C" { #define SN_X25519 "X25519" #define NID_X25519 948 +#define SN_Ed25519 "Ed25519" +#define NID_Ed25519 949 +#define OBJ_Ed25519 1L, 3L, 101L, 112L + + #if defined(__cplusplus) } /* extern C */ #endif