Commit 13735cfe authored by Matt Caswell's avatar Matt Caswell
Browse files

Integrate X448 and Ed448 into libcrypto



This adds all of the relevant EVP plumbing required to make
X448 and Ed448 work.

Reviewed-by: default avatarRich Salz <rsalz@openssl.org>
Reviewed-by: default avatarKurt Roeckx <kurt@roeckx.be>
(Merged from https://github.com/openssl/openssl/pull/5481)
parent f7869f1b
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ static const EVP_PKEY_ASN1_METHOD *standard_methods[] = {
#endif
#ifndef OPENSSL_NO_EC
    &ecx25519_asn1_meth,
    &ecx448_asn1_meth,
#endif
#ifndef OPENSSL_NO_POLY1305
    &poly1305_asn1_meth,
@@ -51,6 +52,7 @@ static const EVP_PKEY_ASN1_METHOD *standard_methods[] = {
#endif
#ifndef OPENSSL_NO_EC
    &ed25519_asn1_meth,
    &ed448_asn1_meth,
#endif
};
+5 −0
Original line number Diff line number Diff line
@@ -242,6 +242,10 @@ static const ERR_STRING_DATA EC_str_functs[] = {
     "ossl_ecdsa_verify_sig"},
    {ERR_PACK(ERR_LIB_EC, EC_F_PKEY_ECD_CTRL, 0), "pkey_ecd_ctrl"},
    {ERR_PACK(ERR_LIB_EC, EC_F_PKEY_ECD_DIGESTSIGN, 0), "pkey_ecd_digestsign"},
    {ERR_PACK(ERR_LIB_EC, EC_F_PKEY_ECD_DIGESTSIGN25519, 0),
     "pkey_ecd_digestsign25519"},
    {ERR_PACK(ERR_LIB_EC, EC_F_PKEY_ECD_DIGESTSIGN448, 0),
     "pkey_ecd_digestsign448"},
    {ERR_PACK(ERR_LIB_EC, EC_F_PKEY_ECX_DERIVE, 0), "pkey_ecx_derive"},
    {ERR_PACK(ERR_LIB_EC, EC_F_PKEY_EC_CTRL, 0), "pkey_ec_ctrl"},
    {ERR_PACK(ERR_LIB_EC, EC_F_PKEY_EC_CTRL_STR, 0), "pkey_ec_ctrl_str"},
@@ -249,6 +253,7 @@ static const ERR_STRING_DATA EC_str_functs[] = {
    {ERR_PACK(ERR_LIB_EC, EC_F_PKEY_EC_KEYGEN, 0), "pkey_ec_keygen"},
    {ERR_PACK(ERR_LIB_EC, EC_F_PKEY_EC_PARAMGEN, 0), "pkey_ec_paramgen"},
    {ERR_PACK(ERR_LIB_EC, EC_F_PKEY_EC_SIGN, 0), "pkey_ec_sign"},
    {ERR_PACK(ERR_LIB_EC, EC_F_VALIDATE_ECX_DERIVE, 0), "validate_ecx_derive"},
    {0, NULL}
};

+1 −0
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@
#include <openssl/ec.h>
#include <openssl/bn.h>
#include "internal/refcount.h"
#include "curve448/curve448_lcl.h"

#if defined(__SUNPRO_C)
# if __SUNPRO_C >= 0x520
+313 −103
Original line number Diff line number Diff line
@@ -16,30 +16,39 @@
#include "internal/evp_int.h"
#include "ec_lcl.h"

#define X25519_KEYLEN        32
#define X25519_BITS          253
#define X25519_SECURITY_BITS 128

#define ED25519_SIGSIZE      64

typedef struct {
    unsigned char pubkey[X25519_KEYLEN];
    unsigned char *privkey;
} X25519_KEY;
#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 {
    X25519_PUBLIC,
    X25519_PRIVATE,
    X25519_KEYGEN
    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)
{
    X25519_KEY *xkey;
    ECX_KEY *key = NULL;
    unsigned char *privkey, *pubkey;

    if (op != X25519_KEYGEN) {
    if (op != KEY_OP_KEYGEN) {
        if (palg != NULL) {
            int ptype;

@@ -51,69 +60,85 @@ static int ecx_key_op(EVP_PKEY *pkey, int id, const X509_ALGOR *palg,
            }
        }

        if (p == NULL || plen != X25519_KEYLEN) {
        if (p == NULL || plen != KEYLENID(id)) {
            ECerr(EC_F_ECX_KEY_OP, EC_R_INVALID_ENCODING);
            return 0;
        }
    }

    xkey = OPENSSL_zalloc(sizeof(*xkey));
    if (xkey == NULL) {
    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 == X25519_PUBLIC) {
        memcpy(xkey->pubkey, p, plen);
    if (op == KEY_OP_PUBLIC) {
        memcpy(pubkey, p, plen);
    } else {
        xkey->privkey = OPENSSL_secure_malloc(X25519_KEYLEN);
        if (xkey->privkey == NULL) {
        privkey = key->privkey = OPENSSL_secure_malloc(KEYLENID(id));
        if (privkey == NULL) {
            ECerr(EC_F_ECX_KEY_OP, ERR_R_MALLOC_FAILURE);
            OPENSSL_free(xkey);
            return 0;
            goto err;
        }
        if (op == X25519_KEYGEN) {
            if (RAND_bytes(xkey->privkey, X25519_KEYLEN) <= 0) {
                OPENSSL_secure_free(xkey->privkey);
                OPENSSL_free(xkey);
                return 0;
        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) {
                xkey->privkey[0] &= 248;
                xkey->privkey[31] &= 127;
                xkey->privkey[31] |= 64;
                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(xkey->privkey, p, X25519_KEYLEN);
            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;
        }
        if (id == EVP_PKEY_X25519)
            X25519_public_from_private(xkey->pubkey, xkey->privkey);
        else
            ED25519_public_from_private(xkey->pubkey, xkey->privkey);
    }

    EVP_PKEY_assign(pkey, id, xkey);
    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 X25519_KEY *xkey = pkey->pkey.ptr;
    const ECX_KEY *ecxkey = pkey->pkey.ecx;
    unsigned char *penc;

    if (xkey == NULL) {
    if (ecxkey == NULL) {
        ECerr(EC_F_ECX_PUB_ENCODE, EC_R_INVALID_KEY);
        return 0;
    }

    penc = OPENSSL_memdup(xkey->pubkey, X25519_KEYLEN);
    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, X25519_KEYLEN)) {
                                V_ASN1_UNDEF, NULL, penc, KEYLEN(pkey))) {
        OPENSSL_free(penc);
        ECerr(EC_F_ECX_PUB_ENCODE, ERR_R_MALLOC_FAILURE);
        return 0;
@@ -130,17 +155,18 @@ static int ecx_pub_decode(EVP_PKEY *pkey, X509_PUBKEY *pubkey)
    if (!X509_PUBKEY_get0_param(NULL, &p, &pklen, &palg, pubkey))
        return 0;
    return ecx_key_op(pkey, pkey->ameth->pkey_id, palg, p, pklen,
                      X25519_PUBLIC);
                      KEY_OP_PUBLIC);
}

static int ecx_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b)
{
    const X25519_KEY *akey = a->pkey.ptr;
    const X25519_KEY *bkey = b->pkey.ptr;
    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, X25519_KEYLEN);

    return CRYPTO_memcmp(akey->pubkey, bkey->pubkey, KEYLEN(a)) == 0;
}

static int ecx_priv_decode(EVP_PKEY *pkey, const PKCS8_PRIV_KEY_INFO *p8)
@@ -163,25 +189,25 @@ static int ecx_priv_decode(EVP_PKEY *pkey, const PKCS8_PRIV_KEY_INFO *p8)
        plen = ASN1_STRING_length(oct);
    }

    rv = ecx_key_op(pkey, pkey->ameth->pkey_id, palg, p, plen, X25519_PRIVATE);
    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 X25519_KEY *xkey = pkey->pkey.ptr;
    const ECX_KEY *ecxkey = pkey->pkey.ecx;
    ASN1_OCTET_STRING oct;
    unsigned char *penc = NULL;
    int penclen;

    if (xkey == NULL || xkey->privkey == NULL) {
    if (ecxkey == NULL || ecxkey->privkey == NULL) {
        ECerr(EC_F_ECX_PRIV_ENCODE, EC_R_INVALID_PRIVATE_KEY);
        return 0;
    }

    oct.data = xkey->privkey;
    oct.length = X25519_KEYLEN;
    oct.data = ecxkey->privkey;
    oct.length = KEYLEN(pkey);
    oct.flags = 0;

    penclen = i2d_ASN1_OCTET_STRING(&oct, &penc);
@@ -202,26 +228,34 @@ static int ecx_priv_encode(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pkey)

static int ecx_size(const EVP_PKEY *pkey)
{
    return X25519_KEYLEN;
    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)
{
    X25519_KEY *xkey = pkey->pkey.ptr;

    if (xkey)
        OPENSSL_secure_clear_free(xkey->privkey, X25519_KEYLEN);
    OPENSSL_free(xkey);
    if (pkey->pkey.ecx != NULL)
        OPENSSL_secure_clear_free(pkey->pkey.ecx->privkey, KEYLEN(pkey));
    OPENSSL_free(pkey->pkey.ecx);
}

/* "parameters" are always equal */
@@ -233,12 +267,11 @@ static int ecx_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b)
static int ecx_key_print(BIO *bp, const EVP_PKEY *pkey, int indent,
                         ASN1_PCTX *ctx, ecx_key_op_t op)
{
    const X25519_KEY *xkey = pkey->pkey.ptr;

    const ECX_KEY *ecxkey = pkey->pkey.ecx;
    const char *nm = OBJ_nid2ln(pkey->ameth->pkey_id);

    if (op == X25519_PRIVATE) {
        if (xkey == NULL || xkey->privkey == NULL) {
    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;
@@ -247,10 +280,11 @@ static int ecx_key_print(BIO *bp, const EVP_PKEY *pkey, int indent,
            return 0;
        if (BIO_printf(bp, "%*spriv:\n", indent, "") <= 0)
            return 0;
        if (ASN1_buf_print(bp, xkey->privkey, X25519_KEYLEN, indent + 4) == 0)
        if (ASN1_buf_print(bp, ecxkey->privkey, KEYLEN(pkey),
                           indent + 4) == 0)
            return 0;
    } else {
        if (xkey == NULL) {
        if (ecxkey == NULL) {
            if (BIO_printf(bp, "%*s<INVALID PUBLIC KEY>\n", indent, "") <= 0)
                return 0;
            return 1;
@@ -260,7 +294,9 @@ static int ecx_key_print(BIO *bp, const EVP_PKEY *pkey, int indent,
    }
    if (BIO_printf(bp, "%*spub:\n", indent, "") <= 0)
        return 0;
    if (ASN1_buf_print(bp, xkey->pubkey, X25519_KEYLEN, indent + 4) == 0)

    if (ASN1_buf_print(bp, ecxkey->pubkey, KEYLEN(pkey),
                       indent + 4) == 0)
        return 0;
    return 1;
}
@@ -268,13 +304,13 @@ static int ecx_key_print(BIO *bp, const EVP_PKEY *pkey, int indent,
static int ecx_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent,
                          ASN1_PCTX *ctx)
{
    return ecx_key_print(bp, pkey, indent, ctx, X25519_PRIVATE);
    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, X25519_PUBLIC);
    return ecx_key_print(bp, pkey, indent, ctx, KEY_OP_PUBLIC);
}

static int ecx_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2)
@@ -282,16 +318,16 @@ 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, EVP_PKEY_X25519, NULL, arg2, arg1,
                          X25519_PUBLIC);
        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.ptr != NULL) {
            const X25519_KEY *xkey = pkey->pkey.ptr;
        if (pkey->pkey.ecx != NULL) {
            unsigned char **ppt = arg2;
            *ppt = OPENSSL_memdup(xkey->pubkey, X25519_KEYLEN);

            *ppt = OPENSSL_memdup(pkey->pkey.ecx->pubkey, KEYLEN(pkey));
            if (*ppt != NULL)
                return X25519_KEYLEN;
                return KEYLEN(pkey);
        }
        return 0;

@@ -335,21 +371,58 @@ const EVP_PKEY_ASN1_METHOD ecx25519_asn1_meth = {
    NULL
};

static int ecd_size(const EVP_PKEY *pkey)
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
};

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);
    /* Sanity check: make sure it is ED25519 with absent parameters */
    if (OBJ_obj2nid(obj) != NID_ED25519 || ptype != V_ASN1_UNDEF) {
    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;
    }
@@ -360,7 +433,7 @@ static int ecd_item_verify(EVP_MD_CTX *ctx, const ASN1_ITEM *it, void *asn,
    return 2;
}

static int ecd_item_sign(EVP_MD_CTX *ctx, const ASN1_ITEM *it, void *asn,
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)
{
@@ -372,7 +445,7 @@ static int ecd_item_sign(EVP_MD_CTX *ctx, const ASN1_ITEM *it, void *asn,
    return 3;
}

static int ecd_sig_info_set(X509_SIG_INFO *siginf, const X509_ALGOR *alg,
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,
@@ -380,6 +453,27 @@ static int ecd_sig_info_set(X509_SIG_INFO *siginf, const X509_ALGOR *alg,
    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,
@@ -396,7 +490,7 @@ const EVP_PKEY_ASN1_METHOD ed25519_asn1_meth = {
    ecx_priv_encode,
    ecx_priv_print,

    ecd_size,
    ecd_size25519,
    ecx_bits,
    ecx_security_bits,

@@ -409,37 +503,98 @@ const EVP_PKEY_ASN1_METHOD ed25519_asn1_meth = {
    NULL,
    NULL,
    ecd_item_verify,
    ecd_item_sign,
    ecd_sig_info_set
    ecd_item_sign25519,
    ecd_sig_info_set25519
};

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
};

static int pkey_ecx_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
{
    return ecx_key_op(pkey, ctx->pmeth->pkey_id, NULL, NULL, 0, X25519_KEYGEN);
    return ecx_key_op(pkey, ctx->pmeth->pkey_id, NULL, NULL, 0, KEY_OP_KEYGEN);
}

static int pkey_ecx_derive(EVP_PKEY_CTX *ctx, unsigned char *key,
                           size_t *keylen)
static int validate_ecx_derive(EVP_PKEY_CTX *ctx, unsigned char *key,
                                          size_t *keylen,
                                          const unsigned char **privkey,
                                          const unsigned char **pubkey)
{
    const X25519_KEY *pkey, *peerkey;
    const ECX_KEY *ecxkey, *peerkey;

    if (ctx->pkey == NULL || ctx->peerkey == NULL) {
        ECerr(EC_F_PKEY_ECX_DERIVE, EC_R_KEYS_NOT_SET);
        ECerr(EC_F_VALIDATE_ECX_DERIVE, EC_R_KEYS_NOT_SET);
        return 0;
    }
    pkey = ctx->pkey->pkey.ptr;
    peerkey = ctx->peerkey->pkey.ptr;
    if (pkey == NULL || pkey->privkey == NULL) {
        ECerr(EC_F_PKEY_ECX_DERIVE, EC_R_INVALID_PRIVATE_KEY);
    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_PKEY_ECX_DERIVE, EC_R_INVALID_PEER_KEY);
        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;
    if (key != NULL && X25519(key, pkey->privkey, peerkey->pubkey) == 0)
    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;
}

@@ -456,23 +611,33 @@ const EVP_PKEY_METHOD ecx25519_pkey_meth = {
    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_derive,
    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_digestsign(EVP_MD_CTX *ctx, unsigned char *sig,
static int pkey_ecd_digestsign25519(EVP_MD_CTX *ctx, unsigned char *sig,
                                    size_t *siglen, const unsigned char *tbs,
                                    size_t tbslen)
{
    const X25519_KEY *edkey = EVP_MD_CTX_pkey_ctx(ctx)->pkey->pkey.ptr;
    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_DIGESTSIGN, EC_R_BUFFER_TOO_SMALL);
        ECerr(EC_F_PKEY_ECD_DIGESTSIGN25519, EC_R_BUFFER_TOO_SMALL);
        return 0;
    }

@@ -482,11 +647,33 @@ static int pkey_ecd_digestsign(EVP_MD_CTX *ctx, unsigned char *sig,
    return 1;
}

static int pkey_ecd_digestverify(EVP_MD_CTX *ctx, const unsigned char *sig,
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 X25519_KEY *edkey = EVP_MD_CTX_pkey_ctx(ctx)->pkey->pkey.ptr;
    const ECX_KEY *edkey = EVP_MD_CTX_pkey_ctx(ctx)->pkey->pkey.ecx;

    if (siglen != ED25519_SIGSIZE)
        return 0;
@@ -494,6 +681,18 @@ static int pkey_ecd_digestverify(EVP_MD_CTX *ctx, const unsigned char *sig,
    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) {
@@ -517,6 +716,17 @@ const EVP_PKEY_METHOD ed25519_pkey_meth = {
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    pkey_ecd_ctrl,
    0,
    pkey_ecd_digestsign,
    pkey_ecd_digestverify
    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
};
+3 −0
Original line number Diff line number Diff line
@@ -594,6 +594,8 @@ EC_F_OSSL_ECDSA_SIGN_SIG:249:ossl_ecdsa_sign_sig
EC_F_OSSL_ECDSA_VERIFY_SIG:250:ossl_ecdsa_verify_sig
EC_F_PKEY_ECD_CTRL:271:pkey_ecd_ctrl
EC_F_PKEY_ECD_DIGESTSIGN:272:pkey_ecd_digestsign
EC_F_PKEY_ECD_DIGESTSIGN25519:276:pkey_ecd_digestsign25519
EC_F_PKEY_ECD_DIGESTSIGN448:277:pkey_ecd_digestsign448
EC_F_PKEY_ECX_DERIVE:269:pkey_ecx_derive
EC_F_PKEY_EC_CTRL:197:pkey_ec_ctrl
EC_F_PKEY_EC_CTRL_STR:198:pkey_ec_ctrl_str
@@ -601,6 +603,7 @@ EC_F_PKEY_EC_DERIVE:217:pkey_ec_derive
EC_F_PKEY_EC_KEYGEN:199:pkey_ec_keygen
EC_F_PKEY_EC_PARAMGEN:219:pkey_ec_paramgen
EC_F_PKEY_EC_SIGN:218:pkey_ec_sign
EC_F_VALIDATE_ECX_DERIVE:278:validate_ecx_derive
ENGINE_F_DIGEST_UPDATE:198:digest_update
ENGINE_F_DYNAMIC_CTRL:180:dynamic_ctrl
ENGINE_F_DYNAMIC_GET_DATA_CTX:181:dynamic_get_data_ctx
Loading