/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifdef FREEBL_NO_DEPEND #include "../stubs.h" #endif #include "ecl-priv.h" #include "secitem.h" #include "secerr.h" #include "secmpi.h" #include "../verified/Hacl_P521.h" /* * Point Validation for P-521. */ SECStatus ec_secp521r1_pt_validate(const SECItem *pt) { SECStatus res = SECSuccess; if (!pt || !pt->data) { PORT_SetError(SEC_ERROR_INVALID_ARGS); res = SECFailure; return res; } if (pt->len != 133) { PORT_SetError(SEC_ERROR_BAD_KEY); res = SECFailure; return res; } if (pt->data[0] != EC_POINT_FORM_UNCOMPRESSED) { PORT_SetError(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM); res = SECFailure; return res; } bool b = Hacl_P521_validate_public_key(pt->data + 1); if (!b) { PORT_SetError(SEC_ERROR_BAD_KEY); res = SECFailure; } return res; } /* * Scalar Validation for P-521. */ SECStatus ec_secp521r1_scalar_validate(const SECItem *scalar) { SECStatus res = SECSuccess; if (!scalar || !scalar->data) { PORT_SetError(SEC_ERROR_INVALID_ARGS); res = SECFailure; return res; } if (scalar->len != 66) { PORT_SetError(SEC_ERROR_BAD_KEY); res = SECFailure; return res; } bool b = Hacl_P521_validate_private_key(scalar->data); if (!b) { PORT_SetError(SEC_ERROR_BAD_KEY); res = SECFailure; } return res; } /* * Scalar multiplication for P-521. * If P == NULL, the base point is used. * Returns X = k*P */ SECStatus ec_secp521r1_pt_mul(SECItem *X, SECItem *k, SECItem *P) { SECStatus res = SECSuccess; if (!P) { uint8_t derived[132] = { 0 }; if (!X || !k || !X->data || !k->data || X->len < 133 || k->len != 66) { PORT_SetError(SEC_ERROR_INVALID_ARGS); res = SECFailure; return res; } bool b = Hacl_P521_dh_initiator(derived, k->data); if (!b) { PORT_SetError(SEC_ERROR_BAD_KEY); res = SECFailure; return res; } X->len = 133; X->data[0] = EC_POINT_FORM_UNCOMPRESSED; memcpy(X->data + 1, derived, 132); } else { uint8_t full_key[66] = { 0 }; uint8_t *key; uint8_t derived[132] = { 0 }; if (!X || !k || !P || !X->data || !k->data || !P->data || X->len < 66 || P->len != 133 || P->data[0] != EC_POINT_FORM_UNCOMPRESSED) { PORT_SetError(SEC_ERROR_INVALID_ARGS); res = SECFailure; return res; } /* We consider keys of up to size 66, or of size 67 with a single leading 0 */ if (k->len < 66) { memcpy(full_key + 66 - k->len, k->data, k->len); key = full_key; } else if (k->len == 66) { key = k->data; } else if (k->len == 67 && k->data[0] == 0) { key = k->data + 1; } else { PORT_SetError(SEC_ERROR_INVALID_ARGS); res = SECFailure; return res; } bool b = Hacl_P521_dh_responder(derived, P->data + 1, key); if (!b) { PORT_SetError(SEC_ERROR_BAD_KEY); res = SECFailure; return res; } X->len = 66; memcpy(X->data, derived, 66); } return res; } /* * ECDSA Signature for P-521 */ SECStatus ec_secp521r1_sign_digest(ECPrivateKey *ecPrivKey, SECItem *signature, const SECItem *digest, const unsigned char *kb, const unsigned int kblen) { SECStatus res = SECSuccess; if (!ecPrivKey || !signature || !digest || !kb || !ecPrivKey->privateValue.data || !signature->data || !digest->data || ecPrivKey->ecParams.name != ECCurve_NIST_P521) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } if (kblen == 0 || digest->len == 0 || signature->len < 132) { PORT_SetError(SEC_ERROR_INPUT_LEN); return SECFailure; } // Private keys should be 66 bytes, but some software trims leading zeros, // and some software produces 67 byte keys with a leading zero. We'll // accept these variants. uint8_t padded_key_data[66] = { 0 }; uint8_t *key; SECItem *privKey = &ecPrivKey->privateValue; if (privKey->len == 66) { key = privKey->data; } else if (privKey->len == 67 && privKey->data[0] == 0) { key = privKey->data + 1; } else if (privKey->len < 66) { memcpy(padded_key_data + 66 - privKey->len, privKey->data, privKey->len); key = padded_key_data; } else { PORT_SetError(SEC_ERROR_INPUT_LEN); return SECFailure; } uint8_t hash[66] = { 0 }; if (digest->len < 66) { memcpy(hash + 66 - digest->len, digest->data, digest->len); } else { // SEC 1 takes the most significant ceil(log(n)) bits of hash output when the hash output is longer than log(n). hash[0] = digest->data[0] >> 7; for (size_t i = 1; i < 66; i++) { hash[i] = (digest->data[i - 1] << 1) | (digest->data[i] >> 7); } } uint8_t nonce[66] = { 0 }; if (kblen < 66) { memcpy(nonce + 66 - kblen, kb, kblen); } else { memcpy(nonce, kb, 66); } bool b = Hacl_P521_ecdsa_sign_p521_without_hash( signature->data, 66, hash, key, nonce); if (!b) { PORT_SetError(SEC_ERROR_BAD_KEY); res = SECFailure; return res; } signature->len = 132; return res; } /* * ECDSA Signature Verification for P-521 */ SECStatus ec_secp521r1_verify_digest(ECPublicKey *key, const SECItem *signature, const SECItem *digest) { SECStatus res = SECSuccess; if (!key || !signature || !digest || !key->publicValue.data || !signature->data || !digest->data || key->ecParams.name != ECCurve_NIST_P521) { PORT_SetError(SEC_ERROR_INVALID_ARGS); res = SECFailure; return res; } if (signature->len == 0 || signature->len % 2 != 0 || signature->len > 132 || digest->len == 0 || key->publicValue.len != 133) { PORT_SetError(SEC_ERROR_INPUT_LEN); res = SECFailure; return res; } if (key->publicValue.data[0] != EC_POINT_FORM_UNCOMPRESSED) { PORT_SetError(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM); res = SECFailure; return res; } // Signatures should be 132 bytes, but some software produces short signatures. // Pad components with zeros if necessary. uint8_t paddedSigData[132] = { 0 }; uint8_t *sig; if (signature->len != 132) { size_t split = signature->len / 2; memcpy(paddedSigData + 66 - split, signature->data, split); memcpy(paddedSigData + 132 - split, signature->data + split, split); sig = paddedSigData; } else { sig = signature->data; } uint8_t hash[66] = { 0 }; if (digest->len < 66) { memcpy(hash + 66 - digest->len, digest->data, digest->len); } else { // SEC 1 takes the most significant ceil(log(n)) bits of hash output when the hash output is longer than log(n). hash[0] = digest->data[0] >> 7; for (size_t i = 1; i < 66; i++) { hash[i] = (digest->data[i - 1] << 1) | (digest->data[i] >> 7); } } bool b = Hacl_P521_ecdsa_verif_without_hash( 66, hash, key->publicValue.data + 1, sig, sig + 66); if (!b) { PORT_SetError(SEC_ERROR_BAD_SIGNATURE); res = SECFailure; return res; } return res; }