es256_pk_from_EC_KEY doesn't support coordinates using less than 32 bytes
agalluzzi-cybele opened this issue · comments
When key is ES256, public key cbor map stores coordinates as 32 bytes values. In order to create an es256_pk_t I was loading an EC_KEY storing parameters readed from public key cbor map in BN values which will be later loaded in EC_KEY using OpenSSL methods:
BN_bin2bn(cbor_bytestring_handle(pkMap[i].value), cbor_bytestring_length(pkMap[i].value), x);
I had an issue when one of the coordinates was less than 32 bytes long, for example, because there was a leading zero. In my case, cbor_bytestring_handle(pkMap[i].value)
for key -2 was:
[0]: 0 '\0'
[1]: 51 '3'
[2]: 196 'Ä'
[3]: 103 'g'
[4]: 59 ';'
[5]: 13 '\r'
[6]: 77 'M'
[7]: 116 't'
[8]: 255 'ÿ'
[9]: 207 'Ï'
[10]: 208 'Ð'
[11]: 143 '�'
[12]: 131 'ƒ'
[13]: 229 'å'
[14]: 58 ':'
[15]: 129 '�'
[16]: 26 '\x1a'
[17]: 171 '«'
[18]: 91 '['
[19]: 90 'Z'
[20]: 226 'â'
[21]: 63 '?'
[22]: 59 ';'
[23]: 117 'u'
[24]: 109 'm'
[25]: 51 '3'
[26]: 60 '<'
[27]: 173 ''
[28]: 21 '\x15'
[29]: 178 '²'
[30]: 89 'Y'
[31]: 29 '\x1d'
After loading the value in the EC_KEY, I was calling
es256_pk_t* npk = es256_pk_new();
es256_pk_from_EC_KEY(npk, ec);
When inspecting npk->x
there was no leading zero, and that changed all the curve and validation failed. In order to fix that I had to change es256_pk_from_EC_KEY to offset BN_bn2bin to the right location:
int
es256_pk_from_EC_KEY(es256_pk_t *pk, const EC_KEY *ec)
{
BN_CTX *bnctx = NULL;
BIGNUM *x = NULL;
BIGNUM *y = NULL;
const EC_POINT *q = NULL;
const EC_GROUP *g = NULL;
int ok = FIDO_ERR_INTERNAL;
int n;
if ((q = EC_KEY_get0_public_key(ec)) == NULL ||
(g = EC_KEY_get0_group(ec)) == NULL ||
(bnctx = BN_CTX_new()) == NULL)
goto fail;
BN_CTX_start(bnctx);
if ((x = BN_CTX_get(bnctx)) == NULL ||
(y = BN_CTX_get(bnctx)) == NULL)
goto fail;
if (EC_POINT_get_affine_coordinates_GFp(g, q, x, y, bnctx) == 0 ||
(n = BN_num_bytes(x)) < 0 || (size_t)n > sizeof(pk->x) ||
(n = BN_num_bytes(y)) < 0 || (size_t)n > sizeof(pk->y)) {
fido_log_debug("%s: EC_POINT_get_affine_coordinates_GFp",
__func__);
goto fail;
}
if ((n = BN_bn2bin(x, pk->x+(sizeof(pk->x)-BN_num_bytes(x)))) < 0 || (size_t)n > sizeof(pk->x) ||
(n = BN_bn2bin(y, pk->y+(sizeof(pk->y)-BN_num_bytes(y)))) < 0 || (size_t)n > sizeof(pk->y)) {
fido_log_debug("%s: BN_bn2bin", __func__);
goto fail;
}
ok = FIDO_OK;
fail:
if (bnctx != NULL) {
BN_CTX_end(bnctx);
BN_CTX_free(bnctx);
}
return (ok);
}
@agalluzzi-cybele Thank you for the report!