/* * LITLS -- ECDSA P-256 wrapper over BearSSL */ #include "bearssl/inner.h" #include "litls.h" int litls_p256_keygen(uint8_t private_key[32], uint8_t public_key[65]) { br_ec_private_key sk; br_ec_public_key pk; size_t pub_len; /* * Generate random 32-byte private key. * The key must be in [1, n-1] where n is the P-256 order. * We generate random bytes and validate by attempting to compute * the public key; BearSSL's mulgen will fail (return 0) if the * scalar is invalid. */ for (int attempts = 0; attempts < 64; attempts++) { if (litls_random_bytes(private_key, 32) != 0) return -1; /* Reject the zero scalar */ uint8_t acc = 0; for (int i = 0; i < 32; i++) acc |= private_key[i]; if (acc == 0) continue; sk.curve = BR_EC_secp256r1; sk.x = private_key; sk.xlen = 32; pub_len = br_ec_compute_pub(&br_ec_p256_m15, &pk, public_key, &sk); if (pub_len == 65) return 0; } return -1; } int litls_p256_ecdsa_sign(const uint8_t *hash, size_t hash_len, const uint8_t private_key[32], uint8_t *sig, size_t *sig_len) { br_ec_private_key sk; size_t ret; /* br_ecdsa_i15_sign_raw derives the hash length from the SHA-256 vtable * and unconditionally reads 32 bytes from `hash`. Reject any other length * so a short buffer cannot cause an out-of-bounds read. */ if (hash_len != 32) return -1; sk.curve = BR_EC_secp256r1; sk.x = (unsigned char *)private_key; sk.xlen = 32; /* * br_ecdsa_i15_sign_raw uses RFC 6979 deterministic k via HMAC-DRBG. * The hash function vtable is used for: * 1) Getting hash output length via BR_HASHDESC_OUT * 2) HMAC-DRBG seeding * Returns the signature length (64 for P-256), or 0 on error. */ ret = br_ecdsa_i15_sign_raw(&br_ec_p256_m15, &br_sha256_vtable, hash, &sk, sig); if (ret == 0) return -1; *sig_len = ret; return 0; } int litls_p256_ecdsa_verify(const uint8_t *hash, size_t hash_len, const uint8_t public_key[65], const uint8_t *sig, size_t sig_len) { br_ec_public_key pk; uint32_t ret; pk.curve = BR_EC_secp256r1; pk.q = (unsigned char *)public_key; pk.qlen = 65; ret = br_ecdsa_i15_vrfy_raw(&br_ec_p256_m15, hash, hash_len, &pk, sig, sig_len); return ret ? 0 : -1; }