Yubico / libfido2

Provides library functionality for FIDO2, including communication with a device over USB or NFC.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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!