From 0378578cd4960765bb0f52123a82d8cacc653991 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Wed, 22 Jun 2022 00:13:19 -0400 Subject: [PATCH 01/38] Dedup a few more load/store implementations. Change-Id: I521922842b3586ab7c6e242281188745a879f1df Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/53094 Reviewed-by: Adam Langley --- crypto/poly1305/poly1305_vec.c | 40 ++++++++++------------------------ 1 file changed, 12 insertions(+), 28 deletions(-) diff --git a/crypto/poly1305/poly1305_vec.c b/crypto/poly1305/poly1305_vec.c index 83f1efee34..073050883b 100644 --- a/crypto/poly1305/poly1305_vec.c +++ b/crypto/poly1305/poly1305_vec.c @@ -27,22 +27,6 @@ #include -static uint32_t load_u32_le(const uint8_t in[4]) { - uint32_t ret; - OPENSSL_memcpy(&ret, in, 4); - return ret; -} - -static uint64_t load_u64_le(const uint8_t in[8]) { - uint64_t ret; - OPENSSL_memcpy(&ret, in, 8); - return ret; -} - -static void store_u64_le(uint8_t out[8], uint64_t v) { - OPENSSL_memcpy(out, &v, 8); -} - typedef __m128i xmmi; static const alignas(16) uint32_t poly1305_x64_sse2_message_mask[4] = { @@ -112,8 +96,8 @@ void CRYPTO_poly1305_init(poly1305_state *state, const uint8_t key[32]) { uint64_t t0, t1; // clamp key - t0 = load_u64_le(key + 0); - t1 = load_u64_le(key + 8); + t0 = CRYPTO_load_u64_le(key + 0); + t1 = CRYPTO_load_u64_le(key + 8); r0 = t0 & 0xffc0fffffff; t0 >>= 44; t0 |= t1 << 20; @@ -131,10 +115,10 @@ void CRYPTO_poly1305_init(poly1305_state *state, const uint8_t key[32]) { p->R22.d[3] = (uint32_t)(r2 >> 32); // store pad - p->R23.d[1] = load_u32_le(key + 16); - p->R23.d[3] = load_u32_le(key + 20); - p->R24.d[1] = load_u32_le(key + 24); - p->R24.d[3] = load_u32_le(key + 28); + p->R23.d[1] = CRYPTO_load_u32_le(key + 16); + p->R23.d[3] = CRYPTO_load_u32_le(key + 20); + p->R24.d[1] = CRYPTO_load_u32_le(key + 24); + p->R24.d[3] = CRYPTO_load_u32_le(key + 28); // H = 0 st->H[0] = _mm_setzero_si128(); @@ -766,8 +750,8 @@ void CRYPTO_poly1305_finish(poly1305_state *state, uint8_t mac[16]) { } poly1305_donna_atleast16bytes: - t0 = load_u64_le(m + 0); - t1 = load_u64_le(m + 8); + t0 = CRYPTO_load_u64_le(m + 0); + t1 = CRYPTO_load_u64_le(m + 8); h0 += t0 & 0xfffffffffff; t0 = shr128_pair(t1, t0, 44); h1 += t0 & 0xfffffffffff; @@ -806,8 +790,8 @@ void CRYPTO_poly1305_finish(poly1305_state *state, uint8_t mac[16]) { OPENSSL_memset(m + leftover, 0, 16 - leftover); leftover = 16; - t0 = load_u64_le(m + 0); - t1 = load_u64_le(m + 8); + t0 = CRYPTO_load_u64_le(m + 0); + t1 = CRYPTO_load_u64_le(m + 8); h0 += t0 & 0xfffffffffff; t0 = shr128_pair(t1, t0, 44); h1 += t0 & 0xfffffffffff; @@ -853,8 +837,8 @@ void CRYPTO_poly1305_finish(poly1305_state *state, uint8_t mac[16]) { t1 = (t1 >> 24); h2 += (t1)+c; - store_u64_le(mac + 0, ((h0) | (h1 << 44))); - store_u64_le(mac + 8, ((h1 >> 20) | (h2 << 24))); + CRYPTO_store_u64_le(mac + 0, ((h0) | (h1 << 44))); + CRYPTO_store_u64_le(mac + 8, ((h1 >> 20) | (h2 << 24))); } #endif // BORINGSSL_HAS_UINT128 && OPENSSL_X86_64 From fdeb4aa9251aad073a36426f66d2e0819a3a4a6d Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Wed, 22 Jun 2022 14:18:20 -0400 Subject: [PATCH 02/38] Reimplement ASN1_TIME_print with the new parser. No sense in keeping two around. This does cause the functions to reject some previously accepted invalid inputs. These were intentionally accepted by https://boringssl-review.googlesource.com/c/boringssl/+/13082 for an old version of M2Crypto, but I belive we no longer need to be compatible with that. Update-Note: ASN1_TIME_print, ASN1_UTCTIME_print, and ASN1_GENERALIZEDTIME_print will no longer accept various invalid inputs. Change-Id: I4606d0b39585a19eb4b984ac809706e497a3f799 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/53090 Commit-Queue: David Benjamin Reviewed-by: Bob Beck --- crypto/asn1/a_strex.c | 145 +++++------------------------------ crypto/asn1/asn1_test.cc | 48 +++++++++--- crypto/x509/x509_test.cc | 8 +- include/openssl/bytestring.h | 7 +- 4 files changed, 65 insertions(+), 143 deletions(-) diff --git a/crypto/asn1/a_strex.c b/crypto/asn1/a_strex.c index 52d979e263..e6aacf06f0 100644 --- a/crypto/asn1/a_strex.c +++ b/crypto/asn1/a_strex.c @@ -60,8 +60,10 @@ #include #include #include +#include #include +#include #include #include "internal.h" @@ -464,7 +466,7 @@ int ASN1_TIME_print(BIO *bp, const ASN1_TIME *tm) { if (tm->type == V_ASN1_GENERALIZEDTIME) { return ASN1_GENERALIZEDTIME_print(bp, tm); } - BIO_write(bp, "Bad time value", 14); + BIO_puts(bp, "Bad time value"); return 0; } @@ -472,136 +474,29 @@ static const char *const mon[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; int ASN1_GENERALIZEDTIME_print(BIO *bp, const ASN1_GENERALIZEDTIME *tm) { - char *v; - int gmt = 0; - int i; - int y = 0, M = 0, d = 0, h = 0, m = 0, s = 0; - char *f = NULL; - int f_len = 0; - - i = tm->length; - v = (char *)tm->data; - - if (i < 12) { - goto err; - } - if (v[i - 1] == 'Z') { - gmt = 1; - } - for (i = 0; i < 12; i++) { - if ((v[i] > '9') || (v[i] < '0')) { - goto err; - } - } - y = (v[0] - '0') * 1000 + (v[1] - '0') * 100 + (v[2] - '0') * 10 + - (v[3] - '0'); - M = (v[4] - '0') * 10 + (v[5] - '0'); - if ((M > 12) || (M < 1)) { - goto err; - } - d = (v[6] - '0') * 10 + (v[7] - '0'); - h = (v[8] - '0') * 10 + (v[9] - '0'); - m = (v[10] - '0') * 10 + (v[11] - '0'); - if (tm->length >= 14 && (v[12] >= '0') && (v[12] <= '9') && (v[13] >= '0') && - (v[13] <= '9')) { - s = (v[12] - '0') * 10 + (v[13] - '0'); - // Check for fractions of seconds. - if (tm->length >= 15 && v[14] == '.') { - int l = tm->length; - f = &v[14]; // The decimal point. - f_len = 1; - while (14 + f_len < l && f[f_len] >= '0' && f[f_len] <= '9') { - ++f_len; - } - } - } - - if (BIO_printf(bp, "%s %2d %02d:%02d:%02d%.*s %d%s", mon[M - 1], d, h, m, s, - f_len, f, y, (gmt) ? " GMT" : "") <= 0) { - return 0; - } else { - return 1; - } -err: - BIO_write(bp, "Bad time value", 14); - return 0; -} - -// consume_two_digits is a helper function for ASN1_UTCTIME_print. If |*v|, -// assumed to be |*len| bytes long, has two leading digits, updates |*out| with -// their value, updates |v| and |len|, and returns one. Otherwise, returns -// zero. -static int consume_two_digits(int *out, const char **v, int *len) { - if (*len < 2 || !isdigit((unsigned char)((*v)[0])) || - !isdigit((unsigned char)((*v)[1]))) { - return 0; - } - *out = ((*v)[0] - '0') * 10 + ((*v)[1] - '0'); - *len -= 2; - *v += 2; - return 1; -} - -// consume_zulu_timezone is a helper function for ASN1_UTCTIME_print. If |*v|, -// assumed to be |*len| bytes long, starts with "Z" then it updates |*v| and -// |*len| and returns one. Otherwise returns zero. -static int consume_zulu_timezone(const char **v, int *len) { - if (*len == 0 || (*v)[0] != 'Z') { + CBS cbs; + CBS_init(&cbs, tm->data, tm->length); + struct tm utc; + if (!CBS_parse_generalized_time(&cbs, &utc, /*allow_timezone_offset=*/0)) { + BIO_puts(bp, "Bad time value"); return 0; } - *len -= 1; - *v += 1; - return 1; + return BIO_printf(bp, "%s %2d %02d:%02d:%02d %d GMT", mon[utc.tm_mon], + utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec, + utc.tm_year + 1900) > 0; } int ASN1_UTCTIME_print(BIO *bp, const ASN1_UTCTIME *tm) { - const char *v = (const char *)tm->data; - int len = tm->length; - int Y = 0, M = 0, D = 0, h = 0, m = 0, s = 0; - - // YYMMDDhhmm are required to be present. - if (!consume_two_digits(&Y, &v, &len) || !consume_two_digits(&M, &v, &len) || - !consume_two_digits(&D, &v, &len) || !consume_two_digits(&h, &v, &len) || - !consume_two_digits(&m, &v, &len)) { - goto err; - } - // https://tools.ietf.org/html/rfc5280, section 4.1.2.5.1, requires seconds - // to be present, but historically this code has forgiven its absence. - consume_two_digits(&s, &v, &len); - - // https://tools.ietf.org/html/rfc5280, section 4.1.2.5.1, specifies this - // interpretation of the year. - if (Y < 50) { - Y += 2000; - } else { - Y += 1900; - } - if (M > 12 || M == 0) { - goto err; - } - if (D > 31 || D == 0) { - goto err; - } - if (h > 23 || m > 59 || s > 60) { - goto err; - } - - // https://tools.ietf.org/html/rfc5280, section 4.1.2.5.1, requires the "Z" - // to be present, but historically this code has forgiven its absence. - const int is_gmt = consume_zulu_timezone(&v, &len); - - // https://tools.ietf.org/html/rfc5280, section 4.1.2.5.1, does not permit - // the specification of timezones using the +hhmm / -hhmm syntax, which is - // the only other thing that might legitimately be found at the end. - if (len) { - goto err; + CBS cbs; + CBS_init(&cbs, tm->data, tm->length); + struct tm utc; + if (!CBS_parse_utc_time(&cbs, &utc, /*allow_timezone_offset=*/0)) { + BIO_puts(bp, "Bad time value"); + return 0; } - return BIO_printf(bp, "%s %2d %02d:%02d:%02d %d%s", mon[M - 1], D, h, m, s, Y, - is_gmt ? " GMT" : "") > 0; - -err: - BIO_write(bp, "Bad time value", 14); - return 0; + return BIO_printf(bp, "%s %2d %02d:%02d:%02d %d GMT", mon[utc.tm_mon], + utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec, + utc.tm_year + 1900) > 0; } diff --git a/crypto/asn1/asn1_test.cc b/crypto/asn1/asn1_test.cc index c4f47bb5c8..442c1eabbf 100644 --- a/crypto/asn1/asn1_test.cc +++ b/crypto/asn1/asn1_test.cc @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -926,28 +927,46 @@ static bool ASN1Time_check_time_t(const ASN1_TIME *s, time_t t) { return day == 0 && sec ==0; } +static std::string PrintStringToBIO(const ASN1_STRING *str, + int (*print_func)(BIO *, + const ASN1_STRING *)) { + const uint8_t *data; + size_t len; + bssl::UniquePtr bio(BIO_new(BIO_s_mem())); + if (!bio || // + !print_func(bio.get(), str) || + !BIO_mem_contents(bio.get(), &data, &len)) { + ADD_FAILURE() << "Could not print to BIO"; + return ""; + } + return std::string(data, data + len); +} + TEST(ASN1Test, SetTime) { static const struct { time_t time; const char *generalized; const char *utc; + const char *printed; } kTests[] = { - {-631152001, "19491231235959Z", nullptr}, - {-631152000, "19500101000000Z", "500101000000Z"}, - {0, "19700101000000Z", "700101000000Z"}, - {981173106, "20010203040506Z", "010203040506Z"}, - {951804000, "20000229060000Z", "000229060000Z"}, + {-631152001, "19491231235959Z", nullptr, "Dec 31 23:59:59 1949 GMT"}, + {-631152000, "19500101000000Z", "500101000000Z", + "Jan 1 00:00:00 1950 GMT"}, + {0, "19700101000000Z", "700101000000Z", "Jan 1 00:00:00 1970 GMT"}, + {981173106, "20010203040506Z", "010203040506Z", "Feb 3 04:05:06 2001 GMT"}, + {951804000, "20000229060000Z", "000229060000Z", "Feb 29 06:00:00 2000 GMT"}, #if defined(OPENSSL_64_BIT) // TODO(https://crbug.com/boringssl/416): These cases overflow 32-bit // |time_t| and do not consistently work on 32-bit platforms. For now, // disable the tests on 32-bit. Re-enable them once the bug is fixed. - {2524607999, "20491231235959Z", "491231235959Z"}, - {2524608000, "20500101000000Z", nullptr}, + {2524607999, "20491231235959Z", "491231235959Z", + "Dec 31 23:59:59 2049 GMT"}, + {2524608000, "20500101000000Z", nullptr, "Jan 1 00:00:00 2050 GMT"}, // Test boundary conditions. - {-62167219200, "00000101000000Z", nullptr}, - {-62167219201, nullptr, nullptr}, - {253402300799, "99991231235959Z", nullptr}, - {253402300800, nullptr, nullptr}, + {-62167219200, "00000101000000Z", nullptr, "Jan 1 00:00:00 0 GMT"}, + {-62167219201, nullptr, nullptr, nullptr}, + {253402300799, "99991231235959Z", nullptr, "Dec 31 23:59:59 9999 GMT"}, + {253402300800, nullptr, nullptr, nullptr}, #endif }; for (const auto &t : kTests) { @@ -966,6 +985,8 @@ TEST(ASN1Test, SetTime) { EXPECT_EQ(V_ASN1_UTCTIME, ASN1_STRING_type(utc.get())); EXPECT_EQ(t.utc, ASN1StringToStdString(utc.get())); EXPECT_TRUE(ASN1Time_check_time_t(utc.get(), t.time)); + EXPECT_EQ(PrintStringToBIO(utc.get(), &ASN1_UTCTIME_print), t.printed); + EXPECT_EQ(PrintStringToBIO(utc.get(), &ASN1_TIME_print), t.printed); } else { EXPECT_FALSE(utc); } @@ -977,6 +998,11 @@ TEST(ASN1Test, SetTime) { EXPECT_EQ(V_ASN1_GENERALIZEDTIME, ASN1_STRING_type(generalized.get())); EXPECT_EQ(t.generalized, ASN1StringToStdString(generalized.get())); EXPECT_TRUE(ASN1Time_check_time_t(generalized.get(), t.time)); + EXPECT_EQ( + PrintStringToBIO(generalized.get(), &ASN1_GENERALIZEDTIME_print), + t.printed); + EXPECT_EQ(PrintStringToBIO(generalized.get(), &ASN1_TIME_print), + t.printed); } else { EXPECT_FALSE(generalized); } diff --git a/crypto/x509/x509_test.cc b/crypto/x509/x509_test.cc index ce70ae3b22..fe4a775fdb 100644 --- a/crypto/x509/x509_test.cc +++ b/crypto/x509/x509_test.cc @@ -2129,10 +2129,10 @@ TEST(X509Test, TestPrintUTCTIME) { {"000000000000Z", "Bad time value"}, {"999999999999Z", "Bad time value"}, - // Missing components. Not legal RFC 5280, but permitted. - {"090303125425", "Mar 3 12:54:25 2009"}, - {"9003031254", "Mar 3 12:54:00 1990"}, - {"9003031254Z", "Mar 3 12:54:00 1990 GMT"}, + // Missing components. + {"090303125425", "Bad time value"}, + {"9003031254", "Bad time value"}, + {"9003031254Z", "Bad time value"}, // GENERALIZEDTIME confused for UTCTIME. {"20090303125425Z", "Bad time value"}, diff --git a/include/openssl/bytestring.h b/include/openssl/bytestring.h index 846ab24612..1d47f60abe 100644 --- a/include/openssl/bytestring.h +++ b/include/openssl/bytestring.h @@ -362,16 +362,17 @@ OPENSSL_EXPORT char *CBS_asn1_oid_to_text(const CBS *cbs); // corresponding time in UTC. This function does not compute |out_tm->tm_wday| // or |out_tm->tm_yday|. OPENSSL_EXPORT int CBS_parse_generalized_time(const CBS *cbs, struct tm *out_tm, - int allow_timezeone_offset); + int allow_timezone_offset); // CBS_parse_utc_time returns one if |cbs| is a valid DER-encoded, ASN.1 // UTCTime body within the limitations imposed by RFC 5280, or zero otherwise. // If |allow_timezone_offset| is non-zero, four-digit timezone offsets, which // would not be allowed by DER, are permitted. On success, if |out_tm| is // non-NULL, |*out_tm| will be zeroed, and then set to the corresponding time -// in UTC. This function does not compute |out_tm->tm_wday| or |out_tm->tm_yday|. +// in UTC. This function does not compute |out_tm->tm_wday| or +// |out_tm->tm_yday|. OPENSSL_EXPORT int CBS_parse_utc_time(const CBS *cbs, struct tm *out_tm, - int allow_timezeone_offset); + int allow_timezone_offset); // CRYPTO ByteBuilder. // From c239ffd0552179f358de31517391679e9b62ccd3 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Thu, 23 Jun 2022 00:33:48 -0400 Subject: [PATCH 03/38] Remove some unnecessary NULL checks. Our free functions all tolerate NULL. Change-Id: Ifcb3185c8d2f34afb83f7286c3463136edc926fa Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/53125 Reviewed-by: Bob Beck Commit-Queue: David Benjamin --- crypto/asn1/a_object.c | 4 +--- crypto/asn1/a_utctm.c | 2 +- crypto/asn1/tasn_utl.c | 2 +- crypto/x509/a_sign.c | 8 +------- crypto/x509/asn1_gen.c | 24 +++++------------------- crypto/x509/by_dir.c | 28 +++++++++------------------- crypto/x509/by_file.c | 16 ++++------------ crypto/x509/internal.h | 2 +- crypto/x509v3/pcy_tree.c | 23 ++++++----------------- crypto/x509v3/v3_conf.c | 4 +--- crypto/x509v3/v3_crld.c | 16 ++++------------ crypto/x509v3/v3_ncons.c | 9 ++------- crypto/x509v3/v3_utl.c | 16 ++++------------ 13 files changed, 40 insertions(+), 114 deletions(-) diff --git a/crypto/asn1/a_object.c b/crypto/asn1/a_object.c index 17783ba8ec..c854fb8871 100644 --- a/crypto/asn1/a_object.c +++ b/crypto/asn1/a_object.c @@ -204,9 +204,7 @@ ASN1_OBJECT *c2i_ASN1_OBJECT(ASN1_OBJECT **a, const unsigned char **pp, // once detached we can change it if ((data == NULL) || (ret->length < length)) { ret->length = 0; - if (data != NULL) { - OPENSSL_free(data); - } + OPENSSL_free(data); data = (unsigned char *)OPENSSL_malloc(length); if (data == NULL) { i = ERR_R_MALLOC_FAILURE; diff --git a/crypto/asn1/a_utctm.c b/crypto/asn1/a_utctm.c index 159a0ea1f2..ac548ddd39 100644 --- a/crypto/asn1/a_utctm.c +++ b/crypto/asn1/a_utctm.c @@ -154,7 +154,7 @@ ASN1_UTCTIME *ASN1_UTCTIME_adj(ASN1_UTCTIME *s, time_t t, int offset_day, s->type = V_ASN1_UTCTIME; return s; err: - if (free_s && s) { + if (free_s) { ASN1_UTCTIME_free(s); } return NULL; diff --git a/crypto/asn1/tasn_utl.c b/crypto/asn1/tasn_utl.c index a476874ff2..4a9757437a 100644 --- a/crypto/asn1/tasn_utl.c +++ b/crypto/asn1/tasn_utl.c @@ -146,7 +146,7 @@ void asn1_enc_free(ASN1_VALUE **pval, const ASN1_ITEM *it) { ASN1_ENCODING *enc; enc = asn1_get_enc_ptr(pval, it); if (enc) { - if (enc->enc && !enc->alias_only) { + if (!enc->alias_only) { OPENSSL_free(enc->enc); } enc->enc = NULL; diff --git a/crypto/x509/a_sign.c b/crypto/x509/a_sign.c index 010f66083e..ed9e79bb43 100644 --- a/crypto/x509/a_sign.c +++ b/crypto/x509/a_sign.c @@ -107,14 +107,8 @@ int ASN1_item_sign_ctx(const ASN1_ITEM *it, X509_ALGOR *algor1, OPENSSL_PUT_ERROR(X509, ERR_R_EVP_LIB); goto err; } - if (signature->data != NULL) { - OPENSSL_free(signature->data); - } - signature->data = buf_out; + ASN1_STRING_set0(signature, buf_out, outl); buf_out = NULL; - signature->length = outl; - // In the interests of compatibility, I'll make sure that the bit string - // has a 'not-used bits' value of 0 signature->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07); signature->flags |= ASN1_STRING_FLAG_BITS_LEFT; err: diff --git a/crypto/x509/asn1_gen.c b/crypto/x509/asn1_gen.c index 3890c46210..eb31970075 100644 --- a/crypto/x509/asn1_gen.c +++ b/crypto/x509/asn1_gen.c @@ -273,13 +273,8 @@ static ASN1_TYPE *generate_v3(const char *str, X509V3_CTX *cnf, int depth, ret = d2i_ASN1_TYPE(NULL, &cp, len); err: - if (orig_der) { - OPENSSL_free(orig_der); - } - if (new_der) { - OPENSSL_free(new_der); - } - + OPENSSL_free(orig_der); + OPENSSL_free(new_der); return ret; } @@ -513,18 +508,9 @@ static ASN1_TYPE *asn1_multi(int utype, const char *section, X509V3_CTX *cnf, der = NULL; bad: - - if (der) { - OPENSSL_free(der); - } - - if (sk) { - sk_ASN1_TYPE_pop_free(sk, ASN1_TYPE_free); - } - if (sect) { - X509V3_section_free(cnf, sect); - } - + OPENSSL_free(der); + sk_ASN1_TYPE_pop_free(sk, ASN1_TYPE_free); + X509V3_section_free(cnf, sect); return ret; } diff --git a/crypto/x509/by_dir.c b/crypto/x509/by_dir.c index 395e82df69..9e3290ddac 100644 --- a/crypto/x509/by_dir.c +++ b/crypto/x509/by_dir.c @@ -114,10 +114,9 @@ X509_LOOKUP_METHOD *X509_LOOKUP_hash_dir(void) { return &x509_dir_lookup; } static int dir_ctrl(X509_LOOKUP *ctx, int cmd, const char *argp, long argl, char **retp) { int ret = 0; - BY_DIR *ld; char *dir = NULL; - ld = (BY_DIR *)ctx->method_data; + BY_DIR *ld = ctx->method_data; switch (cmd) { case X509_L_ADD_DIR: @@ -151,7 +150,7 @@ static int new_dir(X509_LOOKUP *lu) { return 0; } a->dirs = NULL; - lu->method_data = (char *)a; + lu->method_data = a; return 1; } @@ -168,26 +167,20 @@ static int by_dir_hash_cmp(const BY_DIR_HASH **a, const BY_DIR_HASH **b) { } static void by_dir_entry_free(BY_DIR_ENTRY *ent) { - if (ent->dir) { + if (ent != NULL) { OPENSSL_free(ent->dir); - } - if (ent->hashes) { sk_BY_DIR_HASH_pop_free(ent->hashes, by_dir_hash_free); + OPENSSL_free(ent); } - OPENSSL_free(ent); } static void free_dir(X509_LOOKUP *lu) { - BY_DIR *a; - - a = (BY_DIR *)lu->method_data; - if (a->dirs != NULL) { + BY_DIR *a = lu->method_data; + if (a != NULL) { sk_BY_DIR_ENTRY_pop_free(a->dirs, by_dir_entry_free); - } - if (a->buffer != NULL) { BUF_MEM_free(a->buffer); + OPENSSL_free(a); } - OPENSSL_free(a); } static int add_cert_dir(BY_DIR *ctx, const char *dir, int type) { @@ -253,7 +246,6 @@ static struct CRYPTO_STATIC_MUTEX g_ent_hashes_lock = CRYPTO_STATIC_MUTEX_INIT; static int get_cert_by_subject(X509_LOOKUP *xl, int type, X509_NAME *name, X509_OBJECT *ret) { - BY_DIR *ctx; union { struct { X509 st_x509; @@ -299,7 +291,7 @@ static int get_cert_by_subject(X509_LOOKUP *xl, int type, X509_NAME *name, goto finish; } - ctx = (BY_DIR *)xl->method_data; + BY_DIR *ctx = xl->method_data; hash_array[0] = X509_NAME_hash(name); hash_array[1] = X509_NAME_hash_old(name); @@ -440,9 +432,7 @@ static int get_cert_by_subject(X509_LOOKUP *xl, int type, X509_NAME *name, } } finish: - if (b != NULL) { - BUF_MEM_free(b); - } + BUF_MEM_free(b); return ok; } diff --git a/crypto/x509/by_file.c b/crypto/x509/by_file.c index 65c2b8b438..3435fc2a3a 100644 --- a/crypto/x509/by_file.c +++ b/crypto/x509/by_file.c @@ -171,12 +171,8 @@ int X509_load_cert_file(X509_LOOKUP *ctx, const char *file, int type) { } err: - if (x != NULL) { - X509_free(x); - } - if (in != NULL) { - BIO_free(in); - } + X509_free(x); + BIO_free(in); return ret; } @@ -236,12 +232,8 @@ int X509_load_crl_file(X509_LOOKUP *ctx, const char *file, int type) { } err: - if (x != NULL) { - X509_CRL_free(x); - } - if (in != NULL) { - BIO_free(in); - } + X509_CRL_free(x); + BIO_free(in); return ret; } diff --git a/crypto/x509/internal.h b/crypto/x509/internal.h index 6ac8a3fbef..8785949198 100644 --- a/crypto/x509/internal.h +++ b/crypto/x509/internal.h @@ -310,7 +310,7 @@ struct x509_lookup_st { int init; // have we been started int skip; // don't use us. X509_LOOKUP_METHOD *method; // the functions - char *method_data; // method data + void *method_data; // method data X509_STORE *store_ctx; // who owns us } /* X509_LOOKUP */; diff --git a/crypto/x509v3/pcy_tree.c b/crypto/x509v3/pcy_tree.c index 10dad0567f..673c615ba1 100644 --- a/crypto/x509v3/pcy_tree.c +++ b/crypto/x509v3/pcy_tree.c @@ -688,9 +688,6 @@ static void exnode_free(X509_POLICY_NODE *node) { } void X509_policy_tree_free(X509_POLICY_TREE *tree) { - X509_POLICY_LEVEL *curr; - int i; - if (!tree) { return; } @@ -698,22 +695,14 @@ void X509_policy_tree_free(X509_POLICY_TREE *tree) { sk_X509_POLICY_NODE_free(tree->auth_policies); sk_X509_POLICY_NODE_pop_free(tree->user_policies, exnode_free); - for (i = 0, curr = tree->levels; i < tree->nlevel; i++, curr++) { - if (curr->cert) { - X509_free(curr->cert); - } - if (curr->nodes) { - sk_X509_POLICY_NODE_pop_free(curr->nodes, policy_node_free); - } - if (curr->anyPolicy) { - policy_node_free(curr->anyPolicy); - } - } - - if (tree->extra_data) { - sk_X509_POLICY_DATA_pop_free(tree->extra_data, policy_data_free); + for (int i = 0; i < tree->nlevel; i++) { + X509_POLICY_LEVEL *curr = &tree->levels[i]; + X509_free(curr->cert); + sk_X509_POLICY_NODE_pop_free(curr->nodes, policy_node_free); + policy_node_free(curr->anyPolicy); } + sk_X509_POLICY_DATA_pop_free(tree->extra_data, policy_data_free); OPENSSL_free(tree->levels); OPENSSL_free(tree); } diff --git a/crypto/x509v3/v3_conf.c b/crypto/x509v3/v3_conf.c index 7140edd742..64bed7a4e2 100644 --- a/crypto/x509v3/v3_conf.c +++ b/crypto/x509v3/v3_conf.c @@ -310,9 +310,7 @@ static X509_EXTENSION *v3_generic_extension(const char *ext, const char *value, err: ASN1_OBJECT_free(obj); ASN1_OCTET_STRING_free(oct); - if (ext_der) { - OPENSSL_free(ext_der); - } + OPENSSL_free(ext_der); return extension; } diff --git a/crypto/x509v3/v3_crld.c b/crypto/x509v3/v3_crld.c index f1cab705f8..68ab343981 100644 --- a/crypto/x509v3/v3_crld.c +++ b/crypto/x509v3/v3_crld.c @@ -190,12 +190,8 @@ static int set_dist_point_name(DIST_POINT_NAME **pdp, X509V3_CTX *ctx, return 1; err: - if (fnm) { - sk_GENERAL_NAME_pop_free(fnm, GENERAL_NAME_free); - } - if (rnm) { - sk_X509_NAME_ENTRY_pop_free(rnm, X509_NAME_ENTRY_free); - } + sk_GENERAL_NAME_pop_free(fnm, GENERAL_NAME_free); + sk_X509_NAME_ENTRY_pop_free(rnm, X509_NAME_ENTRY_free); return -1; } @@ -308,9 +304,7 @@ static DIST_POINT *crldp_from_section(X509V3_CTX *ctx, return point; err: - if (point) { - DIST_POINT_free(point); - } + DIST_POINT_free(point); return NULL; } @@ -389,9 +383,7 @@ static int dpn_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, break; case ASN1_OP_FREE_POST: - if (dpn->dpname) { - X509_NAME_free(dpn->dpname); - } + X509_NAME_free(dpn->dpname); break; } return 1; diff --git a/crypto/x509v3/v3_ncons.c b/crypto/x509v3/v3_ncons.c index 55f4eed20f..967423aaf4 100644 --- a/crypto/x509v3/v3_ncons.c +++ b/crypto/x509v3/v3_ncons.c @@ -161,13 +161,8 @@ static void *v2i_NAME_CONSTRAINTS(const X509V3_EXT_METHOD *method, memerr: OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); err: - if (ncons) { - NAME_CONSTRAINTS_free(ncons); - } - if (sub) { - GENERAL_SUBTREE_free(sub); - } - + NAME_CONSTRAINTS_free(ncons); + GENERAL_SUBTREE_free(sub); return NULL; } diff --git a/crypto/x509v3/v3_utl.c b/crypto/x509v3/v3_utl.c index 16e0e076a3..3eccf069bc 100644 --- a/crypto/x509v3/v3_utl.c +++ b/crypto/x509v3/v3_utl.c @@ -158,15 +158,9 @@ void X509V3_conf_free(CONF_VALUE *conf) { if (!conf) { return; } - if (conf->name) { - OPENSSL_free(conf->name); - } - if (conf->value) { - OPENSSL_free(conf->value); - } - if (conf->section) { - OPENSSL_free(conf->section); - } + OPENSSL_free(conf->name); + OPENSSL_free(conf->value); + OPENSSL_free(conf->section); OPENSSL_free(conf); } @@ -551,9 +545,7 @@ unsigned char *x509v3_hex_to_bytes(const char *str, long *len) { return hexbuf; err: - if (hexbuf) { - OPENSSL_free(hexbuf); - } + OPENSSL_free(hexbuf); OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); return NULL; From d827600b68b29403f52d6f2e4d4553defa90ebcb Mon Sep 17 00:00:00 2001 From: Adam Langley Date: Mon, 4 Jul 2022 16:12:06 -0700 Subject: [PATCH 04/38] Add a CCM AEAD for Matter, the IoT standard. Change-Id: I8b1e4652d8d1445a6665af88d158e006ff3fdb20 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/53185 Reviewed-by: David Benjamin Commit-Queue: Adam Langley --- crypto/cipher_extra/aead_test.cc | 3 + .../test/aes_128_ccm_matter_tests.txt | 92 +++++++++++++++++++ crypto/fipsmodule/cipher/e_aesccm.c | 19 ++++ include/openssl/aead.h | 4 + sources.cmake | 1 + 5 files changed, 119 insertions(+) create mode 100644 crypto/cipher_extra/test/aes_128_ccm_matter_tests.txt diff --git a/crypto/cipher_extra/aead_test.cc b/crypto/cipher_extra/aead_test.cc index 6c6210da2f..506db26720 100644 --- a/crypto/cipher_extra/aead_test.cc +++ b/crypto/cipher_extra/aead_test.cc @@ -154,6 +154,9 @@ static const struct KnownAEAD kAEADs[] = { {"AES_128_CCM_BLUETOOTH_8", EVP_aead_aes_128_ccm_bluetooth_8, "aes_128_ccm_bluetooth_8_tests.txt", 0}, + + {"AES_128_CCM_Matter", EVP_aead_aes_128_ccm_matter, + "aes_128_ccm_matter_tests.txt", 0}, }; class PerAEADTest : public testing::TestWithParam { diff --git a/crypto/cipher_extra/test/aes_128_ccm_matter_tests.txt b/crypto/cipher_extra/test/aes_128_ccm_matter_tests.txt new file mode 100644 index 0000000000..7cff4fb005 --- /dev/null +++ b/crypto/cipher_extra/test/aes_128_ccm_matter_tests.txt @@ -0,0 +1,92 @@ +# These test vectors were derived from those found in +# the Bluetooth Mesh Profile Specification v1.0. That document doesn't use +# 16-byte tags, so the tags have been updated here. Note that the first four or +# eight bytes of the tag is not equal to the tag from those vectors because CCM +# authenticates the expected tag length. + +KEY: 0953fa93e7caac9638f58820220a398e +NONCE: 00800000011201000012345678 +IN: fffd034b50057e400000010000 +AD: +CT: b5e5bfdacbaf6cb7fb6bff871f +TAG: b0d6dd827d35bf372fa6425dcd17d356 + +# Section 8.3.2 +KEY: 0953fa93e7caac9638f58820220a398e +NONCE: 00800148202345000012345678 +IN: 120104320308ba072f +AD: +CT: 79d7dbc0c9b4d43eeb +TAG: 281508e50d58dbbd27c39597800f4733 + +# Section 8.3.3. +KEY: 0953fa93e7caac9638f58820220a398e +NONCE: 00802b38322fe3000012345678 +IN: 120104fa0205a6000a +AD: +CT: 53273086b8c5ee00bd +TAG: d52b87a8ce6290a772d472b8c62bdc13 + +# Section 8.3.4. +KEY: be635105434859f484fc798e043ce40e +NONCE: 00800000021201000012345678 +IN: 23450100 +AD: +CT: b0e5d0ad +TAG: 6078e0ddbb7cd43faea57c7051e5b4ae + +# Section 8.3.5. +KEY: be635105434859f484fc798e043ce40e +NONCE: 00800148342345000012345678 +IN: 120102001234567800 +AD: +CT: 5c39da1792b1fee9ec +TAG: a9233958aced64f2343b9d610e876440 + +# Section 8.3.7. +KEY: 0953fa93e7caac9638f58820220a398e +NONCE: 008b0148352345000012345678 +IN: 000300a6ac00000002 +AD: +CT: 0d0d730f94d7f3509d +TAG: dda1694adb791652fb6ae04682f19b29 + +# Section 8.3.9. +KEY: 0953fa93e7caac9638f58820220a398e +NONCE: 008b0148362345000012345678 +IN: 000300a6ac00000003 +AD: +CT: d85d806bbed248614f +TAG: ef7f4d55e47d21522ebe3d5bc735a5c5 + +# Section 8.3.10. +KEY: be635105434859f484fc798e043ce40e +NONCE: 00800000031201000012345678 +IN: 23450101 +AD: +CT: 7777ed35 +TAG: 35d84e18784c4bf3cb1b4c191dc555cc + +# Section 8.3.12. +KEY: be635105434859f484fc798e043ce40e +NONCE: 00800000041201000012345678 +IN: 23450101 +AD: +CT: ae214660 +TAG: d146b28beafe7f984f9430502d07aafe + +# Section 8.3.14. +KEY: be635105434859f484fc798e043ce40e +NONCE: 00800000051201000012345678 +IN: 23450100 +AD: +CT: 7d3ae62a +TAG: 52ee03ab84e1a33365e8a61275665f71 + +# Section 8.3.24. +KEY: 63964771734fbd76e3b40519d1d94a48 +NONCE: 010007080d1234973612345677 +IN: ea0a00576f726c64 +AD: f4a002c7fb1e4ca0a469a021de0db875 +CT: de1547118463123e +TAG: 14604c1ddb4f5987064b1736f3923962 diff --git a/crypto/fipsmodule/cipher/e_aesccm.c b/crypto/fipsmodule/cipher/e_aesccm.c index c9d52e0a5b..cd6170199c 100644 --- a/crypto/fipsmodule/cipher/e_aesccm.c +++ b/crypto/fipsmodule/cipher/e_aesccm.c @@ -432,3 +432,22 @@ DEFINE_METHOD_FUNCTION(EVP_AEAD, EVP_aead_aes_128_ccm_bluetooth_8) { out->seal_scatter = aead_aes_ccm_seal_scatter; out->open_gather = aead_aes_ccm_open_gather; } + +static int aead_aes_ccm_matter_init(EVP_AEAD_CTX *ctx, const uint8_t *key, + size_t key_len, size_t tag_len) { + return aead_aes_ccm_init(ctx, key, key_len, tag_len, 16, 2); +} + +DEFINE_METHOD_FUNCTION(EVP_AEAD, EVP_aead_aes_128_ccm_matter) { + memset(out, 0, sizeof(EVP_AEAD)); + + out->key_len = 16; + out->nonce_len = 13; + out->overhead = 16; + out->max_tag_len = 16; + + out->init = aead_aes_ccm_matter_init; + out->cleanup = aead_aes_ccm_cleanup; + out->seal_scatter = aead_aes_ccm_seal_scatter; + out->open_gather = aead_aes_ccm_open_gather; +} diff --git a/include/openssl/aead.h b/include/openssl/aead.h index 5486b4bbb3..131cfecd2a 100644 --- a/include/openssl/aead.h +++ b/include/openssl/aead.h @@ -180,6 +180,10 @@ OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_128_ccm_bluetooth(void); // v1.0. OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_128_ccm_bluetooth_8(void); +// EVP_aead_aes_128_ccm_matter is AES-128-CCM with M=16 and L=2 (16-byte tags +// and 13-byte nonces), as used in the Matter specification. +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_128_ccm_matter(void); + // EVP_has_aes_hardware returns one if we enable hardware support for fast and // constant-time AES-GCM. OPENSSL_EXPORT int EVP_has_aes_hardware(void); diff --git a/sources.cmake b/sources.cmake index 4cbc4c5db5..b3355a7d78 100644 --- a/sources.cmake +++ b/sources.cmake @@ -11,6 +11,7 @@ set( crypto/cipher_extra/test/aes_128_cbc_sha1_tls_tests.txt crypto/cipher_extra/test/aes_128_ccm_bluetooth_tests.txt crypto/cipher_extra/test/aes_128_ccm_bluetooth_8_tests.txt + crypto/cipher_extra/test/aes_128_ccm_matter_tests.txt crypto/cipher_extra/test/aes_128_ctr_hmac_sha256.txt crypto/cipher_extra/test/aes_128_gcm_randnonce_tests.txt crypto/cipher_extra/test/aes_128_gcm_siv_tests.txt From 17d637da0888a32d93f3d4ca2c4eefd693331e54 Mon Sep 17 00:00:00 2001 From: Adam Langley Date: Wed, 22 Jun 2022 20:51:26 +0000 Subject: [PATCH 05/38] Drop stdout when looking for abort messages Since stdout and stderr aren't synchronised, grepping their combined output can sometimes fail since the regexp is looking for the start of a line. Better to discard the stdout, which always works. Change-Id: I5d0331debfe4b3eddc628c1fecc9c6b83d462a7a Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/53106 Reviewed-by: David Benjamin --- util/fipstools/test-break-kat.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/util/fipstools/test-break-kat.sh b/util/fipstools/test-break-kat.sh index d2c44a7a7a..141e73fe2b 100644 --- a/util/fipstools/test-break-kat.sh +++ b/util/fipstools/test-break-kat.sh @@ -32,7 +32,8 @@ KATS=$(go run util/fipstools/break-kat.go --list-tests) for kat in $KATS; do go run util/fipstools/break-kat.go $TEST_FIPS_BIN $kat > break-kat-bin chmod u+x ./break-kat-bin - if ! (./break-kat-bin 2>&1 || true) | egrep -q "^$kat[^a-zA-Z0-9]"; then + if ! (./break-kat-bin 2>&1 >/dev/null || true) | \ + egrep -q "^$kat[^a-zA-Z0-9]"; then echo "Failure for $kat did not mention that name in the output" exit 1 fi From 28c5354806248f9882eba0a8ad8d63c436018037 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Wed, 6 Jul 2022 15:45:42 -0400 Subject: [PATCH 06/38] Accept invalid "v3" CSRs. Although not defined, older versions of certbot use numeric value 2, which would be a hypothetical v3(2). See https://github.com/certbot/certbot/pull/9334. Accept these for compatibility. Bug: 467 Change-Id: I47cc64503569992595bdb42baa6333058d560242 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/53229 Reviewed-by: Bob Beck Reviewed-by: Adam Langley --- crypto/x509/t_req.c | 4 +++- crypto/x509/x509_test.cc | 15 +++++++++++++++ crypto/x509/x_req.c | 6 +++++- include/openssl/x509.h | 4 +++- 4 files changed, 26 insertions(+), 3 deletions(-) diff --git a/crypto/x509/t_req.c b/crypto/x509/t_req.c index b9090b9253..154fb75bc7 100644 --- a/crypto/x509/t_req.c +++ b/crypto/x509/t_req.c @@ -105,7 +105,9 @@ int X509_REQ_print_ex(BIO *bio, X509_REQ *x, unsigned long nmflags, } if (!(cflag & X509_FLAG_NO_VERSION)) { l = X509_REQ_get_version(x); - assert(l == X509_REQ_VERSION_1); + // Only zero, |X509_REQ_VERSION_1|, is valid but our parser accepts some + // invalid values for compatibility. + assert(0 <= l && l <= 2); if (BIO_printf(bio, "%8sVersion: %ld (0x%lx)\n", "", l + 1, (unsigned long)l) <= 0) { goto err; diff --git a/crypto/x509/x509_test.cc b/crypto/x509/x509_test.cc index fe4a775fdb..425d74541f 100644 --- a/crypto/x509/x509_test.cc +++ b/crypto/x509/x509_test.cc @@ -2936,6 +2936,17 @@ rsn4lSYsqI4OI4ei -----END CERTIFICATE REQUEST----- )"; +// kV3CSRPEM is a v3 CSR. CSR versions only go up to v1. +static const char kV3CSRPEM[] = R"( +-----BEGIN CERTIFICATE REQUEST----- +MIHJMHECAQIwDzENMAsGA1UEAwwEVGVzdDBZMBMGByqGSM49AgEGCCqGSM49AwEH +A0IABJjsayyAQod1J7UJYNT8AH4WWxLdKV0ozhrIz6hCzBAze7AqXWOSH8G+1EWC +pSfL3oMQNtBdJS0kpXXaUqEAgTSgADAKBggqhkjOPQQDAgNIADBFAiAUXVaEYATg +4Cc917T73KBImxh6xyhsA5pKuYpq1S4m9wIhAK+G93HR4ur7Ghel6+zUTvIAsj9e +rsn4lSYsqI4OI4ei +-----END CERTIFICATE REQUEST----- +)"; + // Test that the library enforces versions are valid and match the fields // present. TEST(X509Test, InvalidVersion) { @@ -2955,6 +2966,10 @@ TEST(X509Test, InvalidVersion) { EXPECT_FALSE(CRLFromPEM(kV3CRLPEM)); EXPECT_FALSE(CSRFromPEM(kV2CSRPEM)); + // kV3CSRPEM is invalid but, for now, we accept it. See + // https://github.com/certbot/certbot/pull/9334 + EXPECT_TRUE(CSRFromPEM(kV3CSRPEM)); + bssl::UniquePtr x509(X509_new()); ASSERT_TRUE(x509); EXPECT_FALSE(X509_set_version(x509.get(), -1)); diff --git a/crypto/x509/x_req.c b/crypto/x509/x_req.c index 4ddeaea1ca..f7faf39252 100644 --- a/crypto/x509/x_req.c +++ b/crypto/x509/x_req.c @@ -82,7 +82,11 @@ static int rinf_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, } if (operation == ASN1_OP_D2I_POST) { - if (ASN1_INTEGER_get(rinf->version) != X509_REQ_VERSION_1) { + // The only defined CSR version is v1(0). For compatibility, we also accept + // a hypothetical v3(2). Although not defined, older versions of certbot + // use it. See https://github.com/certbot/certbot/pull/9334. + long version = ASN1_INTEGER_get(rinf->version); + if (version != X509_REQ_VERSION_1 && version != 2) { OPENSSL_PUT_ERROR(X509, X509_R_INVALID_VERSION); return 0; } diff --git a/include/openssl/x509.h b/include/openssl/x509.h index 945355f879..526765f580 100644 --- a/include/openssl/x509.h +++ b/include/openssl/x509.h @@ -396,7 +396,9 @@ OPENSSL_EXPORT long X509_get_pathlen(X509 *x509); #define X509_REQ_VERSION_1 0 // X509_REQ_get_version returns the numerical value of |req|'s version. This -// will always be |X509_REQ_VERSION_1|. +// will always be |X509_REQ_VERSION_1| for valid CSRs. For compatibility, +// |d2i_X509_REQ| also accepts some invalid version numbers, in which case this +// function may return other values. OPENSSL_EXPORT long X509_REQ_get_version(const X509_REQ *req); // X509_REQ_get_subject_name returns |req|'s subject name. Note this function is From e7681d1a788d31a30b714b9688b29074645b096d Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Mon, 4 Jul 2022 16:59:11 -0400 Subject: [PATCH 07/38] Rewrite scalar operations in spake25519.c with BN_ULONG This reuses code we already have, and also avoids another union. Bug: 301 Change-Id: I2f4ab564cf220818ca96d9c99a122c1e5cdc9e7a Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/53228 Reviewed-by: Adam Langley --- crypto/curve25519/spake25519.c | 49 ++++++++++++---------------------- 1 file changed, 17 insertions(+), 32 deletions(-) diff --git a/crypto/curve25519/spake25519.c b/crypto/curve25519/spake25519.c index f750911417..c45d15a58d 100644 --- a/crypto/curve25519/spake25519.c +++ b/crypto/curve25519/spake25519.c @@ -22,6 +22,7 @@ #include #include +#include "../fipsmodule/bn/internal.h" #include "../internal.h" #include "./internal.h" @@ -314,46 +315,30 @@ static void left_shift_3(uint8_t n[32]) { } } -typedef union { - uint8_t bytes[32]; - uint32_t words[8]; +typedef struct { + BN_ULONG words[32 / sizeof(BN_ULONG)]; } scalar; -// kOrder is the order of the prime-order subgroup of curve25519 in -// little-endian order. -static const scalar kOrder = {{0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, - 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}}; +// kOrder is the order of the prime-order subgroup of curve25519. +static const scalar kOrder = { + {TOBN(0x5812631a, 0x5cf5d3ed), TOBN(0x14def9de, 0xa2f79cd6), + TOBN(0x00000000, 0x00000000), TOBN(0x10000000, 0x00000000)}}; // scalar_cmov copies |src| to |dest| if |mask| is all ones. static void scalar_cmov(scalar *dest, const scalar *src, crypto_word_t mask) { - for (size_t i = 0; i < 8; i++) { - dest->words[i] = - constant_time_select_w(mask, src->words[i], dest->words[i]); - } + bn_select_words(dest->words, mask, src->words, dest->words, + OPENSSL_ARRAY_SIZE(dest->words)); } // scalar_double sets |s| to |2×s|. static void scalar_double(scalar *s) { - uint32_t carry = 0; - - for (size_t i = 0; i < 8; i++) { - const uint32_t carry_out = s->words[i] >> 31; - s->words[i] = (s->words[i] << 1) | carry; - carry = carry_out; - } + bn_add_words(s->words, s->words, s->words, OPENSSL_ARRAY_SIZE(s->words)); } // scalar_add sets |dest| to |dest| plus |src|. static void scalar_add(scalar *dest, const scalar *src) { - uint32_t carry = 0; - - for (size_t i = 0; i < 8; i++) { - uint64_t tmp = ((uint64_t)dest->words[i] + src->words[i]) + carry; - dest->words[i] = (uint32_t)tmp; - carry = (uint32_t)(tmp >> 32); - } + bn_add_words(dest->words, dest->words, src->words, + OPENSSL_ARRAY_SIZE(dest->words)); } int SPAKE2_generate_msg(SPAKE2_CTX *ctx, uint8_t *out, size_t *out_len, @@ -412,25 +397,25 @@ int SPAKE2_generate_msg(SPAKE2_CTX *ctx, uint8_t *out, size_t *out_len, OPENSSL_memset(&tmp, 0, sizeof(tmp)); scalar_cmov(&tmp, &order, - constant_time_eq_w(password_scalar.bytes[0] & 1, 1)); + constant_time_eq_w(password_scalar.words[0] & 1, 1)); scalar_add(&password_scalar, &tmp); scalar_double(&order); OPENSSL_memset(&tmp, 0, sizeof(tmp)); scalar_cmov(&tmp, &order, - constant_time_eq_w(password_scalar.bytes[0] & 2, 2)); + constant_time_eq_w(password_scalar.words[0] & 2, 2)); scalar_add(&password_scalar, &tmp); scalar_double(&order); OPENSSL_memset(&tmp, 0, sizeof(tmp)); scalar_cmov(&tmp, &order, - constant_time_eq_w(password_scalar.bytes[0] & 4, 4)); + constant_time_eq_w(password_scalar.words[0] & 4, 4)); scalar_add(&password_scalar, &tmp); - assert((password_scalar.bytes[0] & 7) == 0); + assert((password_scalar.words[0] & 7) == 0); } - OPENSSL_memcpy(ctx->password_scalar, password_scalar.bytes, + OPENSSL_memcpy(ctx->password_scalar, password_scalar.words, sizeof(ctx->password_scalar)); ge_p3 mask; From 507daf391d1f973cd5226d01361bb4eec9e14766 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Thu, 23 Jun 2022 00:55:22 -0400 Subject: [PATCH 08/38] Check Unicode string encodings in crypto/asn1. This checks validity for UTF8String, BMPString, and UniversalString. When we detach the core types from ASN1_ITEM, this will likely also be reshuffled around, probably into type-specific functions. But for now just get the checks in place. Update-Note: Invalid strings in X.509 certificates and other ASN.1 structures will now be rejected. This change is less risky than it seems because most strings in X.509 are in X509_NAME, which already rejected invalid instances of these string types (but not other string types) during canonicalization. See https://crbug.com/boringssl/412 for a discussion of that mess. Bug: 427 Change-Id: I0d7e24dfd841703d2a8581ec4e78ed5bc3862d75 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/53225 Commit-Queue: David Benjamin Reviewed-by: Adam Langley --- crypto/asn1/asn1_test.cc | 69 ++++++++++++++++++++++++++++++++++++++++ crypto/asn1/tasn_dec.c | 43 ++++++++++++++++++------- 2 files changed, 101 insertions(+), 11 deletions(-) diff --git a/crypto/asn1/asn1_test.cc b/crypto/asn1/asn1_test.cc index 442c1eabbf..195d5a89d3 100644 --- a/crypto/asn1/asn1_test.cc +++ b/crypto/asn1/asn1_test.cc @@ -2175,6 +2175,75 @@ TEST(ASN1Test, ZeroTag) { 0x04, 0x01, 0x84, 0xb7, 0x09, 0x01, 0x00, 0x01, 0x61}); } +TEST(ASN1Test, StringEncoding) { + const struct { + ASN1_STRING *(*d2i)(ASN1_STRING **out, const uint8_t **inp, long len); + std::vector in; + bool valid; + } kTests[] = { + // All OCTET STRINGs are valid. + {d2i_ASN1_OCTET_STRING, {0x04, 0x00}, true}, + {d2i_ASN1_OCTET_STRING, {0x04, 0x01, 0x00}, true}, + + // UTF8String must be valid UTF-8. + {d2i_ASN1_UTF8STRING, {0x0c, 0x00}, true}, + {d2i_ASN1_UTF8STRING, {0x0c, 0x01, 'a'}, true}, + {d2i_ASN1_UTF8STRING, {0x0c, 0x03, 0xe2, 0x98, 0x83}, true}, + // Non-minimal, two-byte UTF-8. + {d2i_ASN1_UTF8STRING, {0x0c, 0x02, 0xc0, 0x81}, false}, + // Truncated, four-byte UTF-8. + {d2i_ASN1_UTF8STRING, {0x0c, 0x03, 0xf0, 0x80, 0x80}, false}, + // Low-surrogate value. + {d2i_ASN1_UTF8STRING, {0x0c, 0x03, 0xed, 0xa0, 0x80}, false}, + // High-surrogate value. + {d2i_ASN1_UTF8STRING, {0x0c, 0x03, 0xed, 0xb0, 0x81}, false}, + + // BMPString must be valid UCS-2. + {d2i_ASN1_BMPSTRING, {0x1e, 0x00}, true}, + {d2i_ASN1_BMPSTRING, {0x1e, 0x02, 0x00, 'a'}, true}, + // Truncated code unit. + {d2i_ASN1_BMPSTRING, {0x1e, 0x01, 'a'}, false}, + // Lone surrogate. + {d2i_ASN1_BMPSTRING, {0x1e, 0x02, 0xd8, 0}, false}, + // BMPString is UCS-2, not UTF-16, so surrogate pairs are also invalid. + {d2i_ASN1_BMPSTRING, {0x1e, 0x04, 0xd8, 0, 0xdc, 1}, false}, + + // UniversalString must be valid UTF-32. + {d2i_ASN1_UNIVERSALSTRING, {0x1c, 0x00}, true}, + {d2i_ASN1_UNIVERSALSTRING, {0x1c, 0x04, 0x00, 0x00, 0x00, 'a'}, true}, + // Maximum code point. + {d2i_ASN1_UNIVERSALSTRING, {0x1c, 0x04, 0x00, 0x10, 0xff, 0xfd}, true}, + // Reserved. + {d2i_ASN1_UNIVERSALSTRING, {0x1c, 0x04, 0x00, 0x10, 0xff, 0xfe}, false}, + {d2i_ASN1_UNIVERSALSTRING, {0x1c, 0x04, 0x00, 0x10, 0xff, 0xff}, false}, + // Too high. + {d2i_ASN1_UNIVERSALSTRING, {0x1c, 0x04, 0x00, 0x11, 0x00, 0x00}, false}, + // Surrogates are not characters. + {d2i_ASN1_UNIVERSALSTRING, {0x1c, 0x04, 0x00, 0x00, 0xd8, 0}, false}, + // Truncated codepoint. + {d2i_ASN1_UNIVERSALSTRING, {0x1c, 0x03, 0x00, 0x00, 0x00}, false}, + + // We interpret T61String as Latin-1, so all inputs are valid. + {d2i_ASN1_T61STRING, {0x14, 0x00}, true}, + {d2i_ASN1_T61STRING, {0x14, 0x01, 0x00}, true}, + }; + for (const auto& t : kTests) { + SCOPED_TRACE(Bytes(t.in)); + const uint8_t *inp; + + if (t.d2i != nullptr) { + inp = t.in.data(); + bssl::UniquePtr str(t.d2i(nullptr, &inp, t.in.size())); + EXPECT_EQ(t.valid, str != nullptr); + } + + // Also test with the ANY parser. + inp = t.in.data(); + bssl::UniquePtr any(d2i_ASN1_TYPE(nullptr, &inp, t.in.size())); + EXPECT_EQ(t.valid, any != nullptr); + } +} + // 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) diff --git a/crypto/asn1/tasn_dec.c b/crypto/asn1/tasn_dec.c index c855fe5291..de8779171f 100644 --- a/crypto/asn1/tasn_dec.c +++ b/crypto/asn1/tasn_dec.c @@ -63,6 +63,7 @@ #include #include +#include "../bytestring/internal.h" #include "../internal.h" #include "internal.h" @@ -797,32 +798,51 @@ static int asn1_ex_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len, case V_ASN1_OTHER: case V_ASN1_SET: case V_ASN1_SEQUENCE: - default: - if (utype == V_ASN1_BMPSTRING && (len & 1)) { - OPENSSL_PUT_ERROR(ASN1, ASN1_R_BMPSTRING_IS_WRONG_LENGTH); - goto err; + default: { + CBS cbs; + CBS_init(&cbs, cont, (size_t)len); + if (utype == V_ASN1_BMPSTRING) { + while (CBS_len(&cbs) != 0) { + uint32_t c; + if (!cbs_get_ucs2_be(&cbs, &c)) { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_BMPSTRING); + goto err; + } + } } - if (utype == V_ASN1_UNIVERSALSTRING && (len & 3)) { - OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNIVERSALSTRING_IS_WRONG_LENGTH); - goto err; + if (utype == V_ASN1_UNIVERSALSTRING) { + while (CBS_len(&cbs) != 0) { + uint32_t c; + if (!cbs_get_utf32_be(&cbs, &c)) { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_UNIVERSALSTRING); + goto err; + } + } + } + if (utype == V_ASN1_UTF8STRING) { + while (CBS_len(&cbs) != 0) { + uint32_t c; + if (!cbs_get_utf8(&cbs, &c)) { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_UTF8STRING); + goto err; + } + } } if (utype == V_ASN1_UTCTIME) { - CBS cbs; - CBS_init(&cbs, cont, (size_t)len); if (!CBS_parse_utc_time(&cbs, NULL, /*allow_timezone_offset=*/1)) { OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_TIME_FORMAT); goto err; } } if (utype == V_ASN1_GENERALIZEDTIME) { - CBS cbs; - CBS_init(&cbs, cont, (size_t)len); if (!CBS_parse_generalized_time(&cbs, NULL, /*allow_timezone_offset=*/0)) { OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_TIME_FORMAT); goto err; } } + // TODO(https://crbug.com/boringssl/427): Check other string types. + // All based on ASN1_STRING and handled the same if (!*pval) { stmp = ASN1_STRING_type_new(utype); @@ -842,6 +862,7 @@ static int asn1_ex_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len, goto err; } break; + } } // If ASN1_ANY and NULL type fix up value if (typ && (utype == V_ASN1_NULL)) { From 695b2e1d566c4612714b23e8f1e283926379a8c3 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Thu, 23 Jun 2022 16:38:15 -0400 Subject: [PATCH 09/38] Check for invalid UCS-2 and UTF-32 in ASN1_STRING_print_ex. Switch to the CBS functions, which do all the checks together. This resolves a TODO that ASN1_STRING_print_ex was inconsistently checking for invalid codepoints. It also removes an optimization when round-tripping UTF-8. This optimization was incorrect if the input was invalid. Finally, this removes UTF8_getc, which no longer has any callers. (I've left UTF8_putc for now because CBB would force a malloc on every character, even with CBB_init_fixed. We should either decide we don't care, or make it possible to stack-allocate the cbb_buffer_st.) Update-Note: This will make ASN1_STRING_print_ex newly fail, but such inputs should be unreachable from the parser as of an earlier change. Change-Id: I52d747c500c6f5f9ef659cdee3ef5d241f38ed21 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/53226 Commit-Queue: David Benjamin Reviewed-by: Adam Langley --- crypto/asn1/a_strex.c | 101 ++++++++++++------------------------- crypto/asn1/a_utf8.c | 106 --------------------------------------- crypto/asn1/asn1_test.cc | 14 +++++- crypto/asn1/internal.h | 1 - 4 files changed, 44 insertions(+), 178 deletions(-) diff --git a/crypto/asn1/a_strex.c b/crypto/asn1/a_strex.c index e6aacf06f0..fd08b02fe3 100644 --- a/crypto/asn1/a_strex.c +++ b/crypto/asn1/a_strex.c @@ -66,6 +66,7 @@ #include #include +#include "../bytestring/internal.h" #include "internal.h" @@ -129,70 +130,46 @@ static int do_esc_char(uint32_t c, unsigned long flags, char *do_quotes, // appropriate. static int do_buf(const unsigned char *buf, int buflen, int encoding, - int utf8_convert, unsigned long flags, char *quotes, - BIO *out) { - // Reject invalid UCS-4 and UCS-2 lengths without parsing. + unsigned long flags, char *quotes, BIO *out) { + int (*get_char)(CBS *cbs, uint32_t *out); + int get_char_error; switch (encoding) { case MBSTRING_UNIV: - if (buflen & 3) { - OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_UNIVERSALSTRING); - return -1; - } + get_char = cbs_get_utf32_be; + get_char_error = ASN1_R_INVALID_UNIVERSALSTRING; break; case MBSTRING_BMP: - if (buflen & 1) { - OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_BMPSTRING); - return -1; - } + get_char = cbs_get_ucs2_be; + get_char_error = ASN1_R_INVALID_BMPSTRING; + break; + case MBSTRING_ASC: + get_char = cbs_get_latin1; + get_char_error = ERR_R_INTERNAL_ERROR; // Should not be possible. break; + case MBSTRING_UTF8: + get_char = cbs_get_utf8; + get_char_error = ASN1_R_INVALID_UTF8STRING; + break; + default: + assert(0); + return -1; } - const unsigned char *p = buf; - const unsigned char *q = buf + buflen; + CBS cbs; + CBS_init(&cbs, buf, buflen); int outlen = 0; - while (p != q) { - const int is_first = p == buf; - // TODO(davidben): Replace this with |cbs_get_ucs2_be|, etc., to check - // for invalid codepoints. Before doing that, enforce it in the parser, - // https://crbug.com/boringssl/427, so these error cases are not - // reachable from parsed objects. + while (CBS_len(&cbs) != 0) { + const int is_first = CBS_data(&cbs) == buf; uint32_t c; - switch (encoding) { - case MBSTRING_UNIV: - c = ((uint32_t)*p++) << 24; - c |= ((uint32_t)*p++) << 16; - c |= ((uint32_t)*p++) << 8; - c |= *p++; - break; - - case MBSTRING_BMP: - c = ((uint32_t)*p++) << 8; - c |= *p++; - break; - - case MBSTRING_ASC: - c = *p++; - break; - - case MBSTRING_UTF8: { - int consumed = UTF8_getc(p, buflen, &c); - if (consumed < 0) { - return -1; // Invalid UTF8String - } - buflen -= consumed; - p += consumed; - break; - } - - default: - assert(0); - return -1; + if (!get_char(&cbs, &c)) { + OPENSSL_PUT_ERROR(ASN1, get_char_error); + return -1; } - const int is_last = p == q; - if (utf8_convert) { + const int is_last = CBS_len(&cbs) == 0; + if (flags & ASN1_STRFLGS_UTF8_CONVERT) { unsigned char utfbuf[6]; int utflen; - utflen = UTF8_putc(utfbuf, sizeof utfbuf, c); + utflen = UTF8_putc(utfbuf, sizeof(utfbuf), c); for (int i = 0; i < utflen; i++) { int len = do_esc_char(utfbuf[i], flags, quotes, out, is_first && i == 0, is_last && i == utflen - 1); @@ -350,24 +327,9 @@ int ASN1_STRING_print_ex(BIO *out, const ASN1_STRING *str, return outlen; } - int utf8_convert = 0; - if (flags & ASN1_STRFLGS_UTF8_CONVERT) { - // If the string is UTF-8, skip decoding and just interpret it as 1 byte - // per character to avoid converting twice. - // - // TODO(davidben): This is not quite a valid optimization if the input - // was invalid UTF-8. - if (encoding == MBSTRING_UTF8) { - encoding = MBSTRING_ASC; - } else { - utf8_convert = 1; - } - } - // Measure the length. char quotes = 0; - int len = do_buf(str->data, str->length, encoding, utf8_convert, flags, - "es, NULL); + int len = do_buf(str->data, str->length, encoding, flags, "es, NULL); if (len < 0) { return -1; } @@ -381,8 +343,7 @@ int ASN1_STRING_print_ex(BIO *out, const ASN1_STRING *str, // Encode the value. if ((quotes && !maybe_write(out, "\"", 1)) || - do_buf(str->data, str->length, encoding, utf8_convert, flags, NULL, out) < - 0 || + do_buf(str->data, str->length, encoding, flags, NULL, out) < 0 || (quotes && !maybe_write(out, "\"", 1))) { return -1; } diff --git a/crypto/asn1/a_utf8.c b/crypto/asn1/a_utf8.c index 58496b2587..02c1d56c66 100644 --- a/crypto/asn1/a_utf8.c +++ b/crypto/asn1/a_utf8.c @@ -63,112 +63,6 @@ // UTF8 utilities -// This parses a UTF8 string one character at a time. It is passed a pointer -// to the string and the length of the string. It sets 'value' to the value -// of the current character. It returns the number of characters read or a -// negative error code: -1 = string too short -2 = illegal character -3 = -// subsequent characters not of the form 10xxxxxx -4 = character encoded -// incorrectly (not minimal length). - -int UTF8_getc(const unsigned char *str, int len, uint32_t *val) { - const unsigned char *p; - uint32_t value; - int ret; - if (len <= 0) { - return 0; - } - p = str; - - // Check syntax and work out the encoded value (if correct) - if ((*p & 0x80) == 0) { - value = *p++ & 0x7f; - ret = 1; - } else if ((*p & 0xe0) == 0xc0) { - if (len < 2) { - return -1; - } - if ((p[1] & 0xc0) != 0x80) { - return -3; - } - value = (*p++ & 0x1f) << 6; - value |= *p++ & 0x3f; - if (value < 0x80) { - return -4; - } - ret = 2; - } else if ((*p & 0xf0) == 0xe0) { - if (len < 3) { - return -1; - } - if (((p[1] & 0xc0) != 0x80) || ((p[2] & 0xc0) != 0x80)) { - return -3; - } - value = (*p++ & 0xf) << 12; - value |= (*p++ & 0x3f) << 6; - value |= *p++ & 0x3f; - if (value < 0x800) { - return -4; - } - ret = 3; - } else if ((*p & 0xf8) == 0xf0) { - if (len < 4) { - return -1; - } - if (((p[1] & 0xc0) != 0x80) || ((p[2] & 0xc0) != 0x80) || - ((p[3] & 0xc0) != 0x80)) { - return -3; - } - value = ((uint32_t)(*p++ & 0x7)) << 18; - value |= (*p++ & 0x3f) << 12; - value |= (*p++ & 0x3f) << 6; - value |= *p++ & 0x3f; - if (value < 0x10000) { - return -4; - } - ret = 4; - } else if ((*p & 0xfc) == 0xf8) { - if (len < 5) { - return -1; - } - if (((p[1] & 0xc0) != 0x80) || ((p[2] & 0xc0) != 0x80) || - ((p[3] & 0xc0) != 0x80) || ((p[4] & 0xc0) != 0x80)) { - return -3; - } - value = ((uint32_t)(*p++ & 0x3)) << 24; - value |= ((uint32_t)(*p++ & 0x3f)) << 18; - value |= ((uint32_t)(*p++ & 0x3f)) << 12; - value |= (*p++ & 0x3f) << 6; - value |= *p++ & 0x3f; - if (value < 0x200000) { - return -4; - } - ret = 5; - } else if ((*p & 0xfe) == 0xfc) { - if (len < 6) { - return -1; - } - if (((p[1] & 0xc0) != 0x80) || ((p[2] & 0xc0) != 0x80) || - ((p[3] & 0xc0) != 0x80) || ((p[4] & 0xc0) != 0x80) || - ((p[5] & 0xc0) != 0x80)) { - return -3; - } - value = ((uint32_t)(*p++ & 0x1)) << 30; - value |= ((uint32_t)(*p++ & 0x3f)) << 24; - value |= ((uint32_t)(*p++ & 0x3f)) << 18; - value |= ((uint32_t)(*p++ & 0x3f)) << 12; - value |= (*p++ & 0x3f) << 6; - value |= *p++ & 0x3f; - if (value < 0x4000000) { - return -4; - } - ret = 6; - } else { - return -2; - } - *val = value; - return ret; -} - // This takes a character 'value' and writes the UTF8 encoded value in 'str' // where 'str' is a buffer containing 'len' characters. Returns the number of // characters written or -1 if 'len' is too small. 'str' can be set to NULL diff --git a/crypto/asn1/asn1_test.cc b/crypto/asn1/asn1_test.cc index 195d5a89d3..9df309a5e8 100644 --- a/crypto/asn1/asn1_test.cc +++ b/crypto/asn1/asn1_test.cc @@ -1278,11 +1278,23 @@ TEST(ASN1Test, StringPrintEx) { int str_flags; unsigned long flags; } kUnprintableTests[] = { - // When decoding strings, invalid codepoints are errors. + // It is an error if the string cannot be decoded. {V_ASN1_UTF8STRING, {0xff}, 0, ASN1_STRFLGS_ESC_MSB}, {V_ASN1_BMPSTRING, {0xff}, 0, ASN1_STRFLGS_ESC_MSB}, {V_ASN1_BMPSTRING, {0xff}, 0, ASN1_STRFLGS_ESC_MSB}, {V_ASN1_UNIVERSALSTRING, {0xff}, 0, ASN1_STRFLGS_ESC_MSB}, + // Invalid codepoints are errors. + {V_ASN1_UTF8STRING, {0xed, 0xa0, 0x80}, 0, ASN1_STRFLGS_ESC_MSB}, + {V_ASN1_BMPSTRING, {0xd8, 0x00}, 0, ASN1_STRFLGS_ESC_MSB}, + {V_ASN1_UNIVERSALSTRING, + {0x00, 0x00, 0xd8, 0x00}, + 0, + ASN1_STRFLGS_ESC_MSB}, + // Even when re-encoding UTF-8 back into UTF-8, we should check validity. + {V_ASN1_UTF8STRING, + {0xff}, + 0, + ASN1_STRFLGS_ESC_MSB | ASN1_STRFLGS_UTF8_CONVERT}, }; for (const auto &t : kUnprintableTests) { SCOPED_TRACE(t.type); diff --git a/crypto/asn1/internal.h b/crypto/asn1/internal.h index 9c0d73e79f..f8ca8fe11a 100644 --- a/crypto/asn1/internal.h +++ b/crypto/asn1/internal.h @@ -133,7 +133,6 @@ OPENSSL_EXPORT int asn1_generalizedtime_to_tm(struct tm *tm, void asn1_item_combine_free(ASN1_VALUE **pval, const ASN1_ITEM *it, int combine); -int UTF8_getc(const unsigned char *str, int len, uint32_t *val); int UTF8_putc(unsigned char *str, int len, uint32_t value); int ASN1_item_ex_new(ASN1_VALUE **pval, const ASN1_ITEM *it); From f2029899b2c1dcf3e3120876794da088f42ad351 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Sat, 25 Jun 2022 23:26:24 -0400 Subject: [PATCH 10/38] Tidy up ASN1_GENERALIZEDTIME_adj and ASN1_UTCTIME_adj. ASN1_STRING_set saves having to manually manage the ASN1_STRING's buffer. Also size that buffer correctly and align the free_s vs tmps mismatch. We can also assume OPENSSL_gmtime writes to the passed-in struct tm. Every other caller already assumes this, and both POSIX (gmtime_r) and C (gmtime_s) agree this is valid. Finally, the cleanup logic is much simpler if we do all the time stuff before handling the maybe-object-reuse bits. Change-Id: I25befc8fa93a1a60246c6abcea6e5d58ee563b48 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/53227 Reviewed-by: Adam Langley Commit-Queue: David Benjamin --- crypto/asn1/a_gentm.c | 61 ++++++++++++++++-------------------------- crypto/asn1/a_utctm.c | 62 ++++++++++++++++--------------------------- 2 files changed, 46 insertions(+), 77 deletions(-) diff --git a/crypto/asn1/a_gentm.c b/crypto/asn1/a_gentm.c index e31ac1d0be..283ff7d349 100644 --- a/crypto/asn1/a_gentm.c +++ b/crypto/asn1/a_gentm.c @@ -107,57 +107,42 @@ ASN1_GENERALIZEDTIME *ASN1_GENERALIZEDTIME_set(ASN1_GENERALIZEDTIME *s, ASN1_GENERALIZEDTIME *ASN1_GENERALIZEDTIME_adj(ASN1_GENERALIZEDTIME *s, time_t t, int offset_day, long offset_sec) { - char *p; - struct tm *ts; struct tm data; - size_t len = 20; - ASN1_GENERALIZEDTIME *tmps = NULL; - - if (s == NULL) { - tmps = ASN1_GENERALIZEDTIME_new(); - } else { - tmps = s; - } - if (tmps == NULL) { + if (!OPENSSL_gmtime(&t, &data)) { return NULL; } - ts = OPENSSL_gmtime(&t, &data); - if (ts == NULL) { - goto err; - } - if (offset_day || offset_sec) { - if (!OPENSSL_gmtime_adj(ts, offset_day, offset_sec)) { - goto err; + if (!OPENSSL_gmtime_adj(&data, offset_day, offset_sec)) { + return NULL; } } - if (ts->tm_year < 0 - 1900 || ts->tm_year > 9999 - 1900) { + if (data.tm_year < 0 - 1900 || data.tm_year > 9999 - 1900) { OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_TIME_VALUE); - goto err; + return NULL; } - p = (char *)tmps->data; - if ((p == NULL) || ((size_t)tmps->length < len)) { - p = OPENSSL_malloc(len); - if (p == NULL) { - OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); - goto err; + char buf[16]; + BIO_snprintf(buf, sizeof(buf), "%04d%02d%02d%02d%02d%02dZ", + data.tm_year + 1900, data.tm_mon + 1, data.tm_mday, data.tm_hour, + data.tm_min, data.tm_sec); + + int free_s = 0; + if (s == NULL) { + free_s = 1; + s = ASN1_UTCTIME_new(); + if (s == NULL) { + return NULL; } - OPENSSL_free(tmps->data); - tmps->data = (unsigned char *)p; } - BIO_snprintf(p, len, "%04d%02d%02d%02d%02d%02dZ", ts->tm_year + 1900, - ts->tm_mon + 1, ts->tm_mday, ts->tm_hour, ts->tm_min, - ts->tm_sec); - tmps->length = strlen(p); - tmps->type = V_ASN1_GENERALIZEDTIME; - return tmps; -err: - if (s == NULL) { - ASN1_GENERALIZEDTIME_free(tmps); + if (!ASN1_STRING_set(s, buf, strlen(buf))) { + if (free_s) { + ASN1_UTCTIME_free(s); + } + return NULL; } - return NULL; + s->type = V_ASN1_GENERALIZEDTIME; + return s; } diff --git a/crypto/asn1/a_utctm.c b/crypto/asn1/a_utctm.c index ac548ddd39..ac6b598483 100644 --- a/crypto/asn1/a_utctm.c +++ b/crypto/asn1/a_utctm.c @@ -105,59 +105,43 @@ ASN1_UTCTIME *ASN1_UTCTIME_set(ASN1_UTCTIME *s, time_t t) { ASN1_UTCTIME *ASN1_UTCTIME_adj(ASN1_UTCTIME *s, time_t t, int offset_day, long offset_sec) { - char *p; - struct tm *ts; struct tm data; - size_t len = 20; - int free_s = 0; - - if (s == NULL) { - free_s = 1; - s = ASN1_UTCTIME_new(); - } - if (s == NULL) { - goto err; - } - - ts = OPENSSL_gmtime(&t, &data); - if (ts == NULL) { - goto err; + if (!OPENSSL_gmtime(&t, &data)) { + return NULL; } if (offset_day || offset_sec) { - if (!OPENSSL_gmtime_adj(ts, offset_day, offset_sec)) { - goto err; + if (!OPENSSL_gmtime_adj(&data, offset_day, offset_sec)) { + return NULL; } } - if ((ts->tm_year < 50) || (ts->tm_year >= 150)) { - goto err; + if (data.tm_year < 50 || data.tm_year >= 150) { + return NULL; } - p = (char *)s->data; - if ((p == NULL) || ((size_t)s->length < len)) { - p = OPENSSL_malloc(len); - if (p == NULL) { - OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); - goto err; - } - if (s->data != NULL) { - OPENSSL_free(s->data); + char buf[14]; + BIO_snprintf(buf, sizeof(buf), "%02d%02d%02d%02d%02d%02dZ", + data.tm_year % 100, data.tm_mon + 1, data.tm_mday, data.tm_hour, + data.tm_min, data.tm_sec); + + int free_s = 0; + if (s == NULL) { + free_s = 1; + s = ASN1_UTCTIME_new(); + if (s == NULL) { + return NULL; } - s->data = (unsigned char *)p; } - BIO_snprintf(p, len, "%02d%02d%02d%02d%02d%02dZ", ts->tm_year % 100, - ts->tm_mon + 1, ts->tm_mday, ts->tm_hour, ts->tm_min, - ts->tm_sec); - s->length = strlen(p); + if (!ASN1_STRING_set(s, buf, strlen(buf))) { + if (free_s) { + ASN1_UTCTIME_free(s); + } + return NULL; + } s->type = V_ASN1_UTCTIME; return s; -err: - if (free_s) { - ASN1_UTCTIME_free(s); - } - return NULL; } int ASN1_UTCTIME_cmp_time_t(const ASN1_UTCTIME *s, time_t t) { From 7528f03c8ad73216f462f86e1d64d3d780a5cd42 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Fri, 8 Jul 2022 15:43:46 -0400 Subject: [PATCH 11/38] Fix memory leak with X509V3_ADD_DELETE. It seems no one has ever exercised this mode to notice it doesn't work. Add a test for this, which catches the memory leak. See also https://github.com/openssl/openssl/issues/18677 Change-Id: I8890febc71decd553a040bdda8739f68ed616c39 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/53285 Commit-Queue: David Benjamin Reviewed-by: Bob Beck Commit-Queue: Bob Beck --- crypto/x509/x509_test.cc | 160 +++++++++++++++++++++++++++++++++++++++ crypto/x509v3/v3_lib.c | 4 +- 2 files changed, 163 insertions(+), 1 deletion(-) diff --git a/crypto/x509/x509_test.cc b/crypto/x509/x509_test.cc index 425d74541f..50121c93cb 100644 --- a/crypto/x509/x509_test.cc +++ b/crypto/x509/x509_test.cc @@ -4388,3 +4388,163 @@ TEST(X509Test, Print) { 40:86 )"); } + +TEST(X509Test, AddExt) { + bssl::UniquePtr x509(X509_new()); + ASSERT_TRUE(x509); + + struct Extension { + int nid; + bool critical; + std::vector data; + }; + auto expect_extensions = [&](const std::vector &exts) { + ASSERT_EQ(static_cast(X509_get_ext_count(x509.get())), exts.size()); + for (size_t i = 0; i < exts.size(); i++) { + SCOPED_TRACE(i); + X509_EXTENSION *ext = X509_get_ext(x509.get(), static_cast(i)); + EXPECT_EQ(OBJ_obj2nid(X509_EXTENSION_get_object(ext)), exts[i].nid); + EXPECT_EQ(X509_EXTENSION_get_critical(ext), exts[i].critical ? 1 : 0); + ASN1_OCTET_STRING *data = X509_EXTENSION_get_data(ext); + EXPECT_EQ(Bytes(ASN1_STRING_get0_data(data), ASN1_STRING_length(data)), + Bytes(exts[i].data)); + } + }; + + // Make a few sample extensions. + + // SEQUENCE {} + std::vector basic1_der = {0x30, 0x00}; + const uint8_t *inp = basic1_der.data(); + bssl::UniquePtr basic1_obj( + d2i_BASIC_CONSTRAINTS(nullptr, &inp, basic1_der.size())); + EXPECT_EQ(inp, basic1_der.data() + basic1_der.size()); + + // SEQUENCE { BOOLEAN { TRUE } } + std::vector basic2_der = {0x30, 0x03, 0x01, 0x01, 0xff}; + inp = basic2_der.data(); + bssl::UniquePtr basic2_obj( + d2i_BASIC_CONSTRAINTS(nullptr, &inp, basic2_der.size())); + EXPECT_EQ(inp, basic2_der.data() + basic2_der.size()); + + // OCTET_STRING {} + std::vector skid1_der = {0x04, 0x00}; + inp = skid1_der.data(); + bssl::UniquePtr skid1_obj( + d2i_ASN1_OCTET_STRING(nullptr, &inp, skid1_der.size())); + EXPECT_EQ(inp, skid1_der.data() + skid1_der.size()); + + // OCTET_STRING { "a" } + std::vector skid2_der = {0x04, 0x01, 0x61}; + inp = skid2_der.data(); + bssl::UniquePtr skid2_obj( + d2i_ASN1_OCTET_STRING(nullptr, &inp, skid2_der.size())); + EXPECT_EQ(inp, skid2_der.data() + skid2_der.size()); + + // Initially, the extension list is empty. + expect_extensions({}); + + // Adding extensions works with the default settings. + EXPECT_EQ( + 1, X509_add1_ext_i2d(x509.get(), NID_basic_constraints, basic1_obj.get(), + /*crit=*/1, X509V3_ADD_DEFAULT)); + expect_extensions({{NID_basic_constraints, true, basic1_der}}); + EXPECT_EQ(1, X509_add1_ext_i2d(x509.get(), NID_subject_key_identifier, + skid1_obj.get(), + /*crit=*/0, X509V3_ADD_DEFAULT)); + expect_extensions({{NID_basic_constraints, true, basic1_der}, + {NID_subject_key_identifier, false, skid1_der}}); + + // By default, we cannot add duplicates. + EXPECT_EQ( + 0, X509_add1_ext_i2d(x509.get(), NID_basic_constraints, basic2_obj.get(), + /*crit=*/0, X509V3_ADD_DEFAULT)); + expect_extensions({{NID_basic_constraints, true, basic1_der}, + {NID_subject_key_identifier, false, skid1_der}}); + + // |X509V3_ADD_KEEP_EXISTING| silently keeps the existing extension if already + // present. + EXPECT_EQ( + 1, X509_add1_ext_i2d(x509.get(), NID_basic_constraints, basic2_obj.get(), + /*crit=*/0, X509V3_ADD_KEEP_EXISTING)); + expect_extensions({{NID_basic_constraints, true, basic1_der}, + {NID_subject_key_identifier, false, skid1_der}}); + + // |X509V3_ADD_REPLACE| replaces it. + EXPECT_EQ( + 1, X509_add1_ext_i2d(x509.get(), NID_basic_constraints, basic2_obj.get(), + /*crit=*/0, X509V3_ADD_REPLACE)); + expect_extensions({{NID_basic_constraints, false, basic2_der}, + {NID_subject_key_identifier, false, skid1_der}}); + + // |X509V3_ADD_REPLACE_EXISTING| also replaces matches. + EXPECT_EQ(1, X509_add1_ext_i2d(x509.get(), NID_subject_key_identifier, + skid2_obj.get(), + /*crit=*/1, X509V3_ADD_REPLACE_EXISTING)); + expect_extensions({{NID_basic_constraints, false, basic2_der}, + {NID_subject_key_identifier, true, skid2_der}}); + + // |X509V3_ADD_DELETE| ignores the value and deletes the extension. + EXPECT_EQ(1, X509_add1_ext_i2d(x509.get(), NID_basic_constraints, nullptr, 0, + X509V3_ADD_DELETE)); + expect_extensions({{NID_subject_key_identifier, true, skid2_der}}); + + // Not finding an extension to delete is an error. + EXPECT_EQ(0, X509_add1_ext_i2d(x509.get(), NID_basic_constraints, nullptr, 0, + X509V3_ADD_DELETE)); + expect_extensions({{NID_subject_key_identifier, true, skid2_der}}); + + // |X509V3_ADD_REPLACE_EXISTING| fails if it cannot find a match. + EXPECT_EQ( + 0, X509_add1_ext_i2d(x509.get(), NID_basic_constraints, basic1_obj.get(), + /*crit=*/1, X509V3_ADD_REPLACE_EXISTING)); + expect_extensions({{NID_subject_key_identifier, true, skid2_der}}); + + // |X509V3_ADD_REPLACE| adds a new extension if not preseent. + EXPECT_EQ( + 1, X509_add1_ext_i2d(x509.get(), NID_basic_constraints, basic1_obj.get(), + /*crit=*/1, X509V3_ADD_REPLACE)); + expect_extensions({{NID_subject_key_identifier, true, skid2_der}, + {NID_basic_constraints, true, basic1_der}}); + + // Delete the extension again. + EXPECT_EQ(1, X509_add1_ext_i2d(x509.get(), NID_basic_constraints, nullptr, 0, + X509V3_ADD_DELETE)); + expect_extensions({{NID_subject_key_identifier, true, skid2_der}}); + + // |X509V3_ADD_KEEP_EXISTING| adds a new extension if not preseent. + EXPECT_EQ( + 1, X509_add1_ext_i2d(x509.get(), NID_basic_constraints, basic1_obj.get(), + /*crit=*/1, X509V3_ADD_KEEP_EXISTING)); + expect_extensions({{NID_subject_key_identifier, true, skid2_der}, + {NID_basic_constraints, true, basic1_der}}); + + // Delete the extension again. + EXPECT_EQ(1, X509_add1_ext_i2d(x509.get(), NID_basic_constraints, nullptr, 0, + X509V3_ADD_DELETE)); + expect_extensions({{NID_subject_key_identifier, true, skid2_der}}); + + // |X509V3_ADD_APPEND| adds a new extension if not present. + EXPECT_EQ( + 1, X509_add1_ext_i2d(x509.get(), NID_basic_constraints, basic1_obj.get(), + /*crit=*/1, X509V3_ADD_APPEND)); + expect_extensions({{NID_subject_key_identifier, true, skid2_der}, + {NID_basic_constraints, true, basic1_der}}); + + // |X509V3_ADD_APPEND| keeps adding duplicates (invalid) even if present. + EXPECT_EQ( + 1, X509_add1_ext_i2d(x509.get(), NID_basic_constraints, basic2_obj.get(), + /*crit=*/0, X509V3_ADD_APPEND)); + expect_extensions({{NID_subject_key_identifier, true, skid2_der}, + {NID_basic_constraints, true, basic1_der}, + {NID_basic_constraints, false, basic2_der}}); + + // |X509V3_ADD_DELETE| only deletes one extension at a time. + EXPECT_EQ(1, X509_add1_ext_i2d(x509.get(), NID_basic_constraints, nullptr, 0, + X509V3_ADD_DELETE)); + expect_extensions({{NID_subject_key_identifier, true, skid2_der}, + {NID_basic_constraints, false, basic2_der}}); + EXPECT_EQ(1, X509_add1_ext_i2d(x509.get(), NID_basic_constraints, nullptr, 0, + X509V3_ADD_DELETE)); + expect_extensions({{NID_subject_key_identifier, true, skid2_der}}); +} diff --git a/crypto/x509v3/v3_lib.c b/crypto/x509v3/v3_lib.c index 4400b8e2b8..51b0f37673 100644 --- a/crypto/x509v3/v3_lib.c +++ b/crypto/x509v3/v3_lib.c @@ -316,9 +316,11 @@ int X509V3_add1_i2d(STACK_OF(X509_EXTENSION) **x, int nid, void *value, } // If delete, just delete it if (ext_op == X509V3_ADD_DELETE) { - if (!sk_X509_EXTENSION_delete(*x, extidx)) { + X509_EXTENSION *prev_ext = sk_X509_EXTENSION_delete(*x, extidx); + if (prev_ext == NULL) { return -1; } + X509_EXTENSION_free(prev_ext); return 1; } } else { From 5c1d5d8035bfad737bed79cd600c6600647e947f Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Mon, 31 Jan 2022 18:43:13 -0500 Subject: [PATCH 12/38] Use GTest's built-in sharding feature https://github.com/google/googletest/blob/main/docs/advanced.md#distributing-test-functions-to-multiple-machines Change-Id: I3998bb4735800a645286728852cb8494b28a6577 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/51225 Reviewed-by: Bob Beck Commit-Queue: Bob Beck --- util/all_tests.go | 85 +++++++++-------------------------------------- 1 file changed, 15 insertions(+), 70 deletions(-) diff --git a/util/all_tests.go b/util/all_tests.go index 884da26b38..4f484f353c 100644 --- a/util/all_tests.go +++ b/util/all_tests.go @@ -15,12 +15,10 @@ package main import ( - "bufio" "bytes" "errors" "flag" "fmt" - "math/rand" "os" "os/exec" "path" @@ -175,11 +173,17 @@ func runTestOnce(test test, mallocNumToFail int64) (passed bool, err error) { } else { cmd = exec.Command(prog, args...) } - if test.Env != nil { + if test.Env != nil || test.numShards != 0 { cmd.Env = make([]string, len(os.Environ())) copy(cmd.Env, os.Environ()) + } + if test.Env != nil { cmd.Env = append(cmd.Env, test.Env...) } + if test.numShards != 0 { + cmd.Env = append(cmd.Env, fmt.Sprintf("GTEST_SHARD_INDEX=%d", test.shard)) + cmd.Env = append(cmd.Env, fmt.Sprintf("GTEST_TOTAL_SHARDS=%d", test.numShards)) + } var outBuf bytes.Buffer cmd.Stdout = &outBuf cmd.Stderr = &outBuf @@ -265,7 +269,7 @@ func worker(tests <-chan test, results chan<- result, done *sync.WaitGroup) { } func (t test) shortName() string { - return t.Cmd[0] + t.shardMsg() + t.cpuMsg() + t.envMsg() + return strings.Join(t.Cmd, " ") + t.shardMsg() + t.cpuMsg() + t.envMsg() } func SpaceIf(returnSpace bool) string { @@ -276,7 +280,7 @@ func SpaceIf(returnSpace bool) string { } func (t test) longName() string { - return strings.Join(t.Env, " ") + SpaceIf(len(t.Env) != 0) + strings.Join(t.Cmd, " ") + t.cpuMsg() + return strings.Join(t.Env, " ") + SpaceIf(len(t.Env) != 0) + strings.Join(t.Cmd, " ") + t.shardMsg() + t.cpuMsg() } func (t test) shardMsg() string { @@ -313,70 +317,11 @@ func (t test) getGTestShards() ([]test, error) { return []test{t}, nil } - prog := path.Join(*buildDir, t.Cmd[0]) - cmd := exec.Command(prog, "--gtest_list_tests") - var stdout bytes.Buffer - cmd.Stdout = &stdout - if err := cmd.Start(); err != nil { - return nil, err - } - if err := cmd.Wait(); err != nil { - return nil, err - } - - var group string - var tests []string - scanner := bufio.NewScanner(&stdout) - for scanner.Scan() { - line := scanner.Text() - - // Remove the parameter comment and trailing space. - if idx := strings.Index(line, "#"); idx >= 0 { - line = line[:idx] - } - line = strings.TrimSpace(line) - if len(line) == 0 { - continue - } - - if line[len(line)-1] == '.' { - group = line - continue - } - - if len(group) == 0 { - return nil, fmt.Errorf("found test case %q without group", line) - } - tests = append(tests, group+line) - } - - const testsPerShard = 20 - if len(tests) <= testsPerShard { - return []test{t}, nil - } - - // Slow tests which process large test vector files tend to be grouped - // together, so shuffle the order. - shuffled := make([]string, len(tests)) - perm := rand.Perm(len(tests)) - for i, j := range perm { - shuffled[i] = tests[j] - } - - var shards []test - for i := 0; i < len(shuffled); i += testsPerShard { - n := len(shuffled) - i - if n > testsPerShard { - n = testsPerShard - } - shard := t - shard.Cmd = []string{shard.Cmd[0], "--gtest_filter=" + strings.Join(shuffled[i:i+n], ":")} - shard.shard = len(shards) - shards = append(shards, shard) - } - + shards := make([]test, *numWorkers) for i := range shards { - shards[i].numShards = len(shards) + shards[i] = t + shards[i].shard = i + shards[i].numShards = *numWorkers } return shards, nil @@ -477,14 +422,14 @@ func main() { if len(skipped) > 0 { fmt.Printf("\n%d of %d tests were skipped:\n", len(skipped), len(testCases)) for _, test := range skipped { - fmt.Printf("\t%s%s\n", strings.Join(test.Cmd, " "), test.cpuMsg()) + fmt.Printf("\t%s\n", test.shortName()) } } if len(failed) > 0 { fmt.Printf("\n%d of %d tests failed:\n", len(failed), len(testCases)) for _, test := range failed { - fmt.Printf("\t%s%s\n", strings.Join(test.Cmd, " "), test.cpuMsg()) + fmt.Printf("\t%s\n", test.shortName()) } os.Exit(1) } From dc112e7ffc9bf95d01f08478ac9be90d6a695cdd Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Sat, 25 Jun 2022 21:42:52 -0400 Subject: [PATCH 13/38] Const-correct the i2d/dup functions we can. Types which do not contain an X509_NAME can be const. X509_NAME still requires some thought. (i2d_X509_NAME can mutate the object and isn't even thread-safe when modified.) Bug: 407 Change-Id: Iceafa2b4ea9c4194cfcc3044d90393b5d91f7c11 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/53305 Reviewed-by: Bob Beck Commit-Queue: Bob Beck --- .clang-format | 1 + crypto/pkcs8/pkcs8_x509.c | 2 +- crypto/x509/internal.h | 10 +++++++-- crypto/x509/rsa_pss.c | 2 +- crypto/x509/x509cset.c | 7 ++----- crypto/x509/x509rset.c | 5 +---- crypto/x509/x_algor.c | 7 ++++--- crypto/x509/x_attrib.c | 4 ++-- crypto/x509/x_exten.c | 8 ++++---- crypto/x509/x_name.c | 4 ++-- crypto/x509/x_pubkey.c | 2 +- crypto/x509/x_sig.c | 2 +- crypto/x509/x_spki.c | 4 ++-- crypto/x509/x_val.c | 2 +- crypto/x509/x_x509.c | 7 ++----- crypto/x509/x_x509a.c | 2 +- crypto/x509v3/v3_bcons.c | 2 +- crypto/x509v3/v3_cpols.c | 10 ++++----- crypto/x509v3/v3_extku.c | 2 +- crypto/x509v3/v3_genn.c | 4 ++-- crypto/x509v3/v3_pcia.c | 4 ++-- include/openssl/asn1t.h | 16 +++++++++------ include/openssl/x509.h | 43 ++++++++++++++++++++++++--------------- include/openssl/x509v3.h | 40 ++++++++++++++++++++++++++---------- 24 files changed, 111 insertions(+), 79 deletions(-) diff --git a/.clang-format b/.clang-format index 68c331a532..0ab585e26f 100644 --- a/.clang-format +++ b/.clang-format @@ -38,6 +38,7 @@ StatementMacros: - "IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname" - "IMPLEMENT_ASN1_ALLOC_FUNCTIONS_pfname" - "IMPLEMENT_ASN1_DUP_FUNCTION" + - "IMPLEMENT_ASN1_DUP_FUNCTION_const" - "IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname" - "IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname" - "IMPLEMENT_ASN1_FUNCTIONS" diff --git a/crypto/pkcs8/pkcs8_x509.c b/crypto/pkcs8/pkcs8_x509.c index 3eff87cb21..5a1d591faa 100644 --- a/crypto/pkcs8/pkcs8_x509.c +++ b/crypto/pkcs8/pkcs8_x509.c @@ -110,7 +110,7 @@ ASN1_SEQUENCE_cb(PKCS8_PRIV_KEY_INFO, pkey_cb) = { ASN1_IMP_SET_OF_OPT(PKCS8_PRIV_KEY_INFO, attributes, X509_ATTRIBUTE, 0), } ASN1_SEQUENCE_END_cb(PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO) -IMPLEMENT_ASN1_FUNCTIONS(PKCS8_PRIV_KEY_INFO) +IMPLEMENT_ASN1_FUNCTIONS_const(PKCS8_PRIV_KEY_INFO) int PKCS8_pkey_set0(PKCS8_PRIV_KEY_INFO *priv, ASN1_OBJECT *aobj, int version, int ptype, void *pval, uint8_t *penc, int penclen) { diff --git a/crypto/x509/internal.h b/crypto/x509/internal.h index 8785949198..23c961e871 100644 --- a/crypto/x509/internal.h +++ b/crypto/x509/internal.h @@ -77,7 +77,7 @@ typedef struct X509_val_st { ASN1_TIME *notAfter; } X509_VAL; -DECLARE_ASN1_FUNCTIONS(X509_VAL) +DECLARE_ASN1_FUNCTIONS_const(X509_VAL) struct X509_pubkey_st { X509_ALGOR *algor; @@ -113,7 +113,7 @@ typedef struct x509_cert_aux_st { ASN1_OCTET_STRING *keyid; // key id of private key } X509_CERT_AUX; -DECLARE_ASN1_FUNCTIONS(X509_CERT_AUX) +DECLARE_ASN1_FUNCTIONS_const(X509_CERT_AUX) struct X509_extension_st { ASN1_OBJECT *object; @@ -135,6 +135,8 @@ typedef struct { ASN1_ENCODING enc; } X509_CINF; +// TODO(https://crbug.com/boringssl/407): This is not const because it contains +// an |X509_NAME|. DECLARE_ASN1_FUNCTIONS(X509_CINF) struct x509_st { @@ -171,6 +173,8 @@ typedef struct { STACK_OF(X509_ATTRIBUTE) *attributes; // [ 0 ] } X509_REQ_INFO; +// TODO(https://crbug.com/boringssl/407): This is not const because it contains +// an |X509_NAME|. DECLARE_ASN1_FUNCTIONS(X509_REQ_INFO) struct X509_req_st { @@ -201,6 +205,8 @@ typedef struct { ASN1_ENCODING enc; } X509_CRL_INFO; +// TODO(https://crbug.com/boringssl/407): This is not const because it contains +// an |X509_NAME|. DECLARE_ASN1_FUNCTIONS(X509_CRL_INFO) struct X509_crl_st { diff --git a/crypto/x509/rsa_pss.c b/crypto/x509/rsa_pss.c index 38cb028926..f5716a61e2 100644 --- a/crypto/x509/rsa_pss.c +++ b/crypto/x509/rsa_pss.c @@ -83,7 +83,7 @@ ASN1_SEQUENCE_cb(RSA_PSS_PARAMS, rsa_pss_cb) = { ASN1_EXP_OPT(RSA_PSS_PARAMS, trailerField, ASN1_INTEGER, 3), } ASN1_SEQUENCE_END_cb(RSA_PSS_PARAMS, RSA_PSS_PARAMS) -IMPLEMENT_ASN1_FUNCTIONS(RSA_PSS_PARAMS) +IMPLEMENT_ASN1_FUNCTIONS_const(RSA_PSS_PARAMS) // Given an MGF1 Algorithm ID decode to an Algorithm Identifier diff --git a/crypto/x509/x509cset.c b/crypto/x509/x509cset.c index 6e812485ea..9558128e56 100644 --- a/crypto/x509/x509cset.c +++ b/crypto/x509/x509cset.c @@ -245,11 +245,8 @@ int i2d_X509_CRL_tbs(X509_CRL *crl, unsigned char **outp) { } int X509_CRL_set1_signature_algo(X509_CRL *crl, const X509_ALGOR *algo) { - // TODO(https://crbug.com/boringssl/407): Generated ASN.1 dup functions - // should be const. Alternatively, when we can embed required fields - // directly in structs, import |X509_ALGOR_copy| from upstream. - X509_ALGOR *copy1 = X509_ALGOR_dup((X509_ALGOR *)algo); - X509_ALGOR *copy2 = X509_ALGOR_dup((X509_ALGOR *)algo); + X509_ALGOR *copy1 = X509_ALGOR_dup(algo); + X509_ALGOR *copy2 = X509_ALGOR_dup(algo); if (copy1 == NULL || copy2 == NULL) { X509_ALGOR_free(copy1); X509_ALGOR_free(copy2); diff --git a/crypto/x509/x509rset.c b/crypto/x509/x509rset.c index 4c6181e61e..869bd40a3f 100644 --- a/crypto/x509/x509rset.c +++ b/crypto/x509/x509rset.c @@ -88,10 +88,7 @@ int X509_REQ_set_pubkey(X509_REQ *x, EVP_PKEY *pkey) { } int X509_REQ_set1_signature_algo(X509_REQ *req, const X509_ALGOR *algo) { - // TODO(https://crbug.com/boringssl/407): Generated ASN.1 dup functions - // should be const. Alternatively, when we can embed required fields - // directly in structs, import |X509_ALGOR_copy| from upstream. - X509_ALGOR *copy = X509_ALGOR_dup((X509_ALGOR *)algo); + X509_ALGOR *copy = X509_ALGOR_dup(algo); if (copy == NULL) { return 0; } diff --git a/crypto/x509/x_algor.c b/crypto/x509/x_algor.c index 09a2221a2f..a2d778a7ef 100644 --- a/crypto/x509/x_algor.c +++ b/crypto/x509/x_algor.c @@ -74,9 +74,10 @@ ASN1_ITEM_TEMPLATE(X509_ALGORS) = ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, X509_ALGOR) ASN1_ITEM_TEMPLATE_END(X509_ALGORS) -IMPLEMENT_ASN1_FUNCTIONS(X509_ALGOR) -IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(X509_ALGORS, X509_ALGORS, X509_ALGORS) -IMPLEMENT_ASN1_DUP_FUNCTION(X509_ALGOR) +IMPLEMENT_ASN1_FUNCTIONS_const(X509_ALGOR) +IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(X509_ALGORS, X509_ALGORS, + X509_ALGORS) +IMPLEMENT_ASN1_DUP_FUNCTION_const(X509_ALGOR) int X509_ALGOR_set0(X509_ALGOR *alg, ASN1_OBJECT *aobj, int ptype, void *pval) { if (!alg) { diff --git a/crypto/x509/x_attrib.c b/crypto/x509/x_attrib.c index a434bc29f1..14428b38b1 100644 --- a/crypto/x509/x_attrib.c +++ b/crypto/x509/x_attrib.c @@ -67,8 +67,8 @@ ASN1_SEQUENCE(X509_ATTRIBUTE) = { ASN1_SET_OF(X509_ATTRIBUTE, set, ASN1_ANY), } ASN1_SEQUENCE_END(X509_ATTRIBUTE) -IMPLEMENT_ASN1_FUNCTIONS(X509_ATTRIBUTE) -IMPLEMENT_ASN1_DUP_FUNCTION(X509_ATTRIBUTE) +IMPLEMENT_ASN1_FUNCTIONS_const(X509_ATTRIBUTE) +IMPLEMENT_ASN1_DUP_FUNCTION_const(X509_ATTRIBUTE) X509_ATTRIBUTE *X509_ATTRIBUTE_create(int nid, int attrtype, void *value) { ASN1_OBJECT *obj = OBJ_nid2obj(nid); diff --git a/crypto/x509/x_exten.c b/crypto/x509/x_exten.c index 53d2b711f6..e181d982de 100644 --- a/crypto/x509/x_exten.c +++ b/crypto/x509/x_exten.c @@ -72,7 +72,7 @@ ASN1_ITEM_TEMPLATE(X509_EXTENSIONS) = ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, Extension, X509_EXTENSION) ASN1_ITEM_TEMPLATE_END(X509_EXTENSIONS) -IMPLEMENT_ASN1_FUNCTIONS(X509_EXTENSION) -IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(X509_EXTENSIONS, X509_EXTENSIONS, - X509_EXTENSIONS) -IMPLEMENT_ASN1_DUP_FUNCTION(X509_EXTENSION) +IMPLEMENT_ASN1_FUNCTIONS_const(X509_EXTENSION) +IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(X509_EXTENSIONS, X509_EXTENSIONS, + X509_EXTENSIONS) +IMPLEMENT_ASN1_DUP_FUNCTION_const(X509_EXTENSION) diff --git a/crypto/x509/x_name.c b/crypto/x509/x_name.c index f54cbe8c1f..a17d9d73f6 100644 --- a/crypto/x509/x_name.c +++ b/crypto/x509/x_name.c @@ -99,8 +99,8 @@ ASN1_SEQUENCE(X509_NAME_ENTRY) = { ASN1_SIMPLE(X509_NAME_ENTRY, value, ASN1_PRINTABLE), } ASN1_SEQUENCE_END(X509_NAME_ENTRY) -IMPLEMENT_ASN1_FUNCTIONS(X509_NAME_ENTRY) -IMPLEMENT_ASN1_DUP_FUNCTION(X509_NAME_ENTRY) +IMPLEMENT_ASN1_FUNCTIONS_const(X509_NAME_ENTRY) +IMPLEMENT_ASN1_DUP_FUNCTION_const(X509_NAME_ENTRY) // For the "Name" type we need a SEQUENCE OF { SET OF X509_NAME_ENTRY } so // declare two template wrappers for this diff --git a/crypto/x509/x_pubkey.c b/crypto/x509/x_pubkey.c index 6a1dece229..6a6a9750cf 100644 --- a/crypto/x509/x_pubkey.c +++ b/crypto/x509/x_pubkey.c @@ -85,7 +85,7 @@ ASN1_SEQUENCE_cb(X509_PUBKEY, pubkey_cb) = { ASN1_SIMPLE(X509_PUBKEY, public_key, ASN1_BIT_STRING), } ASN1_SEQUENCE_END_cb(X509_PUBKEY, X509_PUBKEY) -IMPLEMENT_ASN1_FUNCTIONS(X509_PUBKEY) +IMPLEMENT_ASN1_FUNCTIONS_const(X509_PUBKEY) int X509_PUBKEY_set(X509_PUBKEY **x, EVP_PKEY *pkey) { X509_PUBKEY *pk = NULL; diff --git a/crypto/x509/x_sig.c b/crypto/x509/x_sig.c index b68cb9ef4c..4710cae85a 100644 --- a/crypto/x509/x_sig.c +++ b/crypto/x509/x_sig.c @@ -71,7 +71,7 @@ ASN1_SEQUENCE(X509_SIG) = { ASN1_SIMPLE(X509_SIG, digest, ASN1_OCTET_STRING), } ASN1_SEQUENCE_END(X509_SIG) -IMPLEMENT_ASN1_FUNCTIONS(X509_SIG) +IMPLEMENT_ASN1_FUNCTIONS_const(X509_SIG) void X509_SIG_get0(const X509_SIG *sig, const X509_ALGOR **out_alg, const ASN1_OCTET_STRING **out_digest) { diff --git a/crypto/x509/x_spki.c b/crypto/x509/x_spki.c index 435ff85dd4..589987821c 100644 --- a/crypto/x509/x_spki.c +++ b/crypto/x509/x_spki.c @@ -67,7 +67,7 @@ ASN1_SEQUENCE(NETSCAPE_SPKAC) = { ASN1_SIMPLE(NETSCAPE_SPKAC, challenge, ASN1_IA5STRING), } ASN1_SEQUENCE_END(NETSCAPE_SPKAC) -IMPLEMENT_ASN1_FUNCTIONS(NETSCAPE_SPKAC) +IMPLEMENT_ASN1_FUNCTIONS_const(NETSCAPE_SPKAC) ASN1_SEQUENCE(NETSCAPE_SPKI) = { ASN1_SIMPLE(NETSCAPE_SPKI, spkac, NETSCAPE_SPKAC), @@ -75,4 +75,4 @@ ASN1_SEQUENCE(NETSCAPE_SPKI) = { ASN1_SIMPLE(NETSCAPE_SPKI, signature, ASN1_BIT_STRING), } ASN1_SEQUENCE_END(NETSCAPE_SPKI) -IMPLEMENT_ASN1_FUNCTIONS(NETSCAPE_SPKI) +IMPLEMENT_ASN1_FUNCTIONS_const(NETSCAPE_SPKI) diff --git a/crypto/x509/x_val.c b/crypto/x509/x_val.c index e317a7053a..62dbf6fef2 100644 --- a/crypto/x509/x_val.c +++ b/crypto/x509/x_val.c @@ -68,4 +68,4 @@ ASN1_SEQUENCE(X509_VAL) = { ASN1_SIMPLE(X509_VAL, notAfter, ASN1_TIME), } ASN1_SEQUENCE_END(X509_VAL) -IMPLEMENT_ASN1_FUNCTIONS(X509_VAL) +IMPLEMENT_ASN1_FUNCTIONS_const(X509_VAL) diff --git a/crypto/x509/x_x509.c b/crypto/x509/x_x509.c index ee558a493b..27cbd99389 100644 --- a/crypto/x509/x_x509.c +++ b/crypto/x509/x_x509.c @@ -338,11 +338,8 @@ int i2d_X509_tbs(X509 *x509, unsigned char **outp) { } int X509_set1_signature_algo(X509 *x509, const X509_ALGOR *algo) { - // TODO(https://crbug.com/boringssl/407): Generated ASN.1 dup functions - // should be const. Alternatively, when we can embed required fields - // directly in structs, import |X509_ALGOR_copy| from upstream. - X509_ALGOR *copy1 = X509_ALGOR_dup((X509_ALGOR *)algo); - X509_ALGOR *copy2 = X509_ALGOR_dup((X509_ALGOR *)algo); + X509_ALGOR *copy1 = X509_ALGOR_dup(algo); + X509_ALGOR *copy2 = X509_ALGOR_dup(algo); if (copy1 == NULL || copy2 == NULL) { X509_ALGOR_free(copy1); X509_ALGOR_free(copy2); diff --git a/crypto/x509/x_x509a.c b/crypto/x509/x_x509a.c index d372537f2c..c473f93dd1 100644 --- a/crypto/x509/x_x509a.c +++ b/crypto/x509/x_x509a.c @@ -78,7 +78,7 @@ ASN1_SEQUENCE(X509_CERT_AUX) = { ASN1_OPT(X509_CERT_AUX, keyid, ASN1_OCTET_STRING), } ASN1_SEQUENCE_END(X509_CERT_AUX) -IMPLEMENT_ASN1_FUNCTIONS(X509_CERT_AUX) +IMPLEMENT_ASN1_FUNCTIONS_const(X509_CERT_AUX) static X509_CERT_AUX *aux_get(X509 *x) { if (!x) { diff --git a/crypto/x509v3/v3_bcons.c b/crypto/x509v3/v3_bcons.c index db55f0623c..19c1a5df15 100644 --- a/crypto/x509v3/v3_bcons.c +++ b/crypto/x509v3/v3_bcons.c @@ -93,7 +93,7 @@ ASN1_SEQUENCE(BASIC_CONSTRAINTS) = { ASN1_OPT(BASIC_CONSTRAINTS, pathlen, ASN1_INTEGER), } ASN1_SEQUENCE_END(BASIC_CONSTRAINTS) -IMPLEMENT_ASN1_FUNCTIONS(BASIC_CONSTRAINTS) +IMPLEMENT_ASN1_FUNCTIONS_const(BASIC_CONSTRAINTS) static STACK_OF(CONF_VALUE) *i2v_BASIC_CONSTRAINTS( const X509V3_EXT_METHOD *method, void *ext, STACK_OF(CONF_VALUE) *extlist) { diff --git a/crypto/x509v3/v3_cpols.c b/crypto/x509v3/v3_cpols.c index 5b6841e804..82c68a1ee4 100644 --- a/crypto/x509v3/v3_cpols.c +++ b/crypto/x509v3/v3_cpols.c @@ -107,14 +107,14 @@ ASN1_ITEM_TEMPLATE(CERTIFICATEPOLICIES) = ASN1_EX_TEMPLATE_TYPE( ASN1_TFLG_SEQUENCE_OF, 0, CERTIFICATEPOLICIES, POLICYINFO) ASN1_ITEM_TEMPLATE_END(CERTIFICATEPOLICIES) -IMPLEMENT_ASN1_FUNCTIONS(CERTIFICATEPOLICIES) +IMPLEMENT_ASN1_FUNCTIONS_const(CERTIFICATEPOLICIES) ASN1_SEQUENCE(POLICYINFO) = { ASN1_SIMPLE(POLICYINFO, policyid, ASN1_OBJECT), ASN1_SEQUENCE_OF_OPT(POLICYINFO, qualifiers, POLICYQUALINFO), } ASN1_SEQUENCE_END(POLICYINFO) -IMPLEMENT_ASN1_FUNCTIONS(POLICYINFO) +IMPLEMENT_ASN1_FUNCTIONS_const(POLICYINFO) ASN1_ADB_TEMPLATE(policydefault) = ASN1_SIMPLE(POLICYQUALINFO, d.other, ASN1_ANY); @@ -131,21 +131,21 @@ ASN1_SEQUENCE(POLICYQUALINFO) = { ASN1_ADB_OBJECT(POLICYQUALINFO), } ASN1_SEQUENCE_END(POLICYQUALINFO) -IMPLEMENT_ASN1_FUNCTIONS(POLICYQUALINFO) +IMPLEMENT_ASN1_FUNCTIONS_const(POLICYQUALINFO) ASN1_SEQUENCE(USERNOTICE) = { ASN1_OPT(USERNOTICE, noticeref, NOTICEREF), ASN1_OPT(USERNOTICE, exptext, DISPLAYTEXT), } ASN1_SEQUENCE_END(USERNOTICE) -IMPLEMENT_ASN1_FUNCTIONS(USERNOTICE) +IMPLEMENT_ASN1_FUNCTIONS_const(USERNOTICE) ASN1_SEQUENCE(NOTICEREF) = { ASN1_SIMPLE(NOTICEREF, organization, DISPLAYTEXT), ASN1_SEQUENCE_OF(NOTICEREF, noticenos, ASN1_INTEGER), } ASN1_SEQUENCE_END(NOTICEREF) -IMPLEMENT_ASN1_FUNCTIONS(NOTICEREF) +IMPLEMENT_ASN1_FUNCTIONS_const(NOTICEREF) static void *r2i_certpol(const X509V3_EXT_METHOD *method, X509V3_CTX *ctx, const char *value) { diff --git a/crypto/x509v3/v3_extku.c b/crypto/x509v3/v3_extku.c index 7eb7cc86c0..0305ed29d1 100644 --- a/crypto/x509v3/v3_extku.c +++ b/crypto/x509v3/v3_extku.c @@ -108,7 +108,7 @@ ASN1_ITEM_TEMPLATE(EXTENDED_KEY_USAGE) = ASN1_EX_TEMPLATE_TYPE( ASN1_TFLG_SEQUENCE_OF, 0, EXTENDED_KEY_USAGE, ASN1_OBJECT) ASN1_ITEM_TEMPLATE_END(EXTENDED_KEY_USAGE) -IMPLEMENT_ASN1_FUNCTIONS(EXTENDED_KEY_USAGE) +IMPLEMENT_ASN1_FUNCTIONS_const(EXTENDED_KEY_USAGE) static STACK_OF(CONF_VALUE) *i2v_EXTENDED_KEY_USAGE( const X509V3_EXT_METHOD *method, void *a, STACK_OF(CONF_VALUE) *ext_list) { diff --git a/crypto/x509v3/v3_genn.c b/crypto/x509v3/v3_genn.c index bd1aac16f9..fef0204452 100644 --- a/crypto/x509v3/v3_genn.c +++ b/crypto/x509v3/v3_genn.c @@ -69,7 +69,7 @@ ASN1_SEQUENCE(OTHERNAME) = { ASN1_EXP(OTHERNAME, value, ASN1_ANY, 0), } ASN1_SEQUENCE_END(OTHERNAME) -IMPLEMENT_ASN1_FUNCTIONS(OTHERNAME) +IMPLEMENT_ASN1_FUNCTIONS_const(OTHERNAME) ASN1_SEQUENCE(EDIPARTYNAME) = { // DirectoryString is a CHOICE type, so use explicit tagging. @@ -77,7 +77,7 @@ ASN1_SEQUENCE(EDIPARTYNAME) = { ASN1_EXP(EDIPARTYNAME, partyName, DIRECTORYSTRING, 1), } ASN1_SEQUENCE_END(EDIPARTYNAME) -IMPLEMENT_ASN1_FUNCTIONS(EDIPARTYNAME) +IMPLEMENT_ASN1_FUNCTIONS_const(EDIPARTYNAME) ASN1_CHOICE(GENERAL_NAME) = { ASN1_IMP(GENERAL_NAME, d.otherName, OTHERNAME, GEN_OTHERNAME), diff --git a/crypto/x509v3/v3_pcia.c b/crypto/x509v3/v3_pcia.c index 356fb9d1f3..62893ed794 100644 --- a/crypto/x509v3/v3_pcia.c +++ b/crypto/x509v3/v3_pcia.c @@ -45,11 +45,11 @@ ASN1_SEQUENCE(PROXY_POLICY) = { ASN1_OPT(PROXY_POLICY, policy, ASN1_OCTET_STRING), } ASN1_SEQUENCE_END(PROXY_POLICY) -IMPLEMENT_ASN1_FUNCTIONS(PROXY_POLICY) +IMPLEMENT_ASN1_FUNCTIONS_const(PROXY_POLICY) ASN1_SEQUENCE(PROXY_CERT_INFO_EXTENSION) = { ASN1_OPT(PROXY_CERT_INFO_EXTENSION, pcPathLengthConstraint, ASN1_INTEGER), ASN1_SIMPLE(PROXY_CERT_INFO_EXTENSION, proxyPolicy, PROXY_POLICY), } ASN1_SEQUENCE_END(PROXY_CERT_INFO_EXTENSION) -IMPLEMENT_ASN1_FUNCTIONS(PROXY_CERT_INFO_EXTENSION) +IMPLEMENT_ASN1_FUNCTIONS_const(PROXY_CERT_INFO_EXTENSION) diff --git a/include/openssl/asn1t.h b/include/openssl/asn1t.h index 75bc6f0b2b..105cee8deb 100644 --- a/include/openssl/asn1t.h +++ b/include/openssl/asn1t.h @@ -677,13 +677,17 @@ typedef struct ASN1_AUX_st { int i2d_##fname(const stname *a, unsigned char **out) \ { \ return ASN1_item_i2d((ASN1_VALUE *)a, out, ASN1_ITEM_rptr(itname));\ - } + } + +#define IMPLEMENT_ASN1_DUP_FUNCTION(stname) \ + stname *stname##_dup(stname *x) { \ + return ASN1_item_dup(ASN1_ITEM_rptr(stname), x); \ + } -#define IMPLEMENT_ASN1_DUP_FUNCTION(stname) \ - stname * stname##_dup(stname *x) \ - { \ - return ASN1_item_dup(ASN1_ITEM_rptr(stname), x); \ - } +#define IMPLEMENT_ASN1_DUP_FUNCTION_const(stname) \ + stname *stname##_dup(const stname *x) { \ + return ASN1_item_dup(ASN1_ITEM_rptr(stname), (void *)x); \ + } #define IMPLEMENT_ASN1_FUNCTIONS_const(name) \ IMPLEMENT_ASN1_FUNCTIONS_const_fname(name, name, name) diff --git a/include/openssl/x509.h b/include/openssl/x509.h index 526765f580..673edfecbe 100644 --- a/include/openssl/x509.h +++ b/include/openssl/x509.h @@ -115,7 +115,7 @@ struct X509_algor_st { ASN1_TYPE *parameter; } /* X509_ALGOR */; -DECLARE_ASN1_FUNCTIONS(X509_ALGOR) +DECLARE_ASN1_FUNCTIONS_const(X509_ALGOR) DEFINE_STACK_OF(X509_ALGOR) @@ -704,12 +704,12 @@ OPENSSL_EXPORT DH *d2i_DHparams_bio(BIO *bp, DH **dh); OPENSSL_EXPORT int i2d_DHparams_bio(BIO *bp, const DH *dh); OPENSSL_EXPORT X509 *X509_dup(X509 *x509); -OPENSSL_EXPORT X509_ATTRIBUTE *X509_ATTRIBUTE_dup(X509_ATTRIBUTE *xa); -OPENSSL_EXPORT X509_EXTENSION *X509_EXTENSION_dup(X509_EXTENSION *ex); +OPENSSL_EXPORT X509_ATTRIBUTE *X509_ATTRIBUTE_dup(const X509_ATTRIBUTE *xa); +OPENSSL_EXPORT X509_EXTENSION *X509_EXTENSION_dup(const X509_EXTENSION *ex); OPENSSL_EXPORT X509_CRL *X509_CRL_dup(X509_CRL *crl); OPENSSL_EXPORT X509_REVOKED *X509_REVOKED_dup(X509_REVOKED *rev); OPENSSL_EXPORT X509_REQ *X509_REQ_dup(X509_REQ *req); -OPENSSL_EXPORT X509_ALGOR *X509_ALGOR_dup(X509_ALGOR *xn); +OPENSSL_EXPORT X509_ALGOR *X509_ALGOR_dup(const X509_ALGOR *xn); // X509_ALGOR_set0 sets |alg| to an AlgorithmIdentifier with algorithm |obj| and // parameter determined by |param_type| and |param_value|. It returns one on @@ -761,7 +761,7 @@ OPENSSL_EXPORT void X509_ALGOR_set_md(X509_ALGOR *alg, const EVP_MD *md); OPENSSL_EXPORT int X509_ALGOR_cmp(const X509_ALGOR *a, const X509_ALGOR *b); OPENSSL_EXPORT X509_NAME *X509_NAME_dup(X509_NAME *xn); -OPENSSL_EXPORT X509_NAME_ENTRY *X509_NAME_ENTRY_dup(X509_NAME_ENTRY *ne); +OPENSSL_EXPORT X509_NAME_ENTRY *X509_NAME_ENTRY_dup(const X509_NAME_ENTRY *ne); OPENSSL_EXPORT int X509_NAME_ENTRY_set(const X509_NAME_ENTRY *ne); OPENSSL_EXPORT int X509_NAME_get0_der(X509_NAME *nm, const unsigned char **pder, @@ -799,9 +799,9 @@ OPENSSL_EXPORT const char *X509_get_default_cert_dir_env(void); OPENSSL_EXPORT const char *X509_get_default_cert_file_env(void); OPENSSL_EXPORT const char *X509_get_default_private_dir(void); -DECLARE_ASN1_ENCODE_FUNCTIONS(X509_ALGORS, X509_ALGORS, X509_ALGORS) +DECLARE_ASN1_ENCODE_FUNCTIONS_const(X509_ALGORS, X509_ALGORS) -DECLARE_ASN1_FUNCTIONS(X509_PUBKEY) +DECLARE_ASN1_FUNCTIONS_const(X509_PUBKEY) // X509_PUBKEY_set serializes |pkey| into a newly-allocated |X509_PUBKEY| // structure. On success, it frees |*x|, sets |*x| to the new object, and @@ -814,10 +814,13 @@ OPENSSL_EXPORT int X509_PUBKEY_set(X509_PUBKEY **x, EVP_PKEY *pkey); // not mutate the result. OPENSSL_EXPORT EVP_PKEY *X509_PUBKEY_get(X509_PUBKEY *key); -DECLARE_ASN1_FUNCTIONS(X509_SIG) +DECLARE_ASN1_FUNCTIONS_const(X509_SIG) + +// TODO(https://crbug.com/boringssl/407): This is not const because it contains +// an |X509_NAME|. DECLARE_ASN1_FUNCTIONS(X509_REQ) -DECLARE_ASN1_FUNCTIONS(X509_ATTRIBUTE) +DECLARE_ASN1_FUNCTIONS_const(X509_ATTRIBUTE) // X509_ATTRIBUTE_create returns a newly-allocated |X509_ATTRIBUTE|, or NULL on // error. The attribute has type |nid| and contains a single value determined by @@ -826,17 +829,21 @@ DECLARE_ASN1_FUNCTIONS(X509_ATTRIBUTE) OPENSSL_EXPORT X509_ATTRIBUTE *X509_ATTRIBUTE_create(int nid, int attrtype, void *value); -DECLARE_ASN1_FUNCTIONS(X509_EXTENSION) -DECLARE_ASN1_ENCODE_FUNCTIONS(X509_EXTENSIONS, X509_EXTENSIONS, X509_EXTENSIONS) +DECLARE_ASN1_FUNCTIONS_const(X509_EXTENSION) +DECLARE_ASN1_ENCODE_FUNCTIONS_const(X509_EXTENSIONS, X509_EXTENSIONS) -DECLARE_ASN1_FUNCTIONS(X509_NAME_ENTRY) +DECLARE_ASN1_FUNCTIONS_const(X509_NAME_ENTRY) +// TODO(https://crbug.com/boringssl/407): This is not const because serializing +// an |X509_NAME| is sometimes not thread-safe. DECLARE_ASN1_FUNCTIONS(X509_NAME) // X509_NAME_set makes a copy of |name|. On success, it frees |*xn|, sets |*xn| // to the copy, and returns one. Otherwise, it returns zero. OPENSSL_EXPORT int X509_NAME_set(X509_NAME **xn, X509_NAME *name); +// TODO(https://crbug.com/boringssl/407): This is not const because it contains +// an |X509_NAME|. DECLARE_ASN1_FUNCTIONS(X509) // X509_up_ref adds one to the reference count of |x509| and returns one. @@ -975,7 +982,11 @@ OPENSSL_EXPORT void X509_reject_clear(X509 *x); OPENSSL_EXPORT int X509_TRUST_set(int *t, int trust); +// TODO(https://crbug.com/boringssl/407): This is not const because it contains +// an |X509_NAME|. DECLARE_ASN1_FUNCTIONS(X509_REVOKED) +// TODO(https://crbug.com/boringssl/407): This is not const because it contains +// an |X509_NAME|. DECLARE_ASN1_FUNCTIONS(X509_CRL) OPENSSL_EXPORT int X509_CRL_add0_revoked(X509_CRL *crl, X509_REVOKED *rev); @@ -987,8 +998,8 @@ OPENSSL_EXPORT int X509_CRL_get0_by_cert(X509_CRL *crl, X509_REVOKED **ret, OPENSSL_EXPORT X509_PKEY *X509_PKEY_new(void); OPENSSL_EXPORT void X509_PKEY_free(X509_PKEY *a); -DECLARE_ASN1_FUNCTIONS(NETSCAPE_SPKI) -DECLARE_ASN1_FUNCTIONS(NETSCAPE_SPKAC) +DECLARE_ASN1_FUNCTIONS_const(NETSCAPE_SPKI) +DECLARE_ASN1_FUNCTIONS_const(NETSCAPE_SPKAC) OPENSSL_EXPORT X509_INFO *X509_INFO_new(void); OPENSSL_EXPORT void X509_INFO_free(X509_INFO *a); @@ -1830,7 +1841,7 @@ OPENSSL_EXPORT X509 *X509_find_by_subject(STACK_OF(X509) *sk, X509_NAME *name); // PKCS#8 utilities -DECLARE_ASN1_FUNCTIONS(PKCS8_PRIV_KEY_INFO) +DECLARE_ASN1_FUNCTIONS_const(PKCS8_PRIV_KEY_INFO) OPENSSL_EXPORT EVP_PKEY *EVP_PKCS82PKEY(PKCS8_PRIV_KEY_INFO *p8); OPENSSL_EXPORT PKCS8_PRIV_KEY_INFO *EVP_PKEY2PKCS8(EVP_PKEY *pkey); @@ -1897,7 +1908,7 @@ struct rsa_pss_params_st { X509_ALGOR *maskHash; } /* RSA_PSS_PARAMS */; -DECLARE_ASN1_FUNCTIONS(RSA_PSS_PARAMS) +DECLARE_ASN1_FUNCTIONS_const(RSA_PSS_PARAMS) /* SSL_CTX -> X509_STORE diff --git a/include/openssl/x509v3.h b/include/openssl/x509v3.h index afaf172f87..0ae96137da 100644 --- a/include/openssl/x509v3.h +++ b/include/openssl/x509v3.h @@ -328,8 +328,8 @@ typedef struct PROXY_CERT_INFO_EXTENSION_st { PROXY_POLICY *proxyPolicy; } PROXY_CERT_INFO_EXTENSION; -DECLARE_ASN1_FUNCTIONS(PROXY_POLICY) -DECLARE_ASN1_FUNCTIONS(PROXY_CERT_INFO_EXTENSION) +DECLARE_ASN1_FUNCTIONS_const(PROXY_POLICY) +DECLARE_ASN1_FUNCTIONS_const(PROXY_CERT_INFO_EXTENSION) struct ISSUING_DIST_POINT_st { DIST_POINT_NAME *distpoint; @@ -443,10 +443,14 @@ typedef struct x509_purpose_st { DEFINE_STACK_OF(X509_PURPOSE) -DECLARE_ASN1_FUNCTIONS(BASIC_CONSTRAINTS) +DECLARE_ASN1_FUNCTIONS_const(BASIC_CONSTRAINTS) +// TODO(https://crbug.com/boringssl/407): This is not const because it contains +// an |X509_NAME|. DECLARE_ASN1_FUNCTIONS(AUTHORITY_KEYID) +// TODO(https://crbug.com/boringssl/407): This is not const because it contains +// an |X509_NAME|. DECLARE_ASN1_FUNCTIONS(GENERAL_NAME) OPENSSL_EXPORT GENERAL_NAME *GENERAL_NAME_dup(GENERAL_NAME *a); @@ -470,6 +474,8 @@ OPENSSL_EXPORT STACK_OF(CONF_VALUE) *i2v_GENERAL_NAME( STACK_OF(CONF_VALUE) *ret); OPENSSL_EXPORT int GENERAL_NAME_print(BIO *out, GENERAL_NAME *gen); +// TODO(https://crbug.com/boringssl/407): This is not const because it contains +// an |X509_NAME|. DECLARE_ASN1_FUNCTIONS(GENERAL_NAMES) // i2v_GENERAL_NAMES serializes |gen| as a list of |CONF_VALUE|s. If |ret| is @@ -488,8 +494,8 @@ OPENSSL_EXPORT GENERAL_NAMES *v2i_GENERAL_NAMES(const X509V3_EXT_METHOD *method, X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval); -DECLARE_ASN1_FUNCTIONS(OTHERNAME) -DECLARE_ASN1_FUNCTIONS(EDIPARTYNAME) +DECLARE_ASN1_FUNCTIONS_const(OTHERNAME) +DECLARE_ASN1_FUNCTIONS_const(EDIPARTYNAME) OPENSSL_EXPORT int OTHERNAME_cmp(OTHERNAME *a, OTHERNAME *b); OPENSSL_EXPORT void GENERAL_NAME_set0_value(GENERAL_NAME *a, int type, void *value); @@ -506,18 +512,26 @@ OPENSSL_EXPORT char *i2s_ASN1_OCTET_STRING(const X509V3_EXT_METHOD *method, OPENSSL_EXPORT ASN1_OCTET_STRING *s2i_ASN1_OCTET_STRING( const X509V3_EXT_METHOD *method, X509V3_CTX *ctx, const char *str); -DECLARE_ASN1_FUNCTIONS(EXTENDED_KEY_USAGE) +DECLARE_ASN1_FUNCTIONS_const(EXTENDED_KEY_USAGE) OPENSSL_EXPORT int i2a_ACCESS_DESCRIPTION(BIO *bp, const ACCESS_DESCRIPTION *a); -DECLARE_ASN1_FUNCTIONS(CERTIFICATEPOLICIES) -DECLARE_ASN1_FUNCTIONS(POLICYINFO) -DECLARE_ASN1_FUNCTIONS(POLICYQUALINFO) -DECLARE_ASN1_FUNCTIONS(USERNOTICE) -DECLARE_ASN1_FUNCTIONS(NOTICEREF) +DECLARE_ASN1_FUNCTIONS_const(CERTIFICATEPOLICIES) +DECLARE_ASN1_FUNCTIONS_const(POLICYINFO) +DECLARE_ASN1_FUNCTIONS_const(POLICYQUALINFO) +DECLARE_ASN1_FUNCTIONS_const(USERNOTICE) +DECLARE_ASN1_FUNCTIONS_const(NOTICEREF) +// TODO(https://crbug.com/boringssl/407): This is not const because it contains +// an |X509_NAME|. DECLARE_ASN1_FUNCTIONS(CRL_DIST_POINTS) +// TODO(https://crbug.com/boringssl/407): This is not const because it contains +// an |X509_NAME|. DECLARE_ASN1_FUNCTIONS(DIST_POINT) +// TODO(https://crbug.com/boringssl/407): This is not const because it contains +// an |X509_NAME|. DECLARE_ASN1_FUNCTIONS(DIST_POINT_NAME) +// TODO(https://crbug.com/boringssl/407): This is not const because it contains +// an |X509_NAME|. DECLARE_ASN1_FUNCTIONS(ISSUING_DIST_POINT) OPENSSL_EXPORT int DIST_POINT_set_dpname(DIST_POINT_NAME *dpn, @@ -525,7 +539,11 @@ OPENSSL_EXPORT int DIST_POINT_set_dpname(DIST_POINT_NAME *dpn, OPENSSL_EXPORT int NAME_CONSTRAINTS_check(X509 *x, NAME_CONSTRAINTS *nc); +// TODO(https://crbug.com/boringssl/407): This is not const because it contains +// an |X509_NAME|. DECLARE_ASN1_FUNCTIONS(ACCESS_DESCRIPTION) +// TODO(https://crbug.com/boringssl/407): This is not const because it contains +// an |X509_NAME|. DECLARE_ASN1_FUNCTIONS(AUTHORITY_INFO_ACCESS) DECLARE_ASN1_ITEM(POLICY_MAPPING) From f022e8421b927296d50436ae7b4b54fa4019cf41 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Sat, 25 Jun 2022 22:47:15 -0400 Subject: [PATCH 14/38] Remove X509_REQ's refcount. We have no X509_REQ_up_ref function, and neither does OpenSSL. That means this reference count is unreachable, so remove it. Change-Id: I6a0899b8fcb0716d47c89174b561e90d99a9b54b Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/53306 Reviewed-by: Bob Beck Commit-Queue: David Benjamin --- crypto/x509/internal.h | 1 - crypto/x509/x_req.c | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/crypto/x509/internal.h b/crypto/x509/internal.h index 23c961e871..77f2d976c7 100644 --- a/crypto/x509/internal.h +++ b/crypto/x509/internal.h @@ -181,7 +181,6 @@ struct X509_req_st { X509_REQ_INFO *req_info; X509_ALGOR *sig_alg; ASN1_BIT_STRING *signature; - CRYPTO_refcount_t references; } /* X509_REQ */; struct x509_revoked_st { diff --git a/crypto/x509/x_req.c b/crypto/x509/x_req.c index f7faf39252..59cfbab74d 100644 --- a/crypto/x509/x_req.c +++ b/crypto/x509/x_req.c @@ -105,11 +105,11 @@ ASN1_SEQUENCE_enc(X509_REQ_INFO, enc, rinf_cb) = { IMPLEMENT_ASN1_FUNCTIONS(X509_REQ_INFO) -ASN1_SEQUENCE_ref(X509_REQ, 0) = { +ASN1_SEQUENCE(X509_REQ) = { ASN1_SIMPLE(X509_REQ, req_info, X509_REQ_INFO), ASN1_SIMPLE(X509_REQ, sig_alg, X509_ALGOR), ASN1_SIMPLE(X509_REQ, signature, ASN1_BIT_STRING), -} ASN1_SEQUENCE_END_ref(X509_REQ, X509_REQ) +} ASN1_SEQUENCE_END(X509_REQ) IMPLEMENT_ASN1_FUNCTIONS(X509_REQ) From 534970f39203d3aac98dfcf07bf87a15d2e9f75e Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Fri, 8 Jul 2022 18:00:29 -0400 Subject: [PATCH 15/38] Remove X509_ALGORS. I found no uses of this. If we have to put it back, it's no big deal, but one less group of functions to have to document. (SEQUENCE OF AlgorithmIdentifier is mostly a weird PKCS#7 thing.) Update-Note: X509_ALGORS is removed. If someone was relying on it, we can re-export it. Change-Id: I2b8e8d0d1d56d2debf99687023bc3621e92f6b08 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/53307 Commit-Queue: David Benjamin Reviewed-by: Bob Beck --- crypto/x509/x_algor.c | 7 ------- include/openssl/x509.h | 4 ---- 2 files changed, 11 deletions(-) diff --git a/crypto/x509/x_algor.c b/crypto/x509/x_algor.c index a2d778a7ef..819aee5f35 100644 --- a/crypto/x509/x_algor.c +++ b/crypto/x509/x_algor.c @@ -69,14 +69,7 @@ ASN1_SEQUENCE(X509_ALGOR) = { ASN1_OPT(X509_ALGOR, parameter, ASN1_ANY), } ASN1_SEQUENCE_END(X509_ALGOR) -ASN1_ITEM_TEMPLATE(X509_ALGORS) = ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, - 0, algorithms, - X509_ALGOR) -ASN1_ITEM_TEMPLATE_END(X509_ALGORS) - IMPLEMENT_ASN1_FUNCTIONS_const(X509_ALGOR) -IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(X509_ALGORS, X509_ALGORS, - X509_ALGORS) IMPLEMENT_ASN1_DUP_FUNCTION_const(X509_ALGOR) int X509_ALGOR_set0(X509_ALGOR *alg, ASN1_OBJECT *aobj, int ptype, void *pval) { diff --git a/include/openssl/x509.h b/include/openssl/x509.h index 673edfecbe..e0f4a3bb3c 100644 --- a/include/openssl/x509.h +++ b/include/openssl/x509.h @@ -119,8 +119,6 @@ DECLARE_ASN1_FUNCTIONS_const(X509_ALGOR) DEFINE_STACK_OF(X509_ALGOR) -typedef STACK_OF(X509_ALGOR) X509_ALGORS; - DEFINE_STACK_OF(X509_NAME_ENTRY) DEFINE_STACK_OF(X509_NAME) @@ -799,8 +797,6 @@ OPENSSL_EXPORT const char *X509_get_default_cert_dir_env(void); OPENSSL_EXPORT const char *X509_get_default_cert_file_env(void); OPENSSL_EXPORT const char *X509_get_default_private_dir(void); -DECLARE_ASN1_ENCODE_FUNCTIONS_const(X509_ALGORS, X509_ALGORS) - DECLARE_ASN1_FUNCTIONS_const(X509_PUBKEY) // X509_PUBKEY_set serializes |pkey| into a newly-allocated |X509_PUBKEY| From c8d31372f7342707d8c6e40c814ce1b64fe36086 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Tue, 12 Jul 2022 11:46:03 -0400 Subject: [PATCH 16/38] Bump CMake requirement to 3.8. CMake 3.8 was released April 10, 2017, which puts it past our five year horizon. (CMake 3.9 is just a few days short of it, so using 3.8 for now.) In particular, depending on 3.7+ gets us some nice features like VERSION_GREATER_EQUAL. Change-Id: I90457ad41e7add3c6b2dd3664da964c4b6ede499 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/53345 Commit-Queue: Adam Langley Auto-Submit: David Benjamin Reviewed-by: Adam Langley Commit-Queue: David Benjamin --- BUILDING.md | 2 +- CMakeLists.txt | 15 +++++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/BUILDING.md b/BUILDING.md index e7dfd6ea96..73bc29c1ea 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -10,7 +10,7 @@ Unless otherwise noted, build tools must at most five years old, matching [Abseil guidelines](https://abseil.io/about/compatibility). If in doubt, use the most recent stable version of each tool. - * [CMake](https://cmake.org/download/) 3.5 or later is required. + * [CMake](https://cmake.org/download/) 3.8 or later is required. * A recent version of Perl is required. On Windows, [Active State Perl](http://www.activestate.com/activeperl/) has been diff --git a/CMakeLists.txt b/CMakeLists.txt index 766c839779..0864958aa9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION 3.8) # Defer enabling C and CXX languages. project(BoringSSL NONE) @@ -160,7 +160,7 @@ if(CMAKE_COMPILER_IS_GNUCXX OR CLANG) set(C_CXX_FLAGS "${C_CXX_FLAGS} -Wno-free-nonheap-object") endif() - if(CLANG OR NOT "7.0.0" VERSION_GREATER CMAKE_C_COMPILER_VERSION) + if(CLANG OR CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL "7.0.0") set(C_CXX_FLAGS "${C_CXX_FLAGS} -Wimplicit-fallthrough") endif() @@ -406,10 +406,13 @@ endif() function(go_executable dest package) set(godeps "${CMAKE_SOURCE_DIR}/util/godeps.go") - if(CMAKE_VERSION VERSION_LESS "3.7" OR NOT CMAKE_GENERATOR STREQUAL "Ninja") - # The DEPFILE parameter to add_custom_command is new as of CMake 3.7 and - # only works with Ninja. Query the sources at configure time. Additionally, - # everything depends on go.mod. That affects what external packages to use. + if(NOT CMAKE_GENERATOR STREQUAL "Ninja") + # The DEPFILE parameter to add_custom_command only works with Ninja. Query + # the sources at configure time. Additionally, everything depends on go.mod. + # That affects what external packages to use. + # + # TODO(davidben): Starting CMake 3.20, it also works with Make. Starting + # 3.21, it works with Visual Studio and Xcode too. execute_process(COMMAND ${GO_EXECUTABLE} run ${godeps} -format cmake -pkg ${package} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} From 28127936ad1f9424757c49c27349bae1e7d6a2dd Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Sat, 25 Jun 2022 21:30:08 -0400 Subject: [PATCH 17/38] Start expanding DECLARE_ASN1_* macros in x509.h. This only does a few of them for now, in preparation for the following CL, which tries to group things into sections. Bug: 426 Change-Id: I4604d458ff2d8e81c8c8f0361a519e5291b8e119 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/53308 Commit-Queue: David Benjamin Commit-Queue: Bob Beck Reviewed-by: Bob Beck --- include/openssl/x509.h | 100 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 90 insertions(+), 10 deletions(-) diff --git a/include/openssl/x509.h b/include/openssl/x509.h index e0f4a3bb3c..08c0dc3815 100644 --- a/include/openssl/x509.h +++ b/include/openssl/x509.h @@ -115,7 +115,25 @@ struct X509_algor_st { ASN1_TYPE *parameter; } /* X509_ALGOR */; -DECLARE_ASN1_FUNCTIONS_const(X509_ALGOR) +// X509_ALGOR is an |ASN1_ITEM| whose ASN.1 type is AlgorithmIdentifier and C +// type is |X509_ALGOR*|. +DECLARE_ASN1_ITEM(X509_ALGOR) + +// X509_ALGOR_new returns a newly-allocated, empty |X509_ALGOR| object, or NULL +// on error. +OPENSSL_EXPORT X509_ALGOR *X509_ALGOR_new(void); + +// X509_ALGOR_free releases memory associated with |alg|. +OPENSSL_EXPORT void X509_ALGOR_free(X509_ALGOR *alg); + +// d2i_X509_ALGOR parses up to |len| bytes from |*inp| as a DER-encoded +// AlgorithmIdentifier, as described in |d2i_SAMPLE_with_reuse|. +OPENSSL_EXPORT X509_ALGOR *d2i_X509_ALGOR(X509_ALGOR **out, const uint8_t **inp, + long len); + +// i2d_X509_ALGOR marshals |alg| as a DER-encoded AlgorithmIdentifier, as +// described in |i2d_SAMPLE|. +OPENSSL_EXPORT int i2d_X509_ALGOR(const X509_ALGOR *alg, uint8_t **outp); DEFINE_STACK_OF(X509_ALGOR) @@ -812,9 +830,29 @@ OPENSSL_EXPORT EVP_PKEY *X509_PUBKEY_get(X509_PUBKEY *key); DECLARE_ASN1_FUNCTIONS_const(X509_SIG) -// TODO(https://crbug.com/boringssl/407): This is not const because it contains -// an |X509_NAME|. -DECLARE_ASN1_FUNCTIONS(X509_REQ) +// X509_REQ is an |ASN1_ITEM| whose ASN.1 type is CertificateRequest (RFC 2986) +// and C type is |X509_REQ*|. +DECLARE_ASN1_ITEM(X509_REQ) + +// X509_REQ_new returns a newly-allocated, empty |X509_REQ| object, or NULL on +// error. This object may be filled in and then signed to construct a CSR. +OPENSSL_EXPORT X509_REQ *X509_REQ_new(void); + +// X509_REQ_free releases memory associated with |req|. +OPENSSL_EXPORT void X509_REQ_free(X509_REQ *req); + +// d2i_X509_REQ parses up to |len| bytes from |*inp| as a DER-encoded +// CertificateRequest (RFC 2986), as described in |d2i_SAMPLE_with_reuse|. +OPENSSL_EXPORT X509_REQ *d2i_X509_REQ(X509_REQ **out, const uint8_t **inp, + long len); + +// i2d_X509_REQ marshals |req| as a CertificateRequest (RFC 2986), as described +// in |i2d_SAMPLE|. +// +// TODO(https://crbug.com/boringssl/407): This function should be const and +// thread-safe but is currently neither in some cases, notably if |req| was +// mutated. +OPENSSL_EXPORT int i2d_X509_REQ(X509_REQ *req, uint8_t **outp); DECLARE_ASN1_FUNCTIONS_const(X509_ATTRIBUTE) @@ -838,9 +876,29 @@ DECLARE_ASN1_FUNCTIONS(X509_NAME) // to the copy, and returns one. Otherwise, it returns zero. OPENSSL_EXPORT int X509_NAME_set(X509_NAME **xn, X509_NAME *name); -// TODO(https://crbug.com/boringssl/407): This is not const because it contains -// an |X509_NAME|. -DECLARE_ASN1_FUNCTIONS(X509) +// X509 is an |ASN1_ITEM| whose ASN.1 type is X.509 Certificate (RFC 5280) and C +// type is |X509*|. +DECLARE_ASN1_ITEM(X509) + +// X509_new returns a newly-allocated, empty |X509| object, or NULL on error. +// This object may be filled in and then signed to construct a certificate. +OPENSSL_EXPORT X509 *X509_new(void); + +// X509_free decrements |x509|'s reference count and, if zero, releases memory +// associated with |x509|. +OPENSSL_EXPORT void X509_free(X509 *x509); + +// d2i_X509 parses up to |len| bytes from |*inp| as a DER-encoded X.509 +// Certificate (RFC 5280), as described in |d2i_SAMPLE_with_reuse|. +OPENSSL_EXPORT X509 *d2i_X509(X509 **out, const uint8_t **inp, long len); + +// i2d_X509 marshals |x509| as a DER-encoded X.509 Certificate (RFC 5280), as +// described in |i2d_SAMPLE|. +// +// TODO(https://crbug.com/boringssl/407): This function should be const and +// thread-safe but is currently neither in some cases, notably if |x509| was +// mutated. +OPENSSL_EXPORT int i2d_X509(X509 *x509, uint8_t **outp); // X509_up_ref adds one to the reference count of |x509| and returns one. OPENSSL_EXPORT int X509_up_ref(X509 *x509); @@ -981,9 +1039,31 @@ OPENSSL_EXPORT int X509_TRUST_set(int *t, int trust); // TODO(https://crbug.com/boringssl/407): This is not const because it contains // an |X509_NAME|. DECLARE_ASN1_FUNCTIONS(X509_REVOKED) -// TODO(https://crbug.com/boringssl/407): This is not const because it contains -// an |X509_NAME|. -DECLARE_ASN1_FUNCTIONS(X509_CRL) + +// X509_CRL is an |ASN1_ITEM| whose ASN.1 type is X.509 CertificateList (RFC +// 5280) and C type is |X509_CRL*|. +DECLARE_ASN1_ITEM(X509_CRL) + +// X509_CRL_new returns a newly-allocated, empty |X509_CRL| object, or NULL on +// error. This object may be filled in and then signed to construct a CRL. +OPENSSL_EXPORT X509_CRL *X509_CRL_new(void); + +// X509_CRL_free decrements |crl|'s reference count and, if zero, releases +// memory associated with |crl|. +OPENSSL_EXPORT void X509_CRL_free(X509_CRL *crl); + +// d2i_X509_CRL parses up to |len| bytes from |*inp| as a DER-encoded X.509 +// CertificateList (RFC 5280), as described in |d2i_SAMPLE_with_reuse|. +OPENSSL_EXPORT X509_CRL *d2i_X509_CRL(X509_CRL **out, const uint8_t **inp, + long len); + +// i2d_X509_CRL marshals |crl| as a X.509 CertificateList (RFC 5280), as +// described in |i2d_SAMPLE|. +// +// TODO(https://crbug.com/boringssl/407): This function should be const and +// thread-safe but is currently neither in some cases, notably if |crl| was +// mutated. +OPENSSL_EXPORT int i2d_X509_CRL(X509_CRL *crl, uint8_t **outp); OPENSSL_EXPORT int X509_CRL_add0_revoked(X509_CRL *crl, X509_REVOKED *rev); OPENSSL_EXPORT int X509_CRL_get0_by_serial(X509_CRL *crl, X509_REVOKED **ret, From 4363bdd269a1c377b4355f99e943530e473e74d1 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Wed, 6 Apr 2022 15:19:16 -0400 Subject: [PATCH 18/38] Start grouping x509.h into sections. In particular, since mutating X509s (and X509_CRLs and X509_REQs) does confusing things, I've split the mutation functions into their own section, which discusses constructing new objects. Bug: 426 Change-Id: I1f7dbc5e47f78433e34c74f0cd966803a213e59a Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/53309 Reviewed-by: Bob Beck Commit-Queue: David Benjamin --- include/openssl/x509.h | 1544 +++++++++++++++++++++------------------- 1 file changed, 821 insertions(+), 723 deletions(-) diff --git a/include/openssl/x509.h b/include/openssl/x509.h index 08c0dc3815..5f04055d27 100644 --- a/include/openssl/x509.h +++ b/include/openssl/x509.h @@ -90,11 +90,797 @@ extern "C" { // Legacy X.509 library. // // This header is part of OpenSSL's X.509 implementation. It is retained for -// compatibility but otherwise underdocumented and not actively maintained. In -// the future, a replacement library will be available. Meanwhile, minimize +// compatibility but should not be used by new code. The functions are difficult +// to use correctly, and have buggy or non-standard behaviors. They are thus +// particularly prone to behavior changes and API removals, as BoringSSL +// iterates on these issues. +// +// In the future, a replacement library will be available. Meanwhile, minimize // dependencies on this header where possible. +// +// TODO(https://crbug.com/boringssl/426): Documentation for this library is +// still in progress. Some functions have not yet been documented, and some +// functions have not yet been grouped into sections. + + +// Certificates. +// +// An |X509| object represents an X.509 certificate, defined in RFC 5280. +// +// Although an |X509| is a mutable object, mutating an |X509| can give incorrect +// results. Callers typically obtain |X509|s by parsing some input with +// |d2i_X509|, etc. Such objects carry information such as the serialized +// TBSCertificate and decoded extensions, which will become inconsistent when +// mutated. +// +// Instead, mutation functions should only be used when issuing new +// certificates, as described in a later section. + +DEFINE_STACK_OF(X509) + +// X509 is an |ASN1_ITEM| whose ASN.1 type is X.509 Certificate (RFC 5280) and C +// type is |X509*|. +DECLARE_ASN1_ITEM(X509) + +// X509_up_ref adds one to the reference count of |x509| and returns one. +OPENSSL_EXPORT int X509_up_ref(X509 *x509); + +// X509_chain_up_ref returns a newly-allocated |STACK_OF(X509)| containing a +// shallow copy of |chain|, or NULL on error. That is, the return value has the +// same contents as |chain|, and each |X509|'s reference count is incremented by +// one. +OPENSSL_EXPORT STACK_OF(X509) *X509_chain_up_ref(STACK_OF(X509) *chain); + +// X509_free decrements |x509|'s reference count and, if zero, releases memory +// associated with |x509|. +OPENSSL_EXPORT void X509_free(X509 *x509); + +// d2i_X509 parses up to |len| bytes from |*inp| as a DER-encoded X.509 +// Certificate (RFC 5280), as described in |d2i_SAMPLE_with_reuse|. +OPENSSL_EXPORT X509 *d2i_X509(X509 **out, const uint8_t **inp, long len); + +// X509_parse_from_buffer parses an X.509 structure from |buf| and returns a +// fresh X509 or NULL on error. There must not be any trailing data in |buf|. +// The returned structure (if any) holds a reference to |buf| rather than +// copying parts of it as a normal |d2i_X509| call would do. +OPENSSL_EXPORT X509 *X509_parse_from_buffer(CRYPTO_BUFFER *buf); + +// i2d_X509 marshals |x509| as a DER-encoded X.509 Certificate (RFC 5280), as +// described in |i2d_SAMPLE|. +// +// TODO(https://crbug.com/boringssl/407): This function should be const and +// thread-safe but is currently neither in some cases, notably if |x509| was +// mutated. +OPENSSL_EXPORT int i2d_X509(X509 *x509, uint8_t **outp); + +// X509_VERSION_* are X.509 version numbers. Note the numerical values of all +// defined X.509 versions are one less than the named version. +#define X509_VERSION_1 0 +#define X509_VERSION_2 1 +#define X509_VERSION_3 2 + +// X509_get_version returns the numerical value of |x509|'s version, which will +// be one of the |X509_VERSION_*| constants. +OPENSSL_EXPORT long X509_get_version(const X509 *x509); + +// X509_get0_serialNumber returns |x509|'s serial number. +OPENSSL_EXPORT const ASN1_INTEGER *X509_get0_serialNumber(const X509 *x509); + +// X509_get0_notBefore returns |x509|'s notBefore time. +OPENSSL_EXPORT const ASN1_TIME *X509_get0_notBefore(const X509 *x509); + +// X509_get0_notAfter returns |x509|'s notAfter time. +OPENSSL_EXPORT const ASN1_TIME *X509_get0_notAfter(const X509 *x509); + +// X509_get_issuer_name returns |x509|'s issuer. +OPENSSL_EXPORT X509_NAME *X509_get_issuer_name(const X509 *x509); + +// X509_get_subject_name returns |x509|'s subject. +OPENSSL_EXPORT X509_NAME *X509_get_subject_name(const X509 *x509); + +// X509_get_X509_PUBKEY returns the public key of |x509|. Note this function is +// not const-correct for legacy reasons. Callers should not modify the returned +// object. +OPENSSL_EXPORT X509_PUBKEY *X509_get_X509_PUBKEY(const X509 *x509); + +// X509_get_pubkey returns |x509|'s public key as an |EVP_PKEY|, or NULL if the +// public key was unsupported or could not be decoded. This function returns a +// reference to the |EVP_PKEY|. The caller must release the result with +// |EVP_PKEY_free| when done. +OPENSSL_EXPORT EVP_PKEY *X509_get_pubkey(X509 *x509); + +// X509_get0_pubkey_bitstr returns the BIT STRING portion of |x509|'s public +// key. Note this does not contain the AlgorithmIdentifier portion. +// +// WARNING: This function returns a non-const pointer for OpenSSL compatibility, +// but the caller must not modify the resulting object. Doing so will break +// internal invariants in |x509|. +OPENSSL_EXPORT ASN1_BIT_STRING *X509_get0_pubkey_bitstr(const X509 *x509); + +// X509_get0_uids sets |*out_issuer_uid| to a non-owning pointer to the +// issuerUID field of |x509|, or NULL if |x509| has no issuerUID. It similarly +// outputs |x509|'s subjectUID field to |*out_subject_uid|. +// +// Callers may pass NULL to either |out_issuer_uid| or |out_subject_uid| to +// ignore the corresponding field. +OPENSSL_EXPORT void X509_get0_uids(const X509 *x509, + const ASN1_BIT_STRING **out_issuer_uid, + const ASN1_BIT_STRING **out_subject_uid); + +// X509_get0_extensions returns |x509|'s extension list, or NULL if |x509| omits +// it. +OPENSSL_EXPORT const STACK_OF(X509_EXTENSION) *X509_get0_extensions( + const X509 *x509); + +// X509_get0_tbs_sigalg returns the signature algorithm in |x509|'s +// TBSCertificate. For the outer signature algorithm, see |X509_get0_signature|. +// +// Certificates with mismatched signature algorithms will successfully parse, +// but they will be rejected when verifying. +OPENSSL_EXPORT const X509_ALGOR *X509_get0_tbs_sigalg(const X509 *x509); + +// X509_get0_signature sets |*out_sig| and |*out_alg| to the signature and +// signature algorithm of |x509|, respectively. Either output pointer may be +// NULL to ignore the value. +// +// This function outputs the outer signature algorithm. For the one in the +// TBSCertificate, see |X509_get0_tbs_sigalg|. Certificates with mismatched +// signature algorithms will successfully parse, but they will be rejected when +// verifying. +OPENSSL_EXPORT void X509_get0_signature(const ASN1_BIT_STRING **out_sig, + const X509_ALGOR **out_alg, + const X509 *x509); + +// X509_get_signature_nid returns the NID corresponding to |x509|'s signature +// algorithm, or |NID_undef| if the signature algorithm does not correspond to +// a known NID. +OPENSSL_EXPORT int X509_get_signature_nid(const X509 *x509); + +// i2d_X509_tbs serializes the TBSCertificate portion of |x509|, as described in +// |i2d_SAMPLE|. +// +// This function preserves the original encoding of the TBSCertificate and may +// not reflect modifications made to |x509|. It may be used to manually verify +// the signature of an existing certificate. To generate certificates, use +// |i2d_re_X509_tbs| instead. +OPENSSL_EXPORT int i2d_X509_tbs(X509 *x509, unsigned char **outp); + + +// Issuing certificates. +// +// An |X509| object may also represent an incomplete certificate. Callers may +// construct empty |X509| objects, fill in fields individually, and finally sign +// the result. The following functions may be used for this purpose. + +// X509_new returns a newly-allocated, empty |X509| object, or NULL on error. +// This produces an incomplete certificate which may be filled in to issue a new +// certificate. +OPENSSL_EXPORT X509 *X509_new(void); + +// X509_set_version sets |x509|'s version to |version|, which should be one of +// the |X509V_VERSION_*| constants. It returns one on success and zero on error. +// +// If unsure, use |X509_VERSION_3|. +OPENSSL_EXPORT int X509_set_version(X509 *x509, long version); + +// X509_set_serialNumber sets |x509|'s serial number to |serial|. It returns one +// on success and zero on error. +OPENSSL_EXPORT int X509_set_serialNumber(X509 *x509, + const ASN1_INTEGER *serial); + +// X509_set1_notBefore sets |x509|'s notBefore time to |tm|. It returns one on +// success and zero on error. +OPENSSL_EXPORT int X509_set1_notBefore(X509 *x509, const ASN1_TIME *tm); + +// X509_set1_notAfter sets |x509|'s notAfter time to |tm|. it returns one on +// success and zero on error. +OPENSSL_EXPORT int X509_set1_notAfter(X509 *x509, const ASN1_TIME *tm); + +// X509_getm_notBefore returns a mutable pointer to |x509|'s notBefore time. +OPENSSL_EXPORT ASN1_TIME *X509_getm_notBefore(X509 *x509); + +// X509_getm_notAfter returns a mutable pointer to |x509|'s notAfter time. +OPENSSL_EXPORT ASN1_TIME *X509_getm_notAfter(X509 *x); + +// X509_set_issuer_name sets |x509|'s issuer to a copy of |name|. It returns one +// on success and zero on error. +OPENSSL_EXPORT int X509_set_issuer_name(X509 *x509, X509_NAME *name); + +// X509_set_subject_name sets |x509|'s subject to a copy of |name|. It returns +// one on success and zero on error. +OPENSSL_EXPORT int X509_set_subject_name(X509 *x509, X509_NAME *name); + +// X509_set_pubkey sets |x509|'s public key to |pkey|. It returns one on success +// and zero on error. This function does not take ownership of |pkey| and +// internally copies and updates reference counts as needed. +OPENSSL_EXPORT int X509_set_pubkey(X509 *x509, EVP_PKEY *pkey); + +// X509_sign signs |x509| with |pkey| and replaces the signature algorithm and +// signature fields. It returns one on success and zero on error. This function +// uses digest algorithm |md|, or |pkey|'s default if NULL. Other signing +// parameters use |pkey|'s defaults. To customize them, use |X509_sign_ctx|. +OPENSSL_EXPORT int X509_sign(X509 *x509, EVP_PKEY *pkey, const EVP_MD *md); + +// X509_sign_ctx signs |x509| with |ctx| and replaces the signature algorithm +// and signature fields. It returns one on success and zero on error. The +// signature algorithm and parameters come from |ctx|, which must have been +// initialized with |EVP_DigestSignInit|. The caller should configure the +// corresponding |EVP_PKEY_CTX| before calling this function. +OPENSSL_EXPORT int X509_sign_ctx(X509 *x509, EVP_MD_CTX *ctx); + +// i2d_re_X509_tbs serializes the TBSCertificate portion of |x509|, as described +// in |i2d_SAMPLE|. +// +// This function re-encodes the TBSCertificate and may not reflect |x509|'s +// original encoding. It may be used to manually generate a signature for a new +// certificate. To verify certificates, use |i2d_X509_tbs| instead. +OPENSSL_EXPORT int i2d_re_X509_tbs(X509 *x509, unsigned char **outp); + +// X509_set1_signature_algo sets |x509|'s signature algorithm to |algo| and +// returns one on success or zero on error. It updates both the signature field +// of the TBSCertificate structure, and the signatureAlgorithm field of the +// Certificate. +OPENSSL_EXPORT int X509_set1_signature_algo(X509 *x509, const X509_ALGOR *algo); + +// X509_set1_signature_value sets |x509|'s signature to a copy of the |sig_len| +// bytes pointed by |sig|. It returns one on success and zero on error. +// +// Due to a specification error, X.509 certificates store signatures in ASN.1 +// BIT STRINGs, but signature algorithms return byte strings rather than bit +// strings. This function creates a BIT STRING containing a whole number of +// bytes, with the bit order matching the DER encoding. This matches the +// encoding used by all X.509 signature algorithms. +OPENSSL_EXPORT int X509_set1_signature_value(X509 *x509, const uint8_t *sig, + size_t sig_len); + + +// Auxiliary certificate properties. +// +// |X509| objects optionally maintain auxiliary properties. These are not part +// of the certificates themselves, and thus are not covered by signatures or +// preserved by the standard serialization. They are used as inputs or outputs +// to other functions in this library. + +// i2d_X509_AUX marshals |x509| as a DER-encoded X.509 Certificate (RFC 5280), +// followed optionally by a separate, OpenSSL-specific structure with auxiliary +// properties. It behaves as described in |i2d_SAMPLE|. +// +// Unlike similarly-named functions, this function does not output a single +// ASN.1 element. Directly embedding the output in a larger ASN.1 structure will +// not behave correctly. +OPENSSL_EXPORT int i2d_X509_AUX(X509 *x509, unsigned char **outp); + +// d2i_X509_AUX parses up to |length| bytes from |*inp| as a DER-encoded X.509 +// Certificate (RFC 5280), followed optionally by a separate, OpenSSL-specific +// structure with auxiliary properties. It behaves as described in +// |d2i_SAMPLE_with_reuse|. +// +// Some auxiliary properties affect trust decisions, so this function should not +// be used with untrusted input. +// +// Unlike similarly-named functions, this function does not parse a single +// ASN.1 element. Trying to parse data directly embedded in a larger ASN.1 +// structure will not behave correctly. +OPENSSL_EXPORT X509 *d2i_X509_AUX(X509 **x509, const unsigned char **inp, + long length); + +// X509_alias_set1 sets |x509|'s alias to |len| bytes from |name|. If |name| is +// NULL, the alias is cleared instead. Aliases are not part of the certificate +// itself and will not be serialized by |i2d_X509|. +OPENSSL_EXPORT int X509_alias_set1(X509 *x509, const unsigned char *name, + int len); + +// X509_keyid_set1 sets |x509|'s key ID to |len| bytes from |id|. If |id| is +// NULL, the key ID is cleared instead. Key IDs are not part of the certificate +// itself and will not be serialized by |i2d_X509|. +OPENSSL_EXPORT int X509_keyid_set1(X509 *x509, const unsigned char *id, + int len); + +// X509_alias_get0 looks up |x509|'s alias. If found, it sets |*out_len| to the +// alias's length and returns a pointer to a buffer containing the contents. If +// not found, it outputs the empty string by returning NULL and setting +// |*out_len| to zero. +// +// If |x509| was parsed from a PKCS#12 structure (see +// |PKCS12_get_key_and_certs|), the alias will reflect the friendlyName +// attribute (RFC 2985). +// +// WARNING: In OpenSSL, this function did not set |*out_len| when the alias was +// missing. Callers that target both OpenSSL and BoringSSL should set the value +// to zero before calling this function. +OPENSSL_EXPORT unsigned char *X509_alias_get0(X509 *x509, int *out_len); + +// X509_keyid_get0 looks up |x509|'s key ID. If found, it sets |*out_len| to the +// key ID's length and returns a pointer to a buffer containing the contents. If +// not found, it outputs the empty string by returning NULL and setting +// |*out_len| to zero. +// +// WARNING: In OpenSSL, this function did not set |*out_len| when the alias was +// missing. Callers that target both OpenSSL and BoringSSL should set the value +// to zero before calling this function. +OPENSSL_EXPORT unsigned char *X509_keyid_get0(X509 *x509, int *out_len); + + +// Certificate revocation lists. +// +// An |X509_CRL| object represents an X.509 certificate revocation list (CRL), +// defined in RFC 5280. A CRL is a signed list of certificates which are no +// longer considered valid. +// +// Although an |X509_CRL| is a mutable object, mutating an |X509_CRL| can give +// incorrect results. Callers typically obtain |X509_CRL|s by parsing some input +// with |d2i_X509_CRL|, etc. Such objects carry information such as the +// serialized TBSCertList and decoded extensions, which will become inconsistent +// when mutated. +// +// Instead, mutation functions should only be used when issuing new CRLs, as +// described in a later section. + +DEFINE_STACK_OF(X509_CRL) + +// X509_CRL is an |ASN1_ITEM| whose ASN.1 type is X.509 CertificateList (RFC +// 5280) and C type is |X509_CRL*|. +DECLARE_ASN1_ITEM(X509_CRL) + +// X509_CRL_up_ref adds one to the reference count of |crl| and returns one. +OPENSSL_EXPORT int X509_CRL_up_ref(X509_CRL *crl); + +// X509_CRL_free decrements |crl|'s reference count and, if zero, releases +// memory associated with |crl|. +OPENSSL_EXPORT void X509_CRL_free(X509_CRL *crl); + +// d2i_X509_CRL parses up to |len| bytes from |*inp| as a DER-encoded X.509 +// CertificateList (RFC 5280), as described in |d2i_SAMPLE_with_reuse|. +OPENSSL_EXPORT X509_CRL *d2i_X509_CRL(X509_CRL **out, const uint8_t **inp, + long len); + +// i2d_X509_CRL marshals |crl| as a X.509 CertificateList (RFC 5280), as +// described in |i2d_SAMPLE|. +// +// TODO(https://crbug.com/boringssl/407): This function should be const and +// thread-safe but is currently neither in some cases, notably if |crl| was +// mutated. +OPENSSL_EXPORT int i2d_X509_CRL(X509_CRL *crl, uint8_t **outp); + +#define X509_CRL_VERSION_1 0 +#define X509_CRL_VERSION_2 1 + +// X509_CRL_get_version returns the numerical value of |crl|'s version, which +// will be one of the |X509_CRL_VERSION_*| constants. +OPENSSL_EXPORT long X509_CRL_get_version(const X509_CRL *crl); + +// X509_CRL_get0_lastUpdate returns |crl|'s lastUpdate time. +OPENSSL_EXPORT const ASN1_TIME *X509_CRL_get0_lastUpdate(const X509_CRL *crl); + +// X509_CRL_get0_nextUpdate returns |crl|'s nextUpdate time, or NULL if |crl| +// has none. +OPENSSL_EXPORT const ASN1_TIME *X509_CRL_get0_nextUpdate(const X509_CRL *crl); + +// X509_CRL_get_issuer returns |crl|'s issuer name. Note this function is not +// const-correct for legacy reasons. +OPENSSL_EXPORT X509_NAME *X509_CRL_get_issuer(const X509_CRL *crl); + +// X509_CRL_get_REVOKED returns the list of revoked certificates in |crl|, or +// NULL if |crl| omits it. +// +// TOOD(davidben): This function was originally a macro, without clear const +// semantics. It should take a const input and give const output, but the latter +// would break existing callers. For now, we match upstream. +OPENSSL_EXPORT STACK_OF(X509_REVOKED) *X509_CRL_get_REVOKED(X509_CRL *crl); + +// X509_CRL_get0_extensions returns |crl|'s extension list, or NULL if |crl| +// omits it. +OPENSSL_EXPORT const STACK_OF(X509_EXTENSION) *X509_CRL_get0_extensions( + const X509_CRL *crl); + +// X509_CRL_get0_signature sets |*out_sig| and |*out_alg| to the signature and +// signature algorithm of |crl|, respectively. Either output pointer may be NULL +// to ignore the value. +// +// This function outputs the outer signature algorithm, not the one in the +// TBSCertList. CRLs with mismatched signature algorithms will successfully +// parse, but they will be rejected when verifying. +OPENSSL_EXPORT void X509_CRL_get0_signature(const X509_CRL *crl, + const ASN1_BIT_STRING **out_sig, + const X509_ALGOR **out_alg); + +// X509_CRL_get_signature_nid returns the NID corresponding to |crl|'s signature +// algorithm, or |NID_undef| if the signature algorithm does not correspond to +// a known NID. +OPENSSL_EXPORT int X509_CRL_get_signature_nid(const X509_CRL *crl); + +// i2d_X509_CRL_tbs serializes the TBSCertList portion of |crl|, as described in +// |i2d_SAMPLE|. +// +// This function preserves the original encoding of the TBSCertList and may not +// reflect modifications made to |crl|. It may be used to manually verify the +// signature of an existing CRL. To generate CRLs, use |i2d_re_X509_CRL_tbs| +// instead. +OPENSSL_EXPORT int i2d_X509_CRL_tbs(X509_CRL *crl, unsigned char **outp); + + +// Issuing certificate revocation lists. +// +// An |X509_CRL| object may also represent an incomplete CRL. Callers may +// construct empty |X509_CRL| objects, fill in fields individually, and finally +// sign the result. The following functions may be used for this purpose. + +// X509_CRL_new returns a newly-allocated, empty |X509_CRL| object, or NULL on +// error. This object may be filled in and then signed to construct a CRL. +OPENSSL_EXPORT X509_CRL *X509_CRL_new(void); + +// X509_CRL_set_version sets |crl|'s version to |version|, which should be one +// of the |X509_CRL_VERSION_*| constants. It returns one on success and zero on +// error. +// +// If unsure, use |X509_CRL_VERSION_2|. Note that, unlike certificates, CRL +// versions are only defined up to v2. Callers should not use |X509_VERSION_3|. +OPENSSL_EXPORT int X509_CRL_set_version(X509_CRL *crl, long version); + +// X509_CRL_set_issuer_name sets |crl|'s issuer to a copy of |name|. It returns +// one on success and zero on error. +OPENSSL_EXPORT int X509_CRL_set_issuer_name(X509_CRL *crl, X509_NAME *name); + +// X509_CRL_set1_lastUpdate sets |crl|'s lastUpdate time to |tm|. It returns one +// on success and zero on error. +OPENSSL_EXPORT int X509_CRL_set1_lastUpdate(X509_CRL *crl, const ASN1_TIME *tm); + +// X509_CRL_set1_nextUpdate sets |crl|'s nextUpdate time to |tm|. It returns one +// on success and zero on error. +OPENSSL_EXPORT int X509_CRL_set1_nextUpdate(X509_CRL *crl, const ASN1_TIME *tm); + +// X509_CRL_sign signs |crl| with |pkey| and replaces the signature algorithm +// and signature fields. It returns one on success and zero on error. This +// function uses digest algorithm |md|, or |pkey|'s default if NULL. Other +// signing parameters use |pkey|'s defaults. To customize them, use +// |X509_CRL_sign_ctx|. +OPENSSL_EXPORT int X509_CRL_sign(X509_CRL *crl, EVP_PKEY *pkey, + const EVP_MD *md); + +// X509_CRL_sign_ctx signs |crl| with |ctx| and replaces the signature algorithm +// and signature fields. It returns one on success and zero on error. The +// signature algorithm and parameters come from |ctx|, which must have been +// initialized with |EVP_DigestSignInit|. The caller should configure the +// corresponding |EVP_PKEY_CTX| before calling this function. +OPENSSL_EXPORT int X509_CRL_sign_ctx(X509_CRL *crl, EVP_MD_CTX *ctx); + +// i2d_re_X509_CRL_tbs serializes the TBSCertList portion of |crl|, as described +// in |i2d_SAMPLE|. +// +// This function re-encodes the TBSCertList and may not reflect |crl|'s original +// encoding. It may be used to manually generate a signature for a new CRL. To +// verify CRLs, use |i2d_X509_CRL_tbs| instead. +OPENSSL_EXPORT int i2d_re_X509_CRL_tbs(X509_CRL *crl, unsigned char **outp); + +// X509_CRL_set1_signature_algo sets |crl|'s signature algorithm to |algo| and +// returns one on success or zero on error. It updates both the signature field +// of the TBSCertList structure, and the signatureAlgorithm field of the CRL. +OPENSSL_EXPORT int X509_CRL_set1_signature_algo(X509_CRL *crl, + const X509_ALGOR *algo); + +// X509_CRL_set1_signature_value sets |crl|'s signature to a copy of the +// |sig_len| bytes pointed by |sig|. It returns one on success and zero on +// error. +// +// Due to a specification error, X.509 CRLs store signatures in ASN.1 BIT +// STRINGs, but signature algorithms return byte strings rather than bit +// strings. This function creates a BIT STRING containing a whole number of +// bytes, with the bit order matching the DER encoding. This matches the +// encoding used by all X.509 signature algorithms. +OPENSSL_EXPORT int X509_CRL_set1_signature_value(X509_CRL *crl, + const uint8_t *sig, + size_t sig_len); + + +// Certificate requests. +// +// An |X509_REQ| represents a PKCS #10 certificate request (RFC 2986). These are +// also referred to as certificate signing requests or CSRs. CSRs are a common +// format used to request a certificate from a CA. +// +// Although an |X509_REQ| is a mutable object, mutating an |X509_REQ| can give +// incorrect results. Callers typically obtain |X509_REQ|s by parsing some input +// with |d2i_X509_REQ|, etc. Such objects carry information such as the +// serialized CertificationRequestInfo, which will become inconsistent when +// mutated. +// +// Instead, mutation functions should only be used when issuing new CRLs, as +// described in a later section. + +// X509_REQ is an |ASN1_ITEM| whose ASN.1 type is CertificateRequest (RFC 2986) +// and C type is |X509_REQ*|. +DECLARE_ASN1_ITEM(X509_REQ) + +// X509_REQ_free releases memory associated with |req|. +OPENSSL_EXPORT void X509_REQ_free(X509_REQ *req); + +// d2i_X509_REQ parses up to |len| bytes from |*inp| as a DER-encoded +// CertificateRequest (RFC 2986), as described in |d2i_SAMPLE_with_reuse|. +OPENSSL_EXPORT X509_REQ *d2i_X509_REQ(X509_REQ **out, const uint8_t **inp, + long len); + +// i2d_X509_REQ marshals |req| as a CertificateRequest (RFC 2986), as described +// in |i2d_SAMPLE|. +// +// TODO(https://crbug.com/boringssl/407): This function should be const and +// thread-safe but is currently neither in some cases, notably if |req| was +// mutated. +OPENSSL_EXPORT int i2d_X509_REQ(X509_REQ *req, uint8_t **outp); + + +// X509_REQ_VERSION_1 is the version constant for |X509_REQ| objects. No other +// versions are defined. +#define X509_REQ_VERSION_1 0 + +// X509_REQ_get_version returns the numerical value of |req|'s version. This +// will always be |X509_REQ_VERSION_1| for valid CSRs. For compatibility, +// |d2i_X509_REQ| also accepts some invalid version numbers, in which case this +// function may return other values. +OPENSSL_EXPORT long X509_REQ_get_version(const X509_REQ *req); + +// X509_REQ_get_subject_name returns |req|'s subject name. Note this function is +// not const-correct for legacy reasons. +OPENSSL_EXPORT X509_NAME *X509_REQ_get_subject_name(const X509_REQ *req); + +// X509_REQ_get_pubkey returns |req|'s public key as an |EVP_PKEY|, or NULL if +// the public key was unsupported or could not be decoded. This function returns +// a reference to the |EVP_PKEY|. The caller must release the result with +// |EVP_PKEY_free| when done. +OPENSSL_EXPORT EVP_PKEY *X509_REQ_get_pubkey(X509_REQ *req); + +// X509_REQ_get0_signature sets |*out_sig| and |*out_alg| to the signature and +// signature algorithm of |req|, respectively. Either output pointer may be NULL +// to ignore the value. +OPENSSL_EXPORT void X509_REQ_get0_signature(const X509_REQ *req, + const ASN1_BIT_STRING **out_sig, + const X509_ALGOR **out_alg); + +// X509_REQ_get_signature_nid returns the NID corresponding to |req|'s signature +// algorithm, or |NID_undef| if the signature algorithm does not correspond to +// a known NID. +OPENSSL_EXPORT int X509_REQ_get_signature_nid(const X509_REQ *req); + + +// Issuing certificate requests. +// +// An |X509_REQ| object may also represent an incomplete CSR. Callers may +// construct empty |X509_REQ| objects, fill in fields individually, and finally +// sign the result. The following functions may be used for this purpose. + +// X509_REQ_new returns a newly-allocated, empty |X509_REQ| object, or NULL on +// error. This object may be filled in and then signed to construct a CSR. +OPENSSL_EXPORT X509_REQ *X509_REQ_new(void); + +// X509_REQ_set_version sets |req|'s version to |version|, which should be +// |X509_REQ_VERSION_1|. It returns one on success and zero on error. +// +// The only defined CSR version is |X509_REQ_VERSION_1|, so there is no need to +// call this function. +OPENSSL_EXPORT int X509_REQ_set_version(X509_REQ *req, long version); + +// X509_REQ_set_subject_name sets |req|'s subject to a copy of |name|. It +// returns one on success and zero on error. +OPENSSL_EXPORT int X509_REQ_set_subject_name(X509_REQ *req, X509_NAME *name); + +// X509_REQ_set_pubkey sets |req|'s public key to |pkey|. It returns one on +// success and zero on error. This function does not take ownership of |pkey| +// and internally copies and updates reference counts as needed. +OPENSSL_EXPORT int X509_REQ_set_pubkey(X509_REQ *req, EVP_PKEY *pkey); + +// X509_REQ_sign signs |req| with |pkey| and replaces the signature algorithm +// and signature fields. It returns one on success and zero on error. This +// function uses digest algorithm |md|, or |pkey|'s default if NULL. Other +// signing parameters use |pkey|'s defaults. To customize them, use +// |X509_REQ_sign_ctx|. +OPENSSL_EXPORT int X509_REQ_sign(X509_REQ *req, EVP_PKEY *pkey, + const EVP_MD *md); + +// X509_REQ_sign_ctx signs |req| with |ctx| and replaces the signature algorithm +// and signature fields. It returns one on success and zero on error. The +// signature algorithm and parameters come from |ctx|, which must have been +// initialized with |EVP_DigestSignInit|. The caller should configure the +// corresponding |EVP_PKEY_CTX| before calling this function. +OPENSSL_EXPORT int X509_REQ_sign_ctx(X509_REQ *req, EVP_MD_CTX *ctx); + +// i2d_re_X509_REQ_tbs serializes the CertificationRequestInfo (see RFC 2986) +// portion of |req|, as described in |i2d_SAMPLE|. +// +// This function re-encodes the CertificationRequestInfo and may not reflect +// |req|'s original encoding. It may be used to manually generate a signature +// for a new certificate request. +OPENSSL_EXPORT int i2d_re_X509_REQ_tbs(X509_REQ *req, uint8_t **outp); + +// X509_REQ_set1_signature_algo sets |req|'s signature algorithm to |algo| and +// returns one on success or zero on error. +OPENSSL_EXPORT int X509_REQ_set1_signature_algo(X509_REQ *req, + const X509_ALGOR *algo); + +// X509_REQ_set1_signature_value sets |req|'s signature to a copy of the +// |sig_len| bytes pointed by |sig|. It returns one on success and zero on +// error. +// +// Due to a specification error, PKCS#10 certificate requests store signatures +// in ASN.1 BIT STRINGs, but signature algorithms return byte strings rather +// than bit strings. This function creates a BIT STRING containing a whole +// number of bytes, with the bit order matching the DER encoding. This matches +// the encoding used by all X.509 signature algorithms. +OPENSSL_EXPORT int X509_REQ_set1_signature_value(X509_REQ *req, + const uint8_t *sig, + size_t sig_len); + + +// Algorithm identifiers. +// +// An |X509_ALGOR| represents an AlgorithmIdentifier structure, used in X.509 +// to represent signature algorithms and public key algorithms. + +DEFINE_STACK_OF(X509_ALGOR) + +// X509_ALGOR is an |ASN1_ITEM| whose ASN.1 type is AlgorithmIdentifier and C +// type is |X509_ALGOR*|. +DECLARE_ASN1_ITEM(X509_ALGOR) + +// X509_ALGOR_new returns a newly-allocated, empty |X509_ALGOR| object, or NULL +// on error. +OPENSSL_EXPORT X509_ALGOR *X509_ALGOR_new(void); + +// X509_ALGOR_free releases memory associated with |alg|. +OPENSSL_EXPORT void X509_ALGOR_free(X509_ALGOR *alg); + +// d2i_X509_ALGOR parses up to |len| bytes from |*inp| as a DER-encoded +// AlgorithmIdentifier, as described in |d2i_SAMPLE_with_reuse|. +OPENSSL_EXPORT X509_ALGOR *d2i_X509_ALGOR(X509_ALGOR **out, const uint8_t **inp, + long len); + +// i2d_X509_ALGOR marshals |alg| as a DER-encoded AlgorithmIdentifier, as +// described in |i2d_SAMPLE|. +OPENSSL_EXPORT int i2d_X509_ALGOR(const X509_ALGOR *alg, uint8_t **outp); + +// X509_ALGOR_set0 sets |alg| to an AlgorithmIdentifier with algorithm |obj| and +// parameter determined by |param_type| and |param_value|. It returns one on +// success and zero on error. This function takes ownership of |obj| and +// |param_value| on success. +// +// If |param_type| is |V_ASN1_UNDEF|, the parameter is omitted. If |param_type| +// is zero, the parameter is left unchanged. Otherwise, |param_type| and +// |param_value| are interpreted as in |ASN1_TYPE_set|. +// +// Note omitting the parameter (|V_ASN1_UNDEF|) and encoding an explicit NULL +// value (|V_ASN1_NULL|) are different. Some algorithms require one and some the +// other. Consult the relevant specification before calling this function. The +// correct parameter for an RSASSA-PKCS1-v1_5 signature is |V_ASN1_NULL|. The +// correct one for an ECDSA or Ed25519 signature is |V_ASN1_UNDEF|. +OPENSSL_EXPORT int X509_ALGOR_set0(X509_ALGOR *alg, ASN1_OBJECT *obj, + int param_type, void *param_value); + +// X509_ALGOR_get0 sets |*out_obj| to the |alg|'s algorithm. If |alg|'s +// parameter is omitted, it sets |*out_param_type| and |*out_param_value| to +// |V_ASN1_UNDEF| and NULL. Otherwise, it sets |*out_param_type| and +// |*out_param_value| to the parameter, using the same representation as +// |ASN1_TYPE_set0|. See |ASN1_TYPE_set0| and |ASN1_TYPE| for details. +// +// Callers that require the parameter in serialized form should, after checking +// for |V_ASN1_UNDEF|, use |ASN1_TYPE_set1| and |d2i_ASN1_TYPE|, rather than +// inspecting |*out_param_value|. +// +// Each of |out_obj|, |out_param_type|, and |out_param_value| may be NULL to +// ignore the output. If |out_param_type| is NULL, |out_param_value| is ignored. +// +// WARNING: If |*out_param_type| is set to |V_ASN1_UNDEF|, OpenSSL and older +// revisions of BoringSSL leave |*out_param_value| unset rather than setting it +// to NULL. Callers that support both OpenSSL and BoringSSL should not assume +// |*out_param_value| is uniformly initialized. +OPENSSL_EXPORT void X509_ALGOR_get0(const ASN1_OBJECT **out_obj, + int *out_param_type, + const void **out_param_value, + const X509_ALGOR *alg); + +// X509_ALGOR_set_md sets |alg| to the hash function |md|. Note this +// AlgorithmIdentifier represents the hash function itself, not a signature +// algorithm that uses |md|. +OPENSSL_EXPORT void X509_ALGOR_set_md(X509_ALGOR *alg, const EVP_MD *md); + +// X509_ALGOR_cmp returns zero if |a| and |b| are equal, and some non-zero value +// otherwise. Note this function can only be used for equality checks, not an +// ordering. +OPENSSL_EXPORT int X509_ALGOR_cmp(const X509_ALGOR *a, const X509_ALGOR *b); + + +// Printing functions. +// +// The following functions output human-readable representations of +// X.509-related structures. They should only be used for debugging or logging +// and not parsed programmatically. + +// X509_signature_dump writes a human-readable representation of |sig| to |bio|, +// indented with |indent| spaces. It returns one on success and zero on error. +OPENSSL_EXPORT int X509_signature_dump(BIO *bio, const ASN1_STRING *sig, + int indent); + +// X509_signature_print writes a human-readable representation of |alg| and +// |sig| to |bio|. It returns one on success and zero on error. +OPENSSL_EXPORT int X509_signature_print(BIO *bio, const X509_ALGOR *alg, + const ASN1_STRING *sig); + + +// ex_data functions. +// +// See |ex_data.h| for details. + +OPENSSL_EXPORT int X509_get_ex_new_index(long argl, void *argp, + CRYPTO_EX_unused *unused, + CRYPTO_EX_dup *dup_unused, + CRYPTO_EX_free *free_func); +OPENSSL_EXPORT int X509_set_ex_data(X509 *r, int idx, void *arg); +OPENSSL_EXPORT void *X509_get_ex_data(X509 *r, int idx); + +OPENSSL_EXPORT int X509_STORE_CTX_get_ex_new_index(long argl, void *argp, + CRYPTO_EX_unused *unused, + CRYPTO_EX_dup *dup_unused, + CRYPTO_EX_free *free_func); +OPENSSL_EXPORT int X509_STORE_CTX_set_ex_data(X509_STORE_CTX *ctx, int idx, + void *data); +OPENSSL_EXPORT void *X509_STORE_CTX_get_ex_data(X509_STORE_CTX *ctx, int idx); + + +// Deprecated functions. + +// X509_get_notBefore returns |x509|'s notBefore time. Note this function is not +// const-correct for legacy reasons. Use |X509_get0_notBefore| or +// |X509_getm_notBefore| instead. +OPENSSL_EXPORT ASN1_TIME *X509_get_notBefore(const X509 *x509); + +// X509_get_notAfter returns |x509|'s notAfter time. Note this function is not +// const-correct for legacy reasons. Use |X509_get0_notAfter| or +// |X509_getm_notAfter| instead. +OPENSSL_EXPORT ASN1_TIME *X509_get_notAfter(const X509 *x509); + +// X509_set_notBefore calls |X509_set1_notBefore|. Use |X509_set1_notBefore| +// instead. +OPENSSL_EXPORT int X509_set_notBefore(X509 *x509, const ASN1_TIME *tm); + +// X509_set_notAfter calls |X509_set1_notAfter|. Use |X509_set1_notAfter| +// instead. +OPENSSL_EXPORT int X509_set_notAfter(X509 *x509, const ASN1_TIME *tm); + +// X509_CRL_get_lastUpdate returns a mutable pointer to |crl|'s lastUpdate time. +// Use |X509_CRL_get0_lastUpdate| or |X509_CRL_set1_lastUpdate| instead. +OPENSSL_EXPORT ASN1_TIME *X509_CRL_get_lastUpdate(X509_CRL *crl); + +// X509_CRL_get_nextUpdate returns a mutable pointer to |crl|'s nextUpdate time, +// or NULL if |crl| has none. Use |X509_CRL_get0_nextUpdate| or +// |X509_CRL_set1_nextUpdate| instead. +OPENSSL_EXPORT ASN1_TIME *X509_CRL_get_nextUpdate(X509_CRL *crl); + +// X509_extract_key is a legacy alias to |X509_get_pubkey|. Use +// |X509_get_pubkey| instead. +#define X509_extract_key(x) X509_get_pubkey(x) + +// X509_REQ_extract_key is a legacy alias for |X509_REQ_get_pubkey|. +#define X509_REQ_extract_key(a) X509_REQ_get_pubkey(a) + +// X509_name_cmp is a legacy alias for |X509_NAME_cmp|. +#define X509_name_cmp(a, b) X509_NAME_cmp((a), (b)) + +// The following symbols are deprecated aliases to |X509_CRL_set1_*|. +#define X509_CRL_set_lastUpdate X509_CRL_set1_lastUpdate +#define X509_CRL_set_nextUpdate X509_CRL_set1_nextUpdate + +// X509_get_serialNumber returns a mutable pointer to |x509|'s serial number. +// Prefer |X509_get0_serialNumber|. +OPENSSL_EXPORT ASN1_INTEGER *X509_get_serialNumber(X509 *x509); + + +// Private structures. + +struct X509_algor_st { + ASN1_OBJECT *algorithm; + ASN1_TYPE *parameter; +} /* X509_ALGOR */; +// Functions below this point have not yet been organized into sections. + #define X509_FILETYPE_PEM 1 #define X509_FILETYPE_ASN1 2 #define X509_FILETYPE_DEFAULT 3 @@ -110,33 +896,6 @@ extern "C" { #define X509v3_KU_DECIPHER_ONLY 0x8000 #define X509v3_KU_UNDEF 0xffff -struct X509_algor_st { - ASN1_OBJECT *algorithm; - ASN1_TYPE *parameter; -} /* X509_ALGOR */; - -// X509_ALGOR is an |ASN1_ITEM| whose ASN.1 type is AlgorithmIdentifier and C -// type is |X509_ALGOR*|. -DECLARE_ASN1_ITEM(X509_ALGOR) - -// X509_ALGOR_new returns a newly-allocated, empty |X509_ALGOR| object, or NULL -// on error. -OPENSSL_EXPORT X509_ALGOR *X509_ALGOR_new(void); - -// X509_ALGOR_free releases memory associated with |alg|. -OPENSSL_EXPORT void X509_ALGOR_free(X509_ALGOR *alg); - -// d2i_X509_ALGOR parses up to |len| bytes from |*inp| as a DER-encoded -// AlgorithmIdentifier, as described in |d2i_SAMPLE_with_reuse|. -OPENSSL_EXPORT X509_ALGOR *d2i_X509_ALGOR(X509_ALGOR **out, const uint8_t **inp, - long len); - -// i2d_X509_ALGOR marshals |alg| as a DER-encoded AlgorithmIdentifier, as -// described in |i2d_SAMPLE|. -OPENSSL_EXPORT int i2d_X509_ALGOR(const X509_ALGOR *alg, uint8_t **outp); - -DEFINE_STACK_OF(X509_ALGOR) - DEFINE_STACK_OF(X509_NAME_ENTRY) DEFINE_STACK_OF(X509_NAME) @@ -155,8 +914,6 @@ DEFINE_STACK_OF(X509_ATTRIBUTE) DECLARE_STACK_OF(DIST_POINT) DECLARE_STACK_OF(GENERAL_NAME) -DEFINE_STACK_OF(X509) - // This is used for a table of trust checking functions struct x509_trust_st { @@ -270,8 +1027,6 @@ DEFINE_STACK_OF(X509_REVOKED) DECLARE_STACK_OF(GENERAL_NAMES) -DEFINE_STACK_OF(X509_CRL) - struct private_key_st { int version; // The PKCS#8 data types @@ -317,87 +1072,6 @@ struct Netscape_spki_st { ASN1_BIT_STRING *signature; } /* NETSCAPE_SPKI */; -// TODO(davidben): Document remaining functions, reorganize them, and define -// supported patterns for using |X509| objects in general. In particular, when -// it is safe to call mutating functions is a little tricky due to various -// internal caches. - -// X509_VERSION_* are X.509 version numbers. Note the numerical values of all -// defined X.509 versions are one less than the named version. -#define X509_VERSION_1 0 -#define X509_VERSION_2 1 -#define X509_VERSION_3 2 - -// X509_get_version returns the numerical value of |x509|'s version, which will -// be one of the |X509_VERSION_*| constants. -OPENSSL_EXPORT long X509_get_version(const X509 *x509); - -// X509_set_version sets |x509|'s version to |version|, which should be one of -// the |X509V_VERSION_*| constants. It returns one on success and zero on error. -// -// If unsure, use |X509_VERSION_3|. -OPENSSL_EXPORT int X509_set_version(X509 *x509, long version); - -// X509_get0_serialNumber returns |x509|'s serial number. -OPENSSL_EXPORT const ASN1_INTEGER *X509_get0_serialNumber(const X509 *x509); - -// X509_set_serialNumber sets |x509|'s serial number to |serial|. It returns one -// on success and zero on error. -OPENSSL_EXPORT int X509_set_serialNumber(X509 *x509, - const ASN1_INTEGER *serial); - -// X509_get0_notBefore returns |x509|'s notBefore time. -OPENSSL_EXPORT const ASN1_TIME *X509_get0_notBefore(const X509 *x509); - -// X509_get0_notAfter returns |x509|'s notAfter time. -OPENSSL_EXPORT const ASN1_TIME *X509_get0_notAfter(const X509 *x509); - -// X509_set1_notBefore sets |x509|'s notBefore time to |tm|. It returns one on -// success and zero on error. -OPENSSL_EXPORT int X509_set1_notBefore(X509 *x509, const ASN1_TIME *tm); - -// X509_set1_notAfter sets |x509|'s notAfter time to |tm|. it returns one on -// success and zero on error. -OPENSSL_EXPORT int X509_set1_notAfter(X509 *x509, const ASN1_TIME *tm); - -// X509_getm_notBefore returns a mutable pointer to |x509|'s notBefore time. -OPENSSL_EXPORT ASN1_TIME *X509_getm_notBefore(X509 *x509); - -// X509_getm_notAfter returns a mutable pointer to |x509|'s notAfter time. -OPENSSL_EXPORT ASN1_TIME *X509_getm_notAfter(X509 *x); - -// X509_get_notBefore returns |x509|'s notBefore time. Note this function is not -// const-correct for legacy reasons. Use |X509_get0_notBefore| or -// |X509_getm_notBefore| instead. -OPENSSL_EXPORT ASN1_TIME *X509_get_notBefore(const X509 *x509); - -// X509_get_notAfter returns |x509|'s notAfter time. Note this function is not -// const-correct for legacy reasons. Use |X509_get0_notAfter| or -// |X509_getm_notAfter| instead. -OPENSSL_EXPORT ASN1_TIME *X509_get_notAfter(const X509 *x509); - -// X509_set_notBefore calls |X509_set1_notBefore|. Use |X509_set1_notBefore| -// instead. -OPENSSL_EXPORT int X509_set_notBefore(X509 *x509, const ASN1_TIME *tm); - -// X509_set_notAfter calls |X509_set1_notAfter|. Use |X509_set1_notAfter| -// instead. -OPENSSL_EXPORT int X509_set_notAfter(X509 *x509, const ASN1_TIME *tm); - -// X509_get0_uids sets |*out_issuer_uid| to a non-owning pointer to the -// issuerUID field of |x509|, or NULL if |x509| has no issuerUID. It similarly -// outputs |x509|'s subjectUID field to |*out_subject_uid|. -// -// Callers may pass NULL to either |out_issuer_uid| or |out_subject_uid| to -// ignore the corresponding field. -OPENSSL_EXPORT void X509_get0_uids(const X509 *x509, - const ASN1_BIT_STRING **out_issuer_uid, - const ASN1_BIT_STRING **out_subject_uid); - -// X509_extract_key is a legacy alias to |X509_get_pubkey|. Use -// |X509_get_pubkey| instead. -#define X509_extract_key(x) X509_get_pubkey(x) - // X509_get_pathlen returns path length constraint from the basic constraints // extension in |x509|. (See RFC 5280, section 4.2.1.9.) It returns -1 if the // constraint is not present, or if some extension in |x509| was invalid. @@ -407,78 +1081,6 @@ OPENSSL_EXPORT void X509_get0_uids(const X509 *x509, // |EXFLAG_INVALID| bit. OPENSSL_EXPORT long X509_get_pathlen(X509 *x509); -// X509_REQ_VERSION_1 is the version constant for |X509_REQ| objects. No other -// versions are defined. -#define X509_REQ_VERSION_1 0 - -// X509_REQ_get_version returns the numerical value of |req|'s version. This -// will always be |X509_REQ_VERSION_1| for valid CSRs. For compatibility, -// |d2i_X509_REQ| also accepts some invalid version numbers, in which case this -// function may return other values. -OPENSSL_EXPORT long X509_REQ_get_version(const X509_REQ *req); - -// X509_REQ_get_subject_name returns |req|'s subject name. Note this function is -// not const-correct for legacy reasons. -OPENSSL_EXPORT X509_NAME *X509_REQ_get_subject_name(const X509_REQ *req); - -// X509_REQ_extract_key is a legacy alias for |X509_REQ_get_pubkey|. -#define X509_REQ_extract_key(a) X509_REQ_get_pubkey(a) - -// X509_name_cmp is a legacy alias for |X509_NAME_cmp|. -#define X509_name_cmp(a, b) X509_NAME_cmp((a), (b)) - -#define X509_CRL_VERSION_1 0 -#define X509_CRL_VERSION_2 1 - -// X509_CRL_get_version returns the numerical value of |crl|'s version, which -// will be one of the |X509_CRL_VERSION_*| constants. -OPENSSL_EXPORT long X509_CRL_get_version(const X509_CRL *crl); - -// X509_CRL_get0_lastUpdate returns |crl|'s lastUpdate time. -OPENSSL_EXPORT const ASN1_TIME *X509_CRL_get0_lastUpdate(const X509_CRL *crl); - -// X509_CRL_get0_nextUpdate returns |crl|'s nextUpdate time, or NULL if |crl| -// has none. -OPENSSL_EXPORT const ASN1_TIME *X509_CRL_get0_nextUpdate(const X509_CRL *crl); - -// X509_CRL_set1_lastUpdate sets |crl|'s lastUpdate time to |tm|. It returns one -// on success and zero on error. -OPENSSL_EXPORT int X509_CRL_set1_lastUpdate(X509_CRL *crl, const ASN1_TIME *tm); - -// X509_CRL_set1_nextUpdate sets |crl|'s nextUpdate time to |tm|. It returns one -// on success and zero on error. -OPENSSL_EXPORT int X509_CRL_set1_nextUpdate(X509_CRL *crl, const ASN1_TIME *tm); - -// The following symbols are deprecated aliases to |X509_CRL_set1_*|. -#define X509_CRL_set_lastUpdate X509_CRL_set1_lastUpdate -#define X509_CRL_set_nextUpdate X509_CRL_set1_nextUpdate - -// X509_CRL_get_lastUpdate returns a mutable pointer to |crl|'s lastUpdate time. -// Use |X509_CRL_get0_lastUpdate| or |X509_CRL_set1_lastUpdate| instead. -OPENSSL_EXPORT ASN1_TIME *X509_CRL_get_lastUpdate(X509_CRL *crl); - -// X509_CRL_get_nextUpdate returns a mutable pointer to |crl|'s nextUpdate time, -// or NULL if |crl| has none. Use |X509_CRL_get0_nextUpdate| or -// |X509_CRL_set1_nextUpdate| instead. -OPENSSL_EXPORT ASN1_TIME *X509_CRL_get_nextUpdate(X509_CRL *crl); - -// X509_CRL_get_issuer returns |crl|'s issuer name. Note this function is not -// const-correct for legacy reasons. -OPENSSL_EXPORT X509_NAME *X509_CRL_get_issuer(const X509_CRL *crl); - -// X509_CRL_get_REVOKED returns the list of revoked certificates in |crl|, or -// NULL if |crl| omits it. -// -// TOOD(davidben): This function was originally a macro, without clear const -// semantics. It should take a const input and give const output, but the latter -// would break existing callers. For now, we match upstream. -OPENSSL_EXPORT STACK_OF(X509_REVOKED) *X509_CRL_get_REVOKED(X509_CRL *crl); - -// X509_CRL_get0_extensions returns |crl|'s extension list, or NULL if |crl| -// omits it. -OPENSSL_EXPORT const STACK_OF(X509_EXTENSION) *X509_CRL_get0_extensions( - const X509_CRL *crl); - // X509_SIG_get0 sets |*out_alg| and |*out_digest| to non-owning pointers to // |sig|'s algorithm and digest fields, respectively. Either |out_alg| and // |out_digest| may be NULL to skip those fields. @@ -490,11 +1092,6 @@ OPENSSL_EXPORT void X509_SIG_get0(const X509_SIG *sig, OPENSSL_EXPORT void X509_SIG_getm(X509_SIG *sig, X509_ALGOR **out_alg, ASN1_OCTET_STRING **out_digest); -// X509_get_X509_PUBKEY returns the public key of |x509|. Note this function is -// not const-correct for legacy reasons. Callers should not modify the returned -// object. -OPENSSL_EXPORT X509_PUBKEY *X509_get_X509_PUBKEY(const X509 *x509); - // X509_verify_cert_error_string returns |err| as a human-readable string, where // |err| should be one of the |X509_V_*| values. If |err| is unknown, it returns // a default description. @@ -515,86 +1112,33 @@ OPENSSL_EXPORT int X509_REQ_verify(X509_REQ *req, EVP_PKEY *pkey); OPENSSL_EXPORT int X509_CRL_verify(X509_CRL *crl, EVP_PKEY *pkey); // NETSCAPE_SPKI_verify checks that |spki| has a valid signature by |pkey|. It -// returns one if the signature is valid and zero otherwise. -OPENSSL_EXPORT int NETSCAPE_SPKI_verify(NETSCAPE_SPKI *spki, EVP_PKEY *pkey); - -// NETSCAPE_SPKI_b64_decode decodes |len| bytes from |str| as a base64-encoded -// Netscape signed public key and challenge (SPKAC) structure. It returns a -// newly-allocated |NETSCAPE_SPKI| structure with the result, or NULL on error. -// If |len| is 0 or negative, the length is calculated with |strlen| and |str| -// must be a NUL-terminated C string. -OPENSSL_EXPORT NETSCAPE_SPKI *NETSCAPE_SPKI_b64_decode(const char *str, - int len); - -// NETSCAPE_SPKI_b64_encode encodes |spki| as a base64-encoded Netscape signed -// public key and challenge (SPKAC) structure. It returns a newly-allocated -// NUL-terminated C string with the result, or NULL on error. The caller must -// release the memory with |OPENSSL_free| when done. -OPENSSL_EXPORT char *NETSCAPE_SPKI_b64_encode(NETSCAPE_SPKI *spki); - -// NETSCAPE_SPKI_get_pubkey decodes and returns the public key in |spki| as an -// |EVP_PKEY|, or NULL on error. The caller takes ownership of the resulting -// pointer and must call |EVP_PKEY_free| when done. -OPENSSL_EXPORT EVP_PKEY *NETSCAPE_SPKI_get_pubkey(NETSCAPE_SPKI *spki); - -// NETSCAPE_SPKI_set_pubkey sets |spki|'s public key to |pkey|. It returns one -// on success or zero on error. This function does not take ownership of |pkey|, -// so the caller may continue to manage its lifetime independently of |spki|. -OPENSSL_EXPORT int NETSCAPE_SPKI_set_pubkey(NETSCAPE_SPKI *spki, - EVP_PKEY *pkey); - -// X509_signature_dump writes a human-readable representation of |sig| to |bio|, -// indented with |indent| spaces. It returns one on success and zero on error. -OPENSSL_EXPORT int X509_signature_dump(BIO *bio, const ASN1_STRING *sig, - int indent); - -// X509_signature_print writes a human-readable representation of |alg| and -// |sig| to |bio|. It returns one on success and zero on error. -OPENSSL_EXPORT int X509_signature_print(BIO *bio, const X509_ALGOR *alg, - const ASN1_STRING *sig); - -// X509_sign signs |x509| with |pkey| and replaces the signature algorithm and -// signature fields. It returns one on success and zero on error. This function -// uses digest algorithm |md|, or |pkey|'s default if NULL. Other signing -// parameters use |pkey|'s defaults. To customize them, use |X509_sign_ctx|. -OPENSSL_EXPORT int X509_sign(X509 *x509, EVP_PKEY *pkey, const EVP_MD *md); - -// X509_sign_ctx signs |x509| with |ctx| and replaces the signature algorithm -// and signature fields. It returns one on success and zero on error. The -// signature algorithm and parameters come from |ctx|, which must have been -// initialized with |EVP_DigestSignInit|. The caller should configure the -// corresponding |EVP_PKEY_CTX| before calling this function. -OPENSSL_EXPORT int X509_sign_ctx(X509 *x509, EVP_MD_CTX *ctx); +// returns one if the signature is valid and zero otherwise. +OPENSSL_EXPORT int NETSCAPE_SPKI_verify(NETSCAPE_SPKI *spki, EVP_PKEY *pkey); -// X509_REQ_sign signs |req| with |pkey| and replaces the signature algorithm -// and signature fields. It returns one on success and zero on error. This -// function uses digest algorithm |md|, or |pkey|'s default if NULL. Other -// signing parameters use |pkey|'s defaults. To customize them, use -// |X509_REQ_sign_ctx|. -OPENSSL_EXPORT int X509_REQ_sign(X509_REQ *req, EVP_PKEY *pkey, - const EVP_MD *md); +// NETSCAPE_SPKI_b64_decode decodes |len| bytes from |str| as a base64-encoded +// Netscape signed public key and challenge (SPKAC) structure. It returns a +// newly-allocated |NETSCAPE_SPKI| structure with the result, or NULL on error. +// If |len| is 0 or negative, the length is calculated with |strlen| and |str| +// must be a NUL-terminated C string. +OPENSSL_EXPORT NETSCAPE_SPKI *NETSCAPE_SPKI_b64_decode(const char *str, + int len); -// X509_REQ_sign_ctx signs |req| with |ctx| and replaces the signature algorithm -// and signature fields. It returns one on success and zero on error. The -// signature algorithm and parameters come from |ctx|, which must have been -// initialized with |EVP_DigestSignInit|. The caller should configure the -// corresponding |EVP_PKEY_CTX| before calling this function. -OPENSSL_EXPORT int X509_REQ_sign_ctx(X509_REQ *req, EVP_MD_CTX *ctx); +// NETSCAPE_SPKI_b64_encode encodes |spki| as a base64-encoded Netscape signed +// public key and challenge (SPKAC) structure. It returns a newly-allocated +// NUL-terminated C string with the result, or NULL on error. The caller must +// release the memory with |OPENSSL_free| when done. +OPENSSL_EXPORT char *NETSCAPE_SPKI_b64_encode(NETSCAPE_SPKI *spki); -// X509_CRL_sign signs |crl| with |pkey| and replaces the signature algorithm -// and signature fields. It returns one on success and zero on error. This -// function uses digest algorithm |md|, or |pkey|'s default if NULL. Other -// signing parameters use |pkey|'s defaults. To customize them, use -// |X509_CRL_sign_ctx|. -OPENSSL_EXPORT int X509_CRL_sign(X509_CRL *crl, EVP_PKEY *pkey, - const EVP_MD *md); +// NETSCAPE_SPKI_get_pubkey decodes and returns the public key in |spki| as an +// |EVP_PKEY|, or NULL on error. The caller takes ownership of the resulting +// pointer and must call |EVP_PKEY_free| when done. +OPENSSL_EXPORT EVP_PKEY *NETSCAPE_SPKI_get_pubkey(NETSCAPE_SPKI *spki); -// X509_CRL_sign_ctx signs |crl| with |ctx| and replaces the signature algorithm -// and signature fields. It returns one on success and zero on error. The -// signature algorithm and parameters come from |ctx|, which must have been -// initialized with |EVP_DigestSignInit|. The caller should configure the -// corresponding |EVP_PKEY_CTX| before calling this function. -OPENSSL_EXPORT int X509_CRL_sign_ctx(X509_CRL *crl, EVP_MD_CTX *ctx); +// NETSCAPE_SPKI_set_pubkey sets |spki|'s public key to |pkey|. It returns one +// on success or zero on error. This function does not take ownership of |pkey|, +// so the caller may continue to manage its lifetime independently of |spki|. +OPENSSL_EXPORT int NETSCAPE_SPKI_set_pubkey(NETSCAPE_SPKI *spki, + EVP_PKEY *pkey); // NETSCAPE_SPKI_sign signs |spki| with |pkey| and replaces the signature // algorithm and signature fields. It returns one on success and zero on error. @@ -643,12 +1187,6 @@ OPENSSL_EXPORT int X509_REQ_digest(const X509_REQ *req, const EVP_MD *md, OPENSSL_EXPORT int X509_NAME_digest(const X509_NAME *name, const EVP_MD *md, uint8_t *out, unsigned *out_len); -// X509_parse_from_buffer parses an X.509 structure from |buf| and returns a -// fresh X509 or NULL on error. There must not be any trailing data in |buf|. -// The returned structure (if any) holds a reference to |buf| rather than -// copying parts of it as a normal |d2i_X509| call would do. -OPENSSL_EXPORT X509 *X509_parse_from_buffer(CRYPTO_BUFFER *buf); - OPENSSL_EXPORT X509 *d2i_X509_fp(FILE *fp, X509 **x509); OPENSSL_EXPORT int i2d_X509_fp(FILE *fp, X509 *x509); OPENSSL_EXPORT X509_CRL *d2i_X509_CRL_fp(FILE *fp, X509_CRL **crl); @@ -727,55 +1265,6 @@ OPENSSL_EXPORT X509_REVOKED *X509_REVOKED_dup(X509_REVOKED *rev); OPENSSL_EXPORT X509_REQ *X509_REQ_dup(X509_REQ *req); OPENSSL_EXPORT X509_ALGOR *X509_ALGOR_dup(const X509_ALGOR *xn); -// X509_ALGOR_set0 sets |alg| to an AlgorithmIdentifier with algorithm |obj| and -// parameter determined by |param_type| and |param_value|. It returns one on -// success and zero on error. This function takes ownership of |obj| and -// |param_value| on success. -// -// If |param_type| is |V_ASN1_UNDEF|, the parameter is omitted. If |param_type| -// is zero, the parameter is left unchanged. Otherwise, |param_type| and -// |param_value| are interpreted as in |ASN1_TYPE_set|. -// -// Note omitting the parameter (|V_ASN1_UNDEF|) and encoding an explicit NULL -// value (|V_ASN1_NULL|) are different. Some algorithms require one and some the -// other. Consult the relevant specification before calling this function. The -// correct parameter for an RSASSA-PKCS1-v1_5 signature is |V_ASN1_NULL|. The -// correct one for an ECDSA or Ed25519 signature is |V_ASN1_UNDEF|. -OPENSSL_EXPORT int X509_ALGOR_set0(X509_ALGOR *alg, ASN1_OBJECT *obj, - int param_type, void *param_value); - -// X509_ALGOR_get0 sets |*out_obj| to the |alg|'s algorithm. If |alg|'s -// parameter is omitted, it sets |*out_param_type| and |*out_param_value| to -// |V_ASN1_UNDEF| and NULL. Otherwise, it sets |*out_param_type| and -// |*out_param_value| to the parameter, using the same representation as -// |ASN1_TYPE_set0|. See |ASN1_TYPE_set0| and |ASN1_TYPE| for details. -// -// Callers that require the parameter in serialized form should, after checking -// for |V_ASN1_UNDEF|, use |ASN1_TYPE_set1| and |d2i_ASN1_TYPE|, rather than -// inspecting |*out_param_value|. -// -// Each of |out_obj|, |out_param_type|, and |out_param_value| may be NULL to -// ignore the output. If |out_param_type| is NULL, |out_param_value| is ignored. -// -// WARNING: If |*out_param_type| is set to |V_ASN1_UNDEF|, OpenSSL and older -// revisions of BoringSSL leave |*out_param_value| unset rather than setting it -// to NULL. Callers that support both OpenSSL and BoringSSL should not assume -// |*out_param_value| is uniformly initialized. -OPENSSL_EXPORT void X509_ALGOR_get0(const ASN1_OBJECT **out_obj, - int *out_param_type, - const void **out_param_value, - const X509_ALGOR *alg); - -// X509_ALGOR_set_md sets |alg| to the hash function |md|. Note this -// AlgorithmIdentifier represents the hash function itself, not a signature -// algorithm that uses |md|. -OPENSSL_EXPORT void X509_ALGOR_set_md(X509_ALGOR *alg, const EVP_MD *md); - -// X509_ALGOR_cmp returns zero if |a| and |b| are equal, and some non-zero value -// otherwise. Note this function can only be used for equality checks, not an -// ordering. -OPENSSL_EXPORT int X509_ALGOR_cmp(const X509_ALGOR *a, const X509_ALGOR *b); - OPENSSL_EXPORT X509_NAME *X509_NAME_dup(X509_NAME *xn); OPENSSL_EXPORT X509_NAME_ENTRY *X509_NAME_ENTRY_dup(const X509_NAME_ENTRY *ne); OPENSSL_EXPORT int X509_NAME_ENTRY_set(const X509_NAME_ENTRY *ne); @@ -830,30 +1319,6 @@ OPENSSL_EXPORT EVP_PKEY *X509_PUBKEY_get(X509_PUBKEY *key); DECLARE_ASN1_FUNCTIONS_const(X509_SIG) -// X509_REQ is an |ASN1_ITEM| whose ASN.1 type is CertificateRequest (RFC 2986) -// and C type is |X509_REQ*|. -DECLARE_ASN1_ITEM(X509_REQ) - -// X509_REQ_new returns a newly-allocated, empty |X509_REQ| object, or NULL on -// error. This object may be filled in and then signed to construct a CSR. -OPENSSL_EXPORT X509_REQ *X509_REQ_new(void); - -// X509_REQ_free releases memory associated with |req|. -OPENSSL_EXPORT void X509_REQ_free(X509_REQ *req); - -// d2i_X509_REQ parses up to |len| bytes from |*inp| as a DER-encoded -// CertificateRequest (RFC 2986), as described in |d2i_SAMPLE_with_reuse|. -OPENSSL_EXPORT X509_REQ *d2i_X509_REQ(X509_REQ **out, const uint8_t **inp, - long len); - -// i2d_X509_REQ marshals |req| as a CertificateRequest (RFC 2986), as described -// in |i2d_SAMPLE|. -// -// TODO(https://crbug.com/boringssl/407): This function should be const and -// thread-safe but is currently neither in some cases, notably if |req| was -// mutated. -OPENSSL_EXPORT int i2d_X509_REQ(X509_REQ *req, uint8_t **outp); - DECLARE_ASN1_FUNCTIONS_const(X509_ATTRIBUTE) // X509_ATTRIBUTE_create returns a newly-allocated |X509_ATTRIBUTE|, or NULL on @@ -861,172 +1326,20 @@ DECLARE_ASN1_FUNCTIONS_const(X509_ATTRIBUTE) // |attrtype| and |value|, which are interpreted as in |ASN1_TYPE_set|. Note // this function takes ownership of |value|. OPENSSL_EXPORT X509_ATTRIBUTE *X509_ATTRIBUTE_create(int nid, int attrtype, - void *value); - -DECLARE_ASN1_FUNCTIONS_const(X509_EXTENSION) -DECLARE_ASN1_ENCODE_FUNCTIONS_const(X509_EXTENSIONS, X509_EXTENSIONS) - -DECLARE_ASN1_FUNCTIONS_const(X509_NAME_ENTRY) - -// TODO(https://crbug.com/boringssl/407): This is not const because serializing -// an |X509_NAME| is sometimes not thread-safe. -DECLARE_ASN1_FUNCTIONS(X509_NAME) - -// X509_NAME_set makes a copy of |name|. On success, it frees |*xn|, sets |*xn| -// to the copy, and returns one. Otherwise, it returns zero. -OPENSSL_EXPORT int X509_NAME_set(X509_NAME **xn, X509_NAME *name); - -// X509 is an |ASN1_ITEM| whose ASN.1 type is X.509 Certificate (RFC 5280) and C -// type is |X509*|. -DECLARE_ASN1_ITEM(X509) - -// X509_new returns a newly-allocated, empty |X509| object, or NULL on error. -// This object may be filled in and then signed to construct a certificate. -OPENSSL_EXPORT X509 *X509_new(void); - -// X509_free decrements |x509|'s reference count and, if zero, releases memory -// associated with |x509|. -OPENSSL_EXPORT void X509_free(X509 *x509); - -// d2i_X509 parses up to |len| bytes from |*inp| as a DER-encoded X.509 -// Certificate (RFC 5280), as described in |d2i_SAMPLE_with_reuse|. -OPENSSL_EXPORT X509 *d2i_X509(X509 **out, const uint8_t **inp, long len); - -// i2d_X509 marshals |x509| as a DER-encoded X.509 Certificate (RFC 5280), as -// described in |i2d_SAMPLE|. -// -// TODO(https://crbug.com/boringssl/407): This function should be const and -// thread-safe but is currently neither in some cases, notably if |x509| was -// mutated. -OPENSSL_EXPORT int i2d_X509(X509 *x509, uint8_t **outp); - -// X509_up_ref adds one to the reference count of |x509| and returns one. -OPENSSL_EXPORT int X509_up_ref(X509 *x509); - -OPENSSL_EXPORT int X509_get_ex_new_index(long argl, void *argp, - CRYPTO_EX_unused *unused, - CRYPTO_EX_dup *dup_unused, - CRYPTO_EX_free *free_func); -OPENSSL_EXPORT int X509_set_ex_data(X509 *r, int idx, void *arg); -OPENSSL_EXPORT void *X509_get_ex_data(X509 *r, int idx); - -// i2d_re_X509_tbs serializes the TBSCertificate portion of |x509|, as described -// in |i2d_SAMPLE|. -// -// This function re-encodes the TBSCertificate and may not reflect |x509|'s -// original encoding. It may be used to manually generate a signature for a new -// certificate. To verify certificates, use |i2d_X509_tbs| instead. -OPENSSL_EXPORT int i2d_re_X509_tbs(X509 *x509, unsigned char **outp); - -// i2d_X509_tbs serializes the TBSCertificate portion of |x509|, as described in -// |i2d_SAMPLE|. -// -// This function preserves the original encoding of the TBSCertificate and may -// not reflect modifications made to |x509|. It may be used to manually verify -// the signature of an existing certificate. To generate certificates, use -// |i2d_re_X509_tbs| instead. -OPENSSL_EXPORT int i2d_X509_tbs(X509 *x509, unsigned char **outp); - -// X509_set1_signature_algo sets |x509|'s signature algorithm to |algo| and -// returns one on success or zero on error. It updates both the signature field -// of the TBSCertificate structure, and the signatureAlgorithm field of the -// Certificate. -OPENSSL_EXPORT int X509_set1_signature_algo(X509 *x509, const X509_ALGOR *algo); - -// X509_set1_signature_value sets |x509|'s signature to a copy of the |sig_len| -// bytes pointed by |sig|. It returns one on success and zero on error. -// -// Due to a specification error, X.509 certificates store signatures in ASN.1 -// BIT STRINGs, but signature algorithms return byte strings rather than bit -// strings. This function creates a BIT STRING containing a whole number of -// bytes, with the bit order matching the DER encoding. This matches the -// encoding used by all X.509 signature algorithms. -OPENSSL_EXPORT int X509_set1_signature_value(X509 *x509, const uint8_t *sig, - size_t sig_len); - -// X509_get0_signature sets |*out_sig| and |*out_alg| to the signature and -// signature algorithm of |x509|, respectively. Either output pointer may be -// NULL to ignore the value. -// -// This function outputs the outer signature algorithm. For the one in the -// TBSCertificate, see |X509_get0_tbs_sigalg|. Certificates with mismatched -// signature algorithms will successfully parse, but they will be rejected when -// verifying. -OPENSSL_EXPORT void X509_get0_signature(const ASN1_BIT_STRING **out_sig, - const X509_ALGOR **out_alg, - const X509 *x509); - -// X509_get_signature_nid returns the NID corresponding to |x509|'s signature -// algorithm, or |NID_undef| if the signature algorithm does not correspond to -// a known NID. -OPENSSL_EXPORT int X509_get_signature_nid(const X509 *x509); - - -// Auxiliary properties. -// -// |X509| objects optionally maintain auxiliary properties. These are not part -// of the certificates themselves, and thus are not covered by signatures or -// preserved by the standard serialization. They are used as inputs or outputs -// to other functions in this library. - -// i2d_X509_AUX marshals |x509| as a DER-encoded X.509 Certificate (RFC 5280), -// followed optionally by a separate, OpenSSL-specific structure with auxiliary -// properties. It behaves as described in |i2d_SAMPLE|. -// -// Unlike similarly-named functions, this function does not output a single -// ASN.1 element. Directly embedding the output in a larger ASN.1 structure will -// not behave correctly. -OPENSSL_EXPORT int i2d_X509_AUX(X509 *x509, unsigned char **outp); - -// d2i_X509_AUX parses up to |length| bytes from |*inp| as a DER-encoded X.509 -// Certificate (RFC 5280), followed optionally by a separate, OpenSSL-specific -// structure with auxiliary properties. It behaves as described in -// |d2i_SAMPLE_with_reuse|. -// -// Some auxiliary properties affect trust decisions, so this function should not -// be used with untrusted input. -// -// Unlike similarly-named functions, this function does not parse a single -// ASN.1 element. Trying to parse data directly embedded in a larger ASN.1 -// structure will not behave correctly. -OPENSSL_EXPORT X509 *d2i_X509_AUX(X509 **x509, const unsigned char **inp, - long length); + void *value); -// X509_alias_set1 sets |x509|'s alias to |len| bytes from |name|. If |name| is -// NULL, the alias is cleared instead. Aliases are not part of the certificate -// itself and will not be serialized by |i2d_X509|. -OPENSSL_EXPORT int X509_alias_set1(X509 *x509, const unsigned char *name, - int len); +DECLARE_ASN1_FUNCTIONS_const(X509_EXTENSION) +DECLARE_ASN1_ENCODE_FUNCTIONS_const(X509_EXTENSIONS, X509_EXTENSIONS) -// X509_keyid_set1 sets |x509|'s key ID to |len| bytes from |id|. If |id| is -// NULL, the key ID is cleared instead. Key IDs are not part of the certificate -// itself and will not be serialized by |i2d_X509|. -OPENSSL_EXPORT int X509_keyid_set1(X509 *x509, const unsigned char *id, - int len); +DECLARE_ASN1_FUNCTIONS_const(X509_NAME_ENTRY) -// X509_alias_get0 looks up |x509|'s alias. If found, it sets |*out_len| to the -// alias's length and returns a pointer to a buffer containing the contents. If -// not found, it outputs the empty string by returning NULL and setting -// |*out_len| to zero. -// -// If |x509| was parsed from a PKCS#12 structure (see -// |PKCS12_get_key_and_certs|), the alias will reflect the friendlyName -// attribute (RFC 2985). -// -// WARNING: In OpenSSL, this function did not set |*out_len| when the alias was -// missing. Callers that target both OpenSSL and BoringSSL should set the value -// to zero before calling this function. -OPENSSL_EXPORT unsigned char *X509_alias_get0(X509 *x509, int *out_len); +// TODO(https://crbug.com/boringssl/407): This is not const because serializing +// an |X509_NAME| is sometimes not thread-safe. +DECLARE_ASN1_FUNCTIONS(X509_NAME) -// X509_keyid_get0 looks up |x509|'s key ID. If found, it sets |*out_len| to the -// key ID's length and returns a pointer to a buffer containing the contents. If -// not found, it outputs the empty string by returning NULL and setting -// |*out_len| to zero. -// -// WARNING: In OpenSSL, this function did not set |*out_len| when the alias was -// missing. Callers that target both OpenSSL and BoringSSL should set the value -// to zero before calling this function. -OPENSSL_EXPORT unsigned char *X509_keyid_get0(X509 *x509, int *out_len); +// X509_NAME_set makes a copy of |name|. On success, it frees |*xn|, sets |*xn| +// to the copy, and returns one. Otherwise, it returns zero. +OPENSSL_EXPORT int X509_NAME_set(X509_NAME **xn, X509_NAME *name); OPENSSL_EXPORT int X509_add1_trust_object(X509 *x, ASN1_OBJECT *obj); OPENSSL_EXPORT int X509_add1_reject_object(X509 *x, ASN1_OBJECT *obj); @@ -1040,31 +1353,6 @@ OPENSSL_EXPORT int X509_TRUST_set(int *t, int trust); // an |X509_NAME|. DECLARE_ASN1_FUNCTIONS(X509_REVOKED) -// X509_CRL is an |ASN1_ITEM| whose ASN.1 type is X.509 CertificateList (RFC -// 5280) and C type is |X509_CRL*|. -DECLARE_ASN1_ITEM(X509_CRL) - -// X509_CRL_new returns a newly-allocated, empty |X509_CRL| object, or NULL on -// error. This object may be filled in and then signed to construct a CRL. -OPENSSL_EXPORT X509_CRL *X509_CRL_new(void); - -// X509_CRL_free decrements |crl|'s reference count and, if zero, releases -// memory associated with |crl|. -OPENSSL_EXPORT void X509_CRL_free(X509_CRL *crl); - -// d2i_X509_CRL parses up to |len| bytes from |*inp| as a DER-encoded X.509 -// CertificateList (RFC 5280), as described in |d2i_SAMPLE_with_reuse|. -OPENSSL_EXPORT X509_CRL *d2i_X509_CRL(X509_CRL **out, const uint8_t **inp, - long len); - -// i2d_X509_CRL marshals |crl| as a X.509 CertificateList (RFC 5280), as -// described in |i2d_SAMPLE|. -// -// TODO(https://crbug.com/boringssl/407): This function should be const and -// thread-safe but is currently neither in some cases, notably if |crl| was -// mutated. -OPENSSL_EXPORT int i2d_X509_CRL(X509_CRL *crl, uint8_t **outp); - OPENSSL_EXPORT int X509_CRL_add0_revoked(X509_CRL *crl, X509_REVOKED *rev); OPENSSL_EXPORT int X509_CRL_get0_by_serial(X509_CRL *crl, X509_REVOKED **ret, ASN1_INTEGER *serial); @@ -1102,97 +1390,6 @@ OPENSSL_EXPORT int ASN1_item_sign_ctx(const ASN1_ITEM *it, X509_ALGOR *algor1, ASN1_BIT_STRING *signature, void *asn, EVP_MD_CTX *ctx); -// X509_get_serialNumber returns a mutable pointer to |x509|'s serial number. -// Prefer |X509_get0_serialNumber|. -OPENSSL_EXPORT ASN1_INTEGER *X509_get_serialNumber(X509 *x509); - -// X509_set_issuer_name sets |x509|'s issuer to a copy of |name|. It returns one -// on success and zero on error. -OPENSSL_EXPORT int X509_set_issuer_name(X509 *x509, X509_NAME *name); - -// X509_get_issuer_name returns |x509|'s issuer. -OPENSSL_EXPORT X509_NAME *X509_get_issuer_name(const X509 *x509); - -// X509_set_subject_name sets |x509|'s subject to a copy of |name|. It returns -// one on success and zero on error. -OPENSSL_EXPORT int X509_set_subject_name(X509 *x509, X509_NAME *name); - -// X509_get_issuer_name returns |x509|'s subject. -OPENSSL_EXPORT X509_NAME *X509_get_subject_name(const X509 *x509); - -// X509_set_pubkey sets |x509|'s public key to |pkey|. It returns one on success -// and zero on error. This function does not take ownership of |pkey| and -// internally copies and updates reference counts as needed. -OPENSSL_EXPORT int X509_set_pubkey(X509 *x509, EVP_PKEY *pkey); - -// X509_get_pubkey returns |x509|'s public key as an |EVP_PKEY|, or NULL if the -// public key was unsupported or could not be decoded. This function returns a -// reference to the |EVP_PKEY|. The caller must release the result with -// |EVP_PKEY_free| when done. -OPENSSL_EXPORT EVP_PKEY *X509_get_pubkey(X509 *x509); - -// X509_get0_pubkey_bitstr returns the BIT STRING portion of |x509|'s public -// key. Note this does not contain the AlgorithmIdentifier portion. -// -// WARNING: This function returns a non-const pointer for OpenSSL compatibility, -// but the caller must not modify the resulting object. Doing so will break -// internal invariants in |x509|. -OPENSSL_EXPORT ASN1_BIT_STRING *X509_get0_pubkey_bitstr(const X509 *x509); - -// X509_get0_extensions returns |x509|'s extension list, or NULL if |x509| omits -// it. -OPENSSL_EXPORT const STACK_OF(X509_EXTENSION) *X509_get0_extensions( - const X509 *x509); - -// X509_get0_tbs_sigalg returns the signature algorithm in |x509|'s -// TBSCertificate. For the outer signature algorithm, see |X509_get0_signature|. -// -// Certificates with mismatched signature algorithms will successfully parse, -// but they will be rejected when verifying. -OPENSSL_EXPORT const X509_ALGOR *X509_get0_tbs_sigalg(const X509 *x509); - -// X509_REQ_set_version sets |req|'s version to |version|, which should be -// |X509_REQ_VERSION_1|. It returns one on success and zero on error. -// -// The only defined CSR version is |X509_REQ_VERSION_1|, so there is no need to -// call this function. -OPENSSL_EXPORT int X509_REQ_set_version(X509_REQ *req, long version); - -// X509_REQ_set_subject_name sets |req|'s subject to a copy of |name|. It -// returns one on success and zero on error. -OPENSSL_EXPORT int X509_REQ_set_subject_name(X509_REQ *req, X509_NAME *name); - -// X509_REQ_get0_signature sets |*out_sig| and |*out_alg| to the signature and -// signature algorithm of |req|, respectively. Either output pointer may be NULL -// to ignore the value. -OPENSSL_EXPORT void X509_REQ_get0_signature(const X509_REQ *req, - const ASN1_BIT_STRING **out_sig, - const X509_ALGOR **out_alg); - -// X509_REQ_get_signature_nid returns the NID corresponding to |req|'s signature -// algorithm, or |NID_undef| if the signature algorithm does not correspond to -// a known NID. -OPENSSL_EXPORT int X509_REQ_get_signature_nid(const X509_REQ *req); - -// i2d_re_X509_REQ_tbs serializes the CertificationRequestInfo (see RFC 2986) -// portion of |req|, as described in |i2d_SAMPLE|. -// -// This function re-encodes the CertificationRequestInfo and may not reflect -// |req|'s original encoding. It may be used to manually generate a signature -// for a new certificate request. -OPENSSL_EXPORT int i2d_re_X509_REQ_tbs(X509_REQ *req, uint8_t **outp); - -// X509_REQ_set_pubkey sets |req|'s public key to |pkey|. It returns one on -// success and zero on error. This function does not take ownership of |pkey| -// and internally copies and updates reference counts as needed. -OPENSSL_EXPORT int X509_REQ_set_pubkey(X509_REQ *req, EVP_PKEY *pkey); - -// X509_REQ_get_pubkey returns |req|'s public key as an |EVP_PKEY|, or NULL if -// the public key was unsupported or could not be decoded. This function returns -// a reference to the |EVP_PKEY|. The caller must release the result with -// |EVP_PKEY_free| when done. -OPENSSL_EXPORT EVP_PKEY *X509_REQ_get_pubkey(X509_REQ *req); - // X509_REQ_extension_nid returns one if |nid| is a supported CSR attribute type // for carrying extensions and zero otherwise. The supported types are // |NID_ext_req| (pkcs-9-at-extensionRequest from RFC 2985) and |NID_ms_ext_req| @@ -1280,93 +1477,8 @@ OPENSSL_EXPORT int X509_REQ_add1_attr_by_txt(X509_REQ *req, const unsigned char *data, int len); -// X509_REQ_set1_signature_algo sets |req|'s signature algorithm to |algo| and -// returns one on success or zero on error. -OPENSSL_EXPORT int X509_REQ_set1_signature_algo(X509_REQ *req, - const X509_ALGOR *algo); - -// X509_REQ_set1_signature_value sets |req|'s signature to a copy of the -// |sig_len| bytes pointed by |sig|. It returns one on success and zero on -// error. -// -// Due to a specification error, PKCS#10 certificate requests store signatures -// in ASN.1 BIT STRINGs, but signature algorithms return byte strings rather -// than bit strings. This function creates a BIT STRING containing a whole -// number of bytes, with the bit order matching the DER encoding. This matches -// the encoding used by all X.509 signature algorithms. -OPENSSL_EXPORT int X509_REQ_set1_signature_value(X509_REQ *req, - const uint8_t *sig, - size_t sig_len); - -// X509_CRL_set_version sets |crl|'s version to |version|, which should be one -// of the |X509_CRL_VERSION_*| constants. It returns one on success and zero on -// error. -// -// If unsure, use |X509_CRL_VERSION_2|. Note that, unlike certificates, CRL -// versions are only defined up to v2. Callers should not use |X509_VERSION_3|. -OPENSSL_EXPORT int X509_CRL_set_version(X509_CRL *crl, long version); - -// X509_CRL_set_issuer_name sets |crl|'s issuer to a copy of |name|. It returns -// one on success and zero on error. -OPENSSL_EXPORT int X509_CRL_set_issuer_name(X509_CRL *crl, X509_NAME *name); - OPENSSL_EXPORT int X509_CRL_sort(X509_CRL *crl); -// X509_CRL_up_ref adds one to the reference count of |crl| and returns one. -OPENSSL_EXPORT int X509_CRL_up_ref(X509_CRL *crl); - -// X509_CRL_get0_signature sets |*out_sig| and |*out_alg| to the signature and -// signature algorithm of |crl|, respectively. Either output pointer may be NULL -// to ignore the value. -// -// This function outputs the outer signature algorithm, not the one in the -// TBSCertList. CRLs with mismatched signature algorithms will successfully -// parse, but they will be rejected when verifying. -OPENSSL_EXPORT void X509_CRL_get0_signature(const X509_CRL *crl, - const ASN1_BIT_STRING **out_sig, - const X509_ALGOR **out_alg); - -// X509_CRL_get_signature_nid returns the NID corresponding to |crl|'s signature -// algorithm, or |NID_undef| if the signature algorithm does not correspond to -// a known NID. -OPENSSL_EXPORT int X509_CRL_get_signature_nid(const X509_CRL *crl); - -// i2d_re_X509_CRL_tbs serializes the TBSCertList portion of |crl|, as described -// in |i2d_SAMPLE|. -// -// This function re-encodes the TBSCertList and may not reflect |crl|'s original -// encoding. It may be used to manually generate a signature for a new CRL. To -// verify CRLs, use |i2d_X509_CRL_tbs| instead. -OPENSSL_EXPORT int i2d_re_X509_CRL_tbs(X509_CRL *crl, unsigned char **outp); - -// i2d_X509_CRL_tbs serializes the TBSCertList portion of |crl|, as described in -// |i2d_SAMPLE|. -// -// This function preserves the original encoding of the TBSCertList and may not -// reflect modifications made to |crl|. It may be used to manually verify the -// signature of an existing CRL. To generate CRLs, use |i2d_re_X509_CRL_tbs| -// instead. -OPENSSL_EXPORT int i2d_X509_CRL_tbs(X509_CRL *crl, unsigned char **outp); - -// X509_CRL_set1_signature_algo sets |crl|'s signature algorithm to |algo| and -// returns one on success or zero on error. It updates both the signature field -// of the TBSCertList structure, and the signatureAlgorithm field of the CRL. -OPENSSL_EXPORT int X509_CRL_set1_signature_algo(X509_CRL *crl, - const X509_ALGOR *algo); - -// X509_CRL_set1_signature_value sets |crl|'s signature to a copy of the -// |sig_len| bytes pointed by |sig|. It returns one on success and zero on -// error. -// -// Due to a specification error, X.509 CRLs store signatures in ASN.1 BIT -// STRINGs, but signature algorithms return byte strings rather than bit -// strings. This function creates a BIT STRING containing a whole number of -// bytes, with the bit order matching the DER encoding. This matches the -// encoding used by all X.509 signature algorithms. -OPENSSL_EXPORT int X509_CRL_set1_signature_value(X509_CRL *crl, - const uint8_t *sig, - size_t sig_len); - // X509_REVOKED_get0_serialNumber returns the serial number of the certificate // revoked by |revoked|. OPENSSL_EXPORT const ASN1_INTEGER *X509_REVOKED_get0_serialNumber( @@ -1405,12 +1517,6 @@ OPENSSL_EXPORT int X509_chain_check_suiteb(int *perror_depth, X509 *x, OPENSSL_EXPORT int X509_CRL_check_suiteb(X509_CRL *crl, EVP_PKEY *pk, unsigned long flags); -// X509_chain_up_ref returns a newly-allocated |STACK_OF(X509)| containing a -// shallow copy of |chain|, or NULL on error. That is, the return value has the -// same contents as |chain|, and each |X509|'s reference count is incremented by -// one. -OPENSSL_EXPORT STACK_OF(X509) *X509_chain_up_ref(STACK_OF(X509) *chain); - OPENSSL_EXPORT int X509_issuer_and_serial_cmp(const X509 *a, const X509 *b); OPENSSL_EXPORT int X509_issuer_name_cmp(const X509 *a, const X509 *b); @@ -2328,14 +2434,6 @@ OPENSSL_EXPORT int X509_STORE_load_locations(X509_STORE *ctx, const char *file, const char *dir); OPENSSL_EXPORT int X509_STORE_set_default_paths(X509_STORE *ctx); #endif - -OPENSSL_EXPORT int X509_STORE_CTX_get_ex_new_index(long argl, void *argp, - CRYPTO_EX_unused *unused, - CRYPTO_EX_dup *dup_unused, - CRYPTO_EX_free *free_func); -OPENSSL_EXPORT int X509_STORE_CTX_set_ex_data(X509_STORE_CTX *ctx, int idx, - void *data); -OPENSSL_EXPORT void *X509_STORE_CTX_get_ex_data(X509_STORE_CTX *ctx, int idx); OPENSSL_EXPORT int X509_STORE_CTX_get_error(X509_STORE_CTX *ctx); OPENSSL_EXPORT void X509_STORE_CTX_set_error(X509_STORE_CTX *ctx, int s); OPENSSL_EXPORT int X509_STORE_CTX_get_error_depth(X509_STORE_CTX *ctx); From 884ae3a040d8825bfd52ca9200de66c0dbfd90c9 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Fri, 8 Jul 2022 18:18:12 -0400 Subject: [PATCH 19/38] Clarify thisUpdate vs. lastUpdate in docs. OpenSSL calls the timestamp on the CRL lastUpdate, but it's actually called thisUpdate in RFC 5280. Bug: 426 Change-Id: I8a34f3de24e1914eda17d300321febe0205b2ec1 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/53310 Commit-Queue: David Benjamin Reviewed-by: Bob Beck --- include/openssl/x509.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/include/openssl/x509.h b/include/openssl/x509.h index 5f04055d27..1e8105bef2 100644 --- a/include/openssl/x509.h +++ b/include/openssl/x509.h @@ -449,7 +449,8 @@ OPENSSL_EXPORT int i2d_X509_CRL(X509_CRL *crl, uint8_t **outp); // will be one of the |X509_CRL_VERSION_*| constants. OPENSSL_EXPORT long X509_CRL_get_version(const X509_CRL *crl); -// X509_CRL_get0_lastUpdate returns |crl|'s lastUpdate time. +// X509_CRL_get0_lastUpdate returns |crl|'s thisUpdate time. The OpenSSL API +// refers to this field as lastUpdate. OPENSSL_EXPORT const ASN1_TIME *X509_CRL_get0_lastUpdate(const X509_CRL *crl); // X509_CRL_get0_nextUpdate returns |crl|'s nextUpdate time, or NULL if |crl| @@ -521,8 +522,9 @@ OPENSSL_EXPORT int X509_CRL_set_version(X509_CRL *crl, long version); // one on success and zero on error. OPENSSL_EXPORT int X509_CRL_set_issuer_name(X509_CRL *crl, X509_NAME *name); -// X509_CRL_set1_lastUpdate sets |crl|'s lastUpdate time to |tm|. It returns one -// on success and zero on error. +// X509_CRL_set1_lastUpdate sets |crl|'s thisUpdate time to |tm|. It returns one +// on success and zero on error. The OpenSSL API refers to this field as +// lastUpdate. OPENSSL_EXPORT int X509_CRL_set1_lastUpdate(X509_CRL *crl, const ASN1_TIME *tm); // X509_CRL_set1_nextUpdate sets |crl|'s nextUpdate time to |tm|. It returns one @@ -843,7 +845,9 @@ OPENSSL_EXPORT int X509_set_notBefore(X509 *x509, const ASN1_TIME *tm); // instead. OPENSSL_EXPORT int X509_set_notAfter(X509 *x509, const ASN1_TIME *tm); -// X509_CRL_get_lastUpdate returns a mutable pointer to |crl|'s lastUpdate time. +// X509_CRL_get_lastUpdate returns a mutable pointer to |crl|'s thisUpdate time. +// The OpenSSL API refers to this field as lastUpdate. +// // Use |X509_CRL_get0_lastUpdate| or |X509_CRL_set1_lastUpdate| instead. OPENSSL_EXPORT ASN1_TIME *X509_CRL_get_lastUpdate(X509_CRL *crl); From 3be30a55b0fed755b80280d6bdb791f4c19cc52c Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Sat, 9 Jul 2022 14:47:13 -0400 Subject: [PATCH 20/38] Add some tests for X509_NAME_ENTRY management. The X509_NAME representation is a little odd because it flattens the RDN sequence, but maintains RDN indices (X509_NAME_ENTRY_set) to recover the information. add_entry and delete_entry both have logic to maintain invariants. Test that they work. Change-Id: I7d4a033db0a82a1f13888bbfca29076b589cc214 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/53325 Reviewed-by: Bob Beck Commit-Queue: David Benjamin --- crypto/x509/x509_test.cc | 116 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) diff --git a/crypto/x509/x509_test.cc b/crypto/x509/x509_test.cc index 50121c93cb..8aee2d5a10 100644 --- a/crypto/x509/x509_test.cc +++ b/crypto/x509/x509_test.cc @@ -4548,3 +4548,119 @@ TEST(X509Test, AddExt) { X509V3_ADD_DELETE)); expect_extensions({{NID_subject_key_identifier, true, skid2_der}}); } + +TEST(X509Test, NameEntry) { + bssl::UniquePtr name(X509_NAME_new()); + ASSERT_TRUE(name); + + auto check_name = [&](const char *expected_rfc2253) { + // Check RDN indices are self-consistent. + int num = X509_NAME_entry_count(name.get()); + if (num > 0) { + // RDN indices must start at zero. + EXPECT_EQ(0, X509_NAME_ENTRY_set(X509_NAME_get_entry(name.get(), 0))); + } + for (int i = 1; i < num; i++) { + int prev = X509_NAME_ENTRY_set(X509_NAME_get_entry(name.get(), i - 1)); + int current = X509_NAME_ENTRY_set(X509_NAME_get_entry(name.get(), i)); + // RDN indices must increase consecutively. + EXPECT_TRUE(prev == current || prev + 1 == current) + << "Entry " << i << " has RDN index " << current + << " which is inconsistent with previous index " << prev; + } + + // Check the name based on the RFC 2253 serialization. Note the RFC 2253 + // serialization is in reverse. + bssl::UniquePtr bio(BIO_new(BIO_s_mem())); + ASSERT_TRUE(bio); + EXPECT_GE(X509_NAME_print_ex(bio.get(), name.get(), 0, XN_FLAG_RFC2253), 0); + const uint8_t *data; + size_t len; + ASSERT_TRUE(BIO_mem_contents(bio.get(), &data, &len)); + EXPECT_EQ(expected_rfc2253, std::string(data, data + len)); + }; + + check_name(""); + + // |loc| = -1, |set| = 0 appends as new RDNs. + ASSERT_TRUE(X509_NAME_add_entry_by_NID( + name.get(), NID_organizationName, MBSTRING_UTF8, + reinterpret_cast("Org"), /*len=*/-1, /*loc=*/-1, + /*set=*/0)); + check_name("O=Org"); + + // |loc| = -1, |set| = 0 appends as new RDNs. + ASSERT_TRUE(X509_NAME_add_entry_by_NID( + name.get(), NID_commonName, MBSTRING_UTF8, + reinterpret_cast("Name"), /*len=*/-1, /*loc=*/-1, + /*set=*/0)); + check_name("CN=Name,O=Org"); + + // Inserting in the middle of the set, but with |set| = 0 inserts a new RDN + // and fixes the "set" values as needed. + ASSERT_TRUE(X509_NAME_add_entry_by_NID( + name.get(), NID_organizationalUnitName, MBSTRING_UTF8, + reinterpret_cast("Unit"), /*len=*/-1, /*loc=*/1, + /*set=*/0)); + check_name("CN=Name,OU=Unit,O=Org"); + + // |set = -1| adds to the previous entry's RDN. (Although putting O and OU at + // the same level makes little sense, the test is written this way to check + // the function isn't using attribute types to order things.) + ASSERT_TRUE(X509_NAME_add_entry_by_NID( + name.get(), NID_organizationName, MBSTRING_UTF8, + reinterpret_cast("Org2"), /*len=*/-1, /*loc=*/2, + /*set=*/-1)); + check_name("CN=Name,O=Org2+OU=Unit,O=Org"); + + // |set| = 1 adds to the next entry's RDN. + ASSERT_TRUE(X509_NAME_add_entry_by_NID( + name.get(), NID_commonName, MBSTRING_UTF8, + reinterpret_cast("Name2"), /*len=*/-1, /*loc=*/2, + /*set=*/-1)); + check_name("CN=Name,O=Org2+CN=Name2+OU=Unit,O=Org"); + + // If there is no previous RDN, |set| = -1 makes a new RDN. + ASSERT_TRUE(X509_NAME_add_entry_by_NID( + name.get(), NID_countryName, MBSTRING_UTF8, + reinterpret_cast("US"), /*len=*/-1, /*loc=*/0, + /*set=*/-1)); + check_name("CN=Name,O=Org2+CN=Name2+OU=Unit,O=Org,C=US"); + + // Likewise if there is no next RDN. + ASSERT_TRUE(X509_NAME_add_entry_by_NID( + name.get(), NID_commonName, MBSTRING_UTF8, + reinterpret_cast("Name3"), /*len=*/-1, /*loc=*/-1, + /*set=*/1)); + check_name("CN=Name3,CN=Name,O=Org2+CN=Name2+OU=Unit,O=Org,C=US"); + + // If |set| = 0 and we insert in the middle of an existing RDN, it adds an + // RDN boundary after the entry but not before. This is a quirk of how the + // function is implemented and hopefully not something any caller depends on. + ASSERT_TRUE(X509_NAME_add_entry_by_NID( + name.get(), NID_commonName, MBSTRING_UTF8, + reinterpret_cast("Name4"), /*len=*/-1, /*loc=*/3, + /*set=*/0)); + check_name("CN=Name3,CN=Name,O=Org2+CN=Name2,CN=Name4+OU=Unit,O=Org,C=US"); + + // Entries may be deleted. + X509_NAME_ENTRY_free(X509_NAME_delete_entry(name.get(), 7)); + check_name("CN=Name,O=Org2+CN=Name2,CN=Name4+OU=Unit,O=Org,C=US"); + + // When deleting the only attribute in an RDN, index invariants should still + // hold. + X509_NAME_ENTRY_free(X509_NAME_delete_entry(name.get(), 0)); + check_name("CN=Name,O=Org2+CN=Name2,CN=Name4+OU=Unit,O=Org"); + + // Index invariants also hold when deleting attributes from non-singular RDNs. + X509_NAME_ENTRY_free(X509_NAME_delete_entry(name.get(), 1)); + check_name("CN=Name,O=Org2+CN=Name2,CN=Name4,O=Org"); + X509_NAME_ENTRY_free(X509_NAME_delete_entry(name.get(), 1)); + check_name("CN=Name,O=Org2+CN=Name2,O=Org"); + + // Same as above, but delete the second attribute first. + X509_NAME_ENTRY_free(X509_NAME_delete_entry(name.get(), 2)); + check_name("CN=Name,CN=Name2,O=Org"); + X509_NAME_ENTRY_free(X509_NAME_delete_entry(name.get(), 1)); + check_name("CN=Name,O=Org"); +} From b6f47e88b09703e925c894ca77a5d90ee413e6b5 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Sat, 9 Jul 2022 00:57:54 -0400 Subject: [PATCH 21/38] Document most X509_NAME functions. Unfortunately, these functions are not const-correct, even the accessors. Document what they should have been, especially since mutating an X509_NAME_ENTRY directly won't even update the 'modified' bit correctly. Do a pass at adding consts to our code internally, but since the functions return non-const pointers, this isn't checked anywhere. And since serializing an X509_NAME is not always thread-safe, there's a limit to how much we can correctly mark things as const. Bug: 426 Change-Id: Ifa3d8bafb5396fbe7b91416f234de4585284c705 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/53326 Reviewed-by: Bob Beck Commit-Queue: David Benjamin --- crypto/x509/name_print.c | 8 +- crypto/x509/x509_vfy.c | 6 +- crypto/x509/x509name.c | 63 ++++---- crypto/x509v3/v3_ncons.c | 19 ++- crypto/x509v3/v3_utl.c | 55 +++---- include/openssl/x509.h | 338 ++++++++++++++++++++++++++++++--------- 6 files changed, 329 insertions(+), 160 deletions(-) diff --git a/crypto/x509/name_print.c b/crypto/x509/name_print.c index f871df974b..29207ccb69 100644 --- a/crypto/x509/name_print.c +++ b/crypto/x509/name_print.c @@ -86,9 +86,6 @@ static int do_name_ex(BIO *out, const X509_NAME *n, int indent, unsigned long flags) { int i, prev = -1, orflags, cnt; int fn_opt, fn_nid; - ASN1_OBJECT *fn; - ASN1_STRING *val; - X509_NAME_ENTRY *ent; char objtmp[80]; const char *objbuf; int outlen, len; @@ -149,6 +146,7 @@ static int do_name_ex(BIO *out, const X509_NAME *n, int indent, cnt = X509_NAME_entry_count(n); for (i = 0; i < cnt; i++) { + const X509_NAME_ENTRY *ent; if (flags & XN_FLAG_DN_REV) { ent = X509_NAME_get_entry(n, cnt - i - 1); } else { @@ -172,8 +170,8 @@ static int do_name_ex(BIO *out, const X509_NAME *n, int indent, } } prev = X509_NAME_ENTRY_set(ent); - fn = X509_NAME_ENTRY_get_object(ent); - val = X509_NAME_ENTRY_get_data(ent); + const ASN1_OBJECT *fn = X509_NAME_ENTRY_get_object(ent); + const ASN1_STRING *val = X509_NAME_ENTRY_get_data(ent); fn_nid = OBJ_obj2nid(fn); if (fn_opt != XN_FLAG_FN_NONE) { int objlen, fld_len; diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c index 8569d2ac03..5a97353986 100644 --- a/crypto/x509/x509_vfy.c +++ b/crypto/x509/x509_vfy.c @@ -689,7 +689,7 @@ static int check_chain_extensions(X509_STORE_CTX *ctx) { } static int reject_dns_name_in_common_name(X509 *x509) { - X509_NAME *name = X509_get_subject_name(x509); + const X509_NAME *name = X509_get_subject_name(x509); int i = -1; for (;;) { i = X509_NAME_get_index_by_NID(name, NID_commonName, i); @@ -697,8 +697,8 @@ static int reject_dns_name_in_common_name(X509 *x509) { return X509_V_OK; } - X509_NAME_ENTRY *entry = X509_NAME_get_entry(name, i); - ASN1_STRING *common_name = X509_NAME_ENTRY_get_data(entry); + const X509_NAME_ENTRY *entry = X509_NAME_get_entry(name, i); + const ASN1_STRING *common_name = X509_NAME_ENTRY_get_data(entry); unsigned char *idval; int idlen = ASN1_STRING_to_UTF8(&idval, common_name); if (idlen < 0) { diff --git a/crypto/x509/x509name.c b/crypto/x509/x509name.c index 6771b68296..fcfbc0c91c 100644 --- a/crypto/x509/x509name.c +++ b/crypto/x509/x509name.c @@ -80,14 +80,12 @@ int X509_NAME_get_text_by_NID(const X509_NAME *name, int nid, char *buf, int X509_NAME_get_text_by_OBJ(const X509_NAME *name, const ASN1_OBJECT *obj, char *buf, int len) { - int i; - ASN1_STRING *data; - - i = X509_NAME_get_index_by_OBJ(name, obj, -1); + int i = X509_NAME_get_index_by_OBJ(name, obj, -1); if (i < 0) { return -1; } - data = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, i)); + const ASN1_STRING *data = + X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, i)); i = (data->length > (len - 1)) ? (len - 1) : data->length; if (buf == NULL) { return data->length; @@ -148,51 +146,46 @@ X509_NAME_ENTRY *X509_NAME_get_entry(const X509_NAME *name, int loc) { } X509_NAME_ENTRY *X509_NAME_delete_entry(X509_NAME *name, int loc) { - X509_NAME_ENTRY *ret; - int i, n, set_prev, set_next; - STACK_OF(X509_NAME_ENTRY) *sk; - if (name == NULL || loc < 0 || sk_X509_NAME_ENTRY_num(name->entries) <= (size_t)loc) { return NULL; } - sk = name->entries; - ret = sk_X509_NAME_ENTRY_delete(sk, loc); - n = sk_X509_NAME_ENTRY_num(sk); + + STACK_OF(X509_NAME_ENTRY) *sk = name->entries; + X509_NAME_ENTRY *ret = sk_X509_NAME_ENTRY_delete(sk, loc); + int n = sk_X509_NAME_ENTRY_num(sk); name->modified = 1; if (loc == n) { return ret; } - // else we need to fixup the set field + int set_prev; if (loc != 0) { - set_prev = (sk_X509_NAME_ENTRY_value(sk, loc - 1))->set; + set_prev = sk_X509_NAME_ENTRY_value(sk, loc - 1)->set; } else { set_prev = ret->set - 1; } - set_next = sk_X509_NAME_ENTRY_value(sk, loc)->set; + int set_next = sk_X509_NAME_ENTRY_value(sk, loc)->set; - // set_prev is the previous set set is the current set set_next is the - // following prev 1 1 1 1 1 1 1 1 set 1 1 2 2 next 1 1 2 2 2 2 3 2 so - // basically only if prev and next differ by 2, then re-number down by 1 + // If we removed a singleton RDN, update the RDN indices so they are + // consecutive again. if (set_prev + 1 < set_next) { - for (i = loc; i < n; i++) { + for (int i = loc; i < n; i++) { sk_X509_NAME_ENTRY_value(sk, i)->set--; } } return ret; } -int X509_NAME_add_entry_by_OBJ(X509_NAME *name, ASN1_OBJECT *obj, int type, - const unsigned char *bytes, int len, int loc, - int set) { - X509_NAME_ENTRY *ne; - int ret; - ne = X509_NAME_ENTRY_create_by_OBJ(NULL, obj, type, bytes, len); +int X509_NAME_add_entry_by_OBJ(X509_NAME *name, const ASN1_OBJECT *obj, + int type, const unsigned char *bytes, int len, + int loc, int set) { + X509_NAME_ENTRY *ne = + X509_NAME_ENTRY_create_by_OBJ(NULL, obj, type, bytes, len); if (!ne) { return 0; } - ret = X509_NAME_add_entry(name, ne, loc, set); + int ret = X509_NAME_add_entry(name, ne, loc, set); X509_NAME_ENTRY_free(ne); return ret; } @@ -200,13 +193,12 @@ int X509_NAME_add_entry_by_OBJ(X509_NAME *name, ASN1_OBJECT *obj, int type, int X509_NAME_add_entry_by_NID(X509_NAME *name, int nid, int type, const unsigned char *bytes, int len, int loc, int set) { - X509_NAME_ENTRY *ne; - int ret; - ne = X509_NAME_ENTRY_create_by_NID(NULL, nid, type, bytes, len); + X509_NAME_ENTRY *ne = + X509_NAME_ENTRY_create_by_NID(NULL, nid, type, bytes, len); if (!ne) { return 0; } - ret = X509_NAME_add_entry(name, ne, loc, set); + int ret = X509_NAME_add_entry(name, ne, loc, set); X509_NAME_ENTRY_free(ne); return ret; } @@ -214,20 +206,19 @@ int X509_NAME_add_entry_by_NID(X509_NAME *name, int nid, int type, int X509_NAME_add_entry_by_txt(X509_NAME *name, const char *field, int type, const unsigned char *bytes, int len, int loc, int set) { - X509_NAME_ENTRY *ne; - int ret; - ne = X509_NAME_ENTRY_create_by_txt(NULL, field, type, bytes, len); + X509_NAME_ENTRY *ne = + X509_NAME_ENTRY_create_by_txt(NULL, field, type, bytes, len); if (!ne) { return 0; } - ret = X509_NAME_add_entry(name, ne, loc, set); + int ret = X509_NAME_add_entry(name, ne, loc, set); X509_NAME_ENTRY_free(ne); return ret; } // if set is -1, append to previous set, 0 'a new one', and 1, prepend to the // guy we are about to stomp on. -int X509_NAME_add_entry(X509_NAME *name, X509_NAME_ENTRY *ne, int loc, +int X509_NAME_add_entry(X509_NAME *name, const X509_NAME_ENTRY *entry, int loc, int set) { X509_NAME_ENTRY *new_name = NULL; int n, i, inc; @@ -267,7 +258,7 @@ int X509_NAME_add_entry(X509_NAME *name, X509_NAME_ENTRY *ne, int loc, } } - if ((new_name = X509_NAME_ENTRY_dup(ne)) == NULL) { + if ((new_name = X509_NAME_ENTRY_dup(entry)) == NULL) { goto err; } new_name->set = set; diff --git a/crypto/x509v3/v3_ncons.c b/crypto/x509v3/v3_ncons.c index 967423aaf4..5505a620cd 100644 --- a/crypto/x509v3/v3_ncons.c +++ b/crypto/x509v3/v3_ncons.c @@ -76,14 +76,14 @@ static int i2r_NAME_CONSTRAINTS(const X509V3_EXT_METHOD *method, void *a, static int do_i2r_name_constraints(const X509V3_EXT_METHOD *method, STACK_OF(GENERAL_SUBTREE) *trees, BIO *bp, int ind, const char *name); -static int print_nc_ipadd(BIO *bp, ASN1_OCTET_STRING *ip); +static int print_nc_ipadd(BIO *bp, const ASN1_OCTET_STRING *ip); static int nc_match(GENERAL_NAME *gen, NAME_CONSTRAINTS *nc); static int nc_match_single(GENERAL_NAME *sub, GENERAL_NAME *gen); static int nc_dn(X509_NAME *sub, X509_NAME *nm); -static int nc_dns(ASN1_IA5STRING *sub, ASN1_IA5STRING *dns); -static int nc_email(ASN1_IA5STRING *sub, ASN1_IA5STRING *eml); -static int nc_uri(ASN1_IA5STRING *uri, ASN1_IA5STRING *base); +static int nc_dns(const ASN1_IA5STRING *sub, const ASN1_IA5STRING *dns); +static int nc_email(const ASN1_IA5STRING *sub, const ASN1_IA5STRING *eml); +static int nc_uri(const ASN1_IA5STRING *uri, const ASN1_IA5STRING *base); const X509V3_EXT_METHOD v3_name_constraints = { NID_name_constraints, @@ -196,7 +196,7 @@ static int do_i2r_name_constraints(const X509V3_EXT_METHOD *method, return 1; } -static int print_nc_ipadd(BIO *bp, ASN1_OCTET_STRING *ip) { +static int print_nc_ipadd(BIO *bp, const ASN1_OCTET_STRING *ip) { int i, len; unsigned char *p; p = ip->data; @@ -273,12 +273,11 @@ int NAME_CONSTRAINTS_check(X509 *x, NAME_CONSTRAINTS *nc) { // Process any email address attributes in subject name for (i = -1;;) { - X509_NAME_ENTRY *ne; i = X509_NAME_get_index_by_NID(nm, NID_pkcs9_emailAddress, i); if (i == -1) { break; } - ne = X509_NAME_get_entry(nm, i); + const X509_NAME_ENTRY *ne = X509_NAME_get_entry(nm, i); gntmp.d.rfc822Name = X509_NAME_ENTRY_get_data(ne); if (gntmp.d.rfc822Name->type != V_ASN1_IA5STRING) { return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX; @@ -429,7 +428,7 @@ static int has_suffix_case(const CBS *a, const CBS *b) { return equal_case(©, b); } -static int nc_dns(ASN1_IA5STRING *dns, ASN1_IA5STRING *base) { +static int nc_dns(const ASN1_IA5STRING *dns, const ASN1_IA5STRING *base) { CBS dns_cbs, base_cbs; CBS_init(&dns_cbs, dns->data, dns->length); CBS_init(&base_cbs, base->data, base->length); @@ -465,7 +464,7 @@ static int nc_dns(ASN1_IA5STRING *dns, ASN1_IA5STRING *base) { return X509_V_OK; } -static int nc_email(ASN1_IA5STRING *eml, ASN1_IA5STRING *base) { +static int nc_email(const ASN1_IA5STRING *eml, const ASN1_IA5STRING *base) { CBS eml_cbs, base_cbs; CBS_init(&eml_cbs, eml->data, eml->length); CBS_init(&base_cbs, base->data, base->length); @@ -513,7 +512,7 @@ static int nc_email(ASN1_IA5STRING *eml, ASN1_IA5STRING *base) { return X509_V_OK; } -static int nc_uri(ASN1_IA5STRING *uri, ASN1_IA5STRING *base) { +static int nc_uri(const ASN1_IA5STRING *uri, const ASN1_IA5STRING *base) { CBS uri_cbs, base_cbs; CBS_init(&uri_cbs, uri->data, uri->length); CBS_init(&base_cbs, base->data, base->length); diff --git a/crypto/x509v3/v3_utl.c b/crypto/x509v3/v3_utl.c index 3eccf069bc..15ebe540c8 100644 --- a/crypto/x509v3/v3_utl.c +++ b/crypto/x509v3/v3_utl.c @@ -77,10 +77,11 @@ static char *strip_spaces(char *name); static int sk_strcmp(const char **a, const char **b); -static STACK_OF(OPENSSL_STRING) *get_email(X509_NAME *name, - GENERAL_NAMES *gens); +static STACK_OF(OPENSSL_STRING) *get_email(const X509_NAME *name, + const GENERAL_NAMES *gens); static void str_free(OPENSSL_STRING str); -static int append_ia5(STACK_OF(OPENSSL_STRING) **sk, ASN1_IA5STRING *email); +static int append_ia5(STACK_OF(OPENSSL_STRING) **sk, + const ASN1_IA5STRING *email); static int ipv4_from_asc(unsigned char v4[4], const char *in); static int ipv6_from_asc(unsigned char v6[16], const char *in); @@ -617,27 +618,22 @@ STACK_OF(OPENSSL_STRING) *X509_REQ_get1_email(X509_REQ *x) { return ret; } -static STACK_OF(OPENSSL_STRING) *get_email(X509_NAME *name, - GENERAL_NAMES *gens) { +static STACK_OF(OPENSSL_STRING) *get_email(const X509_NAME *name, + const GENERAL_NAMES *gens) { STACK_OF(OPENSSL_STRING) *ret = NULL; - X509_NAME_ENTRY *ne; - ASN1_IA5STRING *email; - GENERAL_NAME *gen; - int i; - size_t j; // Now add any email address(es) to STACK - i = -1; + int i = -1; // First supplied X509_NAME while ((i = X509_NAME_get_index_by_NID(name, NID_pkcs9_emailAddress, i)) >= 0) { - ne = X509_NAME_get_entry(name, i); - email = X509_NAME_ENTRY_get_data(ne); + const X509_NAME_ENTRY *ne = X509_NAME_get_entry(name, i); + const ASN1_IA5STRING *email = X509_NAME_ENTRY_get_data(ne); if (!append_ia5(&ret, email)) { return NULL; } } - for (j = 0; j < sk_GENERAL_NAME_num(gens); j++) { - gen = sk_GENERAL_NAME_value(gens, j); + for (size_t j = 0; j < sk_GENERAL_NAME_num(gens); j++) { + const GENERAL_NAME *gen = sk_GENERAL_NAME_value(gens, j); if (gen->type != GEN_EMAIL) { continue; } @@ -650,7 +646,8 @@ static STACK_OF(OPENSSL_STRING) *get_email(X509_NAME *name, static void str_free(OPENSSL_STRING str) { OPENSSL_free(str); } -static int append_ia5(STACK_OF(OPENSSL_STRING) **sk, ASN1_IA5STRING *email) { +static int append_ia5(STACK_OF(OPENSSL_STRING) **sk, + const ASN1_IA5STRING *email) { // First some sanity checks if (email->type != V_ASN1_IA5STRING) { return 1; @@ -952,7 +949,7 @@ int x509v3_looks_like_dns_name(const unsigned char *in, size_t len) { // cmp_type > 0 only compare if string matches the type, otherwise convert it // to UTF8. -static int do_check_string(ASN1_STRING *a, int cmp_type, equal_fn equal, +static int do_check_string(const ASN1_STRING *a, int cmp_type, equal_fn equal, unsigned int flags, int check_type, const char *b, size_t blen, char **peername) { int rv = 0; @@ -997,15 +994,10 @@ static int do_check_string(ASN1_STRING *a, int cmp_type, equal_fn equal, static int do_x509_check(X509 *x, const char *chk, size_t chklen, unsigned int flags, int check_type, char **peername) { - GENERAL_NAMES *gens = NULL; - X509_NAME *name = NULL; - size_t i; - int j; int cnid = NID_undef; int alt_type; int rv = 0; equal_fn equal; - if (check_type == GEN_EMAIL) { cnid = NID_pkcs9_emailAddress; alt_type = V_ASN1_IA5STRING; @@ -1023,15 +1015,14 @@ static int do_x509_check(X509 *x, const char *chk, size_t chklen, equal = equal_case; } - gens = X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL); + GENERAL_NAMES *gens = X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL); if (gens) { - for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) { - GENERAL_NAME *gen; - ASN1_STRING *cstr; - gen = sk_GENERAL_NAME_value(gens, i); + for (size_t i = 0; i < sk_GENERAL_NAME_num(gens); i++) { + const GENERAL_NAME *gen = sk_GENERAL_NAME_value(gens, i); if (gen->type != check_type) { continue; } + const ASN1_STRING *cstr; if (check_type == GEN_EMAIL) { cstr = gen->d.rfc822Name; } else if (check_type == GEN_DNS) { @@ -1054,13 +1045,11 @@ static int do_x509_check(X509 *x, const char *chk, size_t chklen, return 0; } - j = -1; - name = X509_get_subject_name(x); + int j = -1; + const X509_NAME *name = X509_get_subject_name(x); while ((j = X509_NAME_get_index_by_NID(name, cnid, j)) >= 0) { - X509_NAME_ENTRY *ne; - ASN1_STRING *str; - ne = X509_NAME_get_entry(name, j); - str = X509_NAME_ENTRY_get_data(ne); + const X509_NAME_ENTRY *ne = X509_NAME_get_entry(name, j); + const ASN1_STRING *str = X509_NAME_ENTRY_get_data(ne); // Positive on success, negative on error! if ((rv = do_check_string(str, -1, equal, flags, check_type, chk, chklen, peername)) != 0) { diff --git a/include/openssl/x509.h b/include/openssl/x509.h index 1e8105bef2..34eb840a3d 100644 --- a/include/openssl/x509.h +++ b/include/openssl/x509.h @@ -711,6 +711,246 @@ OPENSSL_EXPORT int X509_REQ_set1_signature_value(X509_REQ *req, size_t sig_len); +// Names. +// +// An |X509_NAME| represents an X.509 Name structure (RFC 5280). X.509 names are +// a complex, hierarchical structure over a collection of attributes. Each name +// is sequence of relative distinguished names (RDNs), decreasing in +// specificity. For example, the first RDN may specify the country, while the +// next RDN may specify a locality. Each RDN is, itself, a set of attributes. +// Having more than one attribute in an RDN is uncommon, but possible. Within an +// RDN, attributes have the same level in specificity. Attribute types are +// OBJECT IDENTIFIERs. This determines the ASN.1 type of the value, which is +// commonly a string but may be other types. +// +// The |X509_NAME| representation flattens this two-level structure into a +// single list of attributes. Each attribute is stored in an |X509_NAME_ENTRY|, +// with also maintains the index of the RDN it is part of, accessible via +// |X509_NAME_ENTRY_set|. This can be used to recover the two-level structure. +// +// X.509 names are largely vestigial. Historically, DNS names were parsed out of +// the subject's common name attribute, but this is deprecated and has since +// moved to the subject alternative name extension. In modern usage, X.509 names +// are primarily opaque identifiers to link a certificate with its issuer. + +DEFINE_STACK_OF(X509_NAME_ENTRY) +DEFINE_STACK_OF(X509_NAME) + +// X509_NAME is an |ASN1_ITEM| whose ASN.1 type is X.509 Name (RFC 5280) and C +// type is |X509_NAME*|. +DECLARE_ASN1_ITEM(X509_NAME) + +// X509_NAME_new returns a new, empty |X509_NAME_new|, or NULL on +// error. +OPENSSL_EXPORT X509_NAME *X509_NAME_new(void); + +// X509_NAME_free releases memory associated with |name|. +OPENSSL_EXPORT void X509_NAME_free(X509_NAME *name); + +// d2i_X509_NAME parses up to |len| bytes from |*inp| as a DER-encoded X.509 +// Name (RFC 5280), as described in |d2i_SAMPLE_with_reuse|. +OPENSSL_EXPORT X509_NAME *d2i_X509_NAME(X509_NAME **out, const uint8_t **inp, + long len); + +// i2d_X509_NAME marshals |in| as a DER-encoded X.509 Name (RFC 5280), as +// described in |i2d_SAMPLE|. +// +// TODO(https://crbug.com/boringssl/407): This function should be const and +// thread-safe but is currently neither in some cases, notably if |in| was +// mutated. +OPENSSL_EXPORT int i2d_X509_NAME(X509_NAME *in, uint8_t **outp); + +// X509_NAME_dup returns a newly-allocated copy of |name|, or NULL on error. +// +// TODO(https://crbug.com/boringssl/407): This function should be const and +// thread-safe but is currently neither in some cases, notably if |name| was +// mutated. +OPENSSL_EXPORT X509_NAME *X509_NAME_dup(X509_NAME *name); + +// X509_NAME_get0_der sets |*out_der| and |*out_der_len| +// +// Avoid this function and prefer |i2d_X509_NAME|. It is one of the reasons +// these functions are not consistently thread-safe or const-correct. Depending +// on the resolution of https://crbug.com/boringssl/407, this function may be +// removed or cause poor performance. +OPENSSL_EXPORT int X509_NAME_get0_der(X509_NAME *name, const uint8_t **out_der, + size_t *out_der_len); + +// X509_NAME_set makes a copy of |name|. On success, it frees |*xn|, sets |*xn| +// to the copy, and returns one. Otherwise, it returns zero. +// +// TODO(https://crbug.com/boringssl/407): This function should be const and +// thread-safe but is currently neither in some cases, notably if |name| was +// mutated. +OPENSSL_EXPORT int X509_NAME_set(X509_NAME **xn, X509_NAME *name); + +// X509_NAME_entry_count returns the number of entries in |name|. +OPENSSL_EXPORT int X509_NAME_entry_count(const X509_NAME *name); + +// X509_NAME_get_index_by_NID returns the zero-based index of the first +// attribute in |name| with type |nid|, or -1 if there is none. |nid| should be +// one of the |NID_*| constants. If |lastpos| is non-negative, it begins +// searching at |lastpos+1|. To search all attributes, pass in -1, not zero. +// +// Indices from this function refer to |X509_NAME|'s flattened representation. +OPENSSL_EXPORT int X509_NAME_get_index_by_NID(const X509_NAME *name, int nid, + int lastpos); + +// X509_NAME_get_index_by_OBJ behaves like |X509_NAME_get_index_by_NID| but +// looks for attributes with type |obj|. +OPENSSL_EXPORT int X509_NAME_get_index_by_OBJ(const X509_NAME *name, + const ASN1_OBJECT *obj, + int lastpos); + +// X509_NAME_get_entry returns the attribute in |name| at index |loc|, or NULL +// if |loc| is out of range. |loc| is interpreted using |X509_NAME|'s flattened +// representation. This function returns a non-const pointer for OpenSSL +// compatibility, but callers should not mutate the result. Doing so will break +// internal invariants in the library. +OPENSSL_EXPORT X509_NAME_ENTRY *X509_NAME_get_entry(const X509_NAME *name, + int loc); + +// X509_NAME_delete_entry removes and returns the attribute in |name| at index +// |loc|, or NULL if |loc| is out of range. |loc| is interpreted using +// |X509_NAME|'s flattened representation. If the attribute is found, the caller +// is responsible for releasing the result with |X509_NAME_ENTRY_free|. +// +// This function will internally update RDN indices (see |X509_NAME_ENTRY_set|) +// so they continue to be consecutive. +OPENSSL_EXPORT X509_NAME_ENTRY *X509_NAME_delete_entry(X509_NAME *name, + int loc); + +// X509_NAME_add_entry adds a copy of |entry| to |name| and returns one on +// success or zero on error. If |loc| is -1, the entry is appended to |name|. +// Otherwise, it is inserted at index |loc|. If |set| is -1, the entry is added +// to the previous entry's RDN. If it is 0, the entry becomes a singleton RDN. +// If 1, it is added to next entry's RDN. +// +// This function will internally update RDN indices (see |X509_NAME_ENTRY_set|) +// so they continue to be consecutive. +OPENSSL_EXPORT int X509_NAME_add_entry(X509_NAME *name, + const X509_NAME_ENTRY *entry, int loc, + int set); + +// X509_NAME_add_entry_by_OBJ adds a new entry to |name| and returns one on +// success or zero on error. The entry's attribute type is |obj|. The entry's +// attribute value is determined by |type|, |bytes|, and |len|, as in +// |X509_NAME_ENTRY_set_data|. The entry's position is determined by |loc| and +// |set| as in |X509_NAME_entry|. +OPENSSL_EXPORT int X509_NAME_add_entry_by_OBJ(X509_NAME *name, + const ASN1_OBJECT *obj, int type, + const uint8_t *bytes, int len, + int loc, int set); + +// X509_NAME_add_entry_by_NID behaves like |X509_NAME_add_entry_by_OBJ| but sets +// the entry's attribute type to |nid|, which should be one of the |NID_*| +// constants. +OPENSSL_EXPORT int X509_NAME_add_entry_by_NID(X509_NAME *name, int nid, + int type, const uint8_t *bytes, + int len, int loc, int set); + +// X509_NAME_add_entry_by_txt behaves like |X509_NAME_add_entry_by_OBJ| but sets +// the entry's attribute type to |field|, which is passed to |OBJ_txt2obj|. +OPENSSL_EXPORT int X509_NAME_add_entry_by_txt(X509_NAME *name, + const char *field, int type, + const uint8_t *bytes, int len, + int loc, int set); + +// X509_NAME_ENTRY is an |ASN1_ITEM| whose ASN.1 type is AttributeTypeAndValue +// (RFC 5280) and C type is |X509_NAME_ENTRY*|. +DECLARE_ASN1_ITEM(X509_NAME_ENTRY) + +// X509_NAME_ENTRY_new returns a new, empty |X509_NAME_ENTRY_new|, or NULL on +// error. +OPENSSL_EXPORT X509_NAME_ENTRY *X509_NAME_ENTRY_new(void); + +// X509_NAME_ENTRY_free releases memory associated with |entry|. +OPENSSL_EXPORT void X509_NAME_ENTRY_free(X509_NAME_ENTRY *entry); + +// d2i_X509_NAME_ENTRY parses up to |len| bytes from |*inp| as a DER-encoded +// AttributeTypeAndValue (RFC 5280), as described in |d2i_SAMPLE_with_reuse|. +OPENSSL_EXPORT X509_NAME_ENTRY *d2i_X509_NAME_ENTRY(X509_NAME_ENTRY **out, + const uint8_t **inp, + long len); + +// i2d_X509_NAME_ENTRY marshals |in| as a DER-encoded AttributeTypeAndValue (RFC +// 5280), as described in |i2d_SAMPLE|. +OPENSSL_EXPORT int i2d_X509_NAME_ENTRY(const X509_NAME_ENTRY *in, + uint8_t **outp); + +// X509_NAME_ENTRY_dup returns a newly-allocated copy of |entry|, or NULL on +// error. +OPENSSL_EXPORT X509_NAME_ENTRY *X509_NAME_ENTRY_dup( + const X509_NAME_ENTRY *entry); + +// X509_NAME_ENTRY_get_object returns |entry|'s attribute type. This function +// returns a non-const pointer for OpenSSL compatibility, but callers should not +// mutate the result. Doing so will break internal invariants in the library. +OPENSSL_EXPORT ASN1_OBJECT *X509_NAME_ENTRY_get_object( + const X509_NAME_ENTRY *entry); + +// X509_NAME_ENTRY_set_object sets |entry|'s attribute type to |obj|. It returns +// one on success and zero on error. +OPENSSL_EXPORT int X509_NAME_ENTRY_set_object(X509_NAME_ENTRY *entry, + const ASN1_OBJECT *obj); + +// X509_NAME_ENTRY_get_data returns |entry|'s attribute value, represented as an +// |ASN1_STRING|. This value may have any ASN.1 type, so callers must check the +// type before interpreting the contents. This function returns a non-const +// pointer for OpenSSL compatibility, but callers should not mutate the result. +// Doing so will break internal invariants in the library. +// +// TODO(https://crbug.com/boringssl/412): Although the spec says any ASN.1 type +// is allowed, we currently only allow an ad-hoc set of types. Additionally, it +// is unclear if some types can even be represented by this function. +OPENSSL_EXPORT ASN1_STRING *X509_NAME_ENTRY_get_data( + const X509_NAME_ENTRY *entry); + +// X509_NAME_ENTRY_set_data sets |entry|'s value to |len| bytes from |bytes|. It +// returns one on success and zero on error. If |len| is -1, |bytes| must be a +// NUL-terminated C string and the length is determined by |strlen|. |bytes| is +// converted to an ASN.1 type as follows: +// +// If |type| is a |MBSTRING_*| constant, the value is an ASN.1 string. The +// string is determined by decoding |bytes| in the encoding specified by |type|, +// and then re-encoding it in a form appropriate for |entry|'s attribute type. +// See |ASN1_STRING_set_by_NID| for details. +// +// Otherwise, the value is an |ASN1_STRING| with type |type| and value |bytes|. +// See |ASN1_STRING| for how to format ASN.1 types as an |ASN1_STRING|. If +// |type| is |V_ASN1_UNDEF| the previous |ASN1_STRING| type is reused. +OPENSSL_EXPORT int X509_NAME_ENTRY_set_data(X509_NAME_ENTRY *entry, int type, + const uint8_t *bytes, int len); + +// X509_NAME_ENTRY_set returns the zero-based index of the RDN which contains +// |entry|. Consecutive entries with the same index are part of the same RDN. +OPENSSL_EXPORT int X509_NAME_ENTRY_set(const X509_NAME_ENTRY *entry); + +// X509_NAME_ENTRY_create_by_OBJ creates a new |X509_NAME_ENTRY| with attribute +// type |obj|. The attribute value is determined from |type|, |bytes|, and |len| +// as in |X509_NAME_ENTRY_set_data|. It returns the |X509_NAME_ENTRY| on success +// and NULL on error. +// +// If |out| is non-NULL and |*out| is NULL, it additionally sets |*out| to the +// result on success. If both |out| and |*out| are non-NULL, it updates the +// object at |*out| instead of allocating a new one. +OPENSSL_EXPORT X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_OBJ( + X509_NAME_ENTRY **out, const ASN1_OBJECT *obj, int type, + const uint8_t *bytes, int len); + +// X509_NAME_ENTRY_create_by_NID behaves like |X509_NAME_ENTRY_create_by_OBJ| +// except the attribute type is |nid|, which should be one of the |NID_*| +// constants. +OPENSSL_EXPORT X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_NID( + X509_NAME_ENTRY **out, int nid, int type, const uint8_t *bytes, int len); + +// X509_NAME_ENTRY_create_by_txt behaves like |X509_NAME_ENTRY_create_by_OBJ| +// except the attribute type is |field|, which is passed to |OBJ_txt2obj|. +OPENSSL_EXPORT X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_txt( + X509_NAME_ENTRY **out, const char *field, int type, const uint8_t *bytes, + int len); + + // Algorithm identifiers. // // An |X509_ALGOR| represents an AlgorithmIdentifier structure, used in X.509 @@ -874,6 +1114,31 @@ OPENSSL_EXPORT ASN1_TIME *X509_CRL_get_nextUpdate(X509_CRL *crl); // Prefer |X509_get0_serialNumber|. OPENSSL_EXPORT ASN1_INTEGER *X509_get_serialNumber(X509 *x509); +// X509_NAME_get_text_by_OBJ finds the first attribute with type |obj| in +// |name|. If found, it ignores the value's ASN.1 type, writes the raw +// |ASN1_STRING| representation to |buf|, followed by a NUL byte, and +// returns the number of bytes in output, excluding the NUL byte. +// +// This function writes at most |len| bytes, including the NUL byte. If |len| is +// not large enough, it silently truncates the output to fit. If |buf| is NULL, +// it instead writes enough and returns the number of bytes in the output, +// excluding the NUL byte. +// +// WARNING: Do not use this function. It does not return enough information for +// the caller to correctly interpret its output. The attribute value may be of +// any type, including one of several ASN.1 string encodings, but this function +// only outputs the raw |ASN1_STRING| representation. See +// https://crbug.com/boringssl/436. +OPENSSL_EXPORT int X509_NAME_get_text_by_OBJ(const X509_NAME *name, + const ASN1_OBJECT *obj, char *buf, + int len); + +// X509_NAME_get_text_by_NID behaves like |X509_NAME_get_text_by_OBJ| except it +// finds an attribute of type |nid|, which should be one of the |NID_*| +// constants. +OPENSSL_EXPORT int X509_NAME_get_text_by_NID(const X509_NAME *name, int nid, + char *buf, int len); + // Private structures. @@ -900,10 +1165,6 @@ struct X509_algor_st { #define X509v3_KU_DECIPHER_ONLY 0x8000 #define X509v3_KU_UNDEF 0xffff -DEFINE_STACK_OF(X509_NAME_ENTRY) - -DEFINE_STACK_OF(X509_NAME) - typedef STACK_OF(X509_EXTENSION) X509_EXTENSIONS; DEFINE_STACK_OF(X509_EXTENSION) @@ -1269,13 +1530,6 @@ OPENSSL_EXPORT X509_REVOKED *X509_REVOKED_dup(X509_REVOKED *rev); OPENSSL_EXPORT X509_REQ *X509_REQ_dup(X509_REQ *req); OPENSSL_EXPORT X509_ALGOR *X509_ALGOR_dup(const X509_ALGOR *xn); -OPENSSL_EXPORT X509_NAME *X509_NAME_dup(X509_NAME *xn); -OPENSSL_EXPORT X509_NAME_ENTRY *X509_NAME_ENTRY_dup(const X509_NAME_ENTRY *ne); -OPENSSL_EXPORT int X509_NAME_ENTRY_set(const X509_NAME_ENTRY *ne); - -OPENSSL_EXPORT int X509_NAME_get0_der(X509_NAME *nm, const unsigned char **pder, - size_t *pderlen); - // X509_cmp_time compares |s| against |*t|. On success, it returns a negative // number if |s| <= |*t| and a positive number if |s| > |*t|. On error, it // returns zero. If |t| is NULL, it uses the current time instead of |*t|. @@ -1335,16 +1589,6 @@ OPENSSL_EXPORT X509_ATTRIBUTE *X509_ATTRIBUTE_create(int nid, int attrtype, DECLARE_ASN1_FUNCTIONS_const(X509_EXTENSION) DECLARE_ASN1_ENCODE_FUNCTIONS_const(X509_EXTENSIONS, X509_EXTENSIONS) -DECLARE_ASN1_FUNCTIONS_const(X509_NAME_ENTRY) - -// TODO(https://crbug.com/boringssl/407): This is not const because serializing -// an |X509_NAME| is sometimes not thread-safe. -DECLARE_ASN1_FUNCTIONS(X509_NAME) - -// X509_NAME_set makes a copy of |name|. On success, it frees |*xn|, sets |*xn| -// to the copy, and returns one. Otherwise, it returns zero. -OPENSSL_EXPORT int X509_NAME_set(X509_NAME **xn, X509_NAME *name); - OPENSSL_EXPORT int X509_add1_trust_object(X509 *x, ASN1_OBJECT *obj); OPENSSL_EXPORT int X509_add1_reject_object(X509 *x, ASN1_OBJECT *obj); OPENSSL_EXPORT void X509_trust_clear(X509 *x); @@ -1559,56 +1803,6 @@ OPENSSL_EXPORT int X509_REQ_print_ex(BIO *bp, X509_REQ *x, unsigned long nmflag, unsigned long cflag); OPENSSL_EXPORT int X509_REQ_print(BIO *bp, X509_REQ *req); -OPENSSL_EXPORT int X509_NAME_entry_count(const X509_NAME *name); -OPENSSL_EXPORT int X509_NAME_get_text_by_NID(const X509_NAME *name, int nid, - char *buf, int len); -OPENSSL_EXPORT int X509_NAME_get_text_by_OBJ(const X509_NAME *name, - const ASN1_OBJECT *obj, char *buf, - int len); - -// NOTE: you should be passsing -1, not 0 as lastpos. The functions that use -// lastpos, search after that position on. -OPENSSL_EXPORT int X509_NAME_get_index_by_NID(const X509_NAME *name, int nid, - int lastpos); -OPENSSL_EXPORT int X509_NAME_get_index_by_OBJ(const X509_NAME *name, - const ASN1_OBJECT *obj, - int lastpos); -OPENSSL_EXPORT X509_NAME_ENTRY *X509_NAME_get_entry(const X509_NAME *name, - int loc); -OPENSSL_EXPORT X509_NAME_ENTRY *X509_NAME_delete_entry(X509_NAME *name, - int loc); -OPENSSL_EXPORT int X509_NAME_add_entry(X509_NAME *name, X509_NAME_ENTRY *ne, - int loc, int set); -OPENSSL_EXPORT int X509_NAME_add_entry_by_OBJ(X509_NAME *name, ASN1_OBJECT *obj, - int type, - const unsigned char *bytes, - int len, int loc, int set); -OPENSSL_EXPORT int X509_NAME_add_entry_by_NID(X509_NAME *name, int nid, - int type, - const unsigned char *bytes, - int len, int loc, int set); -OPENSSL_EXPORT X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_txt( - X509_NAME_ENTRY **ne, const char *field, int type, - const unsigned char *bytes, int len); -OPENSSL_EXPORT X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_NID( - X509_NAME_ENTRY **ne, int nid, int type, const unsigned char *bytes, - int len); -OPENSSL_EXPORT int X509_NAME_add_entry_by_txt(X509_NAME *name, - const char *field, int type, - const unsigned char *bytes, - int len, int loc, int set); -OPENSSL_EXPORT X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_OBJ( - X509_NAME_ENTRY **ne, const ASN1_OBJECT *obj, int type, - const unsigned char *bytes, int len); -OPENSSL_EXPORT int X509_NAME_ENTRY_set_object(X509_NAME_ENTRY *ne, - const ASN1_OBJECT *obj); -OPENSSL_EXPORT int X509_NAME_ENTRY_set_data(X509_NAME_ENTRY *ne, int type, - const unsigned char *bytes, - int len); -OPENSSL_EXPORT ASN1_OBJECT *X509_NAME_ENTRY_get_object( - const X509_NAME_ENTRY *ne); -OPENSSL_EXPORT ASN1_STRING *X509_NAME_ENTRY_get_data(const X509_NAME_ENTRY *ne); - // X509v3_get_ext_count returns the number of extensions in |x|. OPENSSL_EXPORT int X509v3_get_ext_count(const STACK_OF(X509_EXTENSION) *x); @@ -1969,8 +2163,6 @@ OPENSSL_EXPORT int X509_ATTRIBUTE_set1_object(X509_ATTRIBUTE *attr, // |attr|'s type. If |len| is -1, |strlen(data)| is used instead. See // |ASN1_STRING_set_by_NID| for details. // -// TODO(davidben): Document |ASN1_STRING_set_by_NID| so the reference is useful. -// // Otherwise, if |len| is not -1, the value is an ASN.1 string. |attrtype| is an // |ASN1_STRING| type value and the |len| bytes from |data| are copied as the // type-specific representation of |ASN1_STRING|. See |ASN1_STRING| for details. From 0bfc9b32c4ec860dc46338d15320532c5e4496c8 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Sat, 9 Jul 2022 12:33:04 -0400 Subject: [PATCH 22/38] Unexport all low-level policy machinery. OpenSSL has a large exported API surface for exporting the policy tree out of an X509_STORE_CTX. As far as I can tell, no one uses any of these APIs. Remove them. Update-Note: It is no longer possibly to see the policy tree after an X.509 verification. As far as we can tell, this feature is unused. Change-Id: Ieab374774805e90106555ce4e4155f8451ceb5b9 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/53327 Reviewed-by: Bob Beck Commit-Queue: David Benjamin --- crypto/CMakeLists.txt | 1 - crypto/x509/internal.h | 3 + crypto/x509/x509_vfy.c | 11 +-- crypto/x509v3/internal.h | 24 +++++- crypto/x509v3/pcy_lib.c | 156 --------------------------------------- crypto/x509v3/pcy_tree.c | 8 +- include/openssl/base.h | 4 - include/openssl/x509.h | 36 --------- include/openssl/x509v3.h | 4 - 9 files changed, 32 insertions(+), 215 deletions(-) delete mode 100644 crypto/x509v3/pcy_lib.c diff --git a/crypto/CMakeLists.txt b/crypto/CMakeLists.txt index 80752d116d..0af3ea7df6 100644 --- a/crypto/CMakeLists.txt +++ b/crypto/CMakeLists.txt @@ -400,7 +400,6 @@ add_library( x509/x_x509a.c x509v3/pcy_cache.c x509v3/pcy_data.c - x509v3/pcy_lib.c x509v3/pcy_map.c x509v3/pcy_node.c x509v3/pcy_tree.c diff --git a/crypto/x509/internal.h b/crypto/x509/internal.h index 77f2d976c7..7904356304 100644 --- a/crypto/x509/internal.h +++ b/crypto/x509/internal.h @@ -72,6 +72,9 @@ extern "C" { // Internal structures. +typedef struct X509_POLICY_CACHE_st X509_POLICY_CACHE; +typedef struct X509_POLICY_TREE_st X509_POLICY_TREE; + typedef struct X509_val_st { ASN1_TIME *notBefore; ASN1_TIME *notAfter; diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c index 5a97353986..b45797af00 100644 --- a/crypto/x509/x509_vfy.c +++ b/crypto/x509/x509_vfy.c @@ -1710,6 +1710,9 @@ static int check_policy(X509_STORE_CTX *ctx) { if (ctx->parent) { return 1; } + // TODO(davidben): Historically, outputs of the |X509_policy_check| were saved + // on |ctx| and accessible via the public API. This has since been removed, so + // remove the fields from |X509_STORE_CTX|. ret = X509_policy_check(&ctx->tree, &ctx->explicit_policy, ctx->chain, ctx->param->policies, ctx->param->flags); if (ret == 0) { @@ -2406,14 +2409,6 @@ void X509_STORE_CTX_set_verify_cb(X509_STORE_CTX *ctx, ctx->verify_cb = verify_cb; } -X509_POLICY_TREE *X509_STORE_CTX_get0_policy_tree(X509_STORE_CTX *ctx) { - return ctx->tree; -} - -int X509_STORE_CTX_get_explicit_policy(X509_STORE_CTX *ctx) { - return ctx->explicit_policy; -} - int X509_STORE_CTX_set_default(X509_STORE_CTX *ctx, const char *name) { const X509_VERIFY_PARAM *param; param = X509_VERIFY_PARAM_lookup(name); diff --git a/crypto/x509v3/internal.h b/crypto/x509v3/internal.h index abace33fda..9c9c425408 100644 --- a/crypto/x509v3/internal.h +++ b/crypto/x509v3/internal.h @@ -65,6 +65,11 @@ #include #include +// TODO(davidben): Merge x509 and x509v3. This include is needed because some +// internal typedefs are shared between the two, but the two modules depend on +// each other circularly. +#include "../x509/internal.h" + #if defined(__cplusplus) extern "C" { #endif @@ -122,9 +127,6 @@ typedef struct { int x509V3_add_value_asn1_string(const char *name, const ASN1_STRING *value, STACK_OF(CONF_VALUE) **extlist); -typedef struct X509_POLICY_DATA_st X509_POLICY_DATA; - -DEFINE_STACK_OF(X509_POLICY_DATA) // Internal structures @@ -133,6 +135,12 @@ DEFINE_STACK_OF(X509_POLICY_DATA) // X509_POLICY_NODE contains that. This means that the main policy data can // be kept static and cached with the certificate. +typedef struct X509_POLICY_DATA_st X509_POLICY_DATA; +typedef struct X509_POLICY_LEVEL_st X509_POLICY_LEVEL; +typedef struct X509_POLICY_NODE_st X509_POLICY_NODE; + +DEFINE_STACK_OF(X509_POLICY_DATA) + struct X509_POLICY_DATA_st { unsigned int flags; // Policy OID and qualifiers for this data @@ -199,6 +207,8 @@ struct X509_POLICY_NODE_st { int nchild; }; +DEFINE_STACK_OF(X509_POLICY_NODE) + struct X509_POLICY_LEVEL_st { // Cert for this level X509 *cert; @@ -235,6 +245,14 @@ struct X509_POLICY_TREE_st { // Internal functions +void X509_POLICY_NODE_print(BIO *out, X509_POLICY_NODE *node, int indent); + +int X509_policy_check(X509_POLICY_TREE **ptree, int *pexplicit_policy, + STACK_OF(X509) *certs, STACK_OF(ASN1_OBJECT) *policy_oids, + unsigned int flags); + +void X509_policy_tree_free(X509_POLICY_TREE *tree); + X509_POLICY_DATA *policy_data_new(POLICYINFO *policy, const ASN1_OBJECT *id, int crit); void policy_data_free(X509_POLICY_DATA *data); diff --git a/crypto/x509v3/pcy_lib.c b/crypto/x509v3/pcy_lib.c deleted file mode 100644 index 9a629a3828..0000000000 --- a/crypto/x509v3/pcy_lib.c +++ /dev/null @@ -1,156 +0,0 @@ -/* pcy_lib.c */ -/* - * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project - * 2004. - */ -/* ==================================================================== - * Copyright (c) 2004 The OpenSSL Project. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" - * - * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For written permission, please contact - * licensing@OpenSSL.org. - * - * 5. Products derived from this software may not be called "OpenSSL" - * nor may "OpenSSL" appear in their names without prior written - * permission of the OpenSSL Project. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" - * - * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This product includes cryptographic software written by Eric Young - * (eay@cryptsoft.com). This product includes software written by Tim - * Hudson (tjh@cryptsoft.com). */ - -#include -#include - -#include "internal.h" - -// accessor functions - -// X509_POLICY_TREE stuff - -int X509_policy_tree_level_count(const X509_POLICY_TREE *tree) { - if (!tree) { - return 0; - } - return tree->nlevel; -} - -X509_POLICY_LEVEL *X509_policy_tree_get0_level(const X509_POLICY_TREE *tree, - int i) { - if (!tree || (i < 0) || (i >= tree->nlevel)) { - return NULL; - } - return tree->levels + i; -} - -STACK_OF(X509_POLICY_NODE) *X509_policy_tree_get0_policies( - const X509_POLICY_TREE *tree) { - if (!tree) { - return NULL; - } - return tree->auth_policies; -} - -STACK_OF(X509_POLICY_NODE) *X509_policy_tree_get0_user_policies( - const X509_POLICY_TREE *tree) { - if (!tree) { - return NULL; - } - if (tree->flags & POLICY_FLAG_ANY_POLICY) { - return tree->auth_policies; - } else { - return tree->user_policies; - } -} - -// X509_POLICY_LEVEL stuff - -int X509_policy_level_node_count(X509_POLICY_LEVEL *level) { - int n; - if (!level) { - return 0; - } - if (level->anyPolicy) { - n = 1; - } else { - n = 0; - } - if (level->nodes) { - n += sk_X509_POLICY_NODE_num(level->nodes); - } - return n; -} - -X509_POLICY_NODE *X509_policy_level_get0_node(X509_POLICY_LEVEL *level, int i) { - if (!level) { - return NULL; - } - if (level->anyPolicy) { - if (i == 0) { - return level->anyPolicy; - } - i--; - } - return sk_X509_POLICY_NODE_value(level->nodes, i); -} - -// X509_POLICY_NODE stuff - -const ASN1_OBJECT *X509_policy_node_get0_policy(const X509_POLICY_NODE *node) { - if (!node) { - return NULL; - } - return node->data->valid_policy; -} - -STACK_OF(POLICYQUALINFO) *X509_policy_node_get0_qualifiers( - const X509_POLICY_NODE *node) { - if (!node) { - return NULL; - } - return node->data->qualifier_set; -} - -const X509_POLICY_NODE *X509_policy_node_get0_parent( - const X509_POLICY_NODE *node) { - if (!node) { - return NULL; - } - return node->parent; -} diff --git a/crypto/x509v3/pcy_tree.c b/crypto/x509v3/pcy_tree.c index 673c615ba1..44ade30c53 100644 --- a/crypto/x509v3/pcy_tree.c +++ b/crypto/x509v3/pcy_tree.c @@ -811,7 +811,11 @@ int X509_policy_check(X509_POLICY_TREE **ptree, int *pexplicit_policy, } if (*pexplicit_policy) { - nodes = X509_policy_tree_get0_user_policies(tree); + if (tree->flags & POLICY_FLAG_ANY_POLICY) { + nodes = tree->auth_policies; + } else { + nodes = tree->user_policies; + } if (sk_X509_POLICY_NODE_num(nodes) <= 0) { return -2; } @@ -820,8 +824,6 @@ int X509_policy_check(X509_POLICY_TREE **ptree, int *pexplicit_policy, return 1; error: - X509_policy_tree_free(tree); - return 0; } diff --git a/include/openssl/base.h b/include/openssl/base.h index 7e58f00386..b74e66fa7e 100644 --- a/include/openssl/base.h +++ b/include/openssl/base.h @@ -364,10 +364,6 @@ typedef struct NAME_CONSTRAINTS_st NAME_CONSTRAINTS; typedef struct Netscape_spkac_st NETSCAPE_SPKAC; typedef struct Netscape_spki_st NETSCAPE_SPKI; typedef struct RIPEMD160state_st RIPEMD160_CTX; -typedef struct X509_POLICY_CACHE_st X509_POLICY_CACHE; -typedef struct X509_POLICY_LEVEL_st X509_POLICY_LEVEL; -typedef struct X509_POLICY_NODE_st X509_POLICY_NODE; -typedef struct X509_POLICY_TREE_st X509_POLICY_TREE; typedef struct X509_VERIFY_PARAM_st X509_VERIFY_PARAM; typedef struct X509_algor_st X509_ALGOR; typedef struct X509_crl_st X509_CRL; diff --git a/include/openssl/x509.h b/include/openssl/x509.h index 34eb840a3d..acb20f44e8 100644 --- a/include/openssl/x509.h +++ b/include/openssl/x509.h @@ -2660,10 +2660,6 @@ OPENSSL_EXPORT void X509_STORE_CTX_set_time(X509_STORE_CTX *ctx, OPENSSL_EXPORT void X509_STORE_CTX_set_verify_cb( X509_STORE_CTX *ctx, int (*verify_cb)(int, X509_STORE_CTX *)); -OPENSSL_EXPORT X509_POLICY_TREE *X509_STORE_CTX_get0_policy_tree( - X509_STORE_CTX *ctx); -OPENSSL_EXPORT int X509_STORE_CTX_get_explicit_policy(X509_STORE_CTX *ctx); - OPENSSL_EXPORT X509_VERIFY_PARAM *X509_STORE_CTX_get0_param( X509_STORE_CTX *ctx); OPENSSL_EXPORT void X509_STORE_CTX_set0_param(X509_STORE_CTX *ctx, @@ -2729,37 +2725,6 @@ OPENSSL_EXPORT const X509_VERIFY_PARAM *X509_VERIFY_PARAM_lookup( const char *name); OPENSSL_EXPORT void X509_VERIFY_PARAM_table_cleanup(void); -OPENSSL_EXPORT int X509_policy_check(X509_POLICY_TREE **ptree, - int *pexplicit_policy, - STACK_OF(X509) *certs, - STACK_OF(ASN1_OBJECT) *policy_oids, - unsigned int flags); - -OPENSSL_EXPORT void X509_policy_tree_free(X509_POLICY_TREE *tree); - -OPENSSL_EXPORT int X509_policy_tree_level_count(const X509_POLICY_TREE *tree); -OPENSSL_EXPORT X509_POLICY_LEVEL *X509_policy_tree_get0_level( - const X509_POLICY_TREE *tree, int i); - -OPENSSL_EXPORT STACK_OF(X509_POLICY_NODE) *X509_policy_tree_get0_policies( - const X509_POLICY_TREE *tree); - -OPENSSL_EXPORT STACK_OF(X509_POLICY_NODE) *X509_policy_tree_get0_user_policies( - const X509_POLICY_TREE *tree); - -OPENSSL_EXPORT int X509_policy_level_node_count(X509_POLICY_LEVEL *level); - -OPENSSL_EXPORT X509_POLICY_NODE *X509_policy_level_get0_node( - X509_POLICY_LEVEL *level, int i); - -OPENSSL_EXPORT const ASN1_OBJECT *X509_policy_node_get0_policy( - const X509_POLICY_NODE *node); - -OPENSSL_EXPORT STACK_OF(POLICYQUALINFO) *X509_policy_node_get0_qualifiers( - const X509_POLICY_NODE *node); -OPENSSL_EXPORT const X509_POLICY_NODE *X509_policy_node_get0_parent( - const X509_POLICY_NODE *node); - #if defined(__cplusplus) } // extern C @@ -2784,7 +2749,6 @@ BORINGSSL_MAKE_DELETER(X509_LOOKUP, X509_LOOKUP_free) BORINGSSL_MAKE_DELETER(X509_NAME, X509_NAME_free) BORINGSSL_MAKE_DELETER(X509_NAME_ENTRY, X509_NAME_ENTRY_free) BORINGSSL_MAKE_DELETER(X509_PKEY, X509_PKEY_free) -BORINGSSL_MAKE_DELETER(X509_POLICY_TREE, X509_policy_tree_free) BORINGSSL_MAKE_DELETER(X509_PUBKEY, X509_PUBKEY_free) BORINGSSL_MAKE_DELETER(X509_REQ, X509_REQ_free) BORINGSSL_MAKE_DELETER(X509_REVOKED, X509_REVOKED_free) diff --git a/include/openssl/x509v3.h b/include/openssl/x509v3.h index 0ae96137da..38c72cd2bd 100644 --- a/include/openssl/x509v3.h +++ b/include/openssl/x509v3.h @@ -906,10 +906,6 @@ OPENSSL_EXPORT int X509V3_NAME_from_section(X509_NAME *nm, STACK_OF(CONF_VALUE) *dn_sk, unsigned long chtype); -OPENSSL_EXPORT void X509_POLICY_NODE_print(BIO *out, X509_POLICY_NODE *node, - int indent); -DEFINE_STACK_OF(X509_POLICY_NODE) - // BEGIN ERROR CODES // The following lines are auto generated by the script mkerr.pl. Any changes // made after this point may be overwritten when the script is next run. From 6bf129213fc02cf7be5710fb7b5e94ffc0637b39 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Sat, 9 Jul 2022 14:55:59 -0400 Subject: [PATCH 23/38] Remove X509_ocspid_print. This was originally added for the openssl command-line utility and otherwise is not very useful. I found no callers, so drop it. Update-Note: An unused function was removed. Change-Id: I12aa314fd3d8f1dad79eb5a07e0dea662dd9b4a8 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/53328 Reviewed-by: Bob Beck Commit-Queue: David Benjamin --- crypto/x509/t_x509.c | 53 ------------------------------------------ include/openssl/x509.h | 1 - 2 files changed, 54 deletions(-) diff --git a/crypto/x509/t_x509.c b/crypto/x509/t_x509.c index 4db682d9fa..6694e3d127 100644 --- a/crypto/x509/t_x509.c +++ b/crypto/x509/t_x509.c @@ -269,59 +269,6 @@ int X509_print_ex(BIO *bp, X509 *x, unsigned long nmflags, return ret; } -int X509_ocspid_print(BIO *bp, X509 *x) { - unsigned char *der = NULL; - unsigned char *dertmp; - int derlen; - int i; - unsigned char SHA1md[SHA_DIGEST_LENGTH]; - - // display the hash of the subject as it would appear in OCSP requests - if (BIO_printf(bp, " Subject OCSP hash: ") <= 0) { - goto err; - } - derlen = i2d_X509_NAME(x->cert_info->subject, NULL); - if ((der = dertmp = (unsigned char *)OPENSSL_malloc(derlen)) == NULL) { - goto err; - } - i2d_X509_NAME(x->cert_info->subject, &dertmp); - - if (!EVP_Digest(der, derlen, SHA1md, NULL, EVP_sha1(), NULL)) { - goto err; - } - for (i = 0; i < SHA_DIGEST_LENGTH; i++) { - if (BIO_printf(bp, "%02X", SHA1md[i]) <= 0) { - goto err; - } - } - OPENSSL_free(der); - der = NULL; - - // display the hash of the public key as it would appear in OCSP requests - if (BIO_printf(bp, "\n Public key OCSP hash: ") <= 0) { - goto err; - } - - if (!EVP_Digest(x->cert_info->key->public_key->data, - x->cert_info->key->public_key->length, SHA1md, NULL, - EVP_sha1(), NULL)) { - goto err; - } - for (i = 0; i < SHA_DIGEST_LENGTH; i++) { - if (BIO_printf(bp, "%02X", SHA1md[i]) <= 0) { - goto err; - } - } - BIO_printf(bp, "\n"); - - return 1; -err: - if (der != NULL) { - OPENSSL_free(der); - } - return 0; -} - int X509_signature_print(BIO *bp, const X509_ALGOR *sigalg, const ASN1_STRING *sig) { if (BIO_puts(bp, " Signature Algorithm: ") <= 0) { diff --git a/include/openssl/x509.h b/include/openssl/x509.h index acb20f44e8..069df2655c 100644 --- a/include/openssl/x509.h +++ b/include/openssl/x509.h @@ -1797,7 +1797,6 @@ OPENSSL_EXPORT int X509_NAME_print_ex(BIO *out, const X509_NAME *nm, int indent, OPENSSL_EXPORT int X509_print_ex(BIO *bp, X509 *x, unsigned long nmflag, unsigned long cflag); OPENSSL_EXPORT int X509_print(BIO *bp, X509 *x); -OPENSSL_EXPORT int X509_ocspid_print(BIO *bp, X509 *x); OPENSSL_EXPORT int X509_CRL_print(BIO *bp, X509_CRL *x); OPENSSL_EXPORT int X509_REQ_print_ex(BIO *bp, X509_REQ *x, unsigned long nmflag, unsigned long cflag); From 81587d369990f1f07f9d821c0c27f74adbaa8482 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Sat, 9 Jul 2022 15:04:08 -0400 Subject: [PATCH 24/38] Remove the last of the Suite B code. Update-Note: Suite B flags in the X.509 stack are no longer supported. This isn't expected to affect anything but bindings wrapping unused options. Change-Id: Ia0770e545d34e041ab995e80ea11b4dd4a5e47ef Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/53329 Reviewed-by: Bob Beck Commit-Queue: David Benjamin --- crypto/x509/x509_cmp.c | 121 ----------------------------------------- crypto/x509/x509_txt.c | 13 ----- crypto/x509/x509_vfy.c | 20 ------- include/openssl/x509.h | 19 ------- 4 files changed, 173 deletions(-) diff --git a/crypto/x509/x509_cmp.c b/crypto/x509/x509_cmp.c index b98190d2b9..9105b2f492 100644 --- a/crypto/x509/x509_cmp.c +++ b/crypto/x509/x509_cmp.c @@ -305,127 +305,6 @@ int X509_check_private_key(X509 *x, const EVP_PKEY *k) { return 0; } -// Check a suite B algorithm is permitted: pass in a public key and the NID -// of its signature (or 0 if no signature). The pflags is a pointer to a -// flags field which must contain the suite B verification flags. - -static int check_suite_b(EVP_PKEY *pkey, int sign_nid, unsigned long *pflags) { - const EC_GROUP *grp = NULL; - int curve_nid; - if (pkey && pkey->type == EVP_PKEY_EC) { - grp = EC_KEY_get0_group(pkey->pkey.ec); - } - if (!grp) { - return X509_V_ERR_SUITE_B_INVALID_ALGORITHM; - } - curve_nid = EC_GROUP_get_curve_name(grp); - // Check curve is consistent with LOS - if (curve_nid == NID_secp384r1) { // P-384 - // Check signature algorithm is consistent with curve. - if (sign_nid != -1 && sign_nid != NID_ecdsa_with_SHA384) { - return X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM; - } - if (!(*pflags & X509_V_FLAG_SUITEB_192_LOS)) { - return X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED; - } - // If we encounter P-384 we cannot use P-256 later - *pflags &= ~X509_V_FLAG_SUITEB_128_LOS_ONLY; - } else if (curve_nid == NID_X9_62_prime256v1) { // P-256 - if (sign_nid != -1 && sign_nid != NID_ecdsa_with_SHA256) { - return X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM; - } - if (!(*pflags & X509_V_FLAG_SUITEB_128_LOS_ONLY)) { - return X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED; - } - } else { - return X509_V_ERR_SUITE_B_INVALID_CURVE; - } - - return X509_V_OK; -} - -int X509_chain_check_suiteb(int *perror_depth, X509 *x, STACK_OF(X509) *chain, - unsigned long flags) { - int rv, sign_nid; - size_t i; - EVP_PKEY *pk = NULL; - unsigned long tflags; - if (!(flags & X509_V_FLAG_SUITEB_128_LOS)) { - return X509_V_OK; - } - tflags = flags; - // If no EE certificate passed in must be first in chain - if (x == NULL) { - x = sk_X509_value(chain, 0); - i = 1; - } else { - i = 0; - } - - if (X509_get_version(x) != X509_VERSION_3) { - rv = X509_V_ERR_SUITE_B_INVALID_VERSION; - // Correct error depth - i = 0; - goto end; - } - - pk = X509_get_pubkey(x); - // Check EE key only - rv = check_suite_b(pk, -1, &tflags); - if (rv != X509_V_OK) { - // Correct error depth - i = 0; - goto end; - } - for (; i < sk_X509_num(chain); i++) { - sign_nid = X509_get_signature_nid(x); - x = sk_X509_value(chain, i); - if (X509_get_version(x) != X509_VERSION_3) { - rv = X509_V_ERR_SUITE_B_INVALID_VERSION; - goto end; - } - EVP_PKEY_free(pk); - pk = X509_get_pubkey(x); - rv = check_suite_b(pk, sign_nid, &tflags); - if (rv != X509_V_OK) { - goto end; - } - } - - // Final check: root CA signature - rv = check_suite_b(pk, X509_get_signature_nid(x), &tflags); -end: - if (pk) { - EVP_PKEY_free(pk); - } - if (rv != X509_V_OK) { - // Invalid signature or LOS errors are for previous cert - if ((rv == X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM || - rv == X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED) && - i) { - i--; - } - // If we have LOS error and flags changed then we are signing P-384 - // with P-256. Use more meaninggul error. - if (rv == X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED && flags != tflags) { - rv = X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256; - } - if (perror_depth) { - *perror_depth = i; - } - } - return rv; -} - -int X509_CRL_check_suiteb(X509_CRL *crl, EVP_PKEY *pk, unsigned long flags) { - int sign_nid; - if (!(flags & X509_V_FLAG_SUITEB_128_LOS)) { - return X509_V_OK; - } - sign_nid = OBJ_obj2nid(crl->crl->sig_alg->algorithm); - return check_suite_b(pk, sign_nid, &flags); -} - // Not strictly speaking an "up_ref" as a STACK doesn't have a reference // count but it has the same effect by duping the STACK and upping the ref of // each X509 structure. diff --git a/crypto/x509/x509_txt.c b/crypto/x509/x509_txt.c index 16768bf3fd..45e8322bda 100644 --- a/crypto/x509/x509_txt.c +++ b/crypto/x509/x509_txt.c @@ -168,19 +168,6 @@ const char *X509_verify_cert_error_string(long err) { case X509_V_ERR_CRL_PATH_VALIDATION_ERROR: return "CRL path validation error"; - case X509_V_ERR_SUITE_B_INVALID_VERSION: - return "Suite B: certificate version invalid"; - case X509_V_ERR_SUITE_B_INVALID_ALGORITHM: - return "Suite B: invalid public key algorithm"; - case X509_V_ERR_SUITE_B_INVALID_CURVE: - return "Suite B: invalid ECC curve"; - case X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM: - return "Suite B: invalid signature algorithm"; - case X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED: - return "Suite B: curve not allowed for this LOS"; - case X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256: - return "Suite B: cannot sign P-384 with P-256"; - case X509_V_ERR_HOSTNAME_MISMATCH: return "Hostname mismatch"; case X509_V_ERR_EMAIL_MISMATCH: diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c index b45797af00..2e5a3c622e 100644 --- a/crypto/x509/x509_vfy.c +++ b/crypto/x509/x509_vfy.c @@ -457,17 +457,6 @@ int X509_verify_cert(X509_STORE_CTX *ctx) { goto end; } - int err = X509_chain_check_suiteb(&ctx->error_depth, NULL, ctx->chain, - ctx->param->flags); - if (err != X509_V_OK) { - ctx->error = err; - ctx->current_cert = sk_X509_value(ctx->chain, ctx->error_depth); - ok = ctx->verify_cb(0, ctx); - if (!ok) { - goto end; - } - } - // At this point, we have a chain and need to verify it if (ctx->verify != NULL) { ok = ctx->verify(ctx); @@ -1646,15 +1635,6 @@ static int check_crl(X509_STORE_CTX *ctx, X509_CRL *crl) { goto err; } } else { - int rv; - rv = X509_CRL_check_suiteb(crl, ikey, ctx->param->flags); - if (rv != X509_V_OK) { - ctx->error = rv; - ok = ctx->verify_cb(0, ctx); - if (!ok) { - goto err; - } - } // Verify CRL signature if (X509_CRL_verify(crl, ikey) <= 0) { ctx->error = X509_V_ERR_CRL_SIGNATURE_FAILURE; diff --git a/include/openssl/x509.h b/include/openssl/x509.h index 069df2655c..b9e6ab4f97 100644 --- a/include/openssl/x509.h +++ b/include/openssl/x509.h @@ -1759,11 +1759,6 @@ OPENSSL_EXPORT X509_CRL *X509_CRL_diff(X509_CRL *base, X509_CRL *newer, OPENSSL_EXPORT int X509_REQ_check_private_key(X509_REQ *x509, EVP_PKEY *pkey); OPENSSL_EXPORT int X509_check_private_key(X509 *x509, const EVP_PKEY *pkey); -OPENSSL_EXPORT int X509_chain_check_suiteb(int *perror_depth, X509 *x, - STACK_OF(X509) *chain, - unsigned long flags); -OPENSSL_EXPORT int X509_CRL_check_suiteb(X509_CRL *crl, EVP_PKEY *pk, - unsigned long flags); OPENSSL_EXPORT int X509_issuer_and_serial_cmp(const X509 *a, const X509 *b); @@ -2410,14 +2405,6 @@ OPENSSL_EXPORT void X509_STORE_CTX_set_depth(X509_STORE_CTX *ctx, int depth); #define X509_V_ERR_UNSUPPORTED_NAME_SYNTAX 53 #define X509_V_ERR_CRL_PATH_VALIDATION_ERROR 54 -// Suite B mode algorithm violation -#define X509_V_ERR_SUITE_B_INVALID_VERSION 56 -#define X509_V_ERR_SUITE_B_INVALID_ALGORITHM 57 -#define X509_V_ERR_SUITE_B_INVALID_CURVE 58 -#define X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM 59 -#define X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED 60 -#define X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256 61 - // Host, email and IP check errors #define X509_V_ERR_HOSTNAME_MISMATCH 62 #define X509_V_ERR_EMAIL_MISMATCH 63 @@ -2464,12 +2451,6 @@ OPENSSL_EXPORT void X509_STORE_CTX_set_depth(X509_STORE_CTX *ctx, int depth); #define X509_V_FLAG_CHECK_SS_SIGNATURE 0x4000 // Use trusted store first #define X509_V_FLAG_TRUSTED_FIRST 0x8000 -// Suite B 128 bit only mode: not normally used -#define X509_V_FLAG_SUITEB_128_LOS_ONLY 0x10000 -// Suite B 192 bit only mode -#define X509_V_FLAG_SUITEB_192_LOS 0x20000 -// Suite B 128 bit mode allowing 192 bit algorithms -#define X509_V_FLAG_SUITEB_128_LOS 0x30000 // Allow partial chains if at least one certificate is in trusted store #define X509_V_FLAG_PARTIAL_CHAIN 0x80000 From 1b5899510d7a352211a67f8d2aa001bcab495d3c Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Sat, 9 Jul 2022 15:22:13 -0400 Subject: [PATCH 25/38] Fix the documentation of X509_pubkey_digest. It doesn't hash the SPKI, just the BIT STRING in it. Bug: 426 Change-Id: Ib5b8f14f530cc8045a60ac1e9780779d90f5a3bf Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/53330 Commit-Queue: Bob Beck Commit-Queue: David Benjamin Reviewed-by: Bob Beck --- include/openssl/x509.h | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/include/openssl/x509.h b/include/openssl/x509.h index b9e6ab4f97..58e4c4d504 100644 --- a/include/openssl/x509.h +++ b/include/openssl/x509.h @@ -1412,11 +1412,16 @@ OPENSSL_EXPORT int NETSCAPE_SPKI_set_pubkey(NETSCAPE_SPKI *spki, OPENSSL_EXPORT int NETSCAPE_SPKI_sign(NETSCAPE_SPKI *spki, EVP_PKEY *pkey, const EVP_MD *md); -// X509_pubkey_digest hashes the DER encoding of |x509|'s subjectPublicKeyInfo -// field with |md| and writes the result to |out|. |EVP_MD_CTX_size| bytes are -// written, which is at most |EVP_MAX_MD_SIZE|. If |out_len| is not NULL, -// |*out_len| is set to the number of bytes written. This function returns one -// on success and zero on error. +// X509_pubkey_digest hashes the contents of the BIT STRING in |x509|'s +// subjectPublicKeyInfo field with |md| and writes the result to |out|. +// |EVP_MD_CTX_size| bytes are written, which is at most |EVP_MAX_MD_SIZE|. If +// |out_len| is not NULL, |*out_len| is set to the number of bytes written. This +// function returns one on success and zero on error. +// +// This hash omits the BIT STRING tag, length, and number of unused bits. It +// also omits the AlgorithmIdentifier which describes the key type. It +// corresponds to the OCSP KeyHash definition and is not suitable for other +// purposes. OPENSSL_EXPORT int X509_pubkey_digest(const X509 *x509, const EVP_MD *md, uint8_t *out, unsigned *out_len); From 918b8bcbbef85feed8fd1aebd06cdc92f30c743d Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Sat, 9 Jul 2022 15:33:19 -0400 Subject: [PATCH 26/38] Move all the miscelleneous convenience functions into a section. There's a lot of these, so toss them into a corner somewhere. I've added a note to note to discourage using them with memory BIOs. Memory BIOs are, by far, the most common use I've seen for i2d_*_bio and d2i_*_bio. It works, but it's unnecessary. Bug: 426 Change-Id: I8645207a4ac9f1223d0739b5351c99a55400195f Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/53331 Commit-Queue: Bob Beck Commit-Queue: David Benjamin Reviewed-by: Bob Beck --- crypto/x509/x_all.c | 2 - include/openssl/x509.h | 250 ++++++++++++++++++++++------------------- 2 files changed, 135 insertions(+), 117 deletions(-) diff --git a/crypto/x509/x_all.c b/crypto/x509/x_all.c index ad92df1524..bad9ce6221 100644 --- a/crypto/x509/x_all.c +++ b/crypto/x509/x_all.c @@ -241,7 +241,6 @@ IMPLEMENT_I2D_BIO(RSA, i2d_RSAPublicKey_bio, i2d_RSAPublicKey) IMPLEMENT_D2I_BIO(RSA, d2i_RSA_PUBKEY_bio, d2i_RSA_PUBKEY) IMPLEMENT_I2D_BIO(RSA, i2d_RSA_PUBKEY_bio, i2d_RSA_PUBKEY) -#ifndef OPENSSL_NO_DSA IMPLEMENT_D2I_FP(DSA, d2i_DSAPrivateKey_fp, d2i_DSAPrivateKey_bio) IMPLEMENT_I2D_FP(DSA, i2d_DSAPrivateKey_fp, i2d_DSAPrivateKey_bio) @@ -253,7 +252,6 @@ IMPLEMENT_I2D_BIO(DSA, i2d_DSAPrivateKey_bio, i2d_DSAPrivateKey) IMPLEMENT_D2I_BIO(DSA, d2i_DSA_PUBKEY_bio, d2i_DSA_PUBKEY) IMPLEMENT_I2D_BIO(DSA, i2d_DSA_PUBKEY_bio, i2d_DSA_PUBKEY) -#endif IMPLEMENT_D2I_FP(EC_KEY, d2i_ECPrivateKey_fp, d2i_ECPrivateKey_bio) IMPLEMENT_I2D_FP(EC_KEY, i2d_ECPrivateKey_fp, i2d_ECPrivateKey_bio) diff --git a/include/openssl/x509.h b/include/openssl/x509.h index 58e4c4d504..6c3d978018 100644 --- a/include/openssl/x509.h +++ b/include/openssl/x509.h @@ -1045,6 +1045,141 @@ OPENSSL_EXPORT int X509_signature_print(BIO *bio, const X509_ALGOR *alg, const ASN1_STRING *sig); +// Convenience functions. + +// X509_pubkey_digest hashes the contents of the BIT STRING in |x509|'s +// subjectPublicKeyInfo field with |md| and writes the result to |out|. +// |EVP_MD_CTX_size| bytes are written, which is at most |EVP_MAX_MD_SIZE|. If +// |out_len| is not NULL, |*out_len| is set to the number of bytes written. This +// function returns one on success and zero on error. +// +// This hash omits the BIT STRING tag, length, and number of unused bits. It +// also omits the AlgorithmIdentifier which describes the key type. It +// corresponds to the OCSP KeyHash definition and is not suitable for other +// purposes. +OPENSSL_EXPORT int X509_pubkey_digest(const X509 *x509, const EVP_MD *md, + uint8_t *out, unsigned *out_len); + +// X509_digest hashes |x509|'s DER encoding with |md| and writes the result to +// |out|. |EVP_MD_CTX_size| bytes are written, which is at most +// |EVP_MAX_MD_SIZE|. If |out_len| is not NULL, |*out_len| is set to the number +// of bytes written. This function returns one on success and zero on error. +// Note this digest covers the entire certificate, not just the signed portion. +OPENSSL_EXPORT int X509_digest(const X509 *x509, const EVP_MD *md, uint8_t *out, + unsigned *out_len); + +// X509_CRL_digest hashes |crl|'s DER encoding with |md| and writes the result +// to |out|. |EVP_MD_CTX_size| bytes are written, which is at most +// |EVP_MAX_MD_SIZE|. If |out_len| is not NULL, |*out_len| is set to the number +// of bytes written. This function returns one on success and zero on error. +// Note this digest covers the entire CRL, not just the signed portion. +OPENSSL_EXPORT int X509_CRL_digest(const X509_CRL *crl, const EVP_MD *md, + uint8_t *out, unsigned *out_len); + +// X509_REQ_digest hashes |req|'s DER encoding with |md| and writes the result +// to |out|. |EVP_MD_CTX_size| bytes are written, which is at most +// |EVP_MAX_MD_SIZE|. If |out_len| is not NULL, |*out_len| is set to the number +// of bytes written. This function returns one on success and zero on error. +// Note this digest covers the entire certificate request, not just the signed +// portion. +OPENSSL_EXPORT int X509_REQ_digest(const X509_REQ *req, const EVP_MD *md, + uint8_t *out, unsigned *out_len); + +// X509_NAME_digest hashes |name|'s DER encoding with |md| and writes the result +// to |out|. |EVP_MD_CTX_size| bytes are written, which is at most +// |EVP_MAX_MD_SIZE|. If |out_len| is not NULL, |*out_len| is set to the number +// of bytes written. This function returns one on success and zero on error. +OPENSSL_EXPORT int X509_NAME_digest(const X509_NAME *name, const EVP_MD *md, + uint8_t *out, unsigned *out_len); + +// The following functions behave like the corresponding unsuffixed |d2i_*| +// functions, but read the result from |bp| instead. Callers using these +// functions with memory |BIO|s to parse structures already in memory should use +// |d2i_*| instead. +OPENSSL_EXPORT X509 *d2i_X509_bio(BIO *bp, X509 **x509); +OPENSSL_EXPORT X509_CRL *d2i_X509_CRL_bio(BIO *bp, X509_CRL **crl); +OPENSSL_EXPORT X509_REQ *d2i_X509_REQ_bio(BIO *bp, X509_REQ **req); +OPENSSL_EXPORT RSA *d2i_RSAPrivateKey_bio(BIO *bp, RSA **rsa); +OPENSSL_EXPORT RSA *d2i_RSAPublicKey_bio(BIO *bp, RSA **rsa); +OPENSSL_EXPORT RSA *d2i_RSA_PUBKEY_bio(BIO *bp, RSA **rsa); +OPENSSL_EXPORT DSA *d2i_DSA_PUBKEY_bio(BIO *bp, DSA **dsa); +OPENSSL_EXPORT DSA *d2i_DSAPrivateKey_bio(BIO *bp, DSA **dsa); +OPENSSL_EXPORT EC_KEY *d2i_EC_PUBKEY_bio(BIO *bp, EC_KEY **eckey); +OPENSSL_EXPORT EC_KEY *d2i_ECPrivateKey_bio(BIO *bp, EC_KEY **eckey); +OPENSSL_EXPORT X509_SIG *d2i_PKCS8_bio(BIO *bp, X509_SIG **p8); +OPENSSL_EXPORT PKCS8_PRIV_KEY_INFO *d2i_PKCS8_PRIV_KEY_INFO_bio( + BIO *bp, PKCS8_PRIV_KEY_INFO **p8inf); +OPENSSL_EXPORT EVP_PKEY *d2i_PUBKEY_bio(BIO *bp, EVP_PKEY **a); +OPENSSL_EXPORT DH *d2i_DHparams_bio(BIO *bp, DH **dh); + +// d2i_PrivateKey_bio behaves like |d2i_AutoPrivateKey|, but reads from |bp| +// instead. +OPENSSL_EXPORT EVP_PKEY *d2i_PrivateKey_bio(BIO *bp, EVP_PKEY **a); + +// The following functions behave like the corresponding unsuffixed |i2d_*| +// functions, but write the result to |bp|. They return one on success and zero +// on error. Callers using them with memory |BIO|s to encode structures to +// memory should use |i2d_*| directly instead. +OPENSSL_EXPORT int i2d_X509_bio(BIO *bp, X509 *x509); +OPENSSL_EXPORT int i2d_X509_CRL_bio(BIO *bp, X509_CRL *crl); +OPENSSL_EXPORT int i2d_X509_REQ_bio(BIO *bp, X509_REQ *req); +OPENSSL_EXPORT int i2d_RSAPrivateKey_bio(BIO *bp, RSA *rsa); +OPENSSL_EXPORT int i2d_RSAPublicKey_bio(BIO *bp, RSA *rsa); +OPENSSL_EXPORT int i2d_RSA_PUBKEY_bio(BIO *bp, RSA *rsa); +OPENSSL_EXPORT int i2d_DSA_PUBKEY_bio(BIO *bp, DSA *dsa); +OPENSSL_EXPORT int i2d_DSAPrivateKey_bio(BIO *bp, DSA *dsa); +OPENSSL_EXPORT int i2d_EC_PUBKEY_bio(BIO *bp, EC_KEY *eckey); +OPENSSL_EXPORT int i2d_ECPrivateKey_bio(BIO *bp, EC_KEY *eckey); +OPENSSL_EXPORT int i2d_PKCS8_bio(BIO *bp, X509_SIG *p8); +OPENSSL_EXPORT int i2d_PKCS8_PRIV_KEY_INFO_bio(BIO *bp, + PKCS8_PRIV_KEY_INFO *p8inf); +OPENSSL_EXPORT int i2d_PrivateKey_bio(BIO *bp, EVP_PKEY *pkey); +OPENSSL_EXPORT int i2d_PUBKEY_bio(BIO *bp, EVP_PKEY *pkey); +OPENSSL_EXPORT int i2d_DHparams_bio(BIO *bp, const DH *dh); + +// i2d_PKCS8PrivateKeyInfo_bio encodes |key| as a PKCS#8 PrivateKeyInfo +// structure (see |EVP_marshal_private_key|) and writes the result to |bp|. It +// returns one on success and zero on error. +OPENSSL_EXPORT int i2d_PKCS8PrivateKeyInfo_bio(BIO *bp, EVP_PKEY *key); + +// The following functions behave like the corresponding |d2i_*_bio| functions, +// but read from |fp| instead. +OPENSSL_EXPORT X509 *d2i_X509_fp(FILE *fp, X509 **x509); +OPENSSL_EXPORT X509_CRL *d2i_X509_CRL_fp(FILE *fp, X509_CRL **crl); +OPENSSL_EXPORT X509_REQ *d2i_X509_REQ_fp(FILE *fp, X509_REQ **req); +OPENSSL_EXPORT RSA *d2i_RSAPrivateKey_fp(FILE *fp, RSA **rsa); +OPENSSL_EXPORT RSA *d2i_RSAPublicKey_fp(FILE *fp, RSA **rsa); +OPENSSL_EXPORT RSA *d2i_RSA_PUBKEY_fp(FILE *fp, RSA **rsa); +OPENSSL_EXPORT DSA *d2i_DSA_PUBKEY_fp(FILE *fp, DSA **dsa); +OPENSSL_EXPORT DSA *d2i_DSAPrivateKey_fp(FILE *fp, DSA **dsa); +OPENSSL_EXPORT EC_KEY *d2i_EC_PUBKEY_fp(FILE *fp, EC_KEY **eckey); +OPENSSL_EXPORT EC_KEY *d2i_ECPrivateKey_fp(FILE *fp, EC_KEY **eckey); +OPENSSL_EXPORT X509_SIG *d2i_PKCS8_fp(FILE *fp, X509_SIG **p8); +OPENSSL_EXPORT PKCS8_PRIV_KEY_INFO *d2i_PKCS8_PRIV_KEY_INFO_fp( + FILE *fp, PKCS8_PRIV_KEY_INFO **p8inf); +OPENSSL_EXPORT EVP_PKEY *d2i_PrivateKey_fp(FILE *fp, EVP_PKEY **a); +OPENSSL_EXPORT EVP_PKEY *d2i_PUBKEY_fp(FILE *fp, EVP_PKEY **a); + +// The following functions behave like the corresponding |i2d_*_bio| functions, +// but write to |fp| instead. +OPENSSL_EXPORT int i2d_X509_fp(FILE *fp, X509 *x509); +OPENSSL_EXPORT int i2d_X509_CRL_fp(FILE *fp, X509_CRL *crl); +OPENSSL_EXPORT int i2d_X509_REQ_fp(FILE *fp, X509_REQ *req); +OPENSSL_EXPORT int i2d_RSAPrivateKey_fp(FILE *fp, RSA *rsa); +OPENSSL_EXPORT int i2d_RSAPublicKey_fp(FILE *fp, RSA *rsa); +OPENSSL_EXPORT int i2d_RSA_PUBKEY_fp(FILE *fp, RSA *rsa); +OPENSSL_EXPORT int i2d_DSA_PUBKEY_fp(FILE *fp, DSA *dsa); +OPENSSL_EXPORT int i2d_DSAPrivateKey_fp(FILE *fp, DSA *dsa); +OPENSSL_EXPORT int i2d_EC_PUBKEY_fp(FILE *fp, EC_KEY *eckey); +OPENSSL_EXPORT int i2d_ECPrivateKey_fp(FILE *fp, EC_KEY *eckey); +OPENSSL_EXPORT int i2d_PKCS8_fp(FILE *fp, X509_SIG *p8); +OPENSSL_EXPORT int i2d_PKCS8_PRIV_KEY_INFO_fp(FILE *fp, + PKCS8_PRIV_KEY_INFO *p8inf); +OPENSSL_EXPORT int i2d_PKCS8PrivateKeyInfo_fp(FILE *fp, EVP_PKEY *key); +OPENSSL_EXPORT int i2d_PrivateKey_fp(FILE *fp, EVP_PKEY *pkey); +OPENSSL_EXPORT int i2d_PUBKEY_fp(FILE *fp, EVP_PKEY *pkey); + + // ex_data functions. // // See |ex_data.h| for details. @@ -1412,121 +1547,6 @@ OPENSSL_EXPORT int NETSCAPE_SPKI_set_pubkey(NETSCAPE_SPKI *spki, OPENSSL_EXPORT int NETSCAPE_SPKI_sign(NETSCAPE_SPKI *spki, EVP_PKEY *pkey, const EVP_MD *md); -// X509_pubkey_digest hashes the contents of the BIT STRING in |x509|'s -// subjectPublicKeyInfo field with |md| and writes the result to |out|. -// |EVP_MD_CTX_size| bytes are written, which is at most |EVP_MAX_MD_SIZE|. If -// |out_len| is not NULL, |*out_len| is set to the number of bytes written. This -// function returns one on success and zero on error. -// -// This hash omits the BIT STRING tag, length, and number of unused bits. It -// also omits the AlgorithmIdentifier which describes the key type. It -// corresponds to the OCSP KeyHash definition and is not suitable for other -// purposes. -OPENSSL_EXPORT int X509_pubkey_digest(const X509 *x509, const EVP_MD *md, - uint8_t *out, unsigned *out_len); - -// X509_digest hashes |x509|'s DER encoding with |md| and writes the result to -// |out|. |EVP_MD_CTX_size| bytes are written, which is at most -// |EVP_MAX_MD_SIZE|. If |out_len| is not NULL, |*out_len| is set to the number -// of bytes written. This function returns one on success and zero on error. -// Note this digest covers the entire certificate, not just the signed portion. -OPENSSL_EXPORT int X509_digest(const X509 *x509, const EVP_MD *md, uint8_t *out, - unsigned *out_len); - -// X509_CRL_digest hashes |crl|'s DER encoding with |md| and writes the result -// to |out|. |EVP_MD_CTX_size| bytes are written, which is at most -// |EVP_MAX_MD_SIZE|. If |out_len| is not NULL, |*out_len| is set to the number -// of bytes written. This function returns one on success and zero on error. -// Note this digest covers the entire CRL, not just the signed portion. -OPENSSL_EXPORT int X509_CRL_digest(const X509_CRL *crl, const EVP_MD *md, - uint8_t *out, unsigned *out_len); - -// X509_REQ_digest hashes |req|'s DER encoding with |md| and writes the result -// to |out|. |EVP_MD_CTX_size| bytes are written, which is at most -// |EVP_MAX_MD_SIZE|. If |out_len| is not NULL, |*out_len| is set to the number -// of bytes written. This function returns one on success and zero on error. -// Note this digest covers the entire certificate request, not just the signed -// portion. -OPENSSL_EXPORT int X509_REQ_digest(const X509_REQ *req, const EVP_MD *md, - uint8_t *out, unsigned *out_len); - -// X509_NAME_digest hashes |name|'s DER encoding with |md| and writes the result -// to |out|. |EVP_MD_CTX_size| bytes are written, which is at most -// |EVP_MAX_MD_SIZE|. If |out_len| is not NULL, |*out_len| is set to the number -// of bytes written. This function returns one on success and zero on error. -OPENSSL_EXPORT int X509_NAME_digest(const X509_NAME *name, const EVP_MD *md, - uint8_t *out, unsigned *out_len); - -OPENSSL_EXPORT X509 *d2i_X509_fp(FILE *fp, X509 **x509); -OPENSSL_EXPORT int i2d_X509_fp(FILE *fp, X509 *x509); -OPENSSL_EXPORT X509_CRL *d2i_X509_CRL_fp(FILE *fp, X509_CRL **crl); -OPENSSL_EXPORT int i2d_X509_CRL_fp(FILE *fp, X509_CRL *crl); -OPENSSL_EXPORT X509_REQ *d2i_X509_REQ_fp(FILE *fp, X509_REQ **req); -OPENSSL_EXPORT int i2d_X509_REQ_fp(FILE *fp, X509_REQ *req); -OPENSSL_EXPORT RSA *d2i_RSAPrivateKey_fp(FILE *fp, RSA **rsa); -OPENSSL_EXPORT int i2d_RSAPrivateKey_fp(FILE *fp, RSA *rsa); -OPENSSL_EXPORT RSA *d2i_RSAPublicKey_fp(FILE *fp, RSA **rsa); -OPENSSL_EXPORT int i2d_RSAPublicKey_fp(FILE *fp, RSA *rsa); -OPENSSL_EXPORT RSA *d2i_RSA_PUBKEY_fp(FILE *fp, RSA **rsa); -OPENSSL_EXPORT int i2d_RSA_PUBKEY_fp(FILE *fp, RSA *rsa); -#ifndef OPENSSL_NO_DSA -OPENSSL_EXPORT DSA *d2i_DSA_PUBKEY_fp(FILE *fp, DSA **dsa); -OPENSSL_EXPORT int i2d_DSA_PUBKEY_fp(FILE *fp, DSA *dsa); -OPENSSL_EXPORT DSA *d2i_DSAPrivateKey_fp(FILE *fp, DSA **dsa); -OPENSSL_EXPORT int i2d_DSAPrivateKey_fp(FILE *fp, DSA *dsa); -#endif -OPENSSL_EXPORT EC_KEY *d2i_EC_PUBKEY_fp(FILE *fp, EC_KEY **eckey); -OPENSSL_EXPORT int i2d_EC_PUBKEY_fp(FILE *fp, EC_KEY *eckey); -OPENSSL_EXPORT EC_KEY *d2i_ECPrivateKey_fp(FILE *fp, EC_KEY **eckey); -OPENSSL_EXPORT int i2d_ECPrivateKey_fp(FILE *fp, EC_KEY *eckey); -OPENSSL_EXPORT X509_SIG *d2i_PKCS8_fp(FILE *fp, X509_SIG **p8); -OPENSSL_EXPORT int i2d_PKCS8_fp(FILE *fp, X509_SIG *p8); -OPENSSL_EXPORT PKCS8_PRIV_KEY_INFO *d2i_PKCS8_PRIV_KEY_INFO_fp( - FILE *fp, PKCS8_PRIV_KEY_INFO **p8inf); -OPENSSL_EXPORT int i2d_PKCS8_PRIV_KEY_INFO_fp(FILE *fp, - PKCS8_PRIV_KEY_INFO *p8inf); -OPENSSL_EXPORT int i2d_PKCS8PrivateKeyInfo_fp(FILE *fp, EVP_PKEY *key); -OPENSSL_EXPORT int i2d_PrivateKey_fp(FILE *fp, EVP_PKEY *pkey); -OPENSSL_EXPORT EVP_PKEY *d2i_PrivateKey_fp(FILE *fp, EVP_PKEY **a); -OPENSSL_EXPORT int i2d_PUBKEY_fp(FILE *fp, EVP_PKEY *pkey); -OPENSSL_EXPORT EVP_PKEY *d2i_PUBKEY_fp(FILE *fp, EVP_PKEY **a); - -OPENSSL_EXPORT X509 *d2i_X509_bio(BIO *bp, X509 **x509); -OPENSSL_EXPORT int i2d_X509_bio(BIO *bp, X509 *x509); -OPENSSL_EXPORT X509_CRL *d2i_X509_CRL_bio(BIO *bp, X509_CRL **crl); -OPENSSL_EXPORT int i2d_X509_CRL_bio(BIO *bp, X509_CRL *crl); -OPENSSL_EXPORT X509_REQ *d2i_X509_REQ_bio(BIO *bp, X509_REQ **req); -OPENSSL_EXPORT int i2d_X509_REQ_bio(BIO *bp, X509_REQ *req); -OPENSSL_EXPORT RSA *d2i_RSAPrivateKey_bio(BIO *bp, RSA **rsa); -OPENSSL_EXPORT int i2d_RSAPrivateKey_bio(BIO *bp, RSA *rsa); -OPENSSL_EXPORT RSA *d2i_RSAPublicKey_bio(BIO *bp, RSA **rsa); -OPENSSL_EXPORT int i2d_RSAPublicKey_bio(BIO *bp, RSA *rsa); -OPENSSL_EXPORT RSA *d2i_RSA_PUBKEY_bio(BIO *bp, RSA **rsa); -OPENSSL_EXPORT int i2d_RSA_PUBKEY_bio(BIO *bp, RSA *rsa); -#ifndef OPENSSL_NO_DSA -OPENSSL_EXPORT DSA *d2i_DSA_PUBKEY_bio(BIO *bp, DSA **dsa); -OPENSSL_EXPORT int i2d_DSA_PUBKEY_bio(BIO *bp, DSA *dsa); -OPENSSL_EXPORT DSA *d2i_DSAPrivateKey_bio(BIO *bp, DSA **dsa); -OPENSSL_EXPORT int i2d_DSAPrivateKey_bio(BIO *bp, DSA *dsa); -#endif -OPENSSL_EXPORT EC_KEY *d2i_EC_PUBKEY_bio(BIO *bp, EC_KEY **eckey); -OPENSSL_EXPORT int i2d_EC_PUBKEY_bio(BIO *bp, EC_KEY *eckey); -OPENSSL_EXPORT EC_KEY *d2i_ECPrivateKey_bio(BIO *bp, EC_KEY **eckey); -OPENSSL_EXPORT int i2d_ECPrivateKey_bio(BIO *bp, EC_KEY *eckey); -OPENSSL_EXPORT X509_SIG *d2i_PKCS8_bio(BIO *bp, X509_SIG **p8); -OPENSSL_EXPORT int i2d_PKCS8_bio(BIO *bp, X509_SIG *p8); -OPENSSL_EXPORT PKCS8_PRIV_KEY_INFO *d2i_PKCS8_PRIV_KEY_INFO_bio( - BIO *bp, PKCS8_PRIV_KEY_INFO **p8inf); -OPENSSL_EXPORT int i2d_PKCS8_PRIV_KEY_INFO_bio(BIO *bp, - PKCS8_PRIV_KEY_INFO *p8inf); -OPENSSL_EXPORT int i2d_PKCS8PrivateKeyInfo_bio(BIO *bp, EVP_PKEY *key); -OPENSSL_EXPORT int i2d_PrivateKey_bio(BIO *bp, EVP_PKEY *pkey); -OPENSSL_EXPORT EVP_PKEY *d2i_PrivateKey_bio(BIO *bp, EVP_PKEY **a); -OPENSSL_EXPORT int i2d_PUBKEY_bio(BIO *bp, EVP_PKEY *pkey); -OPENSSL_EXPORT EVP_PKEY *d2i_PUBKEY_bio(BIO *bp, EVP_PKEY **a); -OPENSSL_EXPORT DH *d2i_DHparams_bio(BIO *bp, DH **dh); -OPENSSL_EXPORT int i2d_DHparams_bio(BIO *bp, const DH *dh); - OPENSSL_EXPORT X509 *X509_dup(X509 *x509); OPENSSL_EXPORT X509_ATTRIBUTE *X509_ATTRIBUTE_dup(const X509_ATTRIBUTE *xa); OPENSSL_EXPORT X509_EXTENSION *X509_EXTENSION_dup(const X509_EXTENSION *ex); From 4f4ae71835797a8eb76bda3ed6da87e86f716c71 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Sat, 9 Jul 2022 15:48:29 -0400 Subject: [PATCH 27/38] Remove PKCS8_pkey_get0 and PKCS8_pkey_set0. I can't find any users of these APIs. If we remove them, the only publicly exposed operation on PKCS8_PRIV_KEY_INFO becomes EVP_PKCS82PKEY. We can then parse it without a dependency on the legacy ASN.1 stack. While I'm here, remove the callback on the structure. OPENSSL_free automatically calls OPENSSL_cleanse in BoringSSL, so the call is redundant. Update-Note: Removed some unused accessors. Change-Id: I400748463abe3c28dfa42ae9de9be59cb76cd2b2 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/53332 Reviewed-by: Bob Beck Commit-Queue: David Benjamin --- crypto/pkcs8/pkcs8_x509.c | 50 ++------------------------------------- include/openssl/x509.h | 7 ------ 2 files changed, 2 insertions(+), 55 deletions(-) diff --git a/crypto/pkcs8/pkcs8_x509.c b/crypto/pkcs8/pkcs8_x509.c index 5a1d591faa..f5dd5b4c67 100644 --- a/crypto/pkcs8/pkcs8_x509.c +++ b/crypto/pkcs8/pkcs8_x509.c @@ -90,61 +90,15 @@ int pkcs12_iterations_acceptable(uint64_t iterations) { return 0 < iterations && iterations <= kIterationsLimit; } -// Minor tweak to operation: zero private key data -static int pkey_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, - void *exarg) { - // Since the structure must still be valid use ASN1_OP_FREE_PRE - if (operation == ASN1_OP_FREE_PRE) { - PKCS8_PRIV_KEY_INFO *key = (PKCS8_PRIV_KEY_INFO *)*pval; - if (key->pkey) { - OPENSSL_cleanse(key->pkey->data, key->pkey->length); - } - } - return 1; -} - -ASN1_SEQUENCE_cb(PKCS8_PRIV_KEY_INFO, pkey_cb) = { +ASN1_SEQUENCE(PKCS8_PRIV_KEY_INFO) = { ASN1_SIMPLE(PKCS8_PRIV_KEY_INFO, version, ASN1_INTEGER), ASN1_SIMPLE(PKCS8_PRIV_KEY_INFO, pkeyalg, X509_ALGOR), ASN1_SIMPLE(PKCS8_PRIV_KEY_INFO, pkey, ASN1_OCTET_STRING), ASN1_IMP_SET_OF_OPT(PKCS8_PRIV_KEY_INFO, attributes, X509_ATTRIBUTE, 0), -} ASN1_SEQUENCE_END_cb(PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO) +} ASN1_SEQUENCE_END(PKCS8_PRIV_KEY_INFO) IMPLEMENT_ASN1_FUNCTIONS_const(PKCS8_PRIV_KEY_INFO) -int PKCS8_pkey_set0(PKCS8_PRIV_KEY_INFO *priv, ASN1_OBJECT *aobj, int version, - int ptype, void *pval, uint8_t *penc, int penclen) { - if (version >= 0 && - !ASN1_INTEGER_set(priv->version, version)) { - return 0; - } - - if (!X509_ALGOR_set0(priv->pkeyalg, aobj, ptype, pval)) { - return 0; - } - - if (penc != NULL) { - ASN1_STRING_set0(priv->pkey, penc, penclen); - } - - return 1; -} - -int PKCS8_pkey_get0(ASN1_OBJECT **ppkalg, const uint8_t **pk, int *ppklen, - X509_ALGOR **pa, PKCS8_PRIV_KEY_INFO *p8) { - if (ppkalg) { - *ppkalg = p8->pkeyalg->algorithm; - } - if (pk) { - *pk = ASN1_STRING_data(p8->pkey); - *ppklen = ASN1_STRING_length(p8->pkey); - } - if (pa) { - *pa = p8->pkeyalg; - } - return 1; -} - EVP_PKEY *EVP_PKCS82PKEY(PKCS8_PRIV_KEY_INFO *p8) { uint8_t *der = NULL; int der_len = i2d_PKCS8_PRIV_KEY_INFO(p8, &der); diff --git a/include/openssl/x509.h b/include/openssl/x509.h index 6c3d978018..b89be08abc 100644 --- a/include/openssl/x509.h +++ b/include/openssl/x509.h @@ -2243,13 +2243,6 @@ DECLARE_ASN1_FUNCTIONS_const(PKCS8_PRIV_KEY_INFO) OPENSSL_EXPORT EVP_PKEY *EVP_PKCS82PKEY(PKCS8_PRIV_KEY_INFO *p8); OPENSSL_EXPORT PKCS8_PRIV_KEY_INFO *EVP_PKEY2PKCS8(EVP_PKEY *pkey); -OPENSSL_EXPORT int PKCS8_pkey_set0(PKCS8_PRIV_KEY_INFO *priv, ASN1_OBJECT *aobj, - int version, int ptype, void *pval, - unsigned char *penc, int penclen); -OPENSSL_EXPORT int PKCS8_pkey_get0(ASN1_OBJECT **ppkalg, - const unsigned char **pk, int *ppklen, - X509_ALGOR **pa, PKCS8_PRIV_KEY_INFO *p8); - // X509_PUBKEY_set0_param sets |pub| to a key with AlgorithmIdentifier // determined by |obj|, |param_type|, and |param_value|, and an encoded // public key of |key|. On success, it takes ownership of all its parameters and From 892b9bc658f4e5e5989bb62b8c1356f3550e96a2 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Sun, 10 Jul 2022 01:15:31 -0400 Subject: [PATCH 28/38] Const-correct and document EVP_PKCS82PKEY and EVP_PKEY2PKCS8. Bug: 407 Change-Id: I973e0cfe636fb0cdef211b078503cce5df5293b6 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/53333 Reviewed-by: Bob Beck Commit-Queue: David Benjamin --- crypto/pkcs8/pkcs8_x509.c | 4 ++-- include/openssl/x509.h | 15 +++++++++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/crypto/pkcs8/pkcs8_x509.c b/crypto/pkcs8/pkcs8_x509.c index f5dd5b4c67..f7b37e9ed7 100644 --- a/crypto/pkcs8/pkcs8_x509.c +++ b/crypto/pkcs8/pkcs8_x509.c @@ -99,7 +99,7 @@ ASN1_SEQUENCE(PKCS8_PRIV_KEY_INFO) = { IMPLEMENT_ASN1_FUNCTIONS_const(PKCS8_PRIV_KEY_INFO) -EVP_PKEY *EVP_PKCS82PKEY(PKCS8_PRIV_KEY_INFO *p8) { +EVP_PKEY *EVP_PKCS82PKEY(const PKCS8_PRIV_KEY_INFO *p8) { uint8_t *der = NULL; int der_len = i2d_PKCS8_PRIV_KEY_INFO(p8, &der); if (der_len < 0) { @@ -120,7 +120,7 @@ EVP_PKEY *EVP_PKCS82PKEY(PKCS8_PRIV_KEY_INFO *p8) { return ret; } -PKCS8_PRIV_KEY_INFO *EVP_PKEY2PKCS8(EVP_PKEY *pkey) { +PKCS8_PRIV_KEY_INFO *EVP_PKEY2PKCS8(const EVP_PKEY *pkey) { CBB cbb; uint8_t *der = NULL; size_t der_len; diff --git a/include/openssl/x509.h b/include/openssl/x509.h index b89be08abc..453fb0b9c2 100644 --- a/include/openssl/x509.h +++ b/include/openssl/x509.h @@ -2240,8 +2240,19 @@ OPENSSL_EXPORT X509 *X509_find_by_subject(STACK_OF(X509) *sk, X509_NAME *name); DECLARE_ASN1_FUNCTIONS_const(PKCS8_PRIV_KEY_INFO) -OPENSSL_EXPORT EVP_PKEY *EVP_PKCS82PKEY(PKCS8_PRIV_KEY_INFO *p8); -OPENSSL_EXPORT PKCS8_PRIV_KEY_INFO *EVP_PKEY2PKCS8(EVP_PKEY *pkey); +// EVP_PKCS82PKEY returns |p8| as a newly-allocated |EVP_PKEY|, or NULL if the +// key was unsupported or could not be decoded. If non-NULL, the caller must +// release the result with |EVP_PKEY_free| when done. +// +// Use |EVP_parse_private_key| instead. +OPENSSL_EXPORT EVP_PKEY *EVP_PKCS82PKEY(const PKCS8_PRIV_KEY_INFO *p8); + +// EVP_PKEY2PKCS8 encodes |pkey| as a PKCS#8 PrivateKeyInfo (RFC 5208), +// represented as a newly-allocated |PKCS8_PRIV_KEY_INFO|, or NULL on error. The +// caller must release the result with |PKCS8_PRIV_KEY_INFO_free| when done. +// +// Use |EVP_marshal_private_key| instead. +OPENSSL_EXPORT PKCS8_PRIV_KEY_INFO *EVP_PKEY2PKCS8(const EVP_PKEY *pkey); // X509_PUBKEY_set0_param sets |pub| to a key with AlgorithmIdentifier // determined by |obj|, |param_type|, and |param_value|, and an encoded From 84311cec95da26b3a9f81eb073e6d4336e04ccf5 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Sun, 10 Jul 2022 01:01:13 -0400 Subject: [PATCH 29/38] Const-correct X509_REVOKED as well. Although it contains an X509_NAME (by way of GENERAL_NAME), the GENERAL_NAME field does not participate in serialization, so it is actually const. Bug: 407 Change-Id: I299815789744597e2b355cb0b996ba90c3b6a72f Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/53334 Reviewed-by: Bob Beck Commit-Queue: David Benjamin --- crypto/x509/x_crl.c | 8 +++++--- include/openssl/x509.h | 6 ++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/crypto/x509/x_crl.c b/crypto/x509/x_crl.c index f65afba245..a8e6c743a3 100644 --- a/crypto/x509/x_crl.c +++ b/crypto/x509/x_crl.c @@ -348,9 +348,11 @@ ASN1_SEQUENCE_ref(X509_CRL, crl_cb) = { ASN1_SIMPLE(X509_CRL, signature, ASN1_BIT_STRING), } ASN1_SEQUENCE_END_ref(X509_CRL, X509_CRL) -IMPLEMENT_ASN1_FUNCTIONS(X509_REVOKED) - -IMPLEMENT_ASN1_DUP_FUNCTION(X509_REVOKED) +// Although |X509_REVOKED| contains an |X509_NAME|, it can be const. It is not +// affected by https://crbug.com/boringssl/407 because the |X509_NAME| does +// not participate in serialization. +IMPLEMENT_ASN1_FUNCTIONS_const(X509_REVOKED) +IMPLEMENT_ASN1_DUP_FUNCTION_const(X509_REVOKED) IMPLEMENT_ASN1_FUNCTIONS(X509_CRL_INFO) IMPLEMENT_ASN1_FUNCTIONS(X509_CRL) diff --git a/include/openssl/x509.h b/include/openssl/x509.h index 453fb0b9c2..cbb2f67632 100644 --- a/include/openssl/x509.h +++ b/include/openssl/x509.h @@ -1551,7 +1551,7 @@ OPENSSL_EXPORT X509 *X509_dup(X509 *x509); OPENSSL_EXPORT X509_ATTRIBUTE *X509_ATTRIBUTE_dup(const X509_ATTRIBUTE *xa); OPENSSL_EXPORT X509_EXTENSION *X509_EXTENSION_dup(const X509_EXTENSION *ex); OPENSSL_EXPORT X509_CRL *X509_CRL_dup(X509_CRL *crl); -OPENSSL_EXPORT X509_REVOKED *X509_REVOKED_dup(X509_REVOKED *rev); +OPENSSL_EXPORT X509_REVOKED *X509_REVOKED_dup(const X509_REVOKED *rev); OPENSSL_EXPORT X509_REQ *X509_REQ_dup(X509_REQ *req); OPENSSL_EXPORT X509_ALGOR *X509_ALGOR_dup(const X509_ALGOR *xn); @@ -1622,9 +1622,7 @@ OPENSSL_EXPORT void X509_reject_clear(X509 *x); OPENSSL_EXPORT int X509_TRUST_set(int *t, int trust); -// TODO(https://crbug.com/boringssl/407): This is not const because it contains -// an |X509_NAME|. -DECLARE_ASN1_FUNCTIONS(X509_REVOKED) +DECLARE_ASN1_FUNCTIONS_const(X509_REVOKED) OPENSSL_EXPORT int X509_CRL_add0_revoked(X509_CRL *crl, X509_REVOKED *rev); OPENSSL_EXPORT int X509_CRL_get0_by_serial(X509_CRL *crl, X509_REVOKED **ret, From b859642c20724a9c43d726933c74b30602fb356a Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Sun, 10 Jul 2022 01:08:07 -0400 Subject: [PATCH 30/38] Document all the dup functions. Some don't have sections to go with yet, but will later. Bug: 426 Change-Id: I903a8bf8c33cdc026a79601a8fd37469c839fa00 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/53335 Reviewed-by: Bob Beck Commit-Queue: David Benjamin --- include/openssl/x509.h | 48 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/include/openssl/x509.h b/include/openssl/x509.h index cbb2f67632..ede59940b0 100644 --- a/include/openssl/x509.h +++ b/include/openssl/x509.h @@ -131,6 +131,16 @@ OPENSSL_EXPORT int X509_up_ref(X509 *x509); // one. OPENSSL_EXPORT STACK_OF(X509) *X509_chain_up_ref(STACK_OF(X509) *chain); +// X509_dup returns a newly-allocated copy of |x509|, or NULL on error. This +// function works by serializing the structure, so auxiliary properties (see +// |i2d_X509_AUX|) are not preserved. Additionally, if |x509| is incomplete, +// this function may fail. +// +// TODO(https://crbug.com/boringssl/407): This function should be const and +// thread-safe but is currently neither in some cases, notably if |crl| was +// mutated. +OPENSSL_EXPORT X509 *X509_dup(X509 *x509); + // X509_free decrements |x509|'s reference count and, if zero, releases memory // associated with |x509|. OPENSSL_EXPORT void X509_free(X509 *x509); @@ -425,6 +435,15 @@ DECLARE_ASN1_ITEM(X509_CRL) // X509_CRL_up_ref adds one to the reference count of |crl| and returns one. OPENSSL_EXPORT int X509_CRL_up_ref(X509_CRL *crl); +// X509_CRL_dup returns a newly-allocated copy of |crl|, or NULL on error. This +// function works by serializing the structure, so if |crl| is incomplete, it +// may fail. +// +// TODO(https://crbug.com/boringssl/407): This function should be const and +// thread-safe but is currently neither in some cases, notably if |crl| was +// mutated. +OPENSSL_EXPORT X509_CRL *X509_CRL_dup(X509_CRL *crl); + // X509_CRL_free decrements |crl|'s reference count and, if zero, releases // memory associated with |crl|. OPENSSL_EXPORT void X509_CRL_free(X509_CRL *crl); @@ -593,6 +612,15 @@ OPENSSL_EXPORT int X509_CRL_set1_signature_value(X509_CRL *crl, // and C type is |X509_REQ*|. DECLARE_ASN1_ITEM(X509_REQ) +// X509_REQ_dup returns a newly-allocated copy of |req|, or NULL on error. This +// function works by serializing the structure, so if |req| is incomplete, it +// may fail. +// +// TODO(https://crbug.com/boringssl/407): This function should be const and +// thread-safe but is currently neither in some cases, notably if |req| was +// mutated. +OPENSSL_EXPORT X509_REQ *X509_REQ_dup(X509_REQ *req); + // X509_REQ_free releases memory associated with |req|. OPENSSL_EXPORT void X509_REQ_free(X509_REQ *req); @@ -966,6 +994,11 @@ DECLARE_ASN1_ITEM(X509_ALGOR) // on error. OPENSSL_EXPORT X509_ALGOR *X509_ALGOR_new(void); +// X509_ALGOR_dup returns a newly-allocated copy of |alg|, or NULL on error. +// This function works by serializing the structure, so if |alg| is incomplete, +// it may fail. +OPENSSL_EXPORT X509_ALGOR *X509_ALGOR_dup(const X509_ALGOR *alg); + // X509_ALGOR_free releases memory associated with |alg|. OPENSSL_EXPORT void X509_ALGOR_free(X509_ALGOR *alg); @@ -1547,13 +1580,20 @@ OPENSSL_EXPORT int NETSCAPE_SPKI_set_pubkey(NETSCAPE_SPKI *spki, OPENSSL_EXPORT int NETSCAPE_SPKI_sign(NETSCAPE_SPKI *spki, EVP_PKEY *pkey, const EVP_MD *md); -OPENSSL_EXPORT X509 *X509_dup(X509 *x509); +// X509_ATTRIBUTE_dup returns a newly-allocated copy of |xa|, or NULL on error. +// This function works by serializing the structure, so if |xa| is incomplete, +// it may fail. OPENSSL_EXPORT X509_ATTRIBUTE *X509_ATTRIBUTE_dup(const X509_ATTRIBUTE *xa); + +// X509_EXTENSION_dup returns a newly-allocated copy of |ex|, or NULL on error. +// This function works by serializing the structure, so if |ex| is incomplete, +// it may fail. OPENSSL_EXPORT X509_EXTENSION *X509_EXTENSION_dup(const X509_EXTENSION *ex); -OPENSSL_EXPORT X509_CRL *X509_CRL_dup(X509_CRL *crl); + +// X509_REVOKED_dup returns a newly-allocated copy of |rev|, or NULL on error. +// This function works by serializing the structure, so if |rev| is incomplete, +// it may fail. OPENSSL_EXPORT X509_REVOKED *X509_REVOKED_dup(const X509_REVOKED *rev); -OPENSSL_EXPORT X509_REQ *X509_REQ_dup(X509_REQ *req); -OPENSSL_EXPORT X509_ALGOR *X509_ALGOR_dup(const X509_ALGOR *xn); // X509_cmp_time compares |s| against |*t|. On success, it returns a negative // number if |s| <= |*t| and a positive number if |s| > |*t|. On error, it From 09b8fd44c3d36cab0860a8e520ecbfe58b02a7fa Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Sun, 10 Jul 2022 19:14:48 -0400 Subject: [PATCH 31/38] Const-correct X509_EXTENSION functions, as best we can. Some of these were non-const because dup functions weren't const-correct, but they are now. Once nuisance is the accessors. Ideally they'd return non-const pointers, but that'll break OpenSSL consumers. Bug: 407 Change-Id: I52b939a846b726d1d84dd2d5fdf71a7a7284d49e Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/53336 Reviewed-by: Bob Beck Commit-Queue: David Benjamin --- crypto/x509/t_req.c | 7 +++---- crypto/x509/x509_ext.c | 6 +++--- crypto/x509/x509_test.cc | 4 ++-- crypto/x509/x509_v3.c | 6 +++--- crypto/x509/x509_vfy.c | 5 ++--- crypto/x509v3/v3_akey.c | 2 +- crypto/x509v3/v3_prn.c | 27 ++++++++++++--------------- crypto/x509v3/v3_purp.c | 7 +++---- include/openssl/x509.h | 38 ++++++++++++++++++++++++-------------- include/openssl/x509v3.h | 11 ++++++----- 10 files changed, 59 insertions(+), 54 deletions(-) diff --git a/crypto/x509/t_req.c b/crypto/x509/t_req.c index 154fb75bc7..e9287d5f3d 100644 --- a/crypto/x509/t_req.c +++ b/crypto/x509/t_req.c @@ -208,13 +208,12 @@ int X509_REQ_print_ex(BIO *bio, X509_REQ *x, unsigned long nmflags, if (exts) { BIO_printf(bio, "%8sRequested Extensions:\n", ""); - size_t i; - for (i = 0; i < sk_X509_EXTENSION_num(exts); i++) { - X509_EXTENSION *ex = sk_X509_EXTENSION_value(exts, i); + for (size_t i = 0; i < sk_X509_EXTENSION_num(exts); i++) { + const X509_EXTENSION *ex = sk_X509_EXTENSION_value(exts, i); if (BIO_printf(bio, "%12s", "") <= 0) { goto err; } - ASN1_OBJECT *obj = X509_EXTENSION_get_object(ex); + const ASN1_OBJECT *obj = X509_EXTENSION_get_object(ex); i2a_ASN1_OBJECT(bio, obj); const int is_critical = X509_EXTENSION_get_critical(ex); if (BIO_printf(bio, ": %s\n", is_critical ? "critical" : "") <= 0) { diff --git a/crypto/x509/x509_ext.c b/crypto/x509/x509_ext.c index 17f4d171fe..8ab1926d23 100644 --- a/crypto/x509/x509_ext.c +++ b/crypto/x509/x509_ext.c @@ -99,7 +99,7 @@ int X509_CRL_add1_ext_i2d(X509_CRL *x, int nid, void *value, int crit, return X509V3_add1_i2d(&x->crl->extensions, nid, value, crit, flags); } -int X509_CRL_add_ext(X509_CRL *x, X509_EXTENSION *ex, int loc) { +int X509_CRL_add_ext(X509_CRL *x, const X509_EXTENSION *ex, int loc) { return (X509v3_add_ext(&(x->crl->extensions), ex, loc) != NULL); } @@ -127,7 +127,7 @@ X509_EXTENSION *X509_delete_ext(X509 *x, int loc) { return (X509v3_delete_ext(x->cert_info->extensions, loc)); } -int X509_add_ext(X509 *x, X509_EXTENSION *ex, int loc) { +int X509_add_ext(X509 *x, const X509_EXTENSION *ex, int loc) { return (X509v3_add_ext(&(x->cert_info->extensions), ex, loc) != NULL); } @@ -168,7 +168,7 @@ X509_EXTENSION *X509_REVOKED_delete_ext(X509_REVOKED *x, int loc) { return (X509v3_delete_ext(x->extensions, loc)); } -int X509_REVOKED_add_ext(X509_REVOKED *x, X509_EXTENSION *ex, int loc) { +int X509_REVOKED_add_ext(X509_REVOKED *x, const X509_EXTENSION *ex, int loc) { return (X509v3_add_ext(&(x->extensions), ex, loc) != NULL); } diff --git a/crypto/x509/x509_test.cc b/crypto/x509/x509_test.cc index 8aee2d5a10..8343fee39a 100644 --- a/crypto/x509/x509_test.cc +++ b/crypto/x509/x509_test.cc @@ -4402,10 +4402,10 @@ TEST(X509Test, AddExt) { ASSERT_EQ(static_cast(X509_get_ext_count(x509.get())), exts.size()); for (size_t i = 0; i < exts.size(); i++) { SCOPED_TRACE(i); - X509_EXTENSION *ext = X509_get_ext(x509.get(), static_cast(i)); + const X509_EXTENSION *ext = X509_get_ext(x509.get(), static_cast(i)); EXPECT_EQ(OBJ_obj2nid(X509_EXTENSION_get_object(ext)), exts[i].nid); EXPECT_EQ(X509_EXTENSION_get_critical(ext), exts[i].critical ? 1 : 0); - ASN1_OCTET_STRING *data = X509_EXTENSION_get_data(ext); + const ASN1_OCTET_STRING *data = X509_EXTENSION_get_data(ext); EXPECT_EQ(Bytes(ASN1_STRING_get0_data(data), ASN1_STRING_length(data)), Bytes(exts[i].data)); } diff --git a/crypto/x509/x509_v3.c b/crypto/x509/x509_v3.c index 920923309a..4b88ea7076 100644 --- a/crypto/x509/x509_v3.c +++ b/crypto/x509/x509_v3.c @@ -144,7 +144,7 @@ X509_EXTENSION *X509v3_delete_ext(STACK_OF(X509_EXTENSION) *x, int loc) { } STACK_OF(X509_EXTENSION) *X509v3_add_ext(STACK_OF(X509_EXTENSION) **x, - X509_EXTENSION *ex, int loc) { + const X509_EXTENSION *ex, int loc) { X509_EXTENSION *new_ex = NULL; int n; STACK_OF(X509_EXTENSION) *sk = NULL; @@ -267,14 +267,14 @@ int X509_EXTENSION_set_data(X509_EXTENSION *ex, const ASN1_OCTET_STRING *data) { return 1; } -ASN1_OBJECT *X509_EXTENSION_get_object(X509_EXTENSION *ex) { +ASN1_OBJECT *X509_EXTENSION_get_object(const X509_EXTENSION *ex) { if (ex == NULL) { return NULL; } return ex->object; } -ASN1_OCTET_STRING *X509_EXTENSION_get_data(X509_EXTENSION *ex) { +ASN1_OCTET_STRING *X509_EXTENSION_get_data(const X509_EXTENSION *ex) { if (ex == NULL) { return NULL; } diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c index 2e5a3c622e..e054629af1 100644 --- a/crypto/x509/x509_vfy.c +++ b/crypto/x509/x509_vfy.c @@ -1097,7 +1097,7 @@ static int get_crl_sk(X509_STORE_CTX *ctx, X509_CRL **pcrl, X509_CRL **pdcrl, // both present or both absent. If both present all fields must be identical. static int crl_extension_match(X509_CRL *a, X509_CRL *b, int nid) { - ASN1_OCTET_STRING *exta, *extb; + const ASN1_OCTET_STRING *exta, *extb; int i; i = X509_CRL_get_ext_by_NID(a, nid, -1); if (i >= 0) { @@ -2025,8 +2025,7 @@ X509_CRL *X509_CRL_diff(X509_CRL *base, X509_CRL *newer, EVP_PKEY *skey, // number to correct value too. for (i = 0; i < X509_CRL_get_ext_count(newer); i++) { - X509_EXTENSION *ext; - ext = X509_CRL_get_ext(newer, i); + const X509_EXTENSION *ext = X509_CRL_get_ext(newer, i); if (!X509_CRL_add_ext(crl, ext, -1)) { goto memerr; } diff --git a/crypto/x509v3/v3_akey.c b/crypto/x509v3/v3_akey.c index 343940be49..7616f4f087 100644 --- a/crypto/x509v3/v3_akey.c +++ b/crypto/x509v3/v3_akey.c @@ -143,7 +143,6 @@ static void *v2i_AUTHORITY_KEYID(const X509V3_EXT_METHOD *method, GENERAL_NAMES *gens = NULL; GENERAL_NAME *gen = NULL; ASN1_INTEGER *serial = NULL; - X509_EXTENSION *ext; X509 *cert; AUTHORITY_KEYID *akeyid; @@ -178,6 +177,7 @@ static void *v2i_AUTHORITY_KEYID(const X509V3_EXT_METHOD *method, if (keyid) { j = X509_get_ext_by_NID(cert, NID_subject_key_identifier, -1); + const X509_EXTENSION *ext; if ((j >= 0) && (ext = X509_get_ext(cert, j))) { ikeyid = X509V3_EXT_d2i(ext); } diff --git a/crypto/x509v3/v3_prn.c b/crypto/x509v3/v3_prn.c index 129c4fac00..20d2ad99e5 100644 --- a/crypto/x509v3/v3_prn.c +++ b/crypto/x509v3/v3_prn.c @@ -66,15 +66,13 @@ // Extension printing routines -static int unknown_ext_print(BIO *out, X509_EXTENSION *ext, unsigned long flag, - int indent, int supported); +static int unknown_ext_print(BIO *out, const X509_EXTENSION *ext, + unsigned long flag, int indent, int supported); // Print out a name+value stack -void X509V3_EXT_val_prn(BIO *out, STACK_OF(CONF_VALUE) *val, int indent, +void X509V3_EXT_val_prn(BIO *out, const STACK_OF(CONF_VALUE) *val, int indent, int ml) { - size_t i; - CONF_VALUE *nval; if (!val) { return; } @@ -84,13 +82,13 @@ void X509V3_EXT_val_prn(BIO *out, STACK_OF(CONF_VALUE) *val, int indent, BIO_puts(out, "\n"); } } - for (i = 0; i < sk_CONF_VALUE_num(val); i++) { + for (size_t i = 0; i < sk_CONF_VALUE_num(val); i++) { if (ml) { BIO_printf(out, "%*s", indent, ""); } else if (i > 0) { BIO_printf(out, ", "); } - nval = sk_CONF_VALUE_value(val, i); + const CONF_VALUE *nval = sk_CONF_VALUE_value(val, i); if (!nval->name) { BIO_puts(out, nval->value); } else if (!nval->value) { @@ -106,7 +104,7 @@ void X509V3_EXT_val_prn(BIO *out, STACK_OF(CONF_VALUE) *val, int indent, // Main routine: print out a general extension -int X509V3_EXT_print(BIO *out, X509_EXTENSION *ext, unsigned long flag, +int X509V3_EXT_print(BIO *out, const X509_EXTENSION *ext, unsigned long flag, int indent) { void *ext_str = NULL; char *value = NULL; @@ -180,13 +178,11 @@ int X509V3_extensions_print(BIO *bp, const char *title, } for (i = 0; i < sk_X509_EXTENSION_num(exts); i++) { - ASN1_OBJECT *obj; - X509_EXTENSION *ex; - ex = sk_X509_EXTENSION_value(exts, i); + const X509_EXTENSION *ex = sk_X509_EXTENSION_value(exts, i); if (indent && BIO_printf(bp, "%*s", indent, "") <= 0) { return 0; } - obj = X509_EXTENSION_get_object(ex); + const ASN1_OBJECT *obj = X509_EXTENSION_get_object(ex); i2a_ASN1_OBJECT(bp, obj); j = X509_EXTENSION_get_critical(ex); if (BIO_printf(bp, ": %s\n", j ? "critical" : "") <= 0) { @@ -203,8 +199,8 @@ int X509V3_extensions_print(BIO *bp, const char *title, return 1; } -static int unknown_ext_print(BIO *out, X509_EXTENSION *ext, unsigned long flag, - int indent, int supported) { +static int unknown_ext_print(BIO *out, const X509_EXTENSION *ext, + unsigned long flag, int indent, int supported) { switch (flag & X509V3_EXT_UNKNOWN_MASK) { case X509V3_EXT_DEFAULT: return 0; @@ -229,7 +225,8 @@ static int unknown_ext_print(BIO *out, X509_EXTENSION *ext, unsigned long flag, } } -int X509V3_EXT_print_fp(FILE *fp, X509_EXTENSION *ext, int flag, int indent) { +int X509V3_EXT_print_fp(FILE *fp, const X509_EXTENSION *ext, int flag, + int indent) { BIO *bio_tmp; int ret; if (!(bio_tmp = BIO_new_fp(fp, BIO_NOCLOSE))) { diff --git a/crypto/x509v3/v3_purp.c b/crypto/x509v3/v3_purp.c index 9a925b2293..00c0571c2f 100644 --- a/crypto/x509v3/v3_purp.c +++ b/crypto/x509v3/v3_purp.c @@ -320,7 +320,7 @@ static int nid_cmp(const void *void_a, const void *void_b) { return *a - *b; } -int X509_supported_extension(X509_EXTENSION *ex) { +int X509_supported_extension(const X509_EXTENSION *ex) { // This table is a list of the NIDs of supported extensions: that is // those which are used by the verify process. If an extension is // critical and doesn't appear in this list then the verify process will @@ -405,7 +405,6 @@ int x509v3_cache_extensions(X509 *x) { ASN1_BIT_STRING *usage; ASN1_BIT_STRING *ns; EXTENDED_KEY_USAGE *extusage; - X509_EXTENSION *ex; size_t i; int j; @@ -576,7 +575,7 @@ int x509v3_cache_extensions(X509 *x) { } for (j = 0; j < X509_get_ext_count(x); j++) { - ex = X509_get_ext(x, j); + const X509_EXTENSION *ex = X509_get_ext(x, j); if (OBJ_obj2nid(X509_EXTENSION_get_object(ex)) == NID_freshest_crl) { x->ex_flags |= EXFLAG_FRESHEST; } @@ -768,7 +767,7 @@ static int check_purpose_timestamp_sign(const X509_PURPOSE *xp, const X509 *x, // Extended Key Usage MUST be critical i_ext = X509_get_ext_by_NID((X509 *)x, NID_ext_key_usage, -1); if (i_ext >= 0) { - X509_EXTENSION *ext = X509_get_ext((X509 *)x, i_ext); + const X509_EXTENSION *ext = X509_get_ext((X509 *)x, i_ext); if (!X509_EXTENSION_get_critical(ext)) { return 0; } diff --git a/include/openssl/x509.h b/include/openssl/x509.h index ede59940b0..a2cda17e0c 100644 --- a/include/openssl/x509.h +++ b/include/openssl/x509.h @@ -1889,7 +1889,8 @@ OPENSSL_EXPORT int X509v3_get_ext_by_critical(const STACK_OF(X509_EXTENSION) *x, int crit, int lastpos); // X509v3_get_ext returns the extension in |x| at index |loc|, or NULL if |loc| -// is out of bounds. +// is out of bounds. This function returns a non-const pointer for OpenSSL +// compatibility, but callers should not mutate the result. OPENSSL_EXPORT X509_EXTENSION *X509v3_get_ext(const STACK_OF(X509_EXTENSION) *x, int loc); @@ -1908,7 +1909,7 @@ OPENSSL_EXPORT X509_EXTENSION *X509v3_delete_ext(STACK_OF(X509_EXTENSION) *x, // right. If |loc| is -1 or out of bounds, the new extension is appended to the // list. OPENSSL_EXPORT STACK_OF(X509_EXTENSION) *X509v3_add_ext( - STACK_OF(X509_EXTENSION) **x, X509_EXTENSION *ex, int loc); + STACK_OF(X509_EXTENSION) **x, const X509_EXTENSION *ex, int loc); // X509_get_ext_count returns the number of extensions in |x|. OPENSSL_EXPORT int X509_get_ext_count(const X509 *x); @@ -1928,7 +1929,8 @@ OPENSSL_EXPORT int X509_get_ext_by_critical(const X509 *x, int crit, int lastpos); // X509_get_ext returns the extension in |x| at index |loc|, or NULL if |loc| is -// out of bounds. +// out of bounds. This function returns a non-const pointer for OpenSSL +// compatibility, but callers should not mutate the result. OPENSSL_EXPORT X509_EXTENSION *X509_get_ext(const X509 *x, int loc); // X509_delete_ext removes the extension in |x| at index |loc| and returns the @@ -1944,7 +1946,7 @@ OPENSSL_EXPORT X509_EXTENSION *X509_delete_ext(X509 *x, int loc); // The new extension is inserted at index |loc|, shifting extensions to the // right. If |loc| is -1 or out of bounds, the new extension is appended to the // list. -OPENSSL_EXPORT int X509_add_ext(X509 *x, X509_EXTENSION *ex, int loc); +OPENSSL_EXPORT int X509_add_ext(X509 *x, const X509_EXTENSION *ex, int loc); // X509_get_ext_d2i behaves like |X509V3_get_d2i| but looks for the extension in // |x509|'s extension list. @@ -1982,7 +1984,8 @@ OPENSSL_EXPORT int X509_CRL_get_ext_by_critical(const X509_CRL *x, int crit, int lastpos); // X509_CRL_get_ext returns the extension in |x| at index |loc|, or NULL if -// |loc| is out of bounds. +// |loc| is out of bounds. This function returns a non-const pointer for OpenSSL +// compatibility, but callers should not mutate the result. OPENSSL_EXPORT X509_EXTENSION *X509_CRL_get_ext(const X509_CRL *x, int loc); // X509_CRL_delete_ext removes the extension in |x| at index |loc| and returns @@ -1998,7 +2001,8 @@ OPENSSL_EXPORT X509_EXTENSION *X509_CRL_delete_ext(X509_CRL *x, int loc); // The new extension is inserted at index |loc|, shifting extensions to the // right. If |loc| is -1 or out of bounds, the new extension is appended to the // list. -OPENSSL_EXPORT int X509_CRL_add_ext(X509_CRL *x, X509_EXTENSION *ex, int loc); +OPENSSL_EXPORT int X509_CRL_add_ext(X509_CRL *x, const X509_EXTENSION *ex, + int loc); // X509_CRL_get_ext_d2i behaves like |X509V3_get_d2i| but looks for the // extension in |crl|'s extension list. @@ -2037,7 +2041,8 @@ OPENSSL_EXPORT int X509_REVOKED_get_ext_by_critical(const X509_REVOKED *x, int crit, int lastpos); // X509_REVOKED_get_ext returns the extension in |x| at index |loc|, or NULL if -// |loc| is out of bounds. +// |loc| is out of bounds. This function returns a non-const pointer for OpenSSL +// compatibility, but callers should not mutate the result. OPENSSL_EXPORT X509_EXTENSION *X509_REVOKED_get_ext(const X509_REVOKED *x, int loc); @@ -2056,8 +2061,8 @@ OPENSSL_EXPORT X509_EXTENSION *X509_REVOKED_delete_ext(X509_REVOKED *x, // The new extension is inserted at index |loc|, shifting extensions to the // right. If |loc| is -1 or out of bounds, the new extension is appended to the // list. -OPENSSL_EXPORT int X509_REVOKED_add_ext(X509_REVOKED *x, X509_EXTENSION *ex, - int loc); +OPENSSL_EXPORT int X509_REVOKED_add_ext(X509_REVOKED *x, + const X509_EXTENSION *ex, int loc); // X509_REVOKED_get_ext_d2i behaves like |X509V3_get_d2i| but looks for the // extension in |revoked|'s extension list. @@ -2109,11 +2114,16 @@ OPENSSL_EXPORT int X509_EXTENSION_set_critical(X509_EXTENSION *ex, int crit); OPENSSL_EXPORT int X509_EXTENSION_set_data(X509_EXTENSION *ex, const ASN1_OCTET_STRING *data); -// X509_EXTENSION_get_object returns |ex|'s extension type. -OPENSSL_EXPORT ASN1_OBJECT *X509_EXTENSION_get_object(X509_EXTENSION *ex); - -// X509_EXTENSION_get_data returns |ne|'s extension value. -OPENSSL_EXPORT ASN1_OCTET_STRING *X509_EXTENSION_get_data(X509_EXTENSION *ne); +// X509_EXTENSION_get_object returns |ex|'s extension type. This function +// returns a non-const pointer for OpenSSL compatibility, but callers should not +// mutate the result. +OPENSSL_EXPORT ASN1_OBJECT *X509_EXTENSION_get_object(const X509_EXTENSION *ex); + +// X509_EXTENSION_get_data returns |ne|'s extension value. This function returns +// a non-const pointer for OpenSSL compatibility, but callers should not mutate +// the result. +OPENSSL_EXPORT ASN1_OCTET_STRING *X509_EXTENSION_get_data( + const X509_EXTENSION *ne); // X509_EXTENSION_get_critical returns one if |ex| is critical and zero // otherwise. diff --git a/include/openssl/x509v3.h b/include/openssl/x509v3.h index 38c72cd2bd..9db57e6f6a 100644 --- a/include/openssl/x509v3.h +++ b/include/openssl/x509v3.h @@ -787,12 +787,13 @@ OPENSSL_EXPORT int X509V3_add1_i2d(STACK_OF(X509_EXTENSION) **x, int nid, // hexdump. #define X509V3_EXT_DUMP_UNKNOWN (3L << 16) -OPENSSL_EXPORT void X509V3_EXT_val_prn(BIO *out, STACK_OF(CONF_VALUE) *val, +OPENSSL_EXPORT void X509V3_EXT_val_prn(BIO *out, + const STACK_OF(CONF_VALUE) *val, int indent, int ml); -OPENSSL_EXPORT int X509V3_EXT_print(BIO *out, X509_EXTENSION *ext, +OPENSSL_EXPORT int X509V3_EXT_print(BIO *out, const X509_EXTENSION *ext, unsigned long flag, int indent); -OPENSSL_EXPORT int X509V3_EXT_print_fp(FILE *out, X509_EXTENSION *ext, int flag, - int indent); +OPENSSL_EXPORT int X509V3_EXT_print_fp(FILE *out, const X509_EXTENSION *ext, + int flag, int indent); // X509V3_extensions_print prints |title|, followed by a human-readable // representation of |exts| to |out|. It returns one on success and zero on @@ -805,7 +806,7 @@ OPENSSL_EXPORT int X509V3_extensions_print(BIO *out, const char *title, OPENSSL_EXPORT int X509_check_ca(X509 *x); OPENSSL_EXPORT int X509_check_purpose(X509 *x, int id, int ca); -OPENSSL_EXPORT int X509_supported_extension(X509_EXTENSION *ex); +OPENSSL_EXPORT int X509_supported_extension(const X509_EXTENSION *ex); OPENSSL_EXPORT int X509_PURPOSE_set(int *p, int purpose); OPENSSL_EXPORT int X509_check_issued(X509 *issuer, X509 *subject); OPENSSL_EXPORT int X509_check_akid(X509 *issuer, AUTHORITY_KEYID *akid); From 557b80f1a3e599459367391540488c132a000d55 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Sun, 10 Jul 2022 19:12:12 -0400 Subject: [PATCH 32/38] Document and organize some of the basic extensions functions. I haven't done the i2d/d2i functions yet, since we haven't talked about how extensions can be known to the library. Also X509_REVOKED still needs a home. Bug: 407 Change-Id: I19fb600ccfda5528728849a42a957803b350b5c5 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/53337 Reviewed-by: Bob Beck Commit-Queue: David Benjamin --- include/openssl/x509.h | 421 +++++++++++++++++++++++------------------ 1 file changed, 233 insertions(+), 188 deletions(-) diff --git a/include/openssl/x509.h b/include/openssl/x509.h index a2cda17e0c..96b7495877 100644 --- a/include/openssl/x509.h +++ b/include/openssl/x509.h @@ -222,6 +222,28 @@ OPENSSL_EXPORT void X509_get0_uids(const X509 *x509, OPENSSL_EXPORT const STACK_OF(X509_EXTENSION) *X509_get0_extensions( const X509 *x509); +// X509_get_ext_count returns the number of extensions in |x|. +OPENSSL_EXPORT int X509_get_ext_count(const X509 *x); + +// X509_get_ext_by_NID behaves like |X509v3_get_ext_by_NID| but searches for +// extensions in |x|. +OPENSSL_EXPORT int X509_get_ext_by_NID(const X509 *x, int nid, int lastpos); + +// X509_get_ext_by_OBJ behaves like |X509v3_get_ext_by_OBJ| but searches for +// extensions in |x|. +OPENSSL_EXPORT int X509_get_ext_by_OBJ(const X509 *x, const ASN1_OBJECT *obj, + int lastpos); + +// X509_get_ext_by_critical behaves like |X509v3_get_ext_by_critical| but +// searches for extensions in |x|. +OPENSSL_EXPORT int X509_get_ext_by_critical(const X509 *x, int crit, + int lastpos); + +// X509_get_ext returns the extension in |x| at index |loc|, or NULL if |loc| is +// out of bounds. This function returns a non-const pointer for OpenSSL +// compatibility, but callers should not mutate the result. +OPENSSL_EXPORT X509_EXTENSION *X509_get_ext(const X509 *x, int loc); + // X509_get0_tbs_sigalg returns the signature algorithm in |x509|'s // TBSCertificate. For the outer signature algorithm, see |X509_get0_signature|. // @@ -305,6 +327,20 @@ OPENSSL_EXPORT int X509_set_subject_name(X509 *x509, X509_NAME *name); // internally copies and updates reference counts as needed. OPENSSL_EXPORT int X509_set_pubkey(X509 *x509, EVP_PKEY *pkey); +// X509_delete_ext removes the extension in |x| at index |loc| and returns the +// removed extension, or NULL if |loc| was out of bounds. If non-NULL, the +// caller must release the result with |X509_EXTENSION_free|. +OPENSSL_EXPORT X509_EXTENSION *X509_delete_ext(X509 *x, int loc); + +// X509_add_ext adds a copy of |ex| to |x|. It returns one on success and zero +// on failure. The caller retains ownership of |ex| and can release it +// independently of |x|. +// +// The new extension is inserted at index |loc|, shifting extensions to the +// right. If |loc| is -1 or out of bounds, the new extension is appended to the +// list. +OPENSSL_EXPORT int X509_add_ext(X509 *x, const X509_EXTENSION *ex, int loc); + // X509_sign signs |x509| with |pkey| and replaces the signature algorithm and // signature fields. It returns one on success and zero on error. This function // uses digest algorithm |md|, or |pkey|'s default if NULL. Other signing @@ -493,6 +529,29 @@ OPENSSL_EXPORT STACK_OF(X509_REVOKED) *X509_CRL_get_REVOKED(X509_CRL *crl); OPENSSL_EXPORT const STACK_OF(X509_EXTENSION) *X509_CRL_get0_extensions( const X509_CRL *crl); +// X509_CRL_get_ext_count returns the number of extensions in |x|. +OPENSSL_EXPORT int X509_CRL_get_ext_count(const X509_CRL *x); + +// X509_CRL_get_ext_by_NID behaves like |X509v3_get_ext_by_NID| but searches for +// extensions in |x|. +OPENSSL_EXPORT int X509_CRL_get_ext_by_NID(const X509_CRL *x, int nid, + int lastpos); + +// X509_CRL_get_ext_by_OBJ behaves like |X509v3_get_ext_by_OBJ| but searches for +// extensions in |x|. +OPENSSL_EXPORT int X509_CRL_get_ext_by_OBJ(const X509_CRL *x, + const ASN1_OBJECT *obj, int lastpos); + +// X509_CRL_get_ext_by_critical behaves like |X509v3_get_ext_by_critical| but +// searches for extensions in |x|. +OPENSSL_EXPORT int X509_CRL_get_ext_by_critical(const X509_CRL *x, int crit, + int lastpos); + +// X509_CRL_get_ext returns the extension in |x| at index |loc|, or NULL if +// |loc| is out of bounds. This function returns a non-const pointer for OpenSSL +// compatibility, but callers should not mutate the result. +OPENSSL_EXPORT X509_EXTENSION *X509_CRL_get_ext(const X509_CRL *x, int loc); + // X509_CRL_get0_signature sets |*out_sig| and |*out_alg| to the signature and // signature algorithm of |crl|, respectively. Either output pointer may be NULL // to ignore the value. @@ -550,6 +609,21 @@ OPENSSL_EXPORT int X509_CRL_set1_lastUpdate(X509_CRL *crl, const ASN1_TIME *tm); // on success and zero on error. OPENSSL_EXPORT int X509_CRL_set1_nextUpdate(X509_CRL *crl, const ASN1_TIME *tm); +// X509_CRL_delete_ext removes the extension in |x| at index |loc| and returns +// the removed extension, or NULL if |loc| was out of bounds. If non-NULL, the +// caller must release the result with |X509_EXTENSION_free|. +OPENSSL_EXPORT X509_EXTENSION *X509_CRL_delete_ext(X509_CRL *x, int loc); + +// X509_CRL_add_ext adds a copy of |ex| to |x|. It returns one on success and +// zero on failure. The caller retains ownership of |ex| and can release it +// independently of |x|. +// +// The new extension is inserted at index |loc|, shifting extensions to the +// right. If |loc| is -1 or out of bounds, the new extension is appended to the +// list. +OPENSSL_EXPORT int X509_CRL_add_ext(X509_CRL *x, const X509_EXTENSION *ex, + int loc); + // X509_CRL_sign signs |crl| with |pkey| and replaces the signature algorithm // and signature fields. It returns one on success and zero on error. This // function uses digest algorithm |md|, or |pkey|'s default if NULL. Other @@ -979,6 +1053,164 @@ OPENSSL_EXPORT X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_txt( int len); +// Extensions. +// +// X.509 certificates and CRLs may contain a list of extensions (RFC 5280). +// Extensions have a type, specified by an object identifier (|ASN1_OBJECT|) and +// a byte string value, which should a DER-encoded structure whose type is +// determined by the extension type. This library represents extensions with the +// |X509_EXTENSION| type. + +// X509_EXTENSION is an |ASN1_ITEM| whose ASN.1 type is X.509 Extension (RFC +// 5280) and C type is |X509_EXTENSION*|. +DECLARE_ASN1_ITEM(X509_EXTENSION) + +// X509_EXTENSION_new returns a newly-allocated, empty |X509_EXTENSION| object +// or NULL on error. +OPENSSL_EXPORT X509_EXTENSION *X509_EXTENSION_new(void); + +// X509_EXTENSION_free releases memory associated with |ex|. +OPENSSL_EXPORT void X509_EXTENSION_free(X509_EXTENSION *ex); + +// d2i_X509_EXTENSION parses up to |len| bytes from |*inp| as a DER-encoded +// X.509 Extension (RFC 5280), as described in |d2i_SAMPLE_with_reuse|. +OPENSSL_EXPORT X509_EXTENSION *d2i_X509_EXTENSION(X509_EXTENSION **out, + const uint8_t **inp, + long len); + +// i2d_X509_EXTENSION marshals |alg| as a DER-encoded X.509 Extension (RFC +// 5280), as described in |i2d_SAMPLE|. +OPENSSL_EXPORT int i2d_X509_EXTENSION(const X509_EXTENSION *alg, + uint8_t **outp); + +// X509_EXTENSION_dup returns a newly-allocated copy of |ex|, or NULL on error. +// This function works by serializing the structure, so if |ex| is incomplete, +// it may fail. +OPENSSL_EXPORT X509_EXTENSION *X509_EXTENSION_dup(const X509_EXTENSION *ex); + +// X509_EXTENSION_create_by_NID creates a new |X509_EXTENSION| with type |nid|, +// value |data|, and critical bit |crit|. It returns an |X509_EXTENSION| on +// success, and NULL on error. |nid| should be a |NID_*| constant. +// +// If |ex| and |*ex| are both non-NULL, |*ex| is used to hold the result, +// otherwise a new object is allocated. If |ex| is non-NULL and |*ex| is NULL, +// the function sets |*ex| to point to the newly allocated result, in addition +// to returning the result. +OPENSSL_EXPORT X509_EXTENSION *X509_EXTENSION_create_by_NID( + X509_EXTENSION **ex, int nid, int crit, const ASN1_OCTET_STRING *data); + +// X509_EXTENSION_create_by_OBJ behaves like |X509_EXTENSION_create_by_NID|, but +// the extension type is determined by an |ASN1_OBJECT|. +OPENSSL_EXPORT X509_EXTENSION *X509_EXTENSION_create_by_OBJ( + X509_EXTENSION **ex, const ASN1_OBJECT *obj, int crit, + const ASN1_OCTET_STRING *data); + +// X509_EXTENSION_get_object returns |ex|'s extension type. This function +// returns a non-const pointer for OpenSSL compatibility, but callers should not +// mutate the result. +OPENSSL_EXPORT ASN1_OBJECT *X509_EXTENSION_get_object(const X509_EXTENSION *ex); + +// X509_EXTENSION_get_data returns |ne|'s extension value. This function returns +// a non-const pointer for OpenSSL compatibility, but callers should not mutate +// the result. +OPENSSL_EXPORT ASN1_OCTET_STRING *X509_EXTENSION_get_data( + const X509_EXTENSION *ne); + +// X509_EXTENSION_get_critical returns one if |ex| is critical and zero +// otherwise. +OPENSSL_EXPORT int X509_EXTENSION_get_critical(const X509_EXTENSION *ex); + +// X509_EXTENSION_set_object sets |ex|'s extension type to |obj|. It returns one +// on success and zero on error. +OPENSSL_EXPORT int X509_EXTENSION_set_object(X509_EXTENSION *ex, + const ASN1_OBJECT *obj); + +// X509_EXTENSION_set_critical sets |ex| to critical if |crit| is non-zero and +// to non-critical if |crit| is zero. +OPENSSL_EXPORT int X509_EXTENSION_set_critical(X509_EXTENSION *ex, int crit); + +// X509_EXTENSION_set_data set's |ex|'s extension value to a copy of |data|. It +// returns one on success and zero on error. +OPENSSL_EXPORT int X509_EXTENSION_set_data(X509_EXTENSION *ex, + const ASN1_OCTET_STRING *data); + + +// Extension lists. +// +// The following functions manipulate lists of extensions. Most of them have +// corresponding functions on the containing |X509|, |X509_CRL|, or +// |X509_REVOKED|. + +DEFINE_STACK_OF(X509_EXTENSION) +typedef STACK_OF(X509_EXTENSION) X509_EXTENSIONS; + +// X509_EXTENSIONS is an |ASN1_ITEM| whose ASN.1 type is SEQUENCE of Extension +// (RFC 5280) and C type is |STACK_OF(X509_EXTENSION)*|. +DECLARE_ASN1_ITEM(X509_EXTENSIONS) + +// d2i_X509_EXTENSIONS parses up to |len| bytes from |*inp| as a DER-encoded +// SEQUENCE OF Extension (RFC 5280), as described in |d2i_SAMPLE_with_reuse|. +OPENSSL_EXPORT X509_EXTENSIONS *d2i_X509_EXTENSIONS(X509_EXTENSIONS **out, + const uint8_t **inp, + long len); + +// i2d_X509_EXTENSIONS marshals |alg| as a DER-encoded SEQUENCE OF Extension +// (RFC 5280), as described in |i2d_SAMPLE|. +OPENSSL_EXPORT int i2d_X509_EXTENSIONS(const X509_EXTENSIONS *alg, + uint8_t **outp); + +// X509v3_get_ext_count returns the number of extensions in |x|. +OPENSSL_EXPORT int X509v3_get_ext_count(const STACK_OF(X509_EXTENSION) *x); + +// X509v3_get_ext_by_NID returns the index of the first extension in |x| with +// type |nid|, or a negative number if not found. If found, callers can use +// |X509v3_get_ext| to look up the extension by index. +// +// If |lastpos| is non-negative, it begins searching at |lastpos| + 1. Callers +// can thus loop over all matching extensions by first passing -1 and then +// passing the previously-returned value until no match is returned. +OPENSSL_EXPORT int X509v3_get_ext_by_NID(const STACK_OF(X509_EXTENSION) *x, + int nid, int lastpos); + +// X509v3_get_ext_by_OBJ behaves like |X509v3_get_ext_by_NID| but looks for +// extensions matching |obj|. +OPENSSL_EXPORT int X509v3_get_ext_by_OBJ(const STACK_OF(X509_EXTENSION) *x, + const ASN1_OBJECT *obj, int lastpos); + +// X509v3_get_ext_by_critical returns the index of the first extension in |x| +// whose critical bit matches |crit|, or a negative number if no such extension +// was found. +// +// If |lastpos| is non-negative, it begins searching at |lastpos| + 1. Callers +// can thus loop over all matching extensions by first passing -1 and then +// passing the previously-returned value until no match is returned. +OPENSSL_EXPORT int X509v3_get_ext_by_critical(const STACK_OF(X509_EXTENSION) *x, + int crit, int lastpos); + +// X509v3_get_ext returns the extension in |x| at index |loc|, or NULL if |loc| +// is out of bounds. This function returns a non-const pointer for OpenSSL +// compatibility, but callers should not mutate the result. +OPENSSL_EXPORT X509_EXTENSION *X509v3_get_ext(const STACK_OF(X509_EXTENSION) *x, + int loc); + +// X509v3_delete_ext removes the extension in |x| at index |loc| and returns the +// removed extension, or NULL if |loc| was out of bounds. If an extension was +// returned, the caller must release it with |X509_EXTENSION_free|. +OPENSSL_EXPORT X509_EXTENSION *X509v3_delete_ext(STACK_OF(X509_EXTENSION) *x, + int loc); + +// X509v3_add_ext adds a copy of |ex| to the extension list in |*x|. If |*x| is +// NULL, it allocates a new |STACK_OF(X509_EXTENSION)| to hold the copy and sets +// |*x| to the new list. It returns |*x| on success and NULL on error. The +// caller retains ownership of |ex| and can release it independently of |*x|. +// +// The new extension is inserted at index |loc|, shifting extensions to the +// right. If |loc| is -1 or out of bounds, the new extension is appended to the +// list. +OPENSSL_EXPORT STACK_OF(X509_EXTENSION) *X509v3_add_ext( + STACK_OF(X509_EXTENSION) **x, const X509_EXTENSION *ex, int loc); + + // Algorithm identifiers. // // An |X509_ALGOR| represents an AlgorithmIdentifier structure, used in X.509 @@ -1333,10 +1565,6 @@ struct X509_algor_st { #define X509v3_KU_DECIPHER_ONLY 0x8000 #define X509v3_KU_UNDEF 0xffff -typedef STACK_OF(X509_EXTENSION) X509_EXTENSIONS; - -DEFINE_STACK_OF(X509_EXTENSION) - DEFINE_STACK_OF(X509_ATTRIBUTE) // This stuff is certificate "auxiliary info" @@ -1585,11 +1813,6 @@ OPENSSL_EXPORT int NETSCAPE_SPKI_sign(NETSCAPE_SPKI *spki, EVP_PKEY *pkey, // it may fail. OPENSSL_EXPORT X509_ATTRIBUTE *X509_ATTRIBUTE_dup(const X509_ATTRIBUTE *xa); -// X509_EXTENSION_dup returns a newly-allocated copy of |ex|, or NULL on error. -// This function works by serializing the structure, so if |ex| is incomplete, -// it may fail. -OPENSSL_EXPORT X509_EXTENSION *X509_EXTENSION_dup(const X509_EXTENSION *ex); - // X509_REVOKED_dup returns a newly-allocated copy of |rev|, or NULL on error. // This function works by serializing the structure, so if |rev| is incomplete, // it may fail. @@ -1651,9 +1874,6 @@ DECLARE_ASN1_FUNCTIONS_const(X509_ATTRIBUTE) OPENSSL_EXPORT X509_ATTRIBUTE *X509_ATTRIBUTE_create(int nid, int attrtype, void *value); -DECLARE_ASN1_FUNCTIONS_const(X509_EXTENSION) -DECLARE_ASN1_ENCODE_FUNCTIONS_const(X509_EXTENSIONS, X509_EXTENSIONS) - OPENSSL_EXPORT int X509_add1_trust_object(X509 *x, ASN1_OBJECT *obj); OPENSSL_EXPORT int X509_add1_reject_object(X509 *x, ASN1_OBJECT *obj); OPENSSL_EXPORT void X509_trust_clear(X509 *x); @@ -1860,94 +2080,6 @@ OPENSSL_EXPORT int X509_REQ_print_ex(BIO *bp, X509_REQ *x, unsigned long nmflag, unsigned long cflag); OPENSSL_EXPORT int X509_REQ_print(BIO *bp, X509_REQ *req); -// X509v3_get_ext_count returns the number of extensions in |x|. -OPENSSL_EXPORT int X509v3_get_ext_count(const STACK_OF(X509_EXTENSION) *x); - -// X509v3_get_ext_by_NID returns the index of the first extension in |x| with -// type |nid|, or a negative number if not found. If found, callers can use -// |X509v3_get_ext| to look up the extension by index. -// -// If |lastpos| is non-negative, it begins searching at |lastpos| + 1. Callers -// can thus loop over all matching extensions by first passing -1 and then -// passing the previously-returned value until no match is returned. -OPENSSL_EXPORT int X509v3_get_ext_by_NID(const STACK_OF(X509_EXTENSION) *x, - int nid, int lastpos); - -// X509v3_get_ext_by_OBJ behaves like |X509v3_get_ext_by_NID| but looks for -// extensions matching |obj|. -OPENSSL_EXPORT int X509v3_get_ext_by_OBJ(const STACK_OF(X509_EXTENSION) *x, - const ASN1_OBJECT *obj, int lastpos); - -// X509v3_get_ext_by_critical returns the index of the first extension in |x| -// whose critical bit matches |crit|, or a negative number if no such extension -// was found. -// -// If |lastpos| is non-negative, it begins searching at |lastpos| + 1. Callers -// can thus loop over all matching extensions by first passing -1 and then -// passing the previously-returned value until no match is returned. -OPENSSL_EXPORT int X509v3_get_ext_by_critical(const STACK_OF(X509_EXTENSION) *x, - int crit, int lastpos); - -// X509v3_get_ext returns the extension in |x| at index |loc|, or NULL if |loc| -// is out of bounds. This function returns a non-const pointer for OpenSSL -// compatibility, but callers should not mutate the result. -OPENSSL_EXPORT X509_EXTENSION *X509v3_get_ext(const STACK_OF(X509_EXTENSION) *x, - int loc); - -// X509v3_delete_ext removes the extension in |x| at index |loc| and returns the -// removed extension, or NULL if |loc| was out of bounds. If an extension was -// returned, the caller must release it with |X509_EXTENSION_free|. -OPENSSL_EXPORT X509_EXTENSION *X509v3_delete_ext(STACK_OF(X509_EXTENSION) *x, - int loc); - -// X509v3_add_ext adds a copy of |ex| to the extension list in |*x|. If |*x| is -// NULL, it allocates a new |STACK_OF(X509_EXTENSION)| to hold the copy and sets -// |*x| to the new list. It returns |*x| on success and NULL on error. The -// caller retains ownership of |ex| and can release it independently of |*x|. -// -// The new extension is inserted at index |loc|, shifting extensions to the -// right. If |loc| is -1 or out of bounds, the new extension is appended to the -// list. -OPENSSL_EXPORT STACK_OF(X509_EXTENSION) *X509v3_add_ext( - STACK_OF(X509_EXTENSION) **x, const X509_EXTENSION *ex, int loc); - -// X509_get_ext_count returns the number of extensions in |x|. -OPENSSL_EXPORT int X509_get_ext_count(const X509 *x); - -// X509_get_ext_by_NID behaves like |X509v3_get_ext_by_NID| but searches for -// extensions in |x|. -OPENSSL_EXPORT int X509_get_ext_by_NID(const X509 *x, int nid, int lastpos); - -// X509_get_ext_by_OBJ behaves like |X509v3_get_ext_by_OBJ| but searches for -// extensions in |x|. -OPENSSL_EXPORT int X509_get_ext_by_OBJ(const X509 *x, const ASN1_OBJECT *obj, - int lastpos); - -// X509_get_ext_by_critical behaves like |X509v3_get_ext_by_critical| but -// searches for extensions in |x|. -OPENSSL_EXPORT int X509_get_ext_by_critical(const X509 *x, int crit, - int lastpos); - -// X509_get_ext returns the extension in |x| at index |loc|, or NULL if |loc| is -// out of bounds. This function returns a non-const pointer for OpenSSL -// compatibility, but callers should not mutate the result. -OPENSSL_EXPORT X509_EXTENSION *X509_get_ext(const X509 *x, int loc); - -// X509_delete_ext removes the extension in |x| at index |loc| and returns the -// removed extension, or NULL if |loc| was out of bounds. If non-NULL, the -// caller must release the result with |X509_EXTENSION_free|. It is also safe, -// but not necessary, to call |X509_EXTENSION_free| if the result is NULL. -OPENSSL_EXPORT X509_EXTENSION *X509_delete_ext(X509 *x, int loc); - -// X509_add_ext adds a copy of |ex| to |x|. It returns one on success and zero -// on failure. The caller retains ownership of |ex| and can release it -// independently of |x|. -// -// The new extension is inserted at index |loc|, shifting extensions to the -// right. If |loc| is -1 or out of bounds, the new extension is appended to the -// list. -OPENSSL_EXPORT int X509_add_ext(X509 *x, const X509_EXTENSION *ex, int loc); - // X509_get_ext_d2i behaves like |X509V3_get_d2i| but looks for the extension in // |x509|'s extension list. // @@ -1965,45 +2097,6 @@ OPENSSL_EXPORT void *X509_get_ext_d2i(const X509 *x509, int nid, OPENSSL_EXPORT int X509_add1_ext_i2d(X509 *x, int nid, void *value, int crit, unsigned long flags); -// X509_CRL_get_ext_count returns the number of extensions in |x|. -OPENSSL_EXPORT int X509_CRL_get_ext_count(const X509_CRL *x); - -// X509_CRL_get_ext_by_NID behaves like |X509v3_get_ext_by_NID| but searches for -// extensions in |x|. -OPENSSL_EXPORT int X509_CRL_get_ext_by_NID(const X509_CRL *x, int nid, - int lastpos); - -// X509_CRL_get_ext_by_OBJ behaves like |X509v3_get_ext_by_OBJ| but searches for -// extensions in |x|. -OPENSSL_EXPORT int X509_CRL_get_ext_by_OBJ(const X509_CRL *x, - const ASN1_OBJECT *obj, int lastpos); - -// X509_CRL_get_ext_by_critical behaves like |X509v3_get_ext_by_critical| but -// searches for extensions in |x|. -OPENSSL_EXPORT int X509_CRL_get_ext_by_critical(const X509_CRL *x, int crit, - int lastpos); - -// X509_CRL_get_ext returns the extension in |x| at index |loc|, or NULL if -// |loc| is out of bounds. This function returns a non-const pointer for OpenSSL -// compatibility, but callers should not mutate the result. -OPENSSL_EXPORT X509_EXTENSION *X509_CRL_get_ext(const X509_CRL *x, int loc); - -// X509_CRL_delete_ext removes the extension in |x| at index |loc| and returns -// the removed extension, or NULL if |loc| was out of bounds. If non-NULL, the -// caller must release the result with |X509_EXTENSION_free|. It is also safe, -// but not necessary, to call |X509_EXTENSION_free| if the result is NULL. -OPENSSL_EXPORT X509_EXTENSION *X509_CRL_delete_ext(X509_CRL *x, int loc); - -// X509_CRL_add_ext adds a copy of |ex| to |x|. It returns one on success and -// zero on failure. The caller retains ownership of |ex| and can release it -// independently of |x|. -// -// The new extension is inserted at index |loc|, shifting extensions to the -// right. If |loc| is -1 or out of bounds, the new extension is appended to the -// list. -OPENSSL_EXPORT int X509_CRL_add_ext(X509_CRL *x, const X509_EXTENSION *ex, - int loc); - // X509_CRL_get_ext_d2i behaves like |X509V3_get_d2i| but looks for the // extension in |crl|'s extension list. // @@ -2048,9 +2141,7 @@ OPENSSL_EXPORT X509_EXTENSION *X509_REVOKED_get_ext(const X509_REVOKED *x, // X509_REVOKED_delete_ext removes the extension in |x| at index |loc| and // returns the removed extension, or NULL if |loc| was out of bounds. If -// non-NULL, the caller must release the result with |X509_EXTENSION_free|. It -// is also safe, but not necessary, to call |X509_EXTENSION_free| if the result -// is NULL. +// non-NULL, the caller must release the result with |X509_EXTENSION_free|. OPENSSL_EXPORT X509_EXTENSION *X509_REVOKED_delete_ext(X509_REVOKED *x, int loc); @@ -2083,52 +2174,6 @@ OPENSSL_EXPORT int X509_REVOKED_add1_ext_i2d(X509_REVOKED *x, int nid, void *value, int crit, unsigned long flags); -// X509_EXTENSION_create_by_NID creates a new |X509_EXTENSION| with type |nid|, -// value |data|, and critical bit |crit|. It returns the newly-allocated -// |X509_EXTENSION| on success, and false on error. |nid| should be a |NID_*| -// constant. -// -// If |ex| and |*ex| are both non-NULL, it modifies and returns |*ex| instead of -// creating a new object. If |ex| is non-NULL, but |*ex| is NULL, it sets |*ex| -// to the new |X509_EXTENSION|, in addition to returning the result. -OPENSSL_EXPORT X509_EXTENSION *X509_EXTENSION_create_by_NID( - X509_EXTENSION **ex, int nid, int crit, const ASN1_OCTET_STRING *data); - -// X509_EXTENSION_create_by_OBJ behaves like |X509_EXTENSION_create_by_NID|, but -// the extension type is determined by an |ASN1_OBJECT|. -OPENSSL_EXPORT X509_EXTENSION *X509_EXTENSION_create_by_OBJ( - X509_EXTENSION **ex, const ASN1_OBJECT *obj, int crit, - const ASN1_OCTET_STRING *data); - -// X509_EXTENSION_set_object sets |ex|'s extension type to |obj|. It returns one -// on success and zero on error. -OPENSSL_EXPORT int X509_EXTENSION_set_object(X509_EXTENSION *ex, - const ASN1_OBJECT *obj); - -// X509_EXTENSION_set_critical sets |ex| to critical if |crit| is non-zero and -// to non-critical if |crit| is zero. -OPENSSL_EXPORT int X509_EXTENSION_set_critical(X509_EXTENSION *ex, int crit); - -// X509_EXTENSION_set_data set's |ex|'s extension value to a copy of |data|. It -// returns one on success and zero on error. -OPENSSL_EXPORT int X509_EXTENSION_set_data(X509_EXTENSION *ex, - const ASN1_OCTET_STRING *data); - -// X509_EXTENSION_get_object returns |ex|'s extension type. This function -// returns a non-const pointer for OpenSSL compatibility, but callers should not -// mutate the result. -OPENSSL_EXPORT ASN1_OBJECT *X509_EXTENSION_get_object(const X509_EXTENSION *ex); - -// X509_EXTENSION_get_data returns |ne|'s extension value. This function returns -// a non-const pointer for OpenSSL compatibility, but callers should not mutate -// the result. -OPENSSL_EXPORT ASN1_OCTET_STRING *X509_EXTENSION_get_data( - const X509_EXTENSION *ne); - -// X509_EXTENSION_get_critical returns one if |ex| is critical and zero -// otherwise. -OPENSSL_EXPORT int X509_EXTENSION_get_critical(const X509_EXTENSION *ex); - // X509at_get_attr_count returns the number of attributes in |x|. OPENSSL_EXPORT int X509at_get_attr_count(const STACK_OF(X509_ATTRIBUTE) *x); From dfddbc4ded0df5fdc7263384ab833562d2e67105 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Mon, 18 Jul 2022 16:08:06 -0400 Subject: [PATCH 33/38] Align with OpenSSL on TLS 1.3 cipher suite constants. Our TLS 1.3 stack predates OpenSSL's. We chose TLS1_CK_* to align with the existing names. OpenSSL made a new convention, TLS1_3_CK_*. Match them. This means that, in the likely event that TLS 1.4 uses the same constants, they'll have weird names, just as several of our constants still say SSL3_* but it doesn't particularly matter. Change-Id: I97f29b224d0d282e946344e4b907f2df2be39ce1 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/53425 Auto-Submit: David Benjamin Commit-Queue: David Benjamin Commit-Queue: Bob Beck Reviewed-by: Bob Beck --- include/openssl/tls1.h | 12 +++++++++--- ssl/handshake_client.cc | 10 +++++----- ssl/handshake_server.cc | 2 +- ssl/s3_both.cc | 6 +++--- ssl/ssl_cipher.cc | 6 +++--- ssl/ssl_test.cc | 6 +++--- 6 files changed, 24 insertions(+), 18 deletions(-) diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h index a3136c0d35..d55d905aa0 100644 --- a/include/openssl/tls1.h +++ b/include/openssl/tls1.h @@ -452,9 +452,15 @@ extern "C" { #define TLS1_CK_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 0x0300CCAC // TLS 1.3 ciphersuites from RFC 8446. -#define TLS1_CK_AES_128_GCM_SHA256 0x03001301 -#define TLS1_CK_AES_256_GCM_SHA384 0x03001302 -#define TLS1_CK_CHACHA20_POLY1305_SHA256 0x03001303 +#define TLS1_3_CK_AES_128_GCM_SHA256 0x03001301 +#define TLS1_3_CK_AES_256_GCM_SHA384 0x03001302 +#define TLS1_3_CK_CHACHA20_POLY1305_SHA256 0x03001303 + +// The following constants are legacy aliases of |TLS1_3_CK_*|. +// TODO(davidben): Migrate callers to the new name and remove these. +#define TLS1_CK_AES_128_GCM_SHA256 TLS1_3_CK_AES_128_GCM_SHA256 +#define TLS1_CK_AES_256_GCM_SHA384 TLS1_3_CK_AES_256_GCM_SHA384 +#define TLS1_CK_CHACHA20_POLY1305_SHA256 TLS1_3_CK_CHACHA20_POLY1305_SHA256 // XXX // Inconsistency alert: diff --git a/ssl/handshake_client.cc b/ssl/handshake_client.cc index bb2462ffb7..636d166429 100644 --- a/ssl/handshake_client.cc +++ b/ssl/handshake_client.cc @@ -236,21 +236,21 @@ static bool ssl_write_client_cipher_list(const SSL_HANDSHAKE *hs, CBB *out, // hardware support. if (hs->max_version >= TLS1_3_VERSION) { const bool include_chacha20 = ssl_tls13_cipher_meets_policy( - TLS1_CK_CHACHA20_POLY1305_SHA256 & 0xffff, + TLS1_3_CK_CHACHA20_POLY1305_SHA256 & 0xffff, ssl->config->only_fips_cipher_suites_in_tls13); if (!EVP_has_aes_hardware() && // include_chacha20 && // - !CBB_add_u16(&child, TLS1_CK_CHACHA20_POLY1305_SHA256 & 0xffff)) { + !CBB_add_u16(&child, TLS1_3_CK_CHACHA20_POLY1305_SHA256 & 0xffff)) { return false; } - if (!CBB_add_u16(&child, TLS1_CK_AES_128_GCM_SHA256 & 0xffff) || - !CBB_add_u16(&child, TLS1_CK_AES_256_GCM_SHA384 & 0xffff)) { + if (!CBB_add_u16(&child, TLS1_3_CK_AES_128_GCM_SHA256 & 0xffff) || + !CBB_add_u16(&child, TLS1_3_CK_AES_256_GCM_SHA384 & 0xffff)) { return false; } if (EVP_has_aes_hardware() && // include_chacha20 && // - !CBB_add_u16(&child, TLS1_CK_CHACHA20_POLY1305_SHA256 & 0xffff)) { + !CBB_add_u16(&child, TLS1_3_CK_CHACHA20_POLY1305_SHA256 & 0xffff)) { return false; } } diff --git a/ssl/handshake_server.cc b/ssl/handshake_server.cc index 7678904dff..4a2ada0df2 100644 --- a/ssl/handshake_server.cc +++ b/ssl/handshake_server.cc @@ -411,7 +411,7 @@ static bool is_probably_jdk11_with_tls13(const SSL_CLIENT_HELLO *client_hello) { // JDK 11 does not support ChaCha20-Poly1305. This is unusual: many modern // clients implement ChaCha20-Poly1305. if (ssl_client_cipher_list_contains_cipher( - client_hello, TLS1_CK_CHACHA20_POLY1305_SHA256 & 0xffff)) { + client_hello, TLS1_3_CK_CHACHA20_POLY1305_SHA256 & 0xffff)) { return false; } diff --git a/ssl/s3_both.cc b/ssl/s3_both.cc index d0fc6c04ea..cb831f2e9e 100644 --- a/ssl/s3_both.cc +++ b/ssl/s3_both.cc @@ -697,10 +697,10 @@ bool ssl_tls13_cipher_meets_policy(uint16_t cipher_id, bool only_fips) { } switch (cipher_id) { - case TLS1_CK_AES_128_GCM_SHA256 & 0xffff: - case TLS1_CK_AES_256_GCM_SHA384 & 0xffff: + case TLS1_3_CK_AES_128_GCM_SHA256 & 0xffff: + case TLS1_3_CK_AES_256_GCM_SHA384 & 0xffff: return true; - case TLS1_CK_CHACHA20_POLY1305_SHA256 & 0xffff: + case TLS1_3_CK_CHACHA20_POLY1305_SHA256 & 0xffff: return false; default: assert(false); diff --git a/ssl/ssl_cipher.cc b/ssl/ssl_cipher.cc index 628dddc860..79f33ee8c7 100644 --- a/ssl/ssl_cipher.cc +++ b/ssl/ssl_cipher.cc @@ -266,7 +266,7 @@ static constexpr SSL_CIPHER kCiphers[] = { { TLS1_TXT_AES_128_GCM_SHA256, "TLS_AES_128_GCM_SHA256", - TLS1_CK_AES_128_GCM_SHA256, + TLS1_3_CK_AES_128_GCM_SHA256, SSL_kGENERIC, SSL_aGENERIC, SSL_AES128GCM, @@ -278,7 +278,7 @@ static constexpr SSL_CIPHER kCiphers[] = { { TLS1_TXT_AES_256_GCM_SHA384, "TLS_AES_256_GCM_SHA384", - TLS1_CK_AES_256_GCM_SHA384, + TLS1_3_CK_AES_256_GCM_SHA384, SSL_kGENERIC, SSL_aGENERIC, SSL_AES256GCM, @@ -290,7 +290,7 @@ static constexpr SSL_CIPHER kCiphers[] = { { TLS1_TXT_CHACHA20_POLY1305_SHA256, "TLS_CHACHA20_POLY1305_SHA256", - TLS1_CK_CHACHA20_POLY1305_SHA256, + TLS1_3_CK_CHACHA20_POLY1305_SHA256, SSL_kGENERIC, SSL_aGENERIC, SSL_CHACHA20POLY1305, diff --git a/ssl/ssl_test.cc b/ssl/ssl_test.cc index a40de7914f..fe85840d55 100644 --- a/ssl/ssl_test.cc +++ b/ssl/ssl_test.cc @@ -1002,7 +1002,7 @@ TEST(SSLTest, CipherProperties) { NID_sha256, }, { - TLS1_CK_AES_256_GCM_SHA384, + TLS1_3_CK_AES_256_GCM_SHA384, "TLS_AES_256_GCM_SHA384", NID_aes_256_gcm, NID_undef, @@ -1011,7 +1011,7 @@ TEST(SSLTest, CipherProperties) { NID_sha384, }, { - TLS1_CK_AES_128_GCM_SHA256, + TLS1_3_CK_AES_128_GCM_SHA256, "TLS_AES_128_GCM_SHA256", NID_aes_128_gcm, NID_undef, @@ -1020,7 +1020,7 @@ TEST(SSLTest, CipherProperties) { NID_sha256, }, { - TLS1_CK_CHACHA20_POLY1305_SHA256, + TLS1_3_CK_CHACHA20_POLY1305_SHA256, "TLS_CHACHA20_POLY1305_SHA256", NID_chacha20_poly1305, NID_undef, From a6981a3383c9905a732aab87778326817859cec1 Mon Sep 17 00:00:00 2001 From: Bob Beck Date: Tue, 19 Jul 2022 09:20:50 -0600 Subject: [PATCH 34/38] More alignment with OpenSSL on TLS 1.3 cipher suite constants. Our TLS 1.3 stack predates OpenSSL's. We chose TLS1_TXT_* to align with the existing names. OpenSSL made a new convention, TLS1_3_RFC_*. Match them. Similar to 53425 Change-Id: I8737d98c9c1d5c201c4726739ddcbe96123d9370 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/53445 Commit-Queue: Bob Beck Reviewed-by: David Benjamin --- include/openssl/tls1.h | 11 ++++++++--- ssl/ssl_cipher.cc | 6 +++--- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h index d55d905aa0..724d580257 100644 --- a/include/openssl/tls1.h +++ b/include/openssl/tls1.h @@ -630,10 +630,15 @@ extern "C" { "ECDHE-PSK-CHACHA20-POLY1305" // TLS 1.3 ciphersuites from RFC 8446. -#define TLS1_TXT_AES_128_GCM_SHA256 "TLS_AES_128_GCM_SHA256" -#define TLS1_TXT_AES_256_GCM_SHA384 "TLS_AES_256_GCM_SHA384" -#define TLS1_TXT_CHACHA20_POLY1305_SHA256 "TLS_CHACHA20_POLY1305_SHA256" +#define TLS1_3_RFC_AES_128_GCM_SHA256 "TLS_AES_128_GCM_SHA256" +#define TLS1_3_RFC_AES_256_GCM_SHA384 "TLS_AES_256_GCM_SHA384" +#define TLS1_3_RFC_CHACHA20_POLY1305_SHA256 "TLS_CHACHA20_POLY1305_SHA256" +// The following constants are legacy aliases of |TLS1_3_CK_*|. +// TODO(bbe): Migrate callers to the new name and remove these. +#define TLS1_TXT_AES_128_GCM_SHA256 TLS1_3_RFC_AES_128_GCM_SHA256 +#define TLS1_TXT_AES_256_GCM_SHA384 TLS1_3_RFC_AES_256_GCM_SHA384 +#define TLS1_TXT_CHACHA20_POLY1305_SHA256 TLS1_3_RFC_CHACHA20_POLY1305_SHA256 #define TLS_CT_RSA_SIGN 1 #define TLS_CT_DSS_SIGN 2 diff --git a/ssl/ssl_cipher.cc b/ssl/ssl_cipher.cc index 79f33ee8c7..7c4c034acc 100644 --- a/ssl/ssl_cipher.cc +++ b/ssl/ssl_cipher.cc @@ -264,7 +264,7 @@ static constexpr SSL_CIPHER kCiphers[] = { // Cipher 1301 { - TLS1_TXT_AES_128_GCM_SHA256, + TLS1_3_RFC_AES_128_GCM_SHA256, "TLS_AES_128_GCM_SHA256", TLS1_3_CK_AES_128_GCM_SHA256, SSL_kGENERIC, @@ -276,7 +276,7 @@ static constexpr SSL_CIPHER kCiphers[] = { // Cipher 1302 { - TLS1_TXT_AES_256_GCM_SHA384, + TLS1_3_RFC_AES_256_GCM_SHA384, "TLS_AES_256_GCM_SHA384", TLS1_3_CK_AES_256_GCM_SHA384, SSL_kGENERIC, @@ -288,7 +288,7 @@ static constexpr SSL_CIPHER kCiphers[] = { // Cipher 1303 { - TLS1_TXT_CHACHA20_POLY1305_SHA256, + TLS1_3_RFC_CHACHA20_POLY1305_SHA256, "TLS_CHACHA20_POLY1305_SHA256", TLS1_3_CK_CHACHA20_POLY1305_SHA256, SSL_kGENERIC, From 1ced57a1bca60559741ff8e21a46879cd081bec3 Mon Sep 17 00:00:00 2001 From: Adam Langley Date: Fri, 15 Jul 2022 15:51:40 -0700 Subject: [PATCH 35/38] Add script to run FIPS break tests. Change-Id: I88bf98f0149e12598839a116f064d7dcfd5c860b Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/53385 Auto-Submit: Adam Langley Reviewed-by: David Benjamin --- util/fipstools/break-tests.sh | 52 +++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 util/fipstools/break-tests.sh diff --git a/util/fipstools/break-tests.sh b/util/fipstools/break-tests.sh new file mode 100644 index 0000000000..1b3b7d978d --- /dev/null +++ b/util/fipstools/break-tests.sh @@ -0,0 +1,52 @@ +# Copyright (c) 2022, Google Inc. +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +# SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION +# OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +# This script runs test_fips repeatedly with different FIPS tests broken. It is +# intended to be observed to demonstrate that the various tests are working and +# thus pauses for a keystroke between tests. + +set -e + +TEST_FIPS_BIN="build/util/fipstools/test_fips" + +if [ ! -f $TEST_FIPS_BIN ]; then + echo "$TEST_FIPS_BIN is missing. Run this script from the top level of a" + echo "BoringSSL checkout and ensure that BoringSSL has been built in" + echo "build/ with -DFIPS_BREAK_TEST=TESTS passed to CMake." + exit 1 +fi + +KATS=$(go run util/fipstools/break-kat.go --list-tests) + +echo -e '\033[1mNormal output\033[0m' +$TEST_FIPS_BIN +read + +echo +echo -e '\033[1mIntegrity test failure\033[0m' +go run util/fipstools/break-hash.go $TEST_FIPS_BIN break-bin +chmod u+x ./break-bin +./break-bin || true +rm ./break-bin +read + +for kat in $KATS; do + echo + echo -e "\033[1mKAT failure ${kat}\033[0m" + go run util/fipstools/break-kat.go $TEST_FIPS_BIN $kat > break-bin + chmod u+x ./break-bin + ./break-bin || true + rm ./break-bin + read +done From b95124305ab15c7523d3e21437309fa5dd717ee8 Mon Sep 17 00:00:00 2001 From: Bob Beck Date: Tue, 19 Jul 2022 14:47:58 -0600 Subject: [PATCH 36/38] Mostly Revert 52426 - Drop AVCP support for 3DES Support is still needed for ACVP until 2023 Change-Id: Ia131a85bc06e7c61c823f1b3c021e2625a8769c4 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/53465 Reviewed-by: Corie Pressley Reviewed-by: Adam Langley Commit-Queue: Bob Beck --- .../acvp/acvptool/subprocess/block.go | 128 ++++++++++++++++++ .../acvp/acvptool/subprocess/subprocess.go | 2 + .../acvptool/test/expected/ACVP-TDES-CBC.bz2 | Bin 0 -> 22159 bytes .../acvptool/test/expected/ACVP-TDES-ECB.bz2 | Bin 0 -> 18121 bytes util/fipstools/acvp/acvptool/test/tests.json | 2 + .../acvptool/test/vectors/ACVP-TDES-CBC.bz2 | Bin 0 -> 1009 bytes .../acvptool/test/vectors/ACVP-TDES-ECB.bz2 | Bin 0 -> 930 bytes 7 files changed, 132 insertions(+) create mode 100644 util/fipstools/acvp/acvptool/test/expected/ACVP-TDES-CBC.bz2 create mode 100644 util/fipstools/acvp/acvptool/test/expected/ACVP-TDES-ECB.bz2 create mode 100644 util/fipstools/acvp/acvptool/test/vectors/ACVP-TDES-CBC.bz2 create mode 100644 util/fipstools/acvp/acvptool/test/vectors/ACVP-TDES-ECB.bz2 diff --git a/util/fipstools/acvp/acvptool/subprocess/block.go b/util/fipstools/acvp/acvptool/subprocess/block.go index f979c86506..1b1e93b998 100644 --- a/util/fipstools/acvp/acvptool/subprocess/block.go +++ b/util/fipstools/acvp/acvptool/subprocess/block.go @@ -18,6 +18,7 @@ import ( "encoding/hex" "encoding/json" "fmt" + "math/bits" ) // aesKeyShuffle is the "AES Monte Carlo Key Shuffle" from the ACVP @@ -118,6 +119,113 @@ func iterateAESCBC(transact func(n int, args ...[]byte) ([][]byte, error), encry return mctResults } +// xorKeyWithOddParityLSB XORs value into key while setting the LSB of each bit +// to establish odd parity. This embedding of a parity check in a DES key is an +// old tradition and something that NIST's tests require (despite being +// undocumented). +func xorKeyWithOddParityLSB(key, value []byte) { + for i := range key { + v := key[i] ^ value[i] + // Use LSB to establish odd parity. + v ^= byte((bits.OnesCount8(v) & 1)) ^ 1 + key[i] = v + } +} + +// desKeyShuffle implements the manipulation of the Key arrays in the "TDES +// Monte Carlo Test - ECB mode" algorithm from the ACVP specification. +func keyShuffle3DES(key, result, prevResult, prevPrevResult []byte) { + xorKeyWithOddParityLSB(key[:8], result) + xorKeyWithOddParityLSB(key[8:16], prevResult) + xorKeyWithOddParityLSB(key[16:], prevPrevResult) +} + +// iterate3DES implements "TDES Monte Carlo Test - ECB mode" from the ACVP +// specification. +func iterate3DES(transact func(n int, args ...[]byte) ([][]byte, error), encrypt bool, key, input, iv []byte) (mctResults []blockCipherMCTResult) { + for i := 0; i < 400; i++ { + var iteration blockCipherMCTResult + keyHex := hex.EncodeToString(key) + iteration.Key1Hex = keyHex[:16] + iteration.Key2Hex = keyHex[16:32] + iteration.Key3Hex = keyHex[32:] + + if encrypt { + iteration.PlaintextHex = hex.EncodeToString(input) + } else { + iteration.CiphertextHex = hex.EncodeToString(input) + } + + results, err := transact(3, key, input, uint32le(10000)) + if err != nil { + panic("block operation failed") + } + result := results[0] + prevResult := results[1] + prevPrevResult := results[2] + + if encrypt { + iteration.CiphertextHex = hex.EncodeToString(result) + } else { + iteration.PlaintextHex = hex.EncodeToString(result) + } + + keyShuffle3DES(key, result, prevResult, prevPrevResult) + mctResults = append(mctResults, iteration) + input = result + } + + return mctResults +} + +// iterate3DESCBC implements "TDES Monte Carlo Test - CBC mode" from the ACVP +// specification. +func iterate3DESCBC(transact func(n int, args ...[]byte) ([][]byte, error), encrypt bool, key, input, iv []byte) (mctResults []blockCipherMCTResult) { + for i := 0; i < 400; i++ { + var iteration blockCipherMCTResult + keyHex := hex.EncodeToString(key) + iteration.Key1Hex = keyHex[:16] + iteration.Key2Hex = keyHex[16:32] + iteration.Key3Hex = keyHex[32:] + + if encrypt { + iteration.PlaintextHex = hex.EncodeToString(input) + } else { + iteration.CiphertextHex = hex.EncodeToString(input) + } + iteration.IVHex = hex.EncodeToString(iv) + + results, err := transact(3, key, input, iv, uint32le(10000)) + if err != nil { + panic("block operation failed") + } + + result := results[0] + prevResult := results[1] + prevPrevResult := results[2] + + if encrypt { + iteration.CiphertextHex = hex.EncodeToString(result) + } else { + iteration.PlaintextHex = hex.EncodeToString(result) + } + + keyShuffle3DES(key, result, prevResult, prevPrevResult) + + if encrypt { + input = prevResult + iv = result + } else { + iv = prevResult + input = result + } + + mctResults = append(mctResults, iteration) + } + + return mctResults +} + // blockCipher implements an ACVP algorithm by making requests to the subprocess // to encrypt and decrypt with a block cipher. type blockCipher struct { @@ -148,6 +256,11 @@ type blockCipherTestGroup struct { CiphertextHex string `json:"ct"` IVHex string `json:"iv"` KeyHex string `json:"key"` + + // 3DES tests serialise the key differently. + Key1Hex string `json:"key1"` + Key2Hex string `json:"key2"` + Key3Hex string `json:"key3"` } `json:"tests"` } @@ -168,6 +281,11 @@ type blockCipherMCTResult struct { PlaintextHex string `json:"pt"` CiphertextHex string `json:"ct"` IVHex string `json:"iv,omitempty"` + + // 3DES tests serialise the key differently. + Key1Hex string `json:"key1,omitempty"` + Key2Hex string `json:"key2,omitempty"` + Key3Hex string `json:"key3,omitempty"` } func (b *blockCipher) Process(vectorSet []byte, m Transactable) (interface{}, error) { @@ -213,6 +331,11 @@ func (b *blockCipher) Process(vectorSet []byte, m Transactable) (interface{}, er return nil, fmt.Errorf("test group %d has unknown type %q", group.ID, group.Type) } + if group.KeyBits == 0 { + // 3DES tests fail to set this parameter. + group.KeyBits = 192 + } + if group.KeyBits%8 != 0 { return nil, fmt.Errorf("test group %d contains non-byte-multiple key length %d", group.ID, group.KeyBits) } @@ -223,6 +346,11 @@ func (b *blockCipher) Process(vectorSet []byte, m Transactable) (interface{}, er } for _, test := range group.Tests { + if len(test.KeyHex) == 0 && len(test.Key1Hex) > 0 { + // 3DES encodes the key differently. + test.KeyHex = test.Key1Hex + test.Key2Hex + test.Key3Hex + } + if len(test.KeyHex) != keyBytes*2 { return nil, fmt.Errorf("test case %d/%d contains key %q of length %d, but expected %d-bit key", group.ID, test.ID, test.KeyHex, len(test.KeyHex), group.KeyBits) } diff --git a/util/fipstools/acvp/acvptool/subprocess/subprocess.go b/util/fipstools/acvp/acvptool/subprocess/subprocess.go index 5f7a273ecf..158bae317c 100644 --- a/util/fipstools/acvp/acvptool/subprocess/subprocess.go +++ b/util/fipstools/acvp/acvptool/subprocess/subprocess.go @@ -85,6 +85,8 @@ func NewWithIO(cmd *exec.Cmd, in io.WriteCloser, out io.ReadCloser) *Subprocess "ACVP-AES-CBC": &blockCipher{"AES-CBC", 16, 2, true, true, iterateAESCBC}, "ACVP-AES-CBC-CS3": &blockCipher{"AES-CBC-CS3", 16, 1, false, true, iterateAESCBC}, "ACVP-AES-CTR": &blockCipher{"AES-CTR", 16, 1, false, true, nil}, + "ACVP-TDES-ECB": &blockCipher{"3DES-ECB", 8, 3, true, false, iterate3DES}, + "ACVP-TDES-CBC": &blockCipher{"3DES-CBC", 8, 3, true, true, iterate3DESCBC}, "ACVP-AES-XTS": &xts{}, "ACVP-AES-GCM": &aead{"AES-GCM", false}, "ACVP-AES-GMAC": &aead{"AES-GCM", false}, diff --git a/util/fipstools/acvp/acvptool/test/expected/ACVP-TDES-CBC.bz2 b/util/fipstools/acvp/acvptool/test/expected/ACVP-TDES-CBC.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..4c2832c549bba24f87cccf009cfef1581049e18f GIT binary patch literal 22159 zcmV(!K;^$eT4*^jL0KkKS+WW4TmX8Re}F`EL_kmm|L`E74hlc7-zs2kzB@P#43l6o zP%B2f0000001qF1>6rO4G-zq2iz>?{Ygw_1TFke19hkIg*LJSM6wnP}GHsQoJ5cFq zvA1I!t%ll7X|cCi$Y;suUVD0BFzv001QQRHi~|H1dI_N2ondPyo<)pp{Pn04hl-=+UIWATR;p*|*0n zRo!{rySLNtx+{3=HM#3@*5$3soo;&E^||p@+jDKLT&lHYR<_%fR;|wO>bmyY*4npi zw%cmoUahNYpF^*I`H!>V>0j#7tLcA>;~&|WbE)miS9{o2-jUrdQqtGg1EgB#il=upb=4-nZYh&nn9qx(oRP<7 zv+FHHkq$b(becs%1eaRHCu+rn$#3Rh^3OQp=Zb zS2uI3oe|^4B*d3aNrm=!u*DoFPUY-bthDyElrJ(0mtDEZ&@-`p*{%!3Ixdc5Jf2r@ z=^9!NneiOyTBlg{=1WfI=cFet#>QGUpGhdCj&BfLMvUy1iu04Jy}r55w7z1^==zZQ zv`fHA!-AXHTE0gjkY=A$S-N~%bKR#=icP4SRiRnl+@%O#A#nL6V z=8iYi(e^8}x4uL0TuxKN-%g`S-*zXGs|9Dt1o~?@f=$WyM;);_$HN?xT*j-iP_vHb z4V!n1M|p#Aq-NbVxaBu$_jvm#j)ugJq}*JVvZE!LtrK-O%gqh6pY`dY`>OWswb zzTM=fYWz#@cDtsVsawR0K^ra&%7<4->+G+DQ+cRfJi{49VRulA&19kV_`2NGD4wpp z$>FP7M^bzkO;q_hf}r&wiQ{g}RW?*|O$xFgD>pVvEwqofPtkYO;naI~;yG*Ty0)Xb zQ(|M(ik!mKtzPso3$GEY>hWiBa7^JhDc3szc&i-RM;i6K-yn6Lr+JfhXwzpMN25=h z-t6;Ns(2%9Qmx%=>>aB%mTrlv3F{Kx2|COy;d-3jsHEx*C6{pHd&s-nX?u{x3TvG1 z?v}1MT)oq4H>BfiD`Z*Cjz*nUg!USw+~+CDb=I@SD5Z%is(ql}V>DS$9q83+=ci|4 z^%6#}C1uKa)`da_pry{Y9<+H{Znklm&YrmBM8?{zXu`MQ6O=?Q>I;Rt)W-&tmz=R{HO6-U=)B>6eso z&Gov{hjYH35QoN#yz0oZ8N;=uH6{LYM z6uQH;Nb((s3u5JB00am!)!2<#)v!rwt#BA{*rW^GBd!nU={wU~~S z>@~r(#KbWGHZg6FVnC1pC7R`wc9`2f;)jIrJThx;n`wX!Hq%B}UP9E@O}3WSJrE!R zF^JP9^APVwZx1_02~Hku1#&! zn>o`Rt+)Vy9JqGTTS3dI4jQ(QAPzRd1yukz2Fm5sYo(QS3pZi~g{}hYEyMr-#S6D> zt=8)00^XPdTajxVX3zoCA#K+L)@iCXSau;Udr$!lc_2ZS>uS3juWf9ga_Hg!LhdjI z+FNkYnyu|^2G&eP%7x0R#EW)?HUd}cUp#-(7+mArp9ms+6+lZ+zQGeE-@(`3?ZtTHaHo2U3Oi1 z%0Lx}^8*#y(AivVw0WDD^=AFN5@=bg;kH(~VS^lU-PR3*th5`csT>3f;oATYMB1&Z z6}5XqXLHS)U4qQE=paBg(p|1WWXf5LId$DBHncR!rLCBN2HIN-Ce@l{0yaI^1)0{c zk+!yqUeQYB#|LedyFy#qv@if222gPl4gfmfsSUBML7Ph}d#M08QefEAXaPc!HWMA! zX=NxlfE*c`^PWdYOauTl*uyR$*xu2q;s5{uaN06z6wHLW+pPisZqmBfE4gml5CPX) zHF#_tfYjSyNo#Dv*+2=Kp{=_@3P6ECWdo_B$X;c@07F}rIcR|bk(sKIuH7u4`L?%~ z+taeP)x3WlXx7wf*sWSBv8uS$wX&+UZZfJW+ZAfXR$F_#ZDn|0Z;fu>XK#OhyXf}) zU4355rKTaTa_u+A-+k~OXanQ#zWFVTe&0op_z};O`V(xypWUmM7>QycpT7~`H_zEx zt0||^zHM2rjC#S_t?Qd?JKy=qD30NKqAi^1@iQRUvGk`C5jN7a`oU(i!f}l}TW}rL z9h#;pgoh}?a+)HXv?nDwse())3MA|XkG5b)9-vkP^f!*AR$Ep{c=<9yDr#uV9&e&J zK;m87oI~+&Y>Rg~F&)6~-*NOS2Zf>24<2$vz0E+B8)Rt{)?v65OjJMMf3n;ly?#D; zA_|Oy^9_UI{!y^WaTq$h+eQ-9bbgl}62$bo0~Z*G%4W3f(Zj;*NasVO+CV|*ec&sR z$27*-ht0za44%2J9Que-Y$}7V2@TU4yIL+0S8hd_a?n3!8X1Ntja%~9?%I9hHK>Wb z0*vR2#&|Imu3BqfQjYdiLvtH3@2*wErxxbQ#qS*ZI15a!tCkUkB%W_WnuFhNq0rtGyc@&OVsv4~Ii$9^0uE6C)q;tj#_IlS z;8_*zrVDEXw&;!&8S_I?!Q%_>n&`1+J*c3(Mh_xhuy(?jn-Sa`8tC5_ae}#71Y0n8 z92K|IHNJ)(44xUd&COV*G=N?9^gJ9$x~)fs#N@E*`>G6h!RTZ_#Hb1(iI=_$3%p%G zf2)xcZX}Kf7e(lS7(;3>MlLjIVhga6$?|KkAqTkhVXNK^<&MW2rx+El7dMk3fwg(qqj0-n$bcjCQUEXv8IsFfx41>IC|b* z3!L`Iyug<=$}=g~4m^XE6c|u~*e8~D4em$K^?oVPRza%g6wl{?tM^!7Leq>E9e7;j zgnQ<>W;fvAr2BfSJ+Qu%2()63*SXMHp`}_)>|jz%trzi)p*3_udM@pUn8H~yczzZT zVf$Am1h&0U%Mv5D65~pIVLHtU8{c_?98F3$#8n-E34Jb@Es>eY`TJ^~K$nwZ1%#(@ zKD@5(FS(l=C72q)KX`cZ)nM)$hv}{LItz&VP=}u1AGaZ^)23kqZ3?mu{DJIB84-Pb z*nZbrDT7;sCt0!C;b%nW7L~|E(Ie@mZp@mwrvr0Jpb zFyL|=klWL&&v>I!cr5j1!3?e8P%BjxMITnTP?CyGsmLPX_pXo=PH?J>q@@}?Z;MA% z+#6KyGK|krDpIQq%7r|LpTq;;`}q6m|H*ZVeo6wZe}5fjUw_|$KaPJK`~Bo&lyuG@ zNS>JQKb4(p#W8>4-}K2F8tA{`s-e;Pgtj-dJevp}%^FU#!3BEXd_KTK`#mr5jXYWt zY(obNst#OpD9N*V680+y`|-1jf!v!-AEizG!#K{r9peY!p>8ULIyQpnX_9g*ZinTU zGUy|<{0%mGOB=KZx(f)pa-rYUyAfY%l2qy;+4r18ME(7rp2&E1LEnbqmKqJQz7cn~@40@psnS_)o|oXG_1|#Hhv(BD&D& z1-({ZY##`^53C_fsB{>zT^v3eutoi~XbodwtF^NC$XcYc2)fLMb|OcF**tkc!c*!5 zzL9*6l|D`QIzT*LT~LIvqB5(^v6;GU7(-JKCJ4N-58`zg!MZey!hOyn!&7=_hD!7i&G7mij>u6c@;MB$Lv~e)P zyYwBd+COK zm@k~H^JfewX8zv2oCFd6d<7IXgJvn`qZSzBbB_8!GKaan$lGh0g=e|G7|#oSP>@DB zKI5Seb>8{vj6&@iK6H!~NnBeyQ3w9ccR8T*e^$d8VC~N0dh^=#kPwTzwk7-*8 zmqa;_dm_0VdTMcbL1SFiuDnMBW45k4P4bR5!hHW{2eJ!p<6`jc+(3A)jkj&nXJM6J zy@?D=s4dg(2~2J8i@@f5lC4<9*mk{i=;B&7rq0$$n`NqYaAir zF~Nx{&!)iQrHEr9@X?cTiXKVEiTa|IuA60f+mD#EYdcxg*7)1cObOdcc2GrT-wC;D zprblG&_=4yO{m`fBO@v^?$VnX(CfU=oE_JLj=v*^9h;5NWA4FR$kAAQieV^?a7{~; zB_TDxn9$XX!&CI7lO%?rxw#~D+wbiKHpO9;CJ#V|buter0>$QtA>GVnT8@k19@rCO zVKc3LV@GJ$q|mlGYg0n}M%o#Jr6I?wIJw zM8u{|9C@;WQrCnSt;z22IvT0WhguOpxKV79n;Z>X9QBQ=y06HO7?dfG==T=ELIzW$ zGZz(J4LeJtWyil9@#A2npG;faFE&Ps*2z~4Gem1GSCTDPyT#Xvde$Q{&lN8&@fPAx z@lOOfc%+(@iEqD<1K|7i%py9*3~BqCZ+gFf;P$_@h7unbe?FZ&e*^V@oe`L)n+7U zA7c8ICxyEB_G3uF;Tq=}?1`VkwV}_WWzJyRZ{}#{^G5j3MjzXU&uuwD+MrFj@$DnY3fcCn^@NtEMfUd_)srN=}0pg`L9Q-wPN6B*4NUu@il|Q zCAMZcv7oY~vi+vxnL?jCLa?fdZ=&WO1OssR4G@%NCDo1{&X3(BXzYR9)c4b^>taT_ zb=RZ`h=aTv8S9Nlb80tP0VH%&qx3xF4N^)2M;D!}i&_LVt;ZMI#kmV_JiVsg1W9h~ zs3iuLnZ`O}aYM!h2X3_T2px~LJMtP&M2qUUpMu1*IQ{t_F7N!BkJjSmOUOw02% zeY;Yty`pu3*zUP9KamCF=-#*cbU7Xl#ZaM0Mx`_}R2W8tQ^tk!RzmF!J2Pqt@MwaU zM*l^Jy+6}1J0~E!`9LpfKTxa^D_fcy4lF>Ow?aVOLBos|6`0O0sCYIE5Nx;R#rp_h z*C>daGkoht>6T%P3raKX%o~9sfqI7rbtU^Ye3N4|L-j6;8#$L0heIr2gll2DM@6(r zwQhZ$t@96sdqCqXwS3yy4>(rvmLA(@NnZ6)6|(o2Pj}zuy7P9DzMir0mQ4Q?Y;W=F z^55keOZN!};ouUvSfh~o>5KUehN)z*7Zk=jG^+K?ZT2wBOM8e}8uROc(~>Uqb2xuY zh(Y5=pK|+S-3TeV4I-h9_)O9+(tK7?zam4rHvgB9WFkxXi&0O)~ zOclSid^pR&hK&*T3Or-oZ4G~##!2Ckt%b=s7`hqJO+(YHZfm^Vksl>&$mV#vAeqNQ4M3kw zr;LMmw!l}`H*fOZYa=W>kX423KJH(m+1(}2A|zvqc(`8ct!itg4q+{8R57bk8TSEj zDotj`hgd5=L0D~HXh=&@m6GrxTyyTgBB0m33JcL;vZ*gts5FOfwSK`(3R>rJCQBMR zI`GdAQPKHiil^2>G^eS1uc?8=cqQ?-cDos{PF9U!iu^Vt5kc`6fL->L{)=En%i474 za@h;>=oilxp!x;aH-3=t(S5YrdF*=OGbq+?qieQ_MEQjvjGGDCAbdnbK6aZ;Awr@V zqap~MGby%B8om+f$+dEIuIX>i!B(vq+02CZd~t?D5L{k?jOCUHr=f^^W_&*OLq{hT z(vJ;J&jh^DdWTepgsCDG-5qLa5?)W-0q}iaw>+N0poV5&%NUpKXN>;~W6`+p3&o$l zaeYAs9^wWdcgUh**%*(}uKH@}VZN04>?LzW&qnaPxw6lL0uUsT#SBJ_sF>gK}|4ywl)=0Y5grqAfwcE&Ew(-MGy? zj8oKAzO?+DOqbLqI^6POmUUEtD$rL-w!#H)gn5Opv&rW$;M*xgQet;lR0&B^pb@2v z@Qgs!wm^aIJP%?VX~lF{UA*zdZUqLXs&a}ZTa0eq zD16QlD%DjNw1GGBcy~g4P2^4e0&@$HFSd)Vim>P(^YDcZ0wW*1FC*FxUSE9fJS!&l z*I#H7wgQBf{8%^_lC;3hHa`RsQZy;BYa_?c3-`P%<26rgFS;Xq(&R=;u^6;4pJ?fF zAt|N@V{~hVV`CiGxHTIZGHU!fbn6LFW}7OaY16`Fa{n|pL>9{?Wu4^JBWNL92}yI^@>;pGJwHI=5BqXrI?uUb1~&W zQ@=gN(+LWf9&S!l2SU)FbaV*lo6usu2_2ntn)j@1N>Pawdq!?3NwrPtEyk88u;|}H zWx6;syVSPA*79#VleVW)EehWr!g=6k9OD#21?!Gyd<|YUtK!%(dtK|x3|<{uj`l{j zcXC~v*7`Z#ll^GDXVeXEk~xOO7pj^Y^)ph$0jE;+h=4O&t2G zq7{Heufti7%8~YMh+okT5TEB*z%#O42%=O=UWyEQ!ySObwLB8{v5HVZ30QH@(QEpM zNi=J(GOU@?eD>*y-WaNfgvjSJ?uC)N(}L!-3pzVNTvqW>F;s7gIUDs^SVyBRSnyrY z$K>#0?A&uWXJrU)CFrq}rm;lBvkHAb1UPz;W5c(rg+lJ?@E;I!>~P$XB^t2>;7Qxj27prcw46x3_SJQh z(EHtZ{<7vUV&%zVayL4ALq8l@bG?3?GDi0or$PKUBSIfZ+LnUnj%hpbgDeV$!vrpj zL_F&{(SfrSJB83=y3Us^C|GlI`%0u10W4P)d%aL|uRTt=$F;>)VYYNx)jLaeEM|?c zaJhW!FAPgw^;N2|xjg0XbHa`HCJABF<>TlZF>~U2cO}*ySXNh2MS&sZWtjy-^>y+u zb=+AJ-o)T*ax48f;dvMLYs7|2z{-Uqyx{lfLL5PZQQq=GW24%mK0Ab&*5_jM!8@Ur zdtlGNn;X?Ly2EWoyUgg#sO?rzEI$gVIo^He(*{W^e`piPnUoMJT!pd^4_Lkx3~7z3 zr4Mc1wyfBLMv$Es`#)IE49Ak&%)=mw5;C2|oKfhT?tvl&7n)X=ZMc_Sq>bM|O zH%Z-{1qd1nc;sj-TOt~L?sh>`5KdnNi{qnsc9&UBUVwEPRv0bKUNJ#mhP@?XuLrhK zUC&C1@;z&WjI43VVy6%cQ#W1|)DfW9RME%2L=%C0B5{Z7`O2&$wosDnj`);I4c-Z` zV!48_YY7euV2R$;Znk>+AM4Ov{;a|KnDh;tcwDyIPE!i&j^cANLrxvj8z>XQW|Q)# za9P|PW$Rm(a`iC```vYo(=;m@%2O;zab{F5Y(|I}Iqz&D;Hb?9uy28kFG7uEg~DiA z$z1}u*$(bO{k=YF#jGs~F|xpX4*I3x#NTke83BO>4iGu(1JJ{Gsf3Iy#Qz@E-lM>~KaGRj9rbTvQ9Ye^6{1K$?#*CLq=hf&?v|GMo(7o(Ky@)ZEo74{bou+?4-ObTyZ$N}|=Wha&6=B+Q z6}}TUu^)C7u}afx46Qlp(A`F_9*2A;xEya{h`|uh&x+0b0{1n6u-kU9-4EYV#6B%U z4g^C^hz`4MY)He}v#zu166w)}z}PYa4)^El$a>^@$D(^q!w0twsstJZg|pdoZ#!Mx zecKPhtp&nJ5S7cn(Tu^dlFkh%k(iXl-q_ViLKjJP@c!R5%xMZFx$K_NycWsroIGI0 zOufmf+Q@I?`bcAC=FcD(byKQ+rnsayIx0nuESTw@&4vsZ9j?B!EnItiU$?z>+>uAG z)cneNfQ9$7Utr4|Abrq`5v_|EGG4lWyfXwJt6UP@KAxS?fNAa(?@Qa5W(^AB*lu&X zat{n=LPpqJ+;ZDUtk{iU(aB?Drvr&l> zfee$7K>|rM2Y|KL9=&dyGF6UN z`&|;FMzg>{Y&8^u(HN_d$g|0ovWs1#II75+YsGE`SqKc0D(u8a1WA`? zRa5CAT9`MM53wO+y_+a0C{|Bk`ay$&=;;xg4y%bSthw9}cVa9GyUADiY)f;PEGTv& zvRxEQarZ*M3n;yQRC5D9ZIRG?qV}|MC$jcBzh9~2!k8nT zk*ctL?M_^bOe~kqT!uo^bRNk-3Hi@$n?e^4JPpnxim-es6|2~Ps=5$RY$>vi z*Q3!*(dvjE$)~1%Z=F`=w-kSGyUbTq2&F@)utf(^* zW4kWLFSfn16Sie~)B;HyI&R|&rb5`?Qu?|c28!cFu@_vaUWp8#hX#zPLLLZW;9hja zT3U!tle;8KrwLNp=a1@dq9rxR4}5d2u^rzrhQb9?kCA)8%3T^uxuWh;J1>nE626lfjG#tP?(0@t02M-xUP?M@<>;{1pw9Lw}h6T3`UOo_B2 z#|V71StA$kQmJLA;yoe;bVx{%3E<7D5EMaKVY@IfZ8BB2fFKto5s|DRvD zcr4FCg@l$MAvB&G2uqI=+0mEHn4@tetul~`)l}w~bH0EuSdUs|MsGyE(WIj9Av!i! zg}Pn513vejv_ZNT-zSZsCak#I26^7~)L$4TtYDn=ZER%&8;TZO9bU_e6cf9NO|^{O zu%yjLH_%aKuGZKS2+qJX1{&L;AaaW5-q^avSAcy)sk{a&Lnn)?1tz_ zw-Vg!8M)@{Cm^}I!Or}dIAZ485+J7szD0w!cnfqk(ZmuuG3JFIcfnEX*LzcR3t-OZXm>E}_9M%c zxbN0|9p;mjj)fJaXAPzyP#rwIg88|*8sF8UtZ|_;ULn7r9uU5BOEd@|t|wU@`2GxI zt+K)+>@;Yrr^?xs=4>?IFkE^|vpb+(p|lcWa69DJq8JUDaBOqU+Zy^kI?Cobh3{f{ zzaB`JGGzIv+t^%?qr#12n@utXTs&$79(Ff9e%5s$u!oc9ejwLhMjR+6pDl9(oblqp zlrCzj9M1|D0;7{hjv3E5UmrHe-#*4=AxyalS!l zyWaA*xh6%4n!Qmigvdk*Su?Qlcw}N3=3PrFWfaHOM425J$;X{*$ZhycXn(_PgiM$t zC~Sio7mZ9q$?QXAjCTsvJ?3C?aEJQ8&NrYXoX2Y<~#2=xj!QYlf~$j z=h2gU6+SvC(f-}ezff8w;BUI(FK5~suXa2_teTr4>!HcV38K$qNj1Vp(uy8hlnS%I z)nWOiFL)rM7SkEftgb>k#`>2nF1RgkB#Rch`{!6%?T^byoCpJ9z$qYU(UX?xaB%4h zr0`#Qq2c!;#9HqD+8}S3XA_{>M|rook;V3qP>#0P;_S=nfdnup!8*$fm z)x{Ua4iYY9&BMvsVu%#6l`!b8&-04{B$(0BNjP3k^m60rP4aCU*^y0%D2wAJY~_Y6 zMvjlh`z9wMUCwHn`5F2iCP(Cox?Gv_xQ&u|QhP?eqdP*iTBR6-^N>LN3bU+^O@xPD zYAch(clh5Ez583<{;VE}-5B;6iIMvkgHUtA90z>r&WalgZG<;7_kU$Udc>~QudxUC z8tbpI;p<4PP&boQ1TEe(b2=bkiM8X*nS-r(^{X7{!JME?K>mapuTnD3v@ON@BzbF4 zmMrCGfvn0(4{J9oeCND0^70sdFn=b$RsLF@ehDXqW);TuDbHmbn{XX`bNf#4VAol& zn*2XDK+oS`zUj#(1SH5jaoZaC8qd{sqE5k;Zl1TU)H==0YPvNe$Bh<6B06EakkHi4 zLV}jD+SunrSh6!}E&IQ5b{)f?Mr|C22E+vs_WHq)hF+4-N$U3Gi8I%Xu-=Y zyWgG>5vB`D!W?ree^HBb;R7(v~(XWmt;$2(UHqCZ4EBy)E7I~9K9KS zP}7`4M`=aZc@v&8a*)(lcswiVFHW@7Z2V&;ej~POh@J!>MwtOr@_El^BeQxq7DJAs zux>r;Bw&TG>iL4jqTne|t1cS!L%tr1jSLGCB)ePaE=J=6gBp$w=*2*}xVYDA!oFN! zVhP6s=%;Fl;$uugB}`NhVp2DHbt)QSj~2BWCN!*5Z+BOS`{Qu+n{8vVEvqxSO%#j1 z0>d)IO_ia$95c*zQwCBU>RzQo#63u6N>rp;WsM(8l|1K2sWRzYN8vv}=+}Gk)<^8$ z;UiuYK}t*Rw`Ffy8IjUFacrTfb%CQ3(g;;ztz zJsFKjNgHC~mugouKwZ#g>2Dp`IhW|CJabmwy~}j`^*Jv5 zAW|FLWU}baba0cDVGHGB?{luFb(7OPvrw|SmhPHGw>j-3wM7{c7q>7sy;GFo4Oy3& z7`eeth&M0GU%2JWTzr`!oSfl??GAW}Z+N{vD0jirs)T1*9Di>*7XbtoG|)*7+3RpE zq{u~i_9FHn1x)K#tqjdbyWaB9npn8WCe(DC#KVo`wuPYiDtrahLW5v4evhga_e%Ji`v7e!}E8p zIP2B5<#iu9=IynyOP4Ko^oicoY{CRd6IeTz;Jw5h()VRSf(&RmJJ8vR?v90h*S^?Txl1c-^9ndL{8Ni&4{6MU9t|U9@N46Ffj=_U4gKS-aBOS0_^mf6N)7X{U zn^`Pun~Fv+V#7`P z7-9q<*s837(aD)G6r1M@+Zzi8EkZ(sNvH%>U~)y~5EVEi~)avWGO zz;~_V9Hh@10}8r<-#ozZjcwdH`0L9On5QFGuIgQ5$CDNmS?D;>&#R-b`XTK{ZAFg_ z-uY!OW+6Q!qtb!XruI4u3Uor=vHja4KQVTq#9BG6@1`_$^sBs&PqH1EVYXAf6m*Fm z5rnyHCH)>OMUKA>J$vlFD{y^pK3IwR62VSAV~`4 zXeos~S(zK0UolEY5H#z1*8PhIG0>r*jxBfLSg^y>(Y=CQBy`Q69!CC1;`>?EhDhqI z7J?S$)lW;)OL)+=mUiPosVeo*i3yM9DA$esPsfc2y31{?Zi#}Kt}<>kkP6X>G)FV0 zX?16bCYN&hG1U-;9;4(SuVjTMP^iRJGtik3j7tVI6+)Nv-nFsi?L`4O&ClnedC`v^ z3i(ODXW|$gl%`nCUA~hk zj82xKHL2%(*UXPvwF|KT=NAV%!%^X>#|F+{Y9T`pdhR7+gzLQO$UZMH9SpI}gR!rw zQ^T4H92NC%6;pH;^+Lo9DfrF^M}Y_y)Ad6kEJ*{1Qio{i28{*DC#S7-0-r$0n!$rg zByi2LU>tX-(4AZV`E(yHqV2heu6A< zD-~;if*x_M$Y@OlPprse@~p>PPGyd7fUSkryjVTfWD-@th`hCp?2(6_r+Hz8LysG` z)a(;&adnaqyPZL3J+ist&W=24J-}3>*Ws~FsJ0_8gSDSSwfCLu>eU!J+*3R>PULqP z?L}Q7eS4Pr2r_JAnH2DswXr*ahc~M9C6~1_*qC?WIN>E^ORG@}d~F(?^kg!NF}J2#Z2H?8eO;+~O84eP^i9=w0hrI=;@{)ZDh1#YNHA zW+IH!xUNYGpGog-Q}r-y&r5b*ZIu%ZM}&+QzK~%xzq^_{)>MMAXL}Xp2s)iC;J;E- z==53|*_GS~*7_CK6S}$L_!u~_<);uwQ`f~$CDPWjyI?`$vwOq7wRhqTuvnTHaKWSs z*fHbETPP93P^V{d+BzxAln!39^^w>}p@@<;K~K_)meFkP1e>-(GEmxknKTu%C9XFo zj&DbKhkfyWf^Nz?QKAGHo)-`G9NCO_Ujh_F66b{$48&MW9YGq4BwlMtQ-NjpXuR)< z-3C(EM!q*46MhUQx>DzETPD;g1vEN7nVEuQ+Wl41BF0a3?<`b!C`Gp~xV=I??rTVH zVWO1r!L7j}rtRk+Xf6aNdEHN%sWqi5*^A4-xNp72nNk`79PEm-hC##{g1RAHUZ&E* zK~s`#x{7@u0`nuT3^yzOnZyrFfS z-E4tgdraNLnY>#PI3b~GUAN)`%`=aClc^@P?GHId9{#Z-9^wv7j>*x;bcFi)$y_~&lp969=+a!O zd$i_+Ev0V_glP3Dj*1=NhxQ|cTj(OHhJp?v2TFy7;6D7dj|rN@S;rc^cyGmFO2v5+ z{Q~o20)+ZL&^LTBg2cGZTd|>Tm&3!is>MRiZ$h5(kFo8U6aw4$WV~!1)a|=iTw~RZ z+>JR!4ml(f3f}H`3N#)HZ>}qQ4Dsr=-Ra)QIZ3wXHEN2zm#(V-D?pO%G}g`~L| zH>yM}90nQ2vepXeGosZn&c^sS1QYOy)2P1c!T2~*L7`(qWH;2QTlFQv*J)Du zo3&g?P2Ts%O(nRV47bKvbOVJvBeF4I+c2QKceU%$-tea>y+C+K|WZd5`|+$HLhUHiMbDE z4G7ODaLOODNc!D`l8a;#2vD8`gVcw+nD^Nej2kVnbR75Qy@>nCF$2ByZFjIj%Gs~M zTOOq(GT9`c<@K{IwDO6re8j_Cj))%LTBmk2J>LtI-As<|^(otdYr&sI4oRc$BlBfr zB@X{^L5jWwLiO{E+#Gq8*j#ZED3GgLoce)+VbFC)t)B_VXPzUe^LhGJ4j99}d4~mf ziu=%+(Xzn%dhAIQxND#$cF>qW-*?05=vLR4=Rb9V0k2bH_S$`8cC`!Xkugtlx*lYc zVXAp!chahJ|in|vVn&{|x8kS{GylR{i&{4tPpfM8Ca`@dtMVPR=8v+1K z7K3MfQ?W!@K#M(1n)0*GXqSpWlop&f)KsYS;ps(kbV>4NIEInt%+Pkdp~T_~9Ym5V z*N*`Wh!aCL5X31C6BPNuOtyu$Ul9Y{3K`&HZAFLZPJ0jHqv`Y?l^L!`{lAf8vHTxjv@MNoL=*%u4(gqp~uW_Oz&RZ0` z13h?y#vK=t%E23Rf)m^lMZXH;WnL2vjE$J#LGp!7cx9f&$>mzx&$wLhtE~ArIzvh; z+6LD{fpy-Uu4jjyBuZN7s%h6kp3Rz13xQdjKLXr{9G+={YR0hhr<5FV@7ZITpnL>F zf&+{P+=szL)6=S(dzqo`T=-6fdJzx3 z*AiEyk77NcW=1X5hO@B;21`NI&u@vup2lfcPde zV|h6ZppLPqjIkA)XAh~}wKtoQD6xkiDc(uAK0F6`o!r5mom1R^ zy1_vhUg0EWZH4UBaJj_OJ`-zIxMa1eF(QOl%Ti@&P!~nmIS@P3CkLMIleCC;1&hx; zU2lP9QcP^789tAssZV9t`^(*t4qK_(WcTk0?b8Mg?D+*++1C2i(+t}wTK!wtM zZy|HyS=U1Q1&!(U>Im;blC(RAI4n;`R<^@5Xqg{(>;ywlf#PORx3DOpZ%7P?oI_x< zQRWb_diQ}|k31wS$R@=7%{1>@anP#ask`B_g_xSUGCxd0-SbzRTr4lY>O& zjE}LQf&xQ?p5uw!0tvgf8I3u!1ezY}8EbY3;2Df8e(2{Sp|C}oL|EzwV15xGke!Nk zpn*q6uB{_CHRtO3l|j6*@8=yg6d)6hO6vsGn#j;45JuZ+^tcV5bi%ho**!w;rgUh7sQ^EEBjr#R?xDh|lR_fjC$UEOEgRwEg(%OY_1q!FGA1u-4y6 zb0hJ%_MLV;AF?hMvW??q_=TQ?VjTNI#@9)u@L}p}>T9@PF7x*ULA=-MW{f#&X_3m6 zM=3309dN?0ZU=feX*;5p2d&mmlY~o6sqI+aYEyg1n&A!EIDTKvtU#I0oV=&Yz<@(^ zU#9fEM$0}jVATYu=$aANK?MTS)Fg<$s?yhiai?3-B(#iQaGzggi7fVP5a~HFDfeB? z*I=6kPG>eE`qh*Bv; zEn!XNz2x8}s zL5o5|k96&zVuJ64H*WY*SiN?c(-3xkKf0&uDIiqML$@4~UyF_-OSGV1o5-2C`#K*C zb5MujyJ2iWGn1(h`WHEv5L`7m5d#3DBJo? z_Oa2gRA6WH{d~H~Q9xhC?2*8Q(6j~;U7b9FI0Cx}6IqIC>F!b22OL zspM@7S?%L${Ka6=JEsk(rxJ@{O4SJj$wTu4Y{D4A3Zp;S${P-wToW!$DCi)RPewr? z=)4VJLm1}-Fu1Uu_f@oji0#ey*6V^W=*|{?N}RiWSJZQzAhD$7_swxY#6%lBE+H=N zS6p^{rwGNiNJC`YsHZ3e#}T3D;wl;SVzsd|TnA0jQmmYvrU7*pis>MohSO>#Z7&tZJ!kK%wPO-wok|sE$J#SbqB{KO0mHpoiO&qqdH6~K@)iJYgGI(R7fUrIWpRbX(+C@eZnlKE@LRBmAYpd z*U6x;mC&v^g8Nz%s*&6K7p+{z4I-!(d{udng=R z7&+Wt{Q|IHmtw-Oq84Z0cTq`-GFzdI$$NN2jY1%r z)S|H|6OHt2J!D?~&I+N7I$P(MAZrM!Ull5$1FmmtYr$g|S zTCm>VaRVFlf;0m>%Q7p>tDyCe{OT&XRsGow;cd-~wBE2+c^tu`z?Iti8cbKC$Ac%Y zm?H}HvP~PNy_z?0+ILq+XLqa5BvhHP^4PscBvs^@+eZgII|Q;*?Xh=L$`f@7R>oPk zsoaOI2`w5LAV-gp0w>THOY*_yP=7q-^dySdR!#N!QEgG%c=JfE-$tDL zVFtCDH&G$$g$8~a4Mo`*b3#SV@rjz_Ptwg1t%pm%hknUxiKVK>$tK$H_XdkNK3c-=hG>})q# z1#dz6N?b;qE^?~Eq7Om|P}x6B}7%nb0Qk%CQOPZ-1waYxYGmaI5BZ5*htxYg19tyyt9i5SeS&`L%WY` z+&m#Ja965}Zzsk+L^0;}eqPhZ0tHQv1r;qxThm}PwKQSTlc9<8%`7Fxt~@8wH`iCv zWRV|#A~EAUF1H!7SjSl|Q>cPT4WjaO)A=KOwsN0dXwtU}D4uMqs8$4 zEI=c|osF|?gpk>}u*O^wtMC^OY&FU8q!(4>)2TW=Uxn9kdii~?NqCQE#W18x$)3Y% zu5f_#+s1Z93f-$K4T%#eIxXVvhlX>9%Z5yP6rj2!Z{+7@qsB$nwN0}I$&;77>ojkK zY@Up70d;wm;MzWiRN(`sCav1dD zySL|C)4`CJ(NAa*NNjjc&Nm`?4W1m$m`S$c=o*PlNZ7I9opKXf-N}O8mrRPilGU^s zV$K*IHPG?!ffm=&OZSko1UTI88$*1m&UMe{52jePFT7wH3-K_hzCsPdzSm-5ZEVou zTZ%0ei-(aaG!s=9P#>J`ro}7@5;hzo5I!}>6x?q^!VO>(LiioNh>?kclJUTaJ zgeSqXq&IJEVCQ&mzTi2P5bO(G`%Ag4xgOG0%A)+kUpf?Yqe{ljXn(v>*v-(+I&Vd& z-V9)P$x&`${84GKQg24YQcoy|FAZZmD8392vePand5O@T9&dwkNN=G7;__%n=C`Oha_T2^yywTm^>2r`Us$gBfx5dQPEk zdo!Zi%NWVjwjYbkgRndIPXT9M0PR=XC^GyIk#$Gk0=fkQa>GNkpc&Y2-Fr@h?5H=gj zUi|{S-N~@+`ok!%l>U*ONZH}@!(NJ|qSw-hn^ujeyCz-0IP>yt?vkA|bcQvy!fe(*nCie*%DX3L%h!kb{iL-6QWVlO%0+uu;G>9n}qS=U`HsqlP3h|QWW`e%kisQrpZK;_}8w;wRR!F}q`-AG`+bs}njoOZ(Ij z7bd8Z1Mj@}_~N^GnyK)HwjM=?S3I=icY=%-!8+7RQ|D0odNE8ZPIH1FaBkmv5JCr2 zZ3CfSmOIOqJTj3PKqEG{p-<#NGY7{NbUGc-o>1g#gTfSqz{f0&mc@GqZr2BN5v6%O z>!ll29?E1Fv3T^tqFi%+Aj8C#94+`h6!iwc^-$kZNW+9I24pZs3%SB)3ErxWX@S$= z(?-IDt}PR2HNRVPttqfyi2s`Ri!I#qaG2dA43(7Wn&4nYvZn%MKos+rMo*X z7hSXPU1Nxl;#JYw6x-6dk}ft=ADkX2Uv@1(PL{%6RQG#a!1PU2lmEv1~wLz!W z-1X@Sd+0tRM8pPOcvCcXZP+uT5si^TnmyhUXKeFU!f{^_j$guYa;+|Lk<`{|;$(PZ z(>${x@TPm%(_nV8i;>An*0PbUESu)U?^hj;k;0Vbp5?mBd)R_`hzkxSkqXp_bWXsN zQcc~>>piVriLbYN;TkO-Bq~%@Z<(oA$f|u5`OP7>PZLJT8^uAlRcX!EZor7k8blyu z@?;3fj{bErhC@)r5RM)H`d0uI)7+8XH9sa-ZRkvX@1^DE=M}hn3_zwswPTOl650`( zlfo%0pw;EvJegx0oi4OCo;fph%FEI$;N_3aG)` z;J%fM9y7CLqWB`QgJTeM^l-xT;Uix9*`mYcNuiD3$9_jPYKU>N+HbmUGi0}j9Lc>D zC*HV(sF~FF6A*YqcFB7uj>6J?N`-{s*o{VKMPcwdVGb^+SzBuZ$l!erm_d=xVmtV_ zL`IQ~hsxrp@7*3^b9MImPwcFyxT1jIyeo(ZvUjzU8^LRF6Uv^k_HPqemr1-nO7Lcl zn#z)f<_5bzCk28WnhKs>^v3Ol-nw6Y=;-wVJY3ZvY6{*=7v&VeyMKXM2=5%y|u2zX+ z6|O3qv^wn&ea5Ef_u0E<=Z9<8F0vDE8nE+vSsR=^7YmR}=}_Iax3@tYj`ug>dA7Y! zq2{NkQQfmyW?+%Ahn#ZPs6Pp%!}}MG4RAF%VUF~L&5gG`;2Ejq0$EfLWPY=jW+t_%olE=M&rAYMXOU%EiDXvPLIWdoh`8} zB3CZbLfFB}F^{pss{n^NzluCJu~?rqc`F!KMT4Fy}AMC>@_Wv9s#W zM!S&;;(QktMh?)yP&?<|1^TOJV;kPVq}Zb&4)Th&F_eh}>A)n_1AFkwtcacL_~M5k z>P&DkF6{ai7MFa?Vwpp(sy9cFEN@FQYh65Cen5VWZ^2#0&~IykHa*x5^QA3_L)gs+ z5^2zN3EcGbkkYL;H#@=5pJ3QAs6h77dL$r9Tu^8OH`E&7=2vDQmJ(kgwHzceCx;wE%H7l-kXWj;h^|Wkui5gao9UVWkz7aU7)DuHvr{x$= z!Hda%&g{9@f|0F$AA;gX4=6o|3Z#PiEkewVg(GzcBi@<%!Ykg@ZJ5SeHJBV@l_Eta z4xfZRtHZl6?|&Ti^P}4}EyBh%>D3^)GL3Uwk1+M)K^_Wf{Oh5skr<2RcZzO8Y%Igk zjChCHhjJEc1=I=4gH=~GcvIguJM+xzsYD+n_mmBC%NpGz{=Wu}Siz}AP7cUvvCllb zk0)TlX0N&vTjk>CO+N%uB z3Nl_p_-dDmLRdw?i#*k>N7fzIk(AyELTXmqR%fx-sHc>Wxs=yFk?!CPYyx=X52l z4V0)Ahuz|K$UC`rjY;9!7An?Mu&6G=3FKy;K~#&v2Y8+l@pyFxyMzwEN7; zK`)}AT*qe5!`t}|49>T#R7@Sz^cqbZ3-r-KOYO%XUEb;<<SYoxv562Hj((zdCnJ?NE&AdYl)wBl|= zASQi-9KNN|Q<$l7V_WO`i(WCy)ItVI2ryv}Wq?`*UsyQuU$B!-O8S-GeKSGD>X1>U z$RnuUeQuCv5MDUF3%`udnsyivq&SX^7mXI{>4I_2LqNSzNYhofTbpD-G&njYqR>E4 zqXkp_pzu;Cl<^=z=~%HDhk^wg5~z+iC_zs#C$uzp;vqp0O9Zle!R#_7#0{`sPh*g> zm76sMF^28p`=@o;eZb5;g-;4vvB8ZkoQAWTygsq2c~{QWWz@+ZAlyMiD3RP|3WdV@l2c$m) z&`yI54mKVr^)<*GJ`k1?(2jc)6YX>@-F3nO*e&0n3W*g3#6XJIc2xq#)?ccFJq$8}*9c$tPoWK|3TmQey}(-*@y-ssXTo*d0DEO^3s8BJzdW#%Q?Z^bCqJb7=#MJWtu^8B+J57Fh7akAfVkJ%T4m8#En z##V4>^e}FF;jx=U!2YdHi3ss#A!DK?|V>e$Ysk07SgkOBQo7mIKYYdbhhG3q8G2smW#&_Rg#5EzA zA9_pfpJxdDNPitvhofGcXvm3PvdXS5GeW0vz*vAlOLy%a&|GY0(`0xkX*QhlYBX>S z*p&!2oCFOVPLhywFN-85<%0XGB+b+dxaLo(K^Gr4!mYKpL|+GSuYy~|Y??d?TFH^2 zp}2LSYaMb`=RMB462j=mtrRA7E#)Baj(fsctS3@zL^=0>^8y39`kSh1&$k3iI*_gx zX0j*FQ(bhP-DW)y7fmh-uB$RV(5<_lu@;L9B8 zk?=l`+}M2Monk|4y*DMm_2fdDAe zW{O~C14P0zO3DG4jERhq5J;jj7+8!YFhQm!6vPS|N+S@nFs8^;A(E6#!3Bhq8wmuA z3@nnAR7@cZ%nK-j6emXL_-(vq*5`88qW)_%R z7Ft|wbwz3{qZL`LEzWSeEHJHxX4KWYuy!adwqmGevUScaWubdCrl)yXVy5n26vs<3GEpA%exz^{c&s(1gwQg;-Ta{LNHA%?9TuIy0#9IuLP8I`&+8(QZQ? z2i|R zik)iIqWcSVlfJssZ+Z=8R-8RMt$1>dDs;P}j>w2xJ zaGSAibK-8b@#(}Mez=LE;A=kmH`?85yA=AvEm3x<;)b@@-8w?#R9`!GT&>*p_G#yr zEz750WjwjmQTb`^`$~%G0c})lxQ{2=nTFnW5*v!s&{N7qJ{nOBr7d!&ba%TqCxXzn zeAQ*r=#3dU4uTVQjPV5At>y)Oc1kT%v9B8UnzrYxiCL~~rncUV*Gd?UW%xbesC(tG zBJR$~xQ*7W?3h#XG+K(XE_tPmuJJhbM$?rOwthtJ?FwRbv8v==7Sc(dCGER?=Qkk8sXMq>(yu#MghtAz zSb8;{z8_CzuC3#oKQmqKMZ|QS<*3`Qz1-BowpNv&Y<~GxYMh+d9C-0s^N)E8ER0ak)o!0 z?S(Yyf(IB9-WKhiR;N+A>y2YT&FL-9CM6!&)bQzE%F^|lUg`5KP&Sp6^t9z1eQ~-+ zd|f-0XpH+axKz7IgA#5zy`MM|8cUf{ThOS|*nYaR7V3K3I1;lH+lxkfjhti>ofb zHHLBBL(y?!bGd{uWPr9EL$Hw7YTc0-)dFcCQ)GnO5zvu^VaW)Nh~0-0bVU$~LIEb- zXizOdV-c2NLnfRS=+M>;+7mM!N{%|vyv2(fJmxl&LlQz#?OP7Ru+A*v5=*uWXBjxM zDzqCwjy5fd6i`ivHqKxRvqh~GkZ9*NGzNxt9@$Js7@8XyE2A0#xy8Ey7;wytG%zW; za5-FUgZ0?)oOtB72;(7SagnfCqQhrxvy(v(;Y+tPRxJx1Y8`So7#Xm++oMJk6QFgG zHzKjZSQOY(87hc}2WePi8e^&)u7=C%?W5SJ%iVoO^_ zHzqkVgw$fgoKb=%!xCz8sKa83fT19Q)Na;Ywt<5pMUxg6j03H)v~?ya zaY&fcjTq}r=p2&@SQMOi+q-LfcHVx9s<&^$ZHkSoZM7P;7S`7dZB|unYT=tyQB`AB zs#|#WwUzeYUuxa{9eh4tXOD-6b$>!xrW+VB4~*K@uol<=SS*;Ve=9{F;61HAe$lh( z0*2xwmwur+r;2u&u`%6W+Rnqjw0C^}T2t|@nhq%hqY4cArwJEw>MrzWG%fE%Dmk~% ze1s+3;KLb_QovVX4Kp<1(;0yYJG3+O75~z~_&s}?#tb_~Muq9QweDSN?uIG~N-_M* zlQ|SyA)^D{G->}I7&bNe`zh2zyGuXX5iHh0wma4x7;|_gP2_tU<<`2~kgR6{^J50K zL#{gejY!@W+BABby~#*5Z!rd#-HjX_xAv1HYdiab=iT?6N8r>bLQZLF=)E`?hTG-1 zlH*cu@Na0Jk4v!V65vK5uZ1vx=Gb{M|2va;#T*v=(5z|VDear;{WdYgAK}>`=*?Iw zhPFFuZg6t6Ct)`xxF#U(yPc+4Rl8JASfoV6EAueax3Gtdo-sY0F(u~&mlW_e(*GAI ziiOy_Galq<>B0|&AA&STgMf@aE6G9YsY&-y2b0ofRxC<&Yr!&EDAIKD*m^n_m?&*! z#T{smhA5|~*1Pa*_c?(Jo_lFtc&jWji>UiYED#;~2S<5($A}-|`MJ0khnJ+7Dt-}= z8zSLRL>xXBVjmk)Epaa-KWIvnQN$3%+RYK;lLtyZHhf^I=KdgK6AdYm=f?}oM4hwb zT>Lpt80>^*UiW*=5FsOSMv^mQ&4N{DR3e6v(hE$ZAB)oVhHha^VVT%K(o~Ni(&Gmb z!Z>|Bd^OVtQt-VKEO29e)(@@YJ067^HZqMK;Eggjt`QjDcP}D%E9W;U-4o>rcoGOM zmJ%ekv9SdaLYIa%iWq}^?cJ>LU3!EFoN)Nb=(R_-C*&cg+F`WEG5FtO8e56iQ{i5A zTtv(=4zI`k`|%t~zhZYJFN9H?*M17NrT0u-=yiwwvub&cN;D*Y%vq!_J%^TxD z?mZE>9~&mF@_6eBaeP8Ke;N(3vCEejkBl4?*+U#uy7LAMTIJ*JNV)fORa!F;@i)`h z_73Zkp}=dK*x!mf+F^s7H@B5zvELg6pxy@hLl3uf&?-P{;xrrZdl(gH zKytoRgOGcNO2aW5W)oUGxYm&w5y~$@9U9)h!w}V*aOr$a`*=e5ng^G2gPIvhxq2bh zG+e;%4Lm_Cdf2yox{ry5sA>jtmb3PO9E%ppC!1jp1=v&~^)TsdPG(T(N((eH0S$UW z4GdbFq;lACDB30la-j)E2(t7KXJ|JC`bwdXG$*t)CH#;gIG3OkFtYWo{fO(od{vkf zCdVILQwK|l^XRNiTWZINPZ#jec&opBw}+@0&@wgzj{>LcA`zqti%eW=R19MMoC4id zAJ*dGII7Ta+!)d$3P}Sc(C-b9xjHrs-0?*UVDd%Samk7(oF5W&9GV=adokew3`VA0 zlz9%+&lSksAqj%3pHX$CXDo|Im@M6U+JH!i?A5HDskQ41X#~PK66|J(nB_}M%T&!I zj>!(PRW*@mf3O9D-`n`Le{(gMBK+QCA@JV@oEL3&h{<|@<3Sw9>=FN8pHOAJgJIuo z&H?D=|4i;VGbL1Wy`QP##8#9#i$Px)<%(`?U~PIoq$R=4m>cVrp|Oc7RuEHI>YpD8 z`4jPf!W-41hc0YRjiYB-5@h&KUd!-F5fThMehj`9G$>GUR6G2nNsuAG;84+u_@0O% zLVS3wdlIF^azy`;KS~#dqm#4od-RipNe3MMR;m6mvN`U%cWl3u^5NPT_WxS_hEwZjIOzAr^WdJywf(&}6+ zD<=g|@3DmUxFjEgUJVSKwf4buCtMJHWfRT$zEi0CcGRzCy+MLQ39nIIzXC!egc7f} zlN*N3Usk+C&W@N{@Z>Kme49QyhuYl32p$0%0VCi-3gN1G@^0QfII4;1Xp5{YOYaAQ z@ulv3IY9;pj^2ayiX7u!@K+EiF7qm^-Mr?`v6AGM!P8tgPb!ZCZ%0K_!;i!xwog6> zHel5u|9n;!OydH^6EO5p&i7(dxA|3Dh1Td?YmQ(;qfR?}?ckBbo(jK*Y3YfCHbu$= zKL|F?55QpruFkqI-m@c)V{?3g=O$3ZmOQYpiwlTQEh0*zqTn%WhrWjJgK&`&E9$`5 zGsb<>Rc^AuxH*FuP~TOtx+ z4&RzgJ_^SyC@l(827KtT>^osY1B~2c4F+1}FzauMxR#wkb7lNpTvFp^?R#P$h7OVx zF(8?(%#m-LTiph|hjDvJv8|S@jdU7S=;lhINxK!Tt6ya82W)im;NuV{Z6?Re*9xSy z3^e~F@VDNL_u)-{Vu;=NLf3c;8+nM`vRXtVG0rLr%}h&^pW1=oq6CJC=xq$53DdQe zE|Oe4IR(=g*|Q=a6vhlvP7aEwC8$B#7;@(=a6=>JYgx+pxd$i+OuD1o&bDqrMXh$0D_ zi4F620)Ei-M2@co*f5j0y;#!SySZW-bSPt!hWBW#pq}f@;E@b; za)Ixq?}UxK4&K-Nxey2?cXR`DsZ`nZ(iDKMssiCXFRkEJVC(>6I~4Qu|6es(2g3aHG?tZcp~eJ z@$}4cJIY!B;)V|5>K{v{Dwr59I2j~*o9PsNLF`xvFAImH@-IQER^)LsI#l8=1(&=I z19$HD7xZe>r|-iA3kEdsHNf&{{44Op*NpJUyfH##at6B^9KnKfMaJtXoDCihnGFp{ zlX=_-(0&sm@S^dZT5bJsH5)ayrWXu?iaFSapW|{rKYV`iC#Q z5cLLe(cb7)qF3U$23-^uM8G-`bE(;In#hd4r;zSrVDDaZ9AQ1Nn(<6f)#BkVxq$@-b`-th`1TjA;gZ+Uo#@f_!|fw4 z+Y{}AlysO>JKxc#w?`Z2&XKo9TJtRR@MkKW50{*eIAR5nAhs+qM2@FS3~jz5Z01iL zJ2twLh`fA?ES?y_PIzO(jP%NBzDeeHTub6jUR<9UyWrhhqDFfrZ#2e1Bz8kP>pk$} ze3c~}(>k^T=Ig$L9Nf=la%0M+P9tMx))_j4vZ20Sl#TuCsDFhR(H|NR zjp#BR1$t0LDZ_sC0}AJxft~0`?&_&vq0;<4?Wn# ze=ESU2QLs=R5t9;J+|b%j1oYfH^vZJ3^b~zl;FX#GiRqvd0GZh4F$aI$2@S@9C_D8 zZrKF#nWI7(n~i10$(jBm4iJP9#~k=fkwrB+i%#(9!_&*8p%484EEd1==>%gxh5iKL z$wMx2MlSsL(fk*jkU99A&M<=6kv166VF316=%es3-BcO97V+;XGx+P8`K(a#`l(_j zQOv5gE=xnFMYs|eYeYxCL2xF*r6@q6!d;S0VCL;@Zh+JBhLeK&p|rb)oj*nt2?c@y zudZWp0>Sn>C(|>@q=SQ0keiXzN<1dZiWXZTHmjhd6g05{)@uYX(Qv2*1`&Fp$V=SV zi!P3tcgximioWclhV=_g#>h%)Gp3C>D`Z8Um|dN>ey+K1a~zTQ=^RX{6jtMk8_6?w>9}XB*^@gpX z580z*PIERGfg@H;Z&L6fgg`8rI`EIviNh7GukD1vp-nvuMWfQ z;Kag6=c|lkhA_#D@`c&qGk20U*2FgA>sFjblQ!uVHSn*W`y%7UuT2Ydb<>^qZ8hF8Nw$m ziN@fyL>fUAxWz7g)I73HSl;pA90crj_8&_Zu%hkc_4P>DOEnMN8ZKpUGzNWSVT96o z97hJnJuffA)-na$i$K!p;(>JaBonwK{lPv+B5l2O8pFkh{~BTKb7+1@V>sH-w?P8aT2e z8Zc6o*71EnD6-xv8{tkH`U5=#__#SC`xur$i*WC~Iwe<_ph!Wf5M0f#!I^fGxL*(_ z+-tR~;SJjJV*S5}t$cQTeR3gY?hBlPvezgnjNi{b!A`T@WpeOw5ll5uC%K!kr~1Bo z?W%>dR|{yP!3VH7?BG%B*tx)hKF4W2hoZ}Q@7K$5W3QosN2)=KAbo)fC21gX+;;(b zSR9RX0_xA&-N>1PUe-r(Sv%63NxqlgseU055TZuZQeP~1k;w7U%bGM`eF@`uGG12{ zxG|=KR@qq*Ve~q%IwTlzYeWwp#J?o2922uL8bA|G=$W|5-97fF#T}Xd65l(GY%l>D50RC}=)2 zZ2g57?JNn=<0HkWzwOj~J$}CTx<3!HvtY(2?=042-1UWd1_je#%qNzjfx*7_1M3P8P#m|+6lRBPo-JIt7El*?A%lc<>g4G+;*@{vVr;=@! zRSpKW+jYc3Y+BI7pBirZEGG30JB9P#nvms35>_gxW<;->c@Xmt3Cl>Zkb_@pV+Z*5rU zi~LW;ZtwA%PkiW$#(e7FdM3j1ioyuEe04*P5hH__%nCsL zxG@BVAUfE=5~N)ad<4}=Ij@YXyHI19=6iA3t168tP;2VWW({!>hWJgxl0iPU9aCKq z^$=)Kejv^FLPeRl$x(PLWLyp~zie7w;ADw{!$aX{U3eKGsuTOVk{%(L38n}^rsV<# z8)fy29uWdVg&h(&8)7vUnD+R&u}g?&WnfP4K?aPNICCVJ7`~Sm@F)7h^#fy5OO zNJf}crxH{K-##LVcWXop&=O;SlL)^y*3S6m@M7V~y0%*HWiZcAwA}cCVCUtn#gg!Q0 zp<{#ma9v?$20ax>Jr0Q!YSF?bJNHtfDKP=CWfidRqt&L1u`oNNp_~_oB+BE9v9b7T zPs2DOn6U|NQVQp?lixOevL2PtfPY#Ud#$~u^-8yuUNoTrhnJ(BM z*)Iips$>Pm?l+%Bl|ERZ(9|#+9fBMV@%Ez&}8z+ zDQQVhaxh?mQQqu9tnf;WjSWwM-Hr2koPS{cY%udC42R+c>G}sYN*FvqxJOtMw}#dp z5KS8>@tbfkU&d{WsE}-!zGUFIAz@KOy%dqdqYn~8y$WcA7{fnB6wHmmFD4dneaMwH zdV$5d^Ld&5?|AW(BB`@MF=?LWcBmVBpAQJx8<1~Z?RFVU31d%Y!d#jX=1GWBj&W^A zellVO<-~ozM&dr6RHym&`Z-J_CGSN&RT=6d#J*FSdL>#hk-Kh$&G-_@u$UM|M!d>6 z9@wa66)rqXDV1~@b`)Npt?3&<8_qa?pxJV6JuA>~e2L`EUrpTa367DltPHJla{1}y z9oW$05J-cFE%A2nlt}W0(AmtM7~Repz1NIfk*bPoCJg*&L&tjxX64U`^+gmyqqCn8 z^xUTt15q0eIuD{pH5{gyoy@tBR(K6Pi4)Qb1fe)qvq+rxs840u4Voo6T`+H2`L}~d zqpWv?mmXfDNh{6v8%LIR@TFjeOQkcS8+qF{WwVvt;ht**q9l$8;ob^9@IhZz zB6>WK?lu!wu$636R2bMmbOa*C$A-ipdbnfIKTH%CP<6%;UdXx;J~SPH+2t2*qQ3MB z4iGL+%fhlJtspGgJ8;$`kI2A|FVCW?XU097&hB1@D(jVE3r<14(sw|_Ce41I21VPb zAyHh7rEa|937m?XeJ%EOsL~-uy<+Y9!u*xslj?p&5qM}MuuMNtrc>BX3|-l_=(klm zVd28<0vzUY2bz-2viGS7{aA^#-kPw9WyslFm{=(I(`k(w!Ey;UaFdEp6E|FEX}1_Q zD~`gt6@`|nwF&|(>EX)&j677cr&g!T+t#m~(o4$gF}E+7xlGzsDQyn4gfTo!DulF$ zPAVn>YNXUba6W2=O=~sid!G&QPT#&R`pP2?Ihb+~LPx7==8MRYMII6={|o)7TLnnw zj!x({4cu&x^y`MR&3l6e8}{Zv{gX2u+cPZhOqJaa+}5eW-V8c`NP@6*>vDkL$)$c? zTXEEEsL@o)Lj>BN*{9t!?yL}=Th4=>4UgOEo(>B-^_E ze?lDxj-Qq+P*oZaV~`wN#^7Vb0&8pU#4UtL2M{*?*eH@7+XS(me+k~il8QPf^~@1C zIUO47xUPldNf57?omD7l5KxM25kEjD5a7iSCNr!Bkvr7CIbA5{TfRg@M!xmPKS7h=P*MA3E$I$3)UcSu>zkS0sl_=w0zib z<6k45_H(P8kJEZEv@7qfa%s(uGoXqtJbZUY!~_mQMe3;wg9O9~5I6{DK_Gl;77i>D zT?88tFd!x~!$m1jYiGg19vm7?$su}hHU?5eU4=;u&^Rt@2B|gOP4UP_Cpp5G=Yj94 zhv7EBgJ-0LG4vLs*LFNI0r;Zc3_#cJZG-NNAmi0ge*PlZ!La^$S4bp$;G7}APpYx_ zgQaJX}Aw*W2qmiw%im>Xu7#XkP=QZuLS9{?wEKGyindYP7()lkk3#}(3 z-W{;Id6Vjxbi{DVr?nY_$@6-U@Y*k$uec>9ftFezIZG?kR=z&Z9KB)u5N+re(*n*H zX2FI>NkR!Eb)IAkDtyt`0sG|iPa+0_c@z}Sd#3Wo)k&HPk=OfTen5pNR+$B)3_M>U z5U0W%)l2DhaOK9n42{Kv)sm|dYT&vsU4$fMr`Uzu>7r~Qd07y@2gt*p56&1E;jx2J zrjDB1ZZgKlM&Yd-9q7ELfbQtS2Zbd`(5H!~?vVB5)uzjG$>!QJ678EL=!ptUhVIzd z*u~54+UBzWxkqO)6hIFzPRTs7q7nugsHc%EM8bI^#}QKw&)_2V_!6Y(loV<3`UAbRPy@L}A}$S%%H)!{Sjo~a7L+nCPYH%I{@l~^d*2;i1UI~rf0D{llSTG7JvAi-mz&PDNs77dyzv{tXNCfOLdBaq%T z6%4$3hzR7g1I8WZq1cpM+IhN}W;EBw_be}*b+x1lEI?pl^V}WH$0B-J)%&{~(@==< zgl53$dNjgHJ8sW!jG?p1@r2J%R)Xsu+m-R!k5DTyaC!!9XL-g8Qe$Zc&~710{&Yv$ zt4^6Pbvt2+gzIcxOs3IJ{?^zvOi4gs);26sZgABmyCXu7GR&xvlQe1x`;*0X-u7Jj znB0+>#B)2y*LLzMv%hB4swPG{d^~$*YT_757DO&#x=DPFt)boU%GjX@+8xUa zJzZ!>v`C{!>kV>M**DodZ!8#SnqoTm=aHr{uR`AiQsz*e-t7Os4&2YXkxwI^VeE!t5}a4U4vCT>&C>t&rH#*7Xx$c zL(FGBFz4XUClSEn@21Lj7BnAAEL;ulixHF@p&TY1&YoI=vic|MIui&wTvCLsDHqYP zwE8hnG11yg$fd^1+^S+XFXJZ48;KqYnv-O&o=8LUXwi24BL&nr6zAp4&L1>! z(b8vtP4yrYJT&U#$9`{cQ*KGxnPw9~1&eXXG?Vr?q>*B%Ak<)uTzfKO=*q|6o$$QS@^P-t~! zKiuXW*MDId^{H|+IbLeu*LnEHfn%h0>>XY}6Ht>MkuSr-hSrA+P+F4sF?}(e52285 zi7{uz{CxQ{!sJJ=dOCUbxw?tRxg-;MmP{cSgd<-oLSQNp&|)OKz=YS(c)T^B*|PLe z7!@*AvP4C)jOn4UAts5m6L=yKMQo2@xFJPhAxaZDk?Asnl=I_-$^h+`7EDX( zpWA!viW<|Niq25Vl<3C8+$=&uurB1lKa>}_Vdacw!*pKSZk_hW*{qPlkbL*zCShaZC=>(cd6RFu(NuDqs z4mJ>YgT-hvER|y3JLv8FDvP32PtK{ijX^bpp7z4F@wYgK5$6)ab2nRX$$?;8afL6Q3k0*cagPPIPwE=P1CtDuGrN2A=$a$cxv z#^faqn8vZqdamFmQEK-}6|fys^X)IOMyJnC>pkv3ptwus@glueP53(ZJKsdfvp;-? zXX9KrE~I`UD-7leja-Y_=-JVs%*77~$0!>6eqte*60_e-pjr#XXz`ijuwPL*)T+T?D9Rp*J?rmpB*dEpk8XjW^a0)yp-rR*A@s~=g zV^=z=kdF3<3}8p$5zFqD2@YG9aS1MHyd%PBSALRkLuW@cX4=Xu3nW3qBBzL<=W52^ z!|amhN987kZctXJ8TKZ4n- zh#s@gmx;v=9wTMS39#*(+|GnTj>R-x}7+=5$arDJ1z95YT7Ff92Tmq^C9zqb^v|91&Gy0P~>jxs<6PTjv}<|E4;CZxbInh?sHze+ zl>ydE1`T^tfV5f^3%>$>pv~`0f;+#TVdxmuO2K>8qpGr5r0%UhIZfDqn^!Vpz4sgI z&d_Za8yXWvH+VcP8POw)GbfLTeq_L}XTmgaqvM1MO`P%5w<~sWQSzp(;-IHm1lu!c z^3Acp&v1s11E5R6EPDDAIHX%mS+A4b+OyAvxn^ud7JOmYHynGpRhy_5)ZFi$e4kYg zNQ2(VVespSAG*+7EEqL`7DD`q?sc5ks^wP9Q$WJ8vTLTw^hx4|BSu_vV#bf7FksD2*rvA=+onQFiMed{OCOM*&FxCy@`vHaN`>I8w`+-EH3hlqgP?w z&_^|Bx7}Q<y;GkmhAp2_wdyPa%gX~)(EE&pn4w{`~0>R;UhcUD!zC~MHZkg5iFJ?*|>3A{_ zJf^1JPLpx0fvchKD*Hwk1gUD070QOVITRxHDbtC_)iN~- z?tPk^7{{Q3FrL}=vjuRy^=8h!5zO@a(J7KYa1$ z`DT8EZ3xiL3NgWAcTjm^KK1xL{KakG3>T{!rI#umkz*QG0UjXMe8Ft7`TNj%`(1v@QDnGa^LH0d9yQnJ^h=v!|nJtuG=22hm${(Oq65D%_gRR8Fy<; zH=mqa(Y>CLR^O(YvpTF^bCXw24XWDKH^46!V~LiqfiG1q>|nJQhNRR5dm!+M69R_S zC;Eb&_*j8r#mJYdE)Na#7Z^QW%BrgLaM3=g6B-y?V4S*$_k$#Eg+!z_+!%h^X3JwZ z@;&dTw`2@K7_1C^1>*-8An;@BR3jsqv4NmyCsv1p0bFCj&WqfTdI% z0hWLmcG(XiH&2AL5K3*#4@-SG&K?4B6e3rAN7=1M1N zIW}T1in+s@OOjnv@T5$bL@K+Pq zPbohFr-7dmX%T(47p_?5%A`I~UDehKlj$iq0K4LE8@B`qHCtJtDG)i z;LCg%rd*xB8;2NfbaEc#`h(sLgbxLe#Zhi0)O!p$I}yQo)puKeZl9Xv#&uHS##Mbf zGk2je6f@%d6z)fn#(FR?#tiz1lGoH>a?o2?GvHC^+=?;ll?BkFx#MSu<=2NFo-;Vs z2X%9jVlQf3I~OPWUDQ^-BRKs|OnSBR3PUBT5J)P9INf(+!%r|X$9&&@bs5zU)O0v} z7Vn8-nndwE;#o$#UzekyPaOeZvK)<;m!0C6DPKcF6`%m{Pf$|*t1gI zETL4SM)chqFHZZDAp2=4uDuC@1WphT-L}OAp+NNXeit%(VoM7nxRK)rOxs3F=)`9A zJ=}Di6n_tLNWoo#UA8K*gw&#kfkMw19x|4R*eN5;J)YMU9v>i4J+{QY;wWI$IYro@ z6v#DEQd85DzZGv8&s+t|ovr1!590uKD~cuo9oo_N=9CdaO1mF&<3~z6Pb7l-A5lLTqcS;zXW71R z%fbv9F_Lg_+h%Qyl&`CtAd|$Eqb7`9CAegwo^WA|Y=vXti=sgSaDCEv7}#tLL|k-vLW|kFXD!++|0?miI;pMCQJ^;P7+nH zP=y;07|(4+Iy8}?V+QpVqz%Pv=1#eFs7fdEZ))8xSl;1AQ;lT~^&OGyov>kvAk!|w zTaKH!5FRAxZ(1XGP(cXDJ9RIz6p5XF_tUR#r92~=U{-aWpLZ7p_CnvYa;t!`Ost<$ zxEI5FI*J{kZ=#9~#}jBm4ntP_pC&SUW)M#U1z^IsT@^Qfg`QxRX!h9bzBjXYCkCR@ zHN`&Yh_tRzyBy?iN%Tu*k=eu;*>ZY(U&m*rZMhc=CaZ4LTo7@`6;^51(j;)0BY>n1LN~#`(B`BN+xNEqkji#p!q&17O67nT-quyz4j8#a*5B5bAKaSkjP9 z(dyR`qk_IIo8Z;8*c5HRQKZ^6ubESLRwGr-u(?l(g+YxCIM~>gc8l2vqRsfqpe71U z^IR691lZ6qDC_5O3=Xact#`yxz74%_azhY(j;|uSMKZAAb}%e-=av$Ww&@NW^xhNk z>$tH=(MtHM^^&7^VgB%BC?*3c?6nMThl|YS`!+4oI=Z5sJpk9XHlq5^18nK6_1V%>?Xr5CQ&L9%Y|K;(1%Zr4UBk7Rfa_9LA9@rMhHnjA%F^ zu_MA{fe>~DNmIdfE;JMpQ0(S$FpT`@utj%r8^K9W(yhr9J=)w%v@p+=-52h3%AmJ)-iZXCxCjE<@7-MC|>40$VQ!FZQT^{yIE9Y~R zLZ^&dCvih{u203t7^hR@%z6cB-1j*;htb%N4mu_GH&>1J$19!c5xA0*x+rq$Uv53i z%gqi%HN>-!FsPBsMQ0OLXuv+CkpV{?F&Y}AH=E|@6Xuv<8PDp?SYKkU3hb?<0AW%fu4g7BQ~KDpe^^lAedhsO&xKIxVGOJ z4r`1cq$>#>La#BgFH5EL3zmGaReIX5yk;zgxF_5WOZ>_0cftD6@qB&}jWLYI^YUZ) zX;{o8`CjAQN8z@{L&nNZM112kDP=?NN28N%LH%gFjknCaH=W zjB1fAh_A-dOUely^bXIcrQ^Dv4^)}h5JEW$CGNmb0X;}YP*Rvxe%-q_ZyLXL%Y)4| z<;H*^ufck2Lve*r6^z8M;UL_&{H;Scaa0ssdI;tzM*VK-Fg(Dtii4WI!V=+8OzE5ggeP=_V5zC*e1w zOU)`7AdDHp{3`H^u_B&4Amna*R(MP~@khnQI46Ga+#1U5g9hkIkfAN{_!tG32t~m{ zJKMr2o^jBIc!GB>1~}z{q=2Z%K|~DRPqKVRgb0E#zdf4%4FEbj}Z|U5-)S#N_UgEolbrZsc?A$=h&5 zh8d;dX64Zyfk~E#dr+h#*fEvh)UVEKVuDz>vV~^_tF=^9+OJv0uVMub@I&k?C~#E@ zP7`K_p*e^c)!rzKXN2sCtXrVQYe9xYff+L{nVm z29jULLqobw7sBfl+8LSIRhnBu?*ker_>Yeo(3Zvpl0_iCirKPBUI-Q%$)G6k_e>b( z(z8pd!D*o$>p=AI%%|5bYuquHTs2dXTFfoqL?XN{oG5iKhmsw}JBO34c!{bx-Bt^4 zDt07OZ|N~37BPl_g%PdO^=tiVZrutL z7|(bT^M$kzFCCfa>^CFHy=S}IdY;WI#s$lc0&u+|=wedi6qz_O@(;0ShOdT+8@~)M zZ@nO=#RU&@V&^&W;YpHE+MgaYL?uA0J3HHSi~Mi6+;od%Hx?&jr^z9prfC&+7~itf z@30?1SHvG-b|fzSCL6qttI)0yKRG;XtB{QB5FyMIVgZ7vKq4-t)*FJWz{H%< zS>e&9Y)g+QYgxd`%=lww#`9%I5XluBY+QwgfeATfNLi7kp{{6Nm)V8sv%;Dn(u!ow zm!|G;xp5wI!y8D1NOh%(@k5ZL5aZw@Fjxkyz`%uuQ3e?5nMp1oyd~Dhrjs;W)WIR{ zkYaq5#x=%Fog;;Xj}zC5{p`(2zN;k?uN>LQAaU*5gM|{Fj^Oatam{|6bHR)sIYFU00?R5Q7jdkHgf+DA+A8+Nu^$pN9~3VR3&gRpXlshdY=Vr6 zYm#VN`md-&-nve7F(!6iD>DTzhnzCyT2e5dnqhw*C)WkLhyxh>Y$#P$U z8MYr)ruxDJ$Sm1D2|6ttw})!bPO-~~ru;sjAopQBBSJ}rU|_2REvR!8g^x(Da8W!u zNv1jq-X2t;^m!Dw(Y`HSy#qLQg3!=23`)J=-y_1hRmx3hFK}(x)Mi|VF|@r3R1w4{ z*>Xa*Jj($1ER;XAPC*%;%=undR2%X`Ma8pZwq7r0VlWY{zS|st{pR0F6NJ73xx5o!N zxG#Z(RW2aTbm+twFvxh>(^*O`F0U|zYFG$KwzNV=MuQU~T9IE3r4-_J+-TTAsMMgMFk-D7E8jur zhRArrMdZU^eJaX_Q-18X9U?E6c}awXF?b`je;_f$MSc+ES3*N0bdr6C=JL}wqO{PC zQcrjiEGmm0SoFH?o`QtIL8UNnu0D2Al1qG-FT?pmK?^KTWGXAkhrel3W^6QN269BC%LaQ zj|Q=za+JfWgzw*fG@qt4}Q>FF+fR*Ta1(mll#bYy#sgs`Insi9&xR@pG)7c+TfQnLuS zWVtkC{4CaXGSorCel|hMwcxLqYm{rbl1w%6$6$Ez22%1DoE>J zI9&HWWCf5Nxxpr2)OTZTKF>E|b)imfC+V~n*}9Wv`xEGV>U9WD{*UMZ{v|)a0@f@a z%J>lv=lpaks(&^=h5kQ(LiF0d=4~UazLlCZRVw835j7vqxQ;-n0%4<(645m@$>FI$ zXJ==bs(Y-5TpbZeyqCKV4YBpmM{nkM{$?{*6MA8MjYGnRx->QlEQg0+AU~UKHBId0 z!aY?{n0~@5kfl?dwDfgPYtND(@u!{dFMWr`4~%bl)ONul(rh9S$Zb)JDA^w+gZ0l| z-=?uV9W|*KD99s<Mr$?MZvr4@Cw-9?{RWwDl0(VIQN2^~xYPGig2 z;RqbPgcDW|kr%aIuYz!5GRVK6q=C!rj@HILwhvvIcEWquMs4lU1Gq5^)knuMV(tuB zv*NDI4l$7)I|FFH4o%hh=*`M#I$(EaFv=+I;cVy~#tddi_sES_o- zBVfj9heB}s;d?cuGGvnTwH?zZ0 zvJl~a9yWYYLVKo_6v8%fj=9(;7zuW}OdYYn{9iSp^9IABR{Aa`x6w$1 z2f?sIs(GOm!Q^Z3t?yp4P((8gMmXLFP_wFp;RJ;gr}Yt|QVazHK5YaMs}k_DRiS}T ziyub)ed|6EMB^bQ!cS;Fb|`nYa`I8VxFDCM&^0`X@V-uhTb3|k7T#L9?=#VBJ@*GN zcfjr@EO0yh>cQc0;^0+ zu8Sr~IPAu_W|--h@rJm<95P~@#O$cNChqTYG*N?E&HPbDpw(oEL#B1c(z7%6>88dZ zRPdhRC>PqnXFIJ8h7^dQC_V3Uv6WziE_H=972!-85J;hVE$A4H2hJ7Z3PZ4nuE_a} zHy8KZ8-2-qO}mzTs_7i*ew8{Dn8=+VlJa!#1Tb)mY5Fz1ItkpG9N{=Sot*Y?UP&@` zBxxb~C_Q+Kx2k-zDjsg&_g9kvJM2UW=MlU*TH_ZgurcyRu#h)-A{`rxqtrR911(sQ znA|Xyfht zQZsMHYo!~qe{C2uGC(75p9Sn>h4TDEg&wW08D&Uo)V%j3Ko^}p-tU1O=skimNs!lS zVaw|1aj+i}|mJ>9@}=zrqwNT&)C2yiSrK!_AAtpET3 literal 0 HcmV?d00001 diff --git a/util/fipstools/acvp/acvptool/test/tests.json b/util/fipstools/acvp/acvptool/test/tests.json index 5765de1791..f1cb04f932 100644 --- a/util/fipstools/acvp/acvptool/test/tests.json +++ b/util/fipstools/acvp/acvptool/test/tests.json @@ -9,6 +9,8 @@ {"Wrapper": "modulewrapper", "In": "vectors/ACVP-AES-KW.bz2", "Out": "expected/ACVP-AES-KW.bz2"}, {"Wrapper": "modulewrapper", "In": "vectors/ACVP-AES-KWP.bz2", "Out": "expected/ACVP-AES-KWP.bz2"}, {"Wrapper": "testmodulewrapper", "In": "vectors/ACVP-AES-XTS.bz2", "Out": "expected/ACVP-AES-XTS.bz2"}, +{"Wrapper": "modulewrapper", "In": "vectors/ACVP-TDES-CBC.bz2", "Out": "expected/ACVP-TDES-CBC.bz2"}, +{"Wrapper": "modulewrapper", "In": "vectors/ACVP-TDES-ECB.bz2", "Out": "expected/ACVP-TDES-ECB.bz2"}, {"Wrapper": "modulewrapper", "In": "vectors/CMAC-AES.bz2", "Out": "expected/CMAC-AES.bz2"}, {"Wrapper": "modulewrapper", "In": "vectors/ctrDRBG.bz2", "Out": "expected/ctrDRBG.bz2"}, {"Wrapper": "modulewrapper", "In": "vectors/ECDSA.bz2", "Out": "expected/ECDSA.bz2"}, diff --git a/util/fipstools/acvp/acvptool/test/vectors/ACVP-TDES-CBC.bz2 b/util/fipstools/acvp/acvptool/test/vectors/ACVP-TDES-CBC.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..33fdbf35ad4f6f3923654e50615fc5a259dc32c2 GIT binary patch literal 1009 zcmV}m zlN9nadXv!spa1{>0BTG$(-2Y`44MD{000Q5lO~xN2}A*)00000<^TWy0000007Vis z6A@F|22{!Fcp;Ne@{F6*ndM8=QPAU)5ar9xh(tX7TeolO-(B?Iq-c(yM>KOrw`6L| z3vtSGoR=sdh=?G7S5_Z0JOS8%f^{mR?o>iTy_T8&5%WfA`}XvoupKZ@b;o~9jnhg6 z_*vFA+Z}jy(@_`JYX$jXkGq*s*l`jJM-YQRk>PE&#LxE?Y%Ge!lRPR7C|Oanh3Neu z7!mxdW~CngfXMix3rYesMiyZhl|lo?*n4|HlygQAqA-9I*U#7O?S75&eh8@>q#sBr z7{I;~NVf~q;ZJ?Q`4$oi)L-Yi>pzTDso`78FSx+&x^?D!qd0No1At)TNPt|BJ6y8o zk}hnX@)5=%y^xVr1>}uU+2U52)C3~qnt`2@X{s=|CtlC!!uyPqolaxS+6e~J4Fa-2 zSq2pnsj(r6Dp4F!9dyjaC9}&R#V`mD4)9>p0R(IhOQ(4{WuX<+N?J)0Lp);1gRUfF z(@9Awt5s}$90w2w5}P|fI9#d9xE29=?~T=U^Atr;?KQHD;`l^qtr}|rSVf700$7||Uo7G|6%1t=SMU7MjM>`#F#%$c}G+e@p$ z(<{22=Xul69(Osu7$#s#N>dm>&JA{TfQ}?`2Xw%j*e%TKfU{W_HlS>3Nv-VoB%sE)3+cfu~{ysM?pL>kX#HFk`* z96Cy7s*FvL6X=G((?v|+DOI+dRO}WI;Z1kD|v2{w3ZwYNr* zF-l0TvH}9lVEni|2w;diCP*M5ipoE0?Wx4)2X4LAi%shK{GvRO)3QDnqvSq|V9LL9 z?4v~wUo?Grdk;cBh0B?mEEaJDXpV^CC!#x~MhsEI93=oFEpz$fPD(pgh{*`Lj?1w# zM{e0iHR6sYDAH}^%P#bJ`KXUU8frQYWm=&h(=@>|Ha&qP81{)G#-=yuM@{^ literal 0 HcmV?d00001 diff --git a/util/fipstools/acvp/acvptool/test/vectors/ACVP-TDES-ECB.bz2 b/util/fipstools/acvp/acvptool/test/vectors/ACVP-TDES-ECB.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..c8853ed2219388ed707949cbee9a3cec0864ffe7 GIT binary patch literal 930 zcmV;T16}+=T4*^jL0KkKS$D$JumA?OUw~C~PzV3;KcdeHF7MwePy`%$CBOiKLzn;n z0000000F6p#Apd7g&F_=9-|W=1DF5+00000009(81jRKTrkK=ekkG`?^nvJ^wLv0< zPt!;c^)`v7Kzbl(&OphqNfM$2zCV|{pI zIZi8#5JW@}LaD0{sg>rj5krtcA83dY7JI9Fk?lu{oiWF6psea*t)en9i%gxaS92M# zRXUk298%F>Bv=#_gM5YGLWM_tWko89n38wa4Jv}6ru$L-LNFubtym!ZK0_naj4ddr zQ5ac-VpRwZs^RJB22srzMu@;8O?y3iw_TfbpW1ocF&+7)V@bF$ueF3S)vfzcZg&q8mYRstAZexlP< zSFk<$3b$%kLbm#)j%a=FXkOyNz~yfSXzuGyptrlC1@9p#r=TIC0$t(8<8kDjsna}d zi*`PQw^E(S`>NJw*zV8d3~TUxb5AV%DpasvRHrV@0!gT?B5 zeAiROLB?B77Dhra(?%2D7YbPf!Gbs8e1b8L6#4L`iaQpF$q2fRi*PbWX30k-;Eo0e(reR9ekifo6e~xH`DtQF zO$v+~ZMH-LI7G7zC|MPwVlZ>sjk`75c@b5mBoX{0VmBTr=!`-$AjkY&$rRy2LEj5f Ez!l=2@Bjb+ literal 0 HcmV?d00001 From 5697a9202615925696f8dc7f4e286d44d474769e Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Thu, 21 Jul 2022 10:35:59 -0700 Subject: [PATCH 37/38] Add SSL_CTX_get_num_tickets. CPython uses this function. Our implementation is slightly weird since it leaks the clamping behavior, but probably not a big deal. Update-Note: When this is merged into the internal repository, we can simplify the CPython patches. Change-Id: I291ddf852fb463bf02998fe04d0d0e8cb358dc55 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/53485 Commit-Queue: Bob Beck Auto-Submit: David Benjamin Commit-Queue: David Benjamin Reviewed-by: Bob Beck --- include/openssl/ssl.h | 4 ++++ ssl/ssl_lib.cc | 2 ++ ssl/ssl_test.cc | 2 ++ 3 files changed, 8 insertions(+) diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h index 0e54ab9eff..3a2a86199d 100644 --- a/include/openssl/ssl.h +++ b/include/openssl/ssl.h @@ -2288,6 +2288,10 @@ OPENSSL_EXPORT SSL_SESSION *SSL_process_tls13_new_session_ticket( // By default, BoringSSL sends two tickets. OPENSSL_EXPORT int SSL_CTX_set_num_tickets(SSL_CTX *ctx, size_t num_tickets); +// SSL_CTX_get_num_tickets returns the number of tickets |ctx| will send +// immediately after a successful TLS 1.3 handshake as a server. +OPENSSL_EXPORT size_t SSL_CTX_get_num_tickets(const SSL_CTX *ctx); + // Elliptic curve Diffie-Hellman. // diff --git a/ssl/ssl_lib.cc b/ssl/ssl_lib.cc index 0b3febf110..bbcc3b136b 100644 --- a/ssl/ssl_lib.cc +++ b/ssl/ssl_lib.cc @@ -3037,6 +3037,8 @@ int SSL_CTX_set_num_tickets(SSL_CTX *ctx, size_t num_tickets) { return 1; } +size_t SSL_CTX_get_num_tickets(const SSL_CTX *ctx) { return ctx->num_tickets; } + int SSL_set_tlsext_status_type(SSL *ssl, int type) { if (!ssl->config) { return 0; diff --git a/ssl/ssl_test.cc b/ssl/ssl_test.cc index fe85840d55..6bc015cb15 100644 --- a/ssl/ssl_test.cc +++ b/ssl/ssl_test.cc @@ -8151,11 +8151,13 @@ TEST(SSLTest, NumTickets) { for (size_t num_tickets : {0, 1, 2, 3, 4, 5}) { SCOPED_TRACE(num_tickets); ASSERT_TRUE(SSL_CTX_set_num_tickets(server_ctx.get(), num_tickets)); + EXPECT_EQ(SSL_CTX_get_num_tickets(server_ctx.get()), num_tickets); EXPECT_EQ(count_tickets(), num_tickets); } // Configuring too many tickets causes us to stop at some point. ASSERT_TRUE(SSL_CTX_set_num_tickets(server_ctx.get(), 100000)); + EXPECT_EQ(SSL_CTX_get_num_tickets(server_ctx.get()), 16u); EXPECT_EQ(count_tickets(), 16u); } From 4d7b383e989eff619a60eb1da1b18f613af65daf Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Thu, 14 Jul 2022 19:02:34 -0400 Subject: [PATCH 38/38] Remove PEM_X509_INFO_write_bio. Nothing calls this function, it doesn't support most key types, and accesses pkey.rsa without checking the type. Just remove it. Change-Id: I073dfe74c545c7e08578b85105c88a19bbddf58a Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/53505 Auto-Submit: David Benjamin Reviewed-by: Bob Beck Commit-Queue: Bob Beck --- crypto/pem/pem_info.c | 81 ------------------------------------------- include/openssl/pem.h | 4 --- 2 files changed, 85 deletions(-) diff --git a/crypto/pem/pem_info.c b/crypto/pem/pem_info.c index e30faa3f3b..04b4743709 100644 --- a/crypto/pem/pem_info.c +++ b/crypto/pem/pem_info.c @@ -263,84 +263,3 @@ STACK_OF(X509_INFO) *PEM_X509_INFO_read_bio(BIO *bp, STACK_OF(X509_INFO) *sk, OPENSSL_free(data); return ret; } - -// A TJH addition -int PEM_X509_INFO_write_bio(BIO *bp, X509_INFO *xi, EVP_CIPHER *enc, - unsigned char *kstr, int klen, pem_password_cb *cb, - void *u) { - int i, ret = 0; - unsigned char *data = NULL; - const char *objstr = NULL; - char buf[PEM_BUFSIZE]; - unsigned char *iv = NULL; - unsigned iv_len = 0; - - if (enc != NULL) { - iv_len = EVP_CIPHER_iv_length(enc); - objstr = OBJ_nid2sn(EVP_CIPHER_nid(enc)); - if (objstr == NULL) { - OPENSSL_PUT_ERROR(PEM, PEM_R_UNSUPPORTED_CIPHER); - goto err; - } - } - - // now for the fun part ... if we have a private key then we have to be - // able to handle a not-yet-decrypted key being written out correctly ... - // if it is decrypted or it is non-encrypted then we use the base code - if (xi->x_pkey != NULL) { - if ((xi->enc_data != NULL) && (xi->enc_len > 0)) { - if (enc == NULL) { - OPENSSL_PUT_ERROR(PEM, PEM_R_CIPHER_IS_NULL); - goto err; - } - - // copy from weirdo names into more normal things - iv = xi->enc_cipher.iv; - data = (unsigned char *)xi->enc_data; - i = xi->enc_len; - - // we take the encryption data from the internal stuff rather - // than what the user has passed us ... as we have to match - // exactly for some strange reason - objstr = OBJ_nid2sn(EVP_CIPHER_nid(xi->enc_cipher.cipher)); - if (objstr == NULL) { - OPENSSL_PUT_ERROR(PEM, PEM_R_UNSUPPORTED_CIPHER); - goto err; - } - - // create the right magic header stuff - assert(strlen(objstr) + 23 + 2 * iv_len + 13 <= sizeof buf); - buf[0] = '\0'; - PEM_proc_type(buf, PEM_TYPE_ENCRYPTED); - PEM_dek_info(buf, objstr, iv_len, (char *)iv); - - // use the normal code to write things out - i = PEM_write_bio(bp, PEM_STRING_RSA, buf, data, i); - if (i <= 0) { - goto err; - } - } else { - // Add DSA/DH - // normal optionally encrypted stuff - if (PEM_write_bio_RSAPrivateKey(bp, xi->x_pkey->dec_pkey->pkey.rsa, enc, - kstr, klen, cb, u) <= 0) { - goto err; - } - } - } - - // if we have a certificate then write it out now - if ((xi->x509 != NULL) && (PEM_write_bio_X509(bp, xi->x509) <= 0)) { - goto err; - } - - // we are ignoring anything else that is loaded into the X509_INFO - // structure for the moment ... as I don't need it so I'm not coding it - // here and Eric can do it when this makes it into the base library --tjh - - ret = 1; - -err: - OPENSSL_cleanse(buf, PEM_BUFSIZE); - return ret; -} diff --git a/include/openssl/pem.h b/include/openssl/pem.h index a94f27668e..56075ae8a4 100644 --- a/include/openssl/pem.h +++ b/include/openssl/pem.h @@ -349,10 +349,6 @@ OPENSSL_EXPORT int PEM_ASN1_write_bio(i2d_of_void *i2d, const char *name, OPENSSL_EXPORT STACK_OF(X509_INFO) *PEM_X509_INFO_read_bio( BIO *bp, STACK_OF(X509_INFO) *sk, pem_password_cb *cb, void *u); -OPENSSL_EXPORT int PEM_X509_INFO_write_bio(BIO *bp, X509_INFO *xi, - EVP_CIPHER *enc, unsigned char *kstr, - int klen, pem_password_cb *cd, - void *u); OPENSSL_EXPORT int PEM_read(FILE *fp, char **name, char **header, unsigned char **data, long *len);