diff options
Diffstat (limited to '')
-rw-r--r-- | security/nss/lib/freebl/ecl/ecp_secp256r1.c | 258 |
1 files changed, 258 insertions, 0 deletions
diff --git a/security/nss/lib/freebl/ecl/ecp_secp256r1.c b/security/nss/lib/freebl/ecl/ecp_secp256r1.c new file mode 100644 index 0000000000..044f6a7a1a --- /dev/null +++ b/security/nss/lib/freebl/ecl/ecp_secp256r1.c @@ -0,0 +1,258 @@ +/* P-256 from HACL* */ + +#ifdef FREEBL_NO_DEPEND +#include "../stubs.h" +#endif + +#include "ecl-priv.h" +#include "secitem.h" +#include "secerr.h" +#include "secmpi.h" +#include "../verified/Hacl_P256.h" + +/* + * Point Validation for P-256. + */ + +SECStatus +ec_secp256r1_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 != 65) { + 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_P256_validate_public_key(pt->data + 1); + + if (!b) { + PORT_SetError(SEC_ERROR_BAD_KEY); + res = SECFailure; + } + return res; +} + +/* + * Scalar Validation for P-256. + */ + +SECStatus +ec_secp256r1_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 != 32) { + PORT_SetError(SEC_ERROR_BAD_KEY); + res = SECFailure; + return res; + } + + bool b = Hacl_P256_validate_private_key(scalar->data); + + if (!b) { + PORT_SetError(SEC_ERROR_BAD_KEY); + res = SECFailure; + } + return res; +} + +/* + * Scalar multiplication for P-256. + * If P == NULL, the base point is used. + * Returns X = k*P + */ + +SECStatus +ec_secp256r1_pt_mul(SECItem *X, SECItem *k, SECItem *P) +{ + SECStatus res = SECSuccess; + if (!P) { + uint8_t derived[64] = { 0 }; + + if (!X || !k || !X->data || !k->data || + X->len < 65 || k->len != 32) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + res = SECFailure; + return res; + } + + bool b = Hacl_P256_dh_initiator(derived, k->data); + + if (!b) { + PORT_SetError(SEC_ERROR_BAD_KEY); + res = SECFailure; + return res; + } + + X->len = 65; + X->data[0] = EC_POINT_FORM_UNCOMPRESSED; + memcpy(X->data + 1, derived, 64); + + } else { + uint8_t full_key[32] = { 0 }; + uint8_t *key; + uint8_t derived[64] = { 0 }; + + if (!X || !k || !P || !X->data || !k->data || !P->data || + X->len < 32 || P->len != 65 || + P->data[0] != EC_POINT_FORM_UNCOMPRESSED) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + res = SECFailure; + return res; + } + + /* We consider keys of up to size 32, or of size 33 with a single leading 0 */ + if (k->len < 32) { + memcpy(full_key + 32 - k->len, k->data, k->len); + key = full_key; + } else if (k->len == 32) { + key = k->data; + } else if (k->len == 33 && k->data[0] == 0) { + key = k->data + 1; + } else { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + res = SECFailure; + return res; + } + + bool b = Hacl_P256_dh_responder(derived, P->data + 1, key); + + if (!b) { + PORT_SetError(SEC_ERROR_BAD_KEY); + res = SECFailure; + return res; + } + + X->len = 32; + memcpy(X->data, derived, 32); + } + + return res; +} + +/* + * ECDSA Signature for P-256 + */ + +SECStatus +ec_secp256r1_sign_digest(ECPrivateKey *key, SECItem *signature, + const SECItem *digest, const unsigned char *kb, + const unsigned int kblen) +{ + SECStatus res = SECSuccess; + + if (!key || !signature || !digest || !kb || + !key->privateValue.data || + !signature->data || !digest->data || + key->ecParams.name != ECCurve_NIST_P256) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + res = SECFailure; + return res; + } + + if (key->privateValue.len != 32 || + kblen == 0 || + digest->len == 0 || + signature->len < 64) { + PORT_SetError(SEC_ERROR_INPUT_LEN); + res = SECFailure; + return res; + } + + uint8_t hash[32] = { 0 }; + if (digest->len < 32) { + memcpy(hash + 32 - digest->len, digest->data, digest->len); + } else { + memcpy(hash, digest->data, 32); + } + + uint8_t nonce[32] = { 0 }; + if (kblen < 32) { + memcpy(nonce + 32 - kblen, kb, kblen); + } else { + memcpy(nonce, kb, 32); + } + + bool b = Hacl_P256_ecdsa_sign_p256_without_hash( + signature->data, 32, hash, + key->privateValue.data, nonce); + if (!b) { + PORT_SetError(SEC_ERROR_BAD_KEY); + res = SECFailure; + return res; + } + + signature->len = 64; + return res; +} + +/* + * ECDSA Signature Verification for P-256 + */ + +SECStatus +ec_secp256r1_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_P256) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + res = SECFailure; + return res; + } + + if (key->publicValue.len != 65 || + digest->len == 0 || + signature->len != 64) { + 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; + } + + uint8_t hash[32] = { 0 }; + if (digest->len < 32) { + memcpy(hash + 32 - digest->len, digest->data, digest->len); + } else { + memcpy(hash, digest->data, 32); + } + + bool b = Hacl_P256_ecdsa_verif_without_hash( + 32, hash, + key->publicValue.data + 1, + signature->data, signature->data + 32); + if (!b) { + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); + res = SECFailure; + return res; + } + + return res; +} |