Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Marshalling/Unmarshalling DH public keys #1916

Merged
merged 2 commits into from
Oct 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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));
justsmth marked this conversation as resolved.
Show resolved Hide resolved
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);
justsmth marked this conversation as resolved.
Show resolved Hide resolved
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) {
justsmth marked this conversation as resolved.
Show resolved Hide resolved
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);
justsmth marked this conversation as resolved.
Show resolved Hide resolved
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);
justsmth marked this conversation as resolved.
Show resolved Hide resolved
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
Loading