diff --git a/src/pk.c b/src/pk.c index b35280dd3..7608b732e 100644 --- a/src/pk.c +++ b/src/pk.c @@ -11915,7 +11915,34 @@ int wolfSSL_EC_KEY_LoadDer_ex(WOLFSSL_EC_KEY* key, const unsigned char* derBuf, } else { ret = wc_EccPublicKeyDecode(derBuf, &idx, (ecc_key*)key->internal, - derSz); + derSz); + if (ret < 0) { + ecc_key *tmp = (ecc_key*)XMALLOC(sizeof(ecc_key), + ((ecc_key*)key->internal)->heap, DYNAMIC_TYPE_ECC); + if (tmp == NULL) { + ret = -1; + } + else { + /* We now try again as x.963 [point type][x][opt y]. */ + ret = wc_ecc_init_ex(tmp, ((ecc_key*)key->internal)->heap, + INVALID_DEVID); + if (ret == 0) { + ret = wc_ecc_import_x963(derBuf, derSz, tmp); + if (ret == 0) { + /* Take ownership of new key - set tmp to the old + * key which will then be freed below. */ + ecc_key *old = (ecc_key *)key->internal; + key->internal = tmp; + tmp = old; + + idx = derSz; + } + wc_ecc_free(tmp); + } + XFREE(tmp, ((ecc_key*)key->internal)->heap, + DYNAMIC_TYPE_ECC); + } + } } if (ret < 0) { /* Error returned from wolfSSL. */ diff --git a/src/ssl.c b/src/ssl.c index ed77ed676..c66243fd8 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -23150,9 +23150,18 @@ int wolfSSL_i2d_PublicKey(const WOLFSSL_EVP_PKEY *key, unsigned char **der) * might be a buffereed private key so we need to decode it and then encode * the public part. */ if (ret == 0) { - local_derSz = wolfSSL_EVP_PKEY_get_der(key, &local_der); - if (local_derSz <= 0) { - ret = WOLFSSL_FATAL_ERROR; + ret = wolfSSL_EVP_PKEY_get_der(key, &local_der); + if (ret <= 0) { + /* In this case, there was no buffered DER at all. This could be the + * case where the key that was passed in was generated. So now we + * have to create the local DER. */ + local_derSz = wolfSSL_i2d_ECPrivateKey(key->ecc, &local_der); + if (local_derSz == 0) { + ret = WOLFSSL_FATAL_ERROR; + } + } else { + local_derSz = ret; + ret = 0; } } @@ -23170,6 +23179,10 @@ int wolfSSL_i2d_PublicKey(const WOLFSSL_EVP_PKEY *key, unsigned char **der) if (ret == 0) { ret = wc_EccPublicKeyDecode(local_der, &inOutIdx, eccKey, local_derSz); + if (ret < 0) { + /* We now try again as x.963 [point type][x][opt y]. */ + ret = wc_ecc_import_x963(local_der, local_derSz, eccKey); + } } if (ret == 0) { diff --git a/tests/api.c b/tests/api.c index e863f4ddb..4af2e85c2 100644 --- a/tests/api.c +++ b/tests/api.c @@ -47384,6 +47384,64 @@ static int test_wolfSSL_d2i_and_i2d_PublicKey(void) return res; } +static int test_wolfSSL_d2i_and_i2d_PublicKey_ecc(void) +{ + int res = TEST_SKIPPED; +#if defined(OPENSSL_EXTRA) && defined(HAVE_ECC) && !defined(NO_CERTS) && \ + !defined(NO_ASN) && !defined(NO_PWDBASED) + EVP_PKEY* pkey; + const unsigned char* p; + unsigned char *der = NULL, *tmp = NULL; + int derLen; + unsigned char pub_buf[65]; + const int pub_len = 65; + BN_CTX * ctx; + EC_GROUP * curve; + EC_KEY * ephemeral_key; + const EC_POINT * h; + + /* Generate an x963 key pair and get public part into pub_buf */ + AssertNotNull(ctx = BN_CTX_new()); + AssertNotNull(curve = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1)); + AssertNotNull(ephemeral_key = EC_KEY_new_by_curve_name( + NID_X9_62_prime256v1)); + AssertIntEQ(EC_KEY_generate_key(ephemeral_key), 1); + AssertNotNull(h = EC_KEY_get0_public_key(ephemeral_key)); + AssertIntEQ(pub_len, EC_POINT_point2oct(curve, h, + POINT_CONVERSION_UNCOMPRESSED, + pub_buf, pub_len, ctx)); + /* Prepare the EVP_PKEY */ + AssertNotNull(pkey = EVP_PKEY_new()); + + p = pub_buf; + /* Check that key can be successfully decoded. */ + AssertNotNull(wolfSSL_d2i_PublicKey(EVP_PKEY_EC, &pkey, &p, + pub_len)); + + /* Check that key can be successfully encoded. */ + AssertIntGE((derLen = wolfSSL_i2d_PublicKey(pkey, &der)), 0); + /* Ensure that the encoded version matches the original. */ + AssertIntEQ(derLen, pub_len); + AssertIntEQ(XMEMCMP(der, pub_buf, derLen), 0); + + /* Do same test except with pre-allocated buffer to ensure the der pointer + * is advanced. */ + tmp = der; + AssertIntGE((derLen = wolfSSL_i2d_PublicKey(pkey, &tmp)), 0); + AssertIntEQ(derLen, pub_len); + AssertIntEQ(XMEMCMP(der, pub_buf, derLen), 0); + AssertTrue(der + derLen == tmp); + + XFREE(der, HEAP_HINT, DYNAMIC_TYPE_OPENSSL); + EVP_PKEY_free(pkey); + EC_KEY_free(ephemeral_key); + EC_GROUP_free(curve); + + res = TEST_RES_CHECK(1); +#endif + return res; +} + static int test_wolfSSL_d2i_and_i2d_DSAparams(void) { int res = TEST_SKIPPED; @@ -62255,6 +62313,7 @@ TEST_CASE testCases[] = { TEST_DECL(test_wolfSSL_PKEY_up_ref), TEST_DECL(test_wolfSSL_EVP_Cipher_extra), TEST_DECL(test_wolfSSL_d2i_and_i2d_PublicKey), + TEST_DECL(test_wolfSSL_d2i_and_i2d_PublicKey_ecc), TEST_DECL(test_wolfSSL_d2i_and_i2d_DSAparams), TEST_DECL(test_wolfSSL_i2d_PrivateKey), TEST_DECL(test_wolfSSL_OCSP_id_get0_info),