diff --git a/crypto/asn1/a_bool.c b/crypto/asn1/a_bool.c index 64a079ec..34bbd155 100644 --- a/crypto/asn1/a_bool.c +++ b/crypto/asn1/a_bool.c @@ -62,17 +62,30 @@ int i2d_ASN1_BOOLEAN(int a, unsigned char **pp) { int r; - unsigned char *p; + unsigned char *p, *allocated = NULL; r = ASN1_object_size(0, 1, V_ASN1_BOOLEAN); if (pp == NULL) return (r); - p = *pp; + + if (*pp == NULL) { + if ((p = allocated = OPENSSL_malloc(r)) == NULL) { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + return 0; + } + } else { + p = *pp; + } ASN1_put_object(&p, 0, 1, V_ASN1_BOOLEAN, V_ASN1_UNIVERSAL); - *(p++) = (unsigned char)a; - *pp = p; - return (r); + *p = (unsigned char)a; + + /* + * If a new buffer was allocated, just return it back. + * If not, return the incremented buffer pointer. + */ + *pp = allocated != NULL ? allocated : p + 1; + return r; } int d2i_ASN1_BOOLEAN(int *a, const unsigned char **pp, long length) diff --git a/crypto/asn1/a_object.c b/crypto/asn1/a_object.c index 005e37d5..97335bfd 100644 --- a/crypto/asn1/a_object.c +++ b/crypto/asn1/a_object.c @@ -68,7 +68,7 @@ int i2d_ASN1_OBJECT(ASN1_OBJECT *a, unsigned char **pp) { - unsigned char *p; + unsigned char *p, *allocated = NULL; int objsize; if ((a == NULL) || (a->data == NULL)) @@ -78,13 +78,24 @@ int i2d_ASN1_OBJECT(ASN1_OBJECT *a, unsigned char **pp) if (pp == NULL || objsize == -1) return objsize; - p = *pp; + if (*pp == NULL) { + if ((p = allocated = OPENSSL_malloc(objsize)) == NULL) { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + return 0; + } + } else { + p = *pp; + } + ASN1_put_object(&p, 0, a->length, V_ASN1_OBJECT, V_ASN1_UNIVERSAL); OPENSSL_memcpy(p, a->data, a->length); - p += a->length; - *pp = p; - return (objsize); + /* + * If a new buffer was allocated, just return it back. + * If not, return the incremented buffer pointer. + */ + *pp = allocated != NULL ? allocated : p + a->length; + return objsize; } int i2t_ASN1_OBJECT(char *buf, int buf_len, ASN1_OBJECT *a) diff --git a/crypto/asn1/asn1_test.cc b/crypto/asn1/asn1_test.cc index 1cca36ce..ff80e492 100644 --- a/crypto/asn1/asn1_test.cc +++ b/crypto/asn1/asn1_test.cc @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include "../test/test_util.h" @@ -148,3 +150,37 @@ TEST(ASN1Test, Recursive) { // is too deep, so the |ASN1_R_NESTED_TOO_DEEP| entry drops off the queue. ASN1_LINKED_LIST_free(list); } + +template +void TestSerialize(T obj, int (*i2d_func)(T a, uint8_t **pp), + bssl::Span expected) { + int len = static_cast(expected.size()); + ASSERT_EQ(i2d_func(obj, nullptr), len); + + std::vector buf(expected.size()); + uint8_t *ptr = buf.data(); + ASSERT_EQ(i2d_func(obj, &ptr), len); + EXPECT_EQ(ptr, buf.data() + buf.size()); + EXPECT_EQ(Bytes(expected), Bytes(buf)); + + // Test the allocating version. + ptr = nullptr; + ASSERT_EQ(i2d_func(obj, &ptr), len); + EXPECT_EQ(Bytes(expected), Bytes(ptr, expected.size())); + OPENSSL_free(ptr); +} + +TEST(ASN1Test, SerializeObject) { + static const uint8_t kDER[] = {0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x01}; + const ASN1_OBJECT *obj = OBJ_nid2obj(NID_rsaEncryption); + TestSerialize(const_cast(obj), i2d_ASN1_OBJECT, kDER); +} + +TEST(ASN1Test, SerializeBoolean) { + static const uint8_t kTrue[] = {0x01, 0x01, 0xff}; + TestSerialize(0xff, i2d_ASN1_BOOLEAN, kTrue); + + static const uint8_t kFalse[] = {0x01, 0x01, 0x00}; + TestSerialize(0x00, i2d_ASN1_BOOLEAN, kFalse); +} diff --git a/crypto/test/test_util.cc b/crypto/test/test_util.cc index 4ad777f5..29be702d 100644 --- a/crypto/test/test_util.cc +++ b/crypto/test/test_util.cc @@ -30,15 +30,15 @@ void hexdump(FILE *fp, const char *msg, const void *in, size_t len) { } std::ostream &operator<<(std::ostream &os, const Bytes &in) { - if (in.len == 0) { + if (in.span_.empty()) { return os << ""; } // Print a byte slice as hex. static const char hex[] = "0123456789abcdef"; - for (size_t i = 0; i < in.len; i++) { - os << hex[in.data[i] >> 4]; - os << hex[in.data[i] & 0xf]; + for (uint8_t b : in.span_) { + os << hex[b >> 4]; + os << hex[b & 0xf]; } return os; } diff --git a/crypto/test/test_util.h b/crypto/test/test_util.h index 9c9ef58f..2ef3f19b 100644 --- a/crypto/test/test_util.h +++ b/crypto/test/test_util.h @@ -24,6 +24,8 @@ #include #include +#include + #include "../internal.h" @@ -35,26 +37,22 @@ void hexdump(FILE *fp, const char *msg, const void *in, size_t len); // allows it to be used in EXPECT_EQ macros. struct Bytes { Bytes(const uint8_t *data_arg, size_t len_arg) - : data(data_arg), len(len_arg) {} + : span_(data_arg, len_arg) {} Bytes(const char *data_arg, size_t len_arg) - : data(reinterpret_cast(data_arg)), len(len_arg) {} + : span_(reinterpret_cast(data_arg), len_arg) {} explicit Bytes(const char *str) - : data(reinterpret_cast(str)), len(strlen(str)) {} + : span_(reinterpret_cast(str), strlen(str)) {} explicit Bytes(const std::string &str) - : data(reinterpret_cast(str.data())), len(str.size()) {} - explicit Bytes(const std::vector &vec) - : data(vec.data()), len(vec.size()) {} + : span_(reinterpret_cast(str.data()), str.size()) {} + explicit Bytes(bssl::Span span) + : span_(span) {} - template - explicit Bytes(const uint8_t (&array)[N]) : data(array), len(N) {} - - const uint8_t *data; - size_t len; + bssl::Span span_; }; inline bool operator==(const Bytes &a, const Bytes &b) { - return a.len == b.len && OPENSSL_memcmp(a.data, b.data, a.len) == 0; + return a.span_ == b.span_; } inline bool operator!=(const Bytes &a, const Bytes &b) { return !(a == b); }