Skip to content

Commit

Permalink
add back ASN1_dup with tests
Browse files Browse the repository at this point in the history
  • Loading branch information
samuel40791765 committed May 13, 2024
1 parent 8ae155b commit f3f64e6
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 3 deletions.
20 changes: 20 additions & 0 deletions crypto/asn1/a_dup.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,26 @@
#include <openssl/err.h>
#include <openssl/mem.h>

void *ASN1_dup(i2d_of_void *i2d, d2i_of_void *d2i, void *input) {
if (i2d == NULL || d2i == NULL || input == NULL) {
OPENSSL_PUT_ERROR(ASN1, ERR_R_PASSED_NULL_PARAMETER);
return NULL;
}

// Size and allocate |buf|.
unsigned char *buf = NULL;
int buf_len = i2d(input, &buf);
if (buf == NULL) {
return NULL;
}

// |buf| needs to be converted to |const| to be passed in.
const unsigned char *temp_input = buf;
char *ret = d2i(NULL, &temp_input, buf_len);
OPENSSL_free(buf);
return ret;
}

// ASN1_ITEM version of dup: this follows the model above except we don't
// need to allocate the buffer. At some point this could be rewritten to
// directly dup the underlying structure instead of doing and encode and
Expand Down
45 changes: 45 additions & 0 deletions crypto/asn1/asn1_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2412,6 +2412,51 @@ TEST(ASN1Test, LargeString) {
#endif
}

TEST(ASN1Test, ASN1Dup) {
const uint8_t *tag = kTag128;
bssl::UniquePtr<ASN1_TYPE> asn1(
d2i_ASN1_TYPE(nullptr, &tag, sizeof(kTag128)));
ASSERT_TRUE(asn1);
EXPECT_EQ(128, asn1->type);
bssl::UniquePtr<ASN1_TYPE> asn1_copy((ASN1_TYPE *)ASN1_dup(
(i2d_of_void *)i2d_ASN1_TYPE, (d2i_of_void *)d2i_ASN1_TYPE, asn1.get()));
ASSERT_TRUE(asn1_copy);
EXPECT_EQ(ASN1_TYPE_cmp(asn1.get(), asn1_copy.get()), 0);

bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
ASSERT_TRUE(key);
ASSERT_TRUE(EC_KEY_generate_key(key.get()));
bssl::UniquePtr<EC_KEY> key_copy(
(EC_KEY *)ASN1_dup((i2d_of_void *)i2d_ECPrivateKey,
(d2i_of_void *)d2i_ECPrivateKey, key.get()));
ASSERT_TRUE(key_copy);
EXPECT_EQ(BN_cmp(EC_KEY_get0_private_key(key.get()),
EC_KEY_get0_private_key(key_copy.get())),
0);
EXPECT_EQ(EC_GROUP_cmp(EC_KEY_get0_group(key.get()),
EC_KEY_get0_group(key_copy.get()), nullptr),
0);
EXPECT_EQ(EC_POINT_cmp(EC_KEY_get0_group(key_copy.get()),
EC_KEY_get0_public_key(key.get()),
EC_KEY_get0_public_key(key_copy.get()), nullptr),
0);

bssl::UniquePtr<EVP_PKEY> evp_pkey(EVP_PKEY_new());
X509_PUBKEY *tmp_key = nullptr;
ASSERT_TRUE(evp_pkey);
ASSERT_TRUE(EVP_PKEY_set1_EC_KEY(evp_pkey.get(), key.get()));
ASSERT_TRUE(X509_PUBKEY_set(&tmp_key, evp_pkey.get()));
bssl::UniquePtr<X509_PUBKEY> x509_pubkey(tmp_key);
bssl::UniquePtr<X509_PUBKEY> x509_pubkey_copy((X509_PUBKEY *)ASN1_dup(
(i2d_of_void *)i2d_X509_PUBKEY, (d2i_of_void *)d2i_X509_PUBKEY,
x509_pubkey.get()));
ASSERT_TRUE(x509_pubkey_copy);
EXPECT_EQ(
ASN1_STRING_cmp(X509_PUBKEY_get0_public_key(x509_pubkey.get()),
X509_PUBKEY_get0_public_key(x509_pubkey_copy.get())),
0);
}

// The ASN.1 macros do not work on Windows shared library builds, where usage of
// |OPENSSL_EXPORT| is a bit stricter.
#if !defined(OPENSSL_WINDOWS) || !defined(BORINGSSL_SHARED_LIBRARY)
Expand Down
15 changes: 12 additions & 3 deletions include/openssl/asn1.h
Original file line number Diff line number Diff line change
Expand Up @@ -275,8 +275,7 @@ int i2d_SAMPLE(const SAMPLE *in, uint8_t **outp);

// CHECKED_I2D_OF casts a given pointer to i2d_of_void* and statically checks
// that it was a pointer to |type|'s |i2d| function.
#define CHECKED_I2D_OF(type, i2d) \
((i2d_of_void*) (1 ? i2d : ((I2D_OF(type))0)))
#define CHECKED_I2D_OF(type, i2d) ((i2d_of_void *)(1 ? i2d : ((I2D_OF(type))0)))

// The following typedefs are sometimes used for pointers to functions like
// |d2i_SAMPLE| and |i2d_SAMPLE|. Note, however, that these act on |void*|.
Expand Down Expand Up @@ -391,6 +390,16 @@ OPENSSL_EXPORT ASN1_VALUE *ASN1_item_d2i(ASN1_VALUE **out,
OPENSSL_EXPORT int ASN1_item_i2d(ASN1_VALUE *val, unsigned char **outp,
const ASN1_ITEM *it);

// ASN1_dup returns a newly-allocated copy of |x| by re-encoding with |i2d| and
// |d2i|. |i2d| and |d2i| must be the corresponding type functions of |x|. NULL
// is returned on error.
//
// WARNING: DO NOT USE. Casting the result of this function to the wrong type,
// or passing a pointer of the wrong type into this function, are potentially
// exploitable memory errors. Prefer directly calling |i2d| and |d2i| or other
// type-specific functions.
OPENSSL_EXPORT void *ASN1_dup(i2d_of_void *i2d, d2i_of_void *d2i, void *x);

// ASN1_item_dup returns a newly-allocated copy of |x|, or NULL on error. |x|
// must be an object of |it|'s C type.
//
Expand Down Expand Up @@ -443,7 +452,7 @@ OPENSSL_EXPORT int ASN1_i2d_bio(i2d_of_void *i2d, BIO *out, void *in);
// forces the user to use undefined C behavior and will cause failures when
// running against undefined behavior sanitizers in clang.
#define ASN1_i2d_bio_of(type, i2d, out, in) \
(ASN1_i2d_bio(CHECKED_I2D_OF(type, i2d), out, CHECKED_PTR_OF(type, in)))
(ASN1_i2d_bio(CHECKED_I2D_OF(type, i2d), out, CHECKED_PTR_OF(type, in)))

// ASN1_item_unpack parses |oct|'s contents as |it|'s ASN.1 type. It returns a
// newly-allocated instance of |it|'s C type on success, or NULL on error.
Expand Down

0 comments on commit f3f64e6

Please sign in to comment.