summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRobert Sloan <varomodt@google.com>2017-08-07 09:03:39 -0700
committerRobert Sloan <varomodt@google.com>2017-08-07 09:05:18 -0700
commitfe7cd2122ef131c19c9db15672594fd4f0232496 (patch)
tree5767e1d34655e6208282919746d8e936fb6ac1f7 /src
parentb6d070c5081ba0ca11545eb50870817d6d72d926 (diff)
downloadboringssl-fe7cd2122ef131c19c9db15672594fd4f0232496.tar.gz
external/boringssl: Sync to 9bbdf5832de8a2d395303c669b594fc61c791f4d.
This includes the following changes: https://boringssl.googlesource.com/boringssl/+log/c642aca28feb7e18f244658559f4042286aed0c8..9bbdf5832de8a2d395303c669b594fc61c791f4d Test: BoringSSL CTS Presubmits. Change-Id: Ieb6fcfee99c4cc496b2f6e1d3e6597784bd80189
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt13
-rw-r--r--src/PORTING.md28
-rw-r--r--src/crypto/asn1/asn1_locl.h2
-rw-r--r--src/crypto/asn1/time_support.c10
-rw-r--r--src/crypto/buf/buf.c24
-rwxr-xr-xsrc/crypto/chacha/asm/chacha-x86_64.pl6
-rw-r--r--src/crypto/cipher_extra/e_aesctrhmac.c2
-rw-r--r--src/crypto/cipher_extra/e_aesgcmsiv.c4
-rw-r--r--src/crypto/cipher_extra/e_chacha20poly1305.c107
-rw-r--r--src/crypto/cipher_extra/e_ssl3.c39
-rw-r--r--src/crypto/cipher_extra/e_tls.c50
-rw-r--r--src/crypto/compiler_test.cc15
-rw-r--r--src/crypto/cpu-intel.c29
-rw-r--r--src/crypto/dh/check.c36
-rw-r--r--src/crypto/dsa/dsa.c36
-rw-r--r--src/crypto/fipsmodule/aes/asm/aesni-x86_64.pl2
-rw-r--r--src/crypto/fipsmodule/cipher/aead.c18
-rw-r--r--src/crypto/fipsmodule/cipher/e_aes.c7
-rw-r--r--src/crypto/fipsmodule/cipher/internal.h3
-rw-r--r--src/crypto/fipsmodule/modes/asm/aesni-gcm-x86_64.pl11
-rw-r--r--src/crypto/fipsmodule/modes/asm/ghash-x86_64.pl12
-rw-r--r--src/crypto/fipsmodule/rand/ctrdrbg_test.cc8
-rw-r--r--src/crypto/fipsmodule/rand/rand.c2
-rw-r--r--src/crypto/fipsmodule/rsa/rsa.c8
-rwxr-xr-xsrc/crypto/fipsmodule/sha/asm/sha1-x86_64.pl15
-rwxr-xr-xsrc/crypto/fipsmodule/sha/asm/sha512-x86_64.pl12
-rw-r--r--src/crypto/mem.c47
-rw-r--r--src/crypto/rand_extra/rand_extra.c2
-rw-r--r--src/crypto/test/file_test.cc3
-rw-r--r--src/crypto/x509/x509_vfy.c9
-rw-r--r--src/crypto/x509/x_name.c2
-rw-r--r--src/crypto/x509v3/v3_utl.c8
-rw-r--r--src/include/openssl/aead.h9
-rw-r--r--src/include/openssl/asn1.h2
-rw-r--r--src/include/openssl/base.h20
-rw-r--r--src/include/openssl/bio.h4
-rw-r--r--src/include/openssl/buf.h4
-rw-r--r--src/include/openssl/curve25519.h2
-rw-r--r--src/include/openssl/dsa.h4
-rw-r--r--src/include/openssl/mem.h7
-rw-r--r--src/include/openssl/pool.h2
-rw-r--r--src/include/openssl/rand.h3
-rw-r--r--src/include/openssl/rsa.h4
-rw-r--r--src/include/openssl/span.h163
-rw-r--r--src/include/openssl/ssl.h133
-rw-r--r--src/include/openssl/stack.h144
-rw-r--r--src/include/openssl/x509.h14
-rw-r--r--src/include/openssl/x509_vfy.h1
-rw-r--r--src/include/openssl/x509v3.h6
-rw-r--r--src/ssl/CMakeLists.txt1
-rw-r--r--src/ssl/d1_both.cc112
-rw-r--r--src/ssl/d1_lib.cc25
-rw-r--r--src/ssl/d1_pkt.cc42
-rw-r--r--src/ssl/dtls_method.cc14
-rw-r--r--src/ssl/handshake_client.cc26
-rw-r--r--src/ssl/handshake_server.cc74
-rw-r--r--src/ssl/internal.h131
-rw-r--r--src/ssl/s3_both.cc6
-rw-r--r--src/ssl/span_test.cc90
-rw-r--r--src/ssl/ssl_aead_ctx.cc59
-rw-r--r--src/ssl/ssl_asn1.cc11
-rw-r--r--src/ssl/ssl_cert.cc113
-rw-r--r--src/ssl/ssl_cipher.cc12
-rw-r--r--src/ssl/ssl_lib.cc24
-rw-r--r--src/ssl/ssl_privkey.cc57
-rw-r--r--src/ssl/ssl_session.cc52
-rw-r--r--src/ssl/ssl_test.cc249
-rw-r--r--src/ssl/ssl_x509.cc217
-rw-r--r--src/ssl/t1_lib.cc36
-rw-r--r--src/ssl/test/bssl_shim.cc102
-rw-r--r--src/ssl/test/runner/common.go5
-rw-r--r--src/ssl/test/runner/conn.go9
-rw-r--r--src/ssl/test/runner/dtls.go17
-rw-r--r--src/ssl/test/runner/handshake_client.go5
-rw-r--r--src/ssl/test/runner/handshake_server.go9
-rw-r--r--src/ssl/test/runner/runner.go138
-rw-r--r--src/ssl/test/test_config.cc1
-rw-r--r--src/ssl/test/test_config.h1
-rw-r--r--src/ssl/tls13_both.cc28
-rw-r--r--src/ssl/tls13_client.cc1
-rw-r--r--src/ssl/tls13_server.cc26
-rw-r--r--src/ssl/tls_method.cc7
-rw-r--r--src/ssl/tls_record.cc209
-rw-r--r--src/tool/rand.cc2
-rw-r--r--src/tool/speed.cc44
-rw-r--r--src/tool/transport_common.cc79
-rw-r--r--src/util/BUILD.toplevel57
-rw-r--r--src/util/all_tests.go1
-rw-r--r--src/util/check_imported_libraries.go56
-rw-r--r--src/util/convert_comments.go258
-rw-r--r--src/util/doc.go63
-rw-r--r--src/util/generate_build_files.py2
92 files changed, 2579 insertions, 984 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 3c2d5562..dc6e0d2f 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -32,17 +32,26 @@ if (NOT GO_EXECUTABLE)
message(FATAL_ERROR "Could not find Go")
endif()
+if (BORINGSSL_ALLOW_CXX_RUNTIME)
+ add_definitions(-DBORINGSSL_ALLOW_CXX_RUNTIME)
+endif()
+
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(C_CXX_FLAGS "-Wall -Werror -Wformat=2 -Wsign-compare -Wmissing-field-initializers -Wwrite-strings -ggdb -fvisibility=hidden -fno-common")
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
- set(C_CXX_FLAGS "${C_CXX_FLAGS} -Wnewline-eof")
+ set(C_CXX_FLAGS "${C_CXX_FLAGS} -Wnewline-eof -fcolor-diagnostics")
else()
# GCC (at least 4.8.4) has a bug where it'll find unreachable free() calls
# and declare that the code is trying to free a stack pointer.
set(C_CXX_FLAGS "${C_CXX_FLAGS} -Wno-free-nonheap-object")
endif()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${C_CXX_FLAGS} -Wmissing-prototypes -Wold-style-definition -Wstrict-prototypes")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 ${C_CXX_FLAGS} -Wmissing-declarations -fno-exceptions")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 ${C_CXX_FLAGS} -Wmissing-declarations")
+
+ if(NOT BORINGSSL_ALLOW_CXX_RUNTIME)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions -fno-rtti")
+ endif()
+
# In GCC, -Wmissing-declarations is the C++ spelling of -Wmissing-prototypes
# and using the wrong one is an error. In Clang, -Wmissing-prototypes is the
# spelling for both and -Wmissing-declarations is some other warning.
diff --git a/src/PORTING.md b/src/PORTING.md
index b9d67523..ca9f6a44 100644
--- a/src/PORTING.md
+++ b/src/PORTING.md
@@ -116,7 +116,9 @@ response in (unpipelined) HTTP/1.1.
Things which do not work:
-* There is no support for renegotiation as a server.
+* There is no support for renegotiation as a server. (Attempts by clients will
+ result in a fatal alert so that ClientHello messages cannot be used to flood
+ a server and escape higher-level limits.)
* There is no support for renegotiation in DTLS.
@@ -247,3 +249,27 @@ parameter.
`SSL_CTRL_SET_TMP_ECDH_CB` | `SSL_CTX_set_tmp_ecdh_callback`
`SSL_CTRL_SET_TMP_RSA` | `SSL_CTX_set_tmp_rsa` is equivalent, but [*do not use this function*](https://freakattack.com/). (It is a no-op in BoringSSL.)
`SSL_CTRL_SET_TMP_RSA_CB` | `SSL_CTX_set_tmp_rsa_callback` is equivalent, but [*do not use this function*](https://freakattack.com/). (It is a no-op in BoringSSL.)
+
+## Significant API additions
+
+In some places, BoringSSL has added significant APIs. Use of these APIs goes beyound “porting” and means giving up on OpenSSL compatibility.
+
+One example of this has already been mentioned: the [CBS and CBB](https://commondatastorage.googleapis.com/chromium-boringssl-docs/bytestring.h.html) functions should be used whenever parsing or serialising data.
+
+### CRYPTO\_BUFFER
+
+With the standard OpenSSL APIs, when making many TLS connections, the certificate data for each connection is retained in memory in an expensive `X509` structure. Additionally, common certificates often appear in the chains for multiple connections and are needlessly duplicated in memory.
+
+A [`CRYPTO_BUFFER`](https://commondatastorage.googleapis.com/chromium-boringssl-docs/pool.h.html) is just an opaque byte string. A `CRYPTO_BUFFER_POOL` is an intern table for these buffers, i.e. it ensures that only a single copy of any given byte string is kept for each pool.
+
+The function `TLS_with_buffers_method` returns an `SSL_METHOD` that avoids creating `X509` objects for certificates. Additionally, `SSL_CTX_set0_buffer_pool` can be used to install a pool on an `SSL_CTX` so that certificates can be deduplicated across connections and across `SSL_CTX`s.
+
+When using these functions, the application also needs to ensure that it doesn't call other functions that deal with `X509` or `X509_NAME` objects. For example, `SSL_get_peer_certificate` or `SSL_get_peer_cert_chain`. Doing so will trigger an assert in debug mode and will result in NULLs in release mode. Instead, call the buffer-based alternatives such as `SSL_get0_peer_certificates`. (See [ssl.h](https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html) for functions taking or returning `CRYPTO_BUFFER`.) The buffer-based alternative functions will work even when not using `TLS_with_buffers_method`, thus application code can transition gradually.
+
+In order to use buffers, the application code also needs to implement its own certificate verification using `SSL_[CTX_]set_custom_verify`. Otherwise all connections will fail with a verification error. Auto-chaining is also disabled when using buffers.
+
+Once those changes have been completed, the whole of the OpenSSL X.509 and ASN.1 code should be eliminated by the linker if BoringSSL is linked statically.
+
+### Asynchronous and opaque private keys
+
+OpenSSL offers the ENGINE API for implementing opaque private keys (i.e. private keys where software only has oracle access because the secrets are held in special hardware or on another machine). While the ENGINE API has been mostly removed from BoringSSL, it is still possible to support opaque keys in this way. However, when using such keys with TLS and BoringSSL, you should strongly prefer using `SSL_PRIVATE_KEY_METHOD` via `SSL[_CTX]_set_private_key_method`. This allows a handshake to be suspended while the private operation is in progress. It also supports more forms of opaque key as it exposes higher-level information about the operation to be performed.
diff --git a/src/crypto/asn1/asn1_locl.h b/src/crypto/asn1/asn1_locl.h
index ce8146bf..fef00acf 100644
--- a/src/crypto/asn1/asn1_locl.h
+++ b/src/crypto/asn1/asn1_locl.h
@@ -72,7 +72,7 @@ extern "C" {
/* Wrapper functions for time functions. */
/* OPENSSL_gmtime wraps |gmtime_r|. See the manual page for that function. */
-struct tm *OPENSSL_gmtime(const time_t *timer, struct tm *result);
+struct tm *OPENSSL_gmtime(const time_t *time, struct tm *result);
/* OPENSSL_gmtime_adj updates |tm| by adding |offset_day| days and |offset_sec|
* seconds. */
diff --git a/src/crypto/asn1/time_support.c b/src/crypto/asn1/time_support.c
index 194dc3a7..3efd43e2 100644
--- a/src/crypto/asn1/time_support.c
+++ b/src/crypto/asn1/time_support.c
@@ -171,7 +171,7 @@ int OPENSSL_gmtime_adj(struct tm *tm, int off_day, long offset_sec) {
return 1;
}
-int OPENSSL_gmtime_diff(int *pday, int *psec, const struct tm *from,
+int OPENSSL_gmtime_diff(int *out_days, int *out_secs, const struct tm *from,
const struct tm *to) {
int from_sec, to_sec, diff_sec;
long from_jd, to_jd, diff_day;
@@ -195,11 +195,11 @@ int OPENSSL_gmtime_diff(int *pday, int *psec, const struct tm *from,
diff_sec -= SECS_PER_DAY;
}
- if (pday) {
- *pday = (int)diff_day;
+ if (out_days) {
+ *out_days = (int)diff_day;
}
- if (psec) {
- *psec = diff_sec;
+ if (out_secs) {
+ *out_secs = diff_sec;
}
return 1;
diff --git a/src/crypto/buf/buf.c b/src/crypto/buf/buf.c
index ca1d70b0..f1fcae64 100644
--- a/src/crypto/buf/buf.c
+++ b/src/crypto/buf/buf.c
@@ -153,12 +153,12 @@ size_t BUF_MEM_grow_clean(BUF_MEM *buf, size_t len) {
return buf_mem_grow(buf, len, 1 /* clear old buffer contents. */);
}
-char *BUF_strdup(const char *buf) {
- if (buf == NULL) {
+char *BUF_strdup(const char *str) {
+ if (str == NULL) {
return NULL;
}
- return BUF_strndup(buf, strlen(buf));
+ return BUF_strndup(str, strlen(str));
}
size_t BUF_strnlen(const char *str, size_t max_len) {
@@ -173,15 +173,15 @@ size_t BUF_strnlen(const char *str, size_t max_len) {
return i;
}
-char *BUF_strndup(const char *buf, size_t size) {
+char *BUF_strndup(const char *str, size_t size) {
char *ret;
size_t alloc_size;
- if (buf == NULL) {
+ if (str == NULL) {
return NULL;
}
- size = BUF_strnlen(buf, size);
+ size = BUF_strnlen(str, size);
alloc_size = size + 1;
if (alloc_size < size) {
@@ -195,7 +195,7 @@ char *BUF_strndup(const char *buf, size_t size) {
return NULL;
}
- OPENSSL_memcpy(ret, buf, size);
+ OPENSSL_memcpy(ret, str, size);
ret[size] = '\0';
return ret;
}
@@ -223,19 +223,17 @@ size_t BUF_strlcat(char *dst, const char *src, size_t dst_size) {
return l + BUF_strlcpy(dst, src, dst_size);
}
-void *BUF_memdup(const void *data, size_t dst_size) {
- void *ret;
-
- if (dst_size == 0) {
+void *BUF_memdup(const void *data, size_t size) {
+ if (size == 0) {
return NULL;
}
- ret = OPENSSL_malloc(dst_size);
+ void *ret = OPENSSL_malloc(size);
if (ret == NULL) {
OPENSSL_PUT_ERROR(BUF, ERR_R_MALLOC_FAILURE);
return NULL;
}
- OPENSSL_memcpy(ret, data, dst_size);
+ OPENSSL_memcpy(ret, data, size);
return ret;
}
diff --git a/src/crypto/chacha/asm/chacha-x86_64.pl b/src/crypto/chacha/asm/chacha-x86_64.pl
index 5ab6f879..6b2065e0 100755
--- a/src/crypto/chacha/asm/chacha-x86_64.pl
+++ b/src/crypto/chacha/asm/chacha-x86_64.pl
@@ -24,7 +24,7 @@
#
# Performance in cycles per byte out of large buffer.
#
-# IALU/gcc 4.8(i) 1xSSSE3/SSE2 4xSSSE3 8xAVX2
+# IALU/gcc 4.8(i) 1xSSSE3/SSE2 4xSSSE3 NxAVX(v)
#
# P4 9.48/+99% -/22.7(ii) -
# Core2 7.83/+55% 7.90/8.08 4.35
@@ -32,11 +32,13 @@
# Sandy Bridge 8.31/+42% 5.45/6.76 2.72
# Ivy Bridge 6.71/+46% 5.40/6.49 2.41
# Haswell 5.92/+43% 5.20/6.45 2.42 1.23
-# Skylake 5.87/+39% 4.70/- 2.31 1.19
+# Skylake[-X] 5.87/+39% 4.70/- 2.31 1.19[0.57]
# Silvermont 12.0/+33% 7.75/7.40 7.03(iii)
+# Knights L 11.7/- - 9.60(iii) 0.80
# Goldmont 10.6/+17% 5.10/- 3.28
# Sledgehammer 7.28/+52% -/14.2(ii) -
# Bulldozer 9.66/+28% 9.85/11.1 3.06(iv)
+# Ryzen 5.96/+50% 5.19/- 2.40 2.09
# VIA Nano 10.5/+46% 6.72/8.60 6.05
#
# (i) compared to older gcc 3.x one can observe >2x improvement on
diff --git a/src/crypto/cipher_extra/e_aesctrhmac.c b/src/crypto/cipher_extra/e_aesctrhmac.c
index 2982d0de..3034b8ff 100644
--- a/src/crypto/cipher_extra/e_aesctrhmac.c
+++ b/src/crypto/cipher_extra/e_aesctrhmac.c
@@ -254,6 +254,7 @@ static const EVP_AEAD aead_aes_128_ctr_hmac_sha256 = {
aead_aes_ctr_hmac_sha256_seal_scatter,
aead_aes_ctr_hmac_sha256_open_gather,
NULL /* get_iv */,
+ NULL /* tag_len */,
};
static const EVP_AEAD aead_aes_256_ctr_hmac_sha256 = {
@@ -270,6 +271,7 @@ static const EVP_AEAD aead_aes_256_ctr_hmac_sha256 = {
aead_aes_ctr_hmac_sha256_seal_scatter,
aead_aes_ctr_hmac_sha256_open_gather,
NULL /* get_iv */,
+ NULL /* tag_len */,
};
const EVP_AEAD *EVP_aead_aes_128_ctr_hmac_sha256(void) {
diff --git a/src/crypto/cipher_extra/e_aesgcmsiv.c b/src/crypto/cipher_extra/e_aesgcmsiv.c
index 2dd12670..6adcf17a 100644
--- a/src/crypto/cipher_extra/e_aesgcmsiv.c
+++ b/src/crypto/cipher_extra/e_aesgcmsiv.c
@@ -520,6 +520,7 @@ static const EVP_AEAD aead_aes_128_gcm_siv_asm = {
aead_aes_gcm_siv_asm_seal_scatter,
NULL /* open_gather */,
NULL /* get_iv */,
+ NULL /* tag_len */,
};
static const EVP_AEAD aead_aes_256_gcm_siv_asm = {
@@ -536,6 +537,7 @@ static const EVP_AEAD aead_aes_256_gcm_siv_asm = {
aead_aes_gcm_siv_asm_seal_scatter,
NULL /* open_gather */,
NULL /* get_iv */,
+ NULL /* tag_len */,
};
#endif /* X86_64 && !NO_ASM */
@@ -804,6 +806,7 @@ static const EVP_AEAD aead_aes_128_gcm_siv = {
aead_aes_gcm_siv_seal_scatter,
aead_aes_gcm_siv_open_gather,
NULL /* get_iv */,
+ NULL /* tag_len */,
};
static const EVP_AEAD aead_aes_256_gcm_siv = {
@@ -820,6 +823,7 @@ static const EVP_AEAD aead_aes_256_gcm_siv = {
aead_aes_gcm_siv_seal_scatter,
aead_aes_gcm_siv_open_gather,
NULL /* get_iv */,
+ NULL /* tag_len */,
};
#if defined(OPENSSL_X86_64) && !defined(OPENSSL_NO_ASM)
diff --git a/src/crypto/cipher_extra/e_chacha20poly1305.c b/src/crypto/cipher_extra/e_chacha20poly1305.c
index 515b60f2..8946f1ff 100644
--- a/src/crypto/cipher_extra/e_chacha20poly1305.c
+++ b/src/crypto/cipher_extra/e_chacha20poly1305.c
@@ -22,6 +22,7 @@
#include <openssl/err.h>
#include <openssl/mem.h>
#include <openssl/poly1305.h>
+#include <openssl/type_check.h>
#include "../fipsmodule/cipher/internal.h"
#include "../internal.h"
@@ -30,7 +31,34 @@
#define POLY1305_TAG_LEN 16
struct aead_chacha20_poly1305_ctx {
- unsigned char key[32];
+ uint8_t key[32];
+};
+
+// For convenience (the x86_64 calling convention allows only six parameters in
+// registers), the final parameter for the assembly functions is both an input
+// and output parameter.
+union open_data {
+ struct {
+ alignas(16) uint8_t key[32];
+ uint32_t counter;
+ uint8_t nonce[12];
+ } in;
+ struct {
+ uint8_t tag[POLY1305_TAG_LEN];
+ } out;
+};
+
+union seal_data {
+ struct {
+ alignas(16) uint8_t key[32];
+ uint32_t counter;
+ uint8_t nonce[12];
+ const uint8_t *extra_ciphertext;
+ size_t extra_ciphertext_len;
+ } in;
+ struct {
+ uint8_t tag[POLY1305_TAG_LEN];
+ } out;
};
#if defined(OPENSSL_X86_64) && !defined(OPENSSL_NO_ASM) && \
@@ -40,42 +68,42 @@ static int asm_capable(void) {
return sse41_capable;
}
-// chacha20_poly1305_open is defined in chacha20_poly1305_x86_64.pl. It
-// decrypts |plaintext_len| bytes from |ciphertext| and writes them to
-// |out_plaintext|. On entry, |aead_data| must contain the final 48 bytes of
-// the initial ChaCha20 block, i.e. the key, followed by four zeros, followed
-// by the nonce. On exit, it will contain the calculated tag value, which the
-// caller must check.
+OPENSSL_COMPILE_ASSERT(sizeof(union open_data) == 48, wrong_open_data_size);
+OPENSSL_COMPILE_ASSERT(sizeof(union seal_data) == 48 + 8 + 8,
+ wrong_seal_data_size);
+
+// chacha20_poly1305_open is defined in chacha20_poly1305_x86_64.pl. It decrypts
+// |plaintext_len| bytes from |ciphertext| and writes them to |out_plaintext|.
+// Additional input parameters are passed in |aead_data->in|. On exit, it will
+// write calculated tag value to |aead_data->out.tag|, which the caller must
+// check.
extern void chacha20_poly1305_open(uint8_t *out_plaintext,
const uint8_t *ciphertext,
size_t plaintext_len, const uint8_t *ad,
- size_t ad_len, uint8_t *aead_data);
-
-// chacha20_poly1305_open is defined in chacha20_poly1305_x86_64.pl. It
-// encrypts |plaintext_len| bytes from |plaintext| and writes them to
-// |out_ciphertext|. On entry, |aead_data| must contain the final 48 bytes of
-// the initial ChaCha20 block, i.e. the key, followed by four zeros, followed
-// by the nonce. On exit, it will contain the calculated tag value, which the
-// caller must append to the ciphertext.
+ size_t ad_len, union open_data *aead_data);
+
+// chacha20_poly1305_open is defined in chacha20_poly1305_x86_64.pl. It encrypts
+// |plaintext_len| bytes from |plaintext| and writes them to |out_ciphertext|.
+// Additional input parameters are passed in |aead_data->in|. The calculated tag
+// value is over the computed ciphertext concatenated with |extra_ciphertext|
+// and written to |aead_data->out.tag|.
extern void chacha20_poly1305_seal(uint8_t *out_ciphertext,
const uint8_t *plaintext,
size_t plaintext_len, const uint8_t *ad,
- size_t ad_len, uint8_t *aead_data);
+ size_t ad_len, union seal_data *aead_data);
#else
-static int asm_capable(void) {
- return 0;
-}
+static int asm_capable(void) { return 0; }
static void chacha20_poly1305_open(uint8_t *out_plaintext,
const uint8_t *ciphertext,
size_t plaintext_len, const uint8_t *ad,
- size_t ad_len, uint8_t *aead_data) {}
+ size_t ad_len, union open_data *aead_data) {}
static void chacha20_poly1305_seal(uint8_t *out_ciphertext,
const uint8_t *plaintext,
size_t plaintext_len, const uint8_t *ad,
- size_t ad_len, uint8_t *aead_data) {}
+ size_t ad_len, union seal_data *aead_data) {}
#endif
static int aead_chacha20_poly1305_init(EVP_AEAD_CTX *ctx, const uint8_t *key,
@@ -212,22 +240,21 @@ static int aead_chacha20_poly1305_seal_scatter(
}
}
- alignas(16) uint8_t tag[48 + 8 + 8];
-
+ union seal_data data;
if (asm_capable()) {
- OPENSSL_memcpy(tag, c20_ctx->key, 32);
- OPENSSL_memset(tag + 32, 0, 4);
- OPENSSL_memcpy(tag + 32 + 4, nonce, 12);
- OPENSSL_memcpy(tag + 48, &out_tag, sizeof(out_tag));
- OPENSSL_memcpy(tag + 56, &extra_in_len, sizeof(extra_in_len));
- chacha20_poly1305_seal(out, in, in_len, ad, ad_len, tag);
+ OPENSSL_memcpy(data.in.key, c20_ctx->key, 32);
+ data.in.counter = 0;
+ OPENSSL_memcpy(data.in.nonce, nonce, 12);
+ data.in.extra_ciphertext = out_tag;
+ data.in.extra_ciphertext_len = extra_in_len;
+ chacha20_poly1305_seal(out, in, in_len, ad, ad_len, &data);
} else {
CRYPTO_chacha_20(out, in, in_len, c20_ctx->key, nonce, 1);
- calc_tag(tag, c20_ctx, nonce, ad, ad_len, out, in_len,
- out_tag, extra_in_len);
+ calc_tag(data.out.tag, c20_ctx, nonce, ad, ad_len, out, in_len, out_tag,
+ extra_in_len);
}
- OPENSSL_memcpy(out_tag + extra_in_len, tag, ctx->tag_len);
+ OPENSSL_memcpy(out_tag + extra_in_len, data.out.tag, ctx->tag_len);
*out_tag_len = extra_in_len + ctx->tag_len;
return 1;
}
@@ -260,19 +287,18 @@ static int aead_chacha20_poly1305_open_gather(
return 0;
}
- alignas(16) uint8_t tag[48];
-
+ union open_data data;
if (asm_capable()) {
- OPENSSL_memcpy(tag, c20_ctx->key, 32);
- OPENSSL_memset(tag + 32, 0, 4);
- OPENSSL_memcpy(tag + 32 + 4, nonce, 12);
- chacha20_poly1305_open(out, in, in_len, ad, ad_len, tag);
+ OPENSSL_memcpy(data.in.key, c20_ctx->key, 32);
+ data.in.counter = 0;
+ OPENSSL_memcpy(data.in.nonce, nonce, 12);
+ chacha20_poly1305_open(out, in, in_len, ad, ad_len, &data);
} else {
- calc_tag(tag, c20_ctx, nonce, ad, ad_len, in, in_len, NULL, 0);
+ calc_tag(data.out.tag, c20_ctx, nonce, ad, ad_len, in, in_len, NULL, 0);
CRYPTO_chacha_20(out, in, in_len, c20_ctx->key, nonce, 1);
}
- if (CRYPTO_memcmp(tag, in_tag, ctx->tag_len) != 0) {
+ if (CRYPTO_memcmp(data.out.tag, in_tag, ctx->tag_len) != 0) {
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
return 0;
}
@@ -294,6 +320,7 @@ static const EVP_AEAD aead_chacha20_poly1305 = {
aead_chacha20_poly1305_seal_scatter,
aead_chacha20_poly1305_open_gather,
NULL, /* get_iv */
+ NULL, /* tag_len */
};
const EVP_AEAD *EVP_aead_chacha20_poly1305(void) {
diff --git a/src/crypto/cipher_extra/e_ssl3.c b/src/crypto/cipher_extra/e_ssl3.c
index f2eb357c..dc437136 100644
--- a/src/crypto/cipher_extra/e_ssl3.c
+++ b/src/crypto/cipher_extra/e_ssl3.c
@@ -123,13 +123,33 @@ static int aead_ssl3_init(EVP_AEAD_CTX *ctx, const uint8_t *key, size_t key_len,
return 1;
}
+static size_t aead_ssl3_tag_len(const EVP_AEAD_CTX *ctx, const size_t in_len,
+ const size_t extra_in_len) {
+ assert(extra_in_len == 0);
+ const AEAD_SSL3_CTX *ssl3_ctx = (AEAD_SSL3_CTX*)ctx->aead_state;
+
+ const size_t digest_len = EVP_MD_CTX_size(&ssl3_ctx->md_ctx);
+ if (EVP_CIPHER_CTX_mode(&ssl3_ctx->cipher_ctx) != EVP_CIPH_CBC_MODE) {
+ // The NULL cipher.
+ return digest_len;
+ }
+
+ const size_t block_size = EVP_CIPHER_CTX_block_size(&ssl3_ctx->cipher_ctx);
+ /* An overflow of |in_len + digest_len| doesn't affect the result mod
+ * |block_size|, provided that |block_size| is a smaller power of two. */
+ assert(block_size != 0 && (block_size & (block_size - 1)) == 0);
+ const size_t pad_len = block_size - ((in_len + digest_len) % block_size);
+ return digest_len + pad_len;
+}
+
static int aead_ssl3_seal_scatter(const EVP_AEAD_CTX *ctx, uint8_t *out,
uint8_t *out_tag, size_t *out_tag_len,
- size_t max_out_tag_len, const uint8_t *nonce,
- size_t nonce_len, const uint8_t *in,
- size_t in_len, const uint8_t *extra_in,
- size_t extra_in_len, const uint8_t *ad,
- size_t ad_len) {
+ const size_t max_out_tag_len,
+ const uint8_t *nonce, const size_t nonce_len,
+ const uint8_t *in, const size_t in_len,
+ const uint8_t *extra_in,
+ const size_t extra_in_len, const uint8_t *ad,
+ const size_t ad_len) {
AEAD_SSL3_CTX *ssl3_ctx = (AEAD_SSL3_CTX *)ctx->aead_state;
if (!ssl3_ctx->cipher_ctx.encrypt) {
@@ -144,8 +164,7 @@ static int aead_ssl3_seal_scatter(const EVP_AEAD_CTX *ctx, uint8_t *out,
return 0;
}
- const size_t max_overhead = EVP_AEAD_max_overhead(ctx->aead);
- if (max_out_tag_len < max_overhead) {
+ if (max_out_tag_len < aead_ssl3_tag_len(ctx, in_len, extra_in_len)) {
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL);
return 0;
}
@@ -222,7 +241,7 @@ static int aead_ssl3_seal_scatter(const EVP_AEAD_CTX *ctx, uint8_t *out,
return 0;
}
tag_len += len;
- assert(tag_len <= max_overhead);
+ assert(tag_len == aead_ssl3_tag_len(ctx, in_len, extra_in_len));
*out_tag_len = tag_len;
return 1;
@@ -372,6 +391,7 @@ static const EVP_AEAD aead_aes_128_cbc_sha1_ssl3 = {
aead_ssl3_seal_scatter,
NULL, /* open_gather */
aead_ssl3_get_iv,
+ aead_ssl3_tag_len,
};
static const EVP_AEAD aead_aes_256_cbc_sha1_ssl3 = {
@@ -388,6 +408,7 @@ static const EVP_AEAD aead_aes_256_cbc_sha1_ssl3 = {
aead_ssl3_seal_scatter,
NULL, /* open_gather */
aead_ssl3_get_iv,
+ aead_ssl3_tag_len,
};
static const EVP_AEAD aead_des_ede3_cbc_sha1_ssl3 = {
@@ -404,6 +425,7 @@ static const EVP_AEAD aead_des_ede3_cbc_sha1_ssl3 = {
aead_ssl3_seal_scatter,
NULL, /* open_gather */
aead_ssl3_get_iv,
+ aead_ssl3_tag_len,
};
static const EVP_AEAD aead_null_sha1_ssl3 = {
@@ -420,6 +442,7 @@ static const EVP_AEAD aead_null_sha1_ssl3 = {
aead_ssl3_seal_scatter,
NULL, /* open_gather */
NULL, /* get_iv */
+ aead_ssl3_tag_len,
};
const EVP_AEAD *EVP_aead_aes_128_cbc_sha1_ssl3(void) {
diff --git a/src/crypto/cipher_extra/e_tls.c b/src/crypto/cipher_extra/e_tls.c
index 14d53771..ca206abd 100644
--- a/src/crypto/cipher_extra/e_tls.c
+++ b/src/crypto/cipher_extra/e_tls.c
@@ -99,13 +99,33 @@ static int aead_tls_init(EVP_AEAD_CTX *ctx, const uint8_t *key, size_t key_len,
return 1;
}
+static size_t aead_tls_tag_len(const EVP_AEAD_CTX *ctx, const size_t in_len,
+ const size_t extra_in_len) {
+ assert(extra_in_len == 0);
+ AEAD_TLS_CTX *tls_ctx = (AEAD_TLS_CTX *)ctx->aead_state;
+
+ const size_t hmac_len = HMAC_size(&tls_ctx->hmac_ctx);
+ if (EVP_CIPHER_CTX_mode(&tls_ctx->cipher_ctx) != EVP_CIPH_CBC_MODE) {
+ // The NULL cipher.
+ return hmac_len;
+ }
+
+ const size_t block_size = EVP_CIPHER_CTX_block_size(&tls_ctx->cipher_ctx);
+ /* An overflow of |in_len + hmac_len| doesn't affect the result mod
+ * |block_size|, provided that |block_size| is a smaller power of two. */
+ assert(block_size != 0 && (block_size & (block_size - 1)) == 0);
+ const size_t pad_len = block_size - (in_len + hmac_len) % block_size;
+ return hmac_len + pad_len;
+}
+
static int aead_tls_seal_scatter(const EVP_AEAD_CTX *ctx, uint8_t *out,
uint8_t *out_tag, size_t *out_tag_len,
- size_t max_out_tag_len, const uint8_t *nonce,
- size_t nonce_len, const uint8_t *in,
- size_t in_len, const uint8_t *extra_in,
- size_t extra_in_len, const uint8_t *ad,
- size_t ad_len) {
+ const size_t max_out_tag_len,
+ const uint8_t *nonce, const size_t nonce_len,
+ const uint8_t *in, const size_t in_len,
+ const uint8_t *extra_in,
+ const size_t extra_in_len, const uint8_t *ad,
+ const size_t ad_len) {
AEAD_TLS_CTX *tls_ctx = (AEAD_TLS_CTX *)ctx->aead_state;
if (!tls_ctx->cipher_ctx.encrypt) {
@@ -120,8 +140,7 @@ static int aead_tls_seal_scatter(const EVP_AEAD_CTX *ctx, uint8_t *out,
return 0;
}
- const size_t max_overhead = EVP_AEAD_max_overhead(ctx->aead);
- if (max_out_tag_len < max_overhead) {
+ if (max_out_tag_len < aead_tls_tag_len(ctx, in_len, extra_in_len)) {
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL);
return 0;
}
@@ -173,7 +192,8 @@ static int aead_tls_seal_scatter(const EVP_AEAD_CTX *ctx, uint8_t *out,
* block from encrypting the input and split the result between |out| and
* |out_tag|. Then feed the rest. */
- size_t early_mac_len = (block_size - (in_len % block_size)) % block_size;
+ const size_t early_mac_len =
+ (block_size - (in_len % block_size) % block_size);
if (early_mac_len != 0) {
assert(len + block_size - early_mac_len == in_len);
uint8_t buf[EVP_MAX_BLOCK_LENGTH];
@@ -212,8 +232,8 @@ static int aead_tls_seal_scatter(const EVP_AEAD_CTX *ctx, uint8_t *out,
if (!EVP_EncryptFinal_ex(&tls_ctx->cipher_ctx, out_tag + tag_len, &len)) {
return 0;
}
- tag_len += len;
- assert(tag_len <= max_overhead);
+ assert(len == 0); /* Padding is explicit. */
+ assert(tag_len == aead_tls_tag_len(ctx, in_len, extra_in_len));
*out_tag_len = tag_len;
return 1;
@@ -467,6 +487,7 @@ static const EVP_AEAD aead_aes_128_cbc_sha1_tls = {
aead_tls_seal_scatter,
NULL, /* open_gather */
NULL, /* get_iv */
+ aead_tls_tag_len,
};
static const EVP_AEAD aead_aes_128_cbc_sha1_tls_implicit_iv = {
@@ -483,6 +504,7 @@ static const EVP_AEAD aead_aes_128_cbc_sha1_tls_implicit_iv = {
aead_tls_seal_scatter,
NULL, /* open_gather */
aead_tls_get_iv, /* get_iv */
+ aead_tls_tag_len,
};
static const EVP_AEAD aead_aes_128_cbc_sha256_tls = {
@@ -499,6 +521,7 @@ static const EVP_AEAD aead_aes_128_cbc_sha256_tls = {
aead_tls_seal_scatter,
NULL, /* open_gather */
NULL, /* get_iv */
+ aead_tls_tag_len,
};
static const EVP_AEAD aead_aes_256_cbc_sha1_tls = {
@@ -515,6 +538,7 @@ static const EVP_AEAD aead_aes_256_cbc_sha1_tls = {
aead_tls_seal_scatter,
NULL, /* open_gather */
NULL, /* get_iv */
+ aead_tls_tag_len,
};
static const EVP_AEAD aead_aes_256_cbc_sha1_tls_implicit_iv = {
@@ -531,6 +555,7 @@ static const EVP_AEAD aead_aes_256_cbc_sha1_tls_implicit_iv = {
aead_tls_seal_scatter,
NULL, /* open_gather */
aead_tls_get_iv, /* get_iv */
+ aead_tls_tag_len,
};
static const EVP_AEAD aead_aes_256_cbc_sha256_tls = {
@@ -547,6 +572,7 @@ static const EVP_AEAD aead_aes_256_cbc_sha256_tls = {
aead_tls_seal_scatter,
NULL, /* open_gather */
NULL, /* get_iv */
+ aead_tls_tag_len,
};
static const EVP_AEAD aead_aes_256_cbc_sha384_tls = {
@@ -563,6 +589,7 @@ static const EVP_AEAD aead_aes_256_cbc_sha384_tls = {
aead_tls_seal_scatter,
NULL, /* open_gather */
NULL, /* get_iv */
+ aead_tls_tag_len,
};
static const EVP_AEAD aead_des_ede3_cbc_sha1_tls = {
@@ -579,6 +606,7 @@ static const EVP_AEAD aead_des_ede3_cbc_sha1_tls = {
aead_tls_seal_scatter,
NULL, /* open_gather */
NULL, /* get_iv */
+ aead_tls_tag_len,
};
static const EVP_AEAD aead_des_ede3_cbc_sha1_tls_implicit_iv = {
@@ -595,6 +623,7 @@ static const EVP_AEAD aead_des_ede3_cbc_sha1_tls_implicit_iv = {
aead_tls_seal_scatter,
NULL, /* open_gather */
aead_tls_get_iv, /* get_iv */
+ aead_tls_tag_len,
};
static const EVP_AEAD aead_null_sha1_tls = {
@@ -611,6 +640,7 @@ static const EVP_AEAD aead_null_sha1_tls = {
aead_tls_seal_scatter,
NULL, /* open_gather */
NULL, /* get_iv */
+ aead_tls_tag_len,
};
const EVP_AEAD *EVP_aead_aes_128_cbc_sha1_tls(void) {
diff --git a/src/crypto/compiler_test.cc b/src/crypto/compiler_test.cc
index 2836276e..29375a57 100644
--- a/src/crypto/compiler_test.cc
+++ b/src/crypto/compiler_test.cc
@@ -149,11 +149,11 @@ TEST(CompilerTest, IntegerRepresentation) {
CheckRepresentation(static_cast<uint64_t>(0));
}
-// Converting pointers to integers and doing arithmetic on those values are both
-// defined. Converting those values back into pointers is undefined, but, for
-// aliasing checks, we require that the implementation-defined result of that
-// computation commutes with pointer arithmetic.
TEST(CompilerTest, PointerRepresentation) {
+ // Converting pointers to integers and doing arithmetic on those values are
+ // both defined. Converting those values back into pointers is undefined,
+ // but, for aliasing checks, we require that the implementation-defined
+ // result of that computation commutes with pointer arithmetic.
char chars[256];
for (size_t i = 0; i < sizeof(chars); i++) {
EXPECT_EQ(reinterpret_cast<uintptr_t>(chars) + i,
@@ -165,4 +165,11 @@ TEST(CompilerTest, PointerRepresentation) {
EXPECT_EQ(reinterpret_cast<uintptr_t>(ints) + i * sizeof(int),
reinterpret_cast<uintptr_t>(ints + i));
}
+
+ // nullptr must be represented by all zeros in memory. This is necessary so
+ // structs may be initialized by memset(0).
+ int *null = nullptr;
+ uint8_t bytes[sizeof(null)] = {0};
+ EXPECT_EQ(Bytes(bytes),
+ Bytes(reinterpret_cast<uint8_t *>(&null), sizeof(null)));
}
diff --git a/src/crypto/cpu-intel.c b/src/crypto/cpu-intel.c
index f2e0c4cb..ef327df0 100644
--- a/src/crypto/cpu-intel.c
+++ b/src/crypto/cpu-intel.c
@@ -207,6 +207,14 @@ void OPENSSL_cpuid_setup(void) {
/* Reserved bit #30 is repurposed to signal an Intel CPU. */
if (is_intel) {
edx |= (1 << 30);
+
+ /* Clear the XSAVE bit on Knights Landing to mimic Silvermont. This enables
+ * some Silvermont-specific codepaths which perform better. See OpenSSL
+ * commit 64d92d74985ebb3d0be58a9718f9e080a14a8e7f. */
+ if ((eax & 0x0fff0ff0) == 0x00050670 /* Knights Landing */ ||
+ (eax & 0x0fff0ff0) == 0x00080650 /* Knights Mill (per SDE) */) {
+ ecx &= ~(1 << 26);
+ }
} else {
edx &= ~(1 << 30);
}
@@ -223,13 +231,30 @@ void OPENSSL_cpuid_setup(void) {
/* XCR0 may only be queried if the OSXSAVE bit is set. */
xcr0 = OPENSSL_xgetbv(0);
}
- /* See Intel manual, section 14.3. */
+ /* See Intel manual, volume 1, section 14.3. */
if ((xcr0 & 6) != 6) {
/* YMM registers cannot be used. */
ecx &= ~(1 << 28); /* AVX */
ecx &= ~(1 << 12); /* FMA */
ecx &= ~(1 << 11); /* AMD XOP */
- extended_features &= ~(1 << 5); /* AVX2 */
+ /* Clear AVX2 and AVX512* bits.
+ *
+ * TODO(davidben): Should bits 17 and 26-28 also be cleared? Upstream
+ * doesn't clear those. */
+ extended_features &=
+ ~((1 << 5) | (1 << 16) | (1 << 21) | (1 << 30) | (1 << 31));
+ }
+ /* See Intel manual, volume 1, section 15.2. */
+ if ((xcr0 & 0xe6) != 0xe6) {
+ /* Clear AVX512F. Note we don't touch other AVX512 extensions because they
+ * can be used with YMM. */
+ extended_features &= ~(1 << 16);
+ }
+
+ /* Disable ADX instructions on Knights Landing. See OpenSSL commit
+ * 64d92d74985ebb3d0be58a9718f9e080a14a8e7f. */
+ if ((ecx & (1 << 26)) == 0) {
+ extended_features &= ~(1 << 19);
}
OPENSSL_ia32cap_P[0] = edx;
diff --git a/src/crypto/dh/check.c b/src/crypto/dh/check.c
index e3c111b5..55fc1c30 100644
--- a/src/crypto/dh/check.c
+++ b/src/crypto/dh/check.c
@@ -59,8 +59,8 @@
#include <openssl/bn.h>
-int DH_check_pub_key(const DH *dh, const BIGNUM *pub_key, int *ret) {
- *ret = 0;
+int DH_check_pub_key(const DH *dh, const BIGNUM *pub_key, int *out_flags) {
+ *out_flags = 0;
BN_CTX *ctx = BN_CTX_new();
if (ctx == NULL) {
@@ -77,7 +77,7 @@ int DH_check_pub_key(const DH *dh, const BIGNUM *pub_key, int *ret) {
goto err;
}
if (BN_cmp(pub_key, tmp) <= 0) {
- *ret |= DH_CHECK_PUBKEY_TOO_SMALL;
+ *out_flags |= DH_CHECK_PUBKEY_TOO_SMALL;
}
/* Check |pub_key| is less than |dh->p| - 1. */
@@ -86,7 +86,7 @@ int DH_check_pub_key(const DH *dh, const BIGNUM *pub_key, int *ret) {
goto err;
}
if (BN_cmp(pub_key, tmp) >= 0) {
- *ret |= DH_CHECK_PUBKEY_TOO_LARGE;
+ *out_flags |= DH_CHECK_PUBKEY_TOO_LARGE;
}
if (dh->q != NULL) {
@@ -97,7 +97,7 @@ int DH_check_pub_key(const DH *dh, const BIGNUM *pub_key, int *ret) {
goto err;
}
if (!BN_is_one(tmp)) {
- *ret |= DH_CHECK_PUBKEY_INVALID;
+ *out_flags |= DH_CHECK_PUBKEY_INVALID;
}
}
@@ -110,7 +110,7 @@ err:
}
-int DH_check(const DH *dh, int *ret) {
+int DH_check(const DH *dh, int *out_flags) {
/* Check that p is a safe prime and if g is 2, 3 or 5, check that it is a
* suitable generator where:
* for 2, p mod 24 == 11
@@ -123,7 +123,7 @@ int DH_check(const DH *dh, int *ret) {
BN_ULONG l;
BIGNUM *t1 = NULL, *t2 = NULL;
- *ret = 0;
+ *out_flags = 0;
ctx = BN_CTX_new();
if (ctx == NULL) {
goto err;
@@ -140,16 +140,16 @@ int DH_check(const DH *dh, int *ret) {
if (dh->q) {
if (BN_cmp(dh->g, BN_value_one()) <= 0) {
- *ret |= DH_CHECK_NOT_SUITABLE_GENERATOR;
+ *out_flags |= DH_CHECK_NOT_SUITABLE_GENERATOR;
} else if (BN_cmp(dh->g, dh->p) >= 0) {
- *ret |= DH_CHECK_NOT_SUITABLE_GENERATOR;
+ *out_flags |= DH_CHECK_NOT_SUITABLE_GENERATOR;
} else {
/* Check g^q == 1 mod p */
if (!BN_mod_exp_mont(t1, dh->g, dh->q, dh->p, ctx, NULL)) {
goto err;
}
if (!BN_is_one(t1)) {
- *ret |= DH_CHECK_NOT_SUITABLE_GENERATOR;
+ *out_flags |= DH_CHECK_NOT_SUITABLE_GENERATOR;
}
}
r = BN_is_prime_ex(dh->q, BN_prime_checks, ctx, NULL);
@@ -157,17 +157,17 @@ int DH_check(const DH *dh, int *ret) {
goto err;
}
if (!r) {
- *ret |= DH_CHECK_Q_NOT_PRIME;
+ *out_flags |= DH_CHECK_Q_NOT_PRIME;
}
/* Check p == 1 mod q i.e. q divides p - 1 */
if (!BN_div(t1, t2, dh->p, dh->q, ctx)) {
goto err;
}
if (!BN_is_one(t2)) {
- *ret |= DH_CHECK_INVALID_Q_VALUE;
+ *out_flags |= DH_CHECK_INVALID_Q_VALUE;
}
if (dh->j && BN_cmp(dh->j, t1)) {
- *ret |= DH_CHECK_INVALID_J_VALUE;
+ *out_flags |= DH_CHECK_INVALID_J_VALUE;
}
} else if (BN_is_word(dh->g, DH_GENERATOR_2)) {
l = BN_mod_word(dh->p, 24);
@@ -175,7 +175,7 @@ int DH_check(const DH *dh, int *ret) {
goto err;
}
if (l != 11) {
- *ret |= DH_CHECK_NOT_SUITABLE_GENERATOR;
+ *out_flags |= DH_CHECK_NOT_SUITABLE_GENERATOR;
}
} else if (BN_is_word(dh->g, DH_GENERATOR_5)) {
l = BN_mod_word(dh->p, 10);
@@ -183,10 +183,10 @@ int DH_check(const DH *dh, int *ret) {
goto err;
}
if (l != 3 && l != 7) {
- *ret |= DH_CHECK_NOT_SUITABLE_GENERATOR;
+ *out_flags |= DH_CHECK_NOT_SUITABLE_GENERATOR;
}
} else {
- *ret |= DH_CHECK_UNABLE_TO_CHECK_GENERATOR;
+ *out_flags |= DH_CHECK_UNABLE_TO_CHECK_GENERATOR;
}
r = BN_is_prime_ex(dh->p, BN_prime_checks, ctx, NULL);
@@ -194,7 +194,7 @@ int DH_check(const DH *dh, int *ret) {
goto err;
}
if (!r) {
- *ret |= DH_CHECK_P_NOT_PRIME;
+ *out_flags |= DH_CHECK_P_NOT_PRIME;
} else if (!dh->q) {
if (!BN_rshift1(t1, dh->p)) {
goto err;
@@ -204,7 +204,7 @@ int DH_check(const DH *dh, int *ret) {
goto err;
}
if (!r) {
- *ret |= DH_CHECK_P_NOT_SAFE_PRIME;
+ *out_flags |= DH_CHECK_P_NOT_SAFE_PRIME;
}
}
ok = 1;
diff --git a/src/crypto/dsa/dsa.c b/src/crypto/dsa/dsa.c
index 58126c37..d445f148 100644
--- a/src/crypto/dsa/dsa.c
+++ b/src/crypto/dsa/dsa.c
@@ -917,35 +917,35 @@ int DSA_get_ex_new_index(long argl, void *argp, CRYPTO_EX_unused *unused,
return index;
}
-int DSA_set_ex_data(DSA *d, int idx, void *arg) {
- return CRYPTO_set_ex_data(&d->ex_data, idx, arg);
+int DSA_set_ex_data(DSA *dsa, int idx, void *arg) {
+ return CRYPTO_set_ex_data(&dsa->ex_data, idx, arg);
}
-void *DSA_get_ex_data(const DSA *d, int idx) {
- return CRYPTO_get_ex_data(&d->ex_data, idx);
+void *DSA_get_ex_data(const DSA *dsa, int idx) {
+ return CRYPTO_get_ex_data(&dsa->ex_data, idx);
}
-DH *DSA_dup_DH(const DSA *r) {
- DH *ret = NULL;
-
- if (r == NULL) {
- goto err;
+DH *DSA_dup_DH(const DSA *dsa) {
+ if (dsa == NULL) {
+ return NULL;
}
- ret = DH_new();
+
+ DH *ret = DH_new();
if (ret == NULL) {
goto err;
}
- if (r->q != NULL) {
- ret->priv_length = BN_num_bits(r->q);
- if ((ret->q = BN_dup(r->q)) == NULL) {
+ if (dsa->q != NULL) {
+ ret->priv_length = BN_num_bits(dsa->q);
+ if ((ret->q = BN_dup(dsa->q)) == NULL) {
goto err;
}
}
- if ((r->p != NULL && (ret->p = BN_dup(r->p)) == NULL) ||
- (r->g != NULL && (ret->g = BN_dup(r->g)) == NULL) ||
- (r->pub_key != NULL && (ret->pub_key = BN_dup(r->pub_key)) == NULL) ||
- (r->priv_key != NULL && (ret->priv_key = BN_dup(r->priv_key)) == NULL)) {
- goto err;
+ if ((dsa->p != NULL && (ret->p = BN_dup(dsa->p)) == NULL) ||
+ (dsa->g != NULL && (ret->g = BN_dup(dsa->g)) == NULL) ||
+ (dsa->pub_key != NULL && (ret->pub_key = BN_dup(dsa->pub_key)) == NULL) ||
+ (dsa->priv_key != NULL &&
+ (ret->priv_key = BN_dup(dsa->priv_key)) == NULL)) {
+ goto err;
}
return ret;
diff --git a/src/crypto/fipsmodule/aes/asm/aesni-x86_64.pl b/src/crypto/fipsmodule/aes/asm/aesni-x86_64.pl
index 4ad0fb11..a9b31515 100644
--- a/src/crypto/fipsmodule/aes/asm/aesni-x86_64.pl
+++ b/src/crypto/fipsmodule/aes/asm/aesni-x86_64.pl
@@ -179,8 +179,10 @@
# Haswell 4.44/0.63 0.63 0.73 0.63 0.70
# Skylake 2.62/0.63 0.63 0.63 0.63
# Silvermont 5.75/3.54 3.56 4.12 3.87(*) 4.11
+# Knights L 2.54/0.77 0.78 0.85 - 1.50
# Goldmont 3.82/1.26 1.26 1.29 1.29 1.50
# Bulldozer 5.77/0.70 0.72 0.90 0.70 0.95
+# Ryzen 2.71/0.35 0.35 0.44 0.38 0.49
#
# (*) Atom Silvermont ECB result is suboptimal because of penalties
# incurred by operations on %xmm8-15. As ECB is not considered
diff --git a/src/crypto/fipsmodule/cipher/aead.c b/src/crypto/fipsmodule/cipher/aead.c
index 79139e60..ed302096 100644
--- a/src/crypto/fipsmodule/cipher/aead.c
+++ b/src/crypto/fipsmodule/cipher/aead.c
@@ -264,3 +264,21 @@ int EVP_AEAD_CTX_get_iv(const EVP_AEAD_CTX *ctx, const uint8_t **out_iv,
return ctx->aead->get_iv(ctx, out_iv, out_len);
}
+
+int EVP_AEAD_CTX_tag_len(const EVP_AEAD_CTX *ctx, size_t *out_tag_len,
+ const size_t in_len, const size_t extra_in_len) {
+ assert(ctx->aead->seal_scatter_supports_extra_in || !extra_in_len);
+
+ if (ctx->aead->tag_len) {
+ *out_tag_len = ctx->aead->tag_len(ctx, in_len, extra_in_len);
+ return 1;
+ }
+
+ if (extra_in_len + ctx->tag_len < extra_in_len) {
+ OPENSSL_PUT_ERROR(CIPHER, ERR_R_OVERFLOW);
+ *out_tag_len = 0;
+ return 0;
+ }
+ *out_tag_len = extra_in_len + ctx->tag_len;
+ return 1;
+}
diff --git a/src/crypto/fipsmodule/cipher/e_aes.c b/src/crypto/fipsmodule/cipher/e_aes.c
index 7c7521b4..2c6fc417 100644
--- a/src/crypto/fipsmodule/cipher/e_aes.c
+++ b/src/crypto/fipsmodule/cipher/e_aes.c
@@ -1217,7 +1217,7 @@ static int aead_aes_gcm_seal_scatter(const EVP_AEAD_CTX *ctx, uint8_t *out,
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
return 0;
}
- if (max_out_tag_len < ctx->tag_len + extra_in_len) {
+ if (max_out_tag_len < extra_in_len + ctx->tag_len) {
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL);
return 0;
}
@@ -1226,11 +1226,6 @@ static int aead_aes_gcm_seal_scatter(const EVP_AEAD_CTX *ctx, uint8_t *out,
return 0;
}
- if (max_out_tag_len < ctx->tag_len) {
- OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL);
- return 0;
- }
-
const AES_KEY *key = &gcm_ctx->ks.ks;
OPENSSL_memcpy(&gcm, &gcm_ctx->gcm, sizeof(gcm));
diff --git a/src/crypto/fipsmodule/cipher/internal.h b/src/crypto/fipsmodule/cipher/internal.h
index ea59723e..02335e0d 100644
--- a/src/crypto/fipsmodule/cipher/internal.h
+++ b/src/crypto/fipsmodule/cipher/internal.h
@@ -107,6 +107,9 @@ struct evp_aead_st {
int (*get_iv)(const EVP_AEAD_CTX *ctx, const uint8_t **out_iv,
size_t *out_len);
+
+ size_t (*tag_len)(const EVP_AEAD_CTX *ctx, size_t in_Len,
+ size_t extra_in_len);
};
/* aes_ctr_set_key initialises |*aes_key| using |key_bytes| bytes from |key|,
diff --git a/src/crypto/fipsmodule/modes/asm/aesni-gcm-x86_64.pl b/src/crypto/fipsmodule/modes/asm/aesni-gcm-x86_64.pl
index 57a6a8d8..dd6657bf 100644
--- a/src/crypto/fipsmodule/modes/asm/aesni-gcm-x86_64.pl
+++ b/src/crypto/fipsmodule/modes/asm/aesni-gcm-x86_64.pl
@@ -1,4 +1,11 @@
-#!/usr/bin/env perl
+#! /usr/bin/env perl
+# Copyright 2013-2016 The OpenSSL Project Authors. All Rights Reserved.
+#
+# Licensed under the OpenSSL license (the "License"). You may not use
+# this file except in compliance with the License. You can obtain a copy
+# in the file LICENSE in the source distribution or at
+# https://www.openssl.org/source/license.html
+
#
# ====================================================================
# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
@@ -28,6 +35,8 @@
# Applications using the EVP interface will observe a few percent
# worse performance.]
#
+# Knights Landing processes 1 byte in 1.25 cycles (measured with EVP).
+#
# [1] http://rt.openssl.org/Ticket/Display.html?id=2900&user=guest&pass=guest
# [2] http://www.intel.com/content/dam/www/public/us/en/documents/software-support/enabling-high-performance-gcm.pdf
diff --git a/src/crypto/fipsmodule/modes/asm/ghash-x86_64.pl b/src/crypto/fipsmodule/modes/asm/ghash-x86_64.pl
index 1778ac0b..e6dd0419 100644
--- a/src/crypto/fipsmodule/modes/asm/ghash-x86_64.pl
+++ b/src/crypto/fipsmodule/modes/asm/ghash-x86_64.pl
@@ -1,4 +1,11 @@
-#!/usr/bin/env perl
+#! /usr/bin/env perl
+# Copyright 2010-2016 The OpenSSL Project Authors. All Rights Reserved.
+#
+# Licensed under the OpenSSL license (the "License"). You may not use
+# this file except in compliance with the License. You can obtain a copy
+# in the file LICENSE in the source distribution or at
+# https://www.openssl.org/source/license.html
+
#
# ====================================================================
# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
@@ -67,6 +74,7 @@
# Skylake 0.44(+110%)(if system doesn't support AVX)
# Bulldozer 1.49(+27%)
# Silvermont 2.88(+13%)
+# Knights L 2.12(-) (if system doesn't support AVX)
# Goldmont 1.08(+24%)
# March 2013
@@ -79,6 +87,8 @@
# it performs in 0.41 cycles per byte on Haswell processor, in
# 0.29 on Broadwell, and in 0.36 on Skylake.
#
+# Knights Landing achieves 1.09 cpb.
+#
# [1] http://rt.openssl.org/Ticket/Display.html?id=2900&user=guest&pass=guest
$flavour = shift;
diff --git a/src/crypto/fipsmodule/rand/ctrdrbg_test.cc b/src/crypto/fipsmodule/rand/ctrdrbg_test.cc
index bd84782d..0cc48b14 100644
--- a/src/crypto/fipsmodule/rand/ctrdrbg_test.cc
+++ b/src/crypto/fipsmodule/rand/ctrdrbg_test.cc
@@ -100,19 +100,19 @@ TEST(CTRDRBGTest, TestVectors) {
CTR_DRBG_STATE drbg;
CTR_DRBG_init(&drbg, seed.data(),
- personalisation.size() > 0 ? personalisation.data() : nullptr,
+ personalisation.empty() ? nullptr : personalisation.data(),
personalisation.size());
CTR_DRBG_reseed(&drbg, reseed.data(),
- ai_reseed.size() > 0 ? ai_reseed.data() : nullptr,
+ ai_reseed.empty() ? nullptr : ai_reseed.data(),
ai_reseed.size());
std::vector<uint8_t> out;
out.resize(expected.size());
CTR_DRBG_generate(&drbg, out.data(), out.size(),
- ai1.size() > 0 ? ai1.data() : nullptr, ai1.size());
+ ai1.empty() ? nullptr : ai1.data(), ai1.size());
CTR_DRBG_generate(&drbg, out.data(), out.size(),
- ai2.size() > 0 ? ai2.data() : nullptr, ai2.size());
+ ai2.empty() ? nullptr : ai2.data(), ai2.size());
EXPECT_EQ(Bytes(expected), Bytes(out));
});
diff --git a/src/crypto/fipsmodule/rand/rand.c b/src/crypto/fipsmodule/rand/rand.c
index eb99f729..9480ddbb 100644
--- a/src/crypto/fipsmodule/rand/rand.c
+++ b/src/crypto/fipsmodule/rand/rand.c
@@ -345,8 +345,6 @@ void RAND_bytes_with_additional_data(uint8_t *out, size_t out_len,
#if defined(BORINGSSL_FIPS)
CRYPTO_STATIC_MUTEX_unlock_read(thread_states_list_lock_bss_get());
#endif
-
- return;
}
int RAND_bytes(uint8_t *out, size_t out_len) {
diff --git a/src/crypto/fipsmodule/rsa/rsa.c b/src/crypto/fipsmodule/rsa/rsa.c
index 21dcacdc..a434cb1a 100644
--- a/src/crypto/fipsmodule/rsa/rsa.c
+++ b/src/crypto/fipsmodule/rsa/rsa.c
@@ -293,12 +293,12 @@ int RSA_get_ex_new_index(long argl, void *argp, CRYPTO_EX_unused *unused,
return index;
}
-int RSA_set_ex_data(RSA *d, int idx, void *arg) {
- return CRYPTO_set_ex_data(&d->ex_data, idx, arg);
+int RSA_set_ex_data(RSA *rsa, int idx, void *arg) {
+ return CRYPTO_set_ex_data(&rsa->ex_data, idx, arg);
}
-void *RSA_get_ex_data(const RSA *d, int idx) {
- return CRYPTO_get_ex_data(&d->ex_data, idx);
+void *RSA_get_ex_data(const RSA *rsa, int idx) {
+ return CRYPTO_get_ex_data(&rsa->ex_data, idx);
}
/* SSL_SIG_LENGTH is the size of an SSL/TLS (prior to TLS 1.2) signature: it's
diff --git a/src/crypto/fipsmodule/sha/asm/sha1-x86_64.pl b/src/crypto/fipsmodule/sha/asm/sha1-x86_64.pl
index b269e84d..f5bc2e64 100755
--- a/src/crypto/fipsmodule/sha/asm/sha1-x86_64.pl
+++ b/src/crypto/fipsmodule/sha/asm/sha1-x86_64.pl
@@ -1,4 +1,11 @@
-#!/usr/bin/env perl
+#! /usr/bin/env perl
+# Copyright 2006-2016 The OpenSSL Project Authors. All Rights Reserved.
+#
+# Licensed under the OpenSSL license (the "License"). You may not use
+# this file except in compliance with the License. You can obtain a copy
+# in the file LICENSE in the source distribution or at
+# https://www.openssl.org/source/license.html
+
#
# ====================================================================
# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
@@ -75,9 +82,11 @@
# Haswell 5.45 4.15/+31% 3.57/+53%
# Skylake 5.18 4.06/+28% 3.54/+46%
# Bulldozer 9.11 5.95/+53%
+# Ryzen 4.75 3.80/+24% 1.93/+150%(**)
# VIA Nano 9.32 7.15/+30%
# Atom 10.3 9.17/+12%
# Silvermont 13.1(*) 9.37/+40%
+# Knights L 13.2(*) 9.68/+36% 8.30/+59%
# Goldmont 8.13 6.42/+27% 1.70/+380%(**)
#
# (*) obviously suboptimal result, nothing was done about it,
@@ -537,7 +546,7 @@ sub AUTOLOAD() # thunk [simplified] 32-bit style perlasm
$code .= "\t$opcode\t".join(',',$arg,reverse @_)."\n";
}
-sub Xupdate_ssse3_16_31() # recall that $Xi starts wtih 4
+sub Xupdate_ssse3_16_31() # recall that $Xi starts with 4
{ use integer;
my $body = shift;
my @insns = (&$body,&$body,&$body,&$body); # 40 instructions
@@ -1458,7 +1467,7 @@ sub bodyx_40_59 () { # 10 instructions, 3 cycles critical path
)
}
-sub Xupdate_avx2_16_31() # recall that $Xi starts wtih 4
+sub Xupdate_avx2_16_31() # recall that $Xi starts with 4
{ use integer;
my $body = shift;
my @insns = (&$body,&$body,&$body,&$body,&$body); # 35 instructions
diff --git a/src/crypto/fipsmodule/sha/asm/sha512-x86_64.pl b/src/crypto/fipsmodule/sha/asm/sha512-x86_64.pl
index 7ad74916..e62ad75c 100755
--- a/src/crypto/fipsmodule/sha/asm/sha512-x86_64.pl
+++ b/src/crypto/fipsmodule/sha/asm/sha512-x86_64.pl
@@ -1,4 +1,11 @@
-#!/usr/bin/env perl
+#! /usr/bin/env perl
+# Copyright 2005-2016 The OpenSSL Project Authors. All Rights Reserved.
+#
+# Licensed under the OpenSSL license (the "License"). You may not use
+# this file except in compliance with the License. You can obtain a copy
+# in the file LICENSE in the source distribution or at
+# https://www.openssl.org/source/license.html
+
#
# ====================================================================
# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
@@ -88,9 +95,11 @@
# Haswell 12.2 9.28(+31%) 7.80(+56%) 7.66 5.40(+42%)
# Skylake 11.4 9.03(+26%) 7.70(+48%) 7.25 5.20(+40%)
# Bulldozer 21.1 13.6(+54%) 13.6(+54%(***)) 13.5 8.58(+57%)
+# Ryzen 11.0 9.02(+22%) 2.05(+440%) 7.05 5.67(+20%)
# VIA Nano 23.0 16.5(+39%) - 14.7 -
# Atom 23.0 18.9(+22%) - 14.7 -
# Silvermont 27.4 20.6(+33%) - 17.5 -
+# Knights L 27.4 21.0(+30%) 19.6(+40%) 17.5 12.8(+37%)
# Goldmont 18.9 14.3(+32%) 4.16(+350%) 12.0 -
#
# (*) whichever best applicable, including SHAEXT;
@@ -311,7 +320,6 @@ $code.=<<___;
mov $SZ*5($ctx),$F
mov $SZ*6($ctx),$G
mov $SZ*7($ctx),$H
-
jmp .Lloop
.align 16
diff --git a/src/crypto/mem.c b/src/crypto/mem.c
index 390ca2e7..f451a12d 100644
--- a/src/crypto/mem.c
+++ b/src/crypto/mem.c
@@ -159,27 +159,50 @@ size_t OPENSSL_strnlen(const char *s, size_t len) {
char *OPENSSL_strdup(const char *s) { return _strdup(s); }
-int OPENSSL_strcasecmp(const char *a, const char *b) {
- return _stricmp(a, b);
-}
-
-int OPENSSL_strncasecmp(const char *a, const char *b, size_t n) {
- return _strnicmp(a, b, n);
-}
-
#else
char *OPENSSL_strdup(const char *s) { return strdup(s); }
+#endif
+
+int OPENSSL_tolower(int c) {
+ if (c >= 'A' && c <= 'Z') {
+ return c + ('a' - 'A');
+ }
+ return c;
+}
+
int OPENSSL_strcasecmp(const char *a, const char *b) {
- return strcasecmp(a, b);
+ for (size_t i = 0;; i++) {
+ const int aa = OPENSSL_tolower(a[i]);
+ const int bb = OPENSSL_tolower(b[i]);
+
+ if (aa < bb) {
+ return -1;
+ } else if (aa > bb) {
+ return 1;
+ } else if (aa == 0) {
+ return 0;
+ }
+ }
}
int OPENSSL_strncasecmp(const char *a, const char *b, size_t n) {
- return strncasecmp(a, b, n);
-}
+ for (size_t i = 0; i < n; i++) {
+ const int aa = OPENSSL_tolower(a[i]);
+ const int bb = OPENSSL_tolower(b[i]);
+
+ if (aa < bb) {
+ return -1;
+ } else if (aa > bb) {
+ return 1;
+ } else if (aa == 0) {
+ return 0;
+ }
+ }
-#endif
+ return 0;
+}
int BIO_snprintf(char *buf, size_t n, const char *format, ...) {
va_list args;
diff --git a/src/crypto/rand_extra/rand_extra.c b/src/crypto/rand_extra/rand_extra.c
index 8fce3c89..3b37e297 100644
--- a/src/crypto/rand_extra/rand_extra.c
+++ b/src/crypto/rand_extra/rand_extra.c
@@ -63,6 +63,8 @@ RAND_METHOD *RAND_SSLeay(void) {
return (RAND_METHOD*) &kSSLeayMethod;
}
+const RAND_METHOD *RAND_get_rand_method(void) { return RAND_SSLeay(); }
+
void RAND_set_rand_method(const RAND_METHOD *method) {}
void RAND_cleanup(void) {}
diff --git a/src/crypto/test/file_test.cc b/src/crypto/test/file_test.cc
index c85fac68..ea1fc3c5 100644
--- a/src/crypto/test/file_test.cc
+++ b/src/crypto/test/file_test.cc
@@ -32,7 +32,8 @@
FileTest::FileTest(std::unique_ptr<FileTest::LineReader> reader,
std::function<void(const std::string &)> comment_callback)
- : reader_(std::move(reader)), comment_callback_(comment_callback) {}
+ : reader_(std::move(reader)),
+ comment_callback_(std::move(comment_callback)) {}
FileTest::~FileTest() {}
diff --git a/src/crypto/x509/x509_vfy.c b/src/crypto/x509/x509_vfy.c
index 2413a1c1..b427df63 100644
--- a/src/crypto/x509/x509_vfy.c
+++ b/src/crypto/x509/x509_vfy.c
@@ -2254,10 +2254,15 @@ X509_STORE_CTX *X509_STORE_CTX_new(void)
OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
return NULL;
}
- OPENSSL_memset(ctx, 0, sizeof(X509_STORE_CTX));
+ X509_STORE_CTX_zero(ctx);
return ctx;
}
+void X509_STORE_CTX_zero(X509_STORE_CTX *ctx)
+{
+ OPENSSL_memset(ctx, 0, sizeof(X509_STORE_CTX));
+}
+
void X509_STORE_CTX_free(X509_STORE_CTX *ctx)
{
if (ctx == NULL) {
@@ -2272,7 +2277,7 @@ int X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store, X509 *x509,
{
int ret = 1;
- OPENSSL_memset(ctx, 0, sizeof(X509_STORE_CTX));
+ X509_STORE_CTX_zero(ctx);
ctx->ctx = store;
ctx->cert = x509;
ctx->untrusted = chain;
diff --git a/src/crypto/x509/x_name.c b/src/crypto/x509/x_name.c
index e6eeb957..5fa9077b 100644
--- a/src/crypto/x509/x_name.c
+++ b/src/crypto/x509/x_name.c
@@ -492,7 +492,7 @@ static int asn1_string_canon(ASN1_STRING *out, ASN1_STRING *in)
}
while (!(*from & 0x80) && isspace(*from));
} else {
- *to++ = tolower(*from);
+ *to++ = OPENSSL_tolower(*from);
from++;
i++;
}
diff --git a/src/crypto/x509v3/v3_utl.c b/src/crypto/x509v3/v3_utl.c
index fe7787bb..feb3dc6a 100644
--- a/src/crypto/x509v3/v3_utl.c
+++ b/src/crypto/x509v3/v3_utl.c
@@ -454,15 +454,13 @@ unsigned char *string_to_hex(const char *str, long *len)
OPENSSL_free(hexbuf);
return NULL;
}
- if (isupper(ch))
- ch = tolower(ch);
- if (isupper(cl))
- cl = tolower(cl);
if ((ch >= '0') && (ch <= '9'))
ch -= '0';
else if ((ch >= 'a') && (ch <= 'f'))
ch -= 'a' - 10;
+ else if ((ch >= 'A') && (ch <= 'F'))
+ ch -= 'A' - 10;
else
goto badhex;
@@ -470,6 +468,8 @@ unsigned char *string_to_hex(const char *str, long *len)
cl -= '0';
else if ((cl >= 'a') && (cl <= 'f'))
cl -= 'a' - 10;
+ else if ((cl >= 'A') && (cl <= 'F'))
+ cl -= 'A' - 10;
else
goto badhex;
diff --git a/src/include/openssl/aead.h b/src/include/openssl/aead.h
index f0a67d8f..dd2e4187 100644
--- a/src/include/openssl/aead.h
+++ b/src/include/openssl/aead.h
@@ -389,6 +389,15 @@ OPENSSL_EXPORT int EVP_AEAD_CTX_init_with_direction(
OPENSSL_EXPORT int EVP_AEAD_CTX_get_iv(const EVP_AEAD_CTX *ctx,
const uint8_t **out_iv, size_t *out_len);
+/* EVP_AEAD_CTX_tag_len computes the exact byte length of the tag written by
+ * |EVP_AEAD_CTX_seal_scatter| and writes it to |*out_tag_len|. It returns one
+ * on success or zero on error. |in_len| and |extra_in_len| must equal the
+ * arguments of the same names passed to |EVP_AEAD_CTX_seal_scatter|. */
+OPENSSL_EXPORT int EVP_AEAD_CTX_tag_len(const EVP_AEAD_CTX *ctx,
+ size_t *out_tag_len,
+ const size_t in_len,
+ const size_t extra_in_len);
+
#if defined(__cplusplus)
} /* extern C */
diff --git a/src/include/openssl/asn1.h b/src/include/openssl/asn1.h
index 64d79899..45d4848c 100644
--- a/src/include/openssl/asn1.h
+++ b/src/include/openssl/asn1.h
@@ -876,8 +876,6 @@ extern "C++" {
namespace bssl {
-BORINGSSL_MAKE_STACK_DELETER(ASN1_OBJECT, ASN1_OBJECT_free)
-
BORINGSSL_MAKE_DELETER(ASN1_OBJECT, ASN1_OBJECT_free)
BORINGSSL_MAKE_DELETER(ASN1_STRING, ASN1_STRING_free)
BORINGSSL_MAKE_DELETER(ASN1_TYPE, ASN1_TYPE_free)
diff --git a/src/include/openssl/base.h b/src/include/openssl/base.h
index 42ead4d2..6b43c767 100644
--- a/src/include/openssl/base.h
+++ b/src/include/openssl/base.h
@@ -107,6 +107,10 @@ extern "C" {
#elif defined(__myriad2__)
#define OPENSSL_32_BIT
#else
+/* Note BoringSSL only supports standard 32-bit and 64-bit two's-complement,
+ * little-endian architectures. Functions will not produce the correct answer
+ * on other systems. Run the crypto_test binary, notably
+ * crypto/compiler_test.cc, before adding a new architecture. */
#error "Unknown target CPU"
#endif
@@ -367,7 +371,6 @@ extern "C++" {
#if defined(BORINGSSL_NO_CXX)
#define BORINGSSL_MAKE_DELETER(type, deleter)
-#define BORINGSSL_MAKE_STACK_DELETER(type, deleter)
#else
@@ -410,6 +413,9 @@ class StackAllocated {
T *get() { return &ctx_; }
const T *get() const { return &ctx_; }
+ T *operator->() { return &ctx_; }
+ const T *operator->() const { return &ctx_; }
+
void Reset() {
cleanup(&ctx_);
init(&ctx_);
@@ -429,18 +435,6 @@ class StackAllocated {
}; \
}
-// This makes a unique_ptr to STACK_OF(type) that owns all elements on the
-// stack, i.e. it uses sk_pop_free() to clean up.
-#define BORINGSSL_MAKE_STACK_DELETER(type, deleter) \
- namespace internal { \
- template <> \
- struct DeleterImpl<STACK_OF(type)> { \
- static void Free(STACK_OF(type) *ptr) { \
- sk_##type##_pop_free(ptr, deleter); \
- } \
- }; \
- }
-
// Holds ownership of heap-allocated BoringSSL structures. Sample usage:
// bssl::UniquePtr<RSA> rsa(RSA_new());
// bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_mem()));
diff --git a/src/include/openssl/bio.h b/src/include/openssl/bio.h
index 2d0d9591..9a80cd58 100644
--- a/src/include/openssl/bio.h
+++ b/src/include/openssl/bio.h
@@ -79,9 +79,9 @@ extern "C" {
DEFINE_STACK_OF(BIO)
-/* BIO_new creates a new BIO with the given type and a reference count of one.
+/* BIO_new creates a new BIO with the given method and a reference count of one.
* It returns the fresh |BIO|, or NULL on error. */
-OPENSSL_EXPORT BIO *BIO_new(const BIO_METHOD *type);
+OPENSSL_EXPORT BIO *BIO_new(const BIO_METHOD *method);
/* BIO_free decrements the reference count of |bio|. If the reference count
* drops to zero, it (optionally) calls the BIO's callback with |BIO_CB_FREE|,
diff --git a/src/include/openssl/buf.h b/src/include/openssl/buf.h
index 30f3af79..013c546b 100644
--- a/src/include/openssl/buf.h
+++ b/src/include/openssl/buf.h
@@ -91,7 +91,7 @@ OPENSSL_EXPORT size_t BUF_MEM_grow(BUF_MEM *buf, size_t len);
/* BUF_MEM_grow_clean acts the same as |BUF_MEM_grow|, but clears the previous
* contents of memory if reallocing. */
-OPENSSL_EXPORT size_t BUF_MEM_grow_clean(BUF_MEM *str, size_t len);
+OPENSSL_EXPORT size_t BUF_MEM_grow_clean(BUF_MEM *buf, size_t len);
/* BUF_strdup returns an allocated, duplicate of |str|. */
OPENSSL_EXPORT char *BUF_strdup(const char *str);
@@ -112,7 +112,7 @@ OPENSSL_EXPORT void *BUF_memdup(const void *data, size_t size);
OPENSSL_EXPORT size_t BUF_strlcpy(char *dst, const char *src, size_t dst_size);
/* BUF_strlcat acts like strlcat(3). */
-OPENSSL_EXPORT size_t BUF_strlcat(char *dst, const char *src, size_t size);
+OPENSSL_EXPORT size_t BUF_strlcat(char *dst, const char *src, size_t dst_size);
#if defined(__cplusplus)
diff --git a/src/include/openssl/curve25519.h b/src/include/openssl/curve25519.h
index 97be0670..11fc25e1 100644
--- a/src/include/openssl/curve25519.h
+++ b/src/include/openssl/curve25519.h
@@ -50,7 +50,7 @@ OPENSSL_EXPORT void X25519_keypair(uint8_t out_public_value[32],
* public values as inputs. */
OPENSSL_EXPORT int X25519(uint8_t out_shared_key[32],
const uint8_t private_key[32],
- const uint8_t peers_public_value[32]);
+ const uint8_t peer_public_value[32]);
/* X25519_public_from_private calculates a Diffie-Hellman public value from the
* given private key and writes it to |out_public_value|. */
diff --git a/src/include/openssl/dsa.h b/src/include/openssl/dsa.h
index afe02916..f992b918 100644
--- a/src/include/openssl/dsa.h
+++ b/src/include/openssl/dsa.h
@@ -298,8 +298,8 @@ OPENSSL_EXPORT int DSA_get_ex_new_index(long argl, void *argp,
CRYPTO_EX_unused *unused,
CRYPTO_EX_dup *dup_unused,
CRYPTO_EX_free *free_func);
-OPENSSL_EXPORT int DSA_set_ex_data(DSA *d, int idx, void *arg);
-OPENSSL_EXPORT void *DSA_get_ex_data(const DSA *d, int idx);
+OPENSSL_EXPORT int DSA_set_ex_data(DSA *dsa, int idx, void *arg);
+OPENSSL_EXPORT void *DSA_get_ex_data(const DSA *dsa, int idx);
/* Deprecated functions. */
diff --git a/src/include/openssl/mem.h b/src/include/openssl/mem.h
index 5d96a2d7..c43a16a0 100644
--- a/src/include/openssl/mem.h
+++ b/src/include/openssl/mem.h
@@ -104,10 +104,13 @@ OPENSSL_EXPORT char *OPENSSL_strdup(const char *s);
/* OPENSSL_strnlen has the same behaviour as strnlen(3). */
OPENSSL_EXPORT size_t OPENSSL_strnlen(const char *s, size_t len);
-/* OPENSSL_strcasecmp has the same behaviour as strcasecmp(3). */
+/* OPENSSL_tolower is a locale-independent version of tolower(3). */
+OPENSSL_EXPORT int OPENSSL_tolower(int c);
+
+/* OPENSSL_strcasecmp is a locale-independent version of strcasecmp(3). */
OPENSSL_EXPORT int OPENSSL_strcasecmp(const char *a, const char *b);
-/* OPENSSL_strncasecmp has the same behaviour as strncasecmp(3). */
+/* OPENSSL_strncasecmp is a locale-independent version of strncasecmp(3). */
OPENSSL_EXPORT int OPENSSL_strncasecmp(const char *a, const char *b, size_t n);
/* DECIMAL_SIZE returns an upper bound for the length of the decimal
diff --git a/src/include/openssl/pool.h b/src/include/openssl/pool.h
index 4972b93c..8a07af53 100644
--- a/src/include/openssl/pool.h
+++ b/src/include/openssl/pool.h
@@ -82,8 +82,6 @@ namespace bssl {
BORINGSSL_MAKE_DELETER(CRYPTO_BUFFER_POOL, CRYPTO_BUFFER_POOL_free)
BORINGSSL_MAKE_DELETER(CRYPTO_BUFFER, CRYPTO_BUFFER_free)
-BORINGSSL_MAKE_STACK_DELETER(CRYPTO_BUFFER, CRYPTO_BUFFER_free)
-
} // namespace bssl
} /* extern C++ */
diff --git a/src/include/openssl/rand.h b/src/include/openssl/rand.h
index 0e9a8cd7..a535fbd8 100644
--- a/src/include/openssl/rand.h
+++ b/src/include/openssl/rand.h
@@ -111,6 +111,9 @@ struct rand_meth_st {
/* RAND_SSLeay returns a pointer to a dummy |RAND_METHOD|. */
OPENSSL_EXPORT RAND_METHOD *RAND_SSLeay(void);
+/* RAND_get_rand_method returns |RAND_SSLeay()|. */
+OPENSSL_EXPORT const RAND_METHOD *RAND_get_rand_method(void);
+
/* RAND_set_rand_method does nothing. */
OPENSSL_EXPORT void RAND_set_rand_method(const RAND_METHOD *);
diff --git a/src/include/openssl/rsa.h b/src/include/openssl/rsa.h
index a580f974..ed2c0be2 100644
--- a/src/include/openssl/rsa.h
+++ b/src/include/openssl/rsa.h
@@ -456,8 +456,8 @@ OPENSSL_EXPORT int RSA_get_ex_new_index(long argl, void *argp,
CRYPTO_EX_unused *unused,
CRYPTO_EX_dup *dup_unused,
CRYPTO_EX_free *free_func);
-OPENSSL_EXPORT int RSA_set_ex_data(RSA *r, int idx, void *arg);
-OPENSSL_EXPORT void *RSA_get_ex_data(const RSA *r, int idx);
+OPENSSL_EXPORT int RSA_set_ex_data(RSA *rsa, int idx, void *arg);
+OPENSSL_EXPORT void *RSA_get_ex_data(const RSA *rsa, int idx);
/* Flags. */
diff --git a/src/include/openssl/span.h b/src/include/openssl/span.h
new file mode 100644
index 00000000..4c091595
--- /dev/null
+++ b/src/include/openssl/span.h
@@ -0,0 +1,163 @@
+/* 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. */
+
+#ifndef OPENSSL_HEADER_SSL_SPAN_H
+#define OPENSSL_HEADER_SSL_SPAN_H
+
+#include <openssl/base.h>
+
+#if !defined(BORINGSSL_NO_CXX)
+
+extern "C++" {
+
+#include <algorithm>
+#include <type_traits>
+
+namespace bssl {
+
+template <typename T>
+class Span;
+
+namespace internal {
+template <typename T>
+class SpanBase {
+ /* Put comparison operator implementations into a base class with const T, so
+ * they can be used with any type that implicitly converts into a Span. */
+ static_assert(std::is_const<T>::value,
+ "Span<T> must be derived from SpanBase<const T>");
+
+ friend bool operator==(Span<T> lhs, Span<T> rhs) {
+ /* MSVC issues warning C4996 because std::equal is unsafe. The pragma to
+ * suppress the warning mysteriously has no effect, hence this
+ * implementation. See
+ * https://msdn.microsoft.com/en-us/library/aa985974.aspx. */
+ if (lhs.size() != rhs.size()) {
+ return false;
+ }
+ for (T *l = lhs.begin(), *r = rhs.begin(); l != lhs.end() && r != rhs.end();
+ ++l, ++r) {
+ if (*l != *r) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ friend bool operator!=(Span<T> lhs, Span<T> rhs) { return !(lhs == rhs); }
+};
+} // namespace internal
+
+/* A Span<T> is a non-owning reference to a contiguous array of objects of type
+ * |T|. Conceptually, a Span is a simple a pointer to |T| and a count of
+ * elements accessible via that pointer. The elements referenced by the Span can
+ * be mutated if |T| is mutable.
+ *
+ * A Span can be constructed from container types implementing |data()| and
+ * |size()| methods. If |T| is constant, construction from a container type is
+ * implicit. This allows writing methods that accept data from some unspecified
+ * container type:
+ *
+ * // Foo views data referenced by v.
+ * void Foo(bssl::Span<const uint8_t> v) { ... }
+ *
+ * std::vector<uint8_t> vec;
+ * Foo(vec);
+ *
+ * For mutable Spans, conversion is explicit:
+ *
+ * // FooMutate mutates data referenced by v.
+ * void FooMutate(bssl::Span<uint8_t> v) { ... }
+ *
+ * FooMutate(bssl::Span<uint8_t>(vec));
+ *
+ * You can also use the |MakeSpan| and |MakeConstSpan| factory methods to
+ * construct Spans in order to deduce the type of the Span automatically.
+ *
+ * FooMutate(bssl::MakeSpan(vec));
+ *
+ * Note that Spans have value type sematics. They are cheap to construct and
+ * copy, and should be passed by value whenever a method would otherwise accept
+ * a reference or pointer to a container or array. */
+template <typename T>
+class Span : private internal::SpanBase<const T> {
+ private:
+ template <bool B, class V = void>
+ using enable_if_t = typename std::enable_if<B, V>::type;
+
+ // Heuristically test whether C is a container type that can be converted into
+ // a Span by checking for data() and size() member functions.
+ template <typename C>
+ using EnableIfContainer = enable_if_t<
+ std::is_convertible<decltype(std::declval<C>().data()), T *>::value &&
+ std::is_integral<decltype(std::declval<C>().size())>::value>;
+
+ public:
+ constexpr Span() : Span(nullptr, 0) {}
+ constexpr Span(T *ptr, size_t len) : data_(ptr), size_(len) {}
+
+ template <size_t N>
+ constexpr Span(T (&array)[N]) : Span(array, N) {}
+
+ template <typename C, typename = EnableIfContainer<C>,
+ typename = enable_if_t<std::is_const<T>::value, C>>
+ Span(const C &container) : data_(container.data()), size_(container.size()) {}
+
+ template <typename C, typename = EnableIfContainer<C>,
+ typename = enable_if_t<!std::is_const<T>::value, C>>
+ explicit Span(C &container)
+ : data_(container.data()), size_(container.size()) {}
+
+ T *data() const { return data_; }
+ size_t size() const { return size_; }
+
+ T *begin() const { return data_; }
+ const T *cbegin() const { return data_; }
+ T *end() const { return data_ + size_; };
+ const T *cend() const { return end(); };
+
+ T &operator[](size_t i) const { return data_[i]; }
+ T &at(size_t i) const { return data_[i]; }
+
+ private:
+ T *data_;
+ size_t size_;
+};
+
+template <typename T>
+Span<T> MakeSpan(T *ptr, size_t size) {
+ return Span<T>(ptr, size);
+}
+
+template <typename C>
+auto MakeSpan(C &c) -> decltype(MakeSpan(c.data(), c.size())) {
+ return MakeSpan(c.data(), c.size());
+}
+
+template <typename T>
+Span<const T> MakeConstSpan(T *ptr, size_t size) {
+ return Span<const T>(ptr, size);
+}
+
+template <typename C>
+auto MakeConstSpan(const C &c) -> decltype(MakeConstSpan(c.data(), c.size())) {
+ return MakeConstSpan(c.data(), c.size());
+}
+
+} // namespace bssl
+
+} // extern C++
+
+#endif // !defined(BORINGSSL_NO_CXX)
+
+#endif /* OPENSSL_HEADER_SSL_SPAN_H */
diff --git a/src/include/openssl/ssl.h b/src/include/openssl/ssl.h
index 04ec4b83..a5ac3251 100644
--- a/src/include/openssl/ssl.h
+++ b/src/include/openssl/ssl.h
@@ -149,6 +149,7 @@
#include <openssl/hmac.h>
#include <openssl/lhash.h>
#include <openssl/pem.h>
+#include <openssl/span.h>
#include <openssl/ssl3.h>
#include <openssl/thread.h>
#include <openssl/tls1.h>
@@ -1349,8 +1350,9 @@ OPENSSL_EXPORT int SSL_CIPHER_get_bits(const SSL_CIPHER *cipher,
* be used.
*
* Unknown rules are silently ignored by legacy APIs, and rejected by APIs with
- * "strict" in the name, which should be preferred. Cipher lists can be long and
- * it's easy to commit typos.
+ * "strict" in the name, which should be preferred. Cipher lists can be long
+ * and it's easy to commit typos. Strict functions will also reject the use of
+ * spaces, semi-colons and commas as alternative separators.
*
* The special |@STRENGTH| directive will sort all enabled ciphers by strength.
*
@@ -1368,7 +1370,7 @@ OPENSSL_EXPORT int SSL_CIPHER_get_bits(const SSL_CIPHER *cipher,
* [ECDHE-ECDSA-CHACHA20-POLY1305|ECDHE-ECDSA-AES128-GCM-SHA256]
*
* Once an equal-preference group is used, future directives must be
- * opcode-less.
+ * opcode-less. Inside an equal-preference group, spaces are not allowed.
*
* TLS 1.3 ciphers do not participate in this mechanism and instead have a
* built-in preference order. Functions to set cipher lists do not affect TLS
@@ -2517,7 +2519,8 @@ OPENSSL_EXPORT int SSL_set_tlsext_host_name(SSL *ssl, const char *name);
/* SSL_get_servername, for a server, returns the hostname supplied by the
* client or NULL if there was none. The |type| argument must be
- * |TLSEXT_NAMETYPE_host_name|. */
+ * |TLSEXT_NAMETYPE_host_name|. Note that the returned pointer points inside
+ * |ssl| and is only valid until the next operation on |ssl|. */
OPENSSL_EXPORT const char *SSL_get_servername(const SSL *ssl, const int type);
/* SSL_get_servername_type, for a server, returns |TLSEXT_NAMETYPE_host_name|
@@ -2816,20 +2819,17 @@ OPENSSL_EXPORT const SRTP_PROTECTION_PROFILE *SSL_get_selected_srtp_profile(
* The callback returns the length of the PSK or 0 if no suitable identity was
* found. */
OPENSSL_EXPORT void SSL_CTX_set_psk_client_callback(
- SSL_CTX *ctx,
- unsigned (*psk_client_callback)(
- SSL *ssl, const char *hint, char *identity,
- unsigned max_identity_len, uint8_t *psk, unsigned max_psk_len));
+ SSL_CTX *ctx, unsigned (*cb)(SSL *ssl, const char *hint, char *identity,
+ unsigned max_identity_len, uint8_t *psk,
+ unsigned max_psk_len));
/* SSL_set_psk_client_callback sets the callback to be called when PSK is
* negotiated on the client. This callback must be set to enable PSK cipher
* suites on the client. See also |SSL_CTX_set_psk_client_callback|. */
OPENSSL_EXPORT void SSL_set_psk_client_callback(
- SSL *ssl, unsigned (*psk_client_callback)(SSL *ssl, const char *hint,
- char *identity,
- unsigned max_identity_len,
- uint8_t *psk,
- unsigned max_psk_len));
+ SSL *ssl, unsigned (*cb)(SSL *ssl, const char *hint, char *identity,
+ unsigned max_identity_len, uint8_t *psk,
+ unsigned max_psk_len));
/* SSL_CTX_set_psk_server_callback sets the callback to be called when PSK is
* negotiated on the server. This callback must be set to enable PSK cipher
@@ -2839,19 +2839,15 @@ OPENSSL_EXPORT void SSL_set_psk_client_callback(
* length at most |max_psk_len| to |psk| and return the number of bytes written
* or zero if the PSK identity is unknown. */
OPENSSL_EXPORT void SSL_CTX_set_psk_server_callback(
- SSL_CTX *ctx,
- unsigned (*psk_server_callback)(SSL *ssl, const char *identity,
- uint8_t *psk,
- unsigned max_psk_len));
+ SSL_CTX *ctx, unsigned (*cb)(SSL *ssl, const char *identity, uint8_t *psk,
+ unsigned max_psk_len));
/* SSL_set_psk_server_callback sets the callback to be called when PSK is
* negotiated on the server. This callback must be set to enable PSK cipher
* suites on the server. See also |SSL_CTX_set_psk_server_callback|. */
OPENSSL_EXPORT void SSL_set_psk_server_callback(
- SSL *ssl,
- unsigned (*psk_server_callback)(SSL *ssl, const char *identity,
- uint8_t *psk,
- unsigned max_psk_len));
+ SSL *ssl, unsigned (*cb)(SSL *ssl, const char *identity, uint8_t *psk,
+ unsigned max_psk_len));
/* SSL_CTX_use_psk_identity_hint configures server connections to advertise an
* identity hint of |identity_hint|. It returns one on success and zero on
@@ -2898,14 +2894,14 @@ OPENSSL_EXPORT const char *SSL_get_psk_identity(const SSL *ssl);
*
* Early data as a client is more complex. If the offered session (see
* |SSL_set_session|) is 0-RTT-capable, the handshake will return after sending
- * the ClientHello. The predicted peer certificate and ALPN protocol will be
+ * the ClientHello. The predicted peer certificates and ALPN protocol will be
* available via the usual APIs. |SSL_write| will write early data, up to the
* session's limit. Writes past this limit and |SSL_read| will complete the
* handshake before continuing. Callers may also call |SSL_do_handshake| again
* to complete the handshake sooner.
*
* If the server accepts early data, the handshake will succeed. |SSL_read| and
- * |SSL_write| will then act as in a 1-RTT handshake. The peer certificate and
+ * |SSL_write| will then act as in a 1-RTT handshake. The peer certificates and
* ALPN protocol will be as predicted and need not be re-queried.
*
* If the server rejects early data, |SSL_do_handshake| (and thus |SSL_read| and
@@ -2915,10 +2911,12 @@ OPENSSL_EXPORT const char *SSL_get_psk_identity(const SSL *ssl);
* have processed the early data due to attacker replays.
*
* To then continue the handshake on the original connection, use
- * |SSL_reset_early_data_reject|. This allows a faster retry than making a fresh
- * connection. |SSL_do_handshake| will the complete the full handshake as in a
- * fresh connection. Once reset, the peer certificate, ALPN protocol, and other
- * properties may change so the caller must query them again.
+ * |SSL_reset_early_data_reject|. The connection will then behave as one which
+ * had not yet completed the handshake. This allows a faster retry than making a
+ * fresh connection. |SSL_do_handshake| will complete the full handshake,
+ * possibly resulting in different peer certificates, ALPN protocol, and other
+ * properties. The caller must disregard any values from before the reset and
+ * query again.
*
* Finally, to implement the fallback described in draft-ietf-tls-tls13-18
* appendix C.3, retry on a fresh connection without 0-RTT if the handshake
@@ -3569,7 +3567,7 @@ OPENSSL_EXPORT int SSL_CTX_sess_timeouts(const SSL_CTX *ctx);
OPENSSL_EXPORT int SSL_CTX_sess_cache_full(const SSL_CTX *ctx);
/* SSL_cutthrough_complete calls |SSL_in_false_start|. */
-OPENSSL_EXPORT int SSL_cutthrough_complete(const SSL *s);
+OPENSSL_EXPORT int SSL_cutthrough_complete(const SSL *ssl);
/* SSL_num_renegotiations calls |SSL_total_renegotiations|. */
OPENSSL_EXPORT int SSL_num_renegotiations(const SSL *ssl);
@@ -3593,10 +3591,10 @@ OPENSSL_EXPORT int SSL_CTX_get_read_ahead(const SSL_CTX *ctx);
OPENSSL_EXPORT void SSL_CTX_set_read_ahead(SSL_CTX *ctx, int yes);
/* SSL_get_read_ahead returns zero. */
-OPENSSL_EXPORT int SSL_get_read_ahead(const SSL *s);
+OPENSSL_EXPORT int SSL_get_read_ahead(const SSL *ssl);
/* SSL_set_read_ahead does nothing. */
-OPENSSL_EXPORT void SSL_set_read_ahead(SSL *s, int yes);
+OPENSSL_EXPORT void SSL_set_read_ahead(SSL *ssl, int yes);
/* SSL_renegotiate put an error on the error queue and returns zero. */
OPENSSL_EXPORT int SSL_renegotiate(SSL *ssl);
@@ -3661,10 +3659,10 @@ OPENSSL_EXPORT int SSL_CTX_set_tlsext_use_srtp(SSL_CTX *ctx,
OPENSSL_EXPORT int SSL_set_tlsext_use_srtp(SSL *ssl, const char *profiles);
/* SSL_get_current_compression returns NULL. */
-OPENSSL_EXPORT const COMP_METHOD *SSL_get_current_compression(SSL *s);
+OPENSSL_EXPORT const COMP_METHOD *SSL_get_current_compression(SSL *ssl);
/* SSL_get_current_expansion returns NULL. */
-OPENSSL_EXPORT const COMP_METHOD *SSL_get_current_expansion(SSL *s);
+OPENSSL_EXPORT const COMP_METHOD *SSL_get_current_expansion(SSL *ssl);
/* SSL_get_server_tmp_key returns zero. */
OPENSSL_EXPORT int *SSL_get_server_tmp_key(SSL *ssl, EVP_PKEY **out_key);
@@ -3677,11 +3675,11 @@ OPENSSL_EXPORT int SSL_set_tmp_dh(SSL *ssl, const DH *dh);
/* SSL_CTX_set_tmp_dh_callback does nothing. */
OPENSSL_EXPORT void SSL_CTX_set_tmp_dh_callback(
- SSL_CTX *ctx, DH *(*callback)(SSL *ssl, int is_export, int keylength));
+ SSL_CTX *ctx, DH *(*cb)(SSL *ssl, int is_export, int keylength));
/* SSL_set_tmp_dh_callback does nothing. */
OPENSSL_EXPORT void SSL_set_tmp_dh_callback(SSL *ssl,
- DH *(*dh)(SSL *ssl, int is_export,
+ DH *(*cb)(SSL *ssl, int is_export,
int keylength));
@@ -3781,8 +3779,7 @@ OPENSSL_EXPORT const char *SSL_get_cipher_list(const SSL *ssl, int n);
* this function is confusing. This callback may not be registered concurrently
* with |SSL_CTX_set_cert_cb| or |SSL_set_cert_cb|. */
OPENSSL_EXPORT void SSL_CTX_set_client_cert_cb(
- SSL_CTX *ctx,
- int (*client_cert_cb)(SSL *ssl, X509 **out_x509, EVP_PKEY **out_pkey));
+ SSL_CTX *ctx, int (*cb)(SSL *ssl, X509 **out_x509, EVP_PKEY **out_pkey));
#define SSL_NOTHING 1
#define SSL_WRITING 2
@@ -4365,7 +4362,7 @@ struct ssl_ctx_st {
* in: points to the client's list of supported protocols in
* wire-format.
* inlen: the length of |in|. */
- int (*alpn_select_cb)(SSL *s, const uint8_t **out, uint8_t *out_len,
+ int (*alpn_select_cb)(SSL *ssl, const uint8_t **out, uint8_t *out_len,
const uint8_t *in, unsigned in_len, void *arg);
void *alpn_select_cb_arg;
@@ -4580,6 +4577,8 @@ struct ssl_ctx_st {
#if defined(__cplusplus)
} /* extern C */
+#if !defined(BORINGSSL_NO_CXX)
+
extern "C++" {
namespace bssl {
@@ -4588,10 +4587,70 @@ BORINGSSL_MAKE_DELETER(SSL, SSL_free)
BORINGSSL_MAKE_DELETER(SSL_CTX, SSL_CTX_free)
BORINGSSL_MAKE_DELETER(SSL_SESSION, SSL_SESSION_free)
+enum class OpenRecordResult {
+ kOK,
+ kDiscard,
+ kIncompleteRecord,
+ kAlertCloseNotify,
+ kAlertFatal,
+ kError,
+};
+
+/* *** EXPERIMENTAL -- DO NOT USE ***
+ *
+ * OpenRecord decrypts the first complete SSL record from |in| in-place, sets
+ * |out| to the decrypted application data, and |out_record_len| to the length
+ * of the encrypted record. Returns:
+ * - kOK if an application-data record was successfully decrypted and verified.
+ * - kDiscard if a record was sucessfully processed, but should be discarded.
+ * - kIncompleteRecord if |in| did not contain a complete record.
+ * - kAlertCloseNotify if a record was successfully processed but is a
+ * close_notify alert.
+ * - kAlertFatal if a record was successfully processed but is a fatal alert.
+ * - kError if an error occurred or the record is invalid. |*out_alert| will be
+ * set to an alert to emit. */
+OPENSSL_EXPORT OpenRecordResult OpenRecord(SSL *ssl, Span<uint8_t> *out,
+ size_t *out_record_len,
+ uint8_t *out_alert,
+ Span<uint8_t> in);
+
+OPENSSL_EXPORT size_t SealRecordPrefixLen(const SSL *ssl, size_t plaintext_len);
+
+/* SealRecordSuffixLen returns the length of the suffix written by |SealRecord|.
+ *
+ * |plaintext_len| must be equal to the size of the plaintext passed to
+ * |SealRecord|.
+ *
+ * |plaintext_len| must not exceed |SSL3_RT_MAX_PLAINTEXT_LENGTH|. The returned
+ * suffix length will not exceed |SSL3_RT_MAX_ENCRYPTED_OVERHEAD|. */
+OPENSSL_EXPORT size_t SealRecordSuffixLen(const SSL *ssl, size_t plaintext_len);
+
+/* *** EXPERIMENTAL -- DO NOT USE ***
+ *
+ * SealRecord encrypts the cleartext of |in| and scatters the resulting TLS
+ * application data record between |out_prefix|, |out|, and |out_suffix|. It
+ * returns true on success or false if an error occurred.
+ *
+ * The length of |out_prefix| must equal |SealRecordPrefixLen|. The length of
+ * |out| must equal the length of |in|, which must not exceed
+ * |SSL3_RT_MAX_PLAINTEXT_LENGTH|. The length of |out_suffix| must equal
+ * |SealRecordSuffixLen|.
+ *
+ * If enabled, |SealRecord| may perform TLS 1.0 CBC 1/n-1 record splitting.
+ * |SealRecordPrefixLen| accounts for the required overhead if that is the case.
+ *
+ * |out| may equal |in| to encrypt in-place but may not otherwise alias.
+ * |out_prefix| and |out_suffix| may not alias anything. */
+OPENSSL_EXPORT bool SealRecord(SSL *ssl, Span<uint8_t> out_prefix,
+ Span<uint8_t> out, Span<uint8_t> out_suffix,
+ Span<const uint8_t> in);
+
} // namespace bssl
} /* extern C++ */
+#endif // !defined(BORINGSSL_NO_CXX)
+
#endif
#define SSL_R_APP_DATA_IN_HANDSHAKE 100
diff --git a/src/include/openssl/stack.h b/src/include/openssl/stack.h
index 5c4b506d..3626fb0a 100644
--- a/src/include/openssl/stack.h
+++ b/src/include/openssl/stack.h
@@ -212,11 +212,39 @@ OPENSSL_EXPORT _STACK *sk_deep_copy(const _STACK *sk,
* This set of macros is used to emit the typed functions that act on a
* |STACK_OF(T)|. */
+#if !defined(BORINGSSL_NO_CXX)
+extern "C++" {
+namespace bssl {
+namespace internal {
+template <typename T>
+struct StackTraits {};
+}
+}
+}
+
+#define BORINGSSL_DEFINE_STACK_TRAITS(name, type, is_const) \
+ extern "C++" { \
+ namespace bssl { \
+ namespace internal { \
+ template <> \
+ struct StackTraits<STACK_OF(name)> { \
+ static constexpr bool kIsStack = true; \
+ using Type = type; \
+ static constexpr bool kIsConst = is_const; \
+ }; \
+ } \
+ } \
+ }
+
+#else
+#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 DEFINE_STACK_OF_IMPL(name, ptrtype, constptrtype) \
+#define BORINGSSL_DEFINE_STACK_OF_IMPL(name, ptrtype, constptrtype) \
DECLARE_STACK_OF(name); \
\
typedef int (*stack_##name##_cmp_func)(constptrtype *a, constptrtype *b); \
@@ -323,19 +351,22 @@ OPENSSL_EXPORT _STACK *sk_deep_copy(const _STACK *sk,
/* DEFINE_STACK_OF defines |STACK_OF(type)| to be a stack whose elements are
* |type| *. */
-#define DEFINE_STACK_OF(type) DEFINE_STACK_OF_IMPL(type, type *, const type *)
+#define DEFINE_STACK_OF(type) \
+ BORINGSSL_DEFINE_STACK_OF_IMPL(type, type *, const type *) \
+ BORINGSSL_DEFINE_STACK_TRAITS(type, type, false)
/* DEFINE_CONST_STACK_OF defines |STACK_OF(type)| to be a stack whose elements
* are const |type| *. */
-#define DEFINE_CONST_STACK_OF(type) \
- DEFINE_STACK_OF_IMPL(type, const type *, const type *)
+#define DEFINE_CONST_STACK_OF(type) \
+ BORINGSSL_DEFINE_STACK_OF_IMPL(type, const type *, const type *) \
+ BORINGSSL_DEFINE_STACK_TRAITS(type, const type, true)
/* DEFINE_SPECIAL_STACK_OF defines |STACK_OF(type)| to be a stack whose elements
* are |type|, where |type| must be a typedef for a pointer. */
#define DEFINE_SPECIAL_STACK_OF(type) \
OPENSSL_COMPILE_ASSERT(sizeof(type) == sizeof(void *), \
special_stack_of_non_pointer_##type); \
- DEFINE_STACK_OF_IMPL(type, type, const type)
+ BORINGSSL_DEFINE_STACK_OF_IMPL(type, type, const type)
typedef char *OPENSSL_STRING;
@@ -348,4 +379,107 @@ DEFINE_SPECIAL_STACK_OF(OPENSSL_STRING)
} /* extern C */
#endif
+#if !defined(BORINGSSL_NO_CXX)
+extern "C++" {
+
+#include <type_traits>
+
+namespace bssl {
+
+namespace internal {
+
+// Stacks defined with |DEFINE_CONST_STACK_OF| are freed with |sk_free|.
+template <typename Stack>
+struct DeleterImpl<
+ Stack, typename std::enable_if<StackTraits<Stack>::kIsConst>::type> {
+ static void Free(Stack *sk) { sk_free(reinterpret_cast<_STACK *>(sk)); }
+};
+
+// Stacks defined with |DEFINE_STACK_OF| are freed with |sk_pop_free| and the
+// corresponding type's deleter.
+template <typename Stack>
+struct DeleterImpl<
+ Stack, typename std::enable_if<!StackTraits<Stack>::kIsConst>::type> {
+ static void Free(Stack *sk) {
+ sk_pop_free(
+ reinterpret_cast<_STACK *>(sk),
+ reinterpret_cast<void (*)(void *)>(
+ DeleterImpl<typename StackTraits<Stack>::Type>::Free));
+ }
+};
+
+template <typename Stack>
+class StackIteratorImpl {
+ public:
+ using Type = typename StackTraits<Stack>::Type;
+ // Iterators must be default-constructable.
+ StackIteratorImpl() : sk_(nullptr), idx_(0) {}
+ StackIteratorImpl(const Stack *sk, size_t idx) : sk_(sk), idx_(idx) {}
+
+ bool operator==(StackIteratorImpl other) const {
+ return sk_ == other.sk_ && idx_ == other.idx_;
+ }
+ bool operator!=(StackIteratorImpl other) const {
+ return !(*this == other);
+ }
+
+ Type *operator*() const {
+ return reinterpret_cast<Type *>(
+ sk_value(reinterpret_cast<const _STACK *>(sk_), idx_));
+ }
+
+ StackIteratorImpl &operator++(/* prefix */) {
+ idx_++;
+ return *this;
+ }
+
+ StackIteratorImpl operator++(int /* postfix */) {
+ StackIteratorImpl copy(*this);
+ ++(*this);
+ return copy;
+ }
+
+ private:
+ const Stack *sk_;
+ size_t idx_;
+};
+
+template <typename Stack>
+using StackIterator = typename std::enable_if<StackTraits<Stack>::kIsStack,
+ StackIteratorImpl<Stack>>::type;
+
+} // namespace internal
+
+// PushToStack pushes |elem| to |sk|. It returns true on success and false on
+// allocation failure.
+template <typename Stack>
+static inline
+ typename std::enable_if<!internal::StackTraits<Stack>::kIsConst, bool>::type
+ PushToStack(Stack *sk,
+ UniquePtr<typename internal::StackTraits<Stack>::Type> elem) {
+ if (!sk_push(reinterpret_cast<_STACK *>(sk), elem.get())) {
+ return false;
+ }
+ // sk_push takes ownership on success.
+ elem.release();
+ return true;
+}
+
+} // namespace bssl
+
+// Define begin() and end() for stack types so C++ range for loops work.
+template <typename Stack>
+static inline bssl::internal::StackIterator<Stack> begin(const Stack *sk) {
+ return bssl::internal::StackIterator<Stack>(sk, 0);
+}
+
+template <typename Stack>
+static inline bssl::internal::StackIterator<Stack> end(const Stack *sk) {
+ return bssl::internal::StackIterator<Stack>(
+ sk, sk_num(reinterpret_cast<const _STACK *>(sk)));
+}
+
+} // extern C++
+#endif
+
#endif /* OPENSSL_HEADER_STACK_H */
diff --git a/src/include/openssl/x509.h b/src/include/openssl/x509.h
index efd8c784..138c060e 100644
--- a/src/include/openssl/x509.h
+++ b/src/include/openssl/x509.h
@@ -1094,16 +1094,13 @@ DECLARE_ASN1_FUNCTIONS(RSA_PSS_PARAMS)
#ifdef __cplusplus
}
+#endif
+#if !defined(BORINGSSL_NO_CXX)
extern "C++" {
namespace bssl {
-BORINGSSL_MAKE_STACK_DELETER(X509, X509_free)
-BORINGSSL_MAKE_STACK_DELETER(X509_CRL, X509_CRL_free)
-BORINGSSL_MAKE_STACK_DELETER(X509_EXTENSION, X509_EXTENSION_free)
-BORINGSSL_MAKE_STACK_DELETER(X509_NAME, X509_NAME_free)
-
BORINGSSL_MAKE_DELETER(NETSCAPE_SPKI, NETSCAPE_SPKI_free)
BORINGSSL_MAKE_DELETER(X509, X509_free)
BORINGSSL_MAKE_DELETER(X509_ALGOR, X509_ALGOR_free)
@@ -1123,11 +1120,14 @@ BORINGSSL_MAKE_DELETER(X509_STORE, X509_STORE_free)
BORINGSSL_MAKE_DELETER(X509_STORE_CTX, X509_STORE_CTX_free)
BORINGSSL_MAKE_DELETER(X509_VERIFY_PARAM, X509_VERIFY_PARAM_free)
+using ScopedX509_STORE_CTX =
+ internal::StackAllocated<X509_STORE_CTX, void, X509_STORE_CTX_zero,
+ X509_STORE_CTX_cleanup>;
+
} // namespace bssl
} /* extern C++ */
-
-#endif
+#endif /* !BORINGSSL_NO_CXX */
#define X509_R_AKID_MISMATCH 100
#define X509_R_BAD_PKCS7_VERSION 101
diff --git a/src/include/openssl/x509_vfy.h b/src/include/openssl/x509_vfy.h
index ac739eaa..4abd9cda 100644
--- a/src/include/openssl/x509_vfy.h
+++ b/src/include/openssl/x509_vfy.h
@@ -449,6 +449,7 @@ OPENSSL_EXPORT X509_STORE_CTX *X509_STORE_CTX_new(void);
OPENSSL_EXPORT int X509_STORE_CTX_get1_issuer(X509 **issuer, X509_STORE_CTX *ctx, X509 *x);
+OPENSSL_EXPORT void X509_STORE_CTX_zero(X509_STORE_CTX *ctx);
OPENSSL_EXPORT void X509_STORE_CTX_free(X509_STORE_CTX *ctx);
OPENSSL_EXPORT int X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store,
X509 *x509, STACK_OF(X509) *chain);
diff --git a/src/include/openssl/x509v3.h b/src/include/openssl/x509v3.h
index 7375d23c..dd56bbcc 100644
--- a/src/include/openssl/x509v3.h
+++ b/src/include/openssl/x509v3.h
@@ -747,15 +747,11 @@ extern "C++" {
namespace bssl {
-BORINGSSL_MAKE_STACK_DELETER(DIST_POINT, DIST_POINT_free)
-BORINGSSL_MAKE_STACK_DELETER(GENERAL_NAME, GENERAL_NAME_free)
-// A STACK_OF(POLICYINFO) is also known as a CERTIFICATEPOLICIES.
-BORINGSSL_MAKE_STACK_DELETER(POLICYINFO, POLICYINFO_free)
-
BORINGSSL_MAKE_DELETER(AUTHORITY_KEYID, AUTHORITY_KEYID_free)
BORINGSSL_MAKE_DELETER(BASIC_CONSTRAINTS, BASIC_CONSTRAINTS_free)
BORINGSSL_MAKE_DELETER(DIST_POINT, DIST_POINT_free)
BORINGSSL_MAKE_DELETER(GENERAL_NAME, GENERAL_NAME_free)
+BORINGSSL_MAKE_DELETER(POLICYINFO, POLICYINFO_free)
} // namespace bssl
diff --git a/src/ssl/CMakeLists.txt b/src/ssl/CMakeLists.txt
index c228f4a6..d9d2eb5b 100644
--- a/src/ssl/CMakeLists.txt
+++ b/src/ssl/CMakeLists.txt
@@ -45,6 +45,7 @@ target_link_libraries(ssl crypto)
add_executable(
ssl_test
+ span_test.cc
ssl_test.cc
$<TARGET_OBJECTS:gtest_main>
diff --git a/src/ssl/d1_both.cc b/src/ssl/d1_both.cc
index 50cca832..2fa0183c 100644
--- a/src/ssl/d1_both.cc
+++ b/src/ssl/d1_both.cc
@@ -298,12 +298,10 @@ static hm_fragment *dtls1_get_incoming_message(
return frag;
}
-/* dtls1_process_handshake_record reads a handshake record and processes it. It
- * returns one if the record was successfully processed and 0 or -1 on error. */
+/* dtls1_process_handshake_record reads a record for the handshake and processes
+ * it. It returns one on success and 0 or -1 on error. */
static int dtls1_process_handshake_record(SSL *ssl) {
SSL3_RECORD *rr = &ssl->s3->rrec;
-
-start:
if (rr->length == 0) {
int ret = dtls1_get_record(ssl);
if (ret <= 0) {
@@ -311,27 +309,53 @@ start:
}
}
- /* Cross-epoch records are discarded, but we may receive out-of-order
- * application data between ChangeCipherSpec and Finished or a
- * ChangeCipherSpec before the appropriate point in the handshake. Those must
- * be silently discarded.
- *
- * However, only allow the out-of-order records in the correct epoch.
- * Application data must come in the encrypted epoch, and ChangeCipherSpec in
- * the unencrypted epoch (we never renegotiate). Other cases fall through and
- * fail with a fatal error. */
- if ((rr->type == SSL3_RT_APPLICATION_DATA &&
- !ssl->s3->aead_read_ctx->is_null_cipher()) ||
- (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC &&
- ssl->s3->aead_read_ctx->is_null_cipher())) {
- rr->length = 0;
- goto start;
- }
+ switch (rr->type) {
+ case SSL3_RT_APPLICATION_DATA:
+ /* Unencrypted application data records are always illegal. */
+ if (ssl->s3->aead_read_ctx->is_null_cipher()) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD);
+ return -1;
+ }
+
+ /* Out-of-order application data may be received between ChangeCipherSpec
+ * and finished. Discard it. */
+ rr->length = 0;
+ ssl_read_buffer_discard(ssl);
+ return 1;
+
+ case SSL3_RT_CHANGE_CIPHER_SPEC:
+ /* We do not support renegotiation, so encrypted ChangeCipherSpec records
+ * are illegal. */
+ if (!ssl->s3->aead_read_ctx->is_null_cipher()) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD);
+ return -1;
+ }
+
+ if (rr->length != 1 || rr->data[0] != SSL3_MT_CCS) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_CHANGE_CIPHER_SPEC);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+ return -1;
+ }
+
+ /* Flag the ChangeCipherSpec for later. */
+ ssl->d1->has_change_cipher_spec = true;
+ ssl_do_msg_callback(ssl, 0 /* read */, SSL3_RT_CHANGE_CIPHER_SPEC,
+ rr->data, rr->length);
+
+ rr->length = 0;
+ ssl_read_buffer_discard(ssl);
+ return 1;
+
+ case SSL3_RT_HANDSHAKE:
+ /* Break out to main processing. */
+ break;
- if (rr->type != SSL3_RT_HANDSHAKE) {
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
- OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD);
- return -1;
+ default:
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD);
+ return -1;
}
CBS cbs;
@@ -418,14 +442,16 @@ int dtls1_get_message(SSL *ssl) {
assert(frag->reassembly == NULL);
assert(ssl->d1->handshake_read_seq == frag->seq);
+ if (ssl->init_msg == NULL) {
+ ssl_do_msg_callback(ssl, 0 /* read */, SSL3_RT_HANDSHAKE, frag->data,
+ frag->msg_len + DTLS1_HM_HEADER_LENGTH);
+ }
+
/* TODO(davidben): This function has a lot of implicit outputs. Simplify the
* |ssl_get_message| API. */
ssl->s3->tmp.message_type = frag->type;
ssl->init_msg = frag->data + DTLS1_HM_HEADER_LENGTH;
ssl->init_num = frag->msg_len;
-
- ssl_do_msg_callback(ssl, 0 /* read */, SSL3_RT_HANDSHAKE, frag->data,
- ssl->init_num + DTLS1_HM_HEADER_LENGTH);
return 1;
}
@@ -490,6 +516,19 @@ int dtls1_parse_fragment(CBS *cbs, struct hm_header_st *out_hdr,
return 1;
}
+int dtls1_read_change_cipher_spec(SSL *ssl) {
+ /* Process handshake records until there is a ChangeCipherSpec. */
+ while (!ssl->d1->has_change_cipher_spec) {
+ int ret = dtls1_process_handshake_record(ssl);
+ if (ret <= 0) {
+ return ret;
+ }
+ }
+
+ ssl->d1->has_change_cipher_spec = false;
+ return 1;
+}
+
/* Sending handshake messages. */
@@ -501,6 +540,7 @@ void dtls_clear_outgoing_messages(SSL *ssl) {
ssl->d1->outgoing_messages_len = 0;
ssl->d1->outgoing_written = 0;
ssl->d1->outgoing_offset = 0;
+ ssl->d1->outgoing_messages_complete = false;
}
int dtls1_init_message(SSL *ssl, CBB *cbb, CBB *body, uint8_t type) {
@@ -538,6 +578,13 @@ int dtls1_finish_message(SSL *ssl, CBB *cbb, uint8_t **out_msg,
* it takes ownership of |data| and releases it with |OPENSSL_free| when
* done. */
static int add_outgoing(SSL *ssl, int is_ccs, uint8_t *data, size_t len) {
+ if (ssl->d1->outgoing_messages_complete) {
+ /* If we've begun writing a new flight, we received the peer flight. Discard
+ * the timer and the our flight. */
+ dtls1_stop_timer(ssl);
+ dtls_clear_outgoing_messages(ssl);
+ }
+
static_assert(SSL_MAX_HANDSHAKE_FLIGHT <
(1 << 8 * sizeof(ssl->d1->outgoing_messages_len)),
"outgoing_messages_len is too small");
@@ -756,7 +803,7 @@ packet_full:
return 1;
}
-int dtls1_flush_flight(SSL *ssl) {
+static int send_flight(SSL *ssl) {
dtls1_update_mtu(ssl);
int ret = -1;
@@ -798,6 +845,13 @@ err:
return ret;
}
+int dtls1_flush_flight(SSL *ssl) {
+ ssl->d1->outgoing_messages_complete = true;
+ /* Start the retransmission timer for the next flight (if any). */
+ dtls1_start_timer(ssl);
+ return send_flight(ssl);
+}
+
int dtls1_retransmit_outgoing_messages(SSL *ssl) {
/* Rewind to the start of the flight and write it again.
*
@@ -806,7 +860,7 @@ int dtls1_retransmit_outgoing_messages(SSL *ssl) {
ssl->d1->outgoing_written = 0;
ssl->d1->outgoing_offset = 0;
- return dtls1_flush_flight(ssl);
+ return send_flight(ssl);
}
unsigned int dtls1_min_mtu(void) {
diff --git a/src/ssl/d1_lib.cc b/src/ssl/d1_lib.cc
index 8ef1aa22..30110b44 100644
--- a/src/ssl/d1_lib.cc
+++ b/src/ssl/d1_lib.cc
@@ -150,22 +150,17 @@ int dtls1_is_timer_expired(SSL *ssl) {
return 1;
}
-void dtls1_double_timeout(SSL *ssl) {
+static void dtls1_double_timeout(SSL *ssl) {
ssl->d1->timeout_duration_ms *= 2;
if (ssl->d1->timeout_duration_ms > 60000) {
ssl->d1->timeout_duration_ms = 60000;
}
- dtls1_start_timer(ssl);
}
void dtls1_stop_timer(SSL *ssl) {
- /* Reset everything */
ssl->d1->num_timeouts = 0;
OPENSSL_memset(&ssl->d1->next_timeout, 0, sizeof(ssl->d1->next_timeout));
ssl->d1->timeout_duration_ms = ssl->initial_timeout_duration_ms;
-
- /* Clear retransmission buffer */
- dtls_clear_outgoing_messages(ssl);
}
int dtls1_check_timeout_num(SSL *ssl) {
@@ -183,10 +178,10 @@ int dtls1_check_timeout_num(SSL *ssl) {
if (ssl->d1->num_timeouts > DTLS1_MAX_TIMEOUTS) {
/* fail the connection, enough alerts have been sent */
OPENSSL_PUT_ERROR(SSL, SSL_R_READ_TIMEOUT_EXPIRED);
- return -1;
+ return 0;
}
- return 0;
+ return 1;
}
} // namespace bssl
@@ -202,7 +197,7 @@ int DTLSv1_get_timeout(const SSL *ssl, struct timeval *out) {
return 0;
}
- /* If no timeout is set, just return NULL */
+ /* If no timeout is set, just return 0. */
if (ssl->d1->next_timeout.tv_sec == 0 && ssl->d1->next_timeout.tv_usec == 0) {
return 0;
}
@@ -210,7 +205,7 @@ int DTLSv1_get_timeout(const SSL *ssl, struct timeval *out) {
struct OPENSSL_timeval timenow;
ssl_get_current_time(ssl, &timenow);
- /* If timer already expired, set remaining time to 0 */
+ /* If timer already expired, set remaining time to 0. */
if (ssl->d1->next_timeout.tv_sec < timenow.tv_sec ||
(ssl->d1->next_timeout.tv_sec == timenow.tv_sec &&
ssl->d1->next_timeout.tv_usec <= timenow.tv_usec)) {
@@ -218,7 +213,7 @@ int DTLSv1_get_timeout(const SSL *ssl, struct timeval *out) {
return 1;
}
- /* Calculate time left until timer expires */
+ /* Calculate time left until timer expires. */
struct OPENSSL_timeval ret;
OPENSSL_memcpy(&ret, &ssl->d1->next_timeout, sizeof(ret));
ret.tv_sec -= timenow.tv_sec;
@@ -251,20 +246,20 @@ int DTLSv1_handle_timeout(SSL *ssl) {
ssl_reset_error_state(ssl);
if (!SSL_is_dtls(ssl)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
return -1;
}
- /* if no timer is expired, don't do anything */
+ /* If no timer is expired, don't do anything. */
if (!dtls1_is_timer_expired(ssl)) {
return 0;
}
- dtls1_double_timeout(ssl);
-
- if (dtls1_check_timeout_num(ssl) < 0) {
+ if (!dtls1_check_timeout_num(ssl)) {
return -1;
}
+ dtls1_double_timeout(ssl);
dtls1_start_timer(ssl);
return dtls1_retransmit_outgoing_messages(ssl);
}
diff --git a/src/ssl/d1_pkt.cc b/src/ssl/d1_pkt.cc
index 52e81115..38412327 100644
--- a/src/ssl/d1_pkt.cc
+++ b/src/ssl/d1_pkt.cc
@@ -239,7 +239,7 @@ again:
/* Retransmit our last flight of messages. If the peer sends the second
* Finished, they may not have received ours. Only do this for the
* first fragment, in case the Finished was fragmented. */
- if (dtls1_check_timeout_num(ssl) < 0) {
+ if (!dtls1_check_timeout_num(ssl)) {
return -1;
}
@@ -288,46 +288,6 @@ again:
return len;
}
-int dtls1_read_change_cipher_spec(SSL *ssl) {
- SSL3_RECORD *rr = &ssl->s3->rrec;
-
-again:
- if (rr->length == 0) {
- int ret = dtls1_get_record(ssl);
- if (ret <= 0) {
- return ret;
- }
- }
-
- /* Drop handshake records silently. The epochs match, so this must be a
- * retransmit of a message we already received. */
- if (rr->type == SSL3_RT_HANDSHAKE) {
- rr->length = 0;
- goto again;
- }
-
- /* Other record types are illegal in this epoch. Note all application data
- * records come in the encrypted epoch. */
- if (rr->type != SSL3_RT_CHANGE_CIPHER_SPEC) {
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
- OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD);
- return -1;
- }
-
- if (rr->length != 1 || rr->data[0] != SSL3_MT_CCS) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_CHANGE_CIPHER_SPEC);
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
- return -1;
- }
-
- ssl_do_msg_callback(ssl, 0 /* read */, SSL3_RT_CHANGE_CIPHER_SPEC, rr->data,
- rr->length);
-
- rr->length = 0;
- ssl_read_buffer_discard(ssl);
- return 1;
-}
-
void dtls1_read_close_notify(SSL *ssl) {
/* Bidirectional shutdown doesn't make sense for an unordered transport. DTLS
* alerts also aren't delivered reliably, so we may even time out because the
diff --git a/src/ssl/dtls_method.cc b/src/ssl/dtls_method.cc
index 15c46083..947cfceb 100644
--- a/src/ssl/dtls_method.cc
+++ b/src/ssl/dtls_method.cc
@@ -72,13 +72,16 @@ static int dtls1_supports_cipher(const SSL_CIPHER *cipher) {
return cipher->algorithm_enc != SSL_eNULL;
}
-static void dtls1_expect_flight(SSL *ssl) { dtls1_start_timer(ssl); }
-
-static void dtls1_received_flight(SSL *ssl) { dtls1_stop_timer(ssl); }
+static void dtls1_on_handshake_complete(SSL *ssl) {
+ /* If we wrote the last flight, we'll have a timer left over without waiting
+ * for a read. Stop the timer but leave the flight around for post-handshake
+ * transmission logic. */
+ dtls1_stop_timer(ssl);
+}
static int dtls1_set_read_state(SSL *ssl, UniquePtr<SSLAEADContext> aead_ctx) {
/* Cipher changes are illegal when there are buffered incoming messages. */
- if (dtls_has_incoming_messages(ssl)) {
+ if (dtls_has_incoming_messages(ssl) || ssl->d1->has_change_cipher_spec) {
OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFERED_MESSAGES_ON_CIPHER_CHANGE);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
return 0;
@@ -124,8 +127,7 @@ static const SSL_PROTOCOL_METHOD kDTLSProtocolMethod = {
dtls1_add_change_cipher_spec,
dtls1_add_alert,
dtls1_flush_flight,
- dtls1_expect_flight,
- dtls1_received_flight,
+ dtls1_on_handshake_complete,
dtls1_set_read_state,
dtls1_set_write_state,
};
diff --git a/src/ssl/handshake_client.cc b/src/ssl/handshake_client.cc
index 260d3cd0..946316db 100644
--- a/src/ssl/handshake_client.cc
+++ b/src/ssl/handshake_client.cc
@@ -238,7 +238,6 @@ int ssl3_connect(SSL_HANDSHAKE *hs) {
goto end;
}
if (ssl->d1->send_cookie) {
- ssl->method->received_flight(ssl);
hs->state = SSL3_ST_CW_CLNT_HELLO_A;
} else {
hs->state = SSL3_ST_CR_SRVR_HELLO_A;
@@ -333,7 +332,6 @@ int ssl3_connect(SSL_HANDSHAKE *hs) {
if (ret <= 0) {
goto end;
}
- ssl->method->received_flight(ssl);
hs->state = SSL3_ST_CW_CERT_A;
break;
@@ -460,7 +458,6 @@ int ssl3_connect(SSL_HANDSHAKE *hs) {
if (ret <= 0) {
goto end;
}
- ssl->method->received_flight(ssl);
if (ssl->session != NULL) {
hs->state = SSL3_ST_CW_CHANGE;
@@ -475,9 +472,6 @@ int ssl3_connect(SSL_HANDSHAKE *hs) {
goto end;
}
hs->state = hs->next_state;
- if (hs->state != SSL3_ST_FINISH_CLIENT_HANDSHAKE) {
- ssl->method->expect_flight(ssl);
- }
break;
case SSL_ST_TLS13: {
@@ -497,6 +491,7 @@ int ssl3_connect(SSL_HANDSHAKE *hs) {
}
case SSL3_ST_FINISH_CLIENT_HANDSHAKE:
+ ssl->method->on_handshake_complete(ssl);
ssl->method->release_current_message(ssl, 1 /* free_buffer */);
SSL_SESSION_free(ssl->s3->established_session);
@@ -599,10 +594,8 @@ static int ssl_write_client_cipher_list(SSL_HANDSHAKE *hs, CBB *out) {
}
if (hs->min_version < TLS1_3_VERSION) {
- STACK_OF(SSL_CIPHER) *ciphers = SSL_get_ciphers(ssl);
int any_enabled = 0;
- for (size_t i = 0; i < sk_SSL_CIPHER_num(ciphers); i++) {
- const SSL_CIPHER *cipher = sk_SSL_CIPHER_value(ciphers, i);
+ for (const SSL_CIPHER *cipher : SSL_get_ciphers(ssl)) {
/* Skip disabled ciphers */
if ((cipher->algorithm_mkey & mask_k) ||
(cipher->algorithm_auth & mask_a)) {
@@ -783,7 +776,7 @@ static int dtls1_get_hello_verify_request(SSL_HANDSHAKE *hs) {
}
if (ssl->s3->tmp.message_type != DTLS1_MT_HELLO_VERIFY_REQUEST) {
- ssl->d1->send_cookie = 0;
+ ssl->d1->send_cookie = false;
ssl->s3->tmp.reuse_message = 1;
return 1;
}
@@ -801,7 +794,7 @@ static int dtls1_get_hello_verify_request(SSL_HANDSHAKE *hs) {
OPENSSL_memcpy(ssl->d1->cookie, CBS_data(&cookie), CBS_len(&cookie));
ssl->d1->cookie_len = CBS_len(&cookie);
- ssl->d1->send_cookie = 1;
+ ssl->d1->send_cookie = true;
return 1;
}
@@ -1087,15 +1080,14 @@ static int ssl3_get_server_certificate(SSL_HANDSHAKE *hs) {
CBS_init(&cbs, ssl->init_msg, ssl->init_num);
uint8_t alert = SSL_AD_DECODE_ERROR;
- sk_CRYPTO_BUFFER_pop_free(hs->new_session->certs, CRYPTO_BUFFER_free);
- hs->peer_pubkey.reset();
- hs->new_session->certs =
- ssl_parse_cert_chain(&alert, &hs->peer_pubkey, NULL, &cbs, ssl->ctx->pool)
- .release();
- if (hs->new_session->certs == NULL) {
+ UniquePtr<STACK_OF(CRYPTO_BUFFER)> chain;
+ if (!ssl_parse_cert_chain(&alert, &chain, &hs->peer_pubkey, NULL, &cbs,
+ ssl->ctx->pool)) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
return -1;
}
+ sk_CRYPTO_BUFFER_pop_free(hs->new_session->certs, CRYPTO_BUFFER_free);
+ hs->new_session->certs = chain.release();
if (sk_CRYPTO_BUFFER_num(hs->new_session->certs) == 0 ||
CBS_len(&cbs) != 0 ||
diff --git a/src/ssl/handshake_server.cc b/src/ssl/handshake_server.cc
index 38fbef4b..47fdc61c 100644
--- a/src/ssl/handshake_server.cc
+++ b/src/ssl/handshake_server.cc
@@ -233,7 +233,6 @@ int ssl3_accept(SSL_HANDSHAKE *hs) {
if (ret <= 0) {
goto end;
}
- ssl->method->received_flight(ssl);
hs->state = SSL3_ST_SW_SRVR_HELLO_A;
break;
@@ -362,7 +361,6 @@ int ssl3_accept(SSL_HANDSHAKE *hs) {
goto end;
}
- ssl->method->received_flight(ssl);
if (ssl->session != NULL) {
hs->state = SSL_ST_OK;
} else {
@@ -400,9 +398,6 @@ int ssl3_accept(SSL_HANDSHAKE *hs) {
}
hs->state = hs->next_state;
- if (hs->state != SSL_ST_OK) {
- ssl->method->expect_flight(ssl);
- }
break;
case SSL_ST_TLS13: {
@@ -422,6 +417,7 @@ int ssl3_accept(SSL_HANDSHAKE *hs) {
}
case SSL_ST_OK:
+ ssl->method->on_handshake_complete(ssl);
ssl->method->release_current_message(ssl, 1 /* free_buffer */);
/* If we aren't retaining peer certificates then we can discard it
@@ -558,16 +554,16 @@ static int negotiate_version(SSL_HANDSHAKE *hs, uint8_t *out_alert,
return 1;
}
-static STACK_OF(SSL_CIPHER) *
- ssl_parse_client_cipher_list(const SSL_CLIENT_HELLO *client_hello) {
+static UniquePtr<STACK_OF(SSL_CIPHER)> ssl_parse_client_cipher_list(
+ const SSL_CLIENT_HELLO *client_hello) {
CBS cipher_suites;
CBS_init(&cipher_suites, client_hello->cipher_suites,
client_hello->cipher_suites_len);
- STACK_OF(SSL_CIPHER) *sk = sk_SSL_CIPHER_new_null();
- if (sk == NULL) {
+ UniquePtr<STACK_OF(SSL_CIPHER)> sk(sk_SSL_CIPHER_new_null());
+ if (!sk) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
- goto err;
+ return nullptr;
}
while (CBS_len(&cipher_suites) > 0) {
@@ -575,21 +571,17 @@ static STACK_OF(SSL_CIPHER) *
if (!CBS_get_u16(&cipher_suites, &cipher_suite)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST);
- goto err;
+ return nullptr;
}
const SSL_CIPHER *c = SSL_get_cipher_by_value(cipher_suite);
- if (c != NULL && !sk_SSL_CIPHER_push(sk, c)) {
+ if (c != NULL && !sk_SSL_CIPHER_push(sk.get(), c)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
- goto err;
+ return nullptr;
}
}
return sk;
-
-err:
- sk_SSL_CIPHER_free(sk);
- return NULL;
}
/* ssl_get_compatible_server_ciphers determines the key exchange and
@@ -640,18 +632,18 @@ static const SSL_CIPHER *ssl3_choose_cipher(
* such value exists yet. */
int group_min = -1;
- STACK_OF(SSL_CIPHER) *client_pref =
+ UniquePtr<STACK_OF(SSL_CIPHER)> client_pref =
ssl_parse_client_cipher_list(client_hello);
- if (client_pref == NULL) {
- return NULL;
+ if (!client_pref) {
+ return nullptr;
}
if (ssl->options & SSL_OP_CIPHER_SERVER_PREFERENCE) {
prio = server_pref->ciphers;
in_group_flags = server_pref->in_group_flags;
- allow = client_pref;
+ allow = client_pref.get();
} else {
- prio = client_pref;
+ prio = client_pref.get();
in_group_flags = NULL;
allow = server_pref->ciphers;
}
@@ -659,7 +651,6 @@ static const SSL_CIPHER *ssl3_choose_cipher(
uint32_t mask_k, mask_a;
ssl_get_compatible_server_ciphers(hs, &mask_k, &mask_a);
- const SSL_CIPHER *ret = NULL;
for (size_t i = 0; i < sk_SSL_CIPHER_num(prio); i++) {
const SSL_CIPHER *c = sk_SSL_CIPHER_value(prio, i);
@@ -682,21 +673,18 @@ static const SSL_CIPHER *ssl3_choose_cipher(
if (group_min != -1 && (size_t)group_min < cipher_index) {
cipher_index = group_min;
}
- ret = sk_SSL_CIPHER_value(allow, cipher_index);
- break;
+ return sk_SSL_CIPHER_value(allow, cipher_index);
}
}
if (in_group_flags != NULL && in_group_flags[i] == 0 && group_min != -1) {
/* We are about to leave a group, but we found a match in it, so that's
* our answer. */
- ret = sk_SSL_CIPHER_value(allow, group_min);
- break;
+ return sk_SSL_CIPHER_value(allow, group_min);
}
}
- sk_SSL_CIPHER_free(client_pref);
- return ret;
+ return nullptr;
}
static int ssl3_process_client_hello(SSL_HANDSHAKE *hs) {
@@ -825,14 +813,10 @@ static int ssl3_select_parameters(SSL_HANDSHAKE *hs) {
}
/* Determine whether we are doing session resumption. */
+ UniquePtr<SSL_SESSION> session;
int tickets_supported = 0, renew_ticket = 0;
- /* TODO(davidben): Switch |ssl_get_prev_session| to take a |UniquePtr|
- * output and simplify this. */
- SSL_SESSION *session_raw = nullptr;
- auto session_ret = ssl_get_prev_session(ssl, &session_raw, &tickets_supported,
- &renew_ticket, &client_hello);
- UniquePtr<SSL_SESSION> session(session_raw);
- switch (session_ret) {
+ switch (ssl_get_prev_session(ssl, &session, &tickets_supported, &renew_ticket,
+ &client_hello)) {
case ssl_session_success:
break;
case ssl_session_error:
@@ -1228,20 +1212,18 @@ static int ssl3_get_client_certificate(SSL_HANDSHAKE *hs) {
CBS certificate_msg;
CBS_init(&certificate_msg, ssl->init_msg, ssl->init_num);
- sk_CRYPTO_BUFFER_pop_free(hs->new_session->certs, CRYPTO_BUFFER_free);
- hs->peer_pubkey.reset();
uint8_t alert = SSL_AD_DECODE_ERROR;
- hs->new_session->certs =
- ssl_parse_cert_chain(&alert, &hs->peer_pubkey,
- ssl->retain_only_sha256_of_client_certs
- ? hs->new_session->peer_sha256
- : NULL,
- &certificate_msg, ssl->ctx->pool)
- .release();
- if (hs->new_session->certs == NULL) {
+ UniquePtr<STACK_OF(CRYPTO_BUFFER)> chain;
+ if (!ssl_parse_cert_chain(&alert, &chain, &hs->peer_pubkey,
+ ssl->retain_only_sha256_of_client_certs
+ ? hs->new_session->peer_sha256
+ : NULL,
+ &certificate_msg, ssl->ctx->pool)) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
return -1;
}
+ sk_CRYPTO_BUFFER_pop_free(hs->new_session->certs, CRYPTO_BUFFER_free);
+ hs->new_session->certs = chain.release();
if (CBS_len(&certificate_msg) != 0 ||
!ssl->ctx->x509_method->session_cache_objects(hs->new_session.get())) {
diff --git a/src/ssl/internal.h b/src/ssl/internal.h
index fb02d35f..2d3557cd 100644
--- a/src/ssl/internal.h
+++ b/src/ssl/internal.h
@@ -144,6 +144,9 @@
#include <openssl/base.h>
+#include <stdlib.h>
+
+#include <new>
#include <type_traits>
#include <utility>
@@ -179,13 +182,12 @@ struct SSL_HANDSHAKE;
* Note: unlike |new|, this does not support non-public constructors. */
template <typename T, typename... Args>
T *New(Args &&... args) {
- T *t = reinterpret_cast<T *>(OPENSSL_malloc(sizeof(T)));
+ void *t = OPENSSL_malloc(sizeof(T));
if (t == nullptr) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
return nullptr;
}
- new (t) T(std::forward<Args>(args)...);
- return t;
+ return new (t) T(std::forward<Args>(args)...);
}
/* Delete behaves like |delete| but uses |OPENSSL_free| to release memory.
@@ -199,13 +201,11 @@ void Delete(T *t) {
}
}
-/* Register all types with non-trivial destructors with |UniquePtr|. Types with
- * trivial destructors may be C structs which require a |BORINGSSL_MAKE_DELETER|
- * registration. */
+/* All types with kAllowUniquePtr set may be used with UniquePtr. Other types
+ * may be C structs which require a |BORINGSSL_MAKE_DELETER| registration. */
namespace internal {
template <typename T>
-struct DeleterImpl<T, typename std::enable_if<
- !std::is_trivially_destructible<T>::value>::type> {
+struct DeleterImpl<T, typename std::enable_if<T::kAllowUniquePtr>::type> {
static void Free(T *t) { Delete(t); }
};
}
@@ -217,6 +217,22 @@ UniquePtr<T> MakeUnique(Args &&... args) {
return UniquePtr<T>(New<T>(std::forward<Args>(args)...));
}
+#if defined(BORINGSSL_ALLOW_CXX_RUNTIME)
+#define HAS_VIRTUAL_DESTRUCTOR
+#define PURE_VIRTUAL = 0
+#else
+/* HAS_VIRTUAL_DESTRUCTOR should be declared in any base clas ~s which defines a
+ * virtual destructor. This avoids a dependency on |_ZdlPv| and prevents the
+ * class from being used with |delete|. */
+#define HAS_VIRTUAL_DESTRUCTOR \
+ void operator delete(void *) { abort(); }
+
+/* PURE_VIRTUAL should be used instead of = 0 when defining pure-virtual
+ * functions. This avoids a dependency on |__cxa_pure_virtual| but loses
+ * compile-time checking. */
+#define PURE_VIRTUAL { abort(); }
+#endif
+
/* Protocol versions.
*
@@ -452,6 +468,8 @@ class SSLAEADContext {
public:
SSLAEADContext(uint16_t version, const SSL_CIPHER *cipher);
~SSLAEADContext();
+ static constexpr bool kAllowUniquePtr = true;
+
SSLAEADContext(const SSLAEADContext &&) = delete;
SSLAEADContext &operator=(const SSLAEADContext &&) = delete;
@@ -480,10 +498,12 @@ class SSLAEADContext {
/* MaxOverhead returns the maximum overhead of calling |Seal|. */
size_t MaxOverhead() const;
- /* MaxSuffixLen returns the maximum suffix length written by |SealScatter|.
- * |extra_in_len| should equal the argument of the same name passed to
- * |SealScatter|. */
- size_t MaxSuffixLen(size_t extra_in_len) const;
+ /* SuffixLen calculates the suffix length written by |SealScatter| and writes
+ * it to |*out_suffix_len|. It returns true on success and false on error.
+ * |in_len| and |extra_in_len| should equal the argument of the same names
+ * passed to |SealScatter|. */
+ bool SuffixLen(size_t *out_suffix_len, size_t in_len,
+ size_t extra_in_len) const;
/* Open authenticates and decrypts |in_len| bytes from |in| in-place. On
* success, it sets |*out| to the plaintext in |in| and returns true.
@@ -505,19 +525,17 @@ class SSLAEADContext {
* success and zero on error.
*
* On successful return, exactly |ExplicitNonceLen| bytes are written to
- * |out_prefix|, |in_len| bytes to |out|, and up to |MaxSuffixLen| bytes to
- * |out_suffix|. |*out_suffix_len| is set to the actual number of bytes
- * written to |out_suffix|.
+ * |out_prefix|, |in_len| bytes to |out|, and |SuffixLen| bytes to
+ * |out_suffix|.
*
* |extra_in| may point to an additional plaintext buffer. If present,
* |extra_in_len| additional bytes are encrypted and authenticated, and the
- * ciphertext is written to the beginning of |out_suffix|. |MaxSuffixLen|
- * may be used to size |out_suffix| accordingly.
+ * ciphertext is written to the beginning of |out_suffix|. |SuffixLen| should
+ * be used to size |out_suffix| accordingly.
*
* If |in| and |out| alias then |out| must be == |in|. Other arguments may not
* alias anything. */
bool SealScatter(uint8_t *out_prefix, uint8_t *out, uint8_t *out_suffix,
- size_t *out_suffix_len, size_t max_out_suffix_len,
uint8_t type, uint16_t wire_version, const uint8_t seqnum[8],
const uint8_t *in, size_t in_len, const uint8_t *extra_in,
size_t extra_in_len);
@@ -698,7 +716,7 @@ int ssl_has_private_key(const SSL *ssl);
enum ssl_private_key_result_t ssl_private_key_sign(
SSL_HANDSHAKE *hs, uint8_t *out, size_t *out_len, size_t max_out,
- uint16_t signature_algorithm, const uint8_t *in, size_t in_len);
+ uint16_t sigalg, const uint8_t *in, size_t in_len);
enum ssl_private_key_result_t ssl_private_key_decrypt(
SSL_HANDSHAKE *hs, uint8_t *out, size_t *out_len, size_t max_out,
@@ -710,11 +728,10 @@ int ssl_private_key_supports_signature_algorithm(SSL_HANDSHAKE *hs,
uint16_t sigalg);
/* ssl_public_key_verify verifies that the |signature| is valid for the public
- * key |pkey| and input |in|, using the |signature_algorithm| specified. */
-int ssl_public_key_verify(
- SSL *ssl, const uint8_t *signature, size_t signature_len,
- uint16_t signature_algorithm, EVP_PKEY *pkey,
- const uint8_t *in, size_t in_len);
+ * key |pkey| and input |in|, using the signature algorithm |sigalg|. */
+int ssl_public_key_verify(SSL *ssl, const uint8_t *signature,
+ size_t signature_len, uint16_t sigalg, EVP_PKEY *pkey,
+ const uint8_t *in, size_t in_len);
/* Custom extensions */
@@ -753,17 +770,19 @@ int custom_ext_add_serverhello(SSL_HANDSHAKE *hs, CBB *extensions);
class SSLKeyShare {
public:
virtual ~SSLKeyShare() {}
+ static constexpr bool kAllowUniquePtr = true;
+ HAS_VIRTUAL_DESTRUCTOR
/* Create returns a SSLKeyShare instance for use with group |group_id| or
* nullptr on error. */
static UniquePtr<SSLKeyShare> Create(uint16_t group_id);
/* GroupID returns the group ID. */
- virtual uint16_t GroupID() const = 0;
+ virtual uint16_t GroupID() const PURE_VIRTUAL;
/* Offer generates a keypair and writes the public value to
* |out_public_key|. It returns true on success and false on error. */
- virtual bool Offer(CBB *out_public_key) = 0;
+ virtual bool Offer(CBB *out_public_key) PURE_VIRTUAL;
/* Accept performs a key exchange against the |peer_key| generated by |offer|.
* On success, it returns true, writes the public value to |out_public_key|,
@@ -790,7 +809,7 @@ class SSLKeyShare {
* TODO(davidben): out_secret should be a smart pointer. */
virtual bool Finish(uint8_t **out_secret, size_t *out_secret_len,
uint8_t *out_alert, const uint8_t *peer_key,
- size_t peer_key_len) = 0;
+ size_t peer_key_len) PURE_VIRTUAL;
};
/* ssl_nid_to_group_id looks up the group corresponding to |nid|. On success, it
@@ -906,18 +925,21 @@ void ssl_write_buffer_clear(SSL *ssl);
int ssl_has_certificate(const SSL *ssl);
/* ssl_parse_cert_chain parses a certificate list from |cbs| in the format used
- * by a TLS Certificate message. On success, it returns a newly-allocated
- * |CRYPTO_BUFFER| list and advances |cbs|. Otherwise, it returns nullptr and
- * sets |*out_alert| to an alert to send to the peer.
+ * by a TLS Certificate message. On success, it advances |cbs| and returns
+ * true. Otherwise, it returns false and sets |*out_alert| to an alert to send
+ * to the peer.
*
- * If the list is non-empty then |*out_pubkey| will be set to a freshly
- * allocated public-key from the leaf certificate.
+ * If the list is non-empty then |*out_chain| and |*out_pubkey| will be set to
+ * the certificate chain and the leaf certificate's public key
+ * respectively. Otherwise, both will be set to nullptr.
*
* If the list is non-empty and |out_leaf_sha256| is non-NULL, it writes the
* SHA-256 hash of the leaf to |out_leaf_sha256|. */
-UniquePtr<STACK_OF(CRYPTO_BUFFER)> ssl_parse_cert_chain(
- uint8_t *out_alert, UniquePtr<EVP_PKEY> *out_pubkey,
- uint8_t *out_leaf_sha256, CBS *cbs, CRYPTO_BUFFER_POOL *pool);
+bool ssl_parse_cert_chain(uint8_t *out_alert,
+ UniquePtr<STACK_OF(CRYPTO_BUFFER)> *out_chain,
+ UniquePtr<EVP_PKEY> *out_pubkey,
+ uint8_t *out_leaf_sha256, CBS *cbs,
+ CRYPTO_BUFFER_POOL *pool);
/* ssl_add_cert_chain adds |ssl|'s certificate chain to |cbb| in the format used
* by a TLS Certificate message. If there is no certificate chain, it emits an
@@ -1050,6 +1072,7 @@ enum ssl_hs_wait_t {
struct SSL_HANDSHAKE {
explicit SSL_HANDSHAKE(SSL *ssl);
~SSL_HANDSHAKE();
+ static constexpr bool kAllowUniquePtr = true;
/* ssl is a non-owning pointer to the parent |SSL| object. */
SSL *ssl;
@@ -1769,9 +1792,18 @@ struct OPENSSL_timeval {
};
struct DTLS1_STATE {
- /* send_cookie is true if we are resending the ClientHello
- * with a cookie from a HelloVerifyRequest. */
- unsigned int send_cookie;
+ /* send_cookie is true if we are resending the ClientHello with a cookie from
+ * a HelloVerifyRequest. */
+ bool send_cookie:1;
+
+ /* has_change_cipher_spec is true if we have received a ChangeCipherSpec from
+ * the peer in this epoch. */
+ bool has_change_cipher_spec:1;
+
+ /* outgoing_messages_complete is true if |outgoing_messages| has been
+ * completed by an attempt to flush it. Future calls to |add_message| and
+ * |add_change_cipher_spec| will start a new flight. */
+ bool outgoing_messages_complete:1;
uint8_t cookie[DTLS1_COOKIE_LENGTH];
size_t cookie_len;
@@ -2006,9 +2038,9 @@ static const size_t kMaxEarlyDataAccepted = 14336;
CERT *ssl_cert_new(const SSL_X509_METHOD *x509_method);
CERT *ssl_cert_dup(CERT *cert);
-void ssl_cert_clear_certs(CERT *c);
-void ssl_cert_free(CERT *c);
-int ssl_set_cert(CERT *cert, CRYPTO_BUFFER *buffer);
+void ssl_cert_clear_certs(CERT *cert);
+void ssl_cert_free(CERT *cert);
+int ssl_set_cert(CERT *cert, UniquePtr<CRYPTO_BUFFER> buffer);
int ssl_is_key_type_supported(int key_type);
/* ssl_compare_public_and_private_key returns one if |pubkey| is the public
* counterpart to |privkey|. Otherwise it returns zero and pushes a helpful
@@ -2059,13 +2091,13 @@ enum ssl_session_result_t {
};
/* ssl_get_prev_session looks up the previous session based on |client_hello|.
- * On success, it sets |*out_session| to the session or NULL if none was found.
- * If the session could not be looked up synchronously, it returns
+ * On success, it sets |*out_session| to the session or nullptr if none was
+ * found. If the session could not be looked up synchronously, it returns
* |ssl_session_retry| and should be called again. If a ticket could not be
* decrypted immediately it returns |ssl_session_ticket_retry| and should also
* be called again. Otherwise, it returns |ssl_session_error|. */
enum ssl_session_result_t ssl_get_prev_session(
- SSL *ssl, SSL_SESSION **out_session, int *out_tickets_supported,
+ SSL *ssl, UniquePtr<SSL_SESSION> *out_session, int *out_tickets_supported,
int *out_renew_ticket, const SSL_CLIENT_HELLO *client_hello);
/* The following flags determine which parts of the session are duplicated. */
@@ -2175,7 +2207,6 @@ int dtls1_handshake_write(SSL *ssl);
void dtls1_start_timer(SSL *ssl);
void dtls1_stop_timer(SSL *ssl);
int dtls1_is_timer_expired(SSL *ssl);
-void dtls1_double_timeout(SSL *ssl);
unsigned int dtls1_min_mtu(void);
int dtls1_new(SSL *ssl);
@@ -2243,7 +2274,7 @@ int ssl_parse_serverhello_tlsext(SSL_HANDSHAKE *hs, CBS *cbs);
* Retry later.
* |ssl_ticket_aead_error|: an error occured that is fatal to the connection. */
enum ssl_ticket_aead_result_t ssl_process_ticket(
- SSL *ssl, SSL_SESSION **out_session, int *out_renew_ticket,
+ SSL *ssl, UniquePtr<SSL_SESSION> *out_session, int *out_renew_ticket,
const uint8_t *ticket, size_t ticket_len, const uint8_t *session_id,
size_t session_id_len);
@@ -2371,12 +2402,8 @@ struct ssl_protocol_method_st {
/* flush_flight flushes the pending flight to the transport. It returns one on
* success and <= 0 on error. */
int (*flush_flight)(SSL *ssl);
- /* expect_flight is called when the handshake expects a flight of messages from
- * the peer. */
- void (*expect_flight)(SSL *ssl);
- /* received_flight is called when the handshake has received a flight of
- * messages from the peer. */
- void (*received_flight)(SSL *ssl);
+ /* on_handshake_complete is called when the handshake is complete. */
+ void (*on_handshake_complete)(SSL *ssl);
/* set_read_state sets |ssl|'s read cipher state to |aead_ctx|. It returns
* one on success and zero if changing the read state is forbidden at this
* point. */
diff --git a/src/ssl/s3_both.cc b/src/ssl/s3_both.cc
index b9aa3bc7..4d53d535 100644
--- a/src/ssl/s3_both.cc
+++ b/src/ssl/s3_both.cc
@@ -731,8 +731,10 @@ int ssl3_get_message(SSL *ssl) {
}
/* We have now received a complete message. */
- ssl_do_msg_callback(ssl, 0 /* read */, SSL3_RT_HANDSHAKE, ssl->init_buf->data,
- ssl->init_buf->length);
+ if (ssl->init_msg == NULL && !ssl->s3->is_v2_hello) {
+ ssl_do_msg_callback(ssl, 0 /* read */, SSL3_RT_HANDSHAKE,
+ ssl->init_buf->data, ssl->init_buf->length);
+ }
ssl->s3->tmp.message_type = ((const uint8_t *)ssl->init_buf->data)[0];
ssl->init_msg = (uint8_t*)ssl->init_buf->data + SSL3_HM_HEADER_LENGTH;
diff --git a/src/ssl/span_test.cc b/src/ssl/span_test.cc
new file mode 100644
index 00000000..0aa7f3de
--- /dev/null
+++ b/src/ssl/span_test.cc
@@ -0,0 +1,90 @@
+/* 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. */
+
+#include <stdio.h>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include <openssl/ssl.h>
+
+namespace bssl {
+namespace {
+
+static void TestCtor(Span<int> s, const int *ptr, size_t size) {
+ EXPECT_EQ(s.data(), ptr);
+ EXPECT_EQ(s.size(), size);
+}
+
+static void TestConstCtor(Span<const int> s, const int *ptr, size_t size) {
+ EXPECT_EQ(s.data(), ptr);
+ EXPECT_EQ(s.size(), size);
+}
+
+TEST(SpanTest, CtorEmpty) {
+ Span<int> s;
+ TestCtor(s, nullptr, 0);
+}
+
+TEST(SpanTest, CtorFromPtrAndSize) {
+ std::vector<int> v = {7, 8, 9, 10};
+ Span<int> s(v.data(), v.size());
+ TestCtor(s, v.data(), v.size());
+}
+
+TEST(SpanTest, CtorFromVector) {
+ std::vector<int> v = {1, 2};
+ // Const ctor is implicit.
+ TestConstCtor(v, v.data(), v.size());
+ // Mutable is explicit.
+ Span<int> s(v);
+ TestCtor(s, v.data(), v.size());
+}
+
+TEST(SpanTest, CtorConstFromArray) {
+ int v[] = {10, 11};
+ // Array ctor is implicit for const and mutable T.
+ TestConstCtor(v, v, 2);
+ TestCtor(v, v, 2);
+}
+
+TEST(SpanTest, MakeSpan) {
+ std::vector<int> v = {100, 200, 300};
+ TestCtor(MakeSpan(v), v.data(), v.size());
+ TestCtor(MakeSpan(v.data(), v.size()), v.data(), v.size());
+ TestConstCtor(MakeSpan(v.data(), v.size()), v.data(), v.size());
+ TestConstCtor(MakeSpan(v), v.data(), v.size());
+}
+
+TEST(SpanTest, MakeConstSpan) {
+ std::vector<int> v = {100, 200, 300};
+ TestConstCtor(MakeConstSpan(v), v.data(), v.size());
+ TestConstCtor(MakeConstSpan(v.data(), v.size()), v.data(), v.size());
+ // But not:
+ // TestConstCtor(MakeSpan(v), v.data(), v.size());
+}
+
+TEST(SpanTest, Accessor) {
+ std::vector<int> v({42, 23, 5, 101, 80});
+ Span<int> s(v);
+ for (size_t i = 0; i < s.size(); ++i) {
+ EXPECT_EQ(s[i], v[i]);
+ EXPECT_EQ(s.at(i), v.at(i));
+ }
+ EXPECT_EQ(s.begin(), v.data());
+ EXPECT_EQ(s.end(), v.data() + v.size());
+}
+
+} // namespace
+} // namespace bssl
diff --git a/src/ssl/ssl_aead_ctx.cc b/src/ssl/ssl_aead_ctx.cc
index 3b8d1b25..53dff78a 100644
--- a/src/ssl/ssl_aead_ctx.cc
+++ b/src/ssl/ssl_aead_ctx.cc
@@ -150,15 +150,21 @@ size_t SSLAEADContext::ExplicitNonceLen() const {
return 0;
}
-size_t SSLAEADContext::MaxSuffixLen(size_t extra_in_len) const {
- return extra_in_len +
- (is_null_cipher() || FUZZER_MODE
- ? 0
- : EVP_AEAD_max_overhead(EVP_AEAD_CTX_aead(ctx_.get())));
+bool SSLAEADContext::SuffixLen(size_t *out_suffix_len, const size_t in_len,
+ const size_t extra_in_len) const {
+ if (is_null_cipher() || FUZZER_MODE) {
+ *out_suffix_len = extra_in_len;
+ return true;
+ }
+ return !!EVP_AEAD_CTX_tag_len(ctx_.get(), out_suffix_len, in_len,
+ extra_in_len);
}
size_t SSLAEADContext::MaxOverhead() const {
- return ExplicitNonceLen() + MaxSuffixLen(0);
+ return ExplicitNonceLen() +
+ (is_null_cipher() || FUZZER_MODE
+ ? 0
+ : EVP_AEAD_max_overhead(EVP_AEAD_CTX_aead(ctx_.get())));
}
size_t SSLAEADContext::GetAdditionalData(uint8_t out[13], uint8_t type,
@@ -255,18 +261,20 @@ bool SSLAEADContext::Open(CBS *out, uint8_t type, uint16_t wire_version,
}
bool SSLAEADContext::SealScatter(uint8_t *out_prefix, uint8_t *out,
- uint8_t *out_suffix, size_t *out_suffix_len,
- size_t max_out_suffix_len, uint8_t type,
+ uint8_t *out_suffix, uint8_t type,
uint16_t wire_version, const uint8_t seqnum[8],
const uint8_t *in, size_t in_len,
const uint8_t *extra_in, size_t extra_in_len) {
- if ((in != out && buffers_alias(in, in_len, out, in_len)) ||
- buffers_alias(in, in_len, out_suffix, max_out_suffix_len)) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_OUTPUT_ALIASES_INPUT);
+ const size_t prefix_len = ExplicitNonceLen();
+ size_t suffix_len;
+ if (!SuffixLen(&suffix_len, in_len, extra_in_len)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_RECORD_TOO_LARGE);
return false;
}
- if (extra_in_len > max_out_suffix_len) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL);
+ if ((in != out && buffers_alias(in, in_len, out, in_len)) ||
+ buffers_alias(in, in_len, out_prefix, prefix_len) ||
+ buffers_alias(in, in_len, out_suffix, suffix_len)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_OUTPUT_ALIASES_INPUT);
return false;
}
@@ -274,7 +282,6 @@ bool SSLAEADContext::SealScatter(uint8_t *out_prefix, uint8_t *out,
/* Handle the initial NULL cipher. */
OPENSSL_memmove(out, in, in_len);
OPENSSL_memmove(out_suffix, extra_in, extra_in_len);
- *out_suffix_len = extra_in_len;
return true;
}
@@ -327,32 +334,38 @@ bool SSLAEADContext::SealScatter(uint8_t *out_prefix, uint8_t *out,
}
}
- return !!EVP_AEAD_CTX_seal_scatter(
- ctx_.get(), out, out_suffix, out_suffix_len, max_out_suffix_len, nonce,
+ size_t written_suffix_len;
+ bool result = !!EVP_AEAD_CTX_seal_scatter(
+ ctx_.get(), out, out_suffix, &written_suffix_len, suffix_len, nonce,
nonce_len, in, in_len, extra_in, extra_in_len, ad, ad_len);
+ assert(!result || written_suffix_len == suffix_len);
+ return result;
}
bool SSLAEADContext::Seal(uint8_t *out, size_t *out_len, size_t max_out_len,
uint8_t type, uint16_t wire_version,
const uint8_t seqnum[8], const uint8_t *in,
size_t in_len) {
- size_t prefix_len = ExplicitNonceLen();
- if (in_len + prefix_len < in_len) {
+ const size_t prefix_len = ExplicitNonceLen();
+ size_t suffix_len;
+ if (!SuffixLen(&suffix_len, in_len, 0)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_RECORD_TOO_LARGE);
+ return false;
+ }
+ if (in_len + prefix_len < in_len ||
+ in_len + prefix_len + suffix_len < in_len + prefix_len) {
OPENSSL_PUT_ERROR(CIPHER, SSL_R_RECORD_TOO_LARGE);
return false;
}
- if (in_len + prefix_len > max_out_len) {
+ if (in_len + prefix_len + suffix_len > max_out_len) {
OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL);
return false;
}
- size_t suffix_len;
- if (!SealScatter(out, out + prefix_len, out + prefix_len + in_len,
- &suffix_len, max_out_len - prefix_len - in_len, type,
+ if (!SealScatter(out, out + prefix_len, out + prefix_len + in_len, type,
wire_version, seqnum, in, in_len, 0, 0)) {
return false;
}
- assert(suffix_len <= MaxSuffixLen(0));
*out_len = prefix_len + in_len + suffix_len;
return true;
}
diff --git a/src/ssl/ssl_asn1.cc b/src/ssl/ssl_asn1.cc
index d360a7aa..0cf90d18 100644
--- a/src/ssl/ssl_asn1.cc
+++ b/src/ssl/ssl_asn1.cc
@@ -92,6 +92,8 @@
#include <limits.h>
#include <string.h>
+#include <utility>
+
#include <openssl/buf.h>
#include <openssl/bytestring.h>
#include <openssl/err.h>
@@ -678,11 +680,9 @@ UniquePtr<SSL_SESSION> SSL_SESSION_parse(CBS *cbs,
}
if (has_peer) {
- /* TODO(agl): this should use the |SSL_CTX|'s pool. */
- CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new_from_CBS(&peer, pool);
- if (buffer == NULL ||
- !sk_CRYPTO_BUFFER_push(ret->certs, buffer)) {
- CRYPTO_BUFFER_free(buffer);
+ UniquePtr<CRYPTO_BUFFER> buffer(CRYPTO_BUFFER_new_from_CBS(&peer, pool));
+ if (!buffer ||
+ !PushToStack(ret->certs, std::move(buffer))) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
return nullptr;
}
@@ -696,7 +696,6 @@ UniquePtr<SSL_SESSION> SSL_SESSION_parse(CBS *cbs,
return nullptr;
}
- /* TODO(agl): this should use the |SSL_CTX|'s pool. */
CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new_from_CBS(&cert, pool);
if (buffer == NULL ||
!sk_CRYPTO_BUFFER_push(ret->certs, buffer)) {
diff --git a/src/ssl/ssl_cert.cc b/src/ssl/ssl_cert.cc
index 4f457f61..76af31ee 100644
--- a/src/ssl/ssl_cert.cc
+++ b/src/ssl/ssl_cert.cc
@@ -222,24 +222,24 @@ void ssl_cert_clear_certs(CERT *cert) {
cert->key_method = NULL;
}
-void ssl_cert_free(CERT *c) {
- if (c == NULL) {
+void ssl_cert_free(CERT *cert) {
+ if (cert == NULL) {
return;
}
- ssl_cert_clear_certs(c);
- c->x509_method->cert_free(c);
- OPENSSL_free(c->sigalgs);
- CRYPTO_BUFFER_free(c->signed_cert_timestamp_list);
- CRYPTO_BUFFER_free(c->ocsp_response);
+ ssl_cert_clear_certs(cert);
+ cert->x509_method->cert_free(cert);
+ OPENSSL_free(cert->sigalgs);
+ CRYPTO_BUFFER_free(cert->signed_cert_timestamp_list);
+ CRYPTO_BUFFER_free(cert->ocsp_response);
- OPENSSL_free(c);
+ OPENSSL_free(cert);
}
-static void ssl_cert_set_cert_cb(CERT *c, int (*cb)(SSL *ssl, void *arg),
+static void ssl_cert_set_cert_cb(CERT *cert, int (*cb)(SSL *ssl, void *arg),
void *arg) {
- c->cert_cb = cb;
- c->cert_cb_arg = arg;
+ cert->cert_cb = cb;
+ cert->cert_cb_arg = arg;
}
enum leaf_cert_and_privkey_result_t {
@@ -337,8 +337,8 @@ static int cert_set_chain_and_key(
return 1;
}
-int ssl_set_cert(CERT *cert, CRYPTO_BUFFER *buffer) {
- switch (check_leaf_cert_and_privkey(buffer, cert->privatekey)) {
+int ssl_set_cert(CERT *cert, UniquePtr<CRYPTO_BUFFER> buffer) {
+ switch (check_leaf_cert_and_privkey(buffer.get(), cert->privatekey)) {
case leaf_cert_and_privkey_error:
return 0;
case leaf_cert_and_privkey_mismatch:
@@ -356,8 +356,7 @@ int ssl_set_cert(CERT *cert, CRYPTO_BUFFER *buffer) {
if (cert->chain != NULL) {
CRYPTO_BUFFER_free(sk_CRYPTO_BUFFER_value(cert->chain, 0));
- sk_CRYPTO_BUFFER_set(cert->chain, 0, buffer);
- CRYPTO_BUFFER_up_ref(buffer);
+ sk_CRYPTO_BUFFER_set(cert->chain, 0, buffer.release());
return 1;
}
@@ -366,12 +365,11 @@ int ssl_set_cert(CERT *cert, CRYPTO_BUFFER *buffer) {
return 0;
}
- if (!sk_CRYPTO_BUFFER_push(cert->chain, buffer)) {
+ if (!PushToStack(cert->chain, std::move(buffer))) {
sk_CRYPTO_BUFFER_free(cert->chain);
cert->chain = NULL;
return 0;
}
- CRYPTO_BUFFER_up_ref(buffer);
return 1;
}
@@ -382,39 +380,47 @@ int ssl_has_certificate(const SSL *ssl) {
ssl_has_private_key(ssl);
}
-UniquePtr<STACK_OF(CRYPTO_BUFFER)>
- ssl_parse_cert_chain(uint8_t *out_alert, UniquePtr<EVP_PKEY> *out_pubkey,
- uint8_t *out_leaf_sha256, CBS *cbs,
- CRYPTO_BUFFER_POOL *pool) {
- UniquePtr<EVP_PKEY> pubkey;
- UniquePtr<STACK_OF(CRYPTO_BUFFER)> ret(sk_CRYPTO_BUFFER_new_null());
- if (!ret) {
- *out_alert = SSL_AD_INTERNAL_ERROR;
- OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
- return nullptr;
- }
+bool ssl_parse_cert_chain(uint8_t *out_alert,
+ UniquePtr<STACK_OF(CRYPTO_BUFFER)> *out_chain,
+ UniquePtr<EVP_PKEY> *out_pubkey,
+ uint8_t *out_leaf_sha256, CBS *cbs,
+ CRYPTO_BUFFER_POOL *pool) {
+ out_chain->reset();
+ out_pubkey->reset();
CBS certificate_list;
if (!CBS_get_u24_length_prefixed(cbs, &certificate_list)) {
*out_alert = SSL_AD_DECODE_ERROR;
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
- return nullptr;
+ return false;
}
+ if (CBS_len(&certificate_list) == 0) {
+ return true;
+ }
+
+ UniquePtr<STACK_OF(CRYPTO_BUFFER)> chain(sk_CRYPTO_BUFFER_new_null());
+ if (!chain) {
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ return false;
+ }
+
+ UniquePtr<EVP_PKEY> pubkey;
while (CBS_len(&certificate_list) > 0) {
CBS certificate;
if (!CBS_get_u24_length_prefixed(&certificate_list, &certificate) ||
CBS_len(&certificate) == 0) {
*out_alert = SSL_AD_DECODE_ERROR;
OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_LENGTH_MISMATCH);
- return nullptr;
+ return false;
}
- if (sk_CRYPTO_BUFFER_num(ret.get()) == 0) {
+ if (sk_CRYPTO_BUFFER_num(chain.get()) == 0) {
pubkey = ssl_cert_parse_pubkey(&certificate);
if (!pubkey) {
*out_alert = SSL_AD_DECODE_ERROR;
- return nullptr;
+ return false;
}
/* Retain the hash of the leaf certificate if requested. */
@@ -423,19 +429,19 @@ UniquePtr<STACK_OF(CRYPTO_BUFFER)>
}
}
- CRYPTO_BUFFER *buf =
- CRYPTO_BUFFER_new_from_CBS(&certificate, pool);
- if (buf == NULL ||
- !sk_CRYPTO_BUFFER_push(ret.get(), buf)) {
+ UniquePtr<CRYPTO_BUFFER> buf(
+ CRYPTO_BUFFER_new_from_CBS(&certificate, pool));
+ if (!buf ||
+ !PushToStack(chain.get(), std::move(buf))) {
*out_alert = SSL_AD_INTERNAL_ERROR;
- CRYPTO_BUFFER_free(buf);
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
- return nullptr;
+ return false;
}
}
+ *out_chain = std::move(chain);
*out_pubkey = std::move(pubkey);
- return ret;
+ return true;
}
int ssl_add_cert_chain(SSL *ssl, CBB *cbb) {
@@ -678,11 +684,10 @@ UniquePtr<STACK_OF(CRYPTO_BUFFER)> ssl_parse_client_CA_list(SSL *ssl,
return nullptr;
}
- CRYPTO_BUFFER *buffer =
- CRYPTO_BUFFER_new_from_CBS(&distinguished_name, pool);
- if (buffer == NULL ||
- !sk_CRYPTO_BUFFER_push(ret.get(), buffer)) {
- CRYPTO_BUFFER_free(buffer);
+ UniquePtr<CRYPTO_BUFFER> buffer(
+ CRYPTO_BUFFER_new_from_CBS(&distinguished_name, pool));
+ if (!buffer ||
+ !PushToStack(ret.get(), std::move(buffer))) {
*out_alert = SSL_AD_INTERNAL_ERROR;
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
return nullptr;
@@ -712,9 +717,7 @@ int ssl_add_client_CA_list(SSL *ssl, CBB *cbb) {
return CBB_flush(cbb);
}
- for (size_t i = 0; i < sk_CRYPTO_BUFFER_num(names); i++) {
- const CRYPTO_BUFFER *name = sk_CRYPTO_BUFFER_value(names, i);
-
+ for (const CRYPTO_BUFFER *name : names) {
if (!CBB_add_u16_length_prefixed(&child, &name_cbb) ||
!CBB_add_bytes(&name_cbb, CRYPTO_BUFFER_data(name),
CRYPTO_BUFFER_len(name))) {
@@ -804,25 +807,21 @@ int SSL_CTX_set_chain_and_key(SSL_CTX *ctx, CRYPTO_BUFFER *const *certs,
int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, size_t der_len,
const uint8_t *der) {
- CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new(der, der_len, NULL);
- if (buffer == NULL) {
+ UniquePtr<CRYPTO_BUFFER> buffer(CRYPTO_BUFFER_new(der, der_len, NULL));
+ if (!buffer) {
return 0;
}
- const int ok = ssl_set_cert(ctx->cert, buffer);
- CRYPTO_BUFFER_free(buffer);
- return ok;
+ return ssl_set_cert(ctx->cert, std::move(buffer));
}
int SSL_use_certificate_ASN1(SSL *ssl, const uint8_t *der, size_t der_len) {
- CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new(der, der_len, NULL);
- if (buffer == NULL) {
+ UniquePtr<CRYPTO_BUFFER> buffer(CRYPTO_BUFFER_new(der, der_len, NULL));
+ if (!buffer) {
return 0;
}
- const int ok = ssl_set_cert(ssl->cert, buffer);
- CRYPTO_BUFFER_free(buffer);
- return ok;
+ return ssl_set_cert(ssl->cert, std::move(buffer));
}
void SSL_CTX_set_cert_cb(SSL_CTX *ctx, int (*cb)(SSL *ssl, void *arg),
diff --git a/src/ssl/ssl_cipher.cc b/src/ssl/ssl_cipher.cc
index dbb4c752..f1a215fc 100644
--- a/src/ssl/ssl_cipher.cc
+++ b/src/ssl/ssl_cipher.cc
@@ -756,8 +756,12 @@ const EVP_MD *ssl_get_handshake_digest(uint32_t algorithm_prf,
}
}
-#define ITEM_SEP(a) \
- (((a) == ':') || ((a) == ' ') || ((a) == ';') || ((a) == ','))
+static bool is_cipher_list_separator(char c, int is_strict) {
+ if (c == ':') {
+ return true;
+ }
+ return !is_strict && (c == ' ' || c == ';' || c == ',');
+}
/* rule_equals returns one iff the NUL-terminated string |rule| is equal to the
* |buf_len| bytes at |buf|. */
@@ -1092,7 +1096,7 @@ static int ssl_cipher_process_rulestr(const SSL_PROTOCOL_METHOD *ssl_method,
return 0;
}
- if (ITEM_SEP(ch)) {
+ if (is_cipher_list_separator(ch, strict)) {
l++;
continue;
}
@@ -1186,7 +1190,7 @@ static int ssl_cipher_process_rulestr(const SSL_PROTOCOL_METHOD *ssl_method,
/* We do not support any "multi" options together with "@", so throw away
* the rest of the command, if any left, until end or ':' is found. */
- while (*l != '\0' && !ITEM_SEP(*l)) {
+ while (*l != '\0' && !is_cipher_list_separator(*l, strict)) {
l++;
}
} else if (!skip_rule) {
diff --git a/src/ssl/ssl_lib.cc b/src/ssl/ssl_lib.cc
index 8e7bd885..6611dd25 100644
--- a/src/ssl/ssl_lib.cc
+++ b/src/ssl/ssl_lib.cc
@@ -2148,8 +2148,8 @@ int SSL_get_ex_new_index(long argl, void *argp, CRYPTO_EX_unused *unused,
return index;
}
-int SSL_set_ex_data(SSL *ssl, int idx, void *arg) {
- return CRYPTO_set_ex_data(&ssl->ex_data, idx, arg);
+int SSL_set_ex_data(SSL *ssl, int idx, void *data) {
+ return CRYPTO_set_ex_data(&ssl->ex_data, idx, data);
}
void *SSL_get_ex_data(const SSL *ssl, int idx) {
@@ -2167,8 +2167,8 @@ int SSL_CTX_get_ex_new_index(long argl, void *argp, CRYPTO_EX_unused *unused,
return index;
}
-int SSL_CTX_set_ex_data(SSL_CTX *ctx, int idx, void *arg) {
- return CRYPTO_set_ex_data(&ctx->ex_data, idx, arg);
+int SSL_CTX_set_ex_data(SSL_CTX *ctx, int idx, void *data) {
+ return CRYPTO_set_ex_data(&ctx->ex_data, idx, data);
}
void *SSL_CTX_get_ex_data(const SSL_CTX *ctx, int idx) {
@@ -2179,21 +2179,17 @@ int SSL_want(const SSL *ssl) { return ssl->rwstate; }
void SSL_CTX_set_tmp_rsa_callback(SSL_CTX *ctx,
RSA *(*cb)(SSL *ssl, int is_export,
- int keylength)) {
-}
+ int keylength)) {}
void SSL_set_tmp_rsa_callback(SSL *ssl, RSA *(*cb)(SSL *ssl, int is_export,
- int keylength)) {
-}
+ int keylength)) {}
void SSL_CTX_set_tmp_dh_callback(SSL_CTX *ctx,
- DH *(*callback)(SSL *ssl, int is_export,
- int keylength)) {
-}
+ DH *(*cb)(SSL *ssl, int is_export,
+ int keylength)) {}
-void SSL_set_tmp_dh_callback(SSL *ssl, DH *(*callback)(SSL *ssl, int is_export,
- int keylength)) {
-}
+void SSL_set_tmp_dh_callback(SSL *ssl, DH *(*cb)(SSL *ssl, int is_export,
+ int keylength)) {}
static int use_psk_identity_hint(char **out, const char *identity_hint) {
if (identity_hint != NULL && strlen(identity_hint) > PSK_MAX_IDENTITY_LEN) {
diff --git a/src/ssl/ssl_privkey.cc b/src/ssl/ssl_privkey.cc
index 3e3fa94b..ecdf48f4 100644
--- a/src/ssl/ssl_privkey.cc
+++ b/src/ssl/ssl_privkey.cc
@@ -320,27 +320,19 @@ int ssl_private_key_supports_signature_algorithm(SSL_HANDSHAKE *hs,
using namespace bssl;
int SSL_use_RSAPrivateKey(SSL *ssl, RSA *rsa) {
- EVP_PKEY *pkey;
- int ret;
-
if (rsa == NULL) {
OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
- pkey = EVP_PKEY_new();
- if (pkey == NULL) {
+ UniquePtr<EVP_PKEY> pkey(EVP_PKEY_new());
+ if (!pkey ||
+ !EVP_PKEY_set1_RSA(pkey.get(), rsa)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_EVP_LIB);
return 0;
}
- RSA_up_ref(rsa);
- EVP_PKEY_assign_RSA(pkey, rsa);
-
- ret = ssl_set_pkey(ssl->cert, pkey);
- EVP_PKEY_free(pkey);
-
- return ret;
+ return ssl_set_pkey(ssl->cert, pkey.get());
}
int SSL_use_RSAPrivateKey_ASN1(SSL *ssl, const uint8_t *der, size_t der_len) {
@@ -370,52 +362,40 @@ int SSL_use_PrivateKey_ASN1(int type, SSL *ssl, const uint8_t *der,
}
const uint8_t *p = der;
- EVP_PKEY *pkey = d2i_PrivateKey(type, NULL, &p, (long)der_len);
- if (pkey == NULL || p != der + der_len) {
+ UniquePtr<EVP_PKEY> pkey(d2i_PrivateKey(type, NULL, &p, (long)der_len));
+ if (!pkey || p != der + der_len) {
OPENSSL_PUT_ERROR(SSL, ERR_R_ASN1_LIB);
- EVP_PKEY_free(pkey);
return 0;
}
- int ret = SSL_use_PrivateKey(ssl, pkey);
- EVP_PKEY_free(pkey);
- return ret;
+ return SSL_use_PrivateKey(ssl, pkey.get());
}
int SSL_CTX_use_RSAPrivateKey(SSL_CTX *ctx, RSA *rsa) {
- int ret;
- EVP_PKEY *pkey;
-
if (rsa == NULL) {
OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
- pkey = EVP_PKEY_new();
- if (pkey == NULL) {
+ UniquePtr<EVP_PKEY> pkey(EVP_PKEY_new());
+ if (!pkey ||
+ !EVP_PKEY_set1_RSA(pkey.get(), rsa)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_EVP_LIB);
return 0;
}
- RSA_up_ref(rsa);
- EVP_PKEY_assign_RSA(pkey, rsa);
-
- ret = ssl_set_pkey(ctx->cert, pkey);
- EVP_PKEY_free(pkey);
- return ret;
+ return ssl_set_pkey(ctx->cert, pkey.get());
}
int SSL_CTX_use_RSAPrivateKey_ASN1(SSL_CTX *ctx, const uint8_t *der,
size_t der_len) {
- RSA *rsa = RSA_private_key_from_bytes(der, der_len);
- if (rsa == NULL) {
+ UniquePtr<RSA> rsa(RSA_private_key_from_bytes(der, der_len));
+ if (!rsa) {
OPENSSL_PUT_ERROR(SSL, ERR_R_ASN1_LIB);
return 0;
}
- int ret = SSL_CTX_use_RSAPrivateKey(ctx, rsa);
- RSA_free(rsa);
- return ret;
+ return SSL_CTX_use_RSAPrivateKey(ctx, rsa.get());
}
int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey) {
@@ -435,16 +415,13 @@ int SSL_CTX_use_PrivateKey_ASN1(int type, SSL_CTX *ctx, const uint8_t *der,
}
const uint8_t *p = der;
- EVP_PKEY *pkey = d2i_PrivateKey(type, NULL, &p, (long)der_len);
- if (pkey == NULL || p != der + der_len) {
+ UniquePtr<EVP_PKEY> pkey(d2i_PrivateKey(type, NULL, &p, (long)der_len));
+ if (!pkey || p != der + der_len) {
OPENSSL_PUT_ERROR(SSL, ERR_R_ASN1_LIB);
- EVP_PKEY_free(pkey);
return 0;
}
- int ret = SSL_CTX_use_PrivateKey(ctx, pkey);
- EVP_PKEY_free(pkey);
- return ret;
+ return SSL_CTX_use_PrivateKey(ctx, pkey.get());
}
void SSL_set_private_key_method(SSL *ssl,
diff --git a/src/ssl/ssl_session.cc b/src/ssl/ssl_session.cc
index 02d64221..18307237 100644
--- a/src/ssl/ssl_session.cc
+++ b/src/ssl/ssl_session.cc
@@ -610,18 +610,17 @@ int ssl_session_is_resumable(const SSL_HANDSHAKE *hs,
}
/* ssl_lookup_session looks up |session_id| in the session cache and sets
- * |*out_session| to an |SSL_SESSION| object if found. The caller takes
- * ownership of the result. */
+ * |*out_session| to an |SSL_SESSION| object if found. */
static enum ssl_session_result_t ssl_lookup_session(
- SSL *ssl, SSL_SESSION **out_session, const uint8_t *session_id,
+ SSL *ssl, UniquePtr<SSL_SESSION> *out_session, const uint8_t *session_id,
size_t session_id_len) {
- *out_session = NULL;
+ out_session->reset();
if (session_id_len == 0 || session_id_len > SSL_MAX_SSL_SESSION_ID_LENGTH) {
return ssl_session_success;
}
- SSL_SESSION *session = NULL;
+ UniquePtr<SSL_SESSION> session;
/* Try the internal cache, if it exists. */
if (!(ssl->session_ctx->session_cache_mode &
SSL_SESS_CACHE_NO_INTERNAL_LOOKUP)) {
@@ -631,26 +630,27 @@ static enum ssl_session_result_t ssl_lookup_session(
OPENSSL_memcpy(data.session_id, session_id, session_id_len);
CRYPTO_MUTEX_lock_read(&ssl->session_ctx->lock);
- session = lh_SSL_SESSION_retrieve(ssl->session_ctx->sessions, &data);
- if (session != NULL) {
- SSL_SESSION_up_ref(session);
+ session.reset(lh_SSL_SESSION_retrieve(ssl->session_ctx->sessions, &data));
+ if (session) {
+ /* |lh_SSL_SESSION_retrieve| returns a non-owning pointer. */
+ SSL_SESSION_up_ref(session.get());
}
/* TODO(davidben): This should probably move it to the front of the list. */
CRYPTO_MUTEX_unlock_read(&ssl->session_ctx->lock);
}
/* Fall back to the external cache, if it exists. */
- if (session == NULL &&
- ssl->session_ctx->get_session_cb != NULL) {
+ if (!session && ssl->session_ctx->get_session_cb != NULL) {
int copy = 1;
- session = ssl->session_ctx->get_session_cb(ssl, (uint8_t *)session_id,
- session_id_len, &copy);
+ session.reset(ssl->session_ctx->get_session_cb(ssl, (uint8_t *)session_id,
+ session_id_len, &copy));
- if (session == NULL) {
+ if (!session) {
return ssl_session_success;
}
- if (session == SSL_magic_pending_session_ptr()) {
+ if (session.get() == SSL_magic_pending_session_ptr()) {
+ session.release(); // This pointer is not actually owned.
return ssl_session_retry;
}
@@ -659,34 +659,32 @@ static enum ssl_session_result_t ssl_lookup_session(
* between threads, it must handle the reference count itself [i.e. copy ==
* 0], or things won't be thread-safe). */
if (copy) {
- SSL_SESSION_up_ref(session);
+ SSL_SESSION_up_ref(session.get());
}
/* Add the externally cached session to the internal cache if necessary. */
if (!(ssl->session_ctx->session_cache_mode &
SSL_SESS_CACHE_NO_INTERNAL_STORE)) {
- SSL_CTX_add_session(ssl->session_ctx, session);
+ SSL_CTX_add_session(ssl->session_ctx, session.get());
}
}
- if (session != NULL &&
- !ssl_session_is_time_valid(ssl, session)) {
+ if (session && !ssl_session_is_time_valid(ssl, session.get())) {
/* The session was from the cache, so remove it. */
- SSL_CTX_remove_session(ssl->session_ctx, session);
- SSL_SESSION_free(session);
- session = NULL;
+ SSL_CTX_remove_session(ssl->session_ctx, session.get());
+ session.reset();
}
- *out_session = session;
+ *out_session = std::move(session);
return ssl_session_success;
}
enum ssl_session_result_t ssl_get_prev_session(
- SSL *ssl, SSL_SESSION **out_session, int *out_tickets_supported,
+ SSL *ssl, UniquePtr<SSL_SESSION> *out_session, int *out_tickets_supported,
int *out_renew_ticket, const SSL_CLIENT_HELLO *client_hello) {
/* This is used only by servers. */
assert(ssl->server);
- SSL_SESSION *session = NULL;
+ UniquePtr<SSL_SESSION> session;
int renew_ticket = 0;
/* If tickets are disabled, always behave as if no tickets are present. */
@@ -704,7 +702,7 @@ enum ssl_session_result_t ssl_get_prev_session(
case ssl_ticket_aead_success:
break;
case ssl_ticket_aead_ignore_ticket:
- assert(session == NULL);
+ assert(!session);
break;
case ssl_ticket_aead_error:
return ssl_session_error;
@@ -720,7 +718,7 @@ enum ssl_session_result_t ssl_get_prev_session(
}
}
- *out_session = session;
+ *out_session = std::move(session);
*out_tickets_supported = tickets_supported;
*out_renew_ticket = renew_ticket;
return ssl_session_success;
@@ -913,7 +911,7 @@ int SSL_SESSION_set1_id_context(SSL_SESSION *session, const uint8_t *sid_ctx,
return 0;
}
- assert(sizeof(session->sid_ctx) < 256);
+ static_assert(sizeof(session->sid_ctx) < 256, "sid_ctx_len does not fit");
session->sid_ctx_length = (uint8_t)sid_ctx_len;
OPENSSL_memcpy(session->sid_ctx, sid_ctx, sid_ctx_len);
diff --git a/src/ssl/ssl_test.cc b/src/ssl/ssl_test.cc
index a57298f8..4556fb77 100644
--- a/src/ssl/ssl_test.cc
+++ b/src/ssl/ssl_test.cc
@@ -279,6 +279,19 @@ static const CipherTest kCipherTests[] = {
},
false,
},
+ // Spaces, semi-colons and commas are separators.
+ {
+ "AES128-SHA: AES128-SHA256 AES256-SHA ,AES256-SHA256 ; AES128-GCM-SHA256",
+ {
+ {TLS1_CK_RSA_WITH_AES_128_SHA, 0},
+ {TLS1_CK_RSA_WITH_AES_128_SHA256, 0},
+ {TLS1_CK_RSA_WITH_AES_256_SHA, 0},
+ {TLS1_CK_RSA_WITH_AES_256_SHA256, 0},
+ {TLS1_CK_RSA_WITH_AES_128_GCM_SHA256, 0},
+ },
+ // …but not in strict mode.
+ true,
+ },
};
static const char *kBadRules[] = {
@@ -304,6 +317,8 @@ static const char *kBadRules[] = {
"[ECDHE-RSA-CHACHA20-POLY1305|ECDHE-RSA-AES128-GCM-SHA256]:@STRENGTH",
// Opcode supplied, but missing selector.
"+",
+ // Spaces are forbidden in equal-preference groups.
+ "[AES128-SHA | AES128-SHA256]",
};
static const char *kMustNotIncludeNull[] = {
@@ -1716,14 +1731,16 @@ static bool TestGetPeerCertificate(bool is_dtls, const SSL_METHOD *method,
return false;
}
- // However, for historical reasons, the chain includes the leaf on the
+ // However, for historical reasons, the X509 chain includes the leaf on the
// client, but does not on the server.
- if (sk_X509_num(SSL_get_peer_cert_chain(client.get())) != 1) {
+ if (sk_X509_num(SSL_get_peer_cert_chain(client.get())) != 1 ||
+ sk_CRYPTO_BUFFER_num(SSL_get0_peer_certificates(client.get())) != 1) {
fprintf(stderr, "Client peer chain was incorrect.\n");
return false;
}
- if (sk_X509_num(SSL_get_peer_cert_chain(server.get())) != 0) {
+ if (sk_X509_num(SSL_get_peer_cert_chain(server.get())) != 0 ||
+ sk_CRYPTO_BUFFER_num(SSL_get0_peer_certificates(server.get())) != 1) {
fprintf(stderr, "Server peer chain was incorrect.\n");
return false;
}
@@ -1731,6 +1748,48 @@ static bool TestGetPeerCertificate(bool is_dtls, const SSL_METHOD *method,
return true;
}
+static bool TestNoPeerCertificate(bool is_dtls, const SSL_METHOD *method,
+ uint16_t version) {
+ bssl::UniquePtr<X509> cert = GetTestCertificate();
+ bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
+ if (!cert || !key) {
+ return false;
+ }
+
+ // Configure an anonymous client.
+ bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(method)),
+ client_ctx(SSL_CTX_new(method));
+ if (!server_ctx || !client_ctx ||
+ !SSL_CTX_use_certificate(server_ctx.get(), cert.get()) ||
+ !SSL_CTX_use_PrivateKey(server_ctx.get(), key.get()) ||
+ !SSL_CTX_set_min_proto_version(server_ctx.get(), version) ||
+ !SSL_CTX_set_max_proto_version(server_ctx.get(), version) ||
+ !SSL_CTX_set_min_proto_version(client_ctx.get(), version) ||
+ !SSL_CTX_set_max_proto_version(client_ctx.get(), version)) {
+ return false;
+ }
+ SSL_CTX_set_verify(
+ server_ctx.get(), SSL_VERIFY_PEER, nullptr);
+ SSL_CTX_set_cert_verify_callback(server_ctx.get(), VerifySucceed, NULL);
+ SSL_CTX_set_cert_verify_callback(client_ctx.get(), VerifySucceed, NULL);
+
+ bssl::UniquePtr<SSL> client, server;
+ if (!ConnectClientAndServer(&client, &server, client_ctx.get(),
+ server_ctx.get(), nullptr /* no session */)) {
+ return false;
+ }
+
+ // Client and server should both see the leaf certificate.
+ bssl::UniquePtr<X509> peer(SSL_get_peer_certificate(server.get()));
+ if (peer ||
+ SSL_get0_peer_certificates(server.get()) != nullptr) {
+ fprintf(stderr, "Server peer certificate was non-null.\n");
+ return false;
+ }
+
+ return true;
+}
+
static bool TestRetainOnlySHA256OfCerts(bool is_dtls, const SSL_METHOD *method,
uint16_t version) {
bssl::UniquePtr<X509> cert = GetTestCertificate();
@@ -3693,6 +3752,189 @@ TEST(SSLTest, SelectNextProto) {
EXPECT_EQ(Bytes("x"), Bytes(result, result_len));
}
+TEST(SSLTest, SealRecord) {
+ bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method())),
+ server_ctx(SSL_CTX_new(TLS_method()));
+ ASSERT_TRUE(client_ctx);
+ ASSERT_TRUE(server_ctx);
+
+ bssl::UniquePtr<X509> cert = GetTestCertificate();
+ bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
+ ASSERT_TRUE(cert);
+ ASSERT_TRUE(key);
+ ASSERT_TRUE(SSL_CTX_use_certificate(server_ctx.get(), cert.get()));
+ ASSERT_TRUE(SSL_CTX_use_PrivateKey(server_ctx.get(), key.get()));
+
+ bssl::UniquePtr<SSL> client, server;
+ ASSERT_TRUE(ConnectClientAndServer(&client, &server, client_ctx.get(),
+ server_ctx.get(),
+ nullptr /* no session */));
+
+ const std::vector<uint8_t> record = {1, 2, 3, 4, 5};
+ std::vector<uint8_t> prefix(
+ bssl::SealRecordPrefixLen(client.get(), record.size())),
+ body(record.size()),
+ suffix(bssl::SealRecordSuffixLen(client.get(), record.size()));
+ ASSERT_TRUE(bssl::SealRecord(client.get(), bssl::MakeSpan(prefix),
+ bssl::MakeSpan(body), bssl::MakeSpan(suffix),
+ record));
+
+ std::vector<uint8_t> sealed;
+ sealed.insert(sealed.end(), prefix.begin(), prefix.end());
+ sealed.insert(sealed.end(), body.begin(), body.end());
+ sealed.insert(sealed.end(), suffix.begin(), suffix.end());
+ std::vector<uint8_t> sealed_copy = sealed;
+
+ bssl::Span<uint8_t> plaintext;
+ size_t record_len;
+ uint8_t alert = 255;
+ EXPECT_EQ(bssl::OpenRecord(server.get(), &plaintext, &record_len, &alert,
+ bssl::MakeSpan(sealed)),
+ bssl::OpenRecordResult::kOK);
+ EXPECT_EQ(record_len, sealed.size());
+ EXPECT_EQ(plaintext, record);
+ EXPECT_EQ(255, alert);
+}
+
+TEST(SSLTest, SealRecordInPlace) {
+ bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method())),
+ server_ctx(SSL_CTX_new(TLS_method()));
+ ASSERT_TRUE(client_ctx);
+ ASSERT_TRUE(server_ctx);
+
+ bssl::UniquePtr<X509> cert = GetTestCertificate();
+ bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
+ ASSERT_TRUE(cert);
+ ASSERT_TRUE(key);
+ ASSERT_TRUE(SSL_CTX_use_certificate(server_ctx.get(), cert.get()));
+ ASSERT_TRUE(SSL_CTX_use_PrivateKey(server_ctx.get(), key.get()));
+
+ bssl::UniquePtr<SSL> client, server;
+ ASSERT_TRUE(ConnectClientAndServer(&client, &server, client_ctx.get(),
+ server_ctx.get(),
+ nullptr /* no session */));
+
+ const std::vector<uint8_t> plaintext = {1, 2, 3, 4, 5};
+ std::vector<uint8_t> record = plaintext;
+ std::vector<uint8_t> prefix(
+ bssl::SealRecordPrefixLen(client.get(), record.size())),
+ suffix(bssl::SealRecordSuffixLen(client.get(), record.size()));
+ ASSERT_TRUE(bssl::SealRecord(client.get(), bssl::MakeSpan(prefix),
+ bssl::MakeSpan(record), bssl::MakeSpan(suffix),
+ record));
+ record.insert(record.begin(), prefix.begin(), prefix.end());
+ record.insert(record.end(), suffix.begin(), suffix.end());
+
+ bssl::Span<uint8_t> result;
+ size_t record_len;
+ uint8_t alert;
+ EXPECT_EQ(bssl::OpenRecord(server.get(), &result, &record_len, &alert,
+ bssl::MakeSpan(record)),
+ bssl::OpenRecordResult::kOK);
+ EXPECT_EQ(record_len, record.size());
+ EXPECT_EQ(plaintext, result);
+}
+
+TEST(SSLTest, SealRecordTrailingData) {
+ bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method())),
+ server_ctx(SSL_CTX_new(TLS_method()));
+ ASSERT_TRUE(client_ctx);
+ ASSERT_TRUE(server_ctx);
+
+ bssl::UniquePtr<X509> cert = GetTestCertificate();
+ bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
+ ASSERT_TRUE(cert);
+ ASSERT_TRUE(key);
+ ASSERT_TRUE(SSL_CTX_use_certificate(server_ctx.get(), cert.get()));
+ ASSERT_TRUE(SSL_CTX_use_PrivateKey(server_ctx.get(), key.get()));
+
+ bssl::UniquePtr<SSL> client, server;
+ ASSERT_TRUE(ConnectClientAndServer(&client, &server, client_ctx.get(),
+ server_ctx.get(),
+ nullptr /* no session */));
+
+ const std::vector<uint8_t> plaintext = {1, 2, 3, 4, 5};
+ std::vector<uint8_t> record = plaintext;
+ std::vector<uint8_t> prefix(
+ bssl::SealRecordPrefixLen(client.get(), record.size())),
+ suffix(bssl::SealRecordSuffixLen(client.get(), record.size()));
+ ASSERT_TRUE(bssl::SealRecord(client.get(), bssl::MakeSpan(prefix),
+ bssl::MakeSpan(record), bssl::MakeSpan(suffix),
+ record));
+ record.insert(record.begin(), prefix.begin(), prefix.end());
+ record.insert(record.end(), suffix.begin(), suffix.end());
+ record.insert(record.end(), {5, 4, 3, 2, 1});
+
+ bssl::Span<uint8_t> result;
+ size_t record_len;
+ uint8_t alert;
+ EXPECT_EQ(bssl::OpenRecord(server.get(), &result, &record_len, &alert,
+ bssl::MakeSpan(record)),
+ bssl::OpenRecordResult::kOK);
+ EXPECT_EQ(record_len, record.size() - 5);
+ EXPECT_EQ(plaintext, result);
+}
+
+TEST(SSLTest, SealRecordInvalidSpanSize) {
+ bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method())),
+ server_ctx(SSL_CTX_new(TLS_method()));
+ ASSERT_TRUE(client_ctx);
+ ASSERT_TRUE(server_ctx);
+
+ bssl::UniquePtr<X509> cert = GetTestCertificate();
+ bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
+ ASSERT_TRUE(cert);
+ ASSERT_TRUE(key);
+ ASSERT_TRUE(SSL_CTX_use_certificate(server_ctx.get(), cert.get()));
+ ASSERT_TRUE(SSL_CTX_use_PrivateKey(server_ctx.get(), key.get()));
+
+ bssl::UniquePtr<SSL> client, server;
+ ASSERT_TRUE(ConnectClientAndServer(&client, &server, client_ctx.get(),
+ server_ctx.get(),
+ nullptr /* no session */));
+
+ std::vector<uint8_t> record = {1, 2, 3, 4, 5};
+ std::vector<uint8_t> prefix(
+ bssl::SealRecordPrefixLen(client.get(), record.size())),
+ body(record.size()),
+ suffix(bssl::SealRecordSuffixLen(client.get(), record.size()));
+
+ auto expect_err = []() {
+ int err = ERR_get_error();
+ EXPECT_EQ(ERR_GET_LIB(err), ERR_LIB_SSL);
+ EXPECT_EQ(ERR_GET_REASON(err), SSL_R_BUFFER_TOO_SMALL);
+ ERR_clear_error();
+ };
+ EXPECT_FALSE(bssl::SealRecord(
+ client.get(), bssl::MakeSpan(prefix.data(), prefix.size() - 1),
+ bssl::MakeSpan(record), bssl::MakeSpan(suffix), record));
+ expect_err();
+ EXPECT_FALSE(bssl::SealRecord(
+ client.get(), bssl::MakeSpan(prefix.data(), prefix.size() + 1),
+ bssl::MakeSpan(record), bssl::MakeSpan(suffix), record));
+ expect_err();
+
+ EXPECT_FALSE(
+ bssl::SealRecord(client.get(), bssl::MakeSpan(prefix),
+ bssl::MakeSpan(record.data(), record.size() - 1),
+ bssl::MakeSpan(suffix), record));
+ expect_err();
+ EXPECT_FALSE(
+ bssl::SealRecord(client.get(), bssl::MakeSpan(prefix),
+ bssl::MakeSpan(record.data(), record.size() + 1),
+ bssl::MakeSpan(suffix), record));
+ expect_err();
+
+ EXPECT_FALSE(bssl::SealRecord(
+ client.get(), bssl::MakeSpan(prefix), bssl::MakeSpan(record),
+ bssl::MakeSpan(suffix.data(), suffix.size() - 1), record));
+ expect_err();
+ EXPECT_FALSE(bssl::SealRecord(
+ client.get(), bssl::MakeSpan(prefix), bssl::MakeSpan(record),
+ bssl::MakeSpan(suffix.data(), suffix.size() + 1), record));
+ expect_err();
+}
+
// TODO(davidben): Convert this file to GTest properly.
TEST(SSLTest, AllTests) {
if (!TestSSL_SESSIONEncoding(kOpenSSLSession) ||
@@ -3712,6 +3954,7 @@ TEST(SSLTest, AllTests) {
!ForEachVersion(TestSequenceNumber) ||
!ForEachVersion(TestOneSidedShutdown) ||
!ForEachVersion(TestGetPeerCertificate) ||
+ !ForEachVersion(TestNoPeerCertificate) ||
!ForEachVersion(TestRetainOnlySHA256OfCerts) ||
!TestClientHello() ||
!ForEachVersion(TestSessionIDContext) ||
diff --git a/src/ssl/ssl_x509.cc b/src/ssl/ssl_x509.cc
index fd643086..98a5b8c3 100644
--- a/src/ssl/ssl_x509.cc
+++ b/src/ssl/ssl_x509.cc
@@ -172,14 +172,14 @@ static void check_ssl_ctx_x509_method(const SSL_CTX *ctx) {
/* x509_to_buffer returns a |CRYPTO_BUFFER| that contains the serialised
* contents of |x509|. */
-static CRYPTO_BUFFER *x509_to_buffer(X509 *x509) {
+static UniquePtr<CRYPTO_BUFFER> x509_to_buffer(X509 *x509) {
uint8_t *buf = NULL;
int cert_len = i2d_X509(x509, &buf);
if (cert_len <= 0) {
return 0;
}
- CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new(buf, cert_len, NULL);
+ UniquePtr<CRYPTO_BUFFER> buffer(CRYPTO_BUFFER_new(buf, cert_len, NULL));
OPENSSL_free(buf);
return buffer;
@@ -205,17 +205,17 @@ static STACK_OF(CRYPTO_BUFFER) *new_leafless_chain(void) {
* which case no change to |cert->chain| is made. It preverses the existing
* leaf from |cert->chain|, if any. */
static int ssl_cert_set_chain(CERT *cert, STACK_OF(X509) *chain) {
- STACK_OF(CRYPTO_BUFFER) *new_chain = NULL;
+ UniquePtr<STACK_OF(CRYPTO_BUFFER)> new_chain;
if (cert->chain != NULL) {
- new_chain = sk_CRYPTO_BUFFER_new_null();
- if (new_chain == NULL) {
+ new_chain.reset(sk_CRYPTO_BUFFER_new_null());
+ if (!new_chain) {
return 0;
}
CRYPTO_BUFFER *leaf = sk_CRYPTO_BUFFER_value(cert->chain, 0);
- if (!sk_CRYPTO_BUFFER_push(new_chain, leaf)) {
- goto err;
+ if (!sk_CRYPTO_BUFFER_push(new_chain.get(), leaf)) {
+ return 0;
}
/* |leaf| might be NULL if it's a “leafless” chain. */
if (leaf != NULL) {
@@ -223,30 +223,25 @@ static int ssl_cert_set_chain(CERT *cert, STACK_OF(X509) *chain) {
}
}
- for (size_t i = 0; i < sk_X509_num(chain); i++) {
- if (new_chain == NULL) {
- new_chain = new_leafless_chain();
- if (new_chain == NULL) {
- goto err;
+ for (X509 *x509 : chain) {
+ if (!new_chain) {
+ new_chain.reset(new_leafless_chain());
+ if (!new_chain) {
+ return 0;
}
}
- CRYPTO_BUFFER *buffer = x509_to_buffer(sk_X509_value(chain, i));
- if (buffer == NULL ||
- !sk_CRYPTO_BUFFER_push(new_chain, buffer)) {
- CRYPTO_BUFFER_free(buffer);
- goto err;
+ UniquePtr<CRYPTO_BUFFER> buffer = x509_to_buffer(x509);
+ if (!buffer ||
+ !PushToStack(new_chain.get(), std::move(buffer))) {
+ return 0;
}
}
sk_CRYPTO_BUFFER_pop_free(cert->chain, CRYPTO_BUFFER_free);
- cert->chain = new_chain;
+ cert->chain = new_chain.release();
return 1;
-
-err:
- sk_CRYPTO_BUFFER_pop_free(new_chain, CRYPTO_BUFFER_free);
- return 0;
}
static void ssl_crypto_x509_cert_flush_cached_leaf(CERT *cert) {
@@ -261,8 +256,7 @@ static void ssl_crypto_x509_cert_flush_cached_chain(CERT *cert) {
static int ssl_crypto_x509_check_client_CA_list(
STACK_OF(CRYPTO_BUFFER) *names) {
- for (size_t i = 0; i < sk_CRYPTO_BUFFER_num(names); i++) {
- const CRYPTO_BUFFER *buffer = sk_CRYPTO_BUFFER_value(names, i);
+ for (const CRYPTO_BUFFER *buffer : names) {
const uint8_t *inp = CRYPTO_BUFFER_data(buffer);
X509_NAME *name = d2i_X509_NAME(NULL, &inp, CRYPTO_BUFFER_len(buffer));
const int ok = name != NULL && inp == CRYPTO_BUFFER_data(buffer) +
@@ -298,8 +292,7 @@ static void ssl_crypto_x509_cert_dup(CERT *new_cert, const CERT *cert) {
static int ssl_crypto_x509_session_cache_objects(SSL_SESSION *sess) {
bssl::UniquePtr<STACK_OF(X509)> chain;
- const size_t num_certs = sk_CRYPTO_BUFFER_num(sess->certs);
- if (num_certs > 0) {
+ if (sk_CRYPTO_BUFFER_num(sess->certs) > 0) {
chain.reset(sk_X509_new_null());
if (!chain) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
@@ -307,21 +300,20 @@ static int ssl_crypto_x509_session_cache_objects(SSL_SESSION *sess) {
}
}
- X509 *leaf = NULL;
- for (size_t i = 0; i < num_certs; i++) {
- X509 *x509 = X509_parse_from_buffer(sk_CRYPTO_BUFFER_value(sess->certs, i));
- if (x509 == NULL) {
+ X509 *leaf = nullptr;
+ for (CRYPTO_BUFFER *cert : sess->certs) {
+ UniquePtr<X509> x509(X509_parse_from_buffer(cert));
+ if (!x509) {
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
return 0;
}
- if (!sk_X509_push(chain.get(), x509)) {
+ if (leaf == nullptr) {
+ leaf = x509.get();
+ }
+ if (!PushToStack(chain.get(), std::move(x509))) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
- X509_free(x509);
return 0;
}
- if (i == 0) {
- leaf = x509;
- }
}
sk_X509_pop_free(sess->x509_chain, X509_free);
@@ -437,50 +429,47 @@ static int ssl_crypto_x509_session_verify_cert_chain(SSL_SESSION *session,
}
X509 *leaf = sk_X509_value(cert_chain, 0);
- int ret = 0;
- X509_STORE_CTX ctx;
- if (!X509_STORE_CTX_init(&ctx, verify_store, leaf, cert_chain)) {
+ ScopedX509_STORE_CTX ctx;
+ if (!X509_STORE_CTX_init(ctx.get(), verify_store, leaf, cert_chain)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_X509_LIB);
return 0;
}
- if (!X509_STORE_CTX_set_ex_data(&ctx, SSL_get_ex_data_X509_STORE_CTX_idx(),
- ssl)) {
- goto err;
+ if (!X509_STORE_CTX_set_ex_data(ctx.get(),
+ SSL_get_ex_data_X509_STORE_CTX_idx(), ssl)) {
+ return 0;
}
/* We need to inherit the verify parameters. These can be determined by the
* context: if its a server it will verify SSL client certificates or vice
* versa. */
- X509_STORE_CTX_set_default(&ctx, ssl->server ? "ssl_client" : "ssl_server");
+ X509_STORE_CTX_set_default(ctx.get(),
+ ssl->server ? "ssl_client" : "ssl_server");
/* Anything non-default in "param" should overwrite anything in the ctx. */
- X509_VERIFY_PARAM_set1(X509_STORE_CTX_get0_param(&ctx), ssl->param);
+ X509_VERIFY_PARAM_set1(X509_STORE_CTX_get0_param(ctx.get()), ssl->param);
if (ssl->verify_callback) {
- X509_STORE_CTX_set_verify_cb(&ctx, ssl->verify_callback);
+ X509_STORE_CTX_set_verify_cb(ctx.get(), ssl->verify_callback);
}
int verify_ret;
if (ssl->ctx->app_verify_callback != NULL) {
- verify_ret = ssl->ctx->app_verify_callback(&ctx, ssl->ctx->app_verify_arg);
+ verify_ret =
+ ssl->ctx->app_verify_callback(ctx.get(), ssl->ctx->app_verify_arg);
} else {
- verify_ret = X509_verify_cert(&ctx);
+ verify_ret = X509_verify_cert(ctx.get());
}
- session->verify_result = ctx.error;
+ session->verify_result = ctx->error;
/* If |SSL_VERIFY_NONE|, the error is non-fatal, but we keep the result. */
if (verify_ret <= 0 && ssl->verify_mode != SSL_VERIFY_NONE) {
- *out_alert = ssl_verify_alarm_type(ctx.error);
- goto err;
+ *out_alert = ssl_verify_alarm_type(ctx->error);
+ return 0;
}
ERR_clear_error();
- ret = 1;
-
-err:
- X509_STORE_CTX_cleanup(&ctx);
- return ret;
+ return 1;
}
static void ssl_crypto_x509_hs_flush_cached_ca_names(SSL_HANDSHAKE *hs) {
@@ -517,31 +506,27 @@ static int ssl_crypto_x509_ssl_auto_chain_if_needed(SSL *ssl) {
return 1;
}
- X509 *leaf =
- X509_parse_from_buffer(sk_CRYPTO_BUFFER_value(ssl->cert->chain, 0));
+ UniquePtr<X509> leaf(
+ X509_parse_from_buffer(sk_CRYPTO_BUFFER_value(ssl->cert->chain, 0)));
if (!leaf) {
OPENSSL_PUT_ERROR(SSL, ERR_R_X509_LIB);
return 0;
}
- X509_STORE_CTX ctx;
- if (!X509_STORE_CTX_init(&ctx, ssl->ctx->cert_store, leaf, NULL)) {
- X509_free(leaf);
+ ScopedX509_STORE_CTX ctx;
+ if (!X509_STORE_CTX_init(ctx.get(), ssl->ctx->cert_store, leaf.get(), NULL)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_X509_LIB);
return 0;
}
/* Attempt to build a chain, ignoring the result. */
- X509_verify_cert(&ctx);
- X509_free(leaf);
+ X509_verify_cert(ctx.get());
ERR_clear_error();
/* Remove the leaf from the generated chain. */
- X509_free(sk_X509_shift(ctx.chain));
+ X509_free(sk_X509_shift(ctx->chain));
- const int ok = ssl_cert_set_chain(ssl->cert, ctx.chain);
- X509_STORE_CTX_cleanup(&ctx);
- if (!ok) {
+ if (!ssl_cert_set_chain(ssl->cert, ctx->chain)) {
return 0;
}
@@ -797,14 +782,12 @@ static int ssl_use_certificate(CERT *cert, X509 *x) {
return 0;
}
- CRYPTO_BUFFER *buffer = x509_to_buffer(x);
- if (buffer == NULL) {
+ UniquePtr<CRYPTO_BUFFER> buffer = x509_to_buffer(x);
+ if (!buffer) {
return 0;
}
- const int ok = ssl_set_cert(cert, buffer);
- CRYPTO_BUFFER_free(buffer);
- return ok;
+ return ssl_set_cert(cert, std::move(buffer));
}
int SSL_use_certificate(SSL *ssl, X509 *x) {
@@ -880,24 +863,18 @@ static int ssl_cert_set1_chain(CERT *cert, STACK_OF(X509) *chain) {
static int ssl_cert_append_cert(CERT *cert, X509 *x509) {
assert(cert->x509_method);
- CRYPTO_BUFFER *buffer = x509_to_buffer(x509);
- if (buffer == NULL) {
+ UniquePtr<CRYPTO_BUFFER> buffer = x509_to_buffer(x509);
+ if (!buffer) {
return 0;
}
if (cert->chain != NULL) {
- if (!sk_CRYPTO_BUFFER_push(cert->chain, buffer)) {
- CRYPTO_BUFFER_free(buffer);
- return 0;
- }
-
- return 1;
+ return PushToStack(cert->chain, std::move(buffer));
}
cert->chain = new_leafless_chain();
if (cert->chain == NULL ||
- !sk_CRYPTO_BUFFER_push(cert->chain, buffer)) {
- CRYPTO_BUFFER_free(buffer);
+ !PushToStack(cert->chain, std::move(buffer))) {
sk_CRYPTO_BUFFER_free(cert->chain);
cert->chain = NULL;
return 0;
@@ -997,27 +974,22 @@ static int ssl_cert_cache_chain_certs(CERT *cert) {
return 1;
}
- STACK_OF(X509) *chain = sk_X509_new_null();
- if (chain == NULL) {
+ UniquePtr<STACK_OF(X509)> chain(sk_X509_new_null());
+ if (!chain) {
return 0;
}
for (size_t i = 1; i < sk_CRYPTO_BUFFER_num(cert->chain); i++) {
CRYPTO_BUFFER *buffer = sk_CRYPTO_BUFFER_value(cert->chain, i);
- X509 *x509 = X509_parse_from_buffer(buffer);
- if (x509 == NULL ||
- !sk_X509_push(chain, x509)) {
- X509_free(x509);
- goto err;
+ UniquePtr<X509> x509(X509_parse_from_buffer(buffer));
+ if (!x509 ||
+ !PushToStack(chain.get(), std::move(x509))) {
+ return 0;
}
}
- cert->x509_chain = chain;
+ cert->x509_chain = chain.release();
return 1;
-
-err:
- sk_X509_pop_free(chain, X509_free);
- return 0;
}
int SSL_CTX_get0_chain_certs(const SSL_CTX *ctx, STACK_OF(X509) **out_chain) {
@@ -1096,34 +1068,28 @@ STACK_OF(X509_NAME) *SSL_dup_CA_list(STACK_OF(X509_NAME) *list) {
static void set_client_CA_list(STACK_OF(CRYPTO_BUFFER) **ca_list,
const STACK_OF(X509_NAME) *name_list,
CRYPTO_BUFFER_POOL *pool) {
- STACK_OF(CRYPTO_BUFFER) *buffers = sk_CRYPTO_BUFFER_new_null();
- if (buffers == NULL) {
+ UniquePtr<STACK_OF(CRYPTO_BUFFER)> buffers(sk_CRYPTO_BUFFER_new_null());
+ if (!buffers) {
return;
}
- for (size_t i = 0; i < sk_X509_NAME_num(name_list); i++) {
- X509_NAME *name = sk_X509_NAME_value(name_list, i);
+ for (X509_NAME *name : name_list) {
uint8_t *outp = NULL;
int len = i2d_X509_NAME(name, &outp);
if (len < 0) {
- goto err;
+ return;
}
- CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new(outp, len, pool);
+ UniquePtr<CRYPTO_BUFFER> buffer(CRYPTO_BUFFER_new(outp, len, pool));
OPENSSL_free(outp);
- if (buffer == NULL ||
- !sk_CRYPTO_BUFFER_push(buffers, buffer)) {
- CRYPTO_BUFFER_free(buffer);
- goto err;
+ if (!buffer ||
+ !PushToStack(buffers.get(), std::move(buffer))) {
+ return;
}
}
sk_CRYPTO_BUFFER_pop_free(*ca_list, CRYPTO_BUFFER_free);
- *ca_list = buffers;
- return;
-
-err:
- sk_CRYPTO_BUFFER_pop_free(buffers, CRYPTO_BUFFER_free);
+ *ca_list = buffers.release();
}
void SSL_set_client_CA_list(SSL *ssl, STACK_OF(X509_NAME) *name_list) {
@@ -1151,30 +1117,25 @@ static STACK_OF(X509_NAME) *
return *cached;
}
- STACK_OF(X509_NAME) *new_cache = sk_X509_NAME_new_null();
- if (new_cache == NULL) {
+ UniquePtr<STACK_OF(X509_NAME)> new_cache(sk_X509_NAME_new_null());
+ if (!new_cache) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
return NULL;
}
- for (size_t i = 0; i < sk_CRYPTO_BUFFER_num(names); i++) {
- const CRYPTO_BUFFER *buffer = sk_CRYPTO_BUFFER_value(names, i);
+ for (const CRYPTO_BUFFER *buffer : names) {
const uint8_t *inp = CRYPTO_BUFFER_data(buffer);
- X509_NAME *name = d2i_X509_NAME(NULL, &inp, CRYPTO_BUFFER_len(buffer));
- if (name == NULL ||
+ UniquePtr<X509_NAME> name(
+ d2i_X509_NAME(nullptr, &inp, CRYPTO_BUFFER_len(buffer)));
+ if (!name ||
inp != CRYPTO_BUFFER_data(buffer) + CRYPTO_BUFFER_len(buffer) ||
- !sk_X509_NAME_push(new_cache, name)) {
- X509_NAME_free(name);
- goto err;
+ !PushToStack(new_cache.get(), std::move(name))) {
+ return NULL;
}
}
- *cached = new_cache;
- return new_cache;
-
-err:
- sk_X509_NAME_pop_free(new_cache, X509_NAME_free);
- return NULL;
+ *cached = new_cache.release();
+ return *cached;
}
STACK_OF(X509_NAME) *SSL_get_client_CA_list(const SSL *ssl) {
@@ -1222,9 +1183,9 @@ static int add_client_CA(STACK_OF(CRYPTO_BUFFER) **names, X509 *x509,
return 0;
}
- CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new(outp, len, pool);
+ UniquePtr<CRYPTO_BUFFER> buffer(CRYPTO_BUFFER_new(outp, len, pool));
OPENSSL_free(outp);
- if (buffer == NULL) {
+ if (!buffer) {
return 0;
}
@@ -1234,13 +1195,11 @@ static int add_client_CA(STACK_OF(CRYPTO_BUFFER) **names, X509 *x509,
alloced = 1;
if (*names == NULL) {
- CRYPTO_BUFFER_free(buffer);
return 0;
}
}
- if (!sk_CRYPTO_BUFFER_push(*names, buffer)) {
- CRYPTO_BUFFER_free(buffer);
+ if (!PushToStack(*names, std::move(buffer))) {
if (alloced) {
sk_CRYPTO_BUFFER_pop_free(*names, CRYPTO_BUFFER_free);
*names = NULL;
@@ -1282,6 +1241,8 @@ static int do_client_cert_cb(SSL *ssl, void *arg) {
if (ret < 0) {
return -1;
}
+ UniquePtr<X509> free_x509(x509);
+ UniquePtr<EVP_PKEY> free_pkey(pkey);
if (ret != 0) {
if (!SSL_use_certificate(ssl, x509) ||
@@ -1290,8 +1251,6 @@ static int do_client_cert_cb(SSL *ssl, void *arg) {
}
}
- X509_free(x509);
- EVP_PKEY_free(pkey);
return 1;
}
diff --git a/src/ssl/t1_lib.cc b/src/ssl/t1_lib.cc
index 19f256dc..27a942a8 100644
--- a/src/ssl/t1_lib.cc
+++ b/src/ssl/t1_lib.cc
@@ -802,7 +802,7 @@ static int ext_ri_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert,
#endif
if (!ok) {
OPENSSL_PUT_ERROR(SSL, SSL_R_RENEGOTIATION_MISMATCH);
- *out_alert = SSL_AD_ILLEGAL_PARAMETER;
+ *out_alert = SSL_AD_HANDSHAKE_FAILURE;
return 0;
}
ssl->s3->send_connection_binding = 1;
@@ -1624,11 +1624,8 @@ static void ext_srtp_init(SSL_HANDSHAKE *hs) {
static int ext_srtp_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
SSL *const ssl = hs->ssl;
STACK_OF(SRTP_PROTECTION_PROFILE) *profiles = SSL_get_srtp_profiles(ssl);
- if (profiles == NULL) {
- return 1;
- }
- const size_t num_profiles = sk_SRTP_PROTECTION_PROFILE_num(profiles);
- if (num_profiles == 0) {
+ if (profiles == NULL ||
+ sk_SRTP_PROTECTION_PROFILE_num(profiles) == 0) {
return 1;
}
@@ -1639,9 +1636,8 @@ static int ext_srtp_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
return 0;
}
- for (size_t i = 0; i < num_profiles; i++) {
- if (!CBB_add_u16(&profile_ids,
- sk_SRTP_PROTECTION_PROFILE_value(profiles, i)->id)) {
+ for (const SRTP_PROTECTION_PROFILE *profile : profiles) {
+ if (!CBB_add_u16(&profile_ids, profile->id)) {
return 0;
}
}
@@ -1687,10 +1683,7 @@ static int ext_srtp_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert,
/* Check to see if the server gave us something we support (and presumably
* offered). */
- for (size_t i = 0; i < sk_SRTP_PROTECTION_PROFILE_num(profiles); i++) {
- const SRTP_PROTECTION_PROFILE *profile =
- sk_SRTP_PROTECTION_PROFILE_value(profiles, i);
-
+ for (const SRTP_PROTECTION_PROFILE *profile : profiles) {
if (profile->id == profile_id) {
ssl->srtp_profile = profile;
return 1;
@@ -1723,10 +1716,7 @@ static int ext_srtp_parse_clienthello(SSL_HANDSHAKE *hs, uint8_t *out_alert,
SSL_get_srtp_profiles(ssl);
/* Pick the server's most preferred profile. */
- for (size_t i = 0; i < sk_SRTP_PROTECTION_PROFILE_num(server_profiles); i++) {
- const SRTP_PROTECTION_PROFILE *server_profile =
- sk_SRTP_PROTECTION_PROFILE_value(server_profiles, i);
-
+ for (const SRTP_PROTECTION_PROFILE *server_profile : server_profiles) {
CBS profile_ids_tmp;
CBS_init(&profile_ids_tmp, CBS_data(&profile_ids), CBS_len(&profile_ids));
@@ -3133,11 +3123,11 @@ static enum ssl_ticket_aead_result_t ssl_decrypt_ticket_with_method(
}
enum ssl_ticket_aead_result_t ssl_process_ticket(
- SSL *ssl, SSL_SESSION **out_session, int *out_renew_ticket,
+ SSL *ssl, UniquePtr<SSL_SESSION> *out_session, int *out_renew_ticket,
const uint8_t *ticket, size_t ticket_len, const uint8_t *session_id,
size_t session_id_len) {
*out_renew_ticket = 0;
- *out_session = NULL;
+ out_session->reset();
if ((SSL_get_options(ssl) & SSL_OP_NO_TICKET) ||
session_id_len > SSL_MAX_SSL_SESSION_ID_LENGTH) {
@@ -3160,11 +3150,11 @@ enum ssl_ticket_aead_result_t ssl_process_ticket(
}
/* Decode the session. */
- SSL_SESSION *session =
- SSL_SESSION_from_bytes(plaintext, plaintext_len, ssl->ctx);
+ UniquePtr<SSL_SESSION> session(
+ SSL_SESSION_from_bytes(plaintext, plaintext_len, ssl->ctx));
OPENSSL_free(plaintext);
- if (session == NULL) {
+ if (!session) {
ERR_clear_error(); /* Don't leave an error on the queue. */
return ssl_ticket_aead_ignore_ticket;
}
@@ -3174,7 +3164,7 @@ enum ssl_ticket_aead_result_t ssl_process_ticket(
OPENSSL_memcpy(session->session_id, session_id, session_id_len);
session->session_id_length = session_id_len;
- *out_session = session;
+ *out_session = std::move(session);
return ssl_ticket_aead_success;
}
diff --git a/src/ssl/test/bssl_shim.cc b/src/ssl/test/bssl_shim.cc
index a056be09..8f4126e6 100644
--- a/src/ssl/test/bssl_shim.cc
+++ b/src/ssl/test/bssl_shim.cc
@@ -113,6 +113,8 @@ struct TestState {
bool is_resume = false;
bool early_callback_ready = false;
bool custom_verify_ready = false;
+ std::string msg_callback_text;
+ bool msg_callback_ok = true;
};
static void TestStateExFree(void *parent, void *ptr, CRYPTO_EX_DATA *ad,
@@ -993,6 +995,84 @@ static int ServerNameCallback(SSL *ssl, int *out_alert, void *arg) {
return SSL_TLSEXT_ERR_OK;
}
+static void MessageCallback(int is_write, int version, int content_type,
+ const void *buf, size_t len, SSL *ssl, void *arg) {
+ const uint8_t *buf_u8 = reinterpret_cast<const uint8_t *>(buf);
+ const TestConfig *config = GetTestConfig(ssl);
+ TestState *state = GetTestState(ssl);
+ if (!state->msg_callback_ok) {
+ return;
+ }
+
+ if (content_type == SSL3_RT_HEADER) {
+ if (len !=
+ (config->is_dtls ? DTLS1_RT_HEADER_LENGTH : SSL3_RT_HEADER_LENGTH)) {
+ fprintf(stderr, "Incorrect length for record header: %zu\n", len);
+ state->msg_callback_ok = false;
+ }
+ return;
+ }
+
+ state->msg_callback_text += is_write ? "write " : "read ";
+ switch (content_type) {
+ case 0:
+ if (version != SSL2_VERSION) {
+ fprintf(stderr, "Incorrect version for V2ClientHello: %x\n", version);
+ state->msg_callback_ok = false;
+ return;
+ }
+ state->msg_callback_text += "v2clienthello\n";
+ return;
+
+ case SSL3_RT_HANDSHAKE: {
+ CBS cbs;
+ CBS_init(&cbs, buf_u8, len);
+ uint8_t type;
+ uint32_t msg_len;
+ if (!CBS_get_u8(&cbs, &type) ||
+ /* TODO(davidben): Reporting on entire messages would be more
+ * consistent than fragments. */
+ (config->is_dtls &&
+ !CBS_skip(&cbs, 3 /* total */ + 2 /* seq */ + 3 /* frag_off */)) ||
+ !CBS_get_u24(&cbs, &msg_len) ||
+ !CBS_skip(&cbs, msg_len) ||
+ CBS_len(&cbs) != 0) {
+ fprintf(stderr, "Could not parse handshake message.\n");
+ state->msg_callback_ok = false;
+ return;
+ }
+ char text[16];
+ snprintf(text, sizeof(text), "hs %d\n", type);
+ state->msg_callback_text += text;
+ return;
+ }
+
+ case SSL3_RT_CHANGE_CIPHER_SPEC:
+ if (len != 1 || buf_u8[0] != 1) {
+ fprintf(stderr, "Invalid ChangeCipherSpec.\n");
+ state->msg_callback_ok = false;
+ return;
+ }
+ state->msg_callback_text += "ccs\n";
+ return;
+
+ case SSL3_RT_ALERT:
+ if (len != 2) {
+ fprintf(stderr, "Invalid alert.\n");
+ state->msg_callback_ok = false;
+ return;
+ }
+ char text[16];
+ snprintf(text, sizeof(text), "alert %d %d\n", buf_u8[0], buf_u8[1]);
+ state->msg_callback_text += text;
+ return;
+
+ default:
+ fprintf(stderr, "Invalid content_type: %d\n", content_type);
+ state->msg_callback_ok = false;
+ }
+}
+
// Connect returns a new socket connected to localhost on |port| or -1 on
// error.
static int Connect(uint16_t port) {
@@ -1224,6 +1304,8 @@ static bssl::UniquePtr<SSL_CTX> SetupCtx(SSL_CTX *old_ctx,
}
}
+ SSL_CTX_set_msg_callback(ssl_ctx.get(), MessageCallback);
+
if (old_ctx) {
uint8_t keys[48];
if (!SSL_CTX_get_tlsext_ticket_keys(old_ctx, &keys, sizeof(keys)) ||
@@ -2026,7 +2108,25 @@ static bool DoConnection(bssl::UniquePtr<SSL_SESSION> *out_session,
ret = DoExchange(out_session, ssl.get(), retry_config, is_resume, true);
}
- return ret;
+
+ if (!ret) {
+ return false;
+ }
+
+ if (!GetTestState(ssl.get())->msg_callback_ok) {
+ return false;
+ }
+
+ if (!config->expect_msg_callback.empty() &&
+ GetTestState(ssl.get())->msg_callback_text !=
+ config->expect_msg_callback) {
+ fprintf(stderr, "Bad message callback trace. Wanted:\n%s\nGot:\n%s\n",
+ config->expect_msg_callback.c_str(),
+ GetTestState(ssl.get())->msg_callback_text.c_str());
+ return false;
+ }
+
+ return true;
}
static bool DoExchange(bssl::UniquePtr<SSL_SESSION> *out_session, SSL *ssl,
diff --git a/src/ssl/test/runner/common.go b/src/ssl/test/runner/common.go
index a6a521b9..b8c27859 100644
--- a/src/ssl/test/runner/common.go
+++ b/src/ssl/test/runner/common.go
@@ -584,6 +584,11 @@ type ProtocolBugs struct {
// may be used to test DTLS's handling of reordered ChangeCipherSpec.
StrayChangeCipherSpec bool
+ // ReorderChangeCipherSpec causes the ChangeCipherSpec message to be
+ // sent at start of each flight in DTLS. Unlike EarlyChangeCipherSpec,
+ // the cipher change happens at the usual time.
+ ReorderChangeCipherSpec bool
+
// FragmentAcrossChangeCipherSpec causes the implementation to fragment
// the Finished (or NextProto) message around the ChangeCipherSpec
// messages.
diff --git a/src/ssl/test/runner/conn.go b/src/ssl/test/runner/conn.go
index 047c3c5b..2332e6bf 100644
--- a/src/ssl/test/runner/conn.go
+++ b/src/ssl/test/runner/conn.go
@@ -1023,10 +1023,8 @@ func (c *Conn) writeRecord(typ recordType, data []byte) (n int, err error) {
newData[0] = msgType
data = newData
}
- }
- if msgType := c.config.Bugs.SendTrailingMessageData; msgType != 0 {
- if typ == recordTypeHandshake && data[0] == msgType {
+ if c.config.Bugs.SendTrailingMessageData != 0 && msgType == c.config.Bugs.SendTrailingMessageData {
newData := make([]byte, len(data))
copy(newData, data)
@@ -1060,6 +1058,11 @@ func (c *Conn) writeRecord(typ recordType, data []byte) (n int, err error) {
}
}
+ // Flush buffered data before writing anything.
+ if err := c.flushHandshake(); err != nil {
+ return 0, err
+ }
+
return c.doWriteRecord(typ, data)
}
diff --git a/src/ssl/test/runner/dtls.go b/src/ssl/test/runner/dtls.go
index 72369d60..42b3a655 100644
--- a/src/ssl/test/runner/dtls.go
+++ b/src/ssl/test/runner/dtls.go
@@ -150,12 +150,29 @@ func (c *Conn) makeFragment(header, data []byte, fragOffset, fragLen int) []byte
func (c *Conn) dtlsWriteRecord(typ recordType, data []byte) (n int, err error) {
if typ != recordTypeHandshake {
+ reorder := typ == recordTypeChangeCipherSpec && c.config.Bugs.ReorderChangeCipherSpec
+
+ // Flush pending handshake messages before writing a new record.
+ if !reorder {
+ err = c.dtlsFlushHandshake()
+ if err != nil {
+ return
+ }
+ }
+
// Only handshake messages are fragmented.
n, err = c.dtlsWriteRawRecord(typ, data)
if err != nil {
return
}
+ if reorder {
+ err = c.dtlsFlushHandshake()
+ if err != nil {
+ return
+ }
+ }
+
if typ == recordTypeChangeCipherSpec {
err = c.out.changeCipherSpec(c.config)
if err != nil {
diff --git a/src/ssl/test/runner/handshake_client.go b/src/ssl/test/runner/handshake_client.go
index 10e841a5..33c1b128 100644
--- a/src/ssl/test/runner/handshake_client.go
+++ b/src/ssl/test/runner/handshake_client.go
@@ -1587,7 +1587,6 @@ func (hs *clientHandshakeState) sendFinished(out []byte, isResume bool) error {
c.writeRecord(recordTypeHandshake, postCCSMsgs[0])
postCCSMsgs = postCCSMsgs[1:]
}
- c.flushHandshake()
if !c.config.Bugs.SkipChangeCipherSpec &&
c.config.Bugs.EarlyChangeCipherSpec == 0 {
@@ -1614,9 +1613,9 @@ func (hs *clientHandshakeState) sendFinished(out []byte, isResume bool) error {
if c.config.Bugs.SendExtraFinished {
c.writeRecord(recordTypeHandshake, finished.marshal())
}
-
- c.flushHandshake()
}
+
+ c.flushHandshake()
return nil
}
diff --git a/src/ssl/test/runner/handshake_server.go b/src/ssl/test/runner/handshake_server.go
index 3e70185c..614bb504 100644
--- a/src/ssl/test/runner/handshake_server.go
+++ b/src/ssl/test/runner/handshake_server.go
@@ -1819,7 +1819,6 @@ func (hs *serverHandshakeState) sendFinished(out []byte) error {
c.writeRecord(recordTypeHandshake, postCCSBytes)
postCCSBytes = nil
}
- c.flushHandshake()
if !c.config.Bugs.SkipChangeCipherSpec {
ccs := []byte{1}
@@ -1842,11 +1841,11 @@ func (hs *serverHandshakeState) sendFinished(out []byte) error {
if c.config.Bugs.SendExtraFinished {
c.writeRecord(recordTypeHandshake, finished.marshal())
}
+ }
- if !c.config.Bugs.PackHelloRequestWithFinished {
- // Defer flushing until renegotiation.
- c.flushHandshake()
- }
+ if !c.config.Bugs.PackHelloRequestWithFinished {
+ // Defer flushing until renegotiation.
+ c.flushHandshake()
}
c.cipherSuite = hs.suite
diff --git a/src/ssl/test/runner/runner.go b/src/ssl/test/runner/runner.go
index c5f99715..9898101f 100644
--- a/src/ssl/test/runner/runner.go
+++ b/src/ssl/test/runner/runner.go
@@ -488,15 +488,19 @@ type timeoutConn struct {
}
func (t *timeoutConn) Read(b []byte) (int, error) {
- if err := t.SetReadDeadline(time.Now().Add(t.timeout)); err != nil {
- return 0, err
+ if !*useGDB {
+ if err := t.SetReadDeadline(time.Now().Add(t.timeout)); err != nil {
+ return 0, err
+ }
}
return t.Conn.Read(b)
}
func (t *timeoutConn) Write(b []byte) (int, error) {
- if err := t.SetWriteDeadline(time.Now().Add(t.timeout)); err != nil {
- return 0, err
+ if !*useGDB {
+ if err := t.SetWriteDeadline(time.Now().Add(t.timeout)); err != nil {
+ return 0, err
+ }
}
return t.Conn.Write(b)
}
@@ -891,7 +895,9 @@ func acceptOrWait(listener *net.TCPListener, waitChan chan error) (net.Conn, err
connChan := make(chan connOrError, 1)
go func() {
startTime := time.Now()
- listener.SetDeadline(time.Now().Add(*idleTimeout))
+ if !*useGDB {
+ listener.SetDeadline(time.Now().Add(*idleTimeout))
+ }
conn, err := listener.Accept()
endTime := time.Now()
connChan <- connOrError{conn, err, startTime, endTime}
@@ -1442,6 +1448,54 @@ func addBasicTests() {
},
flags: []string{
"-enable-ocsp-stapling",
+ // This test involves an optional message. Test the message callback
+ // trace to ensure we do not miss or double-report any.
+ "-expect-msg-callback",
+ `write hs 1
+read hs 2
+read hs 11
+read hs 12
+read hs 14
+write hs 16
+write ccs
+write hs 20
+read hs 4
+read ccs
+read hs 20
+read alert 1 0
+`,
+ },
+ },
+ {
+ protocol: dtls,
+ name: "SkipCertificateStatus-DTLS",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ Bugs: ProtocolBugs{
+ SkipCertificateStatus: true,
+ },
+ },
+ flags: []string{
+ "-enable-ocsp-stapling",
+ // This test involves an optional message. Test the message callback
+ // trace to ensure we do not miss or double-report any.
+ "-expect-msg-callback",
+ `write hs 1
+read hs 3
+write hs 1
+read hs 2
+read hs 11
+read hs 12
+read hs 14
+write hs 16
+write ccs
+write hs 20
+read hs 4
+read ccs
+read hs 20
+read alert 1 0
+`,
},
},
{
@@ -4753,6 +4807,20 @@ func addStateMachineCoverageTests(config stateMachineTestConfig) {
SendV2ClientHello: true,
},
},
+ flags: []string{
+ "-expect-msg-callback",
+ `read v2clienthello
+write hs 2
+write hs 11
+write hs 14
+read hs 16
+read ccs
+read hs 20
+write ccs
+write hs 20
+read alert 1 0
+`,
+ },
})
// Test Channel ID
@@ -7044,9 +7112,10 @@ func addRenegotiationTests() {
EmptyRenegotiationInfo: true,
},
},
- flags: []string{"-renegotiate-freely"},
- shouldFail: true,
- expectedError: ":RENEGOTIATION_MISMATCH:",
+ flags: []string{"-renegotiate-freely"},
+ shouldFail: true,
+ expectedError: ":RENEGOTIATION_MISMATCH:",
+ expectedLocalError: "handshake failure",
})
testCases = append(testCases, testCase{
name: "Renegotiate-Client-BadExt",
@@ -7057,9 +7126,10 @@ func addRenegotiationTests() {
BadRenegotiationInfo: true,
},
},
- flags: []string{"-renegotiate-freely"},
- shouldFail: true,
- expectedError: ":RENEGOTIATION_MISMATCH:",
+ flags: []string{"-renegotiate-freely"},
+ shouldFail: true,
+ expectedError: ":RENEGOTIATION_MISMATCH:",
+ expectedLocalError: "handshake failure",
})
testCases = append(testCases, testCase{
name: "Renegotiate-Client-BadExt2",
@@ -7070,9 +7140,10 @@ func addRenegotiationTests() {
BadRenegotiationInfoEnd: true,
},
},
- flags: []string{"-renegotiate-freely"},
- shouldFail: true,
- expectedError: ":RENEGOTIATION_MISMATCH:",
+ flags: []string{"-renegotiate-freely"},
+ shouldFail: true,
+ expectedError: ":RENEGOTIATION_MISMATCH:",
+ expectedLocalError: "handshake failure",
})
testCases = append(testCases, testCase{
name: "Renegotiate-Client-Downgrade",
@@ -7083,9 +7154,10 @@ func addRenegotiationTests() {
NoRenegotiationInfoAfterInitial: true,
},
},
- flags: []string{"-renegotiate-freely"},
- shouldFail: true,
- expectedError: ":RENEGOTIATION_MISMATCH:",
+ flags: []string{"-renegotiate-freely"},
+ shouldFail: true,
+ expectedError: ":RENEGOTIATION_MISMATCH:",
+ expectedLocalError: "handshake failure",
})
testCases = append(testCases, testCase{
name: "Renegotiate-Client-Upgrade",
@@ -7096,9 +7168,10 @@ func addRenegotiationTests() {
NoRenegotiationInfoInInitial: true,
},
},
- flags: []string{"-renegotiate-freely"},
- shouldFail: true,
- expectedError: ":RENEGOTIATION_MISMATCH:",
+ flags: []string{"-renegotiate-freely"},
+ shouldFail: true,
+ expectedError: ":RENEGOTIATION_MISMATCH:",
+ expectedLocalError: "handshake failure",
})
testCases = append(testCases, testCase{
name: "Renegotiate-Client-NoExt-Allowed",
@@ -10029,6 +10102,31 @@ func addChangeCipherSpecTests() {
},
})
+ // Test that reordered ChangeCipherSpecs are tolerated.
+ testCases = append(testCases, testCase{
+ protocol: dtls,
+ name: "ReorderChangeCipherSpec-DTLS-Client",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ ReorderChangeCipherSpec: true,
+ },
+ },
+ resumeSession: true,
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ protocol: dtls,
+ name: "ReorderChangeCipherSpec-DTLS-Server",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ ReorderChangeCipherSpec: true,
+ },
+ },
+ resumeSession: true,
+ })
+
// Test that the contents of ChangeCipherSpec are checked.
testCases = append(testCases, testCase{
name: "BadChangeCipherSpec-1",
diff --git a/src/ssl/test/test_config.cc b/src/ssl/test/test_config.cc
index fa7dfe18..8b2f7f29 100644
--- a/src/ssl/test/test_config.cc
+++ b/src/ssl/test/test_config.cc
@@ -157,6 +157,7 @@ const Flag<std::string> kStringFlags[] = {
{ "-expect-peer-cert-file", &TestConfig::expect_peer_cert_file },
{ "-use-client-ca-list", &TestConfig::use_client_ca_list },
{ "-expect-client-ca-list", &TestConfig::expected_client_ca_list },
+ { "-expect-msg-callback", &TestConfig::expect_msg_callback },
};
const Flag<std::string> kBase64Flags[] = {
diff --git a/src/ssl/test/test_config.h b/src/ssl/test/test_config.h
index 1e5912e3..af75548c 100644
--- a/src/ssl/test/test_config.h
+++ b/src/ssl/test/test_config.h
@@ -145,6 +145,7 @@ struct TestConfig {
bool allow_unknown_alpn_protos = false;
bool enable_ed25519 = false;
bool use_custom_verify_callback = false;
+ std::string expect_msg_callback;
};
bool ParseConfig(int argc, char **argv, TestConfig *out_initial,
diff --git a/src/ssl/tls13_both.cc b/src/ssl/tls13_both.cc
index 338975b1..1c2e7f75 100644
--- a/src/ssl/tls13_both.cc
+++ b/src/ssl/tls13_both.cc
@@ -55,7 +55,6 @@ int tls13_handshake(SSL_HANDSHAKE *hs, int *out_early_return) {
if (hs->wait != ssl_hs_flush_and_read_message) {
break;
}
- ssl->method->expect_flight(ssl);
hs->wait = ssl_hs_read_message;
SSL_FALLTHROUGH;
}
@@ -196,7 +195,9 @@ int tls13_process_certificate(SSL_HANDSHAKE *hs, int allow_anonymous) {
CBS cbs, context, certificate_list;
CBS_init(&cbs, ssl->init_msg, ssl->init_num);
if (!CBS_get_u8_length_prefixed(&cbs, &context) ||
- CBS_len(&context) != 0) {
+ CBS_len(&context) != 0 ||
+ !CBS_get_u24_length_prefixed(&cbs, &certificate_list) ||
+ CBS_len(&cbs) != 0) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
return 0;
@@ -209,12 +210,6 @@ int tls13_process_certificate(SSL_HANDSHAKE *hs, int allow_anonymous) {
return 0;
}
- if (!CBS_get_u24_length_prefixed(&cbs, &certificate_list)) {
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
- OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
- return 0;
- }
-
const bool retain_sha256 =
ssl->server && ssl->retain_only_sha256_of_client_certs;
UniquePtr<EVP_PKEY> pkey;
@@ -249,11 +244,10 @@ int tls13_process_certificate(SSL_HANDSHAKE *hs, int allow_anonymous) {
}
}
- CRYPTO_BUFFER *buf =
- CRYPTO_BUFFER_new_from_CBS(&certificate, ssl->ctx->pool);
- if (buf == NULL ||
- !sk_CRYPTO_BUFFER_push(certs.get(), buf)) {
- CRYPTO_BUFFER_free(buf);
+ UniquePtr<CRYPTO_BUFFER> buf(
+ CRYPTO_BUFFER_new_from_CBS(&certificate, ssl->ctx->pool));
+ if (!buf ||
+ !PushToStack(certs.get(), std::move(buf))) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
return 0;
@@ -326,10 +320,10 @@ int tls13_process_certificate(SSL_HANDSHAKE *hs, int allow_anonymous) {
}
}
- if (CBS_len(&cbs) != 0) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
- return 0;
+ /* Store a null certificate list rather than an empty one if the peer didn't
+ * send certificates. */
+ if (sk_CRYPTO_BUFFER_num(certs.get()) == 0) {
+ certs.reset();
}
hs->peer_pubkey = std::move(pkey);
diff --git a/src/ssl/tls13_client.cc b/src/ssl/tls13_client.cc
index 4cc7e604..29402652 100644
--- a/src/ssl/tls13_client.cc
+++ b/src/ssl/tls13_client.cc
@@ -530,7 +530,6 @@ static enum ssl_hs_wait_t do_process_server_finished(SSL_HANDSHAKE *hs) {
return ssl_hs_error;
}
- ssl->method->received_flight(ssl);
hs->tls13_state = state_send_end_of_early_data;
return ssl_hs_ok;
}
diff --git a/src/ssl/tls13_server.cc b/src/ssl/tls13_server.cc
index 067c427c..03f8bddf 100644
--- a/src/ssl/tls13_server.cc
+++ b/src/ssl/tls13_server.cc
@@ -255,7 +255,7 @@ static enum ssl_hs_wait_t do_select_parameters(SSL_HANDSHAKE *hs) {
}
static enum ssl_ticket_aead_result_t select_session(
- SSL_HANDSHAKE *hs, uint8_t *out_alert, SSL_SESSION **out_session,
+ SSL_HANDSHAKE *hs, uint8_t *out_alert, UniquePtr<SSL_SESSION> *out_session,
int32_t *out_ticket_age_skew, const SSL_CLIENT_HELLO *client_hello) {
SSL *const ssl = hs->ssl;
*out_session = NULL;
@@ -288,7 +288,7 @@ static enum ssl_ticket_aead_result_t select_session(
/* TLS 1.3 session tickets are renewed separately as part of the
* NewSessionTicket. */
int unused_renew;
- SSL_SESSION *session = NULL;
+ UniquePtr<SSL_SESSION> session;
enum ssl_ticket_aead_result_t ret =
ssl_process_ticket(ssl, &session, &unused_renew, CBS_data(&ticket),
CBS_len(&ticket), NULL, 0);
@@ -302,10 +302,9 @@ static enum ssl_ticket_aead_result_t select_session(
return ret;
}
- if (!ssl_session_is_resumable(hs, session) ||
+ if (!ssl_session_is_resumable(hs, session.get()) ||
/* Historically, some TLS 1.3 tickets were missing ticket_age_add. */
!session->ticket_age_add_valid) {
- SSL_SESSION_free(session);
return ssl_ticket_aead_ignore_ticket;
}
@@ -323,7 +322,6 @@ static enum ssl_ticket_aead_result_t select_session(
/* To avoid overflowing |hs->ticket_age_skew|, we will not resume
* 68-year-old sessions. */
if (server_ticket_age > INT32_MAX) {
- SSL_SESSION_free(session);
return ssl_ticket_aead_ignore_ticket;
}
@@ -333,13 +331,12 @@ static enum ssl_ticket_aead_result_t select_session(
(int32_t)client_ticket_age - (int32_t)server_ticket_age;
/* Check the PSK binder. */
- if (!tls13_verify_psk_binder(hs, session, &binders)) {
- SSL_SESSION_free(session);
+ if (!tls13_verify_psk_binder(hs, session.get(), &binders)) {
*out_alert = SSL_AD_DECRYPT_ERROR;
return ssl_ticket_aead_error;
}
- *out_session = session;
+ *out_session = std::move(session);
return ssl_ticket_aead_success;
}
@@ -354,11 +351,11 @@ static enum ssl_hs_wait_t do_select_session(SSL_HANDSHAKE *hs) {
}
uint8_t alert = SSL_AD_DECODE_ERROR;
- SSL_SESSION *session = NULL;
+ UniquePtr<SSL_SESSION> session;
switch (select_session(hs, &alert, &session, &ssl->s3->ticket_age_skew,
&client_hello)) {
case ssl_ticket_aead_ignore_ticket:
- assert(session == NULL);
+ assert(!session);
if (!ssl_get_new_session(hs, 1 /* server */)) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
return ssl_hs_error;
@@ -368,7 +365,8 @@ static enum ssl_hs_wait_t do_select_session(SSL_HANDSHAKE *hs) {
case ssl_ticket_aead_success:
/* Carry over authentication information from the previous handshake into
* a fresh session. */
- hs->new_session = SSL_SESSION_dup(session, SSL_SESSION_DUP_AUTH_ONLY);
+ hs->new_session =
+ SSL_SESSION_dup(session.get(), SSL_SESSION_DUP_AUTH_ONLY);
if (/* Early data must be acceptable for this ticket. */
ssl->cert->enable_early_data &&
@@ -384,7 +382,6 @@ static enum ssl_hs_wait_t do_select_session(SSL_HANDSHAKE *hs) {
ssl->early_data_accepted = 1;
}
- SSL_SESSION_free(session);
if (hs->new_session == NULL) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
return ssl_hs_error;
@@ -455,8 +452,6 @@ static enum ssl_hs_wait_t do_select_session(SSL_HANDSHAKE *hs) {
ssl->s3->skip_early_data = 1;
}
- ssl->method->received_flight(ssl);
-
/* Resolve ECDHE and incorporate it into the secret. */
int need_retry;
if (!resolve_ecdhe_secret(hs, &need_retry, &client_hello)) {
@@ -522,7 +517,6 @@ static enum ssl_hs_wait_t do_process_second_client_hello(SSL_HANDSHAKE *hs) {
return ssl_hs_error;
}
- ssl->method->received_flight(ssl);
hs->tls13_state = state_send_server_hello;
return ssl_hs_ok;
}
@@ -806,8 +800,6 @@ static enum ssl_hs_wait_t do_process_client_finished(SSL_HANDSHAKE *hs) {
return ssl_hs_error;
}
- ssl->method->received_flight(ssl);
-
if (!ssl->early_data_accepted) {
if (!ssl_hash_current_message(hs) ||
!tls13_derive_resumption_secret(hs)) {
diff --git a/src/ssl/tls_method.cc b/src/ssl/tls_method.cc
index 4751e2e9..02f5c076 100644
--- a/src/ssl/tls_method.cc
+++ b/src/ssl/tls_method.cc
@@ -69,9 +69,7 @@ namespace bssl {
static int ssl3_supports_cipher(const SSL_CIPHER *cipher) { return 1; }
-static void ssl3_expect_flight(SSL *ssl) {}
-
-static void ssl3_received_flight(SSL *ssl) {}
+static void ssl3_on_handshake_complete(SSL *ssl) {}
static int ssl3_set_read_state(SSL *ssl, UniquePtr<SSLAEADContext> aead_ctx) {
if (ssl->s3->rrec.length != 0) {
@@ -115,8 +113,7 @@ static const SSL_PROTOCOL_METHOD kTLSProtocolMethod = {
ssl3_add_change_cipher_spec,
ssl3_add_alert,
ssl3_flush_flight,
- ssl3_expect_flight,
- ssl3_received_flight,
+ ssl3_on_handshake_complete,
ssl3_set_read_state,
ssl3_set_write_state,
};
diff --git a/src/ssl/tls_record.cc b/src/ssl/tls_record.cc
index 437d02f1..f8bb521d 100644
--- a/src/ssl/tls_record.cc
+++ b/src/ssl/tls_record.cc
@@ -345,20 +345,35 @@ skipped_data:
}
static int do_seal_record(SSL *ssl, uint8_t *out_prefix, uint8_t *out,
- uint8_t *out_suffix, size_t *out_suffix_len,
- const size_t max_out_suffix_len, uint8_t type,
- const uint8_t *in, const size_t in_len) {
- assert(in == out || !buffers_alias(in, in_len, out, in_len));
- assert(!buffers_alias(in, in_len, out_prefix, ssl_record_prefix_len(ssl)));
- assert(!buffers_alias(in, in_len, out_suffix, max_out_suffix_len));
-
- /* TLS 1.3 hides the actual record type inside the encrypted data. */
+ uint8_t *out_suffix, uint8_t type, const uint8_t *in,
+ const size_t in_len) {
uint8_t *extra_in = NULL;
size_t extra_in_len = 0;
if (!ssl->s3->aead_write_ctx->is_null_cipher() &&
ssl->s3->aead_write_ctx->version() >= TLS1_3_VERSION) {
+ /* TLS 1.3 hides the actual record type inside the encrypted data. */
extra_in = &type;
extra_in_len = 1;
+ }
+
+ size_t suffix_len;
+ if (!ssl->s3->aead_write_ctx->SuffixLen(&suffix_len, in_len, extra_in_len)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_RECORD_TOO_LARGE);
+ return 0;
+ }
+ size_t ciphertext_len =
+ ssl->s3->aead_write_ctx->ExplicitNonceLen() + suffix_len;
+ if (ciphertext_len + in_len < ciphertext_len) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_RECORD_TOO_LARGE);
+ return 0;
+ }
+ ciphertext_len += in_len;
+
+ assert(in == out || !buffers_alias(in, in_len, out, in_len));
+ assert(!buffers_alias(in, in_len, out_prefix, ssl_record_prefix_len(ssl)));
+ assert(!buffers_alias(in, in_len, out_suffix, suffix_len));
+
+ if (extra_in_len) {
out_prefix[0] = SSL3_RT_APPLICATION_DATA;
} else {
out_prefix[0] = type;
@@ -377,33 +392,24 @@ static int do_seal_record(SSL *ssl, uint8_t *out_prefix, uint8_t *out,
}
out_prefix[1] = wire_version >> 8;
out_prefix[2] = wire_version & 0xff;
+ out_prefix[3] = ciphertext_len >> 8;
+ out_prefix[4] = ciphertext_len & 0xff;
- /* Write the ciphertext, leaving two bytes for the length. */
- if (!ssl->s3->aead_write_ctx->SealScatter(
- out_prefix + SSL3_RT_HEADER_LENGTH, out, out_suffix, out_suffix_len,
- max_out_suffix_len, type, wire_version, ssl->s3->write_sequence, in,
- in_len, extra_in, extra_in_len) ||
+ if (!ssl->s3->aead_write_ctx->SealScatter(out_prefix + SSL3_RT_HEADER_LENGTH,
+ out, out_suffix, type, wire_version,
+ ssl->s3->write_sequence, in, in_len,
+ extra_in, extra_in_len) ||
!ssl_record_sequence_update(ssl->s3->write_sequence, 8)) {
return 0;
}
- /* Fill in the length. */
- const size_t ciphertext_len =
- ssl->s3->aead_write_ctx->ExplicitNonceLen() + in_len + *out_suffix_len;
- if (ciphertext_len >= 1 << 15) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
- return 0;
- }
- out_prefix[3] = ciphertext_len >> 8;
- out_prefix[4] = ciphertext_len & 0xff;
-
ssl_do_msg_callback(ssl, 1 /* write */, SSL3_RT_HEADER, out_prefix,
SSL3_RT_HEADER_LENGTH);
return 1;
}
static size_t tls_seal_scatter_prefix_len(const SSL *ssl, uint8_t type,
- size_t in_len) {
+ size_t in_len) {
size_t ret = SSL3_RT_HEADER_LENGTH;
if (type == SSL3_RT_APPLICATION_DATA && in_len > 1 &&
ssl_needs_record_splitting(ssl)) {
@@ -419,18 +425,34 @@ static size_t tls_seal_scatter_prefix_len(const SSL *ssl, uint8_t type,
return ret;
}
+static bool tls_seal_scatter_suffix_len(const SSL *ssl, size_t *out_suffix_len,
+ uint8_t type, size_t in_len) {
+ size_t extra_in_len = 0;
+ if (!ssl->s3->aead_write_ctx->is_null_cipher() &&
+ ssl->s3->aead_write_ctx->version() >= TLS1_3_VERSION) {
+ /* TLS 1.3 adds an extra byte for encrypted record type. */
+ extra_in_len = 1;
+ }
+ if (type == SSL3_RT_APPLICATION_DATA && // clang-format off
+ in_len > 1 &&
+ ssl_needs_record_splitting(ssl)) {
+ /* With record splitting enabled, the first byte gets sealed into a separate
+ * record which is written into the prefix. */
+ in_len -= 1;
+ }
+ return ssl->s3->aead_write_ctx->SuffixLen(out_suffix_len, in_len, extra_in_len);
+}
+
/* tls_seal_scatter_record seals a new record of type |type| and body |in| and
* splits it between |out_prefix|, |out|, and |out_suffix|. Exactly
* |tls_seal_scatter_prefix_len| bytes are written to |out_prefix|, |in_len|
- * bytes to |out|, and up to 1 + |SSLAEADContext::MaxOverhead| bytes to
- * |out_suffix|. |*out_suffix_len| is set to the actual number of bytes written
- * to |out_suffix|. It returns one on success and zero on error. If enabled,
+ * bytes to |out|, and |tls_seal_scatter_suffix_len| bytes to |out_suffix|. It
+ * returns one on success and zero on error. If enabled,
* |tls_seal_scatter_record| implements TLS 1.0 CBC 1/n-1 record splitting and
* may write two records concatenated. */
static int tls_seal_scatter_record(SSL *ssl, uint8_t *out_prefix, uint8_t *out,
- uint8_t *out_suffix, size_t *out_suffix_len,
- size_t max_out_suffix_len, uint8_t type,
- const uint8_t *in, size_t in_len) {
+ uint8_t *out_suffix, uint8_t type,
+ const uint8_t *in, size_t in_len) {
if (type == SSL3_RT_APPLICATION_DATA && in_len > 1 &&
ssl_needs_record_splitting(ssl)) {
assert(ssl->s3->aead_write_ctx->ExplicitNonceLen() == 0);
@@ -440,17 +462,17 @@ static int tls_seal_scatter_record(SSL *ssl, uint8_t *out_prefix, uint8_t *out,
uint8_t *split_body = out_prefix + prefix_len;
uint8_t *split_suffix = split_body + 1;
- /* TODO(martinkr): Make AEAD code not complain if max_suffix_len is lower
- * than |EVP_AEAD_max_overhead| but still sufficiently large. */
- size_t split_max_suffix_len = ssl->s3->aead_write_ctx->MaxSuffixLen(0);
- size_t split_suffix_len = 0;
- if (!do_seal_record(ssl, out_prefix, split_body, split_suffix,
- &split_suffix_len, split_max_suffix_len, type, in, 1)) {
+ if (!do_seal_record(ssl, out_prefix, split_body, split_suffix, type, in,
+ 1)) {
return 0;
}
- size_t split_record_len = prefix_len + 1 + split_suffix_len;
-
+ size_t split_record_suffix_len;
+ if (!ssl->s3->aead_write_ctx->SuffixLen(&split_record_suffix_len, 1, 0)) {
+ assert(false);
+ return 0;
+ }
+ const size_t split_record_len = prefix_len + 1 + split_record_suffix_len;
assert(SSL3_RT_HEADER_LENGTH + ssl_cipher_get_record_split_len(
ssl->s3->aead_write_ctx->cipher()) ==
split_record_len);
@@ -458,8 +480,8 @@ static int tls_seal_scatter_record(SSL *ssl, uint8_t *out_prefix, uint8_t *out,
/* Write the n-1-byte fragment. The header gets split between |out_prefix|
* (header[:-1]) and |out| (header[-1:]). */
uint8_t tmp_prefix[SSL3_RT_HEADER_LENGTH];
- if (!do_seal_record(ssl, tmp_prefix, out + 1, out_suffix, out_suffix_len,
- max_out_suffix_len, type, in + 1, in_len - 1)) {
+ if (!do_seal_record(ssl, tmp_prefix, out + 1, out_suffix, type, in + 1,
+ in_len - 1)) {
return 0;
}
assert(tls_seal_scatter_prefix_len(ssl, type, in_len) ==
@@ -470,8 +492,7 @@ static int tls_seal_scatter_record(SSL *ssl, uint8_t *out_prefix, uint8_t *out,
return 1;
}
- return do_seal_record(ssl, out_prefix, out, out_suffix, out_suffix_len,
- max_out_suffix_len, type, in, in_len);
+ return do_seal_record(ssl, out_prefix, out, out_suffix, type, in, in_len);
}
int tls_seal_record(SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out_len,
@@ -482,12 +503,16 @@ int tls_seal_record(SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out_len,
}
const size_t prefix_len = tls_seal_scatter_prefix_len(ssl, type, in_len);
-
- if (in_len + prefix_len < in_len) {
+ size_t suffix_len;
+ if (!tls_seal_scatter_suffix_len(ssl, &suffix_len, type, in_len)) {
+ return false;
+ }
+ if (in_len + prefix_len < in_len ||
+ prefix_len + in_len + suffix_len < prefix_len + in_len) {
OPENSSL_PUT_ERROR(SSL, SSL_R_RECORD_TOO_LARGE);
return 0;
}
- if (max_out_len < in_len + prefix_len) {
+ if (max_out_len < in_len + prefix_len + suffix_len) {
OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL);
return 0;
}
@@ -495,16 +520,7 @@ int tls_seal_record(SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out_len,
uint8_t *prefix = out;
uint8_t *body = out + prefix_len;
uint8_t *suffix = body + in_len;
- size_t max_suffix_len = max_out_len - prefix_len - in_len;
- size_t suffix_len = 0;
-
- if (!tls_seal_scatter_record(ssl, prefix, body, suffix, &suffix_len,
- max_suffix_len, type, in, in_len)) {
- return 0;
- }
-
- if (prefix_len + in_len + suffix_len < prefix_len + in_len) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_RECORD_TOO_LARGE);
+ if (!tls_seal_scatter_record(ssl, prefix, body, suffix, type, in, in_len)) {
return 0;
}
@@ -567,6 +583,89 @@ enum ssl_open_record_t ssl_process_alert(SSL *ssl, uint8_t *out_alert,
return ssl_open_record_error;
}
+OpenRecordResult OpenRecord(SSL *ssl, Span<uint8_t> *out,
+ size_t *out_record_len, uint8_t *out_alert,
+ const Span<uint8_t> in) {
+ // This API is a work in progress and currently only works for TLS 1.2 servers
+ // and below.
+ if (SSL_in_init(ssl) ||
+ SSL_is_dtls(ssl) ||
+ ssl3_protocol_version(ssl) > TLS1_2_VERSION) {
+ assert(false);
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ return OpenRecordResult::kError;
+ }
+
+ CBS plaintext;
+ uint8_t type;
+ const ssl_open_record_t result = tls_open_record(
+ ssl, &type, &plaintext, out_record_len, out_alert, in.data(), in.size());
+
+ switch (result) {
+ case ssl_open_record_success:
+ if (type != SSL3_RT_APPLICATION_DATA && type != SSL3_RT_ALERT) {
+ *out_alert = SSL_AD_UNEXPECTED_MESSAGE;
+ return OpenRecordResult::kError;
+ }
+ *out = MakeSpan(
+ const_cast<uint8_t*>(CBS_data(&plaintext)), CBS_len(&plaintext));
+ return OpenRecordResult::kOK;
+ case ssl_open_record_discard:
+ return OpenRecordResult::kDiscard;
+ case ssl_open_record_partial:
+ return OpenRecordResult::kIncompleteRecord;
+ case ssl_open_record_close_notify:
+ return OpenRecordResult::kAlertCloseNotify;
+ case ssl_open_record_fatal_alert:
+ return OpenRecordResult::kAlertFatal;
+ case ssl_open_record_error:
+ return OpenRecordResult::kError;
+ }
+ assert(false);
+ return OpenRecordResult::kError;
+}
+
+size_t SealRecordPrefixLen(const SSL *ssl, const size_t record_len) {
+ return tls_seal_scatter_prefix_len(ssl, SSL3_RT_APPLICATION_DATA, record_len);
+}
+
+size_t SealRecordSuffixLen(const SSL *ssl, const size_t plaintext_len) {
+ assert(plaintext_len <= SSL3_RT_MAX_PLAIN_LENGTH);
+ size_t suffix_len;
+ if (!tls_seal_scatter_suffix_len(ssl, &suffix_len, SSL3_RT_APPLICATION_DATA,
+ plaintext_len)) {
+ assert(false);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+ assert(suffix_len <= SSL3_RT_MAX_ENCRYPTED_OVERHEAD);
+ return suffix_len;
+}
+
+bool SealRecord(SSL *ssl, const Span<uint8_t> out_prefix,
+ const Span<uint8_t> out, Span<uint8_t> out_suffix,
+ const Span<const uint8_t> in) {
+ // This API is a work in progress and currently only works for TLS 1.2 servers
+ // and below.
+ if (SSL_in_init(ssl) ||
+ SSL_is_dtls(ssl) ||
+ ssl3_protocol_version(ssl) > TLS1_2_VERSION) {
+ assert(false);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return false;
+ }
+
+ if (out_prefix.size() != SealRecordPrefixLen(ssl, in.size()) ||
+ out.size() != in.size() ||
+ out_suffix.size() != SealRecordSuffixLen(ssl, in.size())) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL);
+ return false;
+ }
+ return tls_seal_scatter_record(ssl, out_prefix.data(), out.data(),
+ out_suffix.data(), SSL3_RT_APPLICATION_DATA,
+ in.data(), in.size());
+}
+
} // namespace bssl
using namespace bssl;
diff --git a/src/tool/rand.cc b/src/tool/rand.cc
index b442e0d0..6519a0da 100644
--- a/src/tool/rand.cc
+++ b/src/tool/rand.cc
@@ -42,7 +42,7 @@ bool Rand(const std::vector<std::string> &args) {
std::vector<std::string> args_copy(args);
const std::string &last_arg = args.back();
- if (last_arg.size() > 0 && last_arg[0] != '-') {
+ if (!last_arg.empty() && last_arg[0] != '-') {
char *endptr;
unsigned long long num = strtoull(last_arg.c_str(), &endptr, 10);
if (*endptr == 0) {
diff --git a/src/tool/speed.cc b/src/tool/speed.cc
index 66522989..cf7e70e8 100644
--- a/src/tool/speed.cc
+++ b/src/tool/speed.cc
@@ -215,15 +215,24 @@ static bool SpeedAEADChunk(const EVP_AEAD *aead, const std::string &name,
std::unique_ptr<uint8_t[]> nonce(new uint8_t[nonce_len]);
OPENSSL_memset(nonce.get(), 0, nonce_len);
std::unique_ptr<uint8_t[]> in_storage(new uint8_t[chunk_len + kAlignment]);
- std::unique_ptr<uint8_t[]> out_storage(new uint8_t[chunk_len + overhead_len + kAlignment]);
+ // N.B. for EVP_AEAD_CTX_seal_scatter the input and output buffers may be the
+ // same size. However, in the direction == evp_aead_open case we still use
+ // non-scattering seal, hence we add overhead_len to the size of this buffer.
+ std::unique_ptr<uint8_t[]> out_storage(
+ new uint8_t[chunk_len + overhead_len + kAlignment]);
std::unique_ptr<uint8_t[]> in2_storage(new uint8_t[chunk_len + kAlignment]);
std::unique_ptr<uint8_t[]> ad(new uint8_t[ad_len]);
OPENSSL_memset(ad.get(), 0, ad_len);
+ std::unique_ptr<uint8_t[]> tag_storage(
+ new uint8_t[overhead_len + kAlignment]);
+
uint8_t *const in = align(in_storage.get(), kAlignment);
OPENSSL_memset(in, 0, chunk_len);
uint8_t *const out = align(out_storage.get(), kAlignment);
OPENSSL_memset(out, 0, chunk_len + overhead_len);
+ uint8_t *const tag = align(tag_storage.get(), kAlignment);
+ OPENSSL_memset(tag, 0, overhead_len);
uint8_t *const in2 = align(in2_storage.get(), kAlignment);
if (!EVP_AEAD_CTX_init_with_direction(ctx.get(), aead, key.get(), key_len,
@@ -236,13 +245,15 @@ static bool SpeedAEADChunk(const EVP_AEAD *aead, const std::string &name,
TimeResults results;
if (direction == evp_aead_seal) {
- if (!TimeFunction(&results, [chunk_len, overhead_len, nonce_len, ad_len, in,
- out, &ctx, &nonce, &ad]() -> bool {
- size_t out_len;
- return EVP_AEAD_CTX_seal(ctx.get(), out, &out_len,
- chunk_len + overhead_len, nonce.get(),
- nonce_len, in, chunk_len, ad.get(), ad_len);
- })) {
+ if (!TimeFunction(&results,
+ [chunk_len, nonce_len, ad_len, overhead_len, in, out, tag,
+ &ctx, &nonce, &ad]() -> bool {
+ size_t tag_len;
+ return EVP_AEAD_CTX_seal_scatter(
+ ctx.get(), out, tag, &tag_len, overhead_len,
+ nonce.get(), nonce_len, in, chunk_len, nullptr, 0,
+ ad.get(), ad_len);
+ })) {
fprintf(stderr, "EVP_AEAD_CTX_seal failed.\n");
ERR_print_errors_fp(stderr);
return false;
@@ -252,13 +263,16 @@ static bool SpeedAEADChunk(const EVP_AEAD *aead, const std::string &name,
EVP_AEAD_CTX_seal(ctx.get(), out, &out_len, chunk_len + overhead_len,
nonce.get(), nonce_len, in, chunk_len, ad.get(), ad_len);
- if (!TimeFunction(&results, [chunk_len, nonce_len, ad_len, in2, out, &ctx,
- &nonce, &ad, out_len]() -> bool {
- size_t in2_len;
- return EVP_AEAD_CTX_open(ctx.get(), in2, &in2_len, chunk_len,
- nonce.get(), nonce_len, out, out_len,
- ad.get(), ad_len);
- })) {
+ if (!TimeFunction(&results,
+ [chunk_len, nonce_len, ad_len, in2, out, out_len, &ctx,
+ &nonce, &ad]() -> bool {
+ size_t in2_len;
+ // N.B. EVP_AEAD_CTX_open_gather is not implemented for
+ // all AEADs.
+ return EVP_AEAD_CTX_open(
+ ctx.get(), in2, &in2_len, chunk_len, nonce.get(),
+ nonce_len, out, out_len, ad.get(), ad_len);
+ })) {
fprintf(stderr, "EVP_AEAD_CTX_open failed.\n");
ERR_print_errors_fp(stderr);
return false;
diff --git a/src/tool/transport_common.cc b/src/tool/transport_common.cc
index 0fc7c3c1..3f75c9fe 100644
--- a/src/tool/transport_common.cc
+++ b/src/tool/transport_common.cc
@@ -348,6 +348,60 @@ bool SocketSetNonBlocking(int sock, bool is_non_blocking) {
return ok;
}
+static bool SocketSelect(int sock, bool stdin_open, bool *socket_ready,
+ bool *stdin_ready) {
+#if !defined(OPENSSL_WINDOWS)
+ fd_set read_fds;
+ FD_ZERO(&read_fds);
+ if (stdin_open) {
+ FD_SET(0, &read_fds);
+ }
+ FD_SET(sock, &read_fds);
+ if (select(sock + 1, &read_fds, NULL, NULL, NULL) <= 0) {
+ perror("select");
+ return false;
+ }
+
+ if (FD_ISSET(0, &read_fds)) {
+ *stdin_ready = true;
+ }
+ if (FD_ISSET(sock, &read_fds)) {
+ *socket_ready = true;
+ }
+
+ return true;
+#else
+ WSAEVENT socket_handle = WSACreateEvent();
+ if (socket_handle == WSA_INVALID_EVENT ||
+ WSAEventSelect(sock, socket_handle, FD_READ) != 0) {
+ WSACloseEvent(socket_handle);
+ return false;
+ }
+
+ HANDLE read_fds[2];
+ read_fds[0] = socket_handle;
+ read_fds[1] = GetStdHandle(STD_INPUT_HANDLE);
+
+ switch (
+ WaitForMultipleObjects(stdin_open ? 2 : 1, read_fds, FALSE, INFINITE)) {
+ case WAIT_OBJECT_0 + 0:
+ *socket_ready = true;
+ break;
+ case WAIT_OBJECT_0 + 1:
+ *stdin_ready = true;
+ break;
+ case WAIT_TIMEOUT:
+ break;
+ default:
+ WSACloseEvent(socket_handle);
+ return false;
+ }
+
+ WSACloseEvent(socket_handle);
+ return true;
+#endif
+}
+
// PrintErrorCallback is a callback function from OpenSSL's
// |ERR_print_errors_cb| that writes errors to a given |FILE*|.
int PrintErrorCallback(const char *str, size_t len, void *ctx) {
@@ -356,28 +410,19 @@ int PrintErrorCallback(const char *str, size_t len, void *ctx) {
}
bool TransferData(SSL *ssl, int sock) {
- bool stdin_open = true;
-
- fd_set read_fds;
- FD_ZERO(&read_fds);
-
if (!SocketSetNonBlocking(sock, true)) {
return false;
}
+ bool stdin_open = true;
for (;;) {
- if (stdin_open) {
- FD_SET(0, &read_fds);
- }
- FD_SET(sock, &read_fds);
-
- int ret = select(sock + 1, &read_fds, NULL, NULL, NULL);
- if (ret <= 0) {
- perror("select");
+ bool socket_ready = false;
+ bool stdin_ready = false;
+ if (!SocketSelect(sock, stdin_open, &socket_ready, &stdin_ready)) {
return false;
}
- if (FD_ISSET(0, &read_fds)) {
+ if (stdin_ready) {
uint8_t buffer[512];
ssize_t n;
@@ -386,7 +431,6 @@ bool TransferData(SSL *ssl, int sock) {
} while (n == -1 && errno == EINTR);
if (n == 0) {
- FD_CLR(0, &read_fds);
stdin_open = false;
#if !defined(OPENSSL_WINDOWS)
shutdown(sock, SHUT_WR);
@@ -399,9 +443,12 @@ bool TransferData(SSL *ssl, int sock) {
return false;
}
+ // On Windows, SocketSelect ends up setting sock to non-blocking.
+#if !defined(OPENSSL_WINDOWS)
if (!SocketSetNonBlocking(sock, false)) {
return false;
}
+#endif
int ssl_ret = SSL_write(ssl, buffer, n);
if (!SocketSetNonBlocking(sock, true)) {
return false;
@@ -418,7 +465,7 @@ bool TransferData(SSL *ssl, int sock) {
}
}
- if (FD_ISSET(sock, &read_fds)) {
+ if (socket_ready) {
uint8_t buffer[512];
int ssl_ret = SSL_read(ssl, buffer, sizeof(buffer));
diff --git a/src/util/BUILD.toplevel b/src/util/BUILD.toplevel
index 68a17a60..af7bd303 100644
--- a/src/util/BUILD.toplevel
+++ b/src/util/BUILD.toplevel
@@ -26,8 +26,7 @@ load(
"fips_fragments",
"ssl_headers",
"ssl_internal_headers",
- "ssl_c_sources",
- "ssl_cc_sources",
+ "ssl_sources",
"tool_sources",
"tool_headers",
)
@@ -42,7 +41,12 @@ config_setting(
values = {"cpu": "darwin"},
)
-boringssl_copts = [
+config_setting(
+ name = "windows_x86_64",
+ values = {"cpu": "x64_windows"},
+)
+
+posix_copts = [
# Assembler option --noexecstack adds .note.GNU-stack to each object to
# ensure that binaries can be built with non-executable stack.
"-Wa,--noexecstack",
@@ -64,9 +68,15 @@ boringssl_copts = [
# operations for reference counting rather than locks. However, it's
# known not to work on some Android builds.
# "-DOPENSSL_C11_ATOMIC",
-] + select({
- ":linux_x86_64": [],
- ":mac_x86_64": [],
+]
+
+boringssl_copts = select({
+ ":linux_x86_64": posix_copts,
+ ":mac_x86_64": posix_copts,
+ ":windows_x86_64": [
+ "-DWIN32_LEAN_AND_MEAN",
+ "-DOPENSSL_NO_ASM",
+ ],
"//conditions:default": ["-DOPENSSL_NO_ASM"],
})
@@ -77,19 +87,31 @@ crypto_sources_asm = select({
})
# For C targets only (not C++), compile with C11 support.
-boringssl_copts_c11 = boringssl_copts + [
+posix_copts_c11 = [
"-std=c11",
"-Wmissing-prototypes",
"-Wold-style-definition",
"-Wstrict-prototypes",
]
-# For C targets only (not C++), compile with C11 support.
-boringssl_copts_cxx = boringssl_copts + [
+boringssl_copts_c11 = boringssl_copts + select({
+ ":linux_x86_64": posix_copts_c11,
+ ":mac_x86_64": posix_copts_c11,
+ "//conditions:default": [],
+})
+
+# For C++ targets only (not C), compile with C++11 support.
+posix_copts_cxx = [
"-std=c++11",
"-Wmissing-declarations",
]
+boringssl_copts_cxx = boringssl_copts + select({
+ ":linux_x86_64": posix_copts_cxx,
+ ":mac_x86_64": posix_copts_cxx,
+ "//conditions:default": [],
+})
+
cc_library(
name = "crypto",
srcs = crypto_sources + crypto_internal_headers + crypto_sources_asm,
@@ -105,21 +127,14 @@ cc_library(
cc_library(
name = "ssl",
- srcs = ssl_c_sources + ssl_internal_headers,
+ srcs = ssl_sources + ssl_internal_headers,
hdrs = ssl_headers,
- copts = boringssl_copts_c11,
+ copts = boringssl_copts_cxx,
includes = ["src/include"],
visibility = ["//visibility:public"],
- deps = [":crypto", ":ssl_cc"],
-)
-
-cc_library(
- name = "ssl_cc",
- srcs = ssl_cc_sources + ssl_internal_headers,
- hdrs = ssl_headers,
- copts = boringssl_copts,
- includes = ["src/include"],
- deps = [":crypto"],
+ deps = [
+ ":crypto",
+ ],
)
cc_binary(
diff --git a/src/util/all_tests.go b/src/util/all_tests.go
index d3f9203a..ef23080e 100644
--- a/src/util/all_tests.go
+++ b/src/util/all_tests.go
@@ -96,6 +96,7 @@ var sdeCPUs = []string{
"slt", // Saltwell
"slm", // Silvermont
"glm", // Goldmont
+ "knm", // Knights Mill
}
func newTestOutput() *testOutput {
diff --git a/src/util/check_imported_libraries.go b/src/util/check_imported_libraries.go
new file mode 100644
index 00000000..835d5fdd
--- /dev/null
+++ b/src/util/check_imported_libraries.go
@@ -0,0 +1,56 @@
+// 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.
+
+// check_imported_libraries.go checks that each of its arguments only imports a
+// whitelist of allowed libraries. This is used to avoid accidental dependencies
+// on libstdc++.so.
+package main
+
+import (
+ "debug/elf"
+ "fmt"
+ "os"
+)
+
+func checkImportedLibraries(path string) {
+ file, err := elf.Open(path)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Error opening %s: %s\n", path, err)
+ os.Exit(1)
+ }
+ defer file.Close()
+
+ libs, err := file.ImportedLibraries()
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Error reading %s: %s\n", path, err)
+ os.Exit(1)
+ }
+
+ for _, lib := range libs {
+ if lib != "libc.so.6" && lib != "libcrypto.so" && lib != "libpthread.so.0" {
+ fmt.Printf("Invalid dependency for %s: %s\n", path, lib)
+ fmt.Printf("All dependencies:\n")
+ for _, lib := range libs {
+ fmt.Printf(" %s\n", lib)
+ }
+ os.Exit(1)
+ }
+ }
+}
+
+func main() {
+ for _, path := range os.Args[1:] {
+ checkImportedLibraries(path)
+ }
+}
diff --git a/src/util/convert_comments.go b/src/util/convert_comments.go
new file mode 100644
index 00000000..c03eeb81
--- /dev/null
+++ b/src/util/convert_comments.go
@@ -0,0 +1,258 @@
+// 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.
+
+package main
+
+import (
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "strings"
+)
+
+// convert_comments.go converts C-style block comments to C++-style line
+// comments. A block comment is converted if all of the following are true:
+//
+// * The comment begins after the first blank line, to leave the license
+// blocks alone.
+//
+// * There are no characters between the '*/' and the end of the line.
+//
+// * Either one of the following are true:
+//
+// - The comment fits on one line.
+//
+// - Each line the comment spans begins with N spaces, followed by '/*' for
+// the initial line or ' *' for subsequent lines, where N is the same for
+// each line.
+//
+// This tool is a heuristic. While it gets almost all cases correct, the final
+// output should still be looked over and fixed up as needed.
+
+// allSpaces returns true if |s| consists entirely of spaces.
+func allSpaces(s string) bool {
+ return strings.IndexFunc(s, func(r rune) bool { return r != ' ' }) == -1
+}
+
+// isContinuation returns true if |s| is a continuation line for a multi-line
+// comment indented to the specified column.
+func isContinuation(s string, column int) bool {
+ if len(s) < column+2 {
+ return false
+ }
+ if !allSpaces(s[:column]) {
+ return false
+ }
+ return s[column:column+2] == " *"
+}
+
+// indexFrom behaves like strings.Index but only reports matches starting at
+// |idx|.
+func indexFrom(s, sep string, idx int) int {
+ ret := strings.Index(s[idx:], sep)
+ if ret < 0 {
+ return -1
+ }
+ return idx + ret
+}
+
+// A lineGroup is a contiguous group of lines with an eligible comment at the
+// same column. Any trailing '*/'s will already be removed.
+type lineGroup struct {
+ // column is the column where the eligible comment begins. line[column]
+ // and line[column+1] will both be replaced with '/'. It is -1 if this
+ // group is not to be converted.
+ column int
+ lines []string
+}
+
+func addLine(groups *[]lineGroup, line string, column int) {
+ if len(*groups) == 0 || (*groups)[len(*groups)-1].column != column {
+ *groups = append(*groups, lineGroup{column, nil})
+ }
+ (*groups)[len(*groups)-1].lines = append((*groups)[len(*groups)-1].lines, line)
+}
+
+// writeLine writes |line| to |out|, followed by a newline.
+func writeLine(out *bytes.Buffer, line string) {
+ out.WriteString(line)
+ out.WriteByte('\n')
+}
+
+func convertComments(path string, in []byte) []byte {
+ lines := strings.Split(string(in), "\n")
+
+ // Account for the trailing newline.
+ if len(lines) > 0 && len(lines[len(lines)-1]) == 0 {
+ lines = lines[:len(lines)-1]
+ }
+
+ // First pass: identify all comments to be converted. Group them into
+ // lineGroups with the same column.
+ var groups []lineGroup
+
+ // Find the license block separator.
+ for len(lines) > 0 {
+ line := lines[0]
+ lines = lines[1:]
+ addLine(&groups, line, -1)
+ if len(line) == 0 {
+ break
+ }
+ }
+
+ // inComment is true if we are in the middle of a comment.
+ var inComment bool
+ // comment is the currently buffered multi-line comment to convert. If
+ // |inComment| is true and it is nil, the current multi-line comment is
+ // not convertable and we copy lines to |out| as-is.
+ var comment []string
+ // column is the column offset of |comment|.
+ var column int
+ for len(lines) > 0 {
+ line := lines[0]
+ lines = lines[1:]
+
+ var idx int
+ if inComment {
+ // Stop buffering if this comment isn't eligible.
+ if comment != nil && !isContinuation(line, column) {
+ for _, l := range comment {
+ addLine(&groups, l, -1)
+ }
+ comment = nil
+ }
+
+ // Look for the end of the current comment.
+ idx = strings.Index(line, "*/")
+ if idx < 0 {
+ if comment != nil {
+ comment = append(comment, line)
+ } else {
+ addLine(&groups, line, -1)
+ }
+ continue
+ }
+
+ inComment = false
+ if comment != nil {
+ if idx == len(line)-2 {
+ // This is a convertable multi-line comment.
+ if idx >= column+2 {
+ // |idx| may be equal to
+ // |column| + 1, if the line is
+ // a '*/' on its own. In that
+ // case, we discard the line.
+ comment = append(comment, line[:idx])
+ }
+ for _, l := range comment {
+ addLine(&groups, l, column)
+ }
+ comment = nil
+ continue
+ }
+
+ // Flush the buffered comment unmodified.
+ for _, l := range comment {
+ addLine(&groups, l, -1)
+ }
+ comment = nil
+ }
+ idx += 2
+ }
+
+ // Parse starting from |idx|, looking for either a convertable
+ // line comment or a multi-line comment.
+ for {
+ idx = indexFrom(line, "/*", idx)
+ if idx < 0 {
+ addLine(&groups, line, -1)
+ break
+ }
+
+ endIdx := indexFrom(line, "*/", idx)
+ if endIdx < 0 {
+ // The comment is, so far, eligible for conversion.
+ inComment = true
+ column = idx
+ comment = []string{line}
+ break
+ }
+
+ if endIdx != len(line)-2 {
+ // Continue parsing for more comments in this line.
+ idx = endIdx + 2
+ continue
+ }
+
+ addLine(&groups, line[:endIdx], idx)
+ break
+ }
+ }
+
+ // Second pass: convert the lineGroups, adjusting spacing as needed.
+ var out bytes.Buffer
+ var lineNo int
+ for _, group := range groups {
+ if group.column < 0 {
+ for _, line := range group.lines {
+ writeLine(&out, line)
+ }
+ } else {
+ // Google C++ style prefers two spaces before a comment
+ // if it is on the same line as code, but clang-format
+ // has been placing one space for block comments. All
+ // comments within a group should be adjusted by the
+ // same amount.
+ var adjust string
+ for _, line := range group.lines {
+ if !allSpaces(line[:group.column]) && line[group.column-1] != '(' {
+ if line[group.column-1] != ' ' {
+ if len(adjust) < 2 {
+ adjust = " "
+ }
+ } else if line[group.column-2] != ' ' {
+ if len(adjust) < 1 {
+ adjust = " "
+ }
+ }
+ }
+ }
+
+ for i, line := range group.lines {
+ newLine := fmt.Sprintf("%s%s//%s", line[:group.column], adjust, strings.TrimRight(line[group.column+2:], " "))
+ if len(newLine) > 80 {
+ fmt.Fprintf(os.Stderr, "%s:%d: Line is now longer than 80 characters\n", path, lineNo+i+1)
+ }
+ writeLine(&out, newLine)
+ }
+
+ }
+ lineNo += len(group.lines)
+ }
+ return out.Bytes()
+}
+
+func main() {
+ for _, arg := range os.Args[1:] {
+ in, err := ioutil.ReadFile(arg)
+ if err != nil {
+ panic(err)
+ }
+ if err := ioutil.WriteFile(arg, convertComments(arg, in), 0666); err != nil {
+ panic(err)
+ }
+ }
+}
diff --git a/src/util/doc.go b/src/util/doc.go
index 987794c9..2d5a297f 100644
--- a/src/util/doc.go
+++ b/src/util/doc.go
@@ -74,8 +74,13 @@ const (
cppGuard = "#if defined(__cplusplus)"
commentStart = "/* "
commentEnd = " */"
+ lineComment = "// "
)
+func isComment(line string) bool {
+ return strings.HasPrefix(line, commentStart) || strings.HasPrefix(line, lineComment)
+}
+
func extractComment(lines []string, lineNo int) (comment []string, rest []string, restLineNo int, err error) {
if len(lines) == 0 {
return nil, lines, lineNo, nil
@@ -84,7 +89,10 @@ func extractComment(lines []string, lineNo int) (comment []string, rest []string
restLineNo = lineNo
rest = lines
- if !strings.HasPrefix(rest[0], commentStart) {
+ var isBlock bool
+ if strings.HasPrefix(rest[0], commentStart) {
+ isBlock = true
+ } else if !strings.HasPrefix(rest[0], lineComment) {
panic("extractComment called on non-comment")
}
commentParagraph := rest[0][len(commentStart):]
@@ -92,25 +100,34 @@ func extractComment(lines []string, lineNo int) (comment []string, rest []string
restLineNo++
for len(rest) > 0 {
- i := strings.Index(commentParagraph, commentEnd)
- if i >= 0 {
- if i != len(commentParagraph)-len(commentEnd) {
- err = fmt.Errorf("garbage after comment end on line %d", restLineNo)
+ if isBlock {
+ i := strings.Index(commentParagraph, commentEnd)
+ if i >= 0 {
+ if i != len(commentParagraph)-len(commentEnd) {
+ err = fmt.Errorf("garbage after comment end on line %d", restLineNo)
+ return
+ }
+ commentParagraph = commentParagraph[:i]
+ if len(commentParagraph) > 0 {
+ comment = append(comment, commentParagraph)
+ }
return
}
- commentParagraph = commentParagraph[:i]
- if len(commentParagraph) > 0 {
- comment = append(comment, commentParagraph)
- }
- return
}
line := rest[0]
- if !strings.HasPrefix(line, " *") {
- err = fmt.Errorf("comment doesn't start with block prefix on line %d: %s", restLineNo, line)
+ if isBlock {
+ if !strings.HasPrefix(line, " *") {
+ err = fmt.Errorf("comment doesn't start with block prefix on line %d: %s", restLineNo, line)
+ return
+ }
+ } else if !strings.HasPrefix(line, "//") {
+ if len(commentParagraph) > 0 {
+ comment = append(comment, commentParagraph)
+ }
return
}
- if len(line) == 2 || line[2] != '/' {
+ if len(line) == 2 || !isBlock || line[2] != '/' {
line = line[2:]
}
if strings.HasPrefix(line, " ") {
@@ -309,7 +326,7 @@ func (config *Config) parseHeader(path string) (*HeaderFile, error) {
}
oldLines = lines
- if len(lines) > 0 && strings.HasPrefix(lines[0], commentStart) {
+ if len(lines) > 0 && isComment(lines[0]) {
comment, rest, restLineNo, err := extractComment(lines, lineNo)
if err != nil {
return nil, err
@@ -345,7 +362,7 @@ func (config *Config) parseHeader(path string) (*HeaderFile, error) {
var section HeaderSection
- if strings.HasPrefix(line, commentStart) {
+ if isComment(line) {
comment, rest, restLineNo, err := extractComment(lines, lineNo)
if err != nil {
return nil, err
@@ -380,7 +397,7 @@ func (config *Config) parseHeader(path string) (*HeaderFile, error) {
var comment []string
var decl string
- if strings.HasPrefix(line, commentStart) {
+ if isComment(line) {
comment, lines, lineNo, err = extractComment(lines, lineNo)
if err != nil {
return nil, err
@@ -459,7 +476,13 @@ func firstSentence(paragraphs []string) string {
return s
}
+// markupPipeWords converts |s| into an HTML string, safe to be included outside
+// a tag, while also marking up words surrounded by |.
func markupPipeWords(allDecls map[string]string, s string) template.HTML {
+ // It is safe to look for '|' in the HTML-escaped version of |s|
+ // below. The escaped version cannot include '|' instead tags because
+ // there are no tags by construction.
+ s = template.HTMLEscapeString(s)
ret := ""
for {
@@ -549,12 +572,12 @@ func generate(outPath string, config *Config) (map[string]string, error) {
<a href="headers.html">All headers</a>
</div>
- {{range .Preamble}}<p>{{. | html | markupPipeWords}}</p>{{end}}
+ {{range .Preamble}}<p>{{. | markupPipeWords}}</p>{{end}}
<ol>
{{range .Sections}}
{{if not .IsPrivate}}
- {{if .Anchor}}<li class="header"><a href="#{{.Anchor}}">{{.Preamble | firstSentence | html | markupPipeWords}}</a></li>{{end}}
+ {{if .Anchor}}<li class="header"><a href="#{{.Anchor}}">{{.Preamble | firstSentence | markupPipeWords}}</a></li>{{end}}
{{range .Decls}}
{{if .Anchor}}<li><a href="#{{.Anchor}}"><tt>{{.Name}}</tt></a></li>{{end}}
{{end}}
@@ -567,14 +590,14 @@ func generate(outPath string, config *Config) (map[string]string, error) {
<div class="section" {{if .Anchor}}id="{{.Anchor}}"{{end}}>
{{if .Preamble}}
<div class="sectionpreamble">
- {{range .Preamble}}<p>{{. | html | markupPipeWords}}</p>{{end}}
+ {{range .Preamble}}<p>{{. | markupPipeWords}}</p>{{end}}
</div>
{{end}}
{{range .Decls}}
<div class="decl" {{if .Anchor}}id="{{.Anchor}}"{{end}}>
{{range .Comment}}
- <p>{{. | html | markupPipeWords | newlinesToBR | markupFirstWord}}</p>
+ <p>{{. | markupPipeWords | newlinesToBR | markupFirstWord}}</p>
{{end}}
<pre>{{.Decl}}</pre>
</div>
diff --git a/src/util/generate_build_files.py b/src/util/generate_build_files.py
index ef340e64..4feb4df8 100644
--- a/src/util/generate_build_files.py
+++ b/src/util/generate_build_files.py
@@ -229,7 +229,7 @@ class Bazel(object):
continue
out.write(' "%s",\n' % PathOf(filename))
- out.write(']\n\n')
+ out.write(']\n')
self.PrintVariableSection(out, 'crypto_test_sources',
files['crypto_test'])