Skip to content

Commit

Permalink
Marshalling/Unmarshalling DH public keys (aws#1916)
Browse files Browse the repository at this point in the history
### Issues:
Addresses: CryptoAlg-2696

### Description of changes: 
* Support marshalling/unmarshalling of DH public keys.

### Testing:
Added test `DHTest.DHMarshalPubKey`

By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache 2.0 license and the ISC license.
  • Loading branch information
justsmth authored Oct 18, 2024
1 parent f815a93 commit f3df19d
Show file tree
Hide file tree
Showing 5 changed files with 186 additions and 5 deletions.
107 changes: 107 additions & 0 deletions crypto/dh_extra/dh_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1051,3 +1051,110 @@ TEST(DHTest, DHCheckForStandardParams) {
ASSERT_TRUE(DH_check(dh2.get(), &flags));
EXPECT_EQ(flags, 0);
}

TEST(DHTest, DHMarshalPubKey) {
const char* dh512_pem =
"-----BEGIN DH PARAMETERS-----\n"
"MEYCQQDqvLe5oX3p+Dw8T7NWG7nlWVFK58Ev74xvxYH72DC4kqfPEFPvNnCpFoRB\n"
"RdxOz7DZ6JO/GxobSRyAAI766+GDAgEC\n"
"-----END DH PARAMETERS-----";
const uint64_t encoded_g = 2;
const char encoded_p_dec_str[] = "12294183602774786812319504504704470077603616440910559765086569005477513835495488680341310019770549315448633656928525381740662262980129138358936697450520963";

bssl::UniquePtr<EVP_PKEY> epkey_dh_params(nullptr);
{
const size_t pem_len = OPENSSL_strnlen(dh512_pem, 1024);
bssl::UniquePtr<BIO> in_bio(BIO_new_mem_buf(dh512_pem, pem_len));
ASSERT_TRUE(in_bio);

epkey_dh_params.reset(PEM_read_bio_Parameters(in_bio.get(), nullptr));
ASSERT_TRUE(epkey_dh_params);
}

// Sanity check the Param parsing
{
DH *dh_params = EVP_PKEY_get0_DH(epkey_dh_params.get());
const BIGNUM *p = DH_get0_p(dh_params);
const BIGNUM *g = DH_get0_g(dh_params);
uint64_t parsed_g = 0;
ASSERT_TRUE(BN_get_u64(g, &parsed_g));
ASSERT_EQ(parsed_g, encoded_g);
const char *parsed_p_dec_str = BN_bn2dec(p);
ASSERT_NE(parsed_p_dec_str, nullptr);
ASSERT_EQ(OPENSSL_strcasecmp(encoded_p_dec_str, parsed_p_dec_str), 0);
OPENSSL_free((void *)parsed_p_dec_str);
}

// Perform keygen operation
bssl::UniquePtr<EVP_PKEY> gen_dh(nullptr);
{
bssl::UniquePtr<EVP_PKEY_CTX> epkey_ctx(
EVP_PKEY_CTX_new(epkey_dh_params.get(), nullptr));
ASSERT_TRUE(epkey_ctx);

ASSERT_TRUE(EVP_PKEY_keygen_init(epkey_ctx.get()));
EVP_PKEY *gen_dh_raw = nullptr;
ASSERT_TRUE(EVP_PKEY_keygen(epkey_ctx.get(), &gen_dh_raw));
gen_dh.reset(gen_dh_raw);
ASSERT_TRUE(gen_dh);
}

// Marshall pubkey to der
const uint8_t* pubkey_der = NULL;
size_t pubkey_der_len = 0;
{
bssl::UniquePtr<BIO> out_bio(BIO_new(BIO_s_mem()));
ASSERT_TRUE(out_bio);
ASSERT_TRUE(i2d_PUBKEY_bio(out_bio.get(), gen_dh.get()));
ASSERT_TRUE(BIO_flush(out_bio.get()));
ASSERT_TRUE(BIO_mem_contents(out_bio.get(), &pubkey_der, &pubkey_der_len));
ASSERT_GT(pubkey_der_len, (size_t)0);
ASSERT_NE(pubkey_der, nullptr);
// We own the allocation after this
pubkey_der = (const uint8_t*)OPENSSL_memdup(pubkey_der, pubkey_der_len);
}

// Parse der to pubkey
bssl::UniquePtr<EVP_PKEY> parsed_der_pubkey(nullptr);
{
bssl::UniquePtr<BIO> in_bio(BIO_new_mem_buf(pubkey_der, pubkey_der_len));
ASSERT_TRUE(in_bio);
EVP_PKEY* parsed_dh_pubkey_raw = nullptr;
ASSERT_TRUE(d2i_PUBKEY_bio(in_bio.get(), &parsed_dh_pubkey_raw));
parsed_der_pubkey.reset(parsed_dh_pubkey_raw);
ASSERT_TRUE(parsed_der_pubkey);
}

ASSERT_TRUE(EVP_PKEY_cmp(gen_dh.get(), parsed_der_pubkey.get()));

// Marshall pubkey to PEM
const uint8_t* pubkey_pem = NULL;
size_t pubkey_pem_len = 0;
{
bssl::UniquePtr<BIO> out_bio(BIO_new(BIO_s_mem()));
ASSERT_TRUE(out_bio);
ASSERT_TRUE(PEM_write_bio_PUBKEY(out_bio.get(), gen_dh.get()));
ASSERT_TRUE(BIO_flush(out_bio.get()));
ASSERT_TRUE(BIO_mem_contents(out_bio.get(), &pubkey_pem, &pubkey_pem_len));
ASSERT_GT(pubkey_pem_len, (size_t)0);
ASSERT_TRUE(pubkey_pem);
// We own the allocation after this
pubkey_pem = (const uint8_t*)OPENSSL_memdup(pubkey_pem, pubkey_pem_len);
}

// Parse PEM to pubkey
bssl::UniquePtr<EVP_PKEY> parsed_pem_pubkey(nullptr);
{
bssl::UniquePtr<BIO> in_bio(BIO_new_mem_buf(pubkey_pem, pubkey_pem_len));
ASSERT_TRUE(in_bio);
EVP_PKEY* pem_pubkey_raw = NULL;
ASSERT_TRUE(PEM_read_bio_PUBKEY(in_bio.get(), &pem_pubkey_raw, NULL, NULL));
parsed_pem_pubkey.reset(pem_pubkey_raw);
ASSERT_TRUE(parsed_pem_pubkey);
}

ASSERT_TRUE(EVP_PKEY_cmp(gen_dh.get(), parsed_pem_pubkey.get()));

OPENSSL_free((void*)pubkey_der);
OPENSSL_free((void*)pubkey_pem);
}
2 changes: 2 additions & 0 deletions crypto/evp_extra/evp_asn1.c
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@ EVP_PKEY *EVP_parse_public_key(CBS *cbs) {
}

int EVP_marshal_public_key(CBB *cbb, const EVP_PKEY *key) {
GUARD_PTR(cbb);
GUARD_PTR(key);
if (key->ameth == NULL || key->ameth->pub_encode == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM);
return 0;
Expand Down
75 changes: 73 additions & 2 deletions crypto/evp_extra/p_dh_asn1.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,71 @@
#include <openssl/bn.h>
#include <openssl/dh.h>
#include <openssl/err.h>
#include <openssl/x509.h>

#include "internal.h"
#include "../internal.h"
#include "../fipsmodule/cpucap/internal.h"
#include "../fipsmodule/dh/internal.h"
#include "../internal.h"
#include "internal.h"

static int dh_pub_encode(CBB *out, const EVP_PKEY *key) {
CBB spki, algorithm, oid, key_bitstring;
if (!CBB_add_asn1(out, &spki, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1(&spki, &algorithm, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) ||
!CBB_add_bytes(&oid, dh_asn1_meth.oid, dh_asn1_meth.oid_len) ||
!DH_marshal_parameters(&algorithm, key->pkey.dh) ||
!CBB_add_asn1(&spki, &key_bitstring, CBS_ASN1_BITSTRING) ||
!CBB_add_u8(&key_bitstring, 0 /* padding */) ||
!BN_marshal_asn1(&key_bitstring, key->pkey.dh->pub_key) ||
!CBB_flush(out)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
return 0;
}

return 1;
}

static int dh_pub_decode(EVP_PKEY *out, CBS *params, CBS *key) {
// RFC 2786
BIGNUM *pubkey = NULL;
DH *dh = NULL;
if (out == NULL || params == NULL || CBS_len(params) == 0 || key == NULL ||
CBS_len(key) == 0) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
goto err;
}

dh = DH_parse_parameters(params);
if (dh == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
goto err;
}

pubkey = BN_new();
if (pubkey == NULL || !BN_parse_asn1_unsigned(key, pubkey)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
goto err;
}

int out_flags = 0;
if (!DH_check_pub_key(dh, pubkey, &out_flags) || out_flags != 0) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
goto err;
}
dh->pub_key = pubkey;

if (!EVP_PKEY_assign_DH(out, dh)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
goto err;
}
return 1;

err:
DH_free(dh);
BN_free(pubkey);
return 0;
}


static void dh_free(EVP_PKEY *pkey) {
Expand Down Expand Up @@ -80,13 +141,23 @@ static int dh_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) {

const EVP_PKEY_ASN1_METHOD dh_asn1_meth = {
.pkey_id = EVP_PKEY_DH,
// 1.2.840.113549.1.3.1
// ((1)*40 + (2)) = 42 = 0x2a
// 840 = 0b_0000110_1001000 => 0b_1000_0110_0100_1000 = 0x86 0x48
// 113549 = 0b_0000110_1110111_0001101 => 0b_1000_0110_1111_0111_0000_1101 = 0x86 0xF7 0x0D
.oid = {0x2a, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x03, 0x01},
.oid_len = 9,
.pem_str = "DH",
.info = "OpenSSL PKCS#3 DH method",
.pub_cmp = dh_pub_cmp,
.pkey_size = dh_size,
.pkey_bits = dh_bits,
.param_missing = dh_param_missing,
.param_copy = dh_param_copy,
.param_cmp = dh_param_cmp,
.pkey_free = dh_free,
.pub_encode = dh_pub_encode,
.pub_decode = dh_pub_decode,
};

int EVP_PKEY_set1_DH(EVP_PKEY *pkey, DH *key) {
Expand Down
3 changes: 2 additions & 1 deletion crypto/evp_extra/p_methods.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ const EVP_PKEY_ASN1_METHOD *const asn1_evp_pkey_methods[] = {
&dilithium3_asn1_meth,
#endif
&kem_asn1_meth,
&hmac_asn1_meth
&hmac_asn1_meth,
&dh_asn1_meth
};
const size_t asn1_evp_pkey_methods_size = sizeof(asn1_evp_pkey_methods)/sizeof(asn1_evp_pkey_methods[0]);

Expand Down
4 changes: 2 additions & 2 deletions crypto/fipsmodule/evp/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -375,10 +375,10 @@ void evp_pkey_set_cb_translate(BN_GENCB *cb, EVP_PKEY_CTX *ctx);

#ifdef ENABLE_DILITHIUM
#define NON_FIPS_EVP_PKEY_METHODS 3
#define ASN1_EVP_PKEY_METHODS 9
#define ASN1_EVP_PKEY_METHODS 10
#else
#define NON_FIPS_EVP_PKEY_METHODS 2
#define ASN1_EVP_PKEY_METHODS 8
#define ASN1_EVP_PKEY_METHODS 9
#endif

struct fips_evp_pkey_methods {
Expand Down

0 comments on commit f3df19d

Please sign in to comment.