diff options
author | Devtools Arcadia <arcadia-devtools@yandex-team.ru> | 2022-02-07 18:08:42 +0300 |
---|---|---|
committer | Devtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net> | 2022-02-07 18:08:42 +0300 |
commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /contrib/libs/openssl/crypto/ec/ecx_meth.c | |
download | ydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'contrib/libs/openssl/crypto/ec/ecx_meth.c')
-rw-r--r-- | contrib/libs/openssl/crypto/ec/ecx_meth.c | 841 |
1 files changed, 841 insertions, 0 deletions
diff --git a/contrib/libs/openssl/crypto/ec/ecx_meth.c b/contrib/libs/openssl/crypto/ec/ecx_meth.c new file mode 100644 index 0000000000..9dc5259e4a --- /dev/null +++ b/contrib/libs/openssl/crypto/ec/ecx_meth.c @@ -0,0 +1,841 @@ +/* + * Copyright 2006-2019 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <stdio.h> +#include "internal/cryptlib.h" +#include <openssl/x509.h> +#include <openssl/ec.h> +#include <openssl/rand.h> +#include "crypto/asn1.h" +#include "crypto/evp.h" +#include "ec_local.h" +#include "curve448/curve448_local.h" + +#define X25519_BITS 253 +#define X25519_SECURITY_BITS 128 + +#define ED25519_SIGSIZE 64 + +#define X448_BITS 448 +#define ED448_BITS 456 +#define X448_SECURITY_BITS 224 + +#define ED448_SIGSIZE 114 + +#define ISX448(id) ((id) == EVP_PKEY_X448) +#define IS25519(id) ((id) == EVP_PKEY_X25519 || (id) == EVP_PKEY_ED25519) +#define KEYLENID(id) (IS25519(id) ? X25519_KEYLEN \ + : ((id) == EVP_PKEY_X448 ? X448_KEYLEN \ + : ED448_KEYLEN)) +#define KEYLEN(p) KEYLENID((p)->ameth->pkey_id) + + +typedef enum { + KEY_OP_PUBLIC, + KEY_OP_PRIVATE, + KEY_OP_KEYGEN +} ecx_key_op_t; + +/* Setup EVP_PKEY using public, private or generation */ +static int ecx_key_op(EVP_PKEY *pkey, int id, const X509_ALGOR *palg, + const unsigned char *p, int plen, ecx_key_op_t op) +{ + ECX_KEY *key = NULL; + unsigned char *privkey, *pubkey; + + if (op != KEY_OP_KEYGEN) { + if (palg != NULL) { + int ptype; + + /* Algorithm parameters must be absent */ + X509_ALGOR_get0(NULL, &ptype, NULL, palg); + if (ptype != V_ASN1_UNDEF) { + ECerr(EC_F_ECX_KEY_OP, EC_R_INVALID_ENCODING); + return 0; + } + } + + if (p == NULL || plen != KEYLENID(id)) { + ECerr(EC_F_ECX_KEY_OP, EC_R_INVALID_ENCODING); + return 0; + } + } + + key = OPENSSL_zalloc(sizeof(*key)); + if (key == NULL) { + ECerr(EC_F_ECX_KEY_OP, ERR_R_MALLOC_FAILURE); + return 0; + } + pubkey = key->pubkey; + + if (op == KEY_OP_PUBLIC) { + memcpy(pubkey, p, plen); + } else { + privkey = key->privkey = OPENSSL_secure_malloc(KEYLENID(id)); + if (privkey == NULL) { + ECerr(EC_F_ECX_KEY_OP, ERR_R_MALLOC_FAILURE); + goto err; + } + if (op == KEY_OP_KEYGEN) { + if (RAND_priv_bytes(privkey, KEYLENID(id)) <= 0) { + OPENSSL_secure_free(privkey); + key->privkey = NULL; + goto err; + } + if (id == EVP_PKEY_X25519) { + privkey[0] &= 248; + privkey[X25519_KEYLEN - 1] &= 127; + privkey[X25519_KEYLEN - 1] |= 64; + } else if (id == EVP_PKEY_X448) { + privkey[0] &= 252; + privkey[X448_KEYLEN - 1] |= 128; + } + } else { + memcpy(privkey, p, KEYLENID(id)); + } + switch (id) { + case EVP_PKEY_X25519: + X25519_public_from_private(pubkey, privkey); + break; + case EVP_PKEY_ED25519: + ED25519_public_from_private(pubkey, privkey); + break; + case EVP_PKEY_X448: + X448_public_from_private(pubkey, privkey); + break; + case EVP_PKEY_ED448: + ED448_public_from_private(pubkey, privkey); + break; + } + } + + EVP_PKEY_assign(pkey, id, key); + return 1; + err: + OPENSSL_free(key); + return 0; +} + +static int ecx_pub_encode(X509_PUBKEY *pk, const EVP_PKEY *pkey) +{ + const ECX_KEY *ecxkey = pkey->pkey.ecx; + unsigned char *penc; + + if (ecxkey == NULL) { + ECerr(EC_F_ECX_PUB_ENCODE, EC_R_INVALID_KEY); + return 0; + } + + penc = OPENSSL_memdup(ecxkey->pubkey, KEYLEN(pkey)); + if (penc == NULL) { + ECerr(EC_F_ECX_PUB_ENCODE, ERR_R_MALLOC_FAILURE); + return 0; + } + + if (!X509_PUBKEY_set0_param(pk, OBJ_nid2obj(pkey->ameth->pkey_id), + V_ASN1_UNDEF, NULL, penc, KEYLEN(pkey))) { + OPENSSL_free(penc); + ECerr(EC_F_ECX_PUB_ENCODE, ERR_R_MALLOC_FAILURE); + return 0; + } + return 1; +} + +static int ecx_pub_decode(EVP_PKEY *pkey, X509_PUBKEY *pubkey) +{ + const unsigned char *p; + int pklen; + X509_ALGOR *palg; + + if (!X509_PUBKEY_get0_param(NULL, &p, &pklen, &palg, pubkey)) + return 0; + return ecx_key_op(pkey, pkey->ameth->pkey_id, palg, p, pklen, + KEY_OP_PUBLIC); +} + +static int ecx_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) +{ + const ECX_KEY *akey = a->pkey.ecx; + const ECX_KEY *bkey = b->pkey.ecx; + + if (akey == NULL || bkey == NULL) + return -2; + + return CRYPTO_memcmp(akey->pubkey, bkey->pubkey, KEYLEN(a)) == 0; +} + +static int ecx_priv_decode(EVP_PKEY *pkey, const PKCS8_PRIV_KEY_INFO *p8) +{ + const unsigned char *p; + int plen; + ASN1_OCTET_STRING *oct = NULL; + const X509_ALGOR *palg; + int rv; + + if (!PKCS8_pkey_get0(NULL, &p, &plen, &palg, p8)) + return 0; + + oct = d2i_ASN1_OCTET_STRING(NULL, &p, plen); + if (oct == NULL) { + p = NULL; + plen = 0; + } else { + p = ASN1_STRING_get0_data(oct); + plen = ASN1_STRING_length(oct); + } + + rv = ecx_key_op(pkey, pkey->ameth->pkey_id, palg, p, plen, KEY_OP_PRIVATE); + ASN1_STRING_clear_free(oct); + return rv; +} + +static int ecx_priv_encode(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pkey) +{ + const ECX_KEY *ecxkey = pkey->pkey.ecx; + ASN1_OCTET_STRING oct; + unsigned char *penc = NULL; + int penclen; + + if (ecxkey == NULL || ecxkey->privkey == NULL) { + ECerr(EC_F_ECX_PRIV_ENCODE, EC_R_INVALID_PRIVATE_KEY); + return 0; + } + + oct.data = ecxkey->privkey; + oct.length = KEYLEN(pkey); + oct.flags = 0; + + penclen = i2d_ASN1_OCTET_STRING(&oct, &penc); + if (penclen < 0) { + ECerr(EC_F_ECX_PRIV_ENCODE, ERR_R_MALLOC_FAILURE); + return 0; + } + + if (!PKCS8_pkey_set0(p8, OBJ_nid2obj(pkey->ameth->pkey_id), 0, + V_ASN1_UNDEF, NULL, penc, penclen)) { + OPENSSL_clear_free(penc, penclen); + ECerr(EC_F_ECX_PRIV_ENCODE, ERR_R_MALLOC_FAILURE); + return 0; + } + + return 1; +} + +static int ecx_size(const EVP_PKEY *pkey) +{ + return KEYLEN(pkey); +} + +static int ecx_bits(const EVP_PKEY *pkey) +{ + if (IS25519(pkey->ameth->pkey_id)) { + return X25519_BITS; + } else if(ISX448(pkey->ameth->pkey_id)) { + return X448_BITS; + } else { + return ED448_BITS; + } +} + +static int ecx_security_bits(const EVP_PKEY *pkey) +{ + if (IS25519(pkey->ameth->pkey_id)) { + return X25519_SECURITY_BITS; + } else { + return X448_SECURITY_BITS; + } +} + +static void ecx_free(EVP_PKEY *pkey) +{ + if (pkey->pkey.ecx != NULL) + OPENSSL_secure_clear_free(pkey->pkey.ecx->privkey, KEYLEN(pkey)); + OPENSSL_free(pkey->pkey.ecx); +} + +/* "parameters" are always equal */ +static int ecx_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b) +{ + return 1; +} + +static int ecx_key_print(BIO *bp, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *ctx, ecx_key_op_t op) +{ + const ECX_KEY *ecxkey = pkey->pkey.ecx; + const char *nm = OBJ_nid2ln(pkey->ameth->pkey_id); + + if (op == KEY_OP_PRIVATE) { + if (ecxkey == NULL || ecxkey->privkey == NULL) { + if (BIO_printf(bp, "%*s<INVALID PRIVATE KEY>\n", indent, "") <= 0) + return 0; + return 1; + } + if (BIO_printf(bp, "%*s%s Private-Key:\n", indent, "", nm) <= 0) + return 0; + if (BIO_printf(bp, "%*spriv:\n", indent, "") <= 0) + return 0; + if (ASN1_buf_print(bp, ecxkey->privkey, KEYLEN(pkey), + indent + 4) == 0) + return 0; + } else { + if (ecxkey == NULL) { + if (BIO_printf(bp, "%*s<INVALID PUBLIC KEY>\n", indent, "") <= 0) + return 0; + return 1; + } + if (BIO_printf(bp, "%*s%s Public-Key:\n", indent, "", nm) <= 0) + return 0; + } + if (BIO_printf(bp, "%*spub:\n", indent, "") <= 0) + return 0; + + if (ASN1_buf_print(bp, ecxkey->pubkey, KEYLEN(pkey), + indent + 4) == 0) + return 0; + return 1; +} + +static int ecx_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *ctx) +{ + return ecx_key_print(bp, pkey, indent, ctx, KEY_OP_PRIVATE); +} + +static int ecx_pub_print(BIO *bp, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *ctx) +{ + return ecx_key_print(bp, pkey, indent, ctx, KEY_OP_PUBLIC); +} + +static int ecx_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2) +{ + switch (op) { + + case ASN1_PKEY_CTRL_SET1_TLS_ENCPT: + return ecx_key_op(pkey, pkey->ameth->pkey_id, NULL, arg2, arg1, + KEY_OP_PUBLIC); + + case ASN1_PKEY_CTRL_GET1_TLS_ENCPT: + if (pkey->pkey.ecx != NULL) { + unsigned char **ppt = arg2; + + *ppt = OPENSSL_memdup(pkey->pkey.ecx->pubkey, KEYLEN(pkey)); + if (*ppt != NULL) + return KEYLEN(pkey); + } + return 0; + + default: + return -2; + + } +} + +static int ecd_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2) +{ + switch (op) { + case ASN1_PKEY_CTRL_DEFAULT_MD_NID: + /* We currently only support Pure EdDSA which takes no digest */ + *(int *)arg2 = NID_undef; + return 2; + + default: + return -2; + + } +} + +static int ecx_set_priv_key(EVP_PKEY *pkey, const unsigned char *priv, + size_t len) +{ + return ecx_key_op(pkey, pkey->ameth->pkey_id, NULL, priv, len, + KEY_OP_PRIVATE); +} + +static int ecx_set_pub_key(EVP_PKEY *pkey, const unsigned char *pub, size_t len) +{ + return ecx_key_op(pkey, pkey->ameth->pkey_id, NULL, pub, len, + KEY_OP_PUBLIC); +} + +static int ecx_get_priv_key(const EVP_PKEY *pkey, unsigned char *priv, + size_t *len) +{ + const ECX_KEY *key = pkey->pkey.ecx; + + if (priv == NULL) { + *len = KEYLENID(pkey->ameth->pkey_id); + return 1; + } + + if (key == NULL + || key->privkey == NULL + || *len < (size_t)KEYLENID(pkey->ameth->pkey_id)) + return 0; + + *len = KEYLENID(pkey->ameth->pkey_id); + memcpy(priv, key->privkey, *len); + + return 1; +} + +static int ecx_get_pub_key(const EVP_PKEY *pkey, unsigned char *pub, + size_t *len) +{ + const ECX_KEY *key = pkey->pkey.ecx; + + if (pub == NULL) { + *len = KEYLENID(pkey->ameth->pkey_id); + return 1; + } + + if (key == NULL + || *len < (size_t)KEYLENID(pkey->ameth->pkey_id)) + return 0; + + *len = KEYLENID(pkey->ameth->pkey_id); + memcpy(pub, key->pubkey, *len); + + return 1; +} + +const EVP_PKEY_ASN1_METHOD ecx25519_asn1_meth = { + EVP_PKEY_X25519, + EVP_PKEY_X25519, + 0, + "X25519", + "OpenSSL X25519 algorithm", + + ecx_pub_decode, + ecx_pub_encode, + ecx_pub_cmp, + ecx_pub_print, + + ecx_priv_decode, + ecx_priv_encode, + ecx_priv_print, + + ecx_size, + ecx_bits, + ecx_security_bits, + + 0, 0, 0, 0, + ecx_cmp_parameters, + 0, 0, + + ecx_free, + ecx_ctrl, + NULL, + NULL, + + NULL, + NULL, + NULL, + + NULL, + NULL, + NULL, + + ecx_set_priv_key, + ecx_set_pub_key, + ecx_get_priv_key, + ecx_get_pub_key, +}; + +const EVP_PKEY_ASN1_METHOD ecx448_asn1_meth = { + EVP_PKEY_X448, + EVP_PKEY_X448, + 0, + "X448", + "OpenSSL X448 algorithm", + + ecx_pub_decode, + ecx_pub_encode, + ecx_pub_cmp, + ecx_pub_print, + + ecx_priv_decode, + ecx_priv_encode, + ecx_priv_print, + + ecx_size, + ecx_bits, + ecx_security_bits, + + 0, 0, 0, 0, + ecx_cmp_parameters, + 0, 0, + + ecx_free, + ecx_ctrl, + NULL, + NULL, + + NULL, + NULL, + NULL, + + NULL, + NULL, + NULL, + + ecx_set_priv_key, + ecx_set_pub_key, + ecx_get_priv_key, + ecx_get_pub_key, +}; + +static int ecd_size25519(const EVP_PKEY *pkey) +{ + return ED25519_SIGSIZE; +} + +static int ecd_size448(const EVP_PKEY *pkey) +{ + return ED448_SIGSIZE; +} + +static int ecd_item_verify(EVP_MD_CTX *ctx, const ASN1_ITEM *it, void *asn, + X509_ALGOR *sigalg, ASN1_BIT_STRING *str, + EVP_PKEY *pkey) +{ + const ASN1_OBJECT *obj; + int ptype; + int nid; + + /* Sanity check: make sure it is ED25519/ED448 with absent parameters */ + X509_ALGOR_get0(&obj, &ptype, NULL, sigalg); + nid = OBJ_obj2nid(obj); + if ((nid != NID_ED25519 && nid != NID_ED448) || ptype != V_ASN1_UNDEF) { + ECerr(EC_F_ECD_ITEM_VERIFY, EC_R_INVALID_ENCODING); + return 0; + } + + if (!EVP_DigestVerifyInit(ctx, NULL, NULL, NULL, pkey)) + return 0; + + return 2; +} + +static int ecd_item_sign25519(EVP_MD_CTX *ctx, const ASN1_ITEM *it, void *asn, + X509_ALGOR *alg1, X509_ALGOR *alg2, + ASN1_BIT_STRING *str) +{ + /* Set algorithms identifiers */ + X509_ALGOR_set0(alg1, OBJ_nid2obj(NID_ED25519), V_ASN1_UNDEF, NULL); + if (alg2) + X509_ALGOR_set0(alg2, OBJ_nid2obj(NID_ED25519), V_ASN1_UNDEF, NULL); + /* Algorithm identifiers set: carry on as normal */ + return 3; +} + +static int ecd_sig_info_set25519(X509_SIG_INFO *siginf, const X509_ALGOR *alg, + const ASN1_STRING *sig) +{ + X509_SIG_INFO_set(siginf, NID_undef, NID_ED25519, X25519_SECURITY_BITS, + X509_SIG_INFO_TLS); + return 1; +} + +static int ecd_item_sign448(EVP_MD_CTX *ctx, const ASN1_ITEM *it, void *asn, + X509_ALGOR *alg1, X509_ALGOR *alg2, + ASN1_BIT_STRING *str) +{ + /* Set algorithm identifier */ + X509_ALGOR_set0(alg1, OBJ_nid2obj(NID_ED448), V_ASN1_UNDEF, NULL); + if (alg2 != NULL) + X509_ALGOR_set0(alg2, OBJ_nid2obj(NID_ED448), V_ASN1_UNDEF, NULL); + /* Algorithm identifier set: carry on as normal */ + return 3; +} + +static int ecd_sig_info_set448(X509_SIG_INFO *siginf, const X509_ALGOR *alg, + const ASN1_STRING *sig) +{ + X509_SIG_INFO_set(siginf, NID_undef, NID_ED448, X448_SECURITY_BITS, + X509_SIG_INFO_TLS); + return 1; +} + + +const EVP_PKEY_ASN1_METHOD ed25519_asn1_meth = { + EVP_PKEY_ED25519, + EVP_PKEY_ED25519, + 0, + "ED25519", + "OpenSSL ED25519 algorithm", + + ecx_pub_decode, + ecx_pub_encode, + ecx_pub_cmp, + ecx_pub_print, + + ecx_priv_decode, + ecx_priv_encode, + ecx_priv_print, + + ecd_size25519, + ecx_bits, + ecx_security_bits, + + 0, 0, 0, 0, + ecx_cmp_parameters, + 0, 0, + + ecx_free, + ecd_ctrl, + NULL, + NULL, + ecd_item_verify, + ecd_item_sign25519, + ecd_sig_info_set25519, + + NULL, + NULL, + NULL, + + ecx_set_priv_key, + ecx_set_pub_key, + ecx_get_priv_key, + ecx_get_pub_key, +}; + +const EVP_PKEY_ASN1_METHOD ed448_asn1_meth = { + EVP_PKEY_ED448, + EVP_PKEY_ED448, + 0, + "ED448", + "OpenSSL ED448 algorithm", + + ecx_pub_decode, + ecx_pub_encode, + ecx_pub_cmp, + ecx_pub_print, + + ecx_priv_decode, + ecx_priv_encode, + ecx_priv_print, + + ecd_size448, + ecx_bits, + ecx_security_bits, + + 0, 0, 0, 0, + ecx_cmp_parameters, + 0, 0, + + ecx_free, + ecd_ctrl, + NULL, + NULL, + ecd_item_verify, + ecd_item_sign448, + ecd_sig_info_set448, + + NULL, + NULL, + NULL, + + ecx_set_priv_key, + ecx_set_pub_key, + ecx_get_priv_key, + ecx_get_pub_key, +}; + +static int pkey_ecx_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) +{ + return ecx_key_op(pkey, ctx->pmeth->pkey_id, NULL, NULL, 0, KEY_OP_KEYGEN); +} + +static int validate_ecx_derive(EVP_PKEY_CTX *ctx, unsigned char *key, + size_t *keylen, + const unsigned char **privkey, + const unsigned char **pubkey) +{ + const ECX_KEY *ecxkey, *peerkey; + + if (ctx->pkey == NULL || ctx->peerkey == NULL) { + ECerr(EC_F_VALIDATE_ECX_DERIVE, EC_R_KEYS_NOT_SET); + return 0; + } + ecxkey = ctx->pkey->pkey.ecx; + peerkey = ctx->peerkey->pkey.ecx; + if (ecxkey == NULL || ecxkey->privkey == NULL) { + ECerr(EC_F_VALIDATE_ECX_DERIVE, EC_R_INVALID_PRIVATE_KEY); + return 0; + } + if (peerkey == NULL) { + ECerr(EC_F_VALIDATE_ECX_DERIVE, EC_R_INVALID_PEER_KEY); + return 0; + } + *privkey = ecxkey->privkey; + *pubkey = peerkey->pubkey; + + return 1; +} + +static int pkey_ecx_derive25519(EVP_PKEY_CTX *ctx, unsigned char *key, + size_t *keylen) +{ + const unsigned char *privkey, *pubkey; + + if (!validate_ecx_derive(ctx, key, keylen, &privkey, &pubkey) + || (key != NULL + && X25519(key, privkey, pubkey) == 0)) + return 0; + *keylen = X25519_KEYLEN; + return 1; +} + +static int pkey_ecx_derive448(EVP_PKEY_CTX *ctx, unsigned char *key, + size_t *keylen) +{ + const unsigned char *privkey, *pubkey; + + if (!validate_ecx_derive(ctx, key, keylen, &privkey, &pubkey) + || (key != NULL + && X448(key, privkey, pubkey) == 0)) + return 0; + *keylen = X448_KEYLEN; + return 1; +} + +static int pkey_ecx_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) +{ + /* Only need to handle peer key for derivation */ + if (type == EVP_PKEY_CTRL_PEER_KEY) + return 1; + return -2; +} + +const EVP_PKEY_METHOD ecx25519_pkey_meth = { + EVP_PKEY_X25519, + 0, 0, 0, 0, 0, 0, 0, + pkey_ecx_keygen, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + pkey_ecx_derive25519, + pkey_ecx_ctrl, + 0 +}; + +const EVP_PKEY_METHOD ecx448_pkey_meth = { + EVP_PKEY_X448, + 0, 0, 0, 0, 0, 0, 0, + pkey_ecx_keygen, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + pkey_ecx_derive448, + pkey_ecx_ctrl, + 0 +}; + +static int pkey_ecd_digestsign25519(EVP_MD_CTX *ctx, unsigned char *sig, + size_t *siglen, const unsigned char *tbs, + size_t tbslen) +{ + const ECX_KEY *edkey = EVP_MD_CTX_pkey_ctx(ctx)->pkey->pkey.ecx; + + if (sig == NULL) { + *siglen = ED25519_SIGSIZE; + return 1; + } + if (*siglen < ED25519_SIGSIZE) { + ECerr(EC_F_PKEY_ECD_DIGESTSIGN25519, EC_R_BUFFER_TOO_SMALL); + return 0; + } + + if (ED25519_sign(sig, tbs, tbslen, edkey->pubkey, edkey->privkey) == 0) + return 0; + *siglen = ED25519_SIGSIZE; + return 1; +} + +static int pkey_ecd_digestsign448(EVP_MD_CTX *ctx, unsigned char *sig, + size_t *siglen, const unsigned char *tbs, + size_t tbslen) +{ + const ECX_KEY *edkey = EVP_MD_CTX_pkey_ctx(ctx)->pkey->pkey.ecx; + + if (sig == NULL) { + *siglen = ED448_SIGSIZE; + return 1; + } + if (*siglen < ED448_SIGSIZE) { + ECerr(EC_F_PKEY_ECD_DIGESTSIGN448, EC_R_BUFFER_TOO_SMALL); + return 0; + } + + if (ED448_sign(sig, tbs, tbslen, edkey->pubkey, edkey->privkey, NULL, + 0) == 0) + return 0; + *siglen = ED448_SIGSIZE; + return 1; +} + +static int pkey_ecd_digestverify25519(EVP_MD_CTX *ctx, const unsigned char *sig, + size_t siglen, const unsigned char *tbs, + size_t tbslen) +{ + const ECX_KEY *edkey = EVP_MD_CTX_pkey_ctx(ctx)->pkey->pkey.ecx; + + if (siglen != ED25519_SIGSIZE) + return 0; + + return ED25519_verify(tbs, tbslen, sig, edkey->pubkey); +} + +static int pkey_ecd_digestverify448(EVP_MD_CTX *ctx, const unsigned char *sig, + size_t siglen, const unsigned char *tbs, + size_t tbslen) +{ + const ECX_KEY *edkey = EVP_MD_CTX_pkey_ctx(ctx)->pkey->pkey.ecx; + + if (siglen != ED448_SIGSIZE) + return 0; + + return ED448_verify(tbs, tbslen, sig, edkey->pubkey, NULL, 0); +} + +static int pkey_ecd_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) +{ + switch (type) { + case EVP_PKEY_CTRL_MD: + /* Only NULL allowed as digest */ + if (p2 == NULL || (const EVP_MD *)p2 == EVP_md_null()) + return 1; + ECerr(EC_F_PKEY_ECD_CTRL, EC_R_INVALID_DIGEST_TYPE); + return 0; + + case EVP_PKEY_CTRL_DIGESTINIT: + return 1; + } + return -2; +} + +const EVP_PKEY_METHOD ed25519_pkey_meth = { + EVP_PKEY_ED25519, EVP_PKEY_FLAG_SIGCTX_CUSTOM, + 0, 0, 0, 0, 0, 0, + pkey_ecx_keygen, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + pkey_ecd_ctrl, + 0, + pkey_ecd_digestsign25519, + pkey_ecd_digestverify25519 +}; + +const EVP_PKEY_METHOD ed448_pkey_meth = { + EVP_PKEY_ED448, EVP_PKEY_FLAG_SIGCTX_CUSTOM, + 0, 0, 0, 0, 0, 0, + pkey_ecx_keygen, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + pkey_ecd_ctrl, + 0, + pkey_ecd_digestsign448, + pkey_ecd_digestverify448 +}; |