diff options
Diffstat (limited to 'src/crypto/evp/p_ed25519_asn1.c')
-rw-r--r-- | src/crypto/evp/p_ed25519_asn1.c | 113 |
1 files changed, 72 insertions, 41 deletions
diff --git a/src/crypto/evp/p_ed25519_asn1.c b/src/crypto/evp/p_ed25519_asn1.c index ba08c6d3..1f996cf6 100644 --- a/src/crypto/evp/p_ed25519_asn1.c +++ b/src/crypto/evp/p_ed25519_asn1.c @@ -28,45 +28,101 @@ static void ed25519_free(EVP_PKEY *pkey) { pkey->pkey.ptr = NULL; } -static int set_pubkey(EVP_PKEY *pkey, const uint8_t pubkey[32]) { +static int ed25519_set_priv_raw(EVP_PKEY *pkey, const uint8_t *in, size_t len) { + if (len != 32) { + OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); + return 0; + } + 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); + + // The RFC 8032 encoding stores only the 32-byte seed, so we must recover the + // full representation which we use from it. + uint8_t pubkey_unused[32]; + ED25519_keypair_from_seed(pubkey_unused, key->key.priv, in); + key->has_private = 1; ed25519_free(pkey); pkey->pkey.ptr = key; return 1; } -static int set_privkey(EVP_PKEY *pkey, const uint8_t privkey[64]) { +static int ed25519_set_pub_raw(EVP_PKEY *pkey, const uint8_t *in, size_t len) { + if (len != 32) { + OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); + return 0; + } + 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); + + OPENSSL_memcpy(key->key.pub.value, in, 32); + key->has_private = 0; ed25519_free(pkey); pkey->pkey.ptr = key; return 1; } +static int ed25519_get_priv_raw(const EVP_PKEY *pkey, uint8_t *out, + size_t *out_len) { + const ED25519_KEY *key = pkey->pkey.ptr; + if (!key->has_private) { + OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY); + return 0; + } + + if (out == NULL) { + *out_len = 32; + return 1; + } + + if (*out_len < 32) { + OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL); + return 0; + } + + // The raw private key format is the first 32 bytes of the private key. + OPENSSL_memcpy(out, key->key.priv, 32); + *out_len = 32; + return 1; +} + +static int ed25519_get_pub_raw(const EVP_PKEY *pkey, uint8_t *out, + size_t *out_len) { + const ED25519_KEY *key = pkey->pkey.ptr; + if (out == NULL) { + *out_len = 32; + return 1; + } + + if (*out_len < 32) { + OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL); + return 0; + } + + OPENSSL_memcpy(out, key->key.pub.value, 32); + *out_len = 32; + return 1; +} + static int ed25519_pub_decode(EVP_PKEY *out, CBS *params, CBS *key) { // See RFC 8410, section 4. // The parameters must be omitted. Public keys have length 32. - if (CBS_len(params) != 0 || - CBS_len(key) != 32) { + if (CBS_len(params) != 0) { OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); return 0; } - return set_pubkey(out, CBS_data(key)); + return ed25519_set_pub_raw(out, CBS_data(key), CBS_len(key)); } static int ed25519_pub_encode(CBB *out, const EVP_PKEY *pkey) { @@ -103,17 +159,12 @@ static int ed25519_priv_decode(EVP_PKEY *out, CBS *params, CBS *key) { CBS inner; if (CBS_len(params) != 0 || !CBS_get_asn1(key, &inner, CBS_ASN1_OCTETSTRING) || - CBS_len(key) != 0 || - CBS_len(&inner) != 32) { + CBS_len(key) != 0) { 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); + return ed25519_set_priv_raw(out, CBS_data(&inner), CBS_len(&inner)); } static int ed25519_priv_encode(CBB *out, const EVP_PKEY *pkey) { @@ -145,7 +196,7 @@ static int ed25519_priv_encode(CBB *out, const EVP_PKEY *pkey) { static int ed25519_size(const EVP_PKEY *pkey) { return 64; } -static int ed25519_bits(const EVP_PKEY *pkey) { return 256; } +static int ed25519_bits(const EVP_PKEY *pkey) { return 253; } const EVP_PKEY_ASN1_METHOD ed25519_asn1_meth = { EVP_PKEY_ED25519, @@ -156,6 +207,10 @@ const EVP_PKEY_ASN1_METHOD ed25519_asn1_meth = { ed25519_pub_cmp, ed25519_priv_decode, ed25519_priv_encode, + ed25519_set_priv_raw, + ed25519_set_pub_raw, + ed25519_get_priv_raw, + ed25519_get_pub_raw, NULL /* pkey_opaque */, ed25519_size, ed25519_bits, @@ -164,27 +219,3 @@ const EVP_PKEY_ASN1_METHOD ed25519_asn1_meth = { 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; -} |