| /* |
| * Copyright 2006-2018 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 "internal/asn1_int.h" |
| #include "internal/evp_int.h" |
| #include "ec_lcl.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_OCTET_STRING_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; |
| |
| case ASN1_PKEY_CTRL_DEFAULT_MD_NID: |
| *(int *)arg2 = NID_sha256; |
| 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); |
| } |
| |
| 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, |
| }; |
| |
| 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, |
| }; |
| |
| 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 idetifiers 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, |
| 0, |
| NULL, |
| NULL, |
| ecd_item_verify, |
| ecd_item_sign25519, |
| ecd_sig_info_set25519, |
| |
| NULL, |
| NULL, |
| NULL, |
| |
| ecx_set_priv_key, |
| ecx_set_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, |
| 0, |
| NULL, |
| NULL, |
| ecd_item_verify, |
| ecd_item_sign448, |
| ecd_sig_info_set448, |
| |
| NULL, |
| NULL, |
| NULL, |
| |
| ecx_set_priv_key, |
| ecx_set_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 |
| }; |