tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ec.c (22738B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #ifdef FREEBL_NO_DEPEND
      6 #include "stubs.h"
      7 #endif
      8 
      9 #include "blapi.h"
     10 #include "blapii.h"
     11 #include "prerr.h"
     12 #include "secerr.h"
     13 #include "secmpi.h"
     14 #include "secitem.h"
     15 #include "mplogic.h"
     16 #include "ec.h"
     17 #include "ecl.h"
     18 #include "verified/Hacl_P384.h"
     19 #include "verified/Hacl_P521.h"
     20 #include "secport.h"
     21 #include "verified/Hacl_Ed25519.h"
     22 
     23 #define EC_DOUBLECHECK PR_FALSE
     24 
     25 SECStatus
     26 ec_ED25519_pt_validate(const SECItem *px)
     27 {
     28    if (!px || !px->data || px->len != Ed25519_PUBLIC_KEYLEN) {
     29        PORT_SetError(SEC_ERROR_INVALID_ARGS);
     30        return SECFailure;
     31    }
     32    return SECSuccess;
     33 }
     34 
     35 SECStatus
     36 ec_ED25519_scalar_validate(const SECItem *scalar)
     37 {
     38    if (!scalar || !scalar->data || scalar->len != Ed25519_PRIVATE_KEYLEN) {
     39        PORT_SetError(SEC_ERROR_INVALID_ARGS);
     40        return SECFailure;
     41    }
     42 
     43    return SECSuccess;
     44 }
     45 
     46 static const ECMethod kMethods[] = {
     47    { ECCurve25519,
     48      ec_Curve25519_pt_mul,
     49      ec_Curve25519_pt_validate,
     50      ec_Curve25519_scalar_validate,
     51      NULL,
     52      NULL },
     53    {
     54        ECCurve_NIST_P256,
     55        ec_secp256r1_pt_mul,
     56        ec_secp256r1_pt_validate,
     57        ec_secp256r1_scalar_validate,
     58        ec_secp256r1_sign_digest,
     59        ec_secp256r1_verify_digest,
     60    },
     61    {
     62        ECCurve_NIST_P384,
     63        ec_secp384r1_pt_mul,
     64        ec_secp384r1_pt_validate,
     65        ec_secp384r1_scalar_validate,
     66        ec_secp384r1_sign_digest,
     67        ec_secp384r1_verify_digest,
     68    },
     69    {
     70        ECCurve_NIST_P521,
     71        ec_secp521r1_pt_mul,
     72        ec_secp521r1_pt_validate,
     73        ec_secp521r1_scalar_validate,
     74        ec_secp521r1_sign_digest,
     75        ec_secp521r1_verify_digest,
     76    },
     77    { ECCurve_Ed25519,
     78      NULL,
     79      ec_ED25519_pt_validate,
     80      ec_ED25519_scalar_validate,
     81      NULL,
     82      NULL },
     83 };
     84 
     85 static const ECMethod *
     86 ec_get_method_from_name(ECCurveName name)
     87 {
     88    unsigned long i;
     89    for (i = 0; i < sizeof(kMethods) / sizeof(kMethods[0]); ++i) {
     90        if (kMethods[i].name == name) {
     91            return &kMethods[i];
     92        }
     93    }
     94    return NULL;
     95 }
     96 
     97 /* Generates a new EC key pair. The private key is a supplied
     98 * value and the public key is the result of performing a scalar
     99 * point multiplication of that value with the curve's base point.
    100 */
    101 SECStatus
    102 ec_NewKey(ECParams *ecParams, ECPrivateKey **privKey,
    103          const unsigned char *privKeyBytes, int privKeyLen)
    104 {
    105    SECStatus rv = SECFailure;
    106    PLArenaPool *arena;
    107    ECPrivateKey *key;
    108    int len;
    109 
    110    if (!ecParams || ecParams->name == ECCurve_noName ||
    111        !privKey || !privKeyBytes || privKeyLen <= 0) {
    112        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    113        return SECFailure;
    114    }
    115 
    116    if (ecParams->fieldID.type != ec_field_plain) {
    117        PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
    118        return SECFailure;
    119    }
    120 
    121    /* Initialize an arena for the EC key. */
    122    if (!(arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE)))
    123        return SECFailure;
    124 
    125    key = (ECPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(ECPrivateKey));
    126    if (!key) {
    127        goto cleanup;
    128    }
    129 
    130    /* Set the version number (SEC 1 section C.4 says it should be 1) */
    131    SECITEM_AllocItem(arena, &key->version, 1);
    132    key->version.data[0] = 1;
    133 
    134    /* Copy all of the fields from the ECParams argument to the
    135     * ECParams structure within the private key.
    136     */
    137    key->ecParams.arena = arena;
    138    key->ecParams.type = ecParams->type;
    139    key->ecParams.fieldID.size = ecParams->fieldID.size;
    140    key->ecParams.fieldID.type = ecParams->fieldID.type;
    141    CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.fieldID.u.prime,
    142                                  &ecParams->fieldID.u.prime));
    143    key->ecParams.fieldID.k1 = ecParams->fieldID.k1;
    144    key->ecParams.fieldID.k2 = ecParams->fieldID.k2;
    145    key->ecParams.fieldID.k3 = ecParams->fieldID.k3;
    146    CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.a,
    147                                  &ecParams->curve.a));
    148    CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.b,
    149                                  &ecParams->curve.b));
    150    CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.seed,
    151                                  &ecParams->curve.seed));
    152    CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.base,
    153                                  &ecParams->base));
    154    CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.order,
    155                                  &ecParams->order));
    156    key->ecParams.cofactor = ecParams->cofactor;
    157    CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.DEREncoding,
    158                                  &ecParams->DEREncoding));
    159    key->ecParams.name = ecParams->name;
    160    CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curveOID,
    161                                  &ecParams->curveOID));
    162 
    163    SECITEM_AllocItem(arena, &key->publicValue, EC_GetPointSize(ecParams));
    164    len = ecParams->order.len;
    165    SECITEM_AllocItem(arena, &key->privateValue, len);
    166 
    167    /* Copy private key */
    168    if (privKeyLen >= len) {
    169        memcpy(key->privateValue.data, privKeyBytes, len);
    170    } else {
    171        memset(key->privateValue.data, 0, (len - privKeyLen));
    172        memcpy(key->privateValue.data + (len - privKeyLen), privKeyBytes, privKeyLen);
    173    }
    174 
    175    /* Compute corresponding public key */
    176 
    177    /* Use curve specific code for point multiplication */
    178    if (ecParams->name == ECCurve_Ed25519) {
    179        CHECK_SEC_OK(ED_DerivePublicKey(&key->privateValue, &key->publicValue));
    180    } else {
    181        const ECMethod *method = ec_get_method_from_name(ecParams->name);
    182        if (method == NULL || method->pt_mul == NULL) {
    183            PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
    184            rv = SECFailure;
    185            goto cleanup;
    186        }
    187        CHECK_SEC_OK(method->pt_mul(&key->publicValue, &key->privateValue, NULL));
    188    }
    189 
    190    NSS_DECLASSIFY(key->publicValue.data, key->publicValue.len); /* Declassifying public key to avoid false positive */
    191    *privKey = key;
    192    return SECSuccess;
    193 
    194 cleanup:
    195    PORT_FreeArena(arena, PR_TRUE);
    196    return rv;
    197 }
    198 
    199 /* Generates a new EC key pair. The private key is a supplied
    200 * random value (in seed) and the public key is the result of
    201 * performing a scalar point multiplication of that value with
    202 * the curve's base point.
    203 */
    204 SECStatus
    205 EC_NewKeyFromSeed(ECParams *ecParams, ECPrivateKey **privKey,
    206                  const unsigned char *seed, int seedlen)
    207 {
    208    return ec_NewKey(ecParams, privKey, seed, seedlen);
    209 }
    210 
    211 /* Generate a random private key using the algorithm A.4.1 or A.4.2 of ANSI X9.62,
    212 * modified a la FIPS 186-2 Change Notice 1 to eliminate the bias in the
    213 * random number generator.
    214 */
    215 
    216 SECStatus
    217 ec_GenerateRandomPrivateKey(ECParams *ecParams, SECItem *privKey)
    218 {
    219    SECStatus rv = SECFailure;
    220 
    221    unsigned int len = EC_GetScalarSize(ecParams);
    222 
    223    if (privKey->len != len || privKey->data == NULL) {
    224        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    225        return SECFailure;
    226    }
    227 
    228    const ECMethod *method = ec_get_method_from_name(ecParams->name);
    229    if (method == NULL || method->scalar_validate == NULL) {
    230        PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
    231        return SECFailure;
    232    }
    233 
    234    uint8_t leading_coeff_mask;
    235    switch (ecParams->name) {
    236        case ECCurve_Ed25519:
    237        case ECCurve25519:
    238        case ECCurve_NIST_P256:
    239        case ECCurve_NIST_P384:
    240            leading_coeff_mask = 0xff;
    241            break;
    242        case ECCurve_NIST_P521:
    243            leading_coeff_mask = 0x01;
    244            break;
    245        default:
    246            PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
    247            return SECFailure;
    248    }
    249 
    250    /* The rejection sampling method from FIPS 186-5 A.4.2 */
    251    int count = 100;
    252    do {
    253        rv = RNG_GenerateGlobalRandomBytes(privKey->data, len);
    254        if (rv != SECSuccess) {
    255            PORT_SetError(SEC_ERROR_NEED_RANDOM);
    256            return SECFailure;
    257        }
    258        privKey->data[0] &= leading_coeff_mask;
    259        NSS_CLASSIFY(privKey->data, privKey->len);
    260        rv = method->scalar_validate(privKey);
    261    } while (rv != SECSuccess && --count > 0);
    262 
    263    if (rv != SECSuccess) { // implies count == 0
    264        PORT_SetError(SEC_ERROR_BAD_KEY);
    265    }
    266 
    267    return rv;
    268 }
    269 
    270 /* Generates a new EC key pair. The private key is a random value and
    271 * the public key is the result of performing a scalar point multiplication
    272 * of that value with the curve's base point.
    273 */
    274 SECStatus
    275 EC_NewKey(ECParams *ecParams, ECPrivateKey **privKey)
    276 {
    277    SECStatus rv = SECFailure;
    278    SECItem privKeyRand = { siBuffer, NULL, 0 };
    279 
    280    if (!ecParams || ecParams->name == ECCurve_noName || !privKey) {
    281        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    282        return SECFailure;
    283    }
    284 
    285    SECITEM_AllocItem(NULL, &privKeyRand, EC_GetScalarSize(ecParams));
    286    if (privKeyRand.data == NULL) {
    287        PORT_SetError(SEC_ERROR_NO_MEMORY);
    288        rv = SECFailure;
    289        goto cleanup;
    290    }
    291    rv = ec_GenerateRandomPrivateKey(ecParams, &privKeyRand);
    292    if (rv != SECSuccess || privKeyRand.data == NULL) {
    293        goto cleanup;
    294    }
    295    /* generate public key */
    296    CHECK_SEC_OK(ec_NewKey(ecParams, privKey, privKeyRand.data, privKeyRand.len));
    297 
    298 cleanup:
    299    if (privKeyRand.data) {
    300        SECITEM_ZfreeItem(&privKeyRand, PR_FALSE);
    301    }
    302 #if EC_DEBUG
    303    printf("EC_NewKey returning %s\n",
    304           (rv == SECSuccess) ? "success" : "failure");
    305 #endif
    306 
    307    return rv;
    308 }
    309 
    310 /* Validates an EC public key as described in Section 5.2.2 of
    311 * X9.62. The ECDH primitive when used without the cofactor does
    312 * not address small subgroup attacks, which may occur when the
    313 * public key is not valid. These attacks can be prevented by
    314 * validating the public key before using ECDH.
    315 */
    316 SECStatus
    317 EC_ValidatePublicKey(ECParams *ecParams, SECItem *publicValue)
    318 {
    319    if (!ecParams || ecParams->name == ECCurve_noName ||
    320        !publicValue || !publicValue->len) {
    321        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    322        return SECFailure;
    323    }
    324 
    325    /* Uses curve specific code for point validation. */
    326    if (ecParams->fieldID.type != ec_field_plain) {
    327        PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
    328        return SECFailure;
    329    }
    330 
    331    const ECMethod *method = ec_get_method_from_name(ecParams->name);
    332    if (method == NULL || method->pt_validate == NULL) {
    333        /* unknown curve */
    334        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    335        return SECFailure;
    336    }
    337 
    338    SECStatus rv = method->pt_validate(publicValue);
    339    if (rv != SECSuccess) {
    340        PORT_SetError(SEC_ERROR_BAD_KEY);
    341    }
    342    return rv;
    343 }
    344 
    345 /*
    346 ** Performs an ECDH key derivation by computing the scalar point
    347 ** multiplication of privateValue and publicValue (with or without the
    348 ** cofactor) and returns the x-coordinate of the resulting elliptic
    349 ** curve point in derived secret.  If successful, derivedSecret->data
    350 ** is set to the address of the newly allocated buffer containing the
    351 ** derived secret, and derivedSecret->len is the size of the secret
    352 ** produced. It is the caller's responsibility to free the allocated
    353 ** buffer containing the derived secret.
    354 */
    355 SECStatus
    356 ECDH_Derive(SECItem *publicValue,
    357            ECParams *ecParams,
    358            SECItem *privateValue,
    359            PRBool withCofactor,
    360            SECItem *derivedSecret)
    361 {
    362    if (!publicValue || !publicValue->len ||
    363        !ecParams || ecParams->name == ECCurve_noName ||
    364        !privateValue || !privateValue->len || !derivedSecret) {
    365        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    366        return SECFailure;
    367    }
    368 
    369    /*
    370     * Make sure the point is on the requested curve to avoid
    371     * certain small subgroup attacks.
    372     */
    373    if (EC_ValidatePublicKey(ecParams, publicValue) != SECSuccess) {
    374        PORT_SetError(SEC_ERROR_BAD_KEY);
    375        return SECFailure;
    376    }
    377 
    378    /* Perform curve specific multiplication using ECMethod */
    379    if (ecParams->fieldID.type != ec_field_plain) {
    380        PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
    381        return SECFailure;
    382    }
    383 
    384    const ECMethod *method = ec_get_method_from_name(ecParams->name);
    385    if (method == NULL || method->pt_validate == NULL ||
    386        method->pt_mul == NULL) {
    387        PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
    388        return SECFailure;
    389    }
    390 
    391    memset(derivedSecret, 0, sizeof(*derivedSecret));
    392    derivedSecret = SECITEM_AllocItem(NULL, derivedSecret, EC_GetScalarSize(ecParams));
    393    if (derivedSecret == NULL) {
    394        PORT_SetError(SEC_ERROR_NO_MEMORY);
    395        return SECFailure;
    396    }
    397 
    398    SECStatus rv = method->pt_mul(derivedSecret, privateValue, publicValue);
    399    if (rv != SECSuccess) {
    400        PORT_SetError(SEC_ERROR_BAD_KEY);
    401        SECITEM_ZfreeItem(derivedSecret, PR_FALSE);
    402    }
    403    return rv;
    404 }
    405 
    406 /* Computes the ECDSA signature (a concatenation of two values r and s)
    407 * on the digest using the given key and the random value kb (used in
    408 * computing s).
    409 */
    410 
    411 static SECStatus
    412 ec_SignDigestWithSeed(ECPrivateKey *key, SECItem *signature,
    413                      const SECItem *digest, const unsigned char *kb, const int kblen)
    414 {
    415    ECParams *ecParams = NULL;
    416    unsigned olen; /* length in bytes of the base point order */
    417 
    418    /* Check args */
    419    if (!key || !signature || !digest || !kb || (kblen <= 0)) {
    420        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    421        return SECFailure;
    422    }
    423 
    424    ecParams = &(key->ecParams);
    425    olen = ecParams->order.len;
    426    if (signature->data == NULL) {
    427        /* a call to get the signature length only */
    428        signature->len = 2 * olen;
    429        return SECSuccess;
    430    }
    431    if (signature->len < 2 * olen) {
    432        PORT_SetError(SEC_ERROR_OUTPUT_LEN);
    433        return SECFailure;
    434    }
    435 
    436    /* Perform curve specific signature using ECMethod */
    437    if (ecParams->fieldID.type != ec_field_plain) {
    438        PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
    439        return SECFailure;
    440    }
    441 
    442    const ECMethod *method = ec_get_method_from_name(ecParams->name);
    443    if (method == NULL || method->sign_digest == NULL) {
    444        PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
    445        return SECFailure;
    446    }
    447 
    448    SECStatus rv = method->sign_digest(key, signature, digest, kb, kblen);
    449    if (rv != SECSuccess) {
    450        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    451    }
    452 
    453 #if EC_DEBUG
    454    printf("ECDSA signing with seed %s\n",
    455           (rv == SECSuccess) ? "succeeded" : "failed");
    456 #endif
    457    return rv;
    458 }
    459 
    460 SECStatus
    461 ECDSA_SignDigestWithSeed(ECPrivateKey *key, SECItem *signature,
    462                         const SECItem *digest, const unsigned char *kb, const int kblen)
    463 {
    464 #if EC_DEBUG || EC_DOUBLECHECK
    465    SECItem *signature2 = SECITEM_AllocItem(NULL, NULL, signature->len);
    466    SECStatus signSuccess = ec_SignDigestWithSeed(key, signature, digest, kb, kblen);
    467    SECStatus signSuccessDouble = ec_SignDigestWithSeed(key, signature2, digest, kb, kblen);
    468    int signaturesEqual = NSS_SecureMemcmp(signature->data, signature2->data, signature->len);
    469    SECStatus rv;
    470 
    471    if ((signaturesEqual == 0) && (signSuccess == SECSuccess) && (signSuccessDouble == SECSuccess)) {
    472        rv = SECSuccess;
    473    } else {
    474        rv = SECFailure;
    475    }
    476 
    477 #if EC_DEBUG
    478    printf("ECDSA signing with seed %s after signing twice\n", (rv == SECSuccess) ? "succeeded" : "failed");
    479 #endif
    480 
    481    SECITEM_FreeItem(signature2, PR_TRUE);
    482    return rv;
    483 #else
    484    return ec_SignDigestWithSeed(key, signature, digest, kb, kblen);
    485 #endif
    486 }
    487 
    488 /*
    489 ** Computes the ECDSA signature on the digest using the given key
    490 ** and a random seed.
    491 */
    492 SECStatus
    493 ECDSA_SignDigest(ECPrivateKey *key, SECItem *signature, const SECItem *digest)
    494 {
    495    SECItem nonceRand = { siBuffer, NULL, 0 };
    496 
    497    if (!key) {
    498        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    499        return SECFailure;
    500    }
    501 
    502    /* Generate random value k */
    503    SECITEM_AllocItem(NULL, &nonceRand, EC_GetScalarSize(&key->ecParams));
    504    if (nonceRand.data == NULL) {
    505        PORT_SetError(SEC_ERROR_NO_MEMORY);
    506        return SECFailure;
    507    }
    508 
    509    SECStatus rv = ec_GenerateRandomPrivateKey(&key->ecParams, &nonceRand);
    510    if (rv != SECSuccess) {
    511        goto cleanup;
    512    }
    513 
    514    /* Generate ECDSA signature with the specified k value */
    515    rv = ECDSA_SignDigestWithSeed(key, signature, digest, nonceRand.data, nonceRand.len);
    516    NSS_DECLASSIFY(signature->data, signature->len);
    517 
    518 cleanup:
    519    SECITEM_ZfreeItem(&nonceRand, PR_FALSE);
    520 
    521 #if EC_DEBUG
    522    printf("ECDSA signing %s\n",
    523           (rv == SECSuccess) ? "succeeded" : "failed");
    524 #endif
    525 
    526    return rv;
    527 }
    528 
    529 /*
    530 ** Checks the signature on the given digest using the key provided.
    531 **
    532 ** The key argument must represent a valid EC public key (a point on
    533 ** the relevant curve).  If it is not a valid point, then the behavior
    534 ** of this function is undefined.  In cases where a public key might
    535 ** not be valid, use EC_ValidatePublicKey to check.
    536 */
    537 SECStatus
    538 ECDSA_VerifyDigest(ECPublicKey *key, const SECItem *signature,
    539                   const SECItem *digest)
    540 {
    541    SECStatus rv = SECFailure;
    542    ECParams *ecParams = NULL;
    543 
    544    /* Check args */
    545    if (!key || !signature || !digest) {
    546        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    547        return SECFailure;
    548    }
    549 
    550    ecParams = &(key->ecParams);
    551 
    552    /* Perform curve specific signature verification using ECMethod */
    553    if (ecParams->fieldID.type != ec_field_plain) {
    554        PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
    555        return SECFailure;
    556    }
    557 
    558    const ECMethod *method = ec_get_method_from_name(ecParams->name);
    559    if (method == NULL || method->verify_digest == NULL) {
    560        PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
    561        return SECFailure;
    562    }
    563 
    564    rv = method->verify_digest(key, signature, digest);
    565    if (rv != SECSuccess) {
    566        PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
    567    }
    568 
    569 #if EC_DEBUG
    570    printf("ECDSA verification %s\n",
    571           (rv == SECSuccess) ? "succeeded" : "failed");
    572 #endif
    573 
    574    return rv;
    575 }
    576 
    577 /*EdDSA: Currently only Ed22519 is implemented.*/
    578 
    579 /*
    580 ** Computes the EdDSA signature on the message using the given key.
    581 */
    582 
    583 SECStatus
    584 ec_ED25519_public_key_validate(const ECPublicKey *key)
    585 {
    586    if (!key || !(key->ecParams.name == ECCurve_Ed25519)) {
    587        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    588        return SECFailure;
    589    }
    590    return ec_ED25519_pt_validate(&key->publicValue);
    591 }
    592 
    593 SECStatus
    594 ec_ED25519_private_key_validate(const ECPrivateKey *key)
    595 {
    596    if (!key || !(key->ecParams.name == ECCurve_Ed25519)) {
    597 
    598        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    599        return SECFailure;
    600    }
    601    return ec_ED25519_scalar_validate(&key->privateValue);
    602 }
    603 
    604 SECStatus
    605 ED_SignMessage(ECPrivateKey *key, SECItem *signature, const SECItem *msg)
    606 {
    607    if (!msg || !signature || signature->len != Ed25519_SIGN_LEN) {
    608        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    609        return SECFailure;
    610    }
    611 
    612    if (ec_ED25519_private_key_validate(key) != SECSuccess) {
    613        return SECFailure; /* error code set by ec_ED25519_scalar_validate. */
    614    }
    615 
    616    if (signature->data) {
    617        Hacl_Ed25519_sign(signature->data, key->privateValue.data, msg->len,
    618                          msg->data);
    619    }
    620    signature->len = ED25519_SIGN_LEN;
    621    BLAPI_CLEAR_STACK(2048);
    622    return SECSuccess;
    623 }
    624 
    625 /*
    626 ** Checks the signature on the given message using the key provided.
    627 */
    628 
    629 SECStatus
    630 ED_VerifyMessage(ECPublicKey *key, const SECItem *signature,
    631                 const SECItem *msg)
    632 {
    633    if (!msg || !signature || !signature->data || signature->len != Ed25519_SIGN_LEN) {
    634        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    635        return SECFailure;
    636    }
    637 
    638    if (ec_ED25519_public_key_validate(key) != SECSuccess) {
    639        return SECFailure; /* error code set by ec_ED25519_pt_validate. */
    640    }
    641 
    642    bool rv = Hacl_Ed25519_verify(key->publicValue.data, msg->len, msg->data,
    643                                  signature->data);
    644    BLAPI_CLEAR_STACK(2048);
    645 
    646 #if EC_DEBUG
    647    printf("ED_VerifyMessage returning %s\n",
    648           (rv) ? "success" : "failure");
    649 #endif
    650 
    651    if (rv) {
    652        return SECSuccess;
    653    }
    654 
    655    PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
    656    return SECFailure;
    657 }
    658 
    659 SECStatus
    660 ED_DerivePublicKey(const SECItem *privateKey, SECItem *publicKey)
    661 {
    662    /* Currently supporting only Ed25519.*/
    663    if (!privateKey || privateKey->len == 0 || !publicKey || publicKey->len != Ed25519_PUBLIC_KEYLEN) {
    664        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    665        return SECFailure;
    666    }
    667 
    668    if (ec_ED25519_scalar_validate(privateKey) != SECSuccess) {
    669        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    670        return SECFailure;
    671    }
    672 
    673    Hacl_Ed25519_secret_to_public(publicKey->data, privateKey->data);
    674    return SECSuccess;
    675 }
    676 
    677 SECStatus
    678 X25519_DerivePublicKey(const SECItem *privateKey, SECItem *publicKey)
    679 {
    680    SECStatus rv = SECFailure;
    681    /* Currently supporting only X25519.*/
    682    if (!privateKey || privateKey->len == 0 || !publicKey || publicKey->len != X25519_PUBLIC_KEYLEN) {
    683        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    684        return SECFailure;
    685    }
    686 
    687    const ECMethod *method = ec_get_method_from_name(ECCurve25519);
    688    if (method == NULL || method->pt_mul == NULL) {
    689        PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
    690        return SECFailure;
    691    }
    692 
    693    rv = method->pt_mul(publicKey, (SECItem *)privateKey, NULL);
    694    return rv;
    695 }
    696 
    697 SECStatus
    698 EC_DerivePublicKey(const SECItem *privateKey, const ECParams *ecParams, SECItem *publicKey)
    699 {
    700    if (!privateKey || privateKey->len == 0 || !publicKey || publicKey->len != EC_GetPointSize(ecParams)) {
    701        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    702        return SECFailure;
    703    }
    704 
    705    const ECMethod *method = ec_get_method_from_name(ecParams->name);
    706    if (method == NULL || method->pt_mul == NULL) {
    707        PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
    708        return SECFailure;
    709    }
    710 
    711    return method->pt_mul(publicKey, (SECItem *)privateKey, NULL);
    712 }
    713 
    714 /* Supported only for P-256, P-384 and P-521*/
    715 SECStatus
    716 EC_DecompressPublicKey(const SECItem *publicCompressed, const ECParams *ecParams, SECItem *publicUncompressed)
    717 {
    718    /* I don't think that we need a special ECMethod extension for decompression. */
    719    switch (ecParams->name) {
    720        case ECCurve_NIST_P256:
    721            return ec_secp256r1_decompress(publicCompressed, publicUncompressed);
    722        case ECCurve_NIST_P384:
    723            return ec_secp384r1_decompress(publicCompressed, publicUncompressed);
    724        case ECCurve_NIST_P521:
    725            return ec_secp521r1_decompress(publicCompressed, publicUncompressed);
    726        default:
    727            PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
    728            return SECFailure;
    729    }
    730 }