From f068def344212558323b66ff902a5d6f58fb5460 Mon Sep 17 00:00:00 2001 From: Robert Sloan Date: Wed, 10 Oct 2018 18:45:40 -0700 Subject: external/boringssl: Sync to 2d98d49cf712ca7dc6f4b23b9c5f5542385d8dbe. This includes the following changes: https://boringssl.googlesource.com/boringssl/+log/5ede28c8a422801ace3ba5e466ba963005351145..2d98d49cf712ca7dc6f4b23b9c5f5542385d8dbe Test: BoringSSL CTS Presubmits Change-Id: I21750d81b070d7e4741e205f5c2ccd8d541b36d1 --- src/BUILDING.md | 6 +- src/crypto/CMakeLists.txt | 1 + src/crypto/asn1/a_d2i_fp.c | 238 ++-------------- src/crypto/asn1/a_dup.c | 24 -- src/crypto/asn1/a_i2d_fp.c | 82 +----- src/crypto/bio/bio.c | 13 + src/crypto/bio/file.c | 3 +- src/crypto/bn_extra/convert.c | 10 +- src/crypto/conf/conf.c | 5 + src/crypto/fipsmodule/CMakeLists.txt | 8 +- src/crypto/fipsmodule/FIPS.md | 2 +- src/crypto/fipsmodule/aes/mode_wrappers.c | 13 +- src/crypto/fipsmodule/bcm.c | 1 + src/crypto/fipsmodule/bn/div.c | 12 +- src/crypto/fipsmodule/bn/internal.h | 4 + src/crypto/fipsmodule/cipher/e_aes.c | 75 +++-- src/crypto/fipsmodule/modes/cbc.c | 4 +- src/crypto/fipsmodule/modes/ccm.c | 14 +- src/crypto/fipsmodule/modes/cfb.c | 10 +- src/crypto/fipsmodule/modes/ctr.c | 11 +- src/crypto/fipsmodule/modes/gcm.c | 16 +- src/crypto/fipsmodule/modes/gcm_test.cc | 2 +- src/crypto/fipsmodule/modes/internal.h | 77 ++--- src/crypto/fipsmodule/modes/ofb.c | 2 +- src/crypto/fipsmodule/self_check/self_check.c | 7 + src/crypto/fipsmodule/sha/asm/sha1-armv8.pl | 1 + src/crypto/fipsmodule/sha/asm/sha512-armv8.pl | 1 + src/crypto/internal.h | 8 +- src/crypto/pem/pem_info.c | 306 ++++++++++---------- src/crypto/pem/pem_lib.c | 53 ++-- src/crypto/pem/pem_pkey.c | 34 +-- src/crypto/pkcs7/pkcs7_x509.c | 12 +- src/crypto/pkcs8/pkcs8_x509.c | 12 +- src/crypto/pool/pool_test.cc | 4 +- src/crypto/rand_extra/rand_test.cc | 10 +- src/crypto/refcount_test.cc | 4 +- src/crypto/rsa_extra/rsa_test.cc | 4 +- src/crypto/stack/stack.c | 57 +++- src/crypto/stack/stack_test.cc | 394 ++++++++++++++++++++++++++ src/crypto/thread_none.c | 4 +- src/crypto/thread_test.cc | 4 +- src/crypto/x509/by_file.c | 22 +- src/crypto/x509/t_crl.c | 13 +- src/crypto/x509/t_req.c | 4 +- src/crypto/x509/t_x509.c | 13 +- src/crypto/x509/x509_test.cc | 122 ++++++++ src/crypto/x509/x_all.c | 325 +++++++-------------- src/crypto/x509v3/v3_genn.c | 7 +- src/decrepit/x509/x509_decrepit.c | 26 +- src/decrepit/xts/xts.c | 20 +- src/include/openssl/asn1.h | 72 ----- src/include/openssl/base.h | 82 +++++- src/include/openssl/bio.h | 6 +- src/include/openssl/conf.h | 5 - src/include/openssl/cpu.h | 10 +- src/include/openssl/pem.h | 164 ++++++----- src/include/openssl/ssl.h | 6 +- src/include/openssl/stack.h | 166 +++++++---- src/include/openssl/thread.h | 2 +- src/include/openssl/type_check.h | 4 - src/include/openssl/x509v3.h | 7 +- src/ssl/handshake_client.cc | 2 +- src/ssl/internal.h | 4 + src/ssl/ssl_lib.cc | 11 +- src/ssl/ssl_test.cc | 4 +- src/ssl/ssl_x509.cc | 22 +- src/ssl/test/runner/runner.go | 104 +++---- src/util/ar/ar.go | 148 ++++++++++ src/util/fipstools/delocate/delocate.go | 3 +- src/util/fipstools/fipscommon/ar.go | 120 -------- src/util/fipstools/inject-hash/inject-hash.go | 175 ------------ src/util/fipstools/inject_hash/inject_hash.go | 176 ++++++++++++ src/util/read_symbols.go | 170 +++++++++++ 73 files changed, 1976 insertions(+), 1587 deletions(-) create mode 100644 src/crypto/stack/stack_test.cc create mode 100644 src/util/ar/ar.go delete mode 100644 src/util/fipstools/fipscommon/ar.go delete mode 100644 src/util/fipstools/inject-hash/inject-hash.go create mode 100644 src/util/fipstools/inject_hash/inject_hash.go create mode 100644 src/util/read_symbols.go (limited to 'src') diff --git a/src/BUILDING.md b/src/BUILDING.md index ab9b71d9..01f5480b 100644 --- a/src/BUILDING.md +++ b/src/BUILDING.md @@ -128,7 +128,11 @@ the prefix `MY_CUSTOM_PREFIX` to all of the symbols listed in `/path/to/symbols.txt`. It is currently the caller's responsibility to create and maintain the list of -symbols to be prefixed. +symbols to be prefixed. Alternatively, `util/read_symbols.go` reads the list of +exported symbols from a `.a` file, and can be used in a build script to generate +the symbol list on the fly (by building without prefixing, using +`read_symbols.go` to construct a symbol list, and then building again with +prefixing). This mechanism is under development and may change over time. Please contact the BoringSSL maintainers if making use of it. diff --git a/src/crypto/CMakeLists.txt b/src/crypto/CMakeLists.txt index 78b835cc..ee9626a1 100644 --- a/src/crypto/CMakeLists.txt +++ b/src/crypto/CMakeLists.txt @@ -467,6 +467,7 @@ add_executable( refcount_test.cc rsa_extra/rsa_test.cc self_test.cc + stack/stack_test.cc test/file_test_gtest.cc thread_test.cc x509/x509_test.cc diff --git a/src/crypto/asn1/a_d2i_fp.c b/src/crypto/asn1/a_d2i_fp.c index 3da6df9b..fd423e27 100644 --- a/src/crypto/asn1/a_d2i_fp.c +++ b/src/crypto/asn1/a_d2i_fp.c @@ -58,240 +58,36 @@ #include -#include +#include #include #include -static int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb); - -#ifndef NO_OLD_ASN1 -# ifndef OPENSSL_NO_FP_API - -void *ASN1_d2i_fp(void *(*xnew) (void), d2i_of_void *d2i, FILE *in, void **x) -{ - BIO *b; - void *ret; - - if ((b = BIO_new(BIO_s_file())) == NULL) { - OPENSSL_PUT_ERROR(ASN1, ERR_R_BUF_LIB); - return (NULL); - } - BIO_set_fp(b, in, BIO_NOCLOSE); - ret = ASN1_d2i_bio(xnew, d2i, b, x); - BIO_free(b); - return (ret); -} -# endif - -void *ASN1_d2i_bio(void *(*xnew) (void), d2i_of_void *d2i, BIO *in, void **x) -{ - BUF_MEM *b = NULL; - const unsigned char *p; - void *ret = NULL; - int len; - - len = asn1_d2i_read_bio(in, &b); - if (len < 0) - goto err; - - p = (unsigned char *)b->data; - ret = d2i(x, &p, len); - err: - if (b != NULL) - BUF_MEM_free(b); - return (ret); -} - -#endif void *ASN1_item_d2i_bio(const ASN1_ITEM *it, BIO *in, void *x) { - BUF_MEM *b = NULL; - const unsigned char *p; - void *ret = NULL; - int len; - - len = asn1_d2i_read_bio(in, &b); - if (len < 0) - goto err; - - p = (const unsigned char *)b->data; - ret = ASN1_item_d2i(x, &p, len, it); - err: - if (b != NULL) - BUF_MEM_free(b); - return (ret); + uint8_t *data; + size_t len; + // Historically, this function did not impose a limit in OpenSSL and is used + // to read CRLs, so we leave this without an external bound. + if (!BIO_read_asn1(in, &data, &len, INT_MAX)) { + return NULL; + } + const uint8_t *ptr = data; + void *ret = ASN1_item_d2i(x, &ptr, len, it); + OPENSSL_free(data); + return ret; } #ifndef OPENSSL_NO_FP_API void *ASN1_item_d2i_fp(const ASN1_ITEM *it, FILE *in, void *x) { - BIO *b; - char *ret; - - if ((b = BIO_new(BIO_s_file())) == NULL) { + BIO *b = BIO_new_fp(in, BIO_NOCLOSE); + if (b == NULL) { OPENSSL_PUT_ERROR(ASN1, ERR_R_BUF_LIB); - return (NULL); + return NULL; } - BIO_set_fp(b, in, BIO_NOCLOSE); - ret = ASN1_item_d2i_bio(it, b, x); + void *ret = ASN1_item_d2i_bio(it, b, x); BIO_free(b); - return (ret); + return ret; } #endif - -typedef struct asn1_const_ctx_st - { - const unsigned char *p;/* work char pointer */ - int eos; /* end of sequence read for indefinite encoding */ - int error; /* error code to use when returning an error */ - int inf; /* constructed if 0x20, indefinite is 0x21 */ - int tag; /* tag from last 'get object' */ - int xclass; /* class from last 'get object' */ - long slen; /* length of last 'get object' */ - const unsigned char *max; /* largest value of p allowed */ - const unsigned char *q;/* temporary variable */ - const unsigned char **pp;/* variable */ - int line; /* used in error processing */ - } ASN1_const_CTX; - -#define HEADER_SIZE 8 -#define ASN1_CHUNK_INITIAL_SIZE (16 * 1024) -static int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb) -{ - BUF_MEM *b; - unsigned char *p; - int i; - ASN1_const_CTX c; - size_t want = HEADER_SIZE; - int eos = 0; - size_t off = 0; - size_t len = 0; - - b = BUF_MEM_new(); - if (b == NULL) { - OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); - return -1; - } - - ERR_clear_error(); - for (;;) { - if (want >= (len - off)) { - want -= (len - off); - - if (len + want < len || !BUF_MEM_grow_clean(b, len + want)) { - OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); - goto err; - } - i = BIO_read(in, &(b->data[len]), want); - if ((i < 0) && ((len - off) == 0)) { - OPENSSL_PUT_ERROR(ASN1, ASN1_R_NOT_ENOUGH_DATA); - goto err; - } - if (i > 0) { - if (len + i < len) { - OPENSSL_PUT_ERROR(ASN1, ASN1_R_TOO_LONG); - goto err; - } - len += i; - } - } - /* else data already loaded */ - - p = (unsigned char *)&(b->data[off]); - c.p = p; - c.inf = ASN1_get_object(&(c.p), &(c.slen), &(c.tag), &(c.xclass), - len - off); - if (c.inf & 0x80) { - uint32_t e; - - e = ERR_GET_REASON(ERR_peek_error()); - if (e != ASN1_R_TOO_LONG) - goto err; - else - ERR_clear_error(); /* clear error */ - } - i = c.p - p; /* header length */ - off += i; /* end of data */ - - if (c.inf & 1) { - /* no data body so go round again */ - eos++; - if (eos < 0) { - OPENSSL_PUT_ERROR(ASN1, ASN1_R_HEADER_TOO_LONG); - goto err; - } - want = HEADER_SIZE; - } else if (eos && (c.slen == 0) && (c.tag == V_ASN1_EOC)) { - /* eos value, so go back and read another header */ - eos--; - if (eos <= 0) - break; - else - want = HEADER_SIZE; - } else { - /* suck in c.slen bytes of data */ - want = c.slen; - if (want > (len - off)) { - size_t chunk_max = ASN1_CHUNK_INITIAL_SIZE; - want -= (len - off); - if (want > INT_MAX /* BIO_read takes an int length */ || - len + want < len) { - OPENSSL_PUT_ERROR(ASN1, ASN1_R_TOO_LONG); - goto err; - } - while (want > 0) { - /* - * Read content in chunks of increasing size - * so we can return an error for EOF without - * having to allocate the entire content length - * in one go. - */ - size_t chunk = want > chunk_max ? chunk_max : want; - - if (!BUF_MEM_grow_clean(b, len + chunk)) { - OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); - goto err; - } - want -= chunk; - while (chunk > 0) { - i = BIO_read(in, &(b->data[len]), chunk); - if (i <= 0) { - OPENSSL_PUT_ERROR(ASN1, ASN1_R_NOT_ENOUGH_DATA); - goto err; - } - /* - * This can't overflow because |len+want| didn't - * overflow. - */ - len += i; - chunk -= i; - } - if (chunk_max < INT_MAX/2) - chunk_max *= 2; - } - } - if (off + c.slen < off) { - OPENSSL_PUT_ERROR(ASN1, ASN1_R_TOO_LONG); - goto err; - } - off += c.slen; - if (eos <= 0) { - break; - } else - want = HEADER_SIZE; - } - } - - if (off > INT_MAX) { - OPENSSL_PUT_ERROR(ASN1, ASN1_R_TOO_LONG); - goto err; - } - - *pb = b; - return off; - err: - if (b != NULL) - BUF_MEM_free(b); - return -1; -} diff --git a/src/crypto/asn1/a_dup.c b/src/crypto/asn1/a_dup.c index 57394f58..9ede8511 100644 --- a/src/crypto/asn1/a_dup.c +++ b/src/crypto/asn1/a_dup.c @@ -59,30 +59,6 @@ #include #include -void *ASN1_dup(i2d_of_void *i2d, d2i_of_void *d2i, void *x) -{ - unsigned char *b, *p; - const unsigned char *p2; - int i; - char *ret; - - if (x == NULL) - return (NULL); - - i = i2d(x, NULL); - b = OPENSSL_malloc(i + 10); - if (b == NULL) { - OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); - return (NULL); - } - p = b; - i = i2d(x, &p); - p2 = b; - ret = d2i(NULL, &p2, i); - OPENSSL_free(b); - return (ret); -} - /* * ASN1_ITEM version of dup: this follows the model above except we don't * need to allocate the buffer. At some point this could be rewritten to diff --git a/src/crypto/asn1/a_i2d_fp.c b/src/crypto/asn1/a_i2d_fp.c index 7b76d0c5..db0d8122 100644 --- a/src/crypto/asn1/a_i2d_fp.c +++ b/src/crypto/asn1/a_i2d_fp.c @@ -56,95 +56,33 @@ #include +#include #include #include -int ASN1_i2d_fp(i2d_of_void *i2d, FILE *out, void *x) -{ - BIO *b; - int ret; - - if ((b = BIO_new(BIO_s_file())) == NULL) { - OPENSSL_PUT_ERROR(ASN1, ERR_R_BUF_LIB); - return (0); - } - BIO_set_fp(b, out, BIO_NOCLOSE); - ret = ASN1_i2d_bio(i2d, b, x); - BIO_free(b); - return (ret); -} - -int ASN1_i2d_bio(i2d_of_void *i2d, BIO *out, void *x) -{ - char *b; - unsigned char *p; - int i, j = 0, n, ret = 1; - - n = i2d(x, NULL); - if (n <= 0) - return 0; - - b = (char *)OPENSSL_malloc(n); - if (b == NULL) { - OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); - return (0); - } - - p = (unsigned char *)b; - i2d(x, &p); - - for (;;) { - i = BIO_write(out, &(b[j]), n); - if (i == n) - break; - if (i <= 0) { - ret = 0; - break; - } - j += i; - n -= i; - } - OPENSSL_free(b); - return (ret); -} int ASN1_item_i2d_fp(const ASN1_ITEM *it, FILE *out, void *x) { - BIO *b; - int ret; - - if ((b = BIO_new(BIO_s_file())) == NULL) { + BIO *b = BIO_new_fp(out, BIO_NOCLOSE); + if (b == NULL) { OPENSSL_PUT_ERROR(ASN1, ERR_R_BUF_LIB); - return (0); + return 0; } - BIO_set_fp(b, out, BIO_NOCLOSE); - ret = ASN1_item_i2d_bio(it, b, x); + int ret = ASN1_item_i2d_bio(it, b, x); BIO_free(b); - return (ret); + return ret; } int ASN1_item_i2d_bio(const ASN1_ITEM *it, BIO *out, void *x) { unsigned char *b = NULL; - int i, j = 0, n, ret = 1; - - n = ASN1_item_i2d(x, &b, it); + int n = ASN1_item_i2d(x, &b, it); if (b == NULL) { OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); - return (0); + return 0; } - for (;;) { - i = BIO_write(out, &(b[j]), n); - if (i == n) - break; - if (i <= 0) { - ret = 0; - break; - } - j += i; - n -= i; - } + int ret = BIO_write_all(out, b, n); OPENSSL_free(b); - return (ret); + return ret; } diff --git a/src/crypto/bio/bio.c b/src/crypto/bio/bio.c index 3e788b87..881c14e1 100644 --- a/src/crypto/bio/bio.c +++ b/src/crypto/bio/bio.c @@ -177,6 +177,19 @@ int BIO_write(BIO *bio, const void *in, int inl) { return ret; } +int BIO_write_all(BIO *bio, const void *data, size_t len) { + const uint8_t *data_u8 = data; + while (len > 0) { + int ret = BIO_write(bio, data_u8, len > INT_MAX ? INT_MAX : (int)len); + if (ret <= 0) { + return 0; + } + data_u8 += ret; + len -= ret; + } + return 1; +} + int BIO_puts(BIO *bio, const char *in) { return BIO_write(bio, in, strlen(in)); } diff --git a/src/crypto/bio/file.c b/src/crypto/bio/file.c index 6a0b9a99..a177763f 100644 --- a/src/crypto/bio/file.c +++ b/src/crypto/bio/file.c @@ -107,13 +107,12 @@ BIO *BIO_new_file(const char *filename, const char *mode) { return NULL; } - ret = BIO_new(BIO_s_file()); + ret = BIO_new_fp(file, BIO_CLOSE); if (ret == NULL) { fclose(file); return NULL; } - BIO_set_fp(ret, file, BIO_CLOSE); return ret; } diff --git a/src/crypto/bn_extra/convert.c b/src/crypto/bn_extra/convert.c index c70ff8b5..9a1a69e3 100644 --- a/src/crypto/bn_extra/convert.c +++ b/src/crypto/bn_extra/convert.c @@ -367,17 +367,13 @@ end: } int BN_print_fp(FILE *fp, const BIGNUM *a) { - BIO *b; - int ret; - - b = BIO_new(BIO_s_file()); + BIO *b = BIO_new_fp(fp, BIO_NOCLOSE); if (b == NULL) { return 0; } - BIO_set_fp(b, fp, BIO_NOCLOSE); - ret = BN_print(b, a); - BIO_free(b); + int ret = BN_print(b, a); + BIO_free(b); return ret; } diff --git a/src/crypto/conf/conf.c b/src/crypto/conf/conf.c index b1982f82..4c27ddf3 100644 --- a/src/crypto/conf/conf.c +++ b/src/crypto/conf/conf.c @@ -62,6 +62,7 @@ #include #include #include +#include #include #include "conf_def.h" @@ -69,6 +70,10 @@ #include "../internal.h" +struct conf_st { + LHASH_OF(CONF_VALUE) *data; +}; + // The maximum length we can grow a value to after variable expansion. 64k // should be more than enough for all reasonable uses. #define MAX_CONF_VALUE_LENGTH 65536 diff --git a/src/crypto/fipsmodule/CMakeLists.txt b/src/crypto/fipsmodule/CMakeLists.txt index 9868dd87..e6c8cc69 100644 --- a/src/crypto/fipsmodule/CMakeLists.txt +++ b/src/crypto/fipsmodule/CMakeLists.txt @@ -162,12 +162,12 @@ if(FIPS_DELOCATE) set_target_properties(bcm_hashunset PROPERTIES POSITION_INDEPENDENT_CODE ON) set_target_properties(bcm_hashunset PROPERTIES LINKER_LANGUAGE C) - go_executable(inject-hash - boringssl.googlesource.com/boringssl/util/fipstools/inject-hash) + go_executable(inject_hash + boringssl.googlesource.com/boringssl/util/fipstools/inject_hash) add_custom_command( OUTPUT bcm.o - COMMAND ./inject-hash -o bcm.o -in-archive $ - DEPENDS bcm_hashunset inject-hash + COMMAND ./inject_hash -o bcm.o -in-archive $ + DEPENDS bcm_hashunset inject_hash WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) diff --git a/src/crypto/fipsmodule/FIPS.md b/src/crypto/fipsmodule/FIPS.md index a691d18a..426b38e2 100644 --- a/src/crypto/fipsmodule/FIPS.md +++ b/src/crypto/fipsmodule/FIPS.md @@ -103,7 +103,7 @@ The script performs a number of other transformations which are worth noting but In order to actually implement the integrity test, a constructor function within the module calculates an HMAC from `module_start` to `module_end` using a fixed, all-zero key. It compares the result with the known-good value added (by the script) to the unhashed portion of the text segment. If they don't match, it calls `exit` in an infinite loop. -Initially the known-good value will be incorrect. Another script (`inject-hash.go`) calculates the correct value from the assembled object and injects it back into the object. +Initially the known-good value will be incorrect. Another script (`inject_hash.go`) calculates the correct value from the assembled object and injects it back into the object. ![build process](/crypto/fipsmodule/intcheck2.png) diff --git a/src/crypto/fipsmodule/aes/mode_wrappers.c b/src/crypto/fipsmodule/aes/mode_wrappers.c index 5c50c858..0140c70f 100644 --- a/src/crypto/fipsmodule/aes/mode_wrappers.c +++ b/src/crypto/fipsmodule/aes/mode_wrappers.c @@ -57,8 +57,7 @@ void AES_ctr128_encrypt(const uint8_t *in, uint8_t *out, size_t len, const AES_KEY *key, uint8_t ivec[AES_BLOCK_SIZE], uint8_t ecount_buf[AES_BLOCK_SIZE], unsigned int *num) { - CRYPTO_ctr128_encrypt(in, out, len, key, ivec, ecount_buf, num, - (block128_f)AES_encrypt); + CRYPTO_ctr128_encrypt(in, out, len, key, ivec, ecount_buf, num, AES_encrypt); } void AES_ecb_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key, @@ -90,9 +89,9 @@ void AES_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t len, aes_nohw_cbc_encrypt(in, out, len, key, ivec, enc); #else if (enc) { - CRYPTO_cbc128_encrypt(in, out, len, key, ivec, (block128_f)AES_encrypt); + CRYPTO_cbc128_encrypt(in, out, len, key, ivec, AES_encrypt); } else { - CRYPTO_cbc128_decrypt(in, out, len, key, ivec, (block128_f)AES_decrypt); + CRYPTO_cbc128_decrypt(in, out, len, key, ivec, AES_decrypt); } #endif } @@ -100,8 +99,7 @@ void AES_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t len, void AES_ofb128_encrypt(const uint8_t *in, uint8_t *out, size_t length, const AES_KEY *key, uint8_t *ivec, int *num) { unsigned num_u = (unsigned)(*num); - CRYPTO_ofb128_encrypt(in, out, length, key, ivec, &num_u, - (block128_f)AES_encrypt); + CRYPTO_ofb128_encrypt(in, out, length, key, ivec, &num_u, AES_encrypt); *num = (int)num_u; } @@ -109,7 +107,6 @@ void AES_cfb128_encrypt(const uint8_t *in, uint8_t *out, size_t length, const AES_KEY *key, uint8_t *ivec, int *num, int enc) { unsigned num_u = (unsigned)(*num); - CRYPTO_cfb128_encrypt(in, out, length, key, ivec, &num_u, enc, - (block128_f)AES_encrypt); + CRYPTO_cfb128_encrypt(in, out, length, key, ivec, &num_u, enc, AES_encrypt); *num = (int)num_u; } diff --git a/src/crypto/fipsmodule/bcm.c b/src/crypto/fipsmodule/bcm.c index 6b21f063..e15ecb85 100644 --- a/src/crypto/fipsmodule/bcm.c +++ b/src/crypto/fipsmodule/bcm.c @@ -124,6 +124,7 @@ BORINGSSL_bcm_power_on_self_test(void) { if (!HMAC(EVP_sha512(), kHMACKey, sizeof(kHMACKey), start, end - start, result, &result_len) || result_len != sizeof(result)) { + fprintf(stderr, "HMAC failed.\n"); goto err; } diff --git a/src/crypto/fipsmodule/bn/div.c b/src/crypto/fipsmodule/bn/div.c index 57485bd1..27b591c9 100644 --- a/src/crypto/fipsmodule/bn/div.c +++ b/src/crypto/fipsmodule/bn/div.c @@ -64,7 +64,7 @@ #include "internal.h" -#if !defined(BN_ULLONG) +#if !defined(BN_CAN_DIVIDE_ULLONG) && !defined(BN_CAN_USE_INLINE_ASM) // bn_div_words divides a double-width |h|,|l| by |d| and returns the result, // which must fit in a |BN_ULONG|. static BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d) { @@ -135,7 +135,7 @@ static BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d) { ret |= q; return ret; } -#endif // !defined(BN_ULLONG) +#endif // !defined(BN_CAN_DIVIDE_ULLONG) && !defined(BN_CAN_USE_INLINE_ASM) static inline void bn_div_rem_words(BN_ULONG *quotient_out, BN_ULONG *rem_out, BN_ULONG n0, BN_ULONG n1, BN_ULONG d0) { @@ -155,20 +155,18 @@ static inline void bn_div_rem_words(BN_ULONG *quotient_out, BN_ULONG *rem_out, // // These issues aren't specific to x86 and x86_64, so it might be worthwhile // to add more assembly language implementations. -#if !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86) && \ - (defined(__GNUC__) || defined(__clang__)) +#if defined(BN_CAN_USE_INLINE_ASM) && defined(OPENSSL_X86) __asm__ volatile("divl %4" : "=a"(*quotient_out), "=d"(*rem_out) : "a"(n1), "d"(n0), "rm"(d0) : "cc"); -#elif !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86_64) && \ - (defined(__GNUC__) || defined(__clang__)) +#elif defined(BN_CAN_USE_INLINE_ASM) && defined(OPENSSL_X86_64) __asm__ volatile("divq %4" : "=a"(*quotient_out), "=d"(*rem_out) : "a"(n1), "d"(n0), "rm"(d0) : "cc"); #else -#if defined(BN_ULLONG) +#if defined(BN_CAN_DIVIDE_ULLONG) BN_ULLONG n = (((BN_ULLONG)n0) << BN_BITS2) | n1; *quotient_out = (BN_ULONG)(n / d0); #else diff --git a/src/crypto/fipsmodule/bn/internal.h b/src/crypto/fipsmodule/bn/internal.h index 9796831f..fb8d11fe 100644 --- a/src/crypto/fipsmodule/bn/internal.h +++ b/src/crypto/fipsmodule/bn/internal.h @@ -185,6 +185,10 @@ extern "C" { #error "Must define either OPENSSL_32_BIT or OPENSSL_64_BIT" #endif +#if !defined(OPENSSL_NO_ASM) && (defined(__GNUC__) || defined(__clang__)) +#define BN_CAN_USE_INLINE_ASM +#endif + // |BN_mod_exp_mont_consttime| is based on the assumption that the L1 data // cache line width of the target processor is at least the following value. #define MOD_EXP_CTIME_MIN_CACHE_LINE_WIDTH 64 diff --git a/src/crypto/fipsmodule/cipher/e_aes.c b/src/crypto/fipsmodule/cipher/e_aes.c index 734a5174..0ced1935 100644 --- a/src/crypto/fipsmodule/cipher/e_aes.c +++ b/src/crypto/fipsmodule/cipher/e_aes.c @@ -198,49 +198,45 @@ static int aes_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key, if ((mode == EVP_CIPH_ECB_MODE || mode == EVP_CIPH_CBC_MODE) && !enc) { if (hwaes_capable()) { ret = aes_hw_set_decrypt_key(key, ctx->key_len * 8, &dat->ks.ks); - dat->block = (block128_f)aes_hw_decrypt; + dat->block = aes_hw_decrypt; dat->stream.cbc = NULL; if (mode == EVP_CIPH_CBC_MODE) { - dat->stream.cbc = (cbc128_f)aes_hw_cbc_encrypt; + dat->stream.cbc = aes_hw_cbc_encrypt; } } else if (bsaes_capable() && mode == EVP_CIPH_CBC_MODE) { ret = AES_set_decrypt_key(key, ctx->key_len * 8, &dat->ks.ks); - dat->block = (block128_f)AES_decrypt; - dat->stream.cbc = (cbc128_f)bsaes_cbc_encrypt; + dat->block = AES_decrypt; + dat->stream.cbc = bsaes_cbc_encrypt; } else if (vpaes_capable()) { ret = vpaes_set_decrypt_key(key, ctx->key_len * 8, &dat->ks.ks); - dat->block = (block128_f)vpaes_decrypt; - dat->stream.cbc = - mode == EVP_CIPH_CBC_MODE ? (cbc128_f)vpaes_cbc_encrypt : NULL; + dat->block = vpaes_decrypt; + dat->stream.cbc = mode == EVP_CIPH_CBC_MODE ? vpaes_cbc_encrypt : NULL; } else { ret = AES_set_decrypt_key(key, ctx->key_len * 8, &dat->ks.ks); - dat->block = (block128_f)AES_decrypt; - dat->stream.cbc = - mode == EVP_CIPH_CBC_MODE ? (cbc128_f)AES_cbc_encrypt : NULL; + dat->block = AES_decrypt; + dat->stream.cbc = mode == EVP_CIPH_CBC_MODE ? AES_cbc_encrypt : NULL; } } else if (hwaes_capable()) { ret = aes_hw_set_encrypt_key(key, ctx->key_len * 8, &dat->ks.ks); - dat->block = (block128_f)aes_hw_encrypt; + dat->block = aes_hw_encrypt; dat->stream.cbc = NULL; if (mode == EVP_CIPH_CBC_MODE) { - dat->stream.cbc = (cbc128_f)aes_hw_cbc_encrypt; + dat->stream.cbc = aes_hw_cbc_encrypt; } else if (mode == EVP_CIPH_CTR_MODE) { - dat->stream.ctr = (ctr128_f)aes_hw_ctr32_encrypt_blocks; + dat->stream.ctr = aes_hw_ctr32_encrypt_blocks; } } else if (bsaes_capable() && mode == EVP_CIPH_CTR_MODE) { ret = AES_set_encrypt_key(key, ctx->key_len * 8, &dat->ks.ks); - dat->block = (block128_f)AES_encrypt; - dat->stream.ctr = (ctr128_f)bsaes_ctr32_encrypt_blocks; + dat->block = AES_encrypt; + dat->stream.ctr = bsaes_ctr32_encrypt_blocks; } else if (vpaes_capable()) { ret = vpaes_set_encrypt_key(key, ctx->key_len * 8, &dat->ks.ks); - dat->block = (block128_f)vpaes_encrypt; - dat->stream.cbc = - mode == EVP_CIPH_CBC_MODE ? (cbc128_f)vpaes_cbc_encrypt : NULL; + dat->block = vpaes_encrypt; + dat->stream.cbc = mode == EVP_CIPH_CBC_MODE ? vpaes_cbc_encrypt : NULL; } else { ret = AES_set_encrypt_key(key, ctx->key_len * 8, &dat->ks.ks); - dat->block = (block128_f)AES_encrypt; - dat->stream.cbc = - mode == EVP_CIPH_CBC_MODE ? (cbc128_f)AES_cbc_encrypt : NULL; + dat->block = AES_encrypt; + dat->stream.cbc = mode == EVP_CIPH_CBC_MODE ? AES_cbc_encrypt : NULL; } if (ret < 0) { @@ -256,11 +252,11 @@ static int aes_cbc_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in, EVP_AES_KEY *dat = (EVP_AES_KEY *)ctx->cipher_data; if (dat->stream.cbc) { - (*dat->stream.cbc)(in, out, len, &dat->ks, ctx->iv, ctx->encrypt); + (*dat->stream.cbc)(in, out, len, &dat->ks.ks, ctx->iv, ctx->encrypt); } else if (ctx->encrypt) { - CRYPTO_cbc128_encrypt(in, out, len, &dat->ks, ctx->iv, dat->block); + CRYPTO_cbc128_encrypt(in, out, len, &dat->ks.ks, ctx->iv, dat->block); } else { - CRYPTO_cbc128_decrypt(in, out, len, &dat->ks, ctx->iv, dat->block); + CRYPTO_cbc128_decrypt(in, out, len, &dat->ks.ks, ctx->iv, dat->block); } return 1; @@ -277,7 +273,7 @@ static int aes_ecb_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in, len -= bl; for (size_t i = 0; i <= len; i += bl) { - (*dat->block)(in + i, out + i, &dat->ks); + (*dat->block)(in + i, out + i, &dat->ks.ks); } return 1; @@ -288,11 +284,11 @@ static int aes_ctr_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in, EVP_AES_KEY *dat = (EVP_AES_KEY *)ctx->cipher_data; if (dat->stream.ctr) { - CRYPTO_ctr128_encrypt_ctr32(in, out, len, &dat->ks, ctx->iv, ctx->buf, + CRYPTO_ctr128_encrypt_ctr32(in, out, len, &dat->ks.ks, ctx->iv, ctx->buf, &ctx->num, dat->stream.ctr); } else { - CRYPTO_ctr128_encrypt(in, out, len, &dat->ks, ctx->iv, ctx->buf, &ctx->num, - dat->block); + CRYPTO_ctr128_encrypt(in, out, len, &dat->ks.ks, ctx->iv, ctx->buf, + &ctx->num, dat->block); } return 1; } @@ -301,7 +297,8 @@ static int aes_ofb_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in, size_t len) { EVP_AES_KEY *dat = (EVP_AES_KEY *)ctx->cipher_data; - CRYPTO_ofb128_encrypt(in, out, len, &dat->ks, ctx->iv, &ctx->num, dat->block); + CRYPTO_ofb128_encrypt(in, out, len, &dat->ks.ks, ctx->iv, &ctx->num, + dat->block); return 1; } @@ -311,42 +308,42 @@ ctr128_f aes_ctr_set_key(AES_KEY *aes_key, GCM128_KEY *gcm_key, if (hwaes_capable()) { aes_hw_set_encrypt_key(key, key_bytes * 8, aes_key); if (gcm_key != NULL) { - CRYPTO_gcm128_init_key(gcm_key, aes_key, (block128_f)aes_hw_encrypt, 1); + CRYPTO_gcm128_init_key(gcm_key, aes_key, aes_hw_encrypt, 1); } if (out_block) { - *out_block = (block128_f) aes_hw_encrypt; + *out_block = aes_hw_encrypt; } - return (ctr128_f)aes_hw_ctr32_encrypt_blocks; + return aes_hw_ctr32_encrypt_blocks; } if (bsaes_capable()) { AES_set_encrypt_key(key, key_bytes * 8, aes_key); if (gcm_key != NULL) { - CRYPTO_gcm128_init_key(gcm_key, aes_key, (block128_f)AES_encrypt, 0); + CRYPTO_gcm128_init_key(gcm_key, aes_key, AES_encrypt, 0); } if (out_block) { - *out_block = (block128_f) AES_encrypt; + *out_block = AES_encrypt; } - return (ctr128_f)bsaes_ctr32_encrypt_blocks; + return bsaes_ctr32_encrypt_blocks; } if (vpaes_capable()) { vpaes_set_encrypt_key(key, key_bytes * 8, aes_key); if (out_block) { - *out_block = (block128_f) vpaes_encrypt; + *out_block = vpaes_encrypt; } if (gcm_key != NULL) { - CRYPTO_gcm128_init_key(gcm_key, aes_key, (block128_f)vpaes_encrypt, 0); + CRYPTO_gcm128_init_key(gcm_key, aes_key, vpaes_encrypt, 0); } return NULL; } AES_set_encrypt_key(key, key_bytes * 8, aes_key); if (gcm_key != NULL) { - CRYPTO_gcm128_init_key(gcm_key, aes_key, (block128_f)AES_encrypt, 0); + CRYPTO_gcm128_init_key(gcm_key, aes_key, AES_encrypt, 0); } if (out_block) { - *out_block = (block128_f) AES_encrypt; + *out_block = AES_encrypt; } return NULL; } diff --git a/src/crypto/fipsmodule/modes/cbc.c b/src/crypto/fipsmodule/modes/cbc.c index db9f0241..64ea5056 100644 --- a/src/crypto/fipsmodule/modes/cbc.c +++ b/src/crypto/fipsmodule/modes/cbc.c @@ -53,7 +53,7 @@ void CRYPTO_cbc128_encrypt(const uint8_t *in, uint8_t *out, size_t len, - const void *key, uint8_t ivec[16], + const AES_KEY *key, uint8_t ivec[16], block128_f block) { size_t n; const uint8_t *iv = ivec; @@ -108,7 +108,7 @@ void CRYPTO_cbc128_encrypt(const uint8_t *in, uint8_t *out, size_t len, } void CRYPTO_cbc128_decrypt(const uint8_t *in, uint8_t *out, size_t len, - const void *key, uint8_t ivec[16], + const AES_KEY *key, uint8_t ivec[16], block128_f block) { size_t n; union { diff --git a/src/crypto/fipsmodule/modes/ccm.c b/src/crypto/fipsmodule/modes/ccm.c index 784e4fa2..5a153f41 100644 --- a/src/crypto/fipsmodule/modes/ccm.c +++ b/src/crypto/fipsmodule/modes/ccm.c @@ -64,8 +64,8 @@ struct ccm128_state { } nonce, cmac; }; -int CRYPTO_ccm128_init(CCM128_CONTEXT *ctx, const void *key, block128_f block, - ctr128_f ctr, unsigned M, unsigned L) { +int CRYPTO_ccm128_init(CCM128_CONTEXT *ctx, const AES_KEY *key, + block128_f block, ctr128_f ctr, unsigned M, unsigned L) { if (M < 4 || M > 16 || (M & 1) != 0 || L < 2 || L > 8) { return 0; } @@ -82,7 +82,7 @@ size_t CRYPTO_ccm128_max_input(const CCM128_CONTEXT *ctx) { } static int ccm128_init_state(const CCM128_CONTEXT *ctx, - struct ccm128_state *state, const void *key, + struct ccm128_state *state, const AES_KEY *key, const uint8_t *nonce, size_t nonce_len, const uint8_t *aad, size_t aad_len, size_t plaintext_len) { @@ -170,7 +170,7 @@ static int ccm128_init_state(const CCM128_CONTEXT *ctx, } static int ccm128_encrypt(const CCM128_CONTEXT *ctx, struct ccm128_state *state, - const void *key, uint8_t *out, const uint8_t *in, + const AES_KEY *key, uint8_t *out, const uint8_t *in, size_t len) { // The counter for encryption begins at one. for (unsigned i = 0; i < ctx->L; i++) { @@ -191,7 +191,7 @@ static int ccm128_encrypt(const CCM128_CONTEXT *ctx, struct ccm128_state *state, } static int ccm128_compute_mac(const CCM128_CONTEXT *ctx, - struct ccm128_state *state, const void *key, + struct ccm128_state *state, const AES_KEY *key, uint8_t *out_tag, size_t tag_len, const uint8_t *in, size_t len) { block128_f block = ctx->block; @@ -231,7 +231,7 @@ static int ccm128_compute_mac(const CCM128_CONTEXT *ctx, return 1; } -int CRYPTO_ccm128_encrypt(const CCM128_CONTEXT *ctx, const void *key, +int CRYPTO_ccm128_encrypt(const CCM128_CONTEXT *ctx, const AES_KEY *key, uint8_t *out, uint8_t *out_tag, size_t tag_len, const uint8_t *nonce, size_t nonce_len, const uint8_t *in, size_t len, const uint8_t *aad, @@ -243,7 +243,7 @@ int CRYPTO_ccm128_encrypt(const CCM128_CONTEXT *ctx, const void *key, ccm128_encrypt(ctx, &state, key, out, in, len); } -int CRYPTO_ccm128_decrypt(const CCM128_CONTEXT *ctx, const void *key, +int CRYPTO_ccm128_decrypt(const CCM128_CONTEXT *ctx, const AES_KEY *key, uint8_t *out, uint8_t *out_tag, size_t tag_len, const uint8_t *nonce, size_t nonce_len, const uint8_t *in, size_t len, const uint8_t *aad, diff --git a/src/crypto/fipsmodule/modes/cfb.c b/src/crypto/fipsmodule/modes/cfb.c index e1b0a80e..d3a38d6e 100644 --- a/src/crypto/fipsmodule/modes/cfb.c +++ b/src/crypto/fipsmodule/modes/cfb.c @@ -57,7 +57,7 @@ OPENSSL_COMPILE_ASSERT((16 % sizeof(size_t)) == 0, bad_size_t_size_cfb); void CRYPTO_cfb128_encrypt(const uint8_t *in, uint8_t *out, size_t len, - const void *key, uint8_t ivec[16], unsigned *num, + const AES_KEY *key, uint8_t ivec[16], unsigned *num, int enc, block128_f block) { size_t l = 0; @@ -161,7 +161,7 @@ void CRYPTO_cfb128_encrypt(const uint8_t *in, uint8_t *out, size_t len, /* This expects a single block of size nbits for both in and out. Note that it corrupts any extra bits in the last byte of out */ static void cfbr_encrypt_block(const uint8_t *in, uint8_t *out, unsigned nbits, - const void *key, uint8_t ivec[16], int enc, + const AES_KEY *key, uint8_t ivec[16], int enc, block128_f block) { int n, rem, num; uint8_t ovec[16 * 2 + 1]; /* +1 because we dererefence (but don't use) one @@ -203,8 +203,8 @@ static void cfbr_encrypt_block(const uint8_t *in, uint8_t *out, unsigned nbits, // N.B. This expects the input to be packed, MS bit first void CRYPTO_cfb128_1_encrypt(const uint8_t *in, uint8_t *out, size_t bits, - const void *key, uint8_t ivec[16], unsigned *num, - int enc, block128_f block) { + const AES_KEY *key, uint8_t ivec[16], + unsigned *num, int enc, block128_f block) { size_t n; uint8_t c[1], d[1]; @@ -220,7 +220,7 @@ void CRYPTO_cfb128_1_encrypt(const uint8_t *in, uint8_t *out, size_t bits, } void CRYPTO_cfb128_8_encrypt(const unsigned char *in, unsigned char *out, - size_t length, const void *key, + size_t length, const AES_KEY *key, unsigned char ivec[16], unsigned *num, int enc, block128_f block) { size_t n; diff --git a/src/crypto/fipsmodule/modes/ctr.c b/src/crypto/fipsmodule/modes/ctr.c index 63907b43..5093408c 100644 --- a/src/crypto/fipsmodule/modes/ctr.c +++ b/src/crypto/fipsmodule/modes/ctr.c @@ -82,7 +82,7 @@ OPENSSL_COMPILE_ASSERT((16 % sizeof(size_t)) == 0, bad_size_t_size_ctr); // of the IV. This implementation takes NO responsibility for checking that // the counter doesn't overflow into the rest of the IV when incremented. void CRYPTO_ctr128_encrypt(const uint8_t *in, uint8_t *out, size_t len, - const void *key, uint8_t ivec[16], + const AES_KEY *key, uint8_t ivec[16], uint8_t ecount_buf[16], unsigned int *num, block128_f block) { unsigned int n; @@ -153,11 +153,10 @@ static void ctr96_inc(uint8_t *counter) { } while (n); } -void CRYPTO_ctr128_encrypt_ctr32(const uint8_t *in, uint8_t *out, - size_t len, const void *key, - uint8_t ivec[16], - uint8_t ecount_buf[16], - unsigned int *num, ctr128_f func) { +void CRYPTO_ctr128_encrypt_ctr32(const uint8_t *in, uint8_t *out, size_t len, + const AES_KEY *key, uint8_t ivec[16], + uint8_t ecount_buf[16], unsigned int *num, + ctr128_f func) { unsigned int n, ctr32; assert(key && ecount_buf && num); diff --git a/src/crypto/fipsmodule/modes/gcm.c b/src/crypto/fipsmodule/modes/gcm.c index 6eff4792..5e556df2 100644 --- a/src/crypto/fipsmodule/modes/gcm.c +++ b/src/crypto/fipsmodule/modes/gcm.c @@ -271,9 +271,9 @@ void gcm_ghash_avx(uint64_t Xi[2], const u128 Htable[16], const uint8_t *in, size_t len); #define AESNI_GCM size_t aesni_gcm_encrypt(const uint8_t *in, uint8_t *out, size_t len, - const void *key, uint8_t ivec[16], uint64_t *Xi); + const AES_KEY *key, uint8_t ivec[16], uint64_t *Xi); size_t aesni_gcm_decrypt(const uint8_t *in, uint8_t *out, size_t len, - const void *key, uint8_t ivec[16], uint64_t *Xi); + const AES_KEY *key, uint8_t ivec[16], uint64_t *Xi); #endif #if defined(OPENSSL_X86) @@ -419,7 +419,7 @@ void CRYPTO_ghash_init(gmult_func *out_mult, ghash_func *out_hash, #endif } -void CRYPTO_gcm128_init_key(GCM128_KEY *gcm_key, const void *aes_key, +void CRYPTO_gcm128_init_key(GCM128_KEY *gcm_key, const AES_KEY *aes_key, block128_f block, int block_is_hwaes) { OPENSSL_memset(gcm_key, 0, sizeof(*gcm_key)); gcm_key->block = block; @@ -435,7 +435,7 @@ void CRYPTO_gcm128_init_key(GCM128_KEY *gcm_key, const void *aes_key, gcm_key->use_aesni_gcm_crypt = (is_avx && block_is_hwaes) ? 1 : 0; } -void CRYPTO_gcm128_setiv(GCM128_CONTEXT *ctx, const void *key, +void CRYPTO_gcm128_setiv(GCM128_CONTEXT *ctx, const AES_KEY *key, const uint8_t *iv, size_t len) { unsigned int ctr; #ifdef GCM_FUNCREF_4BIT @@ -553,7 +553,7 @@ int CRYPTO_gcm128_aad(GCM128_CONTEXT *ctx, const uint8_t *aad, size_t len) { return 1; } -int CRYPTO_gcm128_encrypt(GCM128_CONTEXT *ctx, const void *key, +int CRYPTO_gcm128_encrypt(GCM128_CONTEXT *ctx, const AES_KEY *key, const uint8_t *in, uint8_t *out, size_t len) { unsigned int n, ctr; uint64_t mlen = ctx->len.u[1]; @@ -679,7 +679,7 @@ int CRYPTO_gcm128_encrypt(GCM128_CONTEXT *ctx, const void *key, return 1; } -int CRYPTO_gcm128_decrypt(GCM128_CONTEXT *ctx, const void *key, +int CRYPTO_gcm128_decrypt(GCM128_CONTEXT *ctx, const AES_KEY *key, const unsigned char *in, unsigned char *out, size_t len) { unsigned int n, ctr; @@ -813,7 +813,7 @@ int CRYPTO_gcm128_decrypt(GCM128_CONTEXT *ctx, const void *key, return 1; } -int CRYPTO_gcm128_encrypt_ctr32(GCM128_CONTEXT *ctx, const void *key, +int CRYPTO_gcm128_encrypt_ctr32(GCM128_CONTEXT *ctx, const AES_KEY *key, const uint8_t *in, uint8_t *out, size_t len, ctr128_f stream) { unsigned int n, ctr; @@ -915,7 +915,7 @@ int CRYPTO_gcm128_encrypt_ctr32(GCM128_CONTEXT *ctx, const void *key, return 1; } -int CRYPTO_gcm128_decrypt_ctr32(GCM128_CONTEXT *ctx, const void *key, +int CRYPTO_gcm128_decrypt_ctr32(GCM128_CONTEXT *ctx, const AES_KEY *key, const uint8_t *in, uint8_t *out, size_t len, ctr128_f stream) { unsigned int n, ctr; diff --git a/src/crypto/fipsmodule/modes/gcm_test.cc b/src/crypto/fipsmodule/modes/gcm_test.cc index ab8cc34e..30308f8a 100644 --- a/src/crypto/fipsmodule/modes/gcm_test.cc +++ b/src/crypto/fipsmodule/modes/gcm_test.cc @@ -88,7 +88,7 @@ TEST(GCMTest, TestVectors) { GCM128_CONTEXT ctx; OPENSSL_memset(&ctx, 0, sizeof(ctx)); - CRYPTO_gcm128_init_key(&ctx.gcm_key, &aes_key, (block128_f)AES_encrypt, 0); + CRYPTO_gcm128_init_key(&ctx.gcm_key, &aes_key, AES_encrypt, 0); CRYPTO_gcm128_setiv(&ctx, &aes_key, nonce.data(), nonce.size()); if (!additional_data.empty()) { CRYPTO_gcm128_aad(&ctx, additional_data.data(), additional_data.size()); diff --git a/src/crypto/fipsmodule/modes/internal.h b/src/crypto/fipsmodule/modes/internal.h index 788960b7..23aaca2c 100644 --- a/src/crypto/fipsmodule/modes/internal.h +++ b/src/crypto/fipsmodule/modes/internal.h @@ -50,6 +50,7 @@ #define OPENSSL_HEADER_MODES_INTERNAL_H #include +#include #include @@ -87,16 +88,24 @@ static inline void store_word_le(void *out, size_t v) { OPENSSL_memcpy(out, &v, sizeof(v)); } -// block128_f is the type of a 128-bit, block cipher. +// block128_f is the type of an AES block cipher implementation. +// +// Unlike upstream OpenSSL, it and the other functions in this file hard-code +// |AES_KEY|. It is undefined in C to call a function pointer with anything +// other than the original type. Thus we either must match |block128_f| to the +// type signature of |AES_encrypt| and friends or pass in |void*| wrapper +// functions. +// +// These functions are called exclusively with AES, so we use the former. typedef void (*block128_f)(const uint8_t in[16], uint8_t out[16], - const void *key); + const AES_KEY *key); // CTR. // ctr128_f is the type of a function that performs CTR-mode encryption. typedef void (*ctr128_f)(const uint8_t *in, uint8_t *out, size_t blocks, - const void *key, const uint8_t ivec[16]); + const AES_KEY *key, const uint8_t ivec[16]); // CRYPTO_ctr128_encrypt encrypts (or decrypts, it's the same in CTR mode) // |len| bytes from |in| to |out| using |block| in counter mode. There's no @@ -105,7 +114,7 @@ typedef void (*ctr128_f)(const uint8_t *in, uint8_t *out, size_t blocks, // call. The counter is a 128-bit, big-endian value in |ivec| and is // incremented by this function. void CRYPTO_ctr128_encrypt(const uint8_t *in, uint8_t *out, size_t len, - const void *key, uint8_t ivec[16], + const AES_KEY *key, uint8_t ivec[16], uint8_t ecount_buf[16], unsigned *num, block128_f block); @@ -114,14 +123,14 @@ void CRYPTO_ctr128_encrypt(const uint8_t *in, uint8_t *out, size_t len, // bits of the counter. This is useful when |ctr| can be an optimised // function. void CRYPTO_ctr128_encrypt_ctr32(const uint8_t *in, uint8_t *out, size_t len, - const void *key, uint8_t ivec[16], + const AES_KEY *key, uint8_t ivec[16], uint8_t ecount_buf[16], unsigned *num, ctr128_f ctr); #if !defined(OPENSSL_NO_ASM) && \ (defined(OPENSSL_X86) || defined(OPENSSL_X86_64)) void aesni_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out, size_t blocks, - const void *key, const uint8_t *ivec); + const AES_KEY *key, const uint8_t *ivec); #endif @@ -194,13 +203,13 @@ void CRYPTO_ghash_init(gmult_func *out_mult, ghash_func *out_hash, // CRYPTO_gcm128_init_key initialises |gcm_key| to use |block| (typically AES) // with the given key. |block_is_hwaes| is one if |block| is |aes_hw_encrypt|. -OPENSSL_EXPORT void CRYPTO_gcm128_init_key(GCM128_KEY *gcm_key, const void *key, - block128_f block, +OPENSSL_EXPORT void CRYPTO_gcm128_init_key(GCM128_KEY *gcm_key, + const AES_KEY *key, block128_f block, int block_is_hwaes); // CRYPTO_gcm128_setiv sets the IV (nonce) for |ctx|. The |key| must be the // same key that was passed to |CRYPTO_gcm128_init|. -OPENSSL_EXPORT void CRYPTO_gcm128_setiv(GCM128_CONTEXT *ctx, const void *key, +OPENSSL_EXPORT void CRYPTO_gcm128_setiv(GCM128_CONTEXT *ctx, const AES_KEY *key, const uint8_t *iv, size_t iv_len); // CRYPTO_gcm128_aad sets the authenticated data for an instance of GCM. @@ -212,16 +221,16 @@ OPENSSL_EXPORT int CRYPTO_gcm128_aad(GCM128_CONTEXT *ctx, const uint8_t *aad, // CRYPTO_gcm128_encrypt encrypts |len| bytes from |in| to |out|. The |key| // must be the same key that was passed to |CRYPTO_gcm128_init|. It returns one // on success and zero otherwise. -OPENSSL_EXPORT int CRYPTO_gcm128_encrypt(GCM128_CONTEXT *ctx, const void *key, - const uint8_t *in, uint8_t *out, - size_t len); +OPENSSL_EXPORT int CRYPTO_gcm128_encrypt(GCM128_CONTEXT *ctx, + const AES_KEY *key, const uint8_t *in, + uint8_t *out, size_t len); // CRYPTO_gcm128_decrypt decrypts |len| bytes from |in| to |out|. The |key| // must be the same key that was passed to |CRYPTO_gcm128_init|. It returns one // on success and zero otherwise. -OPENSSL_EXPORT int CRYPTO_gcm128_decrypt(GCM128_CONTEXT *ctx, const void *key, - const uint8_t *in, uint8_t *out, - size_t len); +OPENSSL_EXPORT int CRYPTO_gcm128_decrypt(GCM128_CONTEXT *ctx, + const AES_KEY *key, const uint8_t *in, + uint8_t *out, size_t len); // CRYPTO_gcm128_encrypt_ctr32 encrypts |len| bytes from |in| to |out| using // a CTR function that only handles the bottom 32 bits of the nonce, like @@ -229,7 +238,7 @@ OPENSSL_EXPORT int CRYPTO_gcm128_decrypt(GCM128_CONTEXT *ctx, const void *key, // passed to |CRYPTO_gcm128_init|. It returns one on success and zero // otherwise. OPENSSL_EXPORT int CRYPTO_gcm128_encrypt_ctr32(GCM128_CONTEXT *ctx, - const void *key, + const AES_KEY *key, const uint8_t *in, uint8_t *out, size_t len, ctr128_f stream); @@ -239,7 +248,7 @@ OPENSSL_EXPORT int CRYPTO_gcm128_encrypt_ctr32(GCM128_CONTEXT *ctx, // passed to |CRYPTO_gcm128_init|. It returns one on success and zero // otherwise. OPENSSL_EXPORT int CRYPTO_gcm128_decrypt_ctr32(GCM128_CONTEXT *ctx, - const void *key, + const AES_KEY *key, const uint8_t *in, uint8_t *out, size_t len, ctr128_f stream); @@ -265,8 +274,8 @@ typedef struct ccm128_context { // CRYPTO_ccm128_init initialises |ctx| to use |block| (typically AES) with the // specified |M| and |L| parameters. It returns one on success and zero if |M| // or |L| is invalid. -int CRYPTO_ccm128_init(CCM128_CONTEXT *ctx, const void *key, block128_f block, - ctr128_f ctr, unsigned M, unsigned L); +int CRYPTO_ccm128_init(CCM128_CONTEXT *ctx, const AES_KEY *key, + block128_f block, ctr128_f ctr, unsigned M, unsigned L); // CRYPTO_ccm128_max_input returns the maximum input length accepted by |ctx|. size_t CRYPTO_ccm128_max_input(const CCM128_CONTEXT *ctx); @@ -274,7 +283,7 @@ size_t CRYPTO_ccm128_max_input(const CCM128_CONTEXT *ctx); // CRYPTO_ccm128_encrypt encrypts |len| bytes from |in| to |out| writing the tag // to |out_tag|. |key| must be the same key that was passed to // |CRYPTO_ccm128_init|. It returns one on success and zero otherwise. -int CRYPTO_ccm128_encrypt(const CCM128_CONTEXT *ctx, const void *key, +int CRYPTO_ccm128_encrypt(const CCM128_CONTEXT *ctx, const AES_KEY *key, uint8_t *out, uint8_t *out_tag, size_t tag_len, const uint8_t *nonce, size_t nonce_len, const uint8_t *in, size_t len, const uint8_t *aad, @@ -283,7 +292,7 @@ int CRYPTO_ccm128_encrypt(const CCM128_CONTEXT *ctx, const void *key, // CRYPTO_ccm128_decrypt decrypts |len| bytes from |in| to |out|, writing the // expected tag to |out_tag|. |key| must be the same key that was passed to // |CRYPTO_ccm128_init|. It returns one on success and zero otherwise. -int CRYPTO_ccm128_decrypt(const CCM128_CONTEXT *ctx, const void *key, +int CRYPTO_ccm128_decrypt(const CCM128_CONTEXT *ctx, const AES_KEY *key, uint8_t *out, uint8_t *out_tag, size_t tag_len, const uint8_t *nonce, size_t nonce_len, const uint8_t *in, size_t len, const uint8_t *aad, @@ -294,21 +303,23 @@ int CRYPTO_ccm128_decrypt(const CCM128_CONTEXT *ctx, const void *key, // cbc128_f is the type of a function that performs CBC-mode encryption. typedef void (*cbc128_f)(const uint8_t *in, uint8_t *out, size_t len, - const void *key, uint8_t ivec[16], int enc); + const AES_KEY *key, uint8_t ivec[16], int enc); // CRYPTO_cbc128_encrypt encrypts |len| bytes from |in| to |out| using the // given IV and block cipher in CBC mode. The input need not be a multiple of // 128 bits long, but the output will round up to the nearest 128 bit multiple, // zero padding the input if needed. The IV will be updated on return. void CRYPTO_cbc128_encrypt(const uint8_t *in, uint8_t *out, size_t len, - const void *key, uint8_t ivec[16], block128_f block); + const AES_KEY *key, uint8_t ivec[16], + block128_f block); // CRYPTO_cbc128_decrypt decrypts |len| bytes from |in| to |out| using the // given IV and block cipher in CBC mode. If |len| is not a multiple of 128 // bits then only that many bytes will be written, but a multiple of 128 bits // is always read from |in|. The IV will be updated on return. void CRYPTO_cbc128_decrypt(const uint8_t *in, uint8_t *out, size_t len, - const void *key, uint8_t ivec[16], block128_f block); + const AES_KEY *key, uint8_t ivec[16], + block128_f block); // OFB. @@ -318,9 +329,9 @@ void CRYPTO_cbc128_decrypt(const uint8_t *in, uint8_t *out, size_t len, // requirement that |len| be a multiple of any value and any partial blocks are // stored in |ivec| and |*num|, the latter must be zero before the initial // call. -void CRYPTO_ofb128_encrypt(const uint8_t *in, uint8_t *out, - size_t len, const void *key, uint8_t ivec[16], - unsigned *num, block128_f block); +void CRYPTO_ofb128_encrypt(const uint8_t *in, uint8_t *out, size_t len, + const AES_KEY *key, uint8_t ivec[16], unsigned *num, + block128_f block); // CFB. @@ -330,25 +341,25 @@ void CRYPTO_ofb128_encrypt(const uint8_t *in, uint8_t *out, // |len| be a multiple of any value and any partial blocks are stored in |ivec| // and |*num|, the latter must be zero before the initial call. void CRYPTO_cfb128_encrypt(const uint8_t *in, uint8_t *out, size_t len, - const void *key, uint8_t ivec[16], unsigned *num, + const AES_KEY *key, uint8_t ivec[16], unsigned *num, int enc, block128_f block); // CRYPTO_cfb128_8_encrypt encrypts (or decrypts, if |enc| is zero) |len| bytes // from |in| to |out| using |block| in CFB-8 mode. Prior to the first call // |num| should be set to zero. void CRYPTO_cfb128_8_encrypt(const uint8_t *in, uint8_t *out, size_t len, - const void *key, uint8_t ivec[16], unsigned *num, - int enc, block128_f block); + const AES_KEY *key, uint8_t ivec[16], + unsigned *num, int enc, block128_f block); // CRYPTO_cfb128_1_encrypt encrypts (or decrypts, if |enc| is zero) |len| bytes // from |in| to |out| using |block| in CFB-1 mode. Prior to the first call // |num| should be set to zero. void CRYPTO_cfb128_1_encrypt(const uint8_t *in, uint8_t *out, size_t bits, - const void *key, uint8_t ivec[16], unsigned *num, - int enc, block128_f block); + const AES_KEY *key, uint8_t ivec[16], + unsigned *num, int enc, block128_f block); size_t CRYPTO_cts128_encrypt_block(const uint8_t *in, uint8_t *out, size_t len, - const void *key, uint8_t ivec[16], + const AES_KEY *key, uint8_t ivec[16], block128_f block); diff --git a/src/crypto/fipsmodule/modes/ofb.c b/src/crypto/fipsmodule/modes/ofb.c index 63bba68b..b1b4d875 100644 --- a/src/crypto/fipsmodule/modes/ofb.c +++ b/src/crypto/fipsmodule/modes/ofb.c @@ -57,7 +57,7 @@ OPENSSL_COMPILE_ASSERT((16 % sizeof(size_t)) == 0, bad_size_t_size_ofb); void CRYPTO_ofb128_encrypt(const uint8_t *in, uint8_t *out, size_t len, - const void *key, uint8_t ivec[16], unsigned *num, + const AES_KEY *key, uint8_t ivec[16], unsigned *num, block128_f block) { assert(in && out && key && ivec && num); diff --git a/src/crypto/fipsmodule/self_check/self_check.c b/src/crypto/fipsmodule/self_check/self_check.c index 2c5b3637..1bbefa98 100644 --- a/src/crypto/fipsmodule/self_check/self_check.c +++ b/src/crypto/fipsmodule/self_check/self_check.c @@ -394,6 +394,7 @@ int BORINGSSL_self_test(void) { // AES-CBC Encryption KAT memcpy(aes_iv, kAESIV, sizeof(kAESIV)); if (AES_set_encrypt_key(kAESKey, 8 * sizeof(kAESKey), &aes_key) != 0) { + fprintf(stderr, "AES_set_encrypt_key failed.\n"); goto err; } AES_cbc_encrypt(kPlaintext, output, sizeof(kPlaintext), &aes_key, aes_iv, @@ -406,6 +407,7 @@ int BORINGSSL_self_test(void) { // AES-CBC Decryption KAT memcpy(aes_iv, kAESIV, sizeof(kAESIV)); if (AES_set_decrypt_key(kAESKey, 8 * sizeof(kAESKey), &aes_key) != 0) { + fprintf(stderr, "AES_set_decrypt_key failed.\n"); goto err; } AES_cbc_encrypt(kAESCBCCiphertext, output, sizeof(kAESCBCCiphertext), @@ -420,6 +422,7 @@ int BORINGSSL_self_test(void) { OPENSSL_memset(nonce, 0, sizeof(nonce)); if (!EVP_AEAD_CTX_init(&aead_ctx, EVP_aead_aes_128_gcm(), kAESKey, sizeof(kAESKey), 0, NULL)) { + fprintf(stderr, "EVP_AEAD_CTX_init for AES-128-GCM failed.\n"); goto err; } @@ -429,6 +432,7 @@ int BORINGSSL_self_test(void) { kPlaintext, sizeof(kPlaintext), NULL, 0) || !check_test(kAESGCMCiphertext, output, sizeof(kAESGCMCiphertext), "AES-GCM Encryption KAT")) { + fprintf(stderr, "EVP_AEAD_CTX_seal for AES-128-GCM failed.\n"); goto err; } @@ -439,6 +443,7 @@ int BORINGSSL_self_test(void) { 0) || !check_test(kPlaintext, output, sizeof(kPlaintext), "AES-GCM Decryption KAT")) { + fprintf(stderr, "EVP_AEAD_CTX_open for AES-128-GCM failed.\n"); goto err; } @@ -504,6 +509,7 @@ int BORINGSSL_self_test(void) { &sig_len, rsa_key) || !check_test(kRSASignature, output, sizeof(kRSASignature), "RSA Sign KAT")) { + fprintf(stderr, "RSA signing test failed.\n"); goto err; } @@ -558,6 +564,7 @@ int BORINGSSL_self_test(void) { sizeof(kDRBGAD)) || !check_test(kDRBGReseedOutput, output, sizeof(kDRBGReseedOutput), "DRBG Reseed KAT")) { + fprintf(stderr, "CTR-DRBG failed.\n"); goto err; } CTR_DRBG_clear(&drbg); diff --git a/src/crypto/fipsmodule/sha/asm/sha1-armv8.pl b/src/crypto/fipsmodule/sha/asm/sha1-armv8.pl index cec3669f..80567d9f 100644 --- a/src/crypto/fipsmodule/sha/asm/sha1-armv8.pl +++ b/src/crypto/fipsmodule/sha/asm/sha1-armv8.pl @@ -330,6 +330,7 @@ $code.=<<___; .asciz "SHA1 block transform for ARMv8, CRYPTOGAMS by " .align 2 .comm OPENSSL_armcap_P,4,4 +.hidden OPENSSL_armcap_P ___ }}} diff --git a/src/crypto/fipsmodule/sha/asm/sha512-armv8.pl b/src/crypto/fipsmodule/sha/asm/sha512-armv8.pl index e3244f7d..22c47d75 100644 --- a/src/crypto/fipsmodule/sha/asm/sha512-armv8.pl +++ b/src/crypto/fipsmodule/sha/asm/sha512-armv8.pl @@ -428,6 +428,7 @@ ___ $code.=<<___; #ifndef __KERNEL__ .comm OPENSSL_armcap_P,4,4 +.hidden OPENSSL_armcap_P #endif ___ diff --git a/src/crypto/internal.h b/src/crypto/internal.h index 0e8ae3a6..6944d56a 100644 --- a/src/crypto/internal.h +++ b/src/crypto/internal.h @@ -132,13 +132,13 @@ #endif #endif -#if !defined(OPENSSL_NO_THREADS) && \ +#if defined(OPENSSL_THREADS) && \ (!defined(OPENSSL_WINDOWS) || defined(__MINGW32__)) #include #define OPENSSL_PTHREADS #endif -#if !defined(OPENSSL_NO_THREADS) && !defined(OPENSSL_PTHREADS) && \ +#if defined(OPENSSL_THREADS) && !defined(OPENSSL_PTHREADS) && \ defined(OPENSSL_WINDOWS) #define OPENSSL_WINDOWS_THREADS OPENSSL_MSVC_PRAGMA(warning(push, 3)) @@ -367,7 +367,7 @@ static inline int constant_time_select_int(crypto_word_t mask, int a, int b) { // Thread-safe initialisation. -#if defined(OPENSSL_NO_THREADS) +#if !defined(OPENSSL_THREADS) typedef uint32_t CRYPTO_once_t; #define CRYPTO_ONCE_INIT 0 #elif defined(OPENSSL_WINDOWS_THREADS) @@ -423,7 +423,7 @@ OPENSSL_EXPORT int CRYPTO_refcount_dec_and_test_zero(CRYPTO_refcount_t *count); // thread.h as a structure large enough to fit the real type. The global lock is // a different type so it may be initialized with platform initializer macros. -#if defined(OPENSSL_NO_THREADS) +#if !defined(OPENSSL_THREADS) struct CRYPTO_STATIC_MUTEX { char padding; // Empty structs have different sizes in C and C++. }; diff --git a/src/crypto/pem/pem_info.c b/src/crypto/pem/pem_info.c index d707e426..3627a450 100644 --- a/src/crypto/pem/pem_info.c +++ b/src/crypto/pem/pem_info.c @@ -75,221 +75,203 @@ STACK_OF(X509_INFO) *PEM_X509_INFO_read(FILE *fp, STACK_OF(X509_INFO) *sk, pem_password_cb *cb, void *u) { - BIO *b; - STACK_OF(X509_INFO) *ret; - - if ((b = BIO_new(BIO_s_file())) == NULL) { + BIO *b = BIO_new_fp(fp, BIO_NOCLOSE); + if (b == NULL) { OPENSSL_PUT_ERROR(PEM, ERR_R_BUF_LIB); - return (0); + return 0; } - BIO_set_fp(b, fp, BIO_NOCLOSE); - ret = PEM_X509_INFO_read_bio(b, sk, cb, u); + STACK_OF(X509_INFO) *ret = PEM_X509_INFO_read_bio(b, sk, cb, u); BIO_free(b); - return (ret); + return ret; } #endif +enum parse_result_t { + parse_ok, + parse_error, + parse_new_entry, +}; + +static enum parse_result_t parse_x509(X509_INFO *info, const uint8_t *data, + size_t len, int key_type) +{ + if (info->x509 != NULL) { + return parse_new_entry; + } + info->x509 = d2i_X509(NULL, &data, len); + return info->x509 != NULL ? parse_ok : parse_error; +} + +static enum parse_result_t parse_x509_aux(X509_INFO *info, const uint8_t *data, + size_t len, int key_type) +{ + if (info->x509 != NULL) { + return parse_new_entry; + } + info->x509 = d2i_X509_AUX(NULL, &data, len); + return info->x509 != NULL ? parse_ok : parse_error; +} + +static enum parse_result_t parse_crl(X509_INFO *info, const uint8_t *data, + size_t len, int key_type) +{ + if (info->crl != NULL) { + return parse_new_entry; + } + info->crl = d2i_X509_CRL(NULL, &data, len); + return info->crl != NULL ? parse_ok : parse_error; +} + +static enum parse_result_t parse_key(X509_INFO *info, const uint8_t *data, + size_t len, int key_type) +{ + if (info->x_pkey != NULL) { + return parse_new_entry; + } + info->x_pkey = X509_PKEY_new(); + if (info->x_pkey == NULL) { + return parse_error; + } + info->x_pkey->dec_pkey = d2i_PrivateKey(key_type, NULL, &data, len); + return info->x_pkey->dec_pkey != NULL ? parse_ok : parse_error; +} + STACK_OF(X509_INFO) *PEM_X509_INFO_read_bio(BIO *bp, STACK_OF(X509_INFO) *sk, pem_password_cb *cb, void *u) { - X509_INFO *xi = NULL; + X509_INFO *info = NULL; char *name = NULL, *header = NULL; - void *pp; unsigned char *data = NULL; - const unsigned char *p; - long len, error = 0; + long len; int ok = 0; STACK_OF(X509_INFO) *ret = NULL; - unsigned int i, raw, ptype; - d2i_of_void *d2i = 0; if (sk == NULL) { - if ((ret = sk_X509_INFO_new_null()) == NULL) { + ret = sk_X509_INFO_new_null(); + if (ret == NULL) { OPENSSL_PUT_ERROR(PEM, ERR_R_MALLOC_FAILURE); - goto err; + return NULL; } - } else + } else { ret = sk; + } + size_t orig_num = sk_X509_INFO_num(ret); - if ((xi = X509_INFO_new()) == NULL) + info = X509_INFO_new(); + if (info == NULL) { goto err; + } + for (;;) { - raw = 0; - ptype = 0; - i = PEM_read_bio(bp, &name, &header, &data, &len); - if (i == 0) { - error = ERR_GET_REASON(ERR_peek_last_error()); - if (error == PEM_R_NO_START_LINE) { + if (!PEM_read_bio(bp, &name, &header, &data, &len)) { + uint32_t error = ERR_peek_last_error(); + if (ERR_GET_LIB(error) == ERR_LIB_PEM && + ERR_GET_REASON(error) == PEM_R_NO_START_LINE) { ERR_clear_error(); break; } goto err; } - start: - if ((strcmp(name, PEM_STRING_X509) == 0) || - (strcmp(name, PEM_STRING_X509_OLD) == 0)) { - d2i = (D2I_OF(void)) d2i_X509; - if (xi->x509 != NULL) { - if (!sk_X509_INFO_push(ret, xi)) - goto err; - if ((xi = X509_INFO_new()) == NULL) - goto err; - goto start; - } - pp = &(xi->x509); - } else if ((strcmp(name, PEM_STRING_X509_TRUSTED) == 0)) { - d2i = (D2I_OF(void)) d2i_X509_AUX; - if (xi->x509 != NULL) { - if (!sk_X509_INFO_push(ret, xi)) - goto err; - if ((xi = X509_INFO_new()) == NULL) - goto err; - goto start; - } - pp = &(xi->x509); + + enum parse_result_t (*parse_function)(X509_INFO *, const uint8_t *, + size_t, int) = NULL; + int key_type = EVP_PKEY_NONE; + if (strcmp(name, PEM_STRING_X509) == 0 || + strcmp(name, PEM_STRING_X509_OLD) == 0) { + parse_function = parse_x509; + } else if (strcmp(name, PEM_STRING_X509_TRUSTED) == 0) { + parse_function = parse_x509_aux; } else if (strcmp(name, PEM_STRING_X509_CRL) == 0) { - d2i = (D2I_OF(void)) d2i_X509_CRL; - if (xi->crl != NULL) { - if (!sk_X509_INFO_push(ret, xi)) - goto err; - if ((xi = X509_INFO_new()) == NULL) - goto err; - goto start; - } - pp = &(xi->crl); + parse_function = parse_crl; } else if (strcmp(name, PEM_STRING_RSA) == 0) { - d2i = (D2I_OF(void)) d2i_RSAPrivateKey; - if (xi->x_pkey != NULL) { - if (!sk_X509_INFO_push(ret, xi)) - goto err; - if ((xi = X509_INFO_new()) == NULL) - goto err; - goto start; - } - - xi->enc_data = NULL; - xi->enc_len = 0; + parse_function = parse_key; + key_type = EVP_PKEY_RSA; + } else if (strcmp(name, PEM_STRING_DSA) == 0) { + parse_function = parse_key; + key_type = EVP_PKEY_DSA; + } else if (strcmp(name, PEM_STRING_ECPRIVATEKEY) == 0) { + parse_function = parse_key; + key_type = EVP_PKEY_EC; + } - xi->x_pkey = X509_PKEY_new(); - ptype = EVP_PKEY_RSA; - pp = &xi->x_pkey->dec_pkey; - if ((int)strlen(header) > 10) /* assume encrypted */ - raw = 1; - } else -#ifndef OPENSSL_NO_DSA - if (strcmp(name, PEM_STRING_DSA) == 0) { - d2i = (D2I_OF(void)) d2i_DSAPrivateKey; - if (xi->x_pkey != NULL) { - if (!sk_X509_INFO_push(ret, xi)) + /* If a private key has a header, assume it is encrypted. */ + if (key_type != EVP_PKEY_NONE && strlen(header) > 10) { + if (info->x_pkey != NULL) { + if (!sk_X509_INFO_push(ret, info)) { goto err; - if ((xi = X509_INFO_new()) == NULL) + } + info = X509_INFO_new(); + if (info == NULL) { goto err; - goto start; + } } - - xi->enc_data = NULL; - xi->enc_len = 0; - - xi->x_pkey = X509_PKEY_new(); - ptype = EVP_PKEY_DSA; - pp = &xi->x_pkey->dec_pkey; - if ((int)strlen(header) > 10) /* assume encrypted */ - raw = 1; - } else -#endif - if (strcmp(name, PEM_STRING_ECPRIVATEKEY) == 0) { - d2i = (D2I_OF(void)) d2i_ECPrivateKey; - if (xi->x_pkey != NULL) { - if (!sk_X509_INFO_push(ret, xi)) - goto err; - if ((xi = X509_INFO_new()) == NULL) - goto err; - goto start; + /* Historically, raw entries pushed an empty key. */ + info->x_pkey = X509_PKEY_new(); + if (info->x_pkey == NULL || + !PEM_get_EVP_CIPHER_INFO(header, &info->enc_cipher)) { + goto err; } - - xi->enc_data = NULL; - xi->enc_len = 0; - - xi->x_pkey = X509_PKEY_new(); - ptype = EVP_PKEY_EC; - pp = &xi->x_pkey->dec_pkey; - if ((int)strlen(header) > 10) /* assume encrypted */ - raw = 1; - } else { - d2i = NULL; - pp = NULL; - } - - if (d2i != NULL) { - if (!raw) { - EVP_CIPHER_INFO cipher; - - if (!PEM_get_EVP_CIPHER_INFO(header, &cipher)) - goto err; - if (!PEM_do_header(&cipher, data, &len, cb, u)) - goto err; - p = data; - if (ptype) { - if (!d2i_PrivateKey(ptype, pp, &p, len)) { - OPENSSL_PUT_ERROR(PEM, ERR_R_ASN1_LIB); - goto err; - } - } else if (d2i(pp, &p, len) == NULL) { - OPENSSL_PUT_ERROR(PEM, ERR_R_ASN1_LIB); + info->enc_data = (char *)data; + info->enc_len = (int)len; + data = NULL; + } else if (parse_function != NULL) { + EVP_CIPHER_INFO cipher; + if (!PEM_get_EVP_CIPHER_INFO(header, &cipher) || + !PEM_do_header(&cipher, data, &len, cb, u)) { + goto err; + } + enum parse_result_t result = + parse_function(info, data, len, key_type); + if (result == parse_new_entry) { + if (!sk_X509_INFO_push(ret, info)) { goto err; } - } else { /* encrypted RSA data */ - if (!PEM_get_EVP_CIPHER_INFO(header, &xi->enc_cipher)) + info = X509_INFO_new(); + if (info == NULL) { goto err; - xi->enc_data = (char *)data; - xi->enc_len = (int)len; - data = NULL; + } + result = parse_function(info, data, len, key_type); + } + if (result != parse_ok) { + OPENSSL_PUT_ERROR(PEM, ERR_R_ASN1_LIB); + goto err; } - } else { - /* unknown */ } - if (name != NULL) - OPENSSL_free(name); - if (header != NULL) - OPENSSL_free(header); - if (data != NULL) - OPENSSL_free(data); + OPENSSL_free(name); + OPENSSL_free(header); + OPENSSL_free(data); name = NULL; header = NULL; data = NULL; } - /* - * if the last one hasn't been pushed yet and there is anything in it - * then add it to the stack ... - */ - if ((xi->x509 != NULL) || (xi->crl != NULL) || - (xi->x_pkey != NULL) || (xi->enc_data != NULL)) { - if (!sk_X509_INFO_push(ret, xi)) + /* Push the last entry on the stack if not empty. */ + if (info->x509 != NULL || info->crl != NULL || + info->x_pkey != NULL || info->enc_data != NULL) { + if (!sk_X509_INFO_push(ret, info)) { goto err; - xi = NULL; + } + info = NULL; } + ok = 1; + err: - if (xi != NULL) - X509_INFO_free(xi); + X509_INFO_free(info); if (!ok) { - for (i = 0; i < sk_X509_INFO_num(ret); i++) { - xi = sk_X509_INFO_value(ret, i); - X509_INFO_free(xi); + while (sk_X509_INFO_num(ret) > orig_num) { + X509_INFO_free(sk_X509_INFO_pop(ret)); } - if (ret != sk) + if (ret != sk) { sk_X509_INFO_free(ret); + } ret = NULL; } - if (name != NULL) - OPENSSL_free(name); - if (header != NULL) - OPENSSL_free(header); - if (data != NULL) - OPENSSL_free(data); - return (ret); + OPENSSL_free(name); + OPENSSL_free(header); + OPENSSL_free(data); + return ret; } /* A TJH addition */ diff --git a/src/crypto/pem/pem_lib.c b/src/crypto/pem/pem_lib.c index 5180e55d..c6824296 100644 --- a/src/crypto/pem/pem_lib.c +++ b/src/crypto/pem/pem_lib.c @@ -121,17 +121,14 @@ void PEM_dek_info(char *buf, const char *type, int len, char *str) void *PEM_ASN1_read(d2i_of_void *d2i, const char *name, FILE *fp, void **x, pem_password_cb *cb, void *u) { - BIO *b; - void *ret; - - if ((b = BIO_new(BIO_s_file())) == NULL) { + BIO *b = BIO_new_fp(fp, BIO_NOCLOSE); + if (b == NULL) { OPENSSL_PUT_ERROR(PEM, ERR_R_BUF_LIB); - return (0); + return NULL; } - BIO_set_fp(b, fp, BIO_NOCLOSE); - ret = PEM_ASN1_read_bio(d2i, name, b, x, cb, u); + void *ret = PEM_ASN1_read_bio(d2i, name, b, x, cb, u); BIO_free(b); - return (ret); + return ret; } #endif @@ -220,8 +217,11 @@ int PEM_bytes_read_bio(unsigned char **pdata, long *plen, char **pnm, for (;;) { if (!PEM_read_bio(bp, &nm, &header, &data, &len)) { - if (ERR_GET_REASON(ERR_peek_error()) == PEM_R_NO_START_LINE) + uint32_t error = ERR_peek_error(); + if (ERR_GET_LIB(error) == ERR_LIB_PEM && + ERR_GET_REASON(error) == PEM_R_NO_START_LINE) { ERR_add_error_data(2, "Expecting: ", name); + } return 0; } if (check_pem(nm, name)) @@ -257,17 +257,14 @@ int PEM_ASN1_write(i2d_of_void *i2d, const char *name, FILE *fp, void *x, const EVP_CIPHER *enc, unsigned char *kstr, int klen, pem_password_cb *callback, void *u) { - BIO *b; - int ret; - - if ((b = BIO_new(BIO_s_file())) == NULL) { + BIO *b = BIO_new_fp(fp, BIO_NOCLOSE); + if (b == NULL) { OPENSSL_PUT_ERROR(PEM, ERR_R_BUF_LIB); - return (0); + return 0; } - BIO_set_fp(b, fp, BIO_NOCLOSE); - ret = PEM_ASN1_write_bio(i2d, name, b, x, enc, kstr, klen, callback, u); + int ret = PEM_ASN1_write_bio(i2d, name, b, x, enc, kstr, klen, callback, u); BIO_free(b); - return (ret); + return ret; } #endif @@ -514,15 +511,12 @@ static int load_iv(char **fromp, unsigned char *to, int num) int PEM_write(FILE *fp, const char *name, const char *header, const unsigned char *data, long len) { - BIO *b; - int ret; - - if ((b = BIO_new(BIO_s_file())) == NULL) { + BIO *b = BIO_new_fp(fp, BIO_NOCLOSE); + if (b == NULL) { OPENSSL_PUT_ERROR(PEM, ERR_R_BUF_LIB); - return (0); + return 0; } - BIO_set_fp(b, fp, BIO_NOCLOSE); - ret = PEM_write_bio(b, name, header, data, len); + int ret = PEM_write_bio(b, name, header, data, len); BIO_free(b); return (ret); } @@ -588,15 +582,12 @@ int PEM_write_bio(BIO *bp, const char *name, const char *header, int PEM_read(FILE *fp, char **name, char **header, unsigned char **data, long *len) { - BIO *b; - int ret; - - if ((b = BIO_new(BIO_s_file())) == NULL) { + BIO *b = BIO_new_fp(fp, BIO_NOCLOSE); + if (b == NULL) { OPENSSL_PUT_ERROR(PEM, ERR_R_BUF_LIB); - return (0); + return 0; } - BIO_set_fp(b, fp, BIO_NOCLOSE); - ret = PEM_read_bio(b, name, header, data, len); + int ret = PEM_read_bio(b, name, header, data, len); BIO_free(b); return (ret); } diff --git a/src/crypto/pem/pem_pkey.c b/src/crypto/pem/pem_pkey.c index 9fbaeef8..725a84be 100644 --- a/src/crypto/pem/pem_pkey.c +++ b/src/crypto/pem/pem_pkey.c @@ -155,31 +155,26 @@ int PEM_write_bio_PrivateKey(BIO *bp, EVP_PKEY *x, const EVP_CIPHER *enc, EVP_PKEY *PEM_read_PrivateKey(FILE *fp, EVP_PKEY **x, pem_password_cb *cb, void *u) { - BIO *b; - EVP_PKEY *ret; - - if ((b = BIO_new(BIO_s_file())) == NULL) { + BIO *b = BIO_new_fp(fp, BIO_NOCLOSE); + if (b == NULL) { OPENSSL_PUT_ERROR(PEM, ERR_R_BUF_LIB); - return (0); + return NULL; } - BIO_set_fp(b, fp, BIO_NOCLOSE); - ret = PEM_read_bio_PrivateKey(b, x, cb, u); + EVP_PKEY *ret = PEM_read_bio_PrivateKey(b, x, cb, u); BIO_free(b); - return (ret); + return ret; } int PEM_write_PrivateKey(FILE *fp, EVP_PKEY *x, const EVP_CIPHER *enc, unsigned char *kstr, int klen, pem_password_cb *cb, void *u) { - BIO *b; - int ret; - - if ((b = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) { + BIO *b = BIO_new_fp(fp, BIO_NOCLOSE); + if (b == NULL) { OPENSSL_PUT_ERROR(PEM, ERR_R_BUF_LIB); return 0; } - ret = PEM_write_bio_PrivateKey(b, x, enc, kstr, klen, cb, u); + int ret = PEM_write_bio_PrivateKey(b, x, enc, kstr, klen, cb, u); BIO_free(b); return ret; } @@ -212,16 +207,13 @@ DH *PEM_read_bio_DHparams(BIO *bp, DH **x, pem_password_cb *cb, void *u) #ifndef OPENSSL_NO_FP_API DH *PEM_read_DHparams(FILE *fp, DH **x, pem_password_cb *cb, void *u) { - BIO *b; - DH *ret; - - if ((b = BIO_new(BIO_s_file())) == NULL) { + BIO *b = BIO_new_fp(fp, BIO_NOCLOSE); + if (b == NULL) { OPENSSL_PUT_ERROR(PEM, ERR_R_BUF_LIB); - return (0); + return NULL; } - BIO_set_fp(b, fp, BIO_NOCLOSE); - ret = PEM_read_bio_DHparams(b, x, cb, u); + DH *ret = PEM_read_bio_DHparams(b, x, cb, u); BIO_free(b); - return (ret); + return ret; } #endif diff --git a/src/crypto/pkcs7/pkcs7_x509.c b/src/crypto/pkcs7/pkcs7_x509.c index a2a6b46a..d6ca44ea 100644 --- a/src/crypto/pkcs7/pkcs7_x509.c +++ b/src/crypto/pkcs7/pkcs7_x509.c @@ -333,17 +333,7 @@ int i2d_PKCS7(const PKCS7 *p7, uint8_t **out) { } int i2d_PKCS7_bio(BIO *bio, const PKCS7 *p7) { - size_t written = 0; - while (written < p7->ber_len) { - size_t todo = p7->ber_len - written; - int len = todo > INT_MAX ? INT_MAX : (int)todo; - int ret = BIO_write(bio, p7->ber_bytes + written, len); - if (ret <= 0) { - return 0; - } - written += (size_t)ret; - } - return 1; + return BIO_write_all(bio, p7->ber_bytes, p7->ber_len); } void PKCS7_free(PKCS7 *p7) { diff --git a/src/crypto/pkcs8/pkcs8_x509.c b/src/crypto/pkcs8/pkcs8_x509.c index dc74d968..2c7841ee 100644 --- a/src/crypto/pkcs8/pkcs8_x509.c +++ b/src/crypto/pkcs8/pkcs8_x509.c @@ -861,17 +861,7 @@ int i2d_PKCS12(const PKCS12 *p12, uint8_t **out) { } int i2d_PKCS12_bio(BIO *bio, const PKCS12 *p12) { - size_t written = 0; - while (written < p12->ber_len) { - size_t todo = p12->ber_len - written; - int len = todo > INT_MAX ? INT_MAX : (int)todo; - int ret = BIO_write(bio, p12->ber_bytes + written, len); - if (ret <= 0) { - return 0; - } - written += (size_t)ret; - } - return 1; + return BIO_write_all(bio, p12->ber_bytes, p12->ber_len); } int i2d_PKCS12_fp(FILE *fp, const PKCS12 *p12) { diff --git a/src/crypto/pool/pool_test.cc b/src/crypto/pool/pool_test.cc index 62fb17dd..8f32fb6f 100644 --- a/src/crypto/pool/pool_test.cc +++ b/src/crypto/pool/pool_test.cc @@ -18,7 +18,7 @@ #include "../test/test_util.h" -#if !defined(OPENSSL_NO_THREADS) +#if defined(OPENSSL_THREADS) #include #include #endif @@ -61,7 +61,7 @@ TEST(PoolTest, Pooled) { EXPECT_EQ(buf.get(), buf2.get()) << "CRYPTO_BUFFER_POOL did not dedup data."; } -#if !defined(OPENSSL_NO_THREADS) +#if defined(OPENSSL_THREADS) TEST(PoolTest, Threads) { bssl::UniquePtr pool(CRYPTO_BUFFER_POOL_new()); ASSERT_TRUE(pool); diff --git a/src/crypto/rand_extra/rand_test.cc b/src/crypto/rand_extra/rand_test.cc index bd2eb188..d0a7e40e 100644 --- a/src/crypto/rand_extra/rand_test.cc +++ b/src/crypto/rand_extra/rand_test.cc @@ -20,7 +20,7 @@ #include "../test/test_util.h" -#if !defined(OPENSSL_NO_THREADS) +#if defined(OPENSSL_THREADS) #include #include #include @@ -50,7 +50,8 @@ TEST(RandTest, NotObviouslyBroken) { EXPECT_NE(Bytes(buf2), Bytes(kZeros)); } -#if !defined(OPENSSL_WINDOWS) && !defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE) +#if !defined(OPENSSL_WINDOWS) && !defined(OPENSSL_IOS) && \ + !defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE) static bool ForkAndRand(bssl::Span out) { int pipefds[2]; if (pipe(pipefds) < 0) { @@ -144,9 +145,10 @@ TEST(RandTest, Fork) { EXPECT_NE(Bytes(buf2), Bytes(kZeros)); EXPECT_NE(Bytes(buf3), Bytes(kZeros)); } -#endif // !OPENSSL_WINDOWS && !BORINGSSL_UNSAFE_DETERMINISTIC_MODE +#endif // !OPENSSL_WINDOWS && !OPENSSL_IOS && + // !BORINGSSL_UNSAFE_DETERMINISTIC_MODE -#if !defined(OPENSSL_NO_THREADS) +#if defined(OPENSSL_THREADS) static void RunConcurrentRands(size_t num_threads) { static const uint8_t kZeros[256] = {0}; diff --git a/src/crypto/refcount_test.cc b/src/crypto/refcount_test.cc index 6ce0746d..700863f6 100644 --- a/src/crypto/refcount_test.cc +++ b/src/crypto/refcount_test.cc @@ -16,7 +16,7 @@ #include -#if !defined(OPENSSL_NO_THREADS) +#if defined(OPENSSL_THREADS) #include #endif @@ -43,7 +43,7 @@ TEST(RefCountTest, Basic) { EXPECT_EQ(1u, count); } -#if !defined(OPENSSL_NO_THREADS) +#if defined(OPENSSL_THREADS) // This test is primarily intended to run under ThreadSanitizer. TEST(RefCountTest, Threads) { CRYPTO_refcount_t count = 0; diff --git a/src/crypto/rsa_extra/rsa_test.cc b/src/crypto/rsa_extra/rsa_test.cc index b0a0b7e4..9bd47b1b 100644 --- a/src/crypto/rsa_extra/rsa_test.cc +++ b/src/crypto/rsa_extra/rsa_test.cc @@ -72,7 +72,7 @@ #include "../internal.h" #include "../test/test_util.h" -#if !defined(OPENSSL_NO_THREADS) +#if defined(OPENSSL_THREADS) #include #include #endif @@ -1048,7 +1048,7 @@ TEST(RSATest, SqrtTwo) { } #endif // !BORINGSSL_SHARED_LIBRARY -#if !defined(OPENSSL_NO_THREADS) +#if defined(OPENSSL_THREADS) TEST(RSATest, Threads) { bssl::UniquePtr rsa_template( RSA_private_key_from_bytes(kKey1, sizeof(kKey1) - 1)); diff --git a/src/crypto/stack/stack.c b/src/crypto/stack/stack.c index 7aa32186..93b9d1b0 100644 --- a/src/crypto/stack/stack.c +++ b/src/crypto/stack/stack.c @@ -133,19 +133,31 @@ void sk_free(_STACK *sk) { OPENSSL_free(sk); } -void sk_pop_free(_STACK *sk, void (*func)(void *)) { +void sk_pop_free_ex(_STACK *sk, void (*call_free_func)(stack_free_func, void *), + stack_free_func free_func) { if (sk == NULL) { return; } for (size_t i = 0; i < sk->num; i++) { if (sk->data[i] != NULL) { - func(sk->data[i]); + call_free_func(free_func, sk->data[i]); } } sk_free(sk); } +// Historically, |sk_pop_free| called the function as |stack_free_func| +// directly. This is undefined in C. Some callers called |sk_pop_free| directly, +// so we must maintain a compatibility version for now. +static void call_free_func_legacy(stack_free_func func, void *ptr) { + func(ptr); +} + +void sk_pop_free(_STACK *sk, stack_free_func free_func) { + sk_pop_free_ex(sk, call_free_func_legacy, free_func); +} + size_t sk_insert(_STACK *sk, void *p, size_t where) { if (sk == NULL) { return 0; @@ -209,7 +221,7 @@ void *sk_delete(_STACK *sk, size_t where) { return ret; } -void *sk_delete_ptr(_STACK *sk, void *p) { +void *sk_delete_ptr(_STACK *sk, const void *p) { if (sk == NULL) { return NULL; } @@ -223,7 +235,9 @@ void *sk_delete_ptr(_STACK *sk, void *p) { return NULL; } -int sk_find(const _STACK *sk, size_t *out_index, void *p) { +int sk_find(const _STACK *sk, size_t *out_index, const void *p, + int (*call_cmp_func)(stack_cmp_func, const void **, + const void **)) { if (sk == NULL) { return 0; } @@ -247,7 +261,8 @@ int sk_find(const _STACK *sk, size_t *out_index, void *p) { if (!sk_is_sorted(sk)) { for (size_t i = 0; i < sk->num; i++) { - if (sk->comp((const void **)&p, (const void **)&sk->data[i]) == 0) { + const void *elem = sk->data[i]; + if (call_cmp_func(sk->comp, &p, &elem) == 0) { if (out_index) { *out_index = i; } @@ -262,15 +277,25 @@ int sk_find(const _STACK *sk, size_t *out_index, void *p) { // elements. However, since we're passing an array of pointers to // qsort/bsearch, we can just cast the comparison function and everything // works. + // + // TODO(davidben): This is undefined behavior, but the call is in libc so, + // e.g., CFI does not notice. Unfortunately, |bsearch| is missing a void* + // parameter in its callback and |bsearch_s| is a mess of incompatibility. const void *const *r = bsearch(&p, sk->data, sk->num, sizeof(void *), (int (*)(const void *, const void *))sk->comp); if (r == NULL) { return 0; } size_t idx = ((void **)r) - sk->data; - // This function always returns the first result. - while (idx > 0 && - sk->comp((const void **)&p, (const void **)&sk->data[idx - 1]) == 0) { + // This function always returns the first result. Note this logic is, in the + // worst case, O(N) rather than O(log(N)). If this ever becomes a problem, + // restore https://boringssl-review.googlesource.com/c/boringssl/+/32115/ + // which integrates the preference into the binary search. + while (idx > 0) { + const void *elem = sk->data[idx - 1]; + if (call_cmp_func(sk->comp, &p, &elem) != 0) { + break; + } idx--; } if (out_index) { @@ -340,6 +365,11 @@ void sk_sort(_STACK *sk) { } // See the comment in sk_find about this cast. + // + // TODO(davidben): This is undefined behavior, but the call is in libc so, + // e.g., CFI does not notice. Unfortunately, |qsort| is missing a void* + // parameter in its callback and |qsort_s| / |qsort_r| are a mess of + // incompatibility. comp_func = (int (*)(const void *, const void *))(sk->comp); qsort(sk->data, sk->num, sizeof(void *), comp_func); sk->sorted = 1; @@ -363,8 +393,11 @@ stack_cmp_func sk_set_cmp_func(_STACK *sk, stack_cmp_func comp) { return old; } -_STACK *sk_deep_copy(const _STACK *sk, void *(*copy_func)(void *), - void (*free_func)(void *)) { +_STACK *sk_deep_copy(const _STACK *sk, + void *(*call_copy_func)(stack_copy_func, void *), + stack_copy_func copy_func, + void (*call_free_func)(stack_free_func, void *), + stack_free_func free_func) { _STACK *ret = sk_dup(sk); if (ret == NULL) { return NULL; @@ -374,11 +407,11 @@ _STACK *sk_deep_copy(const _STACK *sk, void *(*copy_func)(void *), if (ret->data[i] == NULL) { continue; } - ret->data[i] = copy_func(ret->data[i]); + ret->data[i] = call_copy_func(copy_func, ret->data[i]); if (ret->data[i] == NULL) { for (size_t j = 0; j < i; j++) { if (ret->data[j] != NULL) { - free_func(ret->data[j]); + call_free_func(free_func, ret->data[j]); } } sk_free(ret); diff --git a/src/crypto/stack/stack_test.cc b/src/crypto/stack/stack_test.cc new file mode 100644 index 00000000..8b269719 --- /dev/null +++ b/src/crypto/stack/stack_test.cc @@ -0,0 +1,394 @@ +/* Copyright (c) 2018, 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. */ + +#include + +#include + +#include +#include +#include +#include + +#include + +#include + + +// Define a custom stack type for testing. +using TEST_INT = int; + +static void TEST_INT_free(TEST_INT *x) { OPENSSL_free(x); } + +namespace bssl { +BORINGSSL_MAKE_DELETER(TEST_INT, TEST_INT_free) +} // namespace bssl + +static bssl::UniquePtr TEST_INT_new(int x) { + bssl::UniquePtr ret( + static_cast(OPENSSL_malloc(sizeof(TEST_INT)))); + if (!ret) { + return nullptr; + } + *ret = x; + return ret; +} + +DEFINE_STACK_OF(TEST_INT) + +struct ShallowStackDeleter { + void operator()(STACK_OF(TEST_INT) *sk) const { sk_TEST_INT_free(sk); } +}; + +using ShallowStack = std::unique_ptr; + +// kNull is treated as a nullptr expectation for purposes of ExpectStackEquals. +// The tests in this file will never use it as a test value. +static const int kNull = INT_MIN; + +static void ExpectStackEquals(const STACK_OF(TEST_INT) *sk, + const std::vector &vec) { + EXPECT_EQ(vec.size(), sk_TEST_INT_num(sk)); + for (size_t i = 0; i < vec.size(); i++) { + SCOPED_TRACE(i); + const TEST_INT *obj = sk_TEST_INT_value(sk, i); + if (vec[i] == kNull) { + EXPECT_FALSE(obj); + } else { + EXPECT_TRUE(obj); + if (obj) { + EXPECT_EQ(vec[i], *obj); + } + } + } + + // Reading out-of-bounds fails. + EXPECT_FALSE(sk_TEST_INT_value(sk, vec.size())); + EXPECT_FALSE(sk_TEST_INT_value(sk, vec.size() + 1)); +} + +TEST(StackTest, Basic) { + bssl::UniquePtr sk(sk_TEST_INT_new_null()); + ASSERT_TRUE(sk); + + // The stack starts out empty. + ExpectStackEquals(sk.get(), {}); + + // Removing elements from an empty stack does nothing. + EXPECT_FALSE(sk_TEST_INT_pop(sk.get())); + EXPECT_FALSE(sk_TEST_INT_shift(sk.get())); + EXPECT_FALSE(sk_TEST_INT_delete(sk.get(), 0)); + + // Push some elements. + for (int i = 0; i < 6; i++) { + auto value = TEST_INT_new(i); + ASSERT_TRUE(value); + ASSERT_TRUE(bssl::PushToStack(sk.get(), std::move(value))); + } + + ExpectStackEquals(sk.get(), {0, 1, 2, 3, 4, 5}); + + // Items may be inserted in the middle. + auto value = TEST_INT_new(6); + ASSERT_TRUE(value); + // Hold on to the object for later. + TEST_INT *raw = value.get(); + ASSERT_TRUE(sk_TEST_INT_insert(sk.get(), value.get(), 4)); + value.release(); // sk_TEST_INT_insert takes ownership on success. + + ExpectStackEquals(sk.get(), {0, 1, 2, 3, 6, 4, 5}); + + // Without a comparison function, find searches by pointer. + value = TEST_INT_new(6); + ASSERT_TRUE(value); + size_t index; + EXPECT_FALSE(sk_TEST_INT_find(sk.get(), &index, value.get())); + ASSERT_TRUE(sk_TEST_INT_find(sk.get(), &index, raw)); + EXPECT_EQ(4u, index); + + // sk_TEST_INT_insert can also insert values at the end. + value = TEST_INT_new(7); + ASSERT_TRUE(value); + ASSERT_TRUE(sk_TEST_INT_insert(sk.get(), value.get(), 7)); + value.release(); // sk_TEST_INT_insert takes ownership on success. + + ExpectStackEquals(sk.get(), {0, 1, 2, 3, 6, 4, 5, 7}); + + // Out-of-bounds indices are clamped. + value = TEST_INT_new(8); + ASSERT_TRUE(value); + ASSERT_TRUE(sk_TEST_INT_insert(sk.get(), value.get(), 999)); + value.release(); // sk_TEST_INT_insert takes ownership on success. + + ExpectStackEquals(sk.get(), {0, 1, 2, 3, 6, 4, 5, 7, 8}); + + // Test removing elements from various places. + bssl::UniquePtr removed(sk_TEST_INT_pop(sk.get())); + EXPECT_EQ(8, *removed); + ExpectStackEquals(sk.get(), {0, 1, 2, 3, 6, 4, 5, 7}); + + removed.reset(sk_TEST_INT_shift(sk.get())); + EXPECT_EQ(0, *removed); + ExpectStackEquals(sk.get(), {1, 2, 3, 6, 4, 5, 7}); + + removed.reset(sk_TEST_INT_delete(sk.get(), 2)); + EXPECT_EQ(3, *removed); + ExpectStackEquals(sk.get(), {1, 2, 6, 4, 5, 7}); + + // Objects may also be deleted by pointer. + removed.reset(sk_TEST_INT_delete_ptr(sk.get(), raw)); + EXPECT_EQ(raw, removed.get()); + ExpectStackEquals(sk.get(), {1, 2, 4, 5, 7}); + + // Deleting is a no-op is the object is not found. + value = TEST_INT_new(100); + ASSERT_TRUE(value); + EXPECT_FALSE(sk_TEST_INT_delete_ptr(sk.get(), value.get())); + + // Insert nullptr to test deep copy handling of it. + ASSERT_TRUE(sk_TEST_INT_insert(sk.get(), nullptr, 0)); + ExpectStackEquals(sk.get(), {kNull, 1, 2, 4, 5, 7}); + + // Test both deep and shallow copies. + bssl::UniquePtr copy(sk_TEST_INT_deep_copy( + sk.get(), + [](TEST_INT *x) -> TEST_INT * { + return x == nullptr ? nullptr : TEST_INT_new(*x).release(); + }, + TEST_INT_free)); + ASSERT_TRUE(copy); + ExpectStackEquals(copy.get(), {kNull, 1, 2, 4, 5, 7}); + + ShallowStack shallow(sk_TEST_INT_dup(sk.get())); + ASSERT_TRUE(shallow); + ASSERT_EQ(sk_TEST_INT_num(sk.get()), sk_TEST_INT_num(shallow.get())); + for (size_t i = 0; i < sk_TEST_INT_num(sk.get()); i++) { + EXPECT_EQ(sk_TEST_INT_value(sk.get(), i), + sk_TEST_INT_value(shallow.get(), i)); + } + + // Deep copies may fail. This should clean up temporaries. + EXPECT_FALSE(sk_TEST_INT_deep_copy(sk.get(), + [](TEST_INT *x) -> TEST_INT * { + return x == nullptr || *x == 4 + ? nullptr + : TEST_INT_new(*x).release(); + }, + TEST_INT_free)); + + // sk_TEST_INT_zero clears a stack, but does not free the elements. + ShallowStack shallow2(sk_TEST_INT_dup(sk.get())); + ASSERT_TRUE(shallow2); + sk_TEST_INT_zero(shallow2.get()); + ExpectStackEquals(shallow2.get(), {}); +} + +TEST(StackTest, BigStack) { + bssl::UniquePtr sk(sk_TEST_INT_new_null()); + ASSERT_TRUE(sk); + + std::vector expected; + static const int kCount = 100000; + for (int i = 0; i < kCount; i++) { + auto value = TEST_INT_new(i); + ASSERT_TRUE(value); + ASSERT_TRUE(bssl::PushToStack(sk.get(), std::move(value))); + expected.push_back(i); + } + ExpectStackEquals(sk.get(), expected); +} + +static uint64_t g_compare_count = 0; + +static int compare(const TEST_INT **a, const TEST_INT **b) { + g_compare_count++; + if (**a < **b) { + return -1; + } + if (**a > **b) { + return 1; + } + return 0; +} + +static int compare_reverse(const TEST_INT **a, const TEST_INT **b) { + return -compare(a, b); +} + +TEST(StackTest, Sorted) { + std::vector vec_sorted = {0, 1, 2, 3, 4, 5, 6}; + std::vector vec = vec_sorted; + do { + bssl::UniquePtr sk(sk_TEST_INT_new(compare)); + ASSERT_TRUE(sk); + for (int v : vec) { + auto value = TEST_INT_new(v); + ASSERT_TRUE(value); + ASSERT_TRUE(bssl::PushToStack(sk.get(), std::move(value))); + } + + // The stack is not (known to be) sorted. + EXPECT_FALSE(sk_TEST_INT_is_sorted(sk.get())); + + // With a comparison function, find matches by value. + auto ten = TEST_INT_new(10); + ASSERT_TRUE(ten); + size_t index; + EXPECT_FALSE(sk_TEST_INT_find(sk.get(), &index, ten.get())); + + auto three = TEST_INT_new(3); + ASSERT_TRUE(three); + ASSERT_TRUE(sk_TEST_INT_find(sk.get(), &index, three.get())); + EXPECT_EQ(3, *sk_TEST_INT_value(sk.get(), index)); + + sk_TEST_INT_sort(sk.get()); + EXPECT_TRUE(sk_TEST_INT_is_sorted(sk.get())); + ExpectStackEquals(sk.get(), vec_sorted); + + // Sorting an already-sorted list is a no-op. + uint64_t old_compare_count = g_compare_count; + sk_TEST_INT_sort(sk.get()); + EXPECT_EQ(old_compare_count, g_compare_count); + EXPECT_TRUE(sk_TEST_INT_is_sorted(sk.get())); + ExpectStackEquals(sk.get(), vec_sorted); + + // When sorted, find uses binary search. + ASSERT_TRUE(ten); + EXPECT_FALSE(sk_TEST_INT_find(sk.get(), &index, ten.get())); + + ASSERT_TRUE(three); + ASSERT_TRUE(sk_TEST_INT_find(sk.get(), &index, three.get())); + EXPECT_EQ(3u, index); + + // Copies preserve comparison and sorted information. + bssl::UniquePtr copy(sk_TEST_INT_deep_copy( + sk.get(), + [](TEST_INT *x) -> TEST_INT * { return TEST_INT_new(*x).release(); }, + TEST_INT_free)); + ASSERT_TRUE(copy); + EXPECT_TRUE(sk_TEST_INT_is_sorted(copy.get())); + ASSERT_TRUE(sk_TEST_INT_find(copy.get(), &index, three.get())); + EXPECT_EQ(3u, index); + + ShallowStack copy2(sk_TEST_INT_dup(sk.get())); + ASSERT_TRUE(copy2); + EXPECT_TRUE(sk_TEST_INT_is_sorted(copy2.get())); + ASSERT_TRUE(sk_TEST_INT_find(copy2.get(), &index, three.get())); + EXPECT_EQ(3u, index); + + // Removing elements does not affect sortedness. + TEST_INT_free(sk_TEST_INT_delete(sk.get(), 0)); + EXPECT_TRUE(sk_TEST_INT_is_sorted(sk.get())); + + // Changing the comparison function invalidates sortedness. + sk_TEST_INT_set_cmp_func(sk.get(), compare_reverse); + EXPECT_FALSE(sk_TEST_INT_is_sorted(sk.get())); + ASSERT_TRUE(sk_TEST_INT_find(sk.get(), &index, three.get())); + EXPECT_EQ(2u, index); + + sk_TEST_INT_sort(sk.get()); + ExpectStackEquals(sk.get(), {6, 5, 4, 3, 2, 1}); + ASSERT_TRUE(sk_TEST_INT_find(sk.get(), &index, three.get())); + EXPECT_EQ(3u, index); + + // Inserting a new element invalidates sortedness. + auto tmp = TEST_INT_new(10); + ASSERT_TRUE(tmp); + ASSERT_TRUE(bssl::PushToStack(sk.get(), std::move(tmp))); + EXPECT_FALSE(sk_TEST_INT_is_sorted(sk.get())); + ASSERT_TRUE(sk_TEST_INT_find(sk.get(), &index, ten.get())); + EXPECT_EQ(6u, index); + } while (std::next_permutation(vec.begin(), vec.end())); +} + +// sk_*_find should return the first matching element in all cases. +TEST(StackTest, FindFirst) { + bssl::UniquePtr sk(sk_TEST_INT_new(compare)); + auto value = TEST_INT_new(1); + ASSERT_TRUE(value); + ASSERT_TRUE(bssl::PushToStack(sk.get(), std::move(value))); + for (int i = 0; i < 10; i++) { + value = TEST_INT_new(2); + ASSERT_TRUE(value); + ASSERT_TRUE(bssl::PushToStack(sk.get(), std::move(value))); + } + + const TEST_INT *two = sk_TEST_INT_value(sk.get(), 1); + // Pointer-based equality. + size_t index; + ASSERT_TRUE(sk_TEST_INT_find(sk.get(), &index, two)); + EXPECT_EQ(1u, index); + + // Comparator-based equality, unsorted. + sk_TEST_INT_set_cmp_func(sk.get(), compare); + EXPECT_FALSE(sk_TEST_INT_is_sorted(sk.get())); + ASSERT_TRUE(sk_TEST_INT_find(sk.get(), &index, two)); + EXPECT_EQ(1u, index); + + // Comparator-based equality, sorted. + sk_TEST_INT_sort(sk.get()); + EXPECT_TRUE(sk_TEST_INT_is_sorted(sk.get())); + ASSERT_TRUE(sk_TEST_INT_find(sk.get(), &index, two)); + EXPECT_EQ(1u, index); + + // Comparator-based equality, sorted and at the front. + sk_TEST_INT_set_cmp_func(sk.get(), compare_reverse); + sk_TEST_INT_sort(sk.get()); + EXPECT_TRUE(sk_TEST_INT_is_sorted(sk.get())); + ASSERT_TRUE(sk_TEST_INT_find(sk.get(), &index, two)); + EXPECT_EQ(0u, index); +} + +// Exhaustively test the binary search. +TEST(StackTest, BinarySearch) { + static const size_t kCount = 100; + for (size_t i = 0; i < kCount; i++) { + SCOPED_TRACE(i); + for (size_t j = i; j <= kCount; j++) { + SCOPED_TRACE(j); + // Make a stack where [0, i) are below, [i, j) match, and [j, kCount) are + // above. + bssl::UniquePtr sk(sk_TEST_INT_new(compare)); + ASSERT_TRUE(sk); + for (size_t k = 0; k < i; k++) { + auto value = TEST_INT_new(-1); + ASSERT_TRUE(value); + ASSERT_TRUE(bssl::PushToStack(sk.get(), std::move(value))); + } + for (size_t k = i; k < j; k++) { + auto value = TEST_INT_new(0); + ASSERT_TRUE(value); + ASSERT_TRUE(bssl::PushToStack(sk.get(), std::move(value))); + } + for (size_t k = j; k < kCount; k++) { + auto value = TEST_INT_new(1); + ASSERT_TRUE(value); + ASSERT_TRUE(bssl::PushToStack(sk.get(), std::move(value))); + } + sk_TEST_INT_sort(sk.get()); + + auto key = TEST_INT_new(0); + ASSERT_TRUE(key); + + size_t idx; + int found = sk_TEST_INT_find(sk.get(), &idx, key.get()); + if (i == j) { + EXPECT_FALSE(found); + } else { + ASSERT_TRUE(found); + EXPECT_EQ(i, idx); + } + } + } +} diff --git a/src/crypto/thread_none.c b/src/crypto/thread_none.c index 718d9601..4f07b9d9 100644 --- a/src/crypto/thread_none.c +++ b/src/crypto/thread_none.c @@ -14,7 +14,7 @@ #include "internal.h" -#if defined(OPENSSL_NO_THREADS) +#if !defined(OPENSSL_THREADS) void CRYPTO_MUTEX_init(CRYPTO_MUTEX *lock) {} @@ -56,4 +56,4 @@ int CRYPTO_set_thread_local(thread_local_data_t index, void *value, return 1; } -#endif // OPENSSL_NO_THREADS +#endif // !OPENSSL_THREADS diff --git a/src/crypto/thread_test.cc b/src/crypto/thread_test.cc index f89b22ec..f9fad9be 100644 --- a/src/crypto/thread_test.cc +++ b/src/crypto/thread_test.cc @@ -25,7 +25,7 @@ #include "test/test_util.h" -#if !defined(OPENSSL_NO_THREADS) +#if defined(OPENSSL_THREADS) static unsigned g_once_init_called = 0; @@ -130,4 +130,4 @@ TEST(ThreadTest, RandState) { thread.join(); } -#endif // !OPENSSL_NO_THREADS +#endif // OPENSSL_THREADS diff --git a/src/crypto/x509/by_file.c b/src/crypto/x509/by_file.c index 555cb854..dfff425d 100644 --- a/src/crypto/x509/by_file.c +++ b/src/crypto/x509/by_file.c @@ -138,14 +138,15 @@ int X509_load_cert_file(X509_LOOKUP *ctx, const char *file, int type) for (;;) { x = PEM_read_bio_X509_AUX(in, NULL, NULL, NULL); if (x == NULL) { - if ((ERR_GET_REASON(ERR_peek_last_error()) == - PEM_R_NO_START_LINE) && (count > 0)) { + uint32_t error = ERR_peek_last_error(); + if (ERR_GET_LIB(error) == ERR_LIB_PEM && + ERR_GET_REASON(error) == PEM_R_NO_START_LINE && + count > 0) { ERR_clear_error(); break; - } else { - OPENSSL_PUT_ERROR(X509, ERR_R_PEM_LIB); - goto err; } + OPENSSL_PUT_ERROR(X509, ERR_R_PEM_LIB); + goto err; } i = X509_STORE_add_cert(ctx->store_ctx, x); if (!i) @@ -197,14 +198,15 @@ int X509_load_crl_file(X509_LOOKUP *ctx, const char *file, int type) for (;;) { x = PEM_read_bio_X509_CRL(in, NULL, NULL, NULL); if (x == NULL) { - if ((ERR_GET_REASON(ERR_peek_last_error()) == - PEM_R_NO_START_LINE) && (count > 0)) { + uint32_t error = ERR_peek_last_error(); + if (ERR_GET_LIB(error) == ERR_LIB_PEM && + ERR_GET_REASON(error) == PEM_R_NO_START_LINE && + count > 0) { ERR_clear_error(); break; - } else { - OPENSSL_PUT_ERROR(X509, ERR_R_PEM_LIB); - goto err; } + OPENSSL_PUT_ERROR(X509, ERR_R_PEM_LIB); + goto err; } i = X509_STORE_add_crl(ctx->store_ctx, x); if (!i) diff --git a/src/crypto/x509/t_crl.c b/src/crypto/x509/t_crl.c index 6c347cb8..dc9b87f8 100644 --- a/src/crypto/x509/t_crl.c +++ b/src/crypto/x509/t_crl.c @@ -64,17 +64,14 @@ #ifndef OPENSSL_NO_FP_API int X509_CRL_print_fp(FILE *fp, X509_CRL *x) { - BIO *b; - int ret; - - if ((b = BIO_new(BIO_s_file())) == NULL) { + BIO *b = BIO_new_fp(fp, BIO_NOCLOSE); + if (b == NULL) { OPENSSL_PUT_ERROR(X509, ERR_R_BUF_LIB); - return (0); + return 0; } - BIO_set_fp(b, fp, BIO_NOCLOSE); - ret = X509_CRL_print(b, x); + int ret = X509_CRL_print(b, x); BIO_free(b); - return (ret); + return ret; } #endif diff --git a/src/crypto/x509/t_req.c b/src/crypto/x509/t_req.c index 39c836cc..2fd36f8c 100644 --- a/src/crypto/x509/t_req.c +++ b/src/crypto/x509/t_req.c @@ -65,13 +65,11 @@ int X509_REQ_print_fp(FILE *fp, X509_REQ *x) { - BIO *bio = BIO_new(BIO_s_file()); + BIO *bio = BIO_new_fp(fp, BIO_NOCLOSE); if (bio == NULL) { OPENSSL_PUT_ERROR(X509, ERR_R_BUF_LIB); return 0; } - - BIO_set_fp(bio, fp, BIO_NOCLOSE); int ret = X509_REQ_print(bio, x); BIO_free(bio); return ret; diff --git a/src/crypto/x509/t_x509.c b/src/crypto/x509/t_x509.c index 3339523c..e45a7659 100644 --- a/src/crypto/x509/t_x509.c +++ b/src/crypto/x509/t_x509.c @@ -72,17 +72,14 @@ int X509_print_ex_fp(FILE *fp, X509 *x, unsigned long nmflag, unsigned long cflag) { - BIO *b; - int ret; - - if ((b = BIO_new(BIO_s_file())) == NULL) { + BIO *b = BIO_new_fp(fp, BIO_NOCLOSE); + if (b == NULL) { OPENSSL_PUT_ERROR(X509, ERR_R_BUF_LIB); - return (0); + return 0; } - BIO_set_fp(b, fp, BIO_NOCLOSE); - ret = X509_print_ex(b, x, nmflag, cflag); + int ret = X509_print_ex(b, x, nmflag, cflag); BIO_free(b); - return (ret); + return ret; } int X509_print_fp(FILE *fp, X509 *x) diff --git a/src/crypto/x509/x509_test.cc b/src/crypto/x509/x509_test.cc index 9ed1b52a..bf0b29a2 100644 --- a/src/crypto/x509/x509_test.cc +++ b/src/crypto/x509/x509_test.cc @@ -1549,3 +1549,125 @@ TEST(X509Test, MismatchAlgorithms) { EXPECT_EQ(ERR_LIB_X509, ERR_GET_LIB(err)); EXPECT_EQ(X509_R_SIGNATURE_ALGORITHM_MISMATCH, ERR_GET_REASON(err)); } + +TEST(X509Test, PEMX509Info) { + std::string cert = kRootCAPEM; + auto cert_obj = CertFromPEM(kRootCAPEM); + ASSERT_TRUE(cert_obj); + + std::string rsa = kRSAKey; + auto rsa_obj = PrivateKeyFromPEM(kRSAKey); + ASSERT_TRUE(rsa_obj); + + std::string crl = kBasicCRL; + auto crl_obj = CRLFromPEM(kBasicCRL); + ASSERT_TRUE(crl_obj); + + std::string unknown = + "-----BEGIN UNKNOWN-----\n" + "AAAA\n" + "-----END UNKNOWN-----\n"; + + std::string invalid = + "-----BEGIN CERTIFICATE-----\n" + "AAAA\n" + "-----END CERTIFICATE-----\n"; + + // Each X509_INFO contains at most one certificate, CRL, etc. The format + // creates a new X509_INFO when a repeated type is seen. + std::string pem = + // The first few entries have one of everything in different orders. + cert + rsa + crl + + rsa + crl + cert + + // Unknown types are ignored. + crl + unknown + cert + rsa + + // Seeing a new certificate starts a new entry, so now we have a bunch of + // certificate-only entries. + cert + cert + cert + + // The key folds into the certificate's entry. + cert + rsa + + // Doubled keys also start new entries. + rsa + rsa + rsa + rsa + crl + + // As do CRLs. + crl + crl; + + const struct ExpectedInfo { + const X509 *cert; + const EVP_PKEY *key; + const X509_CRL *crl; + } kExpected[] = { + {cert_obj.get(), rsa_obj.get(), crl_obj.get()}, + {cert_obj.get(), rsa_obj.get(), crl_obj.get()}, + {cert_obj.get(), rsa_obj.get(), crl_obj.get()}, + {cert_obj.get(), nullptr, nullptr}, + {cert_obj.get(), nullptr, nullptr}, + {cert_obj.get(), nullptr, nullptr}, + {cert_obj.get(), rsa_obj.get(), nullptr}, + {nullptr, rsa_obj.get(), nullptr}, + {nullptr, rsa_obj.get(), nullptr}, + {nullptr, rsa_obj.get(), nullptr}, + {nullptr, rsa_obj.get(), crl_obj.get()}, + {nullptr, nullptr, crl_obj.get()}, + {nullptr, nullptr, crl_obj.get()}, + }; + + auto check_info = [](const ExpectedInfo *expected, const X509_INFO *info) { + if (expected->cert != nullptr) { + EXPECT_EQ(0, X509_cmp(expected->cert, info->x509)); + } else { + EXPECT_EQ(nullptr, info->x509); + } + if (expected->crl != nullptr) { + EXPECT_EQ(0, X509_CRL_cmp(expected->crl, info->crl)); + } else { + EXPECT_EQ(nullptr, info->crl); + } + if (expected->key != nullptr) { + ASSERT_NE(nullptr, info->x_pkey); + // EVP_PKEY_cmp returns one if the keys are equal. + EXPECT_EQ(1, EVP_PKEY_cmp(expected->key, info->x_pkey->dec_pkey)); + } else { + EXPECT_EQ(nullptr, info->x_pkey); + } + }; + + bssl::UniquePtr bio(BIO_new_mem_buf(pem.data(), pem.size())); + ASSERT_TRUE(bio); + bssl::UniquePtr infos( + PEM_X509_INFO_read_bio(bio.get(), nullptr, nullptr, nullptr)); + ASSERT_TRUE(infos); + ASSERT_EQ(OPENSSL_ARRAY_SIZE(kExpected), sk_X509_INFO_num(infos.get())); + for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kExpected); i++) { + SCOPED_TRACE(i); + check_info(&kExpected[i], sk_X509_INFO_value(infos.get(), i)); + } + + // Passing an existing stack appends to it. + bio.reset(BIO_new_mem_buf(pem.data(), pem.size())); + ASSERT_TRUE(bio); + ASSERT_EQ(infos.get(), + PEM_X509_INFO_read_bio(bio.get(), infos.get(), nullptr, nullptr)); + ASSERT_EQ(2 * OPENSSL_ARRAY_SIZE(kExpected), sk_X509_INFO_num(infos.get())); + for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kExpected); i++) { + SCOPED_TRACE(i); + check_info(&kExpected[i], sk_X509_INFO_value(infos.get(), i)); + check_info( + &kExpected[i], + sk_X509_INFO_value(infos.get(), i + OPENSSL_ARRAY_SIZE(kExpected))); + } + + // Gracefully handle errors in both the append and fresh cases. + std::string bad_pem = cert + cert + invalid; + + bio.reset(BIO_new_mem_buf(bad_pem.data(), bad_pem.size())); + ASSERT_TRUE(bio); + bssl::UniquePtr infos2( + PEM_X509_INFO_read_bio(bio.get(), nullptr, nullptr, nullptr)); + EXPECT_FALSE(infos2); + + bio.reset(BIO_new_mem_buf(bad_pem.data(), bad_pem.size())); + ASSERT_TRUE(bio); + EXPECT_FALSE( + PEM_X509_INFO_read_bio(bio.get(), infos.get(), nullptr, nullptr)); + EXPECT_EQ(2 * OPENSSL_ARRAY_SIZE(kExpected), sk_X509_INFO_num(infos.get())); +} diff --git a/src/crypto/x509/x_all.c b/src/crypto/x509/x_all.c index 064c89c8..a37d7bde 100644 --- a/src/crypto/x509/x_all.c +++ b/src/crypto/x509/x_all.c @@ -54,14 +54,18 @@ * copied and put under another distribution licence * [including the GNU Public Licence.] */ +#include + +#include + #include #include #include #include #include +#include #include #include -#include int X509_verify(X509 *a, EVP_PKEY *r) { @@ -201,154 +205,102 @@ int i2d_X509_REQ_bio(BIO *bp, X509_REQ *req) } #ifndef OPENSSL_NO_FP_API -RSA *d2i_RSAPrivateKey_fp(FILE *fp, RSA **rsa) -{ - return ASN1_d2i_fp_of(RSA, RSA_new, d2i_RSAPrivateKey, fp, rsa); -} - -int i2d_RSAPrivateKey_fp(FILE *fp, RSA *rsa) -{ - return ASN1_i2d_fp_of_const(RSA, i2d_RSAPrivateKey, fp, rsa); -} - -RSA *d2i_RSAPublicKey_fp(FILE *fp, RSA **rsa) -{ - return ASN1_d2i_fp_of(RSA, RSA_new, d2i_RSAPublicKey, fp, rsa); -} -RSA *d2i_RSA_PUBKEY_fp(FILE *fp, RSA **rsa) -{ - return ASN1_d2i_fp((void *(*)(void)) - RSA_new, (D2I_OF(void)) d2i_RSA_PUBKEY, fp, - (void **)rsa); -} - -int i2d_RSAPublicKey_fp(FILE *fp, RSA *rsa) -{ - return ASN1_i2d_fp_of_const(RSA, i2d_RSAPublicKey, fp, rsa); -} - -int i2d_RSA_PUBKEY_fp(FILE *fp, RSA *rsa) -{ - return ASN1_i2d_fp((I2D_OF_const(void))i2d_RSA_PUBKEY, fp, rsa); -} +#define IMPLEMENT_D2I_FP(type, name, bio_func) \ + type *name(FILE *fp, type **obj) { \ + BIO *bio = BIO_new_fp(fp, BIO_NOCLOSE); \ + if (bio == NULL) { \ + return NULL; \ + } \ + type *ret = bio_func(bio, obj); \ + BIO_free(bio); \ + return ret; \ + } + +#define IMPLEMENT_I2D_FP(type, name, bio_func) \ + int name(FILE *fp, type *obj) { \ + BIO *bio = BIO_new_fp(fp, BIO_NOCLOSE); \ + if (bio == NULL) { \ + return 0; \ + } \ + int ret = bio_func(bio, obj); \ + BIO_free(bio); \ + return ret; \ + } + +IMPLEMENT_D2I_FP(RSA, d2i_RSAPrivateKey_fp, d2i_RSAPrivateKey_bio) +IMPLEMENT_I2D_FP(RSA, i2d_RSAPrivateKey_fp, i2d_RSAPrivateKey_bio) + +IMPLEMENT_D2I_FP(RSA, d2i_RSAPublicKey_fp, d2i_RSAPublicKey_bio) +IMPLEMENT_I2D_FP(RSA, i2d_RSAPublicKey_fp, i2d_RSAPublicKey_bio) + +IMPLEMENT_D2I_FP(RSA, d2i_RSA_PUBKEY_fp, d2i_RSA_PUBKEY_bio) +IMPLEMENT_I2D_FP(RSA, i2d_RSA_PUBKEY_fp, i2d_RSA_PUBKEY_bio) #endif -RSA *d2i_RSAPrivateKey_bio(BIO *bp, RSA **rsa) -{ - return ASN1_d2i_bio_of(RSA, RSA_new, d2i_RSAPrivateKey, bp, rsa); -} - -int i2d_RSAPrivateKey_bio(BIO *bp, RSA *rsa) -{ - return ASN1_i2d_bio_of_const(RSA, i2d_RSAPrivateKey, bp, rsa); -} - -RSA *d2i_RSAPublicKey_bio(BIO *bp, RSA **rsa) -{ - return ASN1_d2i_bio_of(RSA, RSA_new, d2i_RSAPublicKey, bp, rsa); -} - -RSA *d2i_RSA_PUBKEY_bio(BIO *bp, RSA **rsa) -{ - return ASN1_d2i_bio_of(RSA, RSA_new, d2i_RSA_PUBKEY, bp, rsa); -} - -int i2d_RSAPublicKey_bio(BIO *bp, RSA *rsa) -{ - return ASN1_i2d_bio_of_const(RSA, i2d_RSAPublicKey, bp, rsa); -} - -int i2d_RSA_PUBKEY_bio(BIO *bp, RSA *rsa) -{ - return ASN1_i2d_bio_of_const(RSA, i2d_RSA_PUBKEY, bp, rsa); -} +#define IMPLEMENT_D2I_BIO(type, name, d2i_func) \ + type *name(BIO *bio, type **obj) { \ + uint8_t *data; \ + size_t len; \ + if (!BIO_read_asn1(bio, &data, &len, 100 * 1024)) { \ + return NULL; \ + } \ + const uint8_t *ptr = data; \ + type *ret = d2i_func(obj, &ptr, (long)len); \ + OPENSSL_free(data); \ + return ret; \ + } + +#define IMPLEMENT_I2D_BIO(type, name, i2d_func) \ + int name(BIO *bio, type *obj) { \ + uint8_t *data = NULL; \ + int len = i2d_func(obj, &data); \ + if (len < 0) { \ + return 0; \ + } \ + int ret = BIO_write_all(bio, data, len); \ + OPENSSL_free(data); \ + return ret; \ + } + +IMPLEMENT_D2I_BIO(RSA, d2i_RSAPrivateKey_bio, d2i_RSAPrivateKey) +IMPLEMENT_I2D_BIO(RSA, i2d_RSAPrivateKey_bio, i2d_RSAPrivateKey) + +IMPLEMENT_D2I_BIO(RSA, d2i_RSAPublicKey_bio, d2i_RSAPublicKey) +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 # ifndef OPENSSL_NO_FP_API -DSA *d2i_DSAPrivateKey_fp(FILE *fp, DSA **dsa) -{ - return ASN1_d2i_fp_of(DSA, DSA_new, d2i_DSAPrivateKey, fp, dsa); -} +IMPLEMENT_D2I_FP(DSA, d2i_DSAPrivateKey_fp, d2i_DSAPrivateKey_bio) +IMPLEMENT_I2D_FP(DSA, i2d_DSAPrivateKey_fp, i2d_DSAPrivateKey_bio) -int i2d_DSAPrivateKey_fp(FILE *fp, DSA *dsa) -{ - return ASN1_i2d_fp_of_const(DSA, i2d_DSAPrivateKey, fp, dsa); -} - -DSA *d2i_DSA_PUBKEY_fp(FILE *fp, DSA **dsa) -{ - return ASN1_d2i_fp_of(DSA, DSA_new, d2i_DSA_PUBKEY, fp, dsa); -} - -int i2d_DSA_PUBKEY_fp(FILE *fp, DSA *dsa) -{ - return ASN1_i2d_fp_of_const(DSA, i2d_DSA_PUBKEY, fp, dsa); -} +IMPLEMENT_D2I_FP(DSA, d2i_DSA_PUBKEY_fp, d2i_DSA_PUBKEY_bio) +IMPLEMENT_I2D_FP(DSA, i2d_DSA_PUBKEY_fp, i2d_DSA_PUBKEY_bio) # endif -DSA *d2i_DSAPrivateKey_bio(BIO *bp, DSA **dsa) -{ - return ASN1_d2i_bio_of(DSA, DSA_new, d2i_DSAPrivateKey, bp, dsa); -} - -int i2d_DSAPrivateKey_bio(BIO *bp, DSA *dsa) -{ - return ASN1_i2d_bio_of_const(DSA, i2d_DSAPrivateKey, bp, dsa); -} - -DSA *d2i_DSA_PUBKEY_bio(BIO *bp, DSA **dsa) -{ - return ASN1_d2i_bio_of(DSA, DSA_new, d2i_DSA_PUBKEY, bp, dsa); -} - -int i2d_DSA_PUBKEY_bio(BIO *bp, DSA *dsa) -{ - return ASN1_i2d_bio_of_const(DSA, i2d_DSA_PUBKEY, bp, dsa); -} +IMPLEMENT_D2I_BIO(DSA, d2i_DSAPrivateKey_bio, d2i_DSAPrivateKey) +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 #ifndef OPENSSL_NO_FP_API -EC_KEY *d2i_EC_PUBKEY_fp(FILE *fp, EC_KEY **eckey) -{ - return ASN1_d2i_fp_of(EC_KEY, EC_KEY_new, d2i_EC_PUBKEY, fp, eckey); -} - -int i2d_EC_PUBKEY_fp(FILE *fp, EC_KEY *eckey) -{ - return ASN1_i2d_fp_of_const(EC_KEY, i2d_EC_PUBKEY, fp, eckey); -} - -EC_KEY *d2i_ECPrivateKey_fp(FILE *fp, EC_KEY **eckey) -{ - return ASN1_d2i_fp_of(EC_KEY, EC_KEY_new, d2i_ECPrivateKey, fp, eckey); -} +IMPLEMENT_D2I_FP(EC_KEY, d2i_ECPrivateKey_fp, d2i_ECPrivateKey_bio) +IMPLEMENT_I2D_FP(EC_KEY, i2d_ECPrivateKey_fp, i2d_ECPrivateKey_bio) -int i2d_ECPrivateKey_fp(FILE *fp, EC_KEY *eckey) -{ - return ASN1_i2d_fp_of_const(EC_KEY, i2d_ECPrivateKey, fp, eckey); -} +IMPLEMENT_D2I_FP(EC_KEY, d2i_EC_PUBKEY_fp, d2i_EC_PUBKEY_bio) +IMPLEMENT_I2D_FP(EC_KEY, i2d_EC_PUBKEY_fp, i2d_EC_PUBKEY_bio) #endif -EC_KEY *d2i_EC_PUBKEY_bio(BIO *bp, EC_KEY **eckey) -{ - return ASN1_d2i_bio_of(EC_KEY, EC_KEY_new, d2i_EC_PUBKEY, bp, eckey); -} - -int i2d_EC_PUBKEY_bio(BIO *bp, EC_KEY *ecdsa) -{ - return ASN1_i2d_bio_of_const(EC_KEY, i2d_EC_PUBKEY, bp, ecdsa); -} -EC_KEY *d2i_ECPrivateKey_bio(BIO *bp, EC_KEY **eckey) -{ - return ASN1_d2i_bio_of(EC_KEY, EC_KEY_new, d2i_ECPrivateKey, bp, eckey); -} +IMPLEMENT_D2I_BIO(EC_KEY, d2i_ECPrivateKey_bio, d2i_ECPrivateKey) +IMPLEMENT_I2D_BIO(EC_KEY, i2d_ECPrivateKey_bio, i2d_ECPrivateKey) -int i2d_ECPrivateKey_bio(BIO *bp, EC_KEY *eckey) -{ - return ASN1_i2d_bio_of_const(EC_KEY, i2d_ECPrivateKey, bp, eckey); -} +IMPLEMENT_D2I_BIO(EC_KEY, d2i_EC_PUBKEY_bio, d2i_EC_PUBKEY) +IMPLEMENT_I2D_BIO(EC_KEY, i2d_EC_PUBKEY_bio, i2d_EC_PUBKEY) int X509_pubkey_digest(const X509 *data, const EVP_MD *type, unsigned char *md, unsigned int *len) @@ -389,40 +341,18 @@ int X509_NAME_digest(const X509_NAME *data, const EVP_MD *type, } #ifndef OPENSSL_NO_FP_API -X509_SIG *d2i_PKCS8_fp(FILE *fp, X509_SIG **p8) -{ - return ASN1_d2i_fp_of(X509_SIG, X509_SIG_new, d2i_X509_SIG, fp, p8); -} - -int i2d_PKCS8_fp(FILE *fp, X509_SIG *p8) -{ - return ASN1_i2d_fp_of(X509_SIG, i2d_X509_SIG, fp, p8); -} +IMPLEMENT_D2I_FP(X509_SIG, d2i_PKCS8_fp, d2i_PKCS8_bio) +IMPLEMENT_I2D_FP(X509_SIG, i2d_PKCS8_fp, i2d_PKCS8_bio) #endif -X509_SIG *d2i_PKCS8_bio(BIO *bp, X509_SIG **p8) -{ - return ASN1_d2i_bio_of(X509_SIG, X509_SIG_new, d2i_X509_SIG, bp, p8); -} - -int i2d_PKCS8_bio(BIO *bp, X509_SIG *p8) -{ - return ASN1_i2d_bio_of(X509_SIG, i2d_X509_SIG, bp, p8); -} +IMPLEMENT_D2I_BIO(X509_SIG, d2i_PKCS8_bio, d2i_X509_SIG) +IMPLEMENT_I2D_BIO(X509_SIG, i2d_PKCS8_bio, i2d_X509_SIG) #ifndef OPENSSL_NO_FP_API -PKCS8_PRIV_KEY_INFO *d2i_PKCS8_PRIV_KEY_INFO_fp(FILE *fp, - PKCS8_PRIV_KEY_INFO **p8inf) -{ - return ASN1_d2i_fp_of(PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_new, - d2i_PKCS8_PRIV_KEY_INFO, fp, p8inf); -} - -int i2d_PKCS8_PRIV_KEY_INFO_fp(FILE *fp, PKCS8_PRIV_KEY_INFO *p8inf) -{ - return ASN1_i2d_fp_of(PKCS8_PRIV_KEY_INFO, i2d_PKCS8_PRIV_KEY_INFO, fp, - p8inf); -} +IMPLEMENT_D2I_FP(PKCS8_PRIV_KEY_INFO, d2i_PKCS8_PRIV_KEY_INFO_fp, + d2i_PKCS8_PRIV_KEY_INFO_bio) +IMPLEMENT_I2D_FP(PKCS8_PRIV_KEY_INFO, i2d_PKCS8_PRIV_KEY_INFO_fp, + i2d_PKCS8_PRIV_KEY_INFO_bio) int i2d_PKCS8PrivateKeyInfo_fp(FILE *fp, EVP_PKEY *key) { @@ -436,38 +366,16 @@ int i2d_PKCS8PrivateKeyInfo_fp(FILE *fp, EVP_PKEY *key) return ret; } -int i2d_PrivateKey_fp(FILE *fp, EVP_PKEY *pkey) -{ - return ASN1_i2d_fp_of_const(EVP_PKEY, i2d_PrivateKey, fp, pkey); -} - -EVP_PKEY *d2i_PrivateKey_fp(FILE *fp, EVP_PKEY **a) -{ - return ASN1_d2i_fp_of(EVP_PKEY, EVP_PKEY_new, d2i_AutoPrivateKey, fp, a); -} +IMPLEMENT_D2I_FP(EVP_PKEY, d2i_PrivateKey_fp, d2i_PrivateKey_bio) +IMPLEMENT_I2D_FP(EVP_PKEY, i2d_PrivateKey_fp, i2d_PrivateKey_bio) -int i2d_PUBKEY_fp(FILE *fp, EVP_PKEY *pkey) -{ - return ASN1_i2d_fp_of_const(EVP_PKEY, i2d_PUBKEY, fp, pkey); -} +IMPLEMENT_D2I_FP(EVP_PKEY, d2i_PUBKEY_fp, d2i_PUBKEY_bio) +IMPLEMENT_I2D_FP(EVP_PKEY, i2d_PUBKEY_fp, i2d_PUBKEY_bio) -EVP_PKEY *d2i_PUBKEY_fp(FILE *fp, EVP_PKEY **a) -{ - return ASN1_d2i_fp_of(EVP_PKEY, EVP_PKEY_new, d2i_PUBKEY, fp, a); -} - -PKCS8_PRIV_KEY_INFO *d2i_PKCS8_PRIV_KEY_INFO_bio(BIO *bp, - PKCS8_PRIV_KEY_INFO **p8inf) -{ - return ASN1_d2i_bio_of(PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_new, - d2i_PKCS8_PRIV_KEY_INFO, bp, p8inf); -} - -int i2d_PKCS8_PRIV_KEY_INFO_bio(BIO *bp, PKCS8_PRIV_KEY_INFO *p8inf) -{ - return ASN1_i2d_bio_of(PKCS8_PRIV_KEY_INFO, i2d_PKCS8_PRIV_KEY_INFO, bp, - p8inf); -} +IMPLEMENT_D2I_BIO(PKCS8_PRIV_KEY_INFO, d2i_PKCS8_PRIV_KEY_INFO_bio, + d2i_PKCS8_PRIV_KEY_INFO) +IMPLEMENT_I2D_BIO(PKCS8_PRIV_KEY_INFO, i2d_PKCS8_PRIV_KEY_INFO_bio, + i2d_PKCS8_PRIV_KEY_INFO) int i2d_PKCS8PrivateKeyInfo_bio(BIO *bp, EVP_PKEY *key) { @@ -482,32 +390,11 @@ int i2d_PKCS8PrivateKeyInfo_bio(BIO *bp, EVP_PKEY *key) } #endif -int i2d_PrivateKey_bio(BIO *bp, EVP_PKEY *pkey) -{ - return ASN1_i2d_bio_of_const(EVP_PKEY, i2d_PrivateKey, bp, pkey); -} - -EVP_PKEY *d2i_PrivateKey_bio(BIO *bp, EVP_PKEY **a) -{ - return ASN1_d2i_bio_of(EVP_PKEY, EVP_PKEY_new, d2i_AutoPrivateKey, bp, a); -} +IMPLEMENT_D2I_BIO(EVP_PKEY, d2i_PrivateKey_bio, d2i_AutoPrivateKey) +IMPLEMENT_I2D_BIO(EVP_PKEY, i2d_PrivateKey_bio, i2d_PrivateKey) -int i2d_PUBKEY_bio(BIO *bp, EVP_PKEY *pkey) -{ - return ASN1_i2d_bio_of_const(EVP_PKEY, i2d_PUBKEY, bp, pkey); -} +IMPLEMENT_D2I_BIO(EVP_PKEY, d2i_PUBKEY_bio, d2i_PUBKEY) +IMPLEMENT_I2D_BIO(EVP_PKEY, i2d_PUBKEY_bio, i2d_PUBKEY) -EVP_PKEY *d2i_PUBKEY_bio(BIO *bp, EVP_PKEY **a) -{ - return ASN1_d2i_bio_of(EVP_PKEY, EVP_PKEY_new, d2i_PUBKEY, bp, a); -} - -DH *d2i_DHparams_bio(BIO *bp, DH **dh) -{ - return ASN1_d2i_bio_of(DH, DH_new, d2i_DHparams, bp, dh); -} - -int i2d_DHparams_bio(BIO *bp, const DH *dh) -{ - return ASN1_i2d_bio_of_const(DH, i2d_DHparams, bp, dh); -} +IMPLEMENT_D2I_BIO(DH, d2i_DHparams_bio, d2i_DHparams) +IMPLEMENT_I2D_BIO(const DH, i2d_DHparams_bio, i2d_DHparams) diff --git a/src/crypto/x509v3/v3_genn.c b/src/crypto/x509v3/v3_genn.c index 8c926879..552a5244 100644 --- a/src/crypto/x509v3/v3_genn.c +++ b/src/crypto/x509v3/v3_genn.c @@ -100,12 +100,7 @@ ASN1_ITEM_TEMPLATE_END(GENERAL_NAMES) IMPLEMENT_ASN1_FUNCTIONS(GENERAL_NAMES) -GENERAL_NAME *GENERAL_NAME_dup(GENERAL_NAME *a) -{ - return (GENERAL_NAME *)ASN1_dup((i2d_of_void *)i2d_GENERAL_NAME, - (d2i_of_void *)d2i_GENERAL_NAME, - (char *)a); -} +IMPLEMENT_ASN1_DUP_FUNCTION(GENERAL_NAME) /* Returns 0 if they are equal, != 0 otherwise. */ int GENERAL_NAME_cmp(GENERAL_NAME *a, GENERAL_NAME *b) diff --git a/src/decrepit/x509/x509_decrepit.c b/src/decrepit/x509/x509_decrepit.c index 5714b40a..28015f32 100644 --- a/src/decrepit/x509/x509_decrepit.c +++ b/src/decrepit/x509/x509_decrepit.c @@ -16,27 +16,7 @@ #include -X509_EXTENSION *X509V3_EXT_conf_nid(LHASH_OF(CONF_VALUE) *conf, - X509V3_CTX *ctx, int ext_nid, char *value) { - CONF *nconf = NULL; - LHASH_OF(CONF_VALUE) *orig_data = NULL; - - if (conf != NULL) { - nconf = NCONF_new(NULL /* no method */); - if (nconf == NULL) { - return NULL; - } - - orig_data = nconf->data; - nconf->data = conf; - } - - X509_EXTENSION *ret = X509V3_EXT_nconf_nid(nconf, ctx, ext_nid, value); - - if (nconf != NULL) { - nconf->data = orig_data; - NCONF_free(nconf); - } - - return ret; +X509_EXTENSION *X509V3_EXT_conf_nid(X509_MUST_BE_NULL *conf, X509V3_CTX *ctx, + int ext_nid, char *value) { + return X509V3_EXT_nconf_nid(NULL, ctx, ext_nid, value); } diff --git a/src/decrepit/xts/xts.c b/src/decrepit/xts/xts.c index e3189e59..bc2a1b23 100644 --- a/src/decrepit/xts/xts.c +++ b/src/decrepit/xts/xts.c @@ -57,7 +57,7 @@ typedef struct xts128_context { - void *key1, *key2; + AES_KEY *key1, *key2; block128_f block1, block2; } XTS128_CONTEXT; @@ -186,20 +186,20 @@ static int aes_xts_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key, // key_len is two AES keys if (enc) { AES_set_encrypt_key(key, ctx->key_len * 4, &xctx->ks1.ks); - xctx->xts.block1 = (block128_f) AES_encrypt; + xctx->xts.block1 = AES_encrypt; } else { AES_set_decrypt_key(key, ctx->key_len * 4, &xctx->ks1.ks); - xctx->xts.block1 = (block128_f) AES_decrypt; + xctx->xts.block1 = AES_decrypt; } AES_set_encrypt_key(key + ctx->key_len / 2, ctx->key_len * 4, &xctx->ks2.ks); - xctx->xts.block2 = (block128_f) AES_encrypt; - xctx->xts.key1 = &xctx->ks1; + xctx->xts.block2 = AES_encrypt; + xctx->xts.key1 = &xctx->ks1.ks; } if (iv) { - xctx->xts.key2 = &xctx->ks2; + xctx->xts.key2 = &xctx->ks2.ks; OPENSSL_memcpy(ctx->iv, iv, 16); } @@ -226,16 +226,16 @@ static int aes_xts_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr) { EVP_CIPHER_CTX *out = ptr; EVP_AES_XTS_CTX *xctx_out = out->cipher_data; if (xctx->xts.key1) { - if (xctx->xts.key1 != &xctx->ks1) { + if (xctx->xts.key1 != &xctx->ks1.ks) { return 0; } - xctx_out->xts.key1 = &xctx_out->ks1; + xctx_out->xts.key1 = &xctx_out->ks1.ks; } if (xctx->xts.key2) { - if (xctx->xts.key2 != &xctx->ks2) { + if (xctx->xts.key2 != &xctx->ks2.ks) { return 0; } - xctx_out->xts.key2 = &xctx_out->ks2; + xctx_out->xts.key2 = &xctx_out->ks2.ks; } return 1; } else if (type != EVP_CTRL_INIT) { diff --git a/src/include/openssl/asn1.h b/src/include/openssl/asn1.h index 46e5f537..8b61eaa3 100644 --- a/src/include/openssl/asn1.h +++ b/src/include/openssl/asn1.h @@ -298,19 +298,6 @@ typedef struct ASN1_VALUE_st ASN1_VALUE; OPENSSL_EXPORT int fname##_print_ctx(BIO *out, stname *x, int indent, \ const ASN1_PCTX *pctx); -#define D2I_OF(type) type *(*)(type **,const unsigned char **,long) -#define I2D_OF(type) int (*)(type *,unsigned char **) -#define I2D_OF_const(type) int (*)(const type *,unsigned char **) - -#define CHECKED_D2I_OF(type, d2i) \ - ((d2i_of_void*) (1 ? d2i : ((D2I_OF(type))0))) -#define CHECKED_I2D_OF(type, i2d) \ - ((i2d_of_void*) (1 ? i2d : ((I2D_OF(type))0))) -#define CHECKED_NEW_OF(type, xnew) \ - ((void *(*)(void)) (1 ? xnew : ((type *(*)(void))0))) -#define CHECKED_PPTR_OF(type, p) \ - ((void**) (1 ? p : (type**)0)) - typedef void *d2i_of_void(void **, const unsigned char **, long); typedef int i2d_of_void(const void *, unsigned char **); @@ -762,76 +749,17 @@ OPENSSL_EXPORT void ASN1_put_object(unsigned char **pp, int constructed, int len OPENSSL_EXPORT int ASN1_put_eoc(unsigned char **pp); OPENSSL_EXPORT int ASN1_object_size(int constructed, int length, int tag); -/* Used to implement other functions */ -OPENSSL_EXPORT void *ASN1_dup(i2d_of_void *i2d, d2i_of_void *d2i, void *x); - -#define ASN1_dup_of(type,i2d,d2i,x) \ - ((type*)ASN1_dup(CHECKED_I2D_OF(type, i2d), \ - CHECKED_D2I_OF(type, d2i), \ - CHECKED_PTR_OF(type, x))) - -#define ASN1_dup_of_const(type,i2d,d2i,x) \ - ((type*)ASN1_dup(CHECKED_I2D_OF(const type, i2d), \ - CHECKED_D2I_OF(type, d2i), \ - CHECKED_PTR_OF(const type, x))) - OPENSSL_EXPORT void *ASN1_item_dup(const ASN1_ITEM *it, void *x); -/* ASN1 alloc/free macros for when a type is only used internally */ - -#define M_ASN1_new_of(type) (type *)ASN1_item_new(ASN1_ITEM_rptr(type)) -#define M_ASN1_free_of(x, type) \ - ASN1_item_free(CHECKED_PTR_OF(type, x), ASN1_ITEM_rptr(type)) - #ifndef OPENSSL_NO_FP_API -OPENSSL_EXPORT void *ASN1_d2i_fp(void *(*xnew)(void), d2i_of_void *d2i, FILE *in, void **x); - -#define ASN1_d2i_fp_of(type,xnew,d2i,in,x) \ - ((type*)ASN1_d2i_fp(CHECKED_NEW_OF(type, xnew), \ - CHECKED_D2I_OF(type, d2i), \ - in, \ - CHECKED_PPTR_OF(type, x))) - OPENSSL_EXPORT void *ASN1_item_d2i_fp(const ASN1_ITEM *it, FILE *in, void *x); -OPENSSL_EXPORT int ASN1_i2d_fp(i2d_of_void *i2d,FILE *out,void *x); - -#define ASN1_i2d_fp_of(type,i2d,out,x) \ - (ASN1_i2d_fp(CHECKED_I2D_OF(type, i2d), \ - out, \ - CHECKED_PTR_OF(type, x))) - -#define ASN1_i2d_fp_of_const(type,i2d,out,x) \ - (ASN1_i2d_fp(CHECKED_I2D_OF(const type, i2d), \ - out, \ - CHECKED_PTR_OF(const type, x))) - OPENSSL_EXPORT int ASN1_item_i2d_fp(const ASN1_ITEM *it, FILE *out, void *x); OPENSSL_EXPORT int ASN1_STRING_print_ex_fp(FILE *fp, ASN1_STRING *str, unsigned long flags); #endif OPENSSL_EXPORT int ASN1_STRING_to_UTF8(unsigned char **out, ASN1_STRING *in); -OPENSSL_EXPORT void *ASN1_d2i_bio(void *(*xnew)(void), d2i_of_void *d2i, BIO *in, void **x); - -#define ASN1_d2i_bio_of(type,xnew,d2i,in,x) \ - ((type*)ASN1_d2i_bio( CHECKED_NEW_OF(type, xnew), \ - CHECKED_D2I_OF(type, d2i), \ - in, \ - CHECKED_PPTR_OF(type, x))) - OPENSSL_EXPORT void *ASN1_item_d2i_bio(const ASN1_ITEM *it, BIO *in, void *x); -OPENSSL_EXPORT int ASN1_i2d_bio(i2d_of_void *i2d,BIO *out, void *x); - -#define ASN1_i2d_bio_of(type,i2d,out,x) \ - (ASN1_i2d_bio(CHECKED_I2D_OF(type, i2d), \ - out, \ - CHECKED_PTR_OF(type, x))) - -#define ASN1_i2d_bio_of_const(type,i2d,out,x) \ - (ASN1_i2d_bio(CHECKED_I2D_OF(const type, i2d), \ - out, \ - CHECKED_PTR_OF(const type, x))) - OPENSSL_EXPORT int ASN1_item_i2d_bio(const ASN1_ITEM *it, BIO *out, void *x); OPENSSL_EXPORT int ASN1_UTCTIME_print(BIO *fp, const ASN1_UTCTIME *a); OPENSSL_EXPORT int ASN1_GENERALIZEDTIME_print(BIO *fp, const ASN1_GENERALIZEDTIME *a); diff --git a/src/include/openssl/base.h b/src/include/openssl/base.h index d1349934..5a4bb667 100644 --- a/src/include/openssl/base.h +++ b/src/include/openssl/base.h @@ -65,6 +65,10 @@ #include #endif +#if defined(__APPLE__) +#include +#endif + // Include a BoringSSL-only header so consumers including this header without // setting up include paths do not accidentally pick up the system // opensslconf.h. @@ -120,6 +124,9 @@ extern "C" { #if defined(__APPLE__) #define OPENSSL_APPLE +#if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE +#define OPENSSL_IOS +#endif #endif #if defined(_WIN32) @@ -136,14 +143,36 @@ extern "C" { #if defined(TRUSTY) #define OPENSSL_TRUSTY -#define OPENSSL_NO_THREADS +#define OPENSSL_NO_THREADS_CORRUPT_MEMORY_AND_LEAK_SECRETS_IF_THREADED #endif #if defined(__ANDROID_API__) #define OPENSSL_ANDROID #endif -#if !defined(OPENSSL_NO_THREADS) +// OPENSSL_NO_THREADS has been deprecated in favor of this much longer and +// louder name, to better reflect exactly what that option did. +// +// TODO(davidben): Remove this block when callers have migrated. +#if defined(OPENSSL_NO_THREADS) && \ + !defined(OPENSSL_NO_THREADS_CORRUPT_MEMORY_AND_LEAK_SECRETS_IF_THREADED) +#define OPENSSL_NO_THREADS_CORRUPT_MEMORY_AND_LEAK_SECRETS_IF_THREADED +#endif + +// BoringSSL requires platform's locking APIs to make internal global state +// thread-safe, including the PRNG. On some single-threaded embedded platforms, +// locking APIs may not exist, so this dependency may be disabled with the +// following build flag. +// +// IMPORTANT: Doing so means the consumer promises the library will never be +// used in any multi-threaded context. It causes BoringSSL to be globally +// thread-unsafe. Setting it inappropriately will subtly and unpredictably +// corrupt memory and leak secret keys. +// +// Do not set this flag on any platform where threads are possible. BoringSSL +// maintainers will not provide support for any consumers that do so. Changes +// which break such unsupported configurations will not be reverted. +#if !defined(OPENSSL_NO_THREADS_CORRUPT_MEMORY_AND_LEAK_SECRETS_IF_THREADED) #define OPENSSL_THREADS #endif @@ -217,6 +246,35 @@ extern "C" { #define OPENSSL_UNUSED #endif +// C and C++ handle inline functions differently. In C++, an inline function is +// defined in just the header file, potentially emitted in multiple compilation +// units (in cases the compiler did not inline), but each copy must be identical +// to satsify ODR. In C, a non-static inline must be manually emitted in exactly +// one compilation unit with a separate extern inline declaration. +// +// In both languages, exported inline functions referencing file-local symbols +// are problematic. C forbids this altogether (though GCC and Clang seem not to +// enforce it). It works in C++, but ODR requires the definitions be identical, +// including all names in the definitions resolving to the "same entity". In +// practice, this is unlikely to be a problem, but an inline function that +// returns a pointer to a file-local symbol +// could compile oddly. +// +// Historically, we used static inline in headers. However, to satisfy ODR, use +// plain inline in C++, to allow inline consumer functions to call our header +// functions. Plain inline would also work better with C99 inline, but that is +// not used much in practice, extern inline is tedious, and there are conflicts +// with the old gnu89 model: +// https://stackoverflow.com/questions/216510/extern-inline +#if defined(__cplusplus) +#define OPENSSL_INLINE inline +#else +// Add OPENSSL_UNUSED so that, should an inline function be emitted via macro +// (e.g. a |STACK_OF(T)| implementation) in a source file without tripping +// clang's -Wunused-function. +#define OPENSSL_INLINE static inline OPENSSL_UNUSED +#endif + #if defined(BORINGSSL_UNSAFE_FUZZER_MODE) && \ !defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE) #define BORINGSSL_UNSAFE_DETERMINISTIC_MODE @@ -477,16 +535,16 @@ class StackAllocated { template using UniquePtr = std::unique_ptr>; -#define BORINGSSL_MAKE_UP_REF(type, up_ref_func) \ - static inline UniquePtr UpRef(type *v) { \ - if (v != nullptr) { \ - up_ref_func(v); \ - } \ - return UniquePtr(v); \ - } \ - \ - static inline UniquePtr UpRef(const UniquePtr &ptr) { \ - return UpRef(ptr.get()); \ +#define BORINGSSL_MAKE_UP_REF(type, up_ref_func) \ + inline UniquePtr UpRef(type *v) { \ + if (v != nullptr) { \ + up_ref_func(v); \ + } \ + return UniquePtr(v); \ + } \ + \ + inline UniquePtr UpRef(const UniquePtr &ptr) { \ + return UpRef(ptr.get()); \ } BSSL_NAMESPACE_END diff --git a/src/include/openssl/bio.h b/src/include/openssl/bio.h index 70c2fbf7..8e2db65f 100644 --- a/src/include/openssl/bio.h +++ b/src/include/openssl/bio.h @@ -117,10 +117,14 @@ OPENSSL_EXPORT int BIO_read(BIO *bio, void *data, int len); // return a line for this call, remove the warning above. OPENSSL_EXPORT int BIO_gets(BIO *bio, char *buf, int size); -// BIO_write writes |len| bytes from |data| to BIO. It returns the number of +// BIO_write writes |len| bytes from |data| to |bio|. It returns the number of // bytes written or a negative number on error. OPENSSL_EXPORT int BIO_write(BIO *bio, const void *data, int len); +// BIO_write_all writes |len| bytes from |data| to |bio|, looping as necessary. +// It returns one if all bytes were successfully written and zero on error. +OPENSSL_EXPORT int BIO_write_all(BIO *bio, const void *data, size_t len); + // BIO_puts writes a NUL terminated string from |buf| to |bio|. It returns the // number of bytes written or a negative number on error. OPENSSL_EXPORT int BIO_puts(BIO *bio, const char *buf); diff --git a/src/include/openssl/conf.h b/src/include/openssl/conf.h index 07e34eec..7aa76e13 100644 --- a/src/include/openssl/conf.h +++ b/src/include/openssl/conf.h @@ -60,7 +60,6 @@ #include #include -#include #if defined(__cplusplus) extern "C" { @@ -85,10 +84,6 @@ struct conf_value_st { char *value; }; -struct conf_st { - LHASH_OF(CONF_VALUE) *data; -}; - DEFINE_STACK_OF(CONF_VALUE) diff --git a/src/include/openssl/cpu.h b/src/include/openssl/cpu.h index bb847f96..b2759fed 100644 --- a/src/include/openssl/cpu.h +++ b/src/include/openssl/cpu.h @@ -96,7 +96,7 @@ extern uint32_t OPENSSL_ia32cap_P[4]; #if defined(BORINGSSL_FIPS) const uint32_t *OPENSSL_ia32cap_get(void); #else -static inline const uint32_t *OPENSSL_ia32cap_get(void) { +OPENSSL_INLINE const uint32_t *OPENSSL_ia32cap_get(void) { return OPENSSL_ia32cap_P; } #endif @@ -119,7 +119,7 @@ OPENSSL_EXPORT char CRYPTO_is_NEON_capable_at_runtime(void); // CRYPTO_is_NEON_capable returns true if the current CPU has a NEON unit. If // this is known statically then it returns one immediately. -static inline int CRYPTO_is_NEON_capable(void) { +OPENSSL_INLINE int CRYPTO_is_NEON_capable(void) { // Only statically skip the runtime lookup on aarch64. On arm, one CPU is // known to have a broken NEON unit which is known to fail with on some // hand-written NEON assembly. For now, continue to apply the workaround even @@ -152,7 +152,7 @@ int CRYPTO_is_ARMv8_PMULL_capable(void); #else -static inline int CRYPTO_is_NEON_capable(void) { +OPENSSL_INLINE int CRYPTO_is_NEON_capable(void) { #if defined(OPENSSL_STATIC_ARMCAP_NEON) || defined(__ARM_NEON__) return 1; #else @@ -160,7 +160,7 @@ static inline int CRYPTO_is_NEON_capable(void) { #endif } -static inline int CRYPTO_is_ARMv8_AES_capable(void) { +OPENSSL_INLINE int CRYPTO_is_ARMv8_AES_capable(void) { #if defined(OPENSSL_STATIC_ARMCAP_AES) || defined(__ARM_FEATURE_CRYPTO) return 1; #else @@ -168,7 +168,7 @@ static inline int CRYPTO_is_ARMv8_AES_capable(void) { #endif } -static inline int CRYPTO_is_ARMv8_PMULL_capable(void) { +OPENSSL_INLINE int CRYPTO_is_ARMv8_PMULL_capable(void) { #if defined(OPENSSL_STATIC_ARMCAP_PMULL) || defined(__ARM_FEATURE_CRYPTO) return 1; #else diff --git a/src/include/openssl/pem.h b/src/include/openssl/pem.h index a43ca0de..9c0ff93c 100644 --- a/src/include/openssl/pem.h +++ b/src/include/openssl/pem.h @@ -123,73 +123,109 @@ extern "C" { #else -#define IMPLEMENT_PEM_read_fp(name, type, str, asn1) \ -OPENSSL_EXPORT type *PEM_read_##name(FILE *fp, type **x, pem_password_cb *cb, void *u)\ -{ \ -return (type *)PEM_ASN1_read((d2i_of_void *)d2i_##asn1, str,fp,(void **)x,cb,u); \ -} - -#define IMPLEMENT_PEM_write_fp(name, type, str, asn1) \ -OPENSSL_EXPORT int PEM_write_##name(FILE *fp, type *x) \ -{ \ -return PEM_ASN1_write((i2d_of_void *)i2d_##asn1,str,fp,x,NULL,NULL,0,NULL,NULL); \ -} - -#define IMPLEMENT_PEM_write_fp_const(name, type, str, asn1) \ -OPENSSL_EXPORT int PEM_write_##name(FILE *fp, const type *x) \ -{ \ -return PEM_ASN1_write((i2d_of_void *)i2d_##asn1,str,fp,(void *)x,NULL,NULL,0,NULL,NULL); \ -} - -#define IMPLEMENT_PEM_write_cb_fp(name, type, str, asn1) \ -OPENSSL_EXPORT int PEM_write_##name(FILE *fp, type *x, const EVP_CIPHER *enc, \ - unsigned char *kstr, int klen, pem_password_cb *cb, \ - void *u) \ - { \ - return PEM_ASN1_write((i2d_of_void *)i2d_##asn1,str,fp,x,enc,kstr,klen,cb,u); \ - } - -#define IMPLEMENT_PEM_write_cb_fp_const(name, type, str, asn1) \ -OPENSSL_EXPORT int PEM_write_##name(FILE *fp, type *x, const EVP_CIPHER *enc, \ - unsigned char *kstr, int klen, pem_password_cb *cb, \ - void *u) \ - { \ - return PEM_ASN1_write((i2d_of_void *)i2d_##asn1,str,fp,x,enc,kstr,klen,cb,u); \ - } +#define IMPLEMENT_PEM_read_fp(name, type, str, asn1) \ + static void *pem_read_##name##_d2i(void **x, const unsigned char **inp, \ + long len) { \ + return d2i_##asn1((type **)x, inp, len); \ + } \ + OPENSSL_EXPORT type *PEM_read_##name(FILE *fp, type **x, \ + pem_password_cb *cb, void *u) { \ + return (type *)PEM_ASN1_read(pem_read_##name##_d2i, str, fp, (void **)x, \ + cb, u); \ + } + +#define IMPLEMENT_PEM_write_fp(name, type, str, asn1) \ + static int pem_write_##name##_i2d(const void *x, unsigned char **outp) { \ + return i2d_##asn1((type *)x, outp); \ + } \ + OPENSSL_EXPORT int PEM_write_##name(FILE *fp, type *x) { \ + return PEM_ASN1_write(pem_write_##name##_i2d, str, fp, x, NULL, NULL, 0, \ + NULL, NULL); \ + } + +#define IMPLEMENT_PEM_write_fp_const(name, type, str, asn1) \ + static int pem_write_##name##_i2d(const void *x, unsigned char **outp) { \ + return i2d_##asn1((const type *)x, outp); \ + } \ + OPENSSL_EXPORT int PEM_write_##name(FILE *fp, const type *x) { \ + return PEM_ASN1_write(pem_write_##name##_i2d, str, fp, (void *)x, NULL, \ + NULL, 0, NULL, NULL); \ + } + +#define IMPLEMENT_PEM_write_cb_fp(name, type, str, asn1) \ + static int pem_write_##name##_i2d(const void *x, unsigned char **outp) { \ + return i2d_##asn1((type *)x, outp); \ + } \ + OPENSSL_EXPORT int PEM_write_##name( \ + FILE *fp, type *x, const EVP_CIPHER *enc, unsigned char *kstr, int klen, \ + pem_password_cb *cb, void *u) { \ + return PEM_ASN1_write(pem_write_##name##_i2d, str, fp, x, enc, kstr, klen, \ + cb, u); \ + } + +#define IMPLEMENT_PEM_write_cb_fp_const(name, type, str, asn1) \ + static int pem_write_##name##_i2d(const void *x, unsigned char **outp) { \ + return i2d_##asn1((const type *)x, outp); \ + } \ + OPENSSL_EXPORT int PEM_write_##name( \ + FILE *fp, type *x, const EVP_CIPHER *enc, unsigned char *kstr, int klen, \ + pem_password_cb *cb, void *u) { \ + return PEM_ASN1_write(pem_write_##name##_i2d, str, fp, x, enc, kstr, klen, \ + cb, u); \ + } #endif -#define IMPLEMENT_PEM_read_bio(name, type, str, asn1) \ -OPENSSL_EXPORT type *PEM_read_bio_##name(BIO *bp, type **x, pem_password_cb *cb, void *u)\ -{ \ -return (type *)PEM_ASN1_read_bio((d2i_of_void *)d2i_##asn1, str,bp,(void **)x,cb,u); \ -} - -#define IMPLEMENT_PEM_write_bio(name, type, str, asn1) \ -OPENSSL_EXPORT int PEM_write_bio_##name(BIO *bp, type *x) \ -{ \ -return PEM_ASN1_write_bio((i2d_of_void *)i2d_##asn1,str,bp,x,NULL,NULL,0,NULL,NULL); \ -} - -#define IMPLEMENT_PEM_write_bio_const(name, type, str, asn1) \ -OPENSSL_EXPORT int PEM_write_bio_##name(BIO *bp, const type *x) \ -{ \ -return PEM_ASN1_write_bio((i2d_of_void *)i2d_##asn1,str,bp,(void *)x,NULL,NULL,0,NULL,NULL); \ -} - -#define IMPLEMENT_PEM_write_cb_bio(name, type, str, asn1) \ -OPENSSL_EXPORT int PEM_write_bio_##name(BIO *bp, type *x, const EVP_CIPHER *enc, \ - unsigned char *kstr, int klen, pem_password_cb *cb, void *u) \ - { \ - return PEM_ASN1_write_bio((i2d_of_void *)i2d_##asn1,str,bp,x,enc,kstr,klen,cb,u); \ - } - -#define IMPLEMENT_PEM_write_cb_bio_const(name, type, str, asn1) \ -OPENSSL_EXPORT int PEM_write_bio_##name(BIO *bp, type *x, const EVP_CIPHER *enc, \ - unsigned char *kstr, int klen, pem_password_cb *cb, void *u) \ - { \ - return PEM_ASN1_write_bio((i2d_of_void *)i2d_##asn1,str,bp,(void *)x,enc,kstr,klen,cb,u); \ - } +#define IMPLEMENT_PEM_read_bio(name, type, str, asn1) \ + static void *pem_read_bio_##name##_d2i(void **x, const unsigned char **inp, \ + long len) { \ + return d2i_##asn1((type **)x, inp, len); \ + } \ + OPENSSL_EXPORT type *PEM_read_bio_##name(BIO *bp, type **x, \ + pem_password_cb *cb, void *u) { \ + return (type *)PEM_ASN1_read_bio(pem_read_bio_##name##_d2i, str, bp, \ + (void **)x, cb, u); \ + } + +#define IMPLEMENT_PEM_write_bio(name, type, str, asn1) \ + static int pem_write_bio_##name##_i2d(const void *x, unsigned char **outp) { \ + return i2d_##asn1((type *)x, outp); \ + } \ + OPENSSL_EXPORT int PEM_write_bio_##name(BIO *bp, type *x) { \ + return PEM_ASN1_write_bio(pem_write_bio_##name##_i2d, str, bp, x, NULL, \ + NULL, 0, NULL, NULL); \ + } + +#define IMPLEMENT_PEM_write_bio_const(name, type, str, asn1) \ + static int pem_write_bio_##name##_i2d(const void *x, unsigned char **outp) { \ + return i2d_##asn1((const type *)x, outp); \ + } \ + OPENSSL_EXPORT int PEM_write_bio_##name(BIO *bp, const type *x) { \ + return PEM_ASN1_write_bio(pem_write_bio_##name##_i2d, str, bp, (void *)x, \ + NULL, NULL, 0, NULL, NULL); \ + } + +#define IMPLEMENT_PEM_write_cb_bio(name, type, str, asn1) \ + static int pem_write_bio_##name##_i2d(const void *x, unsigned char **outp) { \ + return i2d_##asn1((type *)x, outp); \ + } \ + OPENSSL_EXPORT int PEM_write_bio_##name( \ + BIO *bp, type *x, const EVP_CIPHER *enc, unsigned char *kstr, int klen, \ + pem_password_cb *cb, void *u) { \ + return PEM_ASN1_write_bio(pem_write_bio_##name##_i2d, str, bp, x, enc, \ + kstr, klen, cb, u); \ + } + +#define IMPLEMENT_PEM_write_cb_bio_const(name, type, str, asn1) \ + static int pem_write_bio_##name##_i2d(const void *x, unsigned char **outp) { \ + return i2d_##asn1((const type *)x, outp); \ + } \ + OPENSSL_EXPORT int PEM_write_bio_##name( \ + BIO *bp, type *x, const EVP_CIPHER *enc, unsigned char *kstr, int klen, \ + pem_password_cb *cb, void *u) { \ + return PEM_ASN1_write_bio(pem_write_bio_##name##_i2d, str, bp, (void *)x, \ + enc, kstr, klen, cb, u); \ + } #define IMPLEMENT_PEM_write(name, type, str, asn1) \ IMPLEMENT_PEM_write_bio(name, type, str, asn1) \ diff --git a/src/include/openssl/ssl.h b/src/include/openssl/ssl.h index 0d5a444d..c0d44ce2 100644 --- a/src/include/openssl/ssl.h +++ b/src/include/openssl/ssl.h @@ -3004,7 +3004,7 @@ OPENSSL_EXPORT const char *SSL_get_psk_identity_hint(const SSL *ssl); OPENSSL_EXPORT const char *SSL_get_psk_identity(const SSL *ssl); -// QUIC Transport Parameters. +// QUIC transport parameters. // // draft-ietf-quic-tls defines a new TLS extension quic_transport_parameters // used by QUIC for each endpoint to unilaterally declare its supported @@ -3667,6 +3667,10 @@ OPENSSL_EXPORT void SSL_CTX_set_false_start_allowed_without_alpn(SSL_CTX *ctx, OPENSSL_EXPORT void SSL_CTX_set_ignore_tls13_downgrade(SSL_CTX *ctx, int ignore); +// SSL_set_ignore_tls13_downgrade configures whether |ssl| ignores the downgrade +// signal in the server's random value. +OPENSSL_EXPORT void SSL_set_ignore_tls13_downgrade(SSL *ssl, int ignore); + // SSL_is_tls13_downgrade returns one if the TLS 1.3 anti-downgrade // mechanism would have aborted |ssl|'s handshake and zero otherwise. OPENSSL_EXPORT int SSL_is_tls13_downgrade(const SSL *ssl); diff --git a/src/include/openssl/stack.h b/src/include/openssl/stack.h index 15b6adf7..c1bf520f 100644 --- a/src/include/openssl/stack.h +++ b/src/include/openssl/stack.h @@ -86,10 +86,23 @@ extern "C" { // STACK_OF(FOO), the macros would be sk_FOO_new, sk_FOO_pop etc. +// stack_free_func is a function that frees an element in a stack. Note its +// actual type is void (*)(T *) for some T. Low-level |sk_*| functions will be +// passed a type-specific wrapper to call it correctly. +typedef void (*stack_free_func)(void *ptr); + +// stack_copy_func is a function that copies an element in a stack. Note its +// actual type is T *(*)(T *) for some T. Low-level |sk_*| functions will be +// passed a type-specific wrapper to call it correctly. +typedef void *(*stack_copy_func)(void *ptr); + // stack_cmp_func is a comparison function that returns a value < 0, 0 or > 0 // if |*a| is less than, equal to or greater than |*b|, respectively. Note the // extra indirection - the function is given a pointer to a pointer to the // element. This differs from the usual qsort/bsearch comparison function. +// +// Note its actual type is int (*)(const T **, const T **). Low-level |sk_*| +// functions will be passed a type-specific wrapper to call it correctly. typedef int (*stack_cmp_func)(const void **a, const void **b); // stack_st contains an array of pointers. It is not designed to be used @@ -140,12 +153,17 @@ OPENSSL_EXPORT void *sk_value(const _STACK *sk, size_t i); OPENSSL_EXPORT void *sk_set(_STACK *sk, size_t i, void *p); // sk_free frees the given stack and array of pointers, but does nothing to -// free the individual elements. Also see |sk_pop_free|. +// free the individual elements. Also see |sk_pop_free_ex|. OPENSSL_EXPORT void sk_free(_STACK *sk); -// sk_pop_free calls |free_func| on each element in the stack and then frees -// the stack itself. -OPENSSL_EXPORT void sk_pop_free(_STACK *sk, void (*free_func)(void *)); +// sk_pop_free_ex calls |free_func| on each element in the stack and then frees +// the stack itself. Note this corresponds to |sk_FOO_pop_free|. It is named +// |sk_pop_free_ex| as a workaround for existing code calling an older version +// of |sk_pop_free|. +OPENSSL_EXPORT void sk_pop_free_ex(_STACK *sk, + void (*call_free_func)(stack_free_func, + void *), + stack_free_func free_func); // sk_insert inserts |p| into the stack at index |where|, moving existing // elements if needed. It returns the length of the new stack, or zero on @@ -160,7 +178,7 @@ OPENSSL_EXPORT void *sk_delete(_STACK *sk, size_t where); // sk_delete_ptr removes, at most, one instance of |p| from the stack based on // pointer equality. If an instance of |p| is found then |p| is returned, // otherwise it returns NULL. -OPENSSL_EXPORT void *sk_delete_ptr(_STACK *sk, void *p); +OPENSSL_EXPORT void *sk_delete_ptr(_STACK *sk, const void *p); // sk_find returns the first value in the stack equal to |p|. If a comparison // function has been set on the stack, equality is defined by it, otherwise @@ -173,7 +191,9 @@ OPENSSL_EXPORT void *sk_delete_ptr(_STACK *sk, void *p); // Note this differs from OpenSSL. The type signature is slightly different, and // OpenSSL's sk_find will implicitly sort |sk| if it has a comparison function // defined. -OPENSSL_EXPORT int sk_find(const _STACK *sk, size_t *out_index, void *p); +OPENSSL_EXPORT int sk_find(const _STACK *sk, size_t *out_index, const void *p, + int (*call_cmp_func)(stack_cmp_func, const void **, + const void **)); // sk_shift removes and returns the first element in the stack, or returns NULL // if the stack is empty. @@ -207,9 +227,20 @@ OPENSSL_EXPORT stack_cmp_func sk_set_cmp_func(_STACK *sk, stack_cmp_func comp); // sk_deep_copy performs a copy of |sk| and of each of the non-NULL elements in // |sk| by using |copy_func|. If an error occurs, |free_func| is used to free // any copies already made and NULL is returned. -OPENSSL_EXPORT _STACK *sk_deep_copy(const _STACK *sk, - void *(*copy_func)(void *), - void (*free_func)(void *)); +OPENSSL_EXPORT _STACK *sk_deep_copy( + const _STACK *sk, void *(*call_copy_func)(stack_copy_func, void *), + stack_copy_func copy_func, void (*call_free_func)(stack_free_func, void *), + stack_free_func free_func); + + +// Deprecated functions. + +// sk_pop_free behaves like |sk_pop_free_ex| but performs an invalid function +// pointer cast. It exists because some existing callers called |sk_pop_free| +// directly. +// +// TODO(davidben): Migrate callers to bssl::UniquePtr and remove this. +OPENSSL_EXPORT void sk_pop_free(_STACK *sk, stack_free_func free_func); // Defining stack types. @@ -245,113 +276,126 @@ BSSL_NAMESPACE_END #define BORINGSSL_DEFINE_STACK_TRAITS(name, type, is_const) #endif -// Stack functions must be tagged unused to support file-local stack types. -// Clang's -Wunused-function only allows unused static inline functions if they -// are defined in a header. - #define BORINGSSL_DEFINE_STACK_OF_IMPL(name, ptrtype, constptrtype) \ DECLARE_STACK_OF(name) \ \ + typedef void (*stack_##name##_free_func)(ptrtype); \ + typedef ptrtype (*stack_##name##_copy_func)(ptrtype); \ typedef int (*stack_##name##_cmp_func)(constptrtype *a, constptrtype *b); \ \ - static inline OPENSSL_UNUSED STACK_OF(name) * \ + OPENSSL_INLINE void sk_##name##_call_free_func(stack_free_func free_func, \ + void *ptr) { \ + ((stack_##name##_free_func)free_func)((ptrtype)ptr); \ + } \ + \ + OPENSSL_INLINE void *sk_##name##_call_copy_func(stack_copy_func copy_func, \ + void *ptr) { \ + return (void *)((stack_##name##_copy_func)copy_func)((ptrtype)ptr); \ + } \ + \ + OPENSSL_INLINE int sk_##name##_call_cmp_func( \ + stack_cmp_func cmp_func, const void **a, const void **b) { \ + constptrtype a_ptr = (constptrtype)*a; \ + constptrtype b_ptr = (constptrtype)*b; \ + return ((stack_##name##_cmp_func)cmp_func)(&a_ptr, &b_ptr); \ + } \ + \ + OPENSSL_INLINE STACK_OF(name) * \ sk_##name##_new(stack_##name##_cmp_func comp) { \ return (STACK_OF(name) *)sk_new((stack_cmp_func)comp); \ } \ \ - static inline OPENSSL_UNUSED STACK_OF(name) *sk_##name##_new_null(void) { \ + OPENSSL_INLINE STACK_OF(name) *sk_##name##_new_null(void) { \ return (STACK_OF(name) *)sk_new_null(); \ } \ \ - static inline OPENSSL_UNUSED size_t sk_##name##_num( \ - const STACK_OF(name) *sk) { \ + OPENSSL_INLINE size_t sk_##name##_num(const STACK_OF(name) *sk) { \ return sk_num((const _STACK *)sk); \ } \ \ - static inline OPENSSL_UNUSED void sk_##name##_zero(STACK_OF(name) *sk) { \ + OPENSSL_INLINE void sk_##name##_zero(STACK_OF(name) *sk) { \ sk_zero((_STACK *)sk); \ } \ \ - static inline OPENSSL_UNUSED ptrtype sk_##name##_value( \ - const STACK_OF(name) *sk, size_t i) { \ + OPENSSL_INLINE ptrtype sk_##name##_value(const STACK_OF(name) *sk, \ + size_t i) { \ return (ptrtype)sk_value((const _STACK *)sk, i); \ } \ \ - static inline OPENSSL_UNUSED ptrtype sk_##name##_set(STACK_OF(name) *sk, \ - size_t i, ptrtype p) { \ + OPENSSL_INLINE ptrtype sk_##name##_set(STACK_OF(name) *sk, size_t i, \ + ptrtype p) { \ return (ptrtype)sk_set((_STACK *)sk, i, (void *)p); \ } \ \ - static inline OPENSSL_UNUSED void sk_##name##_free(STACK_OF(name) *sk) { \ + OPENSSL_INLINE void sk_##name##_free(STACK_OF(name) * sk) { \ sk_free((_STACK *)sk); \ } \ \ - static inline OPENSSL_UNUSED void sk_##name##_pop_free( \ - STACK_OF(name) *sk, void (*free_func)(ptrtype p)) { \ - sk_pop_free((_STACK *)sk, (void (*)(void *))free_func); \ + OPENSSL_INLINE void sk_##name##_pop_free( \ + STACK_OF(name) * sk, stack_##name##_free_func free_func) { \ + sk_pop_free_ex((_STACK *)sk, sk_##name##_call_free_func, \ + (stack_free_func)free_func); \ } \ \ - static inline OPENSSL_UNUSED size_t sk_##name##_insert( \ - STACK_OF(name) *sk, ptrtype p, size_t where) { \ + OPENSSL_INLINE size_t sk_##name##_insert(STACK_OF(name) *sk, ptrtype p, \ + size_t where) { \ return sk_insert((_STACK *)sk, (void *)p, where); \ } \ \ - static inline OPENSSL_UNUSED ptrtype sk_##name##_delete(STACK_OF(name) *sk, \ - size_t where) { \ + OPENSSL_INLINE ptrtype sk_##name##_delete(STACK_OF(name) *sk, \ + size_t where) { \ return (ptrtype)sk_delete((_STACK *)sk, where); \ } \ \ - static inline OPENSSL_UNUSED ptrtype sk_##name##_delete_ptr( \ - STACK_OF(name) *sk, ptrtype p) { \ - return (ptrtype)sk_delete_ptr((_STACK *)sk, (void *)p); \ + OPENSSL_INLINE ptrtype sk_##name##_delete_ptr(STACK_OF(name) *sk, \ + constptrtype p) { \ + return (ptrtype)sk_delete_ptr((_STACK *)sk, (const void *)p); \ } \ \ - static inline OPENSSL_UNUSED int sk_##name##_find( \ - const STACK_OF(name) *sk, size_t *out_index, ptrtype p) { \ - return sk_find((const _STACK *)sk, out_index, (void *)p); \ + OPENSSL_INLINE int sk_##name##_find(const STACK_OF(name) *sk, \ + size_t * out_index, constptrtype p) { \ + return sk_find((const _STACK *)sk, out_index, (const void *)p, \ + sk_##name##_call_cmp_func); \ } \ \ - static inline OPENSSL_UNUSED ptrtype sk_##name##_shift(STACK_OF(name) *sk) { \ + OPENSSL_INLINE ptrtype sk_##name##_shift(STACK_OF(name) *sk) { \ return (ptrtype)sk_shift((_STACK *)sk); \ } \ \ - static inline OPENSSL_UNUSED size_t sk_##name##_push(STACK_OF(name) *sk, \ - ptrtype p) { \ + OPENSSL_INLINE size_t sk_##name##_push(STACK_OF(name) *sk, ptrtype p) { \ return sk_push((_STACK *)sk, (void *)p); \ } \ \ - static inline OPENSSL_UNUSED ptrtype sk_##name##_pop(STACK_OF(name) *sk) { \ + OPENSSL_INLINE ptrtype sk_##name##_pop(STACK_OF(name) *sk) { \ return (ptrtype)sk_pop((_STACK *)sk); \ } \ \ - static inline OPENSSL_UNUSED STACK_OF(name) * \ - sk_##name##_dup(const STACK_OF(name) *sk) { \ + OPENSSL_INLINE STACK_OF(name) * sk_##name##_dup(const STACK_OF(name) *sk) { \ return (STACK_OF(name) *)sk_dup((const _STACK *)sk); \ } \ \ - static inline OPENSSL_UNUSED void sk_##name##_sort(STACK_OF(name) *sk) { \ + OPENSSL_INLINE void sk_##name##_sort(STACK_OF(name) *sk) { \ sk_sort((_STACK *)sk); \ } \ \ - static inline OPENSSL_UNUSED int sk_##name##_is_sorted( \ - const STACK_OF(name) *sk) { \ + OPENSSL_INLINE int sk_##name##_is_sorted(const STACK_OF(name) *sk) { \ return sk_is_sorted((const _STACK *)sk); \ } \ \ - static inline OPENSSL_UNUSED stack_##name##_cmp_func \ - sk_##name##_set_cmp_func(STACK_OF(name) *sk, \ - stack_##name##_cmp_func comp) { \ + OPENSSL_INLINE stack_##name##_cmp_func sk_##name##_set_cmp_func( \ + STACK_OF(name) *sk, stack_##name##_cmp_func comp) { \ return (stack_##name##_cmp_func)sk_set_cmp_func((_STACK *)sk, \ (stack_cmp_func)comp); \ } \ \ - static inline OPENSSL_UNUSED STACK_OF(name) * \ + OPENSSL_INLINE STACK_OF(name) * \ sk_##name##_deep_copy(const STACK_OF(name) *sk, \ ptrtype(*copy_func)(ptrtype), \ void (*free_func)(ptrtype)) { \ - return (STACK_OF(name) *)sk_deep_copy((const _STACK *)sk, \ - (void *(*)(void *))copy_func, \ - (void (*)(void *))free_func); \ + return (STACK_OF(name) *)sk_deep_copy( \ + (const _STACK *)sk, sk_##name##_call_copy_func, \ + (stack_copy_func)copy_func, sk_##name##_call_free_func, \ + (stack_free_func)free_func); \ } // DEFINE_NAMED_STACK_OF defines |STACK_OF(name)| to be a stack whose elements @@ -410,10 +454,14 @@ template struct DeleterImpl< Stack, typename std::enable_if::kIsConst>::type> { static void Free(Stack *sk) { - sk_pop_free( - reinterpret_cast<_STACK *>(sk), - reinterpret_cast( - DeleterImpl::Type>::Free)); + // sk_FOO_pop_free is defined by macros and bound by name, so we cannot + // access it from C++ here. + using Type = typename StackTraits::Type; + sk_pop_free_ex(reinterpret_cast<_STACK *>(sk), + [](stack_free_func /* unused */, void *ptr) { + DeleterImpl::Free(reinterpret_cast(ptr)); + }, + nullptr); } }; @@ -462,7 +510,7 @@ using StackIterator = typename std::enable_if::kIsStack, // PushToStack pushes |elem| to |sk|. It returns true on success and false on // allocation failure. template -static inline +inline typename std::enable_if::kIsConst, bool>::type PushToStack(Stack *sk, UniquePtr::Type> elem) { @@ -478,12 +526,12 @@ BSSL_NAMESPACE_END // Define begin() and end() for stack types so C++ range for loops work. template -static inline bssl::internal::StackIterator begin(const Stack *sk) { +inline bssl::internal::StackIterator begin(const Stack *sk) { return bssl::internal::StackIterator(sk, 0); } template -static inline bssl::internal::StackIterator end(const Stack *sk) { +inline bssl::internal::StackIterator end(const Stack *sk) { return bssl::internal::StackIterator( sk, sk_num(reinterpret_cast(sk))); } diff --git a/src/include/openssl/thread.h b/src/include/openssl/thread.h index 98073b07..91706fec 100644 --- a/src/include/openssl/thread.h +++ b/src/include/openssl/thread.h @@ -66,7 +66,7 @@ extern "C" { #endif -#if defined(OPENSSL_NO_THREADS) +#if !defined(OPENSSL_THREADS) typedef struct crypto_mutex_st { char padding; // Empty structs have different sizes in C and C++. } CRYPTO_MUTEX; diff --git a/src/include/openssl/type_check.h b/src/include/openssl/type_check.h index da78d70c..e5d70479 100644 --- a/src/include/openssl/type_check.h +++ b/src/include/openssl/type_check.h @@ -72,10 +72,6 @@ extern "C" { // CHECKED_CAST casts |p| from type |from| to type |to|. #define CHECKED_CAST(to, from, p) ((to) (1 ? (p) : (from)0)) -// CHECKED_PTR_OF casts a given pointer to void* and statically checks that it -// was a pointer to |type|. -#define CHECKED_PTR_OF(type, p) CHECKED_CAST(void*, type*, (p)) - #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L #define OPENSSL_COMPILE_ASSERT(cond, msg) _Static_assert(cond, #msg) #else diff --git a/src/include/openssl/x509v3.h b/src/include/openssl/x509v3.h index 53e20a07..7d1c306e 100644 --- a/src/include/openssl/x509v3.h +++ b/src/include/openssl/x509v3.h @@ -57,7 +57,6 @@ #include #include -#include #include #ifdef __cplusplus @@ -612,7 +611,8 @@ OPENSSL_EXPORT GENERAL_NAME *v2i_GENERAL_NAME_ex(GENERAL_NAME *out, X509V3_CTX *ctx, CONF_VALUE *cnf, int is_nc); OPENSSL_EXPORT void X509V3_conf_free(CONF_VALUE *val); -OPENSSL_EXPORT X509_EXTENSION *X509V3_EXT_conf_nid(LHASH_OF(CONF_VALUE) *conf, X509V3_CTX *ctx, int ext_nid, char *value); +typedef struct x509_must_be_null_st X509_MUST_BE_NULL; +OPENSSL_EXPORT X509_EXTENSION *X509V3_EXT_conf_nid(X509_MUST_BE_NULL *conf, X509V3_CTX *ctx, int ext_nid, char *value); OPENSSL_EXPORT X509_EXTENSION *X509V3_EXT_nconf_nid(CONF *conf, X509V3_CTX *ctx, int ext_nid, char *value); OPENSSL_EXPORT X509_EXTENSION *X509V3_EXT_nconf(CONF *conf, X509V3_CTX *ctx, char *name, char *value); OPENSSL_EXPORT int X509V3_EXT_add_nconf_sk(CONF *conf, X509V3_CTX *ctx, char *section, STACK_OF(X509_EXTENSION) **sk); @@ -620,9 +620,6 @@ OPENSSL_EXPORT int X509V3_EXT_add_nconf(CONF *conf, X509V3_CTX *ctx, char *secti OPENSSL_EXPORT int X509V3_EXT_REQ_add_nconf(CONF *conf, X509V3_CTX *ctx, char *section, X509_REQ *req); OPENSSL_EXPORT int X509V3_EXT_CRL_add_nconf(CONF *conf, X509V3_CTX *ctx, char *section, X509_CRL *crl); -OPENSSL_EXPORT int X509V3_EXT_CRL_add_conf(LHASH_OF(CONF_VALUE) *conf, X509V3_CTX *ctx, - char *section, X509_CRL *crl); - OPENSSL_EXPORT int X509V3_add_value_bool_nf(char *name, int asn1_bool, STACK_OF(CONF_VALUE) **extlist); OPENSSL_EXPORT int X509V3_get_value_bool(CONF_VALUE *value, int *asn1_bool); diff --git a/src/ssl/handshake_client.cc b/src/ssl/handshake_client.cc index ae96bcf2..e46b39f9 100644 --- a/src/ssl/handshake_client.cc +++ b/src/ssl/handshake_client.cc @@ -600,7 +600,7 @@ static enum ssl_hs_wait_t do_read_server_hello(SSL_HANDSHAKE *hs) { .subspan(SSL3_RANDOM_SIZE - sizeof(kTLS13DowngradeRandom)); if (suffix == kTLS12DowngradeRandom || suffix == kTLS13DowngradeRandom) { ssl->s3->tls13_downgrade = true; - if (!ssl->ctx->ignore_tls13_downgrade) { + if (!hs->config->ignore_tls13_downgrade) { OPENSSL_PUT_ERROR(SSL, SSL_R_TLS13_DOWNGRADE); ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); return ssl_hs_error; diff --git a/src/ssl/internal.h b/src/ssl/internal.h index 0535b8de..561b5d9b 100644 --- a/src/ssl/internal.h +++ b/src/ssl/internal.h @@ -2456,6 +2456,10 @@ struct SSL_CONFIG { // shed_handshake_config indicates that the handshake config (this object!) // should be freed after the handshake completes. bool shed_handshake_config : 1; + + // ignore_tls13_downgrade is whether the connection should continue when the + // server random signals a downgrade. + bool ignore_tls13_downgrade:1; }; // From RFC 8446, used in determining PSK modes. diff --git a/src/ssl/ssl_lib.cc b/src/ssl/ssl_lib.cc index 13b9cacc..9c16de49 100644 --- a/src/ssl/ssl_lib.cc +++ b/src/ssl/ssl_lib.cc @@ -693,6 +693,7 @@ SSL *SSL_new(SSL_CTX *ctx) { ctx->signed_cert_timestamps_enabled; ssl->config->ocsp_stapling_enabled = ctx->ocsp_stapling_enabled; ssl->config->handoff = ctx->handoff; + ssl->config->ignore_tls13_downgrade = ctx->ignore_tls13_downgrade; if (!ssl->method->ssl_new(ssl.get()) || !ssl->ctx->x509_method->ssl_new(ssl->s3->hs.get())) { @@ -709,7 +710,8 @@ SSL_CONFIG::SSL_CONFIG(SSL *ssl_arg) channel_id_enabled(false), retain_only_sha256_of_client_certs(false), handoff(false), - shed_handshake_config(false) { + shed_handshake_config(false), + ignore_tls13_downgrade(false) { assert(ssl); } @@ -2642,6 +2644,13 @@ void SSL_CTX_set_ignore_tls13_downgrade(SSL_CTX *ctx, int ignore) { ctx->ignore_tls13_downgrade = !!ignore; } +void SSL_set_ignore_tls13_downgrade(SSL *ssl, int ignore) { + if (!ssl->config) { + return; + } + ssl->config->ignore_tls13_downgrade = !!ignore; +} + void SSL_set_shed_handshake_config(SSL *ssl, int enable) { if (!ssl->config) { return; diff --git a/src/ssl/ssl_test.cc b/src/ssl/ssl_test.cc index 894bb14e..61a47d3d 100644 --- a/src/ssl/ssl_test.cc +++ b/src/ssl/ssl_test.cc @@ -48,7 +48,7 @@ OPENSSL_MSVC_PRAGMA(warning(pop)) #include #endif -#if !defined(OPENSSL_NO_THREADS) +#if defined(OPENSSL_THREADS) #include #endif @@ -4298,7 +4298,7 @@ TEST_P(SSLVersionTest, FakeIDsForTickets) { // These tests test multi-threaded behavior. They are intended to run with // ThreadSanitizer. -#if !defined(OPENSSL_NO_THREADS) +#if defined(OPENSSL_THREADS) TEST_P(SSLVersionTest, SessionCacheThreads) { SSL_CTX_set_options(server_ctx_.get(), SSL_OP_NO_TICKET); SSL_CTX_set_session_cache_mode(client_ctx_.get(), SSL_SESS_CACHE_BOTH); diff --git a/src/ssl/ssl_x509.cc b/src/ssl/ssl_x509.cc index 9fa800ff..ec203b22 100644 --- a/src/ssl/ssl_x509.cc +++ b/src/ssl/ssl_x509.cc @@ -999,17 +999,25 @@ int SSL_get0_chain_certs(const SSL *ssl, STACK_OF(X509) **out_chain) { return 1; } -static SSL_SESSION *ssl_session_new_with_crypto_x509(void) { - return ssl_session_new(&ssl_crypto_x509_method).release(); -} - SSL_SESSION *d2i_SSL_SESSION_bio(BIO *bio, SSL_SESSION **out) { - return ASN1_d2i_bio_of(SSL_SESSION, ssl_session_new_with_crypto_x509, - d2i_SSL_SESSION, bio, out); + uint8_t *data; + size_t len; + if (!BIO_read_asn1(bio, &data, &len, 1024 * 1024)) { + return 0; + } + bssl::UniquePtr free_data(data); + const uint8_t *ptr = data; + return d2i_SSL_SESSION(out, &ptr, static_cast(len)); } int i2d_SSL_SESSION_bio(BIO *bio, const SSL_SESSION *session) { - return ASN1_i2d_bio_of(SSL_SESSION, i2d_SSL_SESSION, bio, session); + uint8_t *data; + size_t len; + if (!SSL_SESSION_to_bytes(session, &data, &len)) { + return 0; + } + bssl::UniquePtr free_data(data); + return BIO_write_all(bio, data, len); } IMPLEMENT_PEM_rw(SSL_SESSION, SSL_SESSION, PEM_STRING_SSL_SESSION, SSL_SESSION) diff --git a/src/ssl/test/runner/runner.go b/src/ssl/test/runner/runner.go index 4bcf6037..9631e6e2 100644 --- a/src/ssl/test/runner/runner.go +++ b/src/ssl/test/runner/runner.go @@ -5891,59 +5891,65 @@ func addVersionNegotiationTests() { }) // Test TLS 1.3's downgrade signal. - testCases = append(testCases, testCase{ - name: "Downgrade-TLS12-Client", - config: Config{ - Bugs: ProtocolBugs{ - NegotiateVersion: VersionTLS12, - }, - }, - tls13Variant: TLS13RFC, - expectedVersion: VersionTLS12, - shouldFail: true, - expectedError: ":TLS13_DOWNGRADE:", - expectedLocalError: "remote error: illegal parameter", - }) - testCases = append(testCases, testCase{ - testType: serverTest, - name: "Downgrade-TLS12-Server", - config: Config{ - Bugs: ProtocolBugs{ - SendSupportedVersions: []uint16{VersionTLS12}, + var downgradeTests = []struct { + name string + version uint16 + clientShimError string + }{ + {"TLS12", VersionTLS12, "tls: downgrade from TLS 1.3 detected"}, + {"TLS11", VersionTLS11, "tls: downgrade from TLS 1.2 detected"}, + // TLS 1.0 does not have a dedicated value. + {"TLS10", VersionTLS10, "tls: downgrade from TLS 1.2 detected"}, + } + + for _, test := range downgradeTests { + // The client should enforce the downgrade sentinel. + testCases = append(testCases, testCase{ + name: "Downgrade-" + test.name + "-Client", + config: Config{ + Bugs: ProtocolBugs{ + NegotiateVersion: test.version, + }, }, - }, - tls13Variant: TLS13RFC, - expectedVersion: VersionTLS12, - shouldFail: true, - expectedLocalError: "tls: downgrade from TLS 1.3 detected", - }) + tls13Variant: TLS13RFC, + expectedVersion: test.version, + shouldFail: true, + expectedError: ":TLS13_DOWNGRADE:", + expectedLocalError: "remote error: illegal parameter", + }) - testCases = append(testCases, testCase{ - name: "Downgrade-TLS11-Client", - config: Config{ - Bugs: ProtocolBugs{ - NegotiateVersion: VersionTLS11, + // The client should ignore the downgrade sentinel if + // configured. + testCases = append(testCases, testCase{ + name: "Downgrade-" + test.name + "-Client-Ignore", + config: Config{ + Bugs: ProtocolBugs{ + NegotiateVersion: test.version, + }, }, - }, - tls13Variant: TLS13RFC, - expectedVersion: VersionTLS11, - shouldFail: true, - expectedError: ":TLS13_DOWNGRADE:", - expectedLocalError: "remote error: illegal parameter", - }) - testCases = append(testCases, testCase{ - testType: serverTest, - name: "Downgrade-TLS11-Server", - config: Config{ - Bugs: ProtocolBugs{ - SendSupportedVersions: []uint16{VersionTLS11}, + tls13Variant: TLS13RFC, + expectedVersion: test.version, + flags: []string{ + "-ignore-tls13-downgrade", + "-expect-tls13-downgrade", }, - }, - tls13Variant: TLS13RFC, - expectedVersion: VersionTLS11, - shouldFail: true, - expectedLocalError: "tls: downgrade from TLS 1.2 detected", - }) + }) + + // The server should emit the downgrade signal. + testCases = append(testCases, testCase{ + testType: serverTest, + name: "Downgrade-" + test.name + "-Server", + config: Config{ + Bugs: ProtocolBugs{ + SendSupportedVersions: []uint16{test.version}, + }, + }, + tls13Variant: TLS13RFC, + expectedVersion: test.version, + shouldFail: true, + expectedLocalError: test.clientShimError, + }) + } // Test that the draft TLS 1.3 variants don't trigger the downgrade logic. testCases = append(testCases, testCase{ diff --git a/src/util/ar/ar.go b/src/util/ar/ar.go new file mode 100644 index 00000000..f5dee622 --- /dev/null +++ b/src/util/ar/ar.go @@ -0,0 +1,148 @@ +// Copyright (c) 2017, 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. */ + +// ar.go contains functions for parsing .a archive files. + +package ar + +import ( + "bytes" + "errors" + "fmt" + "io" + "strconv" + "strings" +) + +// ParseAR parses an archive file from r and returns a map from filename to +// contents, or else an error. +func ParseAR(r io.Reader) (map[string][]byte, error) { + // See https://en.wikipedia.org/wiki/Ar_(Unix)#File_format_details + const expectedMagic = "!\n" + var magic [len(expectedMagic)]byte + if _, err := io.ReadFull(r, magic[:]); err != nil { + return nil, err + } + if string(magic[:]) != expectedMagic { + return nil, errors.New("ar: not an archive file") + } + + const filenameTableName = "//" + const symbolTableName = "/" + var longFilenameTable []byte + ret := make(map[string][]byte) + + for { + var header [60]byte + if _, err := io.ReadFull(r, header[:]); err != nil { + if err == io.EOF { + break + } + return nil, errors.New("ar: error reading file header: " + err.Error()) + } + + name := strings.TrimRight(string(header[:16]), " ") + sizeStr := strings.TrimRight(string(header[48:58]), "\x00 ") + size, err := strconv.ParseUint(sizeStr, 10, 64) + if err != nil { + return nil, errors.New("ar: failed to parse file size: " + err.Error()) + } + + // File contents are padded to a multiple of two bytes + storedSize := size + if storedSize%2 == 1 { + storedSize++ + } + + contents := make([]byte, storedSize) + if _, err := io.ReadFull(r, contents); err != nil { + return nil, errors.New("ar: error reading file contents: " + err.Error()) + } + contents = contents[:size] + + switch { + case name == filenameTableName: + if longFilenameTable != nil { + return nil, errors.New("ar: two filename tables found") + } + longFilenameTable = contents + continue + + case name == symbolTableName: + continue + + case len(name) > 1 && name[0] == '/': + if longFilenameTable == nil { + return nil, errors.New("ar: long filename reference found before filename table") + } + + // A long filename is stored as "/" followed by a + // base-10 offset in the filename table. + offset, err := strconv.ParseUint(name[1:], 10, 64) + if err != nil { + return nil, errors.New("ar: failed to parse filename offset: " + err.Error()) + } + if offset > uint64((^uint(0))>>1) { + return nil, errors.New("ar: filename offset overflow") + } + + if int(offset) > len(longFilenameTable) { + return nil, errors.New("ar: filename offset out of bounds") + } + + filename := longFilenameTable[offset:] + if i := bytes.IndexByte(filename, '/'); i < 0 { + return nil, errors.New("ar: unterminated filename in table") + } else { + filename = filename[:i] + } + + name = string(filename) + + default: + name = strings.TrimRight(name, "/") + } + + // Post-processing for BSD: + // https://en.wikipedia.org/wiki/Ar_(Unix)#BSD_variant + // + // If the name is of the form #1/XXX, XXX identifies the length of the + // name, and the name itself is stored as a prefix of the data, possibly + // null-padded. + + var namelen uint + n, err := fmt.Sscanf(name, "#1/%d", &namelen) + if err == nil && n == 1 && len(contents) >= int(namelen) { + name = string(contents[:namelen]) + contents = contents[namelen:] + + // Names can be null padded; find the first null (if any). Note that + // this also handles the case of a null followed by non-null + // characters. It's not clear whether those can ever show up in + // practice, but we might as well handle them in case they can show + // up. + var null int + for ; null < len(name); null++ { + if name[null] == 0 { + break + } + } + name = name[:null] + } + + ret[name] = contents + } + + return ret, nil +} diff --git a/src/util/fipstools/delocate/delocate.go b/src/util/fipstools/delocate/delocate.go index a8c4fd0e..47342853 100644 --- a/src/util/fipstools/delocate/delocate.go +++ b/src/util/fipstools/delocate/delocate.go @@ -26,6 +26,7 @@ import ( "strconv" "strings" + "boringssl.googlesource.com/boringssl/util/ar" "boringssl.googlesource.com/boringssl/util/fipstools/fipscommon" ) @@ -1425,7 +1426,7 @@ func parseInputs(inputs []inputFile) error { } defer arFile.Close() - ar, err := fipscommon.ParseAR(arFile) + ar, err := ar.ParseAR(arFile) if err != nil { return err } diff --git a/src/util/fipstools/fipscommon/ar.go b/src/util/fipstools/fipscommon/ar.go deleted file mode 100644 index 85b378d6..00000000 --- a/src/util/fipstools/fipscommon/ar.go +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright (c) 2017, 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. */ - -// ar.go contains functions for parsing .a archive files. - -package fipscommon - -import ( - "bytes" - "errors" - "io" - "strconv" - "strings" -) - -// ParseAR parses an archive file from r and returns a map from filename to -// contents, or else an error. -func ParseAR(r io.Reader) (map[string][]byte, error) { - // See https://en.wikipedia.org/wiki/Ar_(Unix)#File_format_details - const expectedMagic = "!\n" - var magic [len(expectedMagic)]byte - if _, err := io.ReadFull(r, magic[:]); err != nil { - return nil, err - } - if string(magic[:]) != expectedMagic { - return nil, errors.New("ar: not an archive file") - } - - const filenameTableName = "//" - const symbolTableName = "/" - var longFilenameTable []byte - ret := make(map[string][]byte) - - for { - var header [60]byte - if _, err := io.ReadFull(r, header[:]); err != nil { - if err == io.EOF { - break - } - return nil, errors.New("ar: error reading file header: " + err.Error()) - } - - name := strings.TrimRight(string(header[:16]), " ") - sizeStr := strings.TrimRight(string(header[48:58]), "\x00 ") - size, err := strconv.ParseUint(sizeStr, 10, 64) - if err != nil { - return nil, errors.New("ar: failed to parse file size: " + err.Error()) - } - - // File contents are padded to a multiple of two bytes - storedSize := size - if storedSize%2 == 1 { - storedSize++ - } - - contents := make([]byte, storedSize) - if _, err := io.ReadFull(r, contents); err != nil { - return nil, errors.New("ar: error reading file contents: " + err.Error()) - } - contents = contents[:size] - - switch { - case name == filenameTableName: - if longFilenameTable != nil { - return nil, errors.New("ar: two filename tables found") - } - longFilenameTable = contents - continue - - case name == symbolTableName: - continue - - case len(name) > 1 && name[0] == '/': - if longFilenameTable == nil { - return nil, errors.New("ar: long filename reference found before filename table") - } - - // A long filename is stored as "/" followed by a - // base-10 offset in the filename table. - offset, err := strconv.ParseUint(name[1:], 10, 64) - if err != nil { - return nil, errors.New("ar: failed to parse filename offset: " + err.Error()) - } - if offset > uint64((^uint(0))>>1) { - return nil, errors.New("ar: filename offset overflow") - } - - if int(offset) > len(longFilenameTable) { - return nil, errors.New("ar: filename offset out of bounds") - } - - filename := longFilenameTable[offset:] - if i := bytes.IndexByte(filename, '/'); i < 0 { - return nil, errors.New("ar: unterminated filename in table") - } else { - filename = filename[:i] - } - - name = string(filename) - - default: - name = strings.TrimRight(name, "/") - } - - ret[name] = contents - } - - return ret, nil -} diff --git a/src/util/fipstools/inject-hash/inject-hash.go b/src/util/fipstools/inject-hash/inject-hash.go deleted file mode 100644 index 14418a38..00000000 --- a/src/util/fipstools/inject-hash/inject-hash.go +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright (c) 2017, 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. */ - -// inject-hash parses an archive containing a file object file. It finds a FIPS -// module inside that object, calculates its hash and replaces the default hash -// value in the object with the calculated value. -package main - -import ( - "bytes" - "crypto/hmac" - "crypto/sha512" - "debug/elf" - "errors" - "flag" - "fmt" - "io" - "io/ioutil" - "os" - - "boringssl.googlesource.com/boringssl/util/fipstools/fipscommon" -) - -func do(outPath, oInput string, arInput string) error { - var objectBytes []byte - if len(arInput) > 0 { - if len(oInput) > 0 { - return fmt.Errorf("-in-archive and -in-object are mutually exclusive") - } - - arFile, err := os.Open(arInput) - if err != nil { - return err - } - defer arFile.Close() - - ar, err := fipscommon.ParseAR(arFile) - if err != nil { - return err - } - - if len(ar) != 1 { - return fmt.Errorf("expected one file in archive, but found %d", len(ar)) - } - - for _, contents := range ar { - objectBytes = contents - } - } else if len(oInput) > 0 { - var err error - if objectBytes, err = ioutil.ReadFile(oInput); err != nil { - return err - } - } else { - return fmt.Errorf("exactly one of -in-archive or -in-object is required") - } - - object, err := elf.NewFile(bytes.NewReader(objectBytes)) - if err != nil { - return errors.New("failed to parse object: " + err.Error()) - } - - // Find the .text section. - - var textSection *elf.Section - var textSectionIndex elf.SectionIndex - for i, section := range object.Sections { - if section.Name == ".text" { - textSectionIndex = elf.SectionIndex(i) - textSection = section - break - } - } - - if textSection == nil { - return errors.New("failed to find .text section in object") - } - - // Find the starting and ending symbols for the module. - - var startSeen, endSeen bool - var start, end uint64 - - symbols, err := object.Symbols() - if err != nil { - return errors.New("failed to parse symbols: " + err.Error()) - } - - for _, symbol := range symbols { - if symbol.Section != textSectionIndex { - continue - } - - switch symbol.Name { - case "BORINGSSL_bcm_text_start": - if startSeen { - return errors.New("duplicate start symbol found") - } - startSeen = true - start = symbol.Value - case "BORINGSSL_bcm_text_end": - if endSeen { - return errors.New("duplicate end symbol found") - } - endSeen = true - end = symbol.Value - default: - continue - } - } - - if !startSeen || !endSeen { - return errors.New("could not find module boundaries in object") - } - - if max := textSection.Size; start > max || start > end || end > max { - return fmt.Errorf("invalid module boundaries: start: %x, end: %x, max: %x", start, end, max) - } - - // Extract the module from the .text section and hash it. - - text := textSection.Open() - if _, err := text.Seek(int64(start), 0); err != nil { - return errors.New("failed to seek to module start in .text: " + err.Error()) - } - moduleText := make([]byte, end-start) - if _, err := io.ReadFull(text, moduleText); err != nil { - return errors.New("failed to read .text: " + err.Error()) - } - - var zeroKey [64]byte - mac := hmac.New(sha512.New, zeroKey[:]) - mac.Write(moduleText) - calculated := mac.Sum(nil) - - // Replace the default hash value in the object with the calculated - // value and write it out. - - offset := bytes.Index(objectBytes, fipscommon.UninitHashValue[:]) - if offset < 0 { - return errors.New("did not find uninitialised hash value in object file") - } - - if bytes.Index(objectBytes[offset+1:], fipscommon.UninitHashValue[:]) >= 0 { - return errors.New("found two occurrences of uninitialised hash value in object file") - } - - copy(objectBytes[offset:], calculated) - - return ioutil.WriteFile(outPath, objectBytes, 0644) -} - -func main() { - arInput := flag.String("in-archive", "", "Path to a .a file") - oInput := flag.String("in-object", "", "Path to a .o file") - outPath := flag.String("o", "", "Path to output object") - - flag.Parse() - - if err := do(*outPath, *oInput, *arInput); err != nil { - fmt.Fprintf(os.Stderr, "%s\n", err) - os.Exit(1) - } -} diff --git a/src/util/fipstools/inject_hash/inject_hash.go b/src/util/fipstools/inject_hash/inject_hash.go new file mode 100644 index 00000000..29307c03 --- /dev/null +++ b/src/util/fipstools/inject_hash/inject_hash.go @@ -0,0 +1,176 @@ +// Copyright (c) 2017, 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. */ + +// inject_hash parses an archive containing a file object file. It finds a FIPS +// module inside that object, calculates its hash and replaces the default hash +// value in the object with the calculated value. +package main + +import ( + "bytes" + "crypto/hmac" + "crypto/sha512" + "debug/elf" + "errors" + "flag" + "fmt" + "io" + "io/ioutil" + "os" + + "boringssl.googlesource.com/boringssl/util/ar" + "boringssl.googlesource.com/boringssl/util/fipstools/fipscommon" +) + +func do(outPath, oInput string, arInput string) error { + var objectBytes []byte + if len(arInput) > 0 { + if len(oInput) > 0 { + return fmt.Errorf("-in-archive and -in-object are mutually exclusive") + } + + arFile, err := os.Open(arInput) + if err != nil { + return err + } + defer arFile.Close() + + ar, err := ar.ParseAR(arFile) + if err != nil { + return err + } + + if len(ar) != 1 { + return fmt.Errorf("expected one file in archive, but found %d", len(ar)) + } + + for _, contents := range ar { + objectBytes = contents + } + } else if len(oInput) > 0 { + var err error + if objectBytes, err = ioutil.ReadFile(oInput); err != nil { + return err + } + } else { + return fmt.Errorf("exactly one of -in-archive or -in-object is required") + } + + object, err := elf.NewFile(bytes.NewReader(objectBytes)) + if err != nil { + return errors.New("failed to parse object: " + err.Error()) + } + + // Find the .text section. + + var textSection *elf.Section + var textSectionIndex elf.SectionIndex + for i, section := range object.Sections { + if section.Name == ".text" { + textSectionIndex = elf.SectionIndex(i) + textSection = section + break + } + } + + if textSection == nil { + return errors.New("failed to find .text section in object") + } + + // Find the starting and ending symbols for the module. + + var startSeen, endSeen bool + var start, end uint64 + + symbols, err := object.Symbols() + if err != nil { + return errors.New("failed to parse symbols: " + err.Error()) + } + + for _, symbol := range symbols { + if symbol.Section != textSectionIndex { + continue + } + + switch symbol.Name { + case "BORINGSSL_bcm_text_start": + if startSeen { + return errors.New("duplicate start symbol found") + } + startSeen = true + start = symbol.Value + case "BORINGSSL_bcm_text_end": + if endSeen { + return errors.New("duplicate end symbol found") + } + endSeen = true + end = symbol.Value + default: + continue + } + } + + if !startSeen || !endSeen { + return errors.New("could not find module boundaries in object") + } + + if max := textSection.Size; start > max || start > end || end > max { + return fmt.Errorf("invalid module boundaries: start: %x, end: %x, max: %x", start, end, max) + } + + // Extract the module from the .text section and hash it. + + text := textSection.Open() + if _, err := text.Seek(int64(start), 0); err != nil { + return errors.New("failed to seek to module start in .text: " + err.Error()) + } + moduleText := make([]byte, end-start) + if _, err := io.ReadFull(text, moduleText); err != nil { + return errors.New("failed to read .text: " + err.Error()) + } + + var zeroKey [64]byte + mac := hmac.New(sha512.New, zeroKey[:]) + mac.Write(moduleText) + calculated := mac.Sum(nil) + + // Replace the default hash value in the object with the calculated + // value and write it out. + + offset := bytes.Index(objectBytes, fipscommon.UninitHashValue[:]) + if offset < 0 { + return errors.New("did not find uninitialised hash value in object file") + } + + if bytes.Index(objectBytes[offset+1:], fipscommon.UninitHashValue[:]) >= 0 { + return errors.New("found two occurrences of uninitialised hash value in object file") + } + + copy(objectBytes[offset:], calculated) + + return ioutil.WriteFile(outPath, objectBytes, 0644) +} + +func main() { + arInput := flag.String("in-archive", "", "Path to a .a file") + oInput := flag.String("in-object", "", "Path to a .o file") + outPath := flag.String("o", "", "Path to output object") + + flag.Parse() + + if err := do(*outPath, *oInput, *arInput); err != nil { + fmt.Fprintf(os.Stderr, "%s\n", err) + os.Exit(1) + } +} diff --git a/src/util/read_symbols.go b/src/util/read_symbols.go new file mode 100644 index 00000000..5e3a1776 --- /dev/null +++ b/src/util/read_symbols.go @@ -0,0 +1,170 @@ +// Copyright (c) 2018, 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. + +// read_symbols.go scans one or more .a files and, for each object contained in +// the .a files, reads the list of symbols in that object file. +package main + +import ( + "bytes" + "debug/elf" + "debug/macho" + "flag" + "fmt" + "os" + "runtime" + "sort" + "strings" + + "boringssl.googlesource.com/boringssl/util/ar" +) + +const ( + ObjFileFormatELF = "elf" + ObjFileFormatMachO = "macho" +) + +var outFlag = flag.String("out", "-", "File to write output symbols") +var objFileFormat = flag.String("obj-file-format", defaultObjFileFormat(runtime.GOOS), "Object file format to expect (options are elf, macho)") + +func defaultObjFileFormat(goos string) string { + switch goos { + case "linux": + return ObjFileFormatELF + case "darwin": + return ObjFileFormatMachO + default: + // By returning a value here rather than panicking, the user can still + // cross-compile from an unsupported platform to a supported platform by + // overriding this default with a flag. If the user doesn't provide the + // flag, we will panic during flag parsing. + return "unsupported" + } +} + +func main() { + flag.Parse() + if flag.NArg() < 1 { + fmt.Fprintf(os.Stderr, "Usage: %s [-out OUT] [-obj-file-format FORMAT] ARCHIVE_FILE [ARCHIVE_FILE [...]]\n", os.Args[0]) + os.Exit(1) + } + archiveFiles := flag.Args() + + out := os.Stdout + if *outFlag != "-" { + var err error + out, err = os.Create(*outFlag) + nilOrPanic(err, "failed to open output file") + defer out.Close() + } + + var symbols []string + // Only add first instance of any symbol; keep track of them in this map. + added := make(map[string]bool) + for _, archive := range archiveFiles { + f, err := os.Open(archive) + nilOrPanic(err, "failed to open archive file %s", archive) + objectFiles, err := ar.ParseAR(f) + nilOrPanic(err, "failed to read archive file %s", archive) + + for name, contents := range objectFiles { + if !strings.HasSuffix(name, ".o") { + continue + } + for _, s := range listSymbols(name, contents) { + if !added[s] { + added[s] = true + symbols = append(symbols, s) + } + } + } + } + sort.Strings(symbols) + for _, s := range symbols { + // Filter out C++ mangled names. + prefix := "_Z" + if runtime.GOOS == "darwin" { + prefix = "__Z" + } + if !strings.HasPrefix(s, prefix) { + fmt.Fprintln(out, s) + } + } +} + +// listSymbols lists the exported symbols from an object file. +func listSymbols(name string, contents []byte) []string { + switch *objFileFormat { + case ObjFileFormatELF: + return listSymbolsELF(name, contents) + case ObjFileFormatMachO: + return listSymbolsMachO(name, contents) + default: + panic(fmt.Errorf("unsupported object file format %v", *objFileFormat)) + } +} + +func listSymbolsELF(name string, contents []byte) []string { + f, err := elf.NewFile(bytes.NewReader(contents)) + nilOrPanic(err, "failed to parse ELF file %s", name) + syms, err := f.Symbols() + nilOrPanic(err, "failed to read symbol names from ELF file %s", name) + + var names []string + for _, sym := range syms { + // Only include exported, defined symbols + if elf.ST_BIND(sym.Info) != elf.STB_LOCAL && sym.Section != elf.SHN_UNDEF { + names = append(names, sym.Name) + } + } + return names +} + +func listSymbolsMachO(name string, contents []byte) []string { + f, err := macho.NewFile(bytes.NewReader(contents)) + nilOrPanic(err, "failed to parse Mach-O file %s", name) + if f.Symtab == nil { + return nil + } + var names []string + for _, sym := range f.Symtab.Syms { + // Source: https://opensource.apple.com/source/xnu/xnu-3789.51.2/EXTERNAL_HEADERS/mach-o/nlist.h.auto.html + const ( + N_PEXT uint8 = 0x10 // Private external symbol bit + N_EXT uint8 = 0x01 // External symbol bit, set for external symbols + N_TYPE uint8 = 0x0e // mask for the type bits + + N_UNDF uint8 = 0x0 // undefined, n_sect == NO_SECT + N_ABS uint8 = 0x2 // absolute, n_sect == NO_SECT + N_SECT uint8 = 0xe // defined in section number n_sect + N_PBUD uint8 = 0xc // prebound undefined (defined in a dylib) + N_INDR uint8 = 0xa // indirect + ) + + // Only include exported, defined symbols. + if sym.Type&N_EXT != 0 && sym.Type&N_TYPE != N_UNDF { + if len(sym.Name) == 0 || sym.Name[0] != '_' { + panic(fmt.Errorf("unexpected symbol without underscore prefix: %v", sym.Name)) + } + names = append(names, sym.Name[1:]) + } + } + return names +} + +func nilOrPanic(err error, f string, args ...interface{}) { + if err != nil { + panic(fmt.Errorf(f+": %v", append(args, err)...)) + } +} -- cgit v1.2.3