aboutsummaryrefslogtreecommitdiffstats
path: root/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl
diff options
context:
space:
mode:
authorAngelos Mouzakitis <a.mouzakitis@virtualopensystems.com>2023-10-10 14:33:42 +0000
committerAngelos Mouzakitis <a.mouzakitis@virtualopensystems.com>2023-10-10 14:33:42 +0000
commitaf1a266670d040d2f4083ff309d732d648afba2a (patch)
tree2fc46203448ddcc6f81546d379abfaeb323575e9 /roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl
parente02cda008591317b1625707ff8e115a4841aa889 (diff)
Add submodule dependency filesHEADmaster
Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
Diffstat (limited to 'roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl')
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/CMakeLists.txt55
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/bio_ssl.c175
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/custom_extensions.c258
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/d1_both.c814
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/d1_lib.c266
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/d1_pkt.c414
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/d1_srtp.c236
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/dtls_method.c217
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/dtls_record.c334
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/handshake_client.c1909
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/handshake_server.c1953
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/internal.h2231
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/s3_both.c821
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/s3_lib.c220
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/s3_pkt.c489
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_aead_ctx.c336
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_asn1.c824
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_buffer.c312
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_cert.c899
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_cipher.c1867
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_ecdh.c465
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_file.c575
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_lib.c2709
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_privkey.c678
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_privkey_cc.cc76
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_session.c1147
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_stat.c443
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_test.cc3531
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_transcript.c405
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_x509.c1344
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/t1_enc.c561
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/t1_lib.c3562
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/CMakeLists.txt14
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/PORTING.md109
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/README.md38
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/async_bio.cc191
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/async_bio.h43
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/bssl_shim.cc2137
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/packeted_bio.cc265
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/packeted_bio.h43
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/alert.go93
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/cert.pem22
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/chacha20_poly1305.go194
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/chacha20_poly1305_test.go144
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/channel_id_key.pem5
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/cipher_suites.go515
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/common.go1681
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/conn.go1843
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/curve25519/curve25519.go841
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/curve25519/curve25519_test.go29
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/curve25519/doc.go23
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/curve25519/mont25519_amd64.go240
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/deterministic.go37
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/dtls.go499
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/ecdsa_p224_cert.pem12
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/ecdsa_p224_key.pem5
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/ecdsa_p256_cert.pem12
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/ecdsa_p256_key.pem5
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/ecdsa_p384_cert.pem15
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/ecdsa_p384_key.pem6
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/ecdsa_p521_cert.pem17
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/ecdsa_p521_key.pem7
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/fuzzer_mode.json39
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/handshake_client.go1758
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/handshake_messages.go2369
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/handshake_server.go1975
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/hkdf.go57
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/hkdf_test.go101
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/key.pem28
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/key_agreement.go853
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/packet_adapter.go179
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/poly1305/poly1305.go32
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/poly1305/poly1305_test.go86
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/poly1305/sum_amd64.go24
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/poly1305/sum_arm.go24
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/poly1305/sum_ref.go1531
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/prf.go478
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/recordingconn.go167
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/rsa_1024_cert.pem15
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/rsa_1024_key.pem16
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/rsa_chain_cert.pem35
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/rsa_chain_key.pem28
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/runner.go10468
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/runner_test.go21
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/shim_ticket.go249
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/sign.go297
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/test_output.go79
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/ticket.go197
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/tls.go279
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/test_config.cc264
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/test_config.h142
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/tls13_both.c638
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/tls13_client.c686
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/tls13_enc.c430
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/tls13_server.c753
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/tls_method.c328
-rw-r--r--roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/tls_record.c505
97 files changed, 64342 insertions, 0 deletions
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/CMakeLists.txt b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/CMakeLists.txt
new file mode 100644
index 000000000..5b5ea976e
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/CMakeLists.txt
@@ -0,0 +1,55 @@
+include_directories(../include)
+
+add_library(
+ ssl
+
+ bio_ssl.c
+ custom_extensions.c
+ d1_both.c
+ d1_lib.c
+ d1_pkt.c
+ d1_srtp.c
+ dtls_method.c
+ dtls_record.c
+ handshake_client.c
+ handshake_server.c
+ s3_both.c
+ s3_lib.c
+ s3_pkt.c
+ ssl_aead_ctx.c
+ ssl_asn1.c
+ ssl_buffer.c
+ ssl_cert.c
+ ssl_cipher.c
+ ssl_ecdh.c
+ ssl_file.c
+ ssl_lib.c
+ ssl_privkey.c
+ ssl_privkey_cc.cc
+ ssl_session.c
+ ssl_stat.c
+ ssl_transcript.c
+ ssl_x509.c
+ t1_enc.c
+ t1_lib.c
+ tls_method.c
+ tls_record.c
+ tls13_both.c
+ tls13_client.c
+ tls13_enc.c
+ tls13_server.c
+)
+
+target_link_libraries(ssl crypto)
+
+add_executable(
+ ssl_test
+
+ ssl_test.cc
+
+ $<TARGET_OBJECTS:gtest_main>
+ $<TARGET_OBJECTS:test_support>
+)
+
+target_link_libraries(ssl_test ssl crypto gtest)
+add_dependencies(all_tests ssl_test)
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/bio_ssl.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/bio_ssl.c
new file mode 100644
index 000000000..ad8f5d8ff
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/bio_ssl.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright 1995-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
+ */
+
+#include <openssl/ssl.h>
+
+#include <openssl/bio.h>
+
+
+static int ssl_read(BIO *bio, char *out, int outl) {
+ SSL *ssl = bio->ptr;
+ if (ssl == NULL) {
+ return 0;
+ }
+
+ BIO_clear_retry_flags(bio);
+
+ const int ret = SSL_read(ssl, out, outl);
+
+ switch (SSL_get_error(ssl, ret)) {
+ case SSL_ERROR_WANT_READ:
+ BIO_set_retry_read(bio);
+ break;
+
+ case SSL_ERROR_WANT_WRITE:
+ BIO_set_retry_write(bio);
+ break;
+
+ case SSL_ERROR_WANT_ACCEPT:
+ BIO_set_retry_special(bio);
+ bio->retry_reason = BIO_RR_ACCEPT;
+ break;
+
+ case SSL_ERROR_WANT_CONNECT:
+ BIO_set_retry_special(bio);
+ bio->retry_reason = BIO_RR_CONNECT;
+ break;
+
+ case SSL_ERROR_NONE:
+ case SSL_ERROR_SYSCALL:
+ case SSL_ERROR_SSL:
+ case SSL_ERROR_ZERO_RETURN:
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+static int ssl_write(BIO *bio, const char *out, int outl) {
+ SSL *ssl = bio->ptr;
+ if (ssl == NULL) {
+ return 0;
+ }
+
+ BIO_clear_retry_flags(bio);
+
+ const int ret = SSL_write(ssl, out, outl);
+
+ switch (SSL_get_error(ssl, ret)) {
+ case SSL_ERROR_WANT_WRITE:
+ BIO_set_retry_write(bio);
+ break;
+
+ case SSL_ERROR_WANT_READ:
+ BIO_set_retry_read(bio);
+ break;
+
+ case SSL_ERROR_WANT_CONNECT:
+ BIO_set_retry_special(bio);
+ bio->retry_reason = BIO_RR_CONNECT;
+ break;
+
+ case SSL_ERROR_NONE:
+ case SSL_ERROR_SYSCALL:
+ case SSL_ERROR_SSL:
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+static long ssl_ctrl(BIO *bio, int cmd, long num, void *ptr) {
+ SSL *ssl = bio->ptr;
+ if (ssl == NULL && cmd != BIO_C_SET_SSL) {
+ return 0;
+ }
+
+ switch (cmd) {
+ case BIO_C_SET_SSL:
+ bio->shutdown = num;
+ bio->ptr = ptr;
+ bio->init = 1;
+ return 1;
+
+ case BIO_CTRL_GET_CLOSE:
+ return bio->shutdown;
+
+ case BIO_CTRL_SET_CLOSE:
+ bio->shutdown = num;
+ return 1;
+
+ case BIO_CTRL_WPENDING:
+ return BIO_ctrl(SSL_get_wbio(ssl), cmd, num, ptr);
+
+ case BIO_CTRL_PENDING:
+ return SSL_pending(ssl);
+
+ case BIO_CTRL_FLUSH: {
+ BIO_clear_retry_flags(bio);
+ long ret = BIO_ctrl(SSL_get_wbio(ssl), cmd, num, ptr);
+ BIO_copy_next_retry(bio);
+ return ret;
+ }
+
+ case BIO_CTRL_PUSH:
+ case BIO_CTRL_POP:
+ case BIO_CTRL_DUP:
+ return -1;
+
+ default:
+ return BIO_ctrl(SSL_get_rbio(ssl), cmd, num, ptr);
+ }
+}
+
+static int ssl_new(BIO *bio) {
+ return 1;
+}
+
+static int ssl_free(BIO *bio) {
+ SSL *ssl = bio->ptr;
+
+ if (ssl == NULL) {
+ return 1;
+ }
+
+ SSL_shutdown(ssl);
+ if (bio->shutdown) {
+ SSL_free(ssl);
+ }
+
+ return 1;
+}
+
+static long ssl_callback_ctrl(BIO *bio, int cmd, bio_info_cb fp) {
+ SSL *ssl = bio->ptr;
+ if (ssl == NULL) {
+ return 0;
+ }
+
+ switch (cmd) {
+ case BIO_CTRL_SET_CALLBACK:
+ return -1;
+
+ default:
+ return BIO_callback_ctrl(SSL_get_rbio(ssl), cmd, fp);
+ }
+}
+
+static const BIO_METHOD ssl_method = {
+ BIO_TYPE_SSL, "SSL", ssl_write, ssl_read, NULL,
+ NULL, ssl_ctrl, ssl_new, ssl_free, ssl_callback_ctrl,
+};
+
+const BIO_METHOD *BIO_f_ssl(void) { return &ssl_method; }
+
+long BIO_set_ssl(BIO *bio, SSL *ssl, int take_owership) {
+ return BIO_ctrl(bio, BIO_C_SET_SSL, take_owership, ssl);
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/custom_extensions.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/custom_extensions.c
new file mode 100644
index 000000000..10fbfc8f0
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/custom_extensions.c
@@ -0,0 +1,258 @@
+/* Copyright (c) 2014, 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 <openssl/ssl.h>
+
+#include <assert.h>
+#include <string.h>
+
+#include <openssl/bytestring.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/stack.h>
+
+#include "internal.h"
+
+
+void SSL_CUSTOM_EXTENSION_free(SSL_CUSTOM_EXTENSION *custom_extension) {
+ OPENSSL_free(custom_extension);
+}
+
+static const SSL_CUSTOM_EXTENSION *custom_ext_find(
+ STACK_OF(SSL_CUSTOM_EXTENSION) *stack,
+ unsigned *out_index, uint16_t value) {
+ for (size_t i = 0; i < sk_SSL_CUSTOM_EXTENSION_num(stack); i++) {
+ const SSL_CUSTOM_EXTENSION *ext = sk_SSL_CUSTOM_EXTENSION_value(stack, i);
+ if (ext->value == value) {
+ if (out_index != NULL) {
+ *out_index = i;
+ }
+ return ext;
+ }
+ }
+
+ return NULL;
+}
+
+/* default_add_callback is used as the |add_callback| when the user doesn't
+ * provide one. For servers, it does nothing while, for clients, it causes an
+ * empty extension to be included. */
+static int default_add_callback(SSL *ssl, unsigned extension_value,
+ const uint8_t **out, size_t *out_len,
+ int *out_alert_value, void *add_arg) {
+ if (ssl->server) {
+ return 0;
+ }
+ *out_len = 0;
+ return 1;
+}
+
+static int custom_ext_add_hello(SSL_HANDSHAKE *hs, CBB *extensions) {
+ SSL *const ssl = hs->ssl;
+ STACK_OF(SSL_CUSTOM_EXTENSION) *stack = ssl->ctx->client_custom_extensions;
+ if (ssl->server) {
+ stack = ssl->ctx->server_custom_extensions;
+ }
+
+ if (stack == NULL) {
+ return 1;
+ }
+
+ for (size_t i = 0; i < sk_SSL_CUSTOM_EXTENSION_num(stack); i++) {
+ const SSL_CUSTOM_EXTENSION *ext = sk_SSL_CUSTOM_EXTENSION_value(stack, i);
+
+ if (ssl->server &&
+ !(hs->custom_extensions.received & (1u << i))) {
+ /* Servers cannot echo extensions that the client didn't send. */
+ continue;
+ }
+
+ const uint8_t *contents;
+ size_t contents_len;
+ int alert = SSL_AD_DECODE_ERROR;
+ CBB contents_cbb;
+
+ switch (ext->add_callback(ssl, ext->value, &contents, &contents_len, &alert,
+ ext->add_arg)) {
+ case 1:
+ if (!CBB_add_u16(extensions, ext->value) ||
+ !CBB_add_u16_length_prefixed(extensions, &contents_cbb) ||
+ !CBB_add_bytes(&contents_cbb, contents, contents_len) ||
+ !CBB_flush(extensions)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ ERR_add_error_dataf("extension %u", (unsigned) ext->value);
+ if (ext->free_callback && 0 < contents_len) {
+ ext->free_callback(ssl, ext->value, contents, ext->add_arg);
+ }
+ return 0;
+ }
+
+ if (ext->free_callback && 0 < contents_len) {
+ ext->free_callback(ssl, ext->value, contents, ext->add_arg);
+ }
+
+ if (!ssl->server) {
+ assert((hs->custom_extensions.sent & (1u << i)) == 0);
+ hs->custom_extensions.sent |= (1u << i);
+ }
+ break;
+
+ case 0:
+ break;
+
+ default:
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CUSTOM_EXTENSION_ERROR);
+ ERR_add_error_dataf("extension %u", (unsigned) ext->value);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+int custom_ext_add_clienthello(SSL_HANDSHAKE *hs, CBB *extensions) {
+ return custom_ext_add_hello(hs, extensions);
+}
+
+int custom_ext_parse_serverhello(SSL_HANDSHAKE *hs, int *out_alert,
+ uint16_t value, const CBS *extension) {
+ SSL *const ssl = hs->ssl;
+ unsigned index;
+ const SSL_CUSTOM_EXTENSION *ext =
+ custom_ext_find(ssl->ctx->client_custom_extensions, &index, value);
+
+ if (/* Unknown extensions are not allowed in a ServerHello. */
+ ext == NULL ||
+ /* Also, if we didn't send the extension, that's also unacceptable. */
+ !(hs->custom_extensions.sent & (1u << index))) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
+ ERR_add_error_dataf("extension %u", (unsigned)value);
+ *out_alert = SSL_AD_UNSUPPORTED_EXTENSION;
+ return 0;
+ }
+
+ if (ext->parse_callback != NULL &&
+ !ext->parse_callback(ssl, value, CBS_data(extension), CBS_len(extension),
+ out_alert, ext->parse_arg)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CUSTOM_EXTENSION_ERROR);
+ ERR_add_error_dataf("extension %u", (unsigned)ext->value);
+ return 0;
+ }
+
+ return 1;
+}
+
+int custom_ext_parse_clienthello(SSL_HANDSHAKE *hs, int *out_alert,
+ uint16_t value, const CBS *extension) {
+ SSL *const ssl = hs->ssl;
+ unsigned index;
+ const SSL_CUSTOM_EXTENSION *ext =
+ custom_ext_find(ssl->ctx->server_custom_extensions, &index, value);
+
+ if (ext == NULL) {
+ return 1;
+ }
+
+ assert((hs->custom_extensions.received & (1u << index)) == 0);
+ hs->custom_extensions.received |= (1u << index);
+
+ if (ext->parse_callback &&
+ !ext->parse_callback(ssl, value, CBS_data(extension), CBS_len(extension),
+ out_alert, ext->parse_arg)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CUSTOM_EXTENSION_ERROR);
+ ERR_add_error_dataf("extension %u", (unsigned)ext->value);
+ return 0;
+ }
+
+ return 1;
+}
+
+int custom_ext_add_serverhello(SSL_HANDSHAKE *hs, CBB *extensions) {
+ return custom_ext_add_hello(hs, extensions);
+}
+
+/* MAX_NUM_CUSTOM_EXTENSIONS is the maximum number of custom extensions that
+ * can be set on an |SSL_CTX|. It's determined by the size of the bitset used
+ * to track when an extension has been sent. */
+#define MAX_NUM_CUSTOM_EXTENSIONS \
+ (sizeof(((SSL_HANDSHAKE *)NULL)->custom_extensions.sent) * 8)
+
+static int custom_ext_append(STACK_OF(SSL_CUSTOM_EXTENSION) **stack,
+ unsigned extension_value,
+ SSL_custom_ext_add_cb add_cb,
+ SSL_custom_ext_free_cb free_cb, void *add_arg,
+ SSL_custom_ext_parse_cb parse_cb,
+ void *parse_arg) {
+ if (add_cb == NULL ||
+ 0xffff < extension_value ||
+ SSL_extension_supported(extension_value) ||
+ /* Specifying a free callback without an add callback is nonsensical
+ * and an error. */
+ (*stack != NULL &&
+ (MAX_NUM_CUSTOM_EXTENSIONS <= sk_SSL_CUSTOM_EXTENSION_num(*stack) ||
+ custom_ext_find(*stack, NULL, extension_value) != NULL))) {
+ return 0;
+ }
+
+ SSL_CUSTOM_EXTENSION *ext = OPENSSL_malloc(sizeof(SSL_CUSTOM_EXTENSION));
+ if (ext == NULL) {
+ return 0;
+ }
+ ext->add_callback = add_cb;
+ ext->add_arg = add_arg;
+ ext->free_callback = free_cb;
+ ext->parse_callback = parse_cb;
+ ext->parse_arg = parse_arg;
+ ext->value = extension_value;
+
+ if (*stack == NULL) {
+ *stack = sk_SSL_CUSTOM_EXTENSION_new_null();
+ if (*stack == NULL) {
+ SSL_CUSTOM_EXTENSION_free(ext);
+ return 0;
+ }
+ }
+
+ if (!sk_SSL_CUSTOM_EXTENSION_push(*stack, ext)) {
+ SSL_CUSTOM_EXTENSION_free(ext);
+ if (sk_SSL_CUSTOM_EXTENSION_num(*stack) == 0) {
+ sk_SSL_CUSTOM_EXTENSION_free(*stack);
+ *stack = NULL;
+ }
+ return 0;
+ }
+
+ return 1;
+}
+
+int SSL_CTX_add_client_custom_ext(SSL_CTX *ctx, unsigned extension_value,
+ SSL_custom_ext_add_cb add_cb,
+ SSL_custom_ext_free_cb free_cb, void *add_arg,
+ SSL_custom_ext_parse_cb parse_cb,
+ void *parse_arg) {
+ return custom_ext_append(&ctx->client_custom_extensions, extension_value,
+ add_cb ? add_cb : default_add_callback, free_cb,
+ add_arg, parse_cb, parse_arg);
+}
+
+int SSL_CTX_add_server_custom_ext(SSL_CTX *ctx, unsigned extension_value,
+ SSL_custom_ext_add_cb add_cb,
+ SSL_custom_ext_free_cb free_cb, void *add_arg,
+ SSL_custom_ext_parse_cb parse_cb,
+ void *parse_arg) {
+ return custom_ext_append(&ctx->server_custom_extensions, extension_value,
+ add_cb ? add_cb : default_add_callback, free_cb,
+ add_arg, parse_cb, parse_arg);
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/d1_both.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/d1_both.c
new file mode 100644
index 000000000..44e3f2ef6
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/d1_both.c
@@ -0,0 +1,814 @@
+/*
+ * DTLS implementation written by Nagendra Modadugu
+ * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2005 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#include <openssl/ssl.h>
+
+#include <assert.h>
+#include <limits.h>
+#include <string.h>
+
+#include <openssl/buf.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/mem.h>
+#include <openssl/rand.h>
+#include <openssl/type_check.h>
+
+#include "../crypto/internal.h"
+#include "internal.h"
+
+
+/* TODO(davidben): 28 comes from the size of IP + UDP header. Is this reasonable
+ * for these values? Notably, why is kMinMTU a function of the transport
+ * protocol's overhead rather than, say, what's needed to hold a minimally-sized
+ * handshake fragment plus protocol overhead. */
+
+/* kMinMTU is the minimum acceptable MTU value. */
+static const unsigned int kMinMTU = 256 - 28;
+
+/* kDefaultMTU is the default MTU value to use if neither the user nor
+ * the underlying BIO supplies one. */
+static const unsigned int kDefaultMTU = 1500 - 28;
+
+
+/* Receiving handshake messages. */
+
+static void dtls1_hm_fragment_free(hm_fragment *frag) {
+ if (frag == NULL) {
+ return;
+ }
+ OPENSSL_free(frag->data);
+ OPENSSL_free(frag->reassembly);
+ OPENSSL_free(frag);
+}
+
+static hm_fragment *dtls1_hm_fragment_new(const struct hm_header_st *msg_hdr) {
+ hm_fragment *frag = OPENSSL_malloc(sizeof(hm_fragment));
+ if (frag == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ OPENSSL_memset(frag, 0, sizeof(hm_fragment));
+ frag->type = msg_hdr->type;
+ frag->seq = msg_hdr->seq;
+ frag->msg_len = msg_hdr->msg_len;
+
+ /* Allocate space for the reassembled message and fill in the header. */
+ frag->data = OPENSSL_malloc(DTLS1_HM_HEADER_LENGTH + msg_hdr->msg_len);
+ if (frag->data == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ CBB cbb;
+ if (!CBB_init_fixed(&cbb, frag->data, DTLS1_HM_HEADER_LENGTH) ||
+ !CBB_add_u8(&cbb, msg_hdr->type) ||
+ !CBB_add_u24(&cbb, msg_hdr->msg_len) ||
+ !CBB_add_u16(&cbb, msg_hdr->seq) ||
+ !CBB_add_u24(&cbb, 0 /* frag_off */) ||
+ !CBB_add_u24(&cbb, msg_hdr->msg_len) ||
+ !CBB_finish(&cbb, NULL, NULL)) {
+ CBB_cleanup(&cbb);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ /* If the handshake message is empty, |frag->reassembly| is NULL. */
+ if (msg_hdr->msg_len > 0) {
+ /* Initialize reassembly bitmask. */
+ if (msg_hdr->msg_len + 7 < msg_hdr->msg_len) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
+ goto err;
+ }
+ size_t bitmask_len = (msg_hdr->msg_len + 7) / 8;
+ frag->reassembly = OPENSSL_malloc(bitmask_len);
+ if (frag->reassembly == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ OPENSSL_memset(frag->reassembly, 0, bitmask_len);
+ }
+
+ return frag;
+
+err:
+ dtls1_hm_fragment_free(frag);
+ return NULL;
+}
+
+/* bit_range returns a |uint8_t| with bits |start|, inclusive, to |end|,
+ * exclusive, set. */
+static uint8_t bit_range(size_t start, size_t end) {
+ return (uint8_t)(~((1u << start) - 1) & ((1u << end) - 1));
+}
+
+/* dtls1_hm_fragment_mark marks bytes |start|, inclusive, to |end|, exclusive,
+ * as received in |frag|. If |frag| becomes complete, it clears
+ * |frag->reassembly|. The range must be within the bounds of |frag|'s message
+ * and |frag->reassembly| must not be NULL. */
+static void dtls1_hm_fragment_mark(hm_fragment *frag, size_t start,
+ size_t end) {
+ size_t msg_len = frag->msg_len;
+
+ if (frag->reassembly == NULL || start > end || end > msg_len) {
+ assert(0);
+ return;
+ }
+ /* A zero-length message will never have a pending reassembly. */
+ assert(msg_len > 0);
+
+ if ((start >> 3) == (end >> 3)) {
+ frag->reassembly[start >> 3] |= bit_range(start & 7, end & 7);
+ } else {
+ frag->reassembly[start >> 3] |= bit_range(start & 7, 8);
+ for (size_t i = (start >> 3) + 1; i < (end >> 3); i++) {
+ frag->reassembly[i] = 0xff;
+ }
+ if ((end & 7) != 0) {
+ frag->reassembly[end >> 3] |= bit_range(0, end & 7);
+ }
+ }
+
+ /* Check if the fragment is complete. */
+ for (size_t i = 0; i < (msg_len >> 3); i++) {
+ if (frag->reassembly[i] != 0xff) {
+ return;
+ }
+ }
+ if ((msg_len & 7) != 0 &&
+ frag->reassembly[msg_len >> 3] != bit_range(0, msg_len & 7)) {
+ return;
+ }
+
+ OPENSSL_free(frag->reassembly);
+ frag->reassembly = NULL;
+}
+
+/* dtls1_is_current_message_complete returns one if the current handshake
+ * message is complete and zero otherwise. */
+static int dtls1_is_current_message_complete(const SSL *ssl) {
+ hm_fragment *frag = ssl->d1->incoming_messages[ssl->d1->handshake_read_seq %
+ SSL_MAX_HANDSHAKE_FLIGHT];
+ return frag != NULL && frag->reassembly == NULL;
+}
+
+/* dtls1_get_incoming_message returns the incoming message corresponding to
+ * |msg_hdr|. If none exists, it creates a new one and inserts it in the
+ * queue. Otherwise, it checks |msg_hdr| is consistent with the existing one. It
+ * returns NULL on failure. The caller does not take ownership of the result. */
+static hm_fragment *dtls1_get_incoming_message(
+ SSL *ssl, const struct hm_header_st *msg_hdr) {
+ if (msg_hdr->seq < ssl->d1->handshake_read_seq ||
+ msg_hdr->seq - ssl->d1->handshake_read_seq >= SSL_MAX_HANDSHAKE_FLIGHT) {
+ return NULL;
+ }
+
+ size_t idx = msg_hdr->seq % SSL_MAX_HANDSHAKE_FLIGHT;
+ hm_fragment *frag = ssl->d1->incoming_messages[idx];
+ if (frag != NULL) {
+ assert(frag->seq == msg_hdr->seq);
+ /* The new fragment must be compatible with the previous fragments from this
+ * message. */
+ if (frag->type != msg_hdr->type ||
+ frag->msg_len != msg_hdr->msg_len) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_FRAGMENT_MISMATCH);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+ return NULL;
+ }
+ return frag;
+ }
+
+ /* This is the first fragment from this message. */
+ frag = dtls1_hm_fragment_new(msg_hdr);
+ if (frag == NULL) {
+ return NULL;
+ }
+ ssl->d1->incoming_messages[idx] = frag;
+ 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. */
+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) {
+ return ret;
+ }
+ }
+
+ /* 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 != NULL) ||
+ (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC &&
+ ssl->s3->aead_read_ctx == NULL)) {
+ rr->length = 0;
+ goto start;
+ }
+
+ 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;
+ }
+
+ CBS cbs;
+ CBS_init(&cbs, rr->data, rr->length);
+
+ while (CBS_len(&cbs) > 0) {
+ /* Read a handshake fragment. */
+ struct hm_header_st msg_hdr;
+ CBS body;
+ if (!dtls1_parse_fragment(&cbs, &msg_hdr, &body)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_HANDSHAKE_RECORD);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ return -1;
+ }
+
+ const size_t frag_off = msg_hdr.frag_off;
+ const size_t frag_len = msg_hdr.frag_len;
+ const size_t msg_len = msg_hdr.msg_len;
+ if (frag_off > msg_len || frag_off + frag_len < frag_off ||
+ frag_off + frag_len > msg_len ||
+ msg_len > ssl_max_handshake_message_len(ssl)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_EXCESSIVE_MESSAGE_SIZE);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+ return -1;
+ }
+
+ /* The encrypted epoch in DTLS has only one handshake message. */
+ if (ssl->d1->r_epoch == 1 && msg_hdr.seq != ssl->d1->handshake_read_seq) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ if (msg_hdr.seq < ssl->d1->handshake_read_seq ||
+ msg_hdr.seq >
+ (unsigned)ssl->d1->handshake_read_seq + SSL_MAX_HANDSHAKE_FLIGHT) {
+ /* Ignore fragments from the past, or ones too far in the future. */
+ continue;
+ }
+
+ hm_fragment *frag = dtls1_get_incoming_message(ssl, &msg_hdr);
+ if (frag == NULL) {
+ return -1;
+ }
+ assert(frag->msg_len == msg_len);
+
+ if (frag->reassembly == NULL) {
+ /* The message is already assembled. */
+ continue;
+ }
+ assert(msg_len > 0);
+
+ /* Copy the body into the fragment. */
+ OPENSSL_memcpy(frag->data + DTLS1_HM_HEADER_LENGTH + frag_off,
+ CBS_data(&body), CBS_len(&body));
+ dtls1_hm_fragment_mark(frag, frag_off, frag_off + frag_len);
+ }
+
+ rr->length = 0;
+ ssl_read_buffer_discard(ssl);
+ return 1;
+}
+
+int dtls1_get_message(SSL *ssl) {
+ if (ssl->s3->tmp.reuse_message) {
+ /* There must be a current message. */
+ assert(ssl->init_msg != NULL);
+ ssl->s3->tmp.reuse_message = 0;
+ } else {
+ dtls1_release_current_message(ssl, 0 /* don't free buffer */);
+ }
+
+ /* Process handshake records until the current message is ready. */
+ while (!dtls1_is_current_message_complete(ssl)) {
+ int ret = dtls1_process_handshake_record(ssl);
+ if (ret <= 0) {
+ return ret;
+ }
+ }
+
+ hm_fragment *frag = ssl->d1->incoming_messages[ssl->d1->handshake_read_seq %
+ SSL_MAX_HANDSHAKE_FLIGHT];
+ assert(frag != NULL);
+ assert(frag->reassembly == NULL);
+ assert(ssl->d1->handshake_read_seq == frag->seq);
+
+ /* 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;
+}
+
+void dtls1_get_current_message(const SSL *ssl, CBS *out) {
+ assert(dtls1_is_current_message_complete(ssl));
+
+ hm_fragment *frag = ssl->d1->incoming_messages[ssl->d1->handshake_read_seq %
+ SSL_MAX_HANDSHAKE_FLIGHT];
+ CBS_init(out, frag->data, DTLS1_HM_HEADER_LENGTH + frag->msg_len);
+}
+
+void dtls1_release_current_message(SSL *ssl, int free_buffer) {
+ if (ssl->init_msg == NULL) {
+ return;
+ }
+
+ assert(dtls1_is_current_message_complete(ssl));
+ size_t index = ssl->d1->handshake_read_seq % SSL_MAX_HANDSHAKE_FLIGHT;
+ dtls1_hm_fragment_free(ssl->d1->incoming_messages[index]);
+ ssl->d1->incoming_messages[index] = NULL;
+ ssl->d1->handshake_read_seq++;
+
+ ssl->init_msg = NULL;
+ ssl->init_num = 0;
+}
+
+void dtls_clear_incoming_messages(SSL *ssl) {
+ for (size_t i = 0; i < SSL_MAX_HANDSHAKE_FLIGHT; i++) {
+ dtls1_hm_fragment_free(ssl->d1->incoming_messages[i]);
+ ssl->d1->incoming_messages[i] = NULL;
+ }
+}
+
+int dtls_has_incoming_messages(const SSL *ssl) {
+ size_t current = ssl->d1->handshake_read_seq % SSL_MAX_HANDSHAKE_FLIGHT;
+ for (size_t i = 0; i < SSL_MAX_HANDSHAKE_FLIGHT; i++) {
+ /* Skip the current message. */
+ if (ssl->init_msg != NULL && i == current) {
+ assert(dtls1_is_current_message_complete(ssl));
+ continue;
+ }
+ if (ssl->d1->incoming_messages[i] != NULL) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int dtls1_parse_fragment(CBS *cbs, struct hm_header_st *out_hdr,
+ CBS *out_body) {
+ OPENSSL_memset(out_hdr, 0x00, sizeof(struct hm_header_st));
+
+ if (!CBS_get_u8(cbs, &out_hdr->type) ||
+ !CBS_get_u24(cbs, &out_hdr->msg_len) ||
+ !CBS_get_u16(cbs, &out_hdr->seq) ||
+ !CBS_get_u24(cbs, &out_hdr->frag_off) ||
+ !CBS_get_u24(cbs, &out_hdr->frag_len) ||
+ !CBS_get_bytes(cbs, out_body, out_hdr->frag_len)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/* Sending handshake messages. */
+
+void dtls_clear_outgoing_messages(SSL *ssl) {
+ for (size_t i = 0; i < ssl->d1->outgoing_messages_len; i++) {
+ OPENSSL_free(ssl->d1->outgoing_messages[i].data);
+ ssl->d1->outgoing_messages[i].data = NULL;
+ }
+ ssl->d1->outgoing_messages_len = 0;
+ ssl->d1->outgoing_written = 0;
+ ssl->d1->outgoing_offset = 0;
+}
+
+int dtls1_init_message(SSL *ssl, CBB *cbb, CBB *body, uint8_t type) {
+ /* Pick a modest size hint to save most of the |realloc| calls. */
+ if (!CBB_init(cbb, 64) ||
+ !CBB_add_u8(cbb, type) ||
+ !CBB_add_u24(cbb, 0 /* length (filled in later) */) ||
+ !CBB_add_u16(cbb, ssl->d1->handshake_write_seq) ||
+ !CBB_add_u24(cbb, 0 /* offset */) ||
+ !CBB_add_u24_length_prefixed(cbb, body)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+int dtls1_finish_message(SSL *ssl, CBB *cbb, uint8_t **out_msg,
+ size_t *out_len) {
+ *out_msg = NULL;
+ if (!CBB_finish(cbb, out_msg, out_len) ||
+ *out_len < DTLS1_HM_HEADER_LENGTH) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ OPENSSL_free(*out_msg);
+ return 0;
+ }
+
+ /* Fix up the header. Copy the fragment length into the total message
+ * length. */
+ OPENSSL_memcpy(*out_msg + 1, *out_msg + DTLS1_HM_HEADER_LENGTH - 3, 3);
+ return 1;
+}
+
+/* add_outgoing adds a new handshake message or ChangeCipherSpec to the current
+ * outgoing flight. It returns one on success and zero on error. In both cases,
+ * 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) {
+ OPENSSL_COMPILE_ASSERT(SSL_MAX_HANDSHAKE_FLIGHT <
+ (1 << 8 * sizeof(ssl->d1->outgoing_messages_len)),
+ outgoing_messages_len_is_too_small);
+ if (ssl->d1->outgoing_messages_len >= SSL_MAX_HANDSHAKE_FLIGHT) {
+ assert(0);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ OPENSSL_free(data);
+ return 0;
+ }
+
+ if (!is_ccs) {
+ /* TODO(svaldez): Move this up a layer to fix abstraction for SSL_TRANSCRIPT
+ * on hs. */
+ if (ssl->s3->hs != NULL &&
+ !SSL_TRANSCRIPT_update(&ssl->s3->hs->transcript, data, len)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ OPENSSL_free(data);
+ return 0;
+ }
+ ssl->d1->handshake_write_seq++;
+ }
+
+ DTLS_OUTGOING_MESSAGE *msg =
+ &ssl->d1->outgoing_messages[ssl->d1->outgoing_messages_len];
+ msg->data = data;
+ msg->len = len;
+ msg->epoch = ssl->d1->w_epoch;
+ msg->is_ccs = is_ccs;
+
+ ssl->d1->outgoing_messages_len++;
+ return 1;
+}
+
+int dtls1_add_message(SSL *ssl, uint8_t *data, size_t len) {
+ return add_outgoing(ssl, 0 /* handshake */, data, len);
+}
+
+int dtls1_add_change_cipher_spec(SSL *ssl) {
+ return add_outgoing(ssl, 1 /* ChangeCipherSpec */, NULL, 0);
+}
+
+int dtls1_add_alert(SSL *ssl, uint8_t level, uint8_t desc) {
+ /* The |add_alert| path is only used for warning alerts for now, which DTLS
+ * never sends. This will be implemented later once closure alerts are
+ * converted. */
+ assert(0);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return 0;
+}
+
+/* dtls1_update_mtu updates the current MTU from the BIO, ensuring it is above
+ * the minimum. */
+static void dtls1_update_mtu(SSL *ssl) {
+ /* TODO(davidben): No consumer implements |BIO_CTRL_DGRAM_SET_MTU| and the
+ * only |BIO_CTRL_DGRAM_QUERY_MTU| implementation could use
+ * |SSL_set_mtu|. Does this need to be so complex? */
+ if (ssl->d1->mtu < dtls1_min_mtu() &&
+ !(SSL_get_options(ssl) & SSL_OP_NO_QUERY_MTU)) {
+ long mtu = BIO_ctrl(ssl->wbio, BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL);
+ if (mtu >= 0 && mtu <= (1 << 30) && (unsigned)mtu >= dtls1_min_mtu()) {
+ ssl->d1->mtu = (unsigned)mtu;
+ } else {
+ ssl->d1->mtu = kDefaultMTU;
+ BIO_ctrl(ssl->wbio, BIO_CTRL_DGRAM_SET_MTU, ssl->d1->mtu, NULL);
+ }
+ }
+
+ /* The MTU should be above the minimum now. */
+ assert(ssl->d1->mtu >= dtls1_min_mtu());
+}
+
+enum seal_result_t {
+ seal_error,
+ seal_no_progress,
+ seal_partial,
+ seal_success,
+};
+
+/* seal_next_message seals |msg|, which must be the next message, to |out|. If
+ * progress was made, it returns |seal_partial| or |seal_success| and sets
+ * |*out_len| to the number of bytes written. */
+static enum seal_result_t seal_next_message(SSL *ssl, uint8_t *out,
+ size_t *out_len, size_t max_out,
+ const DTLS_OUTGOING_MESSAGE *msg) {
+ assert(ssl->d1->outgoing_written < ssl->d1->outgoing_messages_len);
+ assert(msg == &ssl->d1->outgoing_messages[ssl->d1->outgoing_written]);
+
+ /* DTLS renegotiation is unsupported, so only epochs 0 (NULL cipher) and 1
+ * (negotiated cipher) exist. */
+ assert(ssl->d1->w_epoch == 0 || ssl->d1->w_epoch == 1);
+ assert(msg->epoch <= ssl->d1->w_epoch);
+ enum dtls1_use_epoch_t use_epoch = dtls1_use_current_epoch;
+ if (ssl->d1->w_epoch == 1 && msg->epoch == 0) {
+ use_epoch = dtls1_use_previous_epoch;
+ }
+ size_t overhead = dtls_max_seal_overhead(ssl, use_epoch);
+ size_t prefix = dtls_seal_prefix_len(ssl, use_epoch);
+
+ if (msg->is_ccs) {
+ /* Check there is room for the ChangeCipherSpec. */
+ static const uint8_t kChangeCipherSpec[1] = {SSL3_MT_CCS};
+ if (max_out < sizeof(kChangeCipherSpec) + overhead) {
+ return seal_no_progress;
+ }
+
+ if (!dtls_seal_record(ssl, out, out_len, max_out,
+ SSL3_RT_CHANGE_CIPHER_SPEC, kChangeCipherSpec,
+ sizeof(kChangeCipherSpec), use_epoch)) {
+ return seal_error;
+ }
+
+ ssl_do_msg_callback(ssl, 1 /* write */, SSL3_RT_CHANGE_CIPHER_SPEC,
+ kChangeCipherSpec, sizeof(kChangeCipherSpec));
+ return seal_success;
+ }
+
+ /* DTLS messages are serialized as a single fragment in |msg|. */
+ CBS cbs, body;
+ struct hm_header_st hdr;
+ CBS_init(&cbs, msg->data, msg->len);
+ if (!dtls1_parse_fragment(&cbs, &hdr, &body) ||
+ hdr.frag_off != 0 ||
+ hdr.frag_len != CBS_len(&body) ||
+ hdr.msg_len != CBS_len(&body) ||
+ !CBS_skip(&body, ssl->d1->outgoing_offset) ||
+ CBS_len(&cbs) != 0) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return seal_error;
+ }
+
+ /* Determine how much progress can be made. */
+ if (max_out < DTLS1_HM_HEADER_LENGTH + 1 + overhead || max_out < prefix) {
+ return seal_no_progress;
+ }
+ size_t todo = CBS_len(&body);
+ if (todo > max_out - DTLS1_HM_HEADER_LENGTH - overhead) {
+ todo = max_out - DTLS1_HM_HEADER_LENGTH - overhead;
+ }
+
+ /* Assemble a fragment, to be sealed in-place. */
+ CBB cbb;
+ uint8_t *frag = out + prefix;
+ size_t max_frag = max_out - prefix, frag_len;
+ if (!CBB_init_fixed(&cbb, frag, max_frag) ||
+ !CBB_add_u8(&cbb, hdr.type) ||
+ !CBB_add_u24(&cbb, hdr.msg_len) ||
+ !CBB_add_u16(&cbb, hdr.seq) ||
+ !CBB_add_u24(&cbb, ssl->d1->outgoing_offset) ||
+ !CBB_add_u24(&cbb, todo) ||
+ !CBB_add_bytes(&cbb, CBS_data(&body), todo) ||
+ !CBB_finish(&cbb, NULL, &frag_len)) {
+ CBB_cleanup(&cbb);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return seal_error;
+ }
+
+ ssl_do_msg_callback(ssl, 1 /* write */, SSL3_RT_HANDSHAKE, frag, frag_len);
+
+ if (!dtls_seal_record(ssl, out, out_len, max_out, SSL3_RT_HANDSHAKE,
+ out + prefix, frag_len, use_epoch)) {
+ return seal_error;
+ }
+
+ if (todo == CBS_len(&body)) {
+ /* The next message is complete. */
+ ssl->d1->outgoing_offset = 0;
+ return seal_success;
+ }
+
+ ssl->d1->outgoing_offset += todo;
+ return seal_partial;
+}
+
+/* seal_next_packet writes as much of the next flight as possible to |out| and
+ * advances |ssl->d1->outgoing_written| and |ssl->d1->outgoing_offset| as
+ * appropriate. */
+static int seal_next_packet(SSL *ssl, uint8_t *out, size_t *out_len,
+ size_t max_out) {
+ int made_progress = 0;
+ size_t total = 0;
+ assert(ssl->d1->outgoing_written < ssl->d1->outgoing_messages_len);
+ for (; ssl->d1->outgoing_written < ssl->d1->outgoing_messages_len;
+ ssl->d1->outgoing_written++) {
+ const DTLS_OUTGOING_MESSAGE *msg =
+ &ssl->d1->outgoing_messages[ssl->d1->outgoing_written];
+ size_t len;
+ enum seal_result_t ret = seal_next_message(ssl, out, &len, max_out, msg);
+ switch (ret) {
+ case seal_error:
+ return 0;
+
+ case seal_no_progress:
+ goto packet_full;
+
+ case seal_partial:
+ case seal_success:
+ out += len;
+ max_out -= len;
+ total += len;
+ made_progress = 1;
+
+ if (ret == seal_partial) {
+ goto packet_full;
+ }
+ break;
+ }
+ }
+
+packet_full:
+ /* The MTU was too small to make any progress. */
+ if (!made_progress) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_MTU_TOO_SMALL);
+ return 0;
+ }
+
+ *out_len = total;
+ return 1;
+}
+
+int dtls1_flush_flight(SSL *ssl) {
+ dtls1_update_mtu(ssl);
+
+ int ret = -1;
+ uint8_t *packet = OPENSSL_malloc(ssl->d1->mtu);
+ if (packet == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ while (ssl->d1->outgoing_written < ssl->d1->outgoing_messages_len) {
+ uint8_t old_written = ssl->d1->outgoing_written;
+ uint32_t old_offset = ssl->d1->outgoing_offset;
+
+ size_t packet_len;
+ if (!seal_next_packet(ssl, packet, &packet_len, ssl->d1->mtu)) {
+ goto err;
+ }
+
+ int bio_ret = BIO_write(ssl->wbio, packet, packet_len);
+ if (bio_ret <= 0) {
+ /* Retry this packet the next time around. */
+ ssl->d1->outgoing_written = old_written;
+ ssl->d1->outgoing_offset = old_offset;
+ ssl->rwstate = SSL_WRITING;
+ ret = bio_ret;
+ goto err;
+ }
+ }
+
+ if (BIO_flush(ssl->wbio) <= 0) {
+ ssl->rwstate = SSL_WRITING;
+ goto err;
+ }
+
+ ret = 1;
+
+err:
+ OPENSSL_free(packet);
+ return ret;
+}
+
+int dtls1_retransmit_outgoing_messages(SSL *ssl) {
+ /* Rewind to the start of the flight and write it again.
+ *
+ * TODO(davidben): This does not allow retransmits to be resumed on
+ * non-blocking write. */
+ ssl->d1->outgoing_written = 0;
+ ssl->d1->outgoing_offset = 0;
+
+ return dtls1_flush_flight(ssl);
+}
+
+unsigned int dtls1_min_mtu(void) {
+ return kMinMTU;
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/d1_lib.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/d1_lib.c
new file mode 100644
index 000000000..ef15252fd
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/d1_lib.c
@@ -0,0 +1,266 @@
+/*
+ * DTLS implementation written by Nagendra Modadugu
+ * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.
+ */
+/* ====================================================================
+ * Copyright (c) 1999-2005 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com). */
+
+#include <openssl/ssl.h>
+
+#include <assert.h>
+#include <limits.h>
+#include <string.h>
+
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/nid.h>
+
+#include "../crypto/internal.h"
+#include "internal.h"
+
+
+
+/* DTLS1_MTU_TIMEOUTS is the maximum number of timeouts to expire
+ * before starting to decrease the MTU. */
+#define DTLS1_MTU_TIMEOUTS 2
+
+/* DTLS1_MAX_TIMEOUTS is the maximum number of timeouts to expire
+ * before failing the DTLS handshake. */
+#define DTLS1_MAX_TIMEOUTS 12
+
+int dtls1_new(SSL *ssl) {
+ DTLS1_STATE *d1;
+
+ if (!ssl3_new(ssl)) {
+ return 0;
+ }
+ d1 = OPENSSL_malloc(sizeof *d1);
+ if (d1 == NULL) {
+ ssl3_free(ssl);
+ return 0;
+ }
+ OPENSSL_memset(d1, 0, sizeof *d1);
+
+ ssl->d1 = d1;
+
+ /* Set the version to the highest supported version.
+ *
+ * TODO(davidben): Move this field into |s3|, have it store the normalized
+ * protocol version, and implement this pre-negotiation quirk in |SSL_version|
+ * at the API boundary rather than in internal state. */
+ ssl->version = DTLS1_2_VERSION;
+ return 1;
+}
+
+void dtls1_free(SSL *ssl) {
+ ssl3_free(ssl);
+
+ if (ssl == NULL || ssl->d1 == NULL) {
+ return;
+ }
+
+ dtls_clear_incoming_messages(ssl);
+ dtls_clear_outgoing_messages(ssl);
+
+ OPENSSL_free(ssl->d1);
+ ssl->d1 = NULL;
+}
+
+void DTLSv1_set_initial_timeout_duration(SSL *ssl, unsigned int duration_ms) {
+ ssl->initial_timeout_duration_ms = duration_ms;
+}
+
+void dtls1_start_timer(SSL *ssl) {
+ /* If timer is not set, initialize duration (by default, 1 second) */
+ if (ssl->d1->next_timeout.tv_sec == 0 && ssl->d1->next_timeout.tv_usec == 0) {
+ ssl->d1->timeout_duration_ms = ssl->initial_timeout_duration_ms;
+ }
+
+ /* Set timeout to current time */
+ ssl_get_current_time(ssl, &ssl->d1->next_timeout);
+
+ /* Add duration to current time */
+ ssl->d1->next_timeout.tv_sec += ssl->d1->timeout_duration_ms / 1000;
+ ssl->d1->next_timeout.tv_usec += (ssl->d1->timeout_duration_ms % 1000) * 1000;
+ if (ssl->d1->next_timeout.tv_usec >= 1000000) {
+ ssl->d1->next_timeout.tv_sec++;
+ ssl->d1->next_timeout.tv_usec -= 1000000;
+ }
+}
+
+int DTLSv1_get_timeout(const SSL *ssl, struct timeval *out) {
+ if (!SSL_is_dtls(ssl)) {
+ return 0;
+ }
+
+ /* If no timeout is set, just return NULL */
+ if (ssl->d1->next_timeout.tv_sec == 0 && ssl->d1->next_timeout.tv_usec == 0) {
+ return 0;
+ }
+
+ struct OPENSSL_timeval timenow;
+ ssl_get_current_time(ssl, &timenow);
+
+ /* 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)) {
+ OPENSSL_memset(out, 0, sizeof(*out));
+ return 1;
+ }
+
+ /* 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;
+ if (ret.tv_usec >= timenow.tv_usec) {
+ ret.tv_usec -= timenow.tv_usec;
+ } else {
+ ret.tv_usec = 1000000 + ret.tv_usec - timenow.tv_usec;
+ ret.tv_sec--;
+ }
+
+ /* If remaining time is less than 15 ms, set it to 0 to prevent issues
+ * because of small divergences with socket timeouts. */
+ if (ret.tv_sec == 0 && ret.tv_usec < 15000) {
+ OPENSSL_memset(&ret, 0, sizeof(ret));
+ }
+
+ /* Clamp the result in case of overflow. */
+ if (ret.tv_sec > INT_MAX) {
+ assert(0);
+ out->tv_sec = INT_MAX;
+ } else {
+ out->tv_sec = ret.tv_sec;
+ }
+
+ out->tv_usec = ret.tv_usec;
+ return 1;
+}
+
+int dtls1_is_timer_expired(SSL *ssl) {
+ struct timeval timeleft;
+
+ /* Get time left until timeout, return false if no timer running */
+ if (!DTLSv1_get_timeout(ssl, &timeleft)) {
+ return 0;
+ }
+
+ /* Return false if timer is not expired yet */
+ if (timeleft.tv_sec > 0 || timeleft.tv_usec > 0) {
+ return 0;
+ }
+
+ /* Timer expired, so return true */
+ return 1;
+}
+
+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) {
+ ssl->d1->num_timeouts++;
+
+ /* Reduce MTU after 2 unsuccessful retransmissions */
+ if (ssl->d1->num_timeouts > DTLS1_MTU_TIMEOUTS &&
+ !(SSL_get_options(ssl) & SSL_OP_NO_QUERY_MTU)) {
+ long mtu = BIO_ctrl(ssl->wbio, BIO_CTRL_DGRAM_GET_FALLBACK_MTU, 0, NULL);
+ if (mtu >= 0 && mtu <= (1 << 30) && (unsigned)mtu >= dtls1_min_mtu()) {
+ ssl->d1->mtu = (unsigned)mtu;
+ }
+ }
+
+ 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;
+}
+
+int DTLSv1_handle_timeout(SSL *ssl) {
+ ssl_reset_error_state(ssl);
+
+ if (!SSL_is_dtls(ssl)) {
+ return -1;
+ }
+
+ /* 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) {
+ return -1;
+ }
+
+ dtls1_start_timer(ssl);
+ return dtls1_retransmit_outgoing_messages(ssl);
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/d1_pkt.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/d1_pkt.c
new file mode 100644
index 000000000..34448259e
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/d1_pkt.c
@@ -0,0 +1,414 @@
+/* DTLS implementation written by Nagendra Modadugu
+ * (nagendra@cs.stanford.edu) for the OpenSSL project 2005. */
+/* ====================================================================
+ * Copyright (c) 1998-2005 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#include <openssl/ssl.h>
+
+#include <assert.h>
+#include <string.h>
+
+#include <openssl/bio.h>
+#include <openssl/buf.h>
+#include <openssl/bytestring.h>
+#include <openssl/mem.h>
+#include <openssl/evp.h>
+#include <openssl/err.h>
+#include <openssl/rand.h>
+
+#include "../crypto/internal.h"
+#include "internal.h"
+
+
+int dtls1_get_record(SSL *ssl) {
+again:
+ switch (ssl->s3->recv_shutdown) {
+ case ssl_shutdown_none:
+ break;
+ case ssl_shutdown_fatal_alert:
+ OPENSSL_PUT_ERROR(SSL, SSL_R_PROTOCOL_IS_SHUTDOWN);
+ return -1;
+ case ssl_shutdown_close_notify:
+ return 0;
+ }
+
+ /* Read a new packet if there is no unconsumed one. */
+ if (ssl_read_buffer_len(ssl) == 0) {
+ int read_ret = ssl_read_buffer_extend_to(ssl, 0 /* unused */);
+ if (read_ret < 0 && dtls1_is_timer_expired(ssl)) {
+ /* Historically, timeouts were handled implicitly if the caller did not
+ * handle them.
+ *
+ * TODO(davidben): This was to support blocking sockets but affected
+ * non-blocking sockets. Can it be removed? */
+ int timeout_ret = DTLSv1_handle_timeout(ssl);
+ if (timeout_ret <= 0) {
+ return timeout_ret;
+ }
+ goto again;
+ }
+ if (read_ret <= 0) {
+ return read_ret;
+ }
+ }
+ assert(ssl_read_buffer_len(ssl) > 0);
+
+ CBS body;
+ uint8_t type, alert;
+ size_t consumed;
+ enum ssl_open_record_t open_ret =
+ dtls_open_record(ssl, &type, &body, &consumed, &alert,
+ ssl_read_buffer(ssl), ssl_read_buffer_len(ssl));
+ ssl_read_buffer_consume(ssl, consumed);
+ switch (open_ret) {
+ case ssl_open_record_partial:
+ /* Impossible in DTLS. */
+ break;
+
+ case ssl_open_record_success:
+ if (CBS_len(&body) > 0xffff) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
+ return -1;
+ }
+
+ SSL3_RECORD *rr = &ssl->s3->rrec;
+ rr->type = type;
+ rr->length = (uint16_t)CBS_len(&body);
+ rr->data = (uint8_t *)CBS_data(&body);
+ return 1;
+
+ case ssl_open_record_discard:
+ goto again;
+
+ case ssl_open_record_close_notify:
+ return 0;
+
+ case ssl_open_record_fatal_alert:
+ return -1;
+
+ case ssl_open_record_error:
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
+ return -1;
+ }
+
+ assert(0);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return -1;
+}
+
+int dtls1_read_app_data(SSL *ssl, int *out_got_handshake, uint8_t *buf, int len,
+ int peek) {
+ assert(!SSL_in_init(ssl));
+
+ *out_got_handshake = 0;
+ SSL3_RECORD *rr = &ssl->s3->rrec;
+
+again:
+ if (rr->length == 0) {
+ int ret = dtls1_get_record(ssl);
+ if (ret <= 0) {
+ return ret;
+ }
+ }
+
+ if (rr->type == SSL3_RT_HANDSHAKE) {
+ /* Parse the first fragment header to determine if this is a pre-CCS or
+ * post-CCS handshake record. DTLS resets handshake message numbers on each
+ * handshake, so renegotiations and retransmissions are ambiguous. */
+ CBS cbs, body;
+ struct hm_header_st msg_hdr;
+ CBS_init(&cbs, rr->data, rr->length);
+ if (!dtls1_parse_fragment(&cbs, &msg_hdr, &body)) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_HANDSHAKE_RECORD);
+ return -1;
+ }
+
+ if (msg_hdr.type == SSL3_MT_FINISHED &&
+ msg_hdr.seq == ssl->d1->handshake_read_seq - 1) {
+ if (msg_hdr.frag_off == 0) {
+ /* 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) {
+ return -1;
+ }
+
+ dtls1_retransmit_outgoing_messages(ssl);
+ }
+
+ rr->length = 0;
+ goto again;
+ }
+
+ /* Otherwise, this is a pre-CCS handshake message from an unsupported
+ * renegotiation attempt. Fall through to the error path. */
+ }
+
+ if (rr->type != SSL3_RT_APPLICATION_DATA) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD);
+ return -1;
+ }
+
+ /* Discard empty records. */
+ if (rr->length == 0) {
+ goto again;
+ }
+
+ if (len <= 0) {
+ return len;
+ }
+
+ if ((unsigned)len > rr->length) {
+ len = rr->length;
+ }
+
+ OPENSSL_memcpy(buf, rr->data, len);
+ if (!peek) {
+ /* TODO(davidben): Should the record be truncated instead? This is a
+ * datagram transport. See https://crbug.com/boringssl/65. */
+ rr->length -= len;
+ rr->data += len;
+ if (rr->length == 0) {
+ /* The record has been consumed, so we may now clear the buffer. */
+ ssl_read_buffer_discard(ssl);
+ }
+ }
+
+ 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
+ * peer never received our close_notify. Report to the caller that the channel
+ * has fully shut down. */
+ if (ssl->s3->recv_shutdown == ssl_shutdown_none) {
+ ssl->s3->recv_shutdown = ssl_shutdown_close_notify;
+ }
+}
+
+int dtls1_write_app_data(SSL *ssl, const uint8_t *buf, int len) {
+ assert(!SSL_in_init(ssl));
+
+ if (len > SSL3_RT_MAX_PLAIN_LENGTH) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DTLS_MESSAGE_TOO_BIG);
+ return -1;
+ }
+
+ if (len < 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_LENGTH);
+ return -1;
+ }
+
+ if (len == 0) {
+ return 0;
+ }
+
+ int ret = dtls1_write_record(ssl, SSL3_RT_APPLICATION_DATA, buf, (size_t)len,
+ dtls1_use_current_epoch);
+ if (ret <= 0) {
+ return ret;
+ }
+ return len;
+}
+
+int dtls1_write_record(SSL *ssl, int type, const uint8_t *buf, size_t len,
+ enum dtls1_use_epoch_t use_epoch) {
+ assert(len <= SSL3_RT_MAX_PLAIN_LENGTH);
+ /* There should never be a pending write buffer in DTLS. One can't write half
+ * a datagram, so the write buffer is always dropped in
+ * |ssl_write_buffer_flush|. */
+ assert(!ssl_write_buffer_is_pending(ssl));
+
+ if (len > SSL3_RT_MAX_PLAIN_LENGTH) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
+
+ size_t max_out = len + SSL_max_seal_overhead(ssl);
+ uint8_t *out;
+ size_t ciphertext_len;
+ if (!ssl_write_buffer_init(ssl, &out, max_out) ||
+ !dtls_seal_record(ssl, out, &ciphertext_len, max_out, type, buf, len,
+ use_epoch)) {
+ ssl_write_buffer_clear(ssl);
+ return -1;
+ }
+ ssl_write_buffer_set_len(ssl, ciphertext_len);
+
+ int ret = ssl_write_buffer_flush(ssl);
+ if (ret <= 0) {
+ return ret;
+ }
+ return 1;
+}
+
+int dtls1_dispatch_alert(SSL *ssl) {
+ int ret = dtls1_write_record(ssl, SSL3_RT_ALERT, &ssl->s3->send_alert[0], 2,
+ dtls1_use_current_epoch);
+ if (ret <= 0) {
+ return ret;
+ }
+ ssl->s3->alert_dispatch = 0;
+
+ /* If the alert is fatal, flush the BIO now. */
+ if (ssl->s3->send_alert[0] == SSL3_AL_FATAL) {
+ BIO_flush(ssl->wbio);
+ }
+
+ ssl_do_msg_callback(ssl, 1 /* write */, SSL3_RT_ALERT, ssl->s3->send_alert,
+ 2);
+
+ int alert = (ssl->s3->send_alert[0] << 8) | ssl->s3->send_alert[1];
+ ssl_do_info_callback(ssl, SSL_CB_WRITE_ALERT, alert);
+
+ return 1;
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/d1_srtp.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/d1_srtp.c
new file mode 100644
index 000000000..108537777
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/d1_srtp.c
@@ -0,0 +1,236 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2006 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/*
+ DTLS code by Eric Rescorla <ekr@rtfm.com>
+
+ Copyright (C) 2006, Network Resonance, Inc.
+ Copyright (C) 2011, RTFM, Inc.
+*/
+
+#include <openssl/ssl.h>
+
+#include <string.h>
+
+#include <openssl/bytestring.h>
+#include <openssl/err.h>
+
+#include "internal.h"
+
+
+static const SRTP_PROTECTION_PROFILE kSRTPProfiles[] = {
+ {
+ "SRTP_AES128_CM_SHA1_80", SRTP_AES128_CM_SHA1_80,
+ },
+ {
+ "SRTP_AES128_CM_SHA1_32", SRTP_AES128_CM_SHA1_32,
+ },
+ {
+ "SRTP_AEAD_AES_128_GCM", SRTP_AEAD_AES_128_GCM,
+ },
+ {
+ "SRTP_AEAD_AES_256_GCM", SRTP_AEAD_AES_256_GCM,
+ },
+ {0, 0},
+};
+
+static int find_profile_by_name(const char *profile_name,
+ const SRTP_PROTECTION_PROFILE **pptr,
+ size_t len) {
+ const SRTP_PROTECTION_PROFILE *p;
+
+ p = kSRTPProfiles;
+ while (p->name) {
+ if (len == strlen(p->name) && !strncmp(p->name, profile_name, len)) {
+ *pptr = p;
+ return 1;
+ }
+
+ p++;
+ }
+
+ return 0;
+}
+
+static int ssl_ctx_make_profiles(const char *profiles_string,
+ STACK_OF(SRTP_PROTECTION_PROFILE) **out) {
+ STACK_OF(SRTP_PROTECTION_PROFILE) *profiles =
+ sk_SRTP_PROTECTION_PROFILE_new_null();
+ if (profiles == NULL) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_SRTP_COULD_NOT_ALLOCATE_PROFILES);
+ return 0;
+ }
+
+ const char *col;
+ const char *ptr = profiles_string;
+ do {
+ col = strchr(ptr, ':');
+
+ const SRTP_PROTECTION_PROFILE *profile;
+ if (!find_profile_by_name(ptr, &profile,
+ col ? (size_t)(col - ptr) : strlen(ptr))) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_SRTP_UNKNOWN_PROTECTION_PROFILE);
+ goto err;
+ }
+
+ if (!sk_SRTP_PROTECTION_PROFILE_push(profiles, profile)) {
+ goto err;
+ }
+
+ if (col) {
+ ptr = col + 1;
+ }
+ } while (col);
+
+ sk_SRTP_PROTECTION_PROFILE_free(*out);
+ *out = profiles;
+ return 1;
+
+err:
+ sk_SRTP_PROTECTION_PROFILE_free(profiles);
+ return 0;
+}
+
+int SSL_CTX_set_srtp_profiles(SSL_CTX *ctx, const char *profiles) {
+ return ssl_ctx_make_profiles(profiles, &ctx->srtp_profiles);
+}
+
+int SSL_set_srtp_profiles(SSL *ssl, const char *profiles) {
+ return ssl_ctx_make_profiles(profiles, &ssl->srtp_profiles);
+}
+
+STACK_OF(SRTP_PROTECTION_PROFILE) *SSL_get_srtp_profiles(SSL *ssl) {
+ if (ssl == NULL) {
+ return NULL;
+ }
+
+ if (ssl->srtp_profiles != NULL) {
+ return ssl->srtp_profiles;
+ }
+
+ if (ssl->ctx->srtp_profiles != NULL) {
+ return ssl->ctx->srtp_profiles;
+ }
+
+ return NULL;
+}
+
+const SRTP_PROTECTION_PROFILE *SSL_get_selected_srtp_profile(SSL *ssl) {
+ return ssl->srtp_profile;
+}
+
+int SSL_CTX_set_tlsext_use_srtp(SSL_CTX *ctx, const char *profiles) {
+ /* This API inverts its return value. */
+ return !SSL_CTX_set_srtp_profiles(ctx, profiles);
+}
+
+int SSL_set_tlsext_use_srtp(SSL *ssl, const char *profiles) {
+ /* This API inverts its return value. */
+ return !SSL_set_srtp_profiles(ssl, profiles);
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/dtls_method.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/dtls_method.c
new file mode 100644
index 000000000..60847895a
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/dtls_method.c
@@ -0,0 +1,217 @@
+/*
+ * DTLS implementation written by Nagendra Modadugu
+ * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.
+ */
+/* ====================================================================
+ * Copyright (c) 1999-2005 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com). */
+
+#include <openssl/ssl.h>
+
+#include <assert.h>
+#include <string.h>
+
+#include <openssl/buf.h>
+#include <openssl/err.h>
+
+#include "../crypto/internal.h"
+#include "internal.h"
+
+
+static int dtls1_version_from_wire(uint16_t *out_version,
+ uint16_t wire_version) {
+ switch (wire_version) {
+ case DTLS1_VERSION:
+ /* DTLS 1.0 maps to TLS 1.1, not TLS 1.0. */
+ *out_version = TLS1_1_VERSION;
+ return 1;
+ case DTLS1_2_VERSION:
+ *out_version = TLS1_2_VERSION;
+ return 1;
+ }
+
+ return 0;
+}
+
+static uint16_t dtls1_version_to_wire(uint16_t version) {
+ switch (version) {
+ case TLS1_1_VERSION:
+ /* DTLS 1.0 maps to TLS 1.1, not TLS 1.0. */
+ return DTLS1_VERSION;
+ case TLS1_2_VERSION:
+ return DTLS1_2_VERSION;
+ }
+
+ /* It is an error to use this function with an invalid version. */
+ assert(0);
+ return 0;
+}
+
+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 int dtls1_set_read_state(SSL *ssl, SSL_AEAD_CTX *aead_ctx) {
+ /* Cipher changes are illegal when there are buffered incoming messages. */
+ if (dtls_has_incoming_messages(ssl)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFERED_MESSAGES_ON_CIPHER_CHANGE);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
+ SSL_AEAD_CTX_free(aead_ctx);
+ return 0;
+ }
+
+ ssl->d1->r_epoch++;
+ OPENSSL_memset(&ssl->d1->bitmap, 0, sizeof(ssl->d1->bitmap));
+ OPENSSL_memset(ssl->s3->read_sequence, 0, sizeof(ssl->s3->read_sequence));
+
+ SSL_AEAD_CTX_free(ssl->s3->aead_read_ctx);
+ ssl->s3->aead_read_ctx = aead_ctx;
+ return 1;
+}
+
+static int dtls1_set_write_state(SSL *ssl, SSL_AEAD_CTX *aead_ctx) {
+ ssl->d1->w_epoch++;
+ OPENSSL_memcpy(ssl->d1->last_write_sequence, ssl->s3->write_sequence,
+ sizeof(ssl->s3->write_sequence));
+ OPENSSL_memset(ssl->s3->write_sequence, 0, sizeof(ssl->s3->write_sequence));
+
+ SSL_AEAD_CTX_free(ssl->s3->aead_write_ctx);
+ ssl->s3->aead_write_ctx = aead_ctx;
+ return 1;
+}
+
+static const SSL_PROTOCOL_METHOD kDTLSProtocolMethod = {
+ 1 /* is_dtls */,
+ TLS1_1_VERSION,
+ TLS1_2_VERSION,
+ dtls1_version_from_wire,
+ dtls1_version_to_wire,
+ dtls1_new,
+ dtls1_free,
+ dtls1_get_message,
+ dtls1_get_current_message,
+ dtls1_release_current_message,
+ dtls1_read_app_data,
+ dtls1_read_change_cipher_spec,
+ dtls1_read_close_notify,
+ dtls1_write_app_data,
+ dtls1_dispatch_alert,
+ dtls1_supports_cipher,
+ dtls1_init_message,
+ dtls1_finish_message,
+ dtls1_add_message,
+ dtls1_add_change_cipher_spec,
+ dtls1_add_alert,
+ dtls1_flush_flight,
+ dtls1_expect_flight,
+ dtls1_received_flight,
+ dtls1_set_read_state,
+ dtls1_set_write_state,
+};
+
+const SSL_METHOD *DTLS_method(void) {
+ static const SSL_METHOD kMethod = {
+ 0,
+ &kDTLSProtocolMethod,
+ &ssl_crypto_x509_method,
+ };
+ return &kMethod;
+}
+
+/* Legacy version-locked methods. */
+
+const SSL_METHOD *DTLSv1_2_method(void) {
+ static const SSL_METHOD kMethod = {
+ DTLS1_2_VERSION,
+ &kDTLSProtocolMethod,
+ &ssl_crypto_x509_method,
+ };
+ return &kMethod;
+}
+
+const SSL_METHOD *DTLSv1_method(void) {
+ static const SSL_METHOD kMethod = {
+ DTLS1_VERSION,
+ &kDTLSProtocolMethod,
+ &ssl_crypto_x509_method,
+ };
+ return &kMethod;
+}
+
+/* Legacy side-specific methods. */
+
+const SSL_METHOD *DTLSv1_2_server_method(void) {
+ return DTLSv1_2_method();
+}
+
+const SSL_METHOD *DTLSv1_server_method(void) {
+ return DTLSv1_method();
+}
+
+const SSL_METHOD *DTLSv1_2_client_method(void) {
+ return DTLSv1_2_method();
+}
+
+const SSL_METHOD *DTLSv1_client_method(void) {
+ return DTLSv1_method();
+}
+
+const SSL_METHOD *DTLS_server_method(void) {
+ return DTLS_method();
+}
+
+const SSL_METHOD *DTLS_client_method(void) {
+ return DTLS_method();
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/dtls_record.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/dtls_record.c
new file mode 100644
index 000000000..879706dfc
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/dtls_record.c
@@ -0,0 +1,334 @@
+/* DTLS implementation written by Nagendra Modadugu
+ * (nagendra@cs.stanford.edu) for the OpenSSL project 2005. */
+/* ====================================================================
+ * Copyright (c) 1998-2005 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#include <openssl/ssl.h>
+
+#include <assert.h>
+#include <string.h>
+
+#include <openssl/bytestring.h>
+#include <openssl/err.h>
+
+#include "internal.h"
+#include "../crypto/internal.h"
+
+
+/* to_u64_be treats |in| as a 8-byte big-endian integer and returns the value as
+ * a |uint64_t|. */
+static uint64_t to_u64_be(const uint8_t in[8]) {
+ uint64_t ret = 0;
+ unsigned i;
+ for (i = 0; i < 8; i++) {
+ ret <<= 8;
+ ret |= in[i];
+ }
+ return ret;
+}
+
+/* dtls1_bitmap_should_discard returns one if |seq_num| has been seen in |bitmap|
+ * or is stale. Otherwise it returns zero. */
+static int dtls1_bitmap_should_discard(DTLS1_BITMAP *bitmap,
+ const uint8_t seq_num[8]) {
+ const unsigned kWindowSize = sizeof(bitmap->map) * 8;
+
+ uint64_t seq_num_u = to_u64_be(seq_num);
+ if (seq_num_u > bitmap->max_seq_num) {
+ return 0;
+ }
+ uint64_t idx = bitmap->max_seq_num - seq_num_u;
+ return idx >= kWindowSize || (bitmap->map & (((uint64_t)1) << idx));
+}
+
+/* dtls1_bitmap_record updates |bitmap| to record receipt of sequence number
+ * |seq_num|. It slides the window forward if needed. It is an error to call
+ * this function on a stale sequence number. */
+static void dtls1_bitmap_record(DTLS1_BITMAP *bitmap,
+ const uint8_t seq_num[8]) {
+ const unsigned kWindowSize = sizeof(bitmap->map) * 8;
+
+ uint64_t seq_num_u = to_u64_be(seq_num);
+ /* Shift the window if necessary. */
+ if (seq_num_u > bitmap->max_seq_num) {
+ uint64_t shift = seq_num_u - bitmap->max_seq_num;
+ if (shift >= kWindowSize) {
+ bitmap->map = 0;
+ } else {
+ bitmap->map <<= shift;
+ }
+ bitmap->max_seq_num = seq_num_u;
+ }
+
+ uint64_t idx = bitmap->max_seq_num - seq_num_u;
+ if (idx < kWindowSize) {
+ bitmap->map |= ((uint64_t)1) << idx;
+ }
+}
+
+enum ssl_open_record_t dtls_open_record(SSL *ssl, uint8_t *out_type, CBS *out,
+ size_t *out_consumed,
+ uint8_t *out_alert, uint8_t *in,
+ size_t in_len) {
+ *out_consumed = 0;
+
+ CBS cbs;
+ CBS_init(&cbs, in, in_len);
+
+ /* Decode the record. */
+ uint8_t type;
+ uint16_t version;
+ uint8_t sequence[8];
+ CBS body;
+ if (!CBS_get_u8(&cbs, &type) ||
+ !CBS_get_u16(&cbs, &version) ||
+ !CBS_copy_bytes(&cbs, sequence, 8) ||
+ !CBS_get_u16_length_prefixed(&cbs, &body) ||
+ (ssl->s3->have_version && version != ssl->version) ||
+ (version >> 8) != DTLS1_VERSION_MAJOR ||
+ CBS_len(&body) > SSL3_RT_MAX_ENCRYPTED_LENGTH) {
+ /* The record header was incomplete or malformed. Drop the entire packet. */
+ *out_consumed = in_len;
+ return ssl_open_record_discard;
+ }
+
+ ssl_do_msg_callback(ssl, 0 /* read */, SSL3_RT_HEADER, in,
+ DTLS1_RT_HEADER_LENGTH);
+
+ uint16_t epoch = (((uint16_t)sequence[0]) << 8) | sequence[1];
+ if (epoch != ssl->d1->r_epoch ||
+ dtls1_bitmap_should_discard(&ssl->d1->bitmap, sequence)) {
+ /* Drop this record. It's from the wrong epoch or is a replay. Note that if
+ * |epoch| is the next epoch, the record could be buffered for later. For
+ * simplicity, drop it and expect retransmit to handle it later; DTLS must
+ * handle packet loss anyway. */
+ *out_consumed = in_len - CBS_len(&cbs);
+ return ssl_open_record_discard;
+ }
+
+ /* Decrypt the body in-place. */
+ if (!SSL_AEAD_CTX_open(ssl->s3->aead_read_ctx, out, type, version, sequence,
+ (uint8_t *)CBS_data(&body), CBS_len(&body))) {
+ /* Bad packets are silently dropped in DTLS. See section 4.2.1 of RFC 6347.
+ * Clear the error queue of any errors decryption may have added. Drop the
+ * entire packet as it must not have come from the peer.
+ *
+ * TODO(davidben): This doesn't distinguish malloc failures from encryption
+ * failures. */
+ ERR_clear_error();
+ *out_consumed = in_len - CBS_len(&cbs);
+ return ssl_open_record_discard;
+ }
+ *out_consumed = in_len - CBS_len(&cbs);
+
+ /* Check the plaintext length. */
+ if (CBS_len(out) > SSL3_RT_MAX_PLAIN_LENGTH) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DATA_LENGTH_TOO_LONG);
+ *out_alert = SSL_AD_RECORD_OVERFLOW;
+ return ssl_open_record_error;
+ }
+
+ dtls1_bitmap_record(&ssl->d1->bitmap, sequence);
+
+ /* TODO(davidben): Limit the number of empty records as in TLS? This is only
+ * useful if we also limit discarded packets. */
+
+ if (type == SSL3_RT_ALERT) {
+ return ssl_process_alert(ssl, out_alert, CBS_data(out), CBS_len(out));
+ }
+
+ ssl->s3->warning_alert_count = 0;
+
+ *out_type = type;
+ return ssl_open_record_success;
+}
+
+static const SSL_AEAD_CTX *get_write_aead(const SSL *ssl,
+ enum dtls1_use_epoch_t use_epoch) {
+ if (use_epoch == dtls1_use_previous_epoch) {
+ /* DTLS renegotiation is unsupported, so only epochs 0 (NULL cipher) and 1
+ * (negotiated cipher) exist. */
+ assert(ssl->d1->w_epoch == 1);
+ return NULL;
+ }
+
+ return ssl->s3->aead_write_ctx;
+}
+
+size_t dtls_max_seal_overhead(const SSL *ssl,
+ enum dtls1_use_epoch_t use_epoch) {
+ return DTLS1_RT_HEADER_LENGTH +
+ SSL_AEAD_CTX_max_overhead(get_write_aead(ssl, use_epoch));
+}
+
+size_t dtls_seal_prefix_len(const SSL *ssl, enum dtls1_use_epoch_t use_epoch) {
+ return DTLS1_RT_HEADER_LENGTH +
+ SSL_AEAD_CTX_explicit_nonce_len(get_write_aead(ssl, use_epoch));
+}
+
+int dtls_seal_record(SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out,
+ uint8_t type, const uint8_t *in, size_t in_len,
+ enum dtls1_use_epoch_t use_epoch) {
+ const size_t prefix = dtls_seal_prefix_len(ssl, use_epoch);
+ if (buffers_alias(in, in_len, out, max_out) &&
+ (max_out < prefix || out + prefix != in)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_OUTPUT_ALIASES_INPUT);
+ return 0;
+ }
+
+ /* Determine the parameters for the current epoch. */
+ uint16_t epoch = ssl->d1->w_epoch;
+ SSL_AEAD_CTX *aead = ssl->s3->aead_write_ctx;
+ uint8_t *seq = ssl->s3->write_sequence;
+ if (use_epoch == dtls1_use_previous_epoch) {
+ /* DTLS renegotiation is unsupported, so only epochs 0 (NULL cipher) and 1
+ * (negotiated cipher) exist. */
+ assert(ssl->d1->w_epoch == 1);
+ epoch = ssl->d1->w_epoch - 1;
+ aead = NULL;
+ seq = ssl->d1->last_write_sequence;
+ }
+
+ if (max_out < DTLS1_RT_HEADER_LENGTH) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL);
+ return 0;
+ }
+
+ out[0] = type;
+
+ uint16_t wire_version = ssl->s3->have_version ? ssl->version : DTLS1_VERSION;
+ out[1] = wire_version >> 8;
+ out[2] = wire_version & 0xff;
+
+ out[3] = epoch >> 8;
+ out[4] = epoch & 0xff;
+ OPENSSL_memcpy(&out[5], &seq[2], 6);
+
+ size_t ciphertext_len;
+ if (!SSL_AEAD_CTX_seal(aead, out + DTLS1_RT_HEADER_LENGTH, &ciphertext_len,
+ max_out - DTLS1_RT_HEADER_LENGTH, type, wire_version,
+ &out[3] /* seq */, in, in_len) ||
+ !ssl_record_sequence_update(&seq[2], 6)) {
+ return 0;
+ }
+
+ if (ciphertext_len >= 1 << 16) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
+ return 0;
+ }
+ out[11] = ciphertext_len >> 8;
+ out[12] = ciphertext_len & 0xff;
+
+ *out_len = DTLS1_RT_HEADER_LENGTH + ciphertext_len;
+
+ ssl_do_msg_callback(ssl, 1 /* write */, SSL3_RT_HEADER, out,
+ DTLS1_RT_HEADER_LENGTH);
+
+ return 1;
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/handshake_client.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/handshake_client.c
new file mode 100644
index 000000000..1feb7d8d0
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/handshake_client.c
@@ -0,0 +1,1909 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2007 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ *
+ * Portions of the attached software ("Contribution") are developed by
+ * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
+ *
+ * The Contribution is licensed pursuant to the OpenSSL open source
+ * license provided above.
+ *
+ * ECC cipher suite support in OpenSSL originally written by
+ * Vipul Gupta and Sumit Gupta of Sun Microsystems Laboratories.
+ *
+ */
+/* ====================================================================
+ * Copyright 2005 Nokia. All rights reserved.
+ *
+ * The portions of the attached software ("Contribution") is developed by
+ * Nokia Corporation and is licensed pursuant to the OpenSSL open source
+ * license.
+ *
+ * The Contribution, originally written by Mika Kousa and Pasi Eronen of
+ * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites
+ * support (see RFC 4279) to OpenSSL.
+ *
+ * No patent licenses or other rights except those expressly stated in
+ * the OpenSSL open source license shall be deemed granted or received
+ * expressly, by implication, estoppel, or otherwise.
+ *
+ * No assurances are provided by Nokia that the Contribution does not
+ * infringe the patent or other intellectual property rights of any third
+ * party or that the license provides you with all the necessary rights
+ * to make use of the Contribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN
+ * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA
+ * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY
+ * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
+ * OTHERWISE.
+ */
+
+#include <openssl/ssl.h>
+
+#include <assert.h>
+#include <string.h>
+
+#include <openssl/aead.h>
+#include <openssl/bn.h>
+#include <openssl/buf.h>
+#include <openssl/bytestring.h>
+#include <openssl/dh.h>
+#include <openssl/ec_key.h>
+#include <openssl/ecdsa.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/md5.h>
+#include <openssl/mem.h>
+#include <openssl/rand.h>
+
+#include "../crypto/internal.h"
+#include "internal.h"
+
+
+static int ssl3_send_client_hello(SSL_HANDSHAKE *hs);
+static int dtls1_get_hello_verify(SSL_HANDSHAKE *hs);
+static int ssl3_get_server_hello(SSL_HANDSHAKE *hs);
+static int ssl3_get_server_certificate(SSL_HANDSHAKE *hs);
+static int ssl3_get_cert_status(SSL_HANDSHAKE *hs);
+static int ssl3_verify_server_cert(SSL_HANDSHAKE *hs);
+static int ssl3_get_server_key_exchange(SSL_HANDSHAKE *hs);
+static int ssl3_get_certificate_request(SSL_HANDSHAKE *hs);
+static int ssl3_get_server_hello_done(SSL_HANDSHAKE *hs);
+static int ssl3_send_client_certificate(SSL_HANDSHAKE *hs);
+static int ssl3_send_client_key_exchange(SSL_HANDSHAKE *hs);
+static int ssl3_send_cert_verify(SSL_HANDSHAKE *hs);
+static int ssl3_send_next_proto(SSL_HANDSHAKE *hs);
+static int ssl3_send_channel_id(SSL_HANDSHAKE *hs);
+static int ssl3_get_new_session_ticket(SSL_HANDSHAKE *hs);
+
+int ssl3_connect(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ int ret = -1;
+
+ assert(ssl->handshake_func == ssl3_connect);
+ assert(!ssl->server);
+
+ for (;;) {
+ int state = hs->state;
+
+ switch (hs->state) {
+ case SSL_ST_INIT:
+ ssl_do_info_callback(ssl, SSL_CB_HANDSHAKE_START, 1);
+ hs->state = SSL3_ST_CW_CLNT_HELLO_A;
+ break;
+
+ case SSL3_ST_CW_CLNT_HELLO_A:
+ ret = ssl3_send_client_hello(hs);
+ if (ret <= 0) {
+ goto end;
+ }
+
+ if (!SSL_is_dtls(ssl) || ssl->d1->send_cookie) {
+ hs->next_state = SSL3_ST_CR_SRVR_HELLO_A;
+ } else {
+ hs->next_state = DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A;
+ }
+ hs->state = SSL3_ST_CW_FLUSH;
+ break;
+
+ case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A:
+ assert(SSL_is_dtls(ssl));
+ ret = dtls1_get_hello_verify(hs);
+ if (ret <= 0) {
+ 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;
+ }
+ break;
+
+ case SSL3_ST_CR_SRVR_HELLO_A:
+ ret = ssl3_get_server_hello(hs);
+ if (hs->state == SSL_ST_TLS13) {
+ break;
+ }
+ if (ret <= 0) {
+ goto end;
+ }
+
+ if (ssl->session != NULL) {
+ hs->state = SSL3_ST_CR_SESSION_TICKET_A;
+ } else {
+ hs->state = SSL3_ST_CR_CERT_A;
+ }
+ break;
+
+ case SSL3_ST_CR_CERT_A:
+ if (ssl_cipher_uses_certificate_auth(hs->new_cipher)) {
+ ret = ssl3_get_server_certificate(hs);
+ if (ret <= 0) {
+ goto end;
+ }
+ }
+ hs->state = SSL3_ST_CR_CERT_STATUS_A;
+ break;
+
+ case SSL3_ST_CR_CERT_STATUS_A:
+ if (hs->certificate_status_expected) {
+ ret = ssl3_get_cert_status(hs);
+ if (ret <= 0) {
+ goto end;
+ }
+ }
+ hs->state = SSL3_ST_VERIFY_SERVER_CERT;
+ break;
+
+ case SSL3_ST_VERIFY_SERVER_CERT:
+ if (ssl_cipher_uses_certificate_auth(hs->new_cipher)) {
+ ret = ssl3_verify_server_cert(hs);
+ if (ret <= 0) {
+ goto end;
+ }
+ }
+ hs->state = SSL3_ST_CR_KEY_EXCH_A;
+ break;
+
+ case SSL3_ST_CR_KEY_EXCH_A:
+ ret = ssl3_get_server_key_exchange(hs);
+ if (ret <= 0) {
+ goto end;
+ }
+ hs->state = SSL3_ST_CR_CERT_REQ_A;
+ break;
+
+ case SSL3_ST_CR_CERT_REQ_A:
+ if (ssl_cipher_uses_certificate_auth(hs->new_cipher)) {
+ ret = ssl3_get_certificate_request(hs);
+ if (ret <= 0) {
+ goto end;
+ }
+ }
+ hs->state = SSL3_ST_CR_SRVR_DONE_A;
+ break;
+
+ case SSL3_ST_CR_SRVR_DONE_A:
+ ret = ssl3_get_server_hello_done(hs);
+ if (ret <= 0) {
+ goto end;
+ }
+ ssl->method->received_flight(ssl);
+ hs->state = SSL3_ST_CW_CERT_A;
+ break;
+
+ case SSL3_ST_CW_CERT_A:
+ if (hs->cert_request) {
+ ret = ssl3_send_client_certificate(hs);
+ if (ret <= 0) {
+ goto end;
+ }
+ }
+ hs->state = SSL3_ST_CW_KEY_EXCH_A;
+ break;
+
+ case SSL3_ST_CW_KEY_EXCH_A:
+ ret = ssl3_send_client_key_exchange(hs);
+ if (ret <= 0) {
+ goto end;
+ }
+ hs->state = SSL3_ST_CW_CERT_VRFY_A;
+ break;
+
+ case SSL3_ST_CW_CERT_VRFY_A:
+ case SSL3_ST_CW_CERT_VRFY_B:
+ if (hs->cert_request && ssl_has_certificate(ssl)) {
+ ret = ssl3_send_cert_verify(hs);
+ if (ret <= 0) {
+ goto end;
+ }
+ }
+ hs->state = SSL3_ST_CW_CHANGE;
+ break;
+
+ case SSL3_ST_CW_CHANGE:
+ if (!ssl->method->add_change_cipher_spec(ssl) ||
+ !tls1_change_cipher_state(hs, SSL3_CHANGE_CIPHER_CLIENT_WRITE)) {
+ ret = -1;
+ goto end;
+ }
+
+ hs->state = SSL3_ST_CW_NEXT_PROTO_A;
+ break;
+
+ case SSL3_ST_CW_NEXT_PROTO_A:
+ if (hs->next_proto_neg_seen) {
+ ret = ssl3_send_next_proto(hs);
+ if (ret <= 0) {
+ goto end;
+ }
+ }
+ hs->state = SSL3_ST_CW_CHANNEL_ID_A;
+ break;
+
+ case SSL3_ST_CW_CHANNEL_ID_A:
+ if (ssl->s3->tlsext_channel_id_valid) {
+ ret = ssl3_send_channel_id(hs);
+ if (ret <= 0) {
+ goto end;
+ }
+ }
+ hs->state = SSL3_ST_CW_FINISHED_A;
+ break;
+
+ case SSL3_ST_CW_FINISHED_A:
+ ret = ssl3_send_finished(hs);
+ if (ret <= 0) {
+ goto end;
+ }
+ hs->state = SSL3_ST_CW_FLUSH;
+
+ if (ssl->session != NULL) {
+ hs->next_state = SSL3_ST_FINISH_CLIENT_HANDSHAKE;
+ } else {
+ /* This is a non-resumption handshake. If it involves ChannelID, then
+ * record the handshake hashes at this point in the session so that
+ * any resumption of this session with ChannelID can sign those
+ * hashes. */
+ ret = tls1_record_handshake_hashes_for_channel_id(hs);
+ if (ret <= 0) {
+ goto end;
+ }
+ if ((SSL_get_mode(ssl) & SSL_MODE_ENABLE_FALSE_START) &&
+ ssl3_can_false_start(ssl) &&
+ /* No False Start on renegotiation (would complicate the state
+ * machine). */
+ !ssl->s3->initial_handshake_complete) {
+ hs->next_state = SSL3_ST_FALSE_START;
+ } else {
+ hs->next_state = SSL3_ST_CR_SESSION_TICKET_A;
+ }
+ }
+ break;
+
+ case SSL3_ST_FALSE_START:
+ hs->state = SSL3_ST_CR_SESSION_TICKET_A;
+ hs->in_false_start = 1;
+ ret = 1;
+ goto end;
+
+ case SSL3_ST_CR_SESSION_TICKET_A:
+ if (hs->ticket_expected) {
+ ret = ssl3_get_new_session_ticket(hs);
+ if (ret <= 0) {
+ goto end;
+ }
+ }
+ hs->state = SSL3_ST_CR_CHANGE;
+ break;
+
+ case SSL3_ST_CR_CHANGE:
+ ret = ssl->method->read_change_cipher_spec(ssl);
+ if (ret <= 0) {
+ goto end;
+ }
+
+ if (!tls1_change_cipher_state(hs, SSL3_CHANGE_CIPHER_CLIENT_READ)) {
+ ret = -1;
+ goto end;
+ }
+ hs->state = SSL3_ST_CR_FINISHED_A;
+ break;
+
+ case SSL3_ST_CR_FINISHED_A:
+ ret = ssl3_get_finished(hs);
+ if (ret <= 0) {
+ goto end;
+ }
+ ssl->method->received_flight(ssl);
+
+ if (ssl->session != NULL) {
+ hs->state = SSL3_ST_CW_CHANGE;
+ } else {
+ hs->state = SSL3_ST_FINISH_CLIENT_HANDSHAKE;
+ }
+ break;
+
+ case SSL3_ST_CW_FLUSH:
+ ret = ssl->method->flush_flight(ssl);
+ if (ret <= 0) {
+ 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:
+ ret = tls13_handshake(hs);
+ if (ret <= 0) {
+ goto end;
+ }
+ hs->state = SSL3_ST_FINISH_CLIENT_HANDSHAKE;
+ break;
+
+ case SSL3_ST_FINISH_CLIENT_HANDSHAKE:
+ ssl->method->release_current_message(ssl, 1 /* free_buffer */);
+
+ SSL_SESSION_free(ssl->s3->established_session);
+ if (ssl->session != NULL) {
+ SSL_SESSION_up_ref(ssl->session);
+ ssl->s3->established_session = ssl->session;
+ } else {
+ /* We make a copy of the session in order to maintain the immutability
+ * of the new established_session due to False Start. The caller may
+ * have taken a reference to the temporary session. */
+ ssl->s3->established_session =
+ SSL_SESSION_dup(hs->new_session, SSL_SESSION_DUP_ALL);
+ if (ssl->s3->established_session == NULL) {
+ ret = -1;
+ goto end;
+ }
+ ssl->s3->established_session->not_resumable = 0;
+
+ SSL_SESSION_free(hs->new_session);
+ hs->new_session = NULL;
+ }
+
+ hs->state = SSL_ST_OK;
+ break;
+
+ case SSL_ST_OK: {
+ const int is_initial_handshake = !ssl->s3->initial_handshake_complete;
+ ssl->s3->initial_handshake_complete = 1;
+ if (is_initial_handshake) {
+ /* Renegotiations do not participate in session resumption. */
+ ssl_update_cache(hs, SSL_SESS_CACHE_CLIENT);
+ }
+
+ ret = 1;
+ ssl_do_info_callback(ssl, SSL_CB_HANDSHAKE_DONE, 1);
+ goto end;
+ }
+
+ default:
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_STATE);
+ ret = -1;
+ goto end;
+ }
+
+ if (hs->state != state) {
+ ssl_do_info_callback(ssl, SSL_CB_CONNECT_LOOP, 1);
+ }
+ }
+
+end:
+ ssl_do_info_callback(ssl, SSL_CB_CONNECT_EXIT, ret);
+ return ret;
+}
+
+uint16_t ssl_get_grease_value(const SSL *ssl, enum ssl_grease_index_t index) {
+ /* Use the client_random for entropy. This both avoids calling |RAND_bytes| on
+ * a single byte repeatedly and ensures the values are deterministic. This
+ * allows the same ClientHello be sent twice for a HelloRetryRequest or the
+ * same group be advertised in both supported_groups and key_shares. */
+ uint16_t ret = ssl->s3->client_random[index];
+ /* This generates a random value of the form 0xωaωa, for all 0 ≤ ω < 16. */
+ ret = (ret & 0xf0) | 0x0a;
+ ret |= ret << 8;
+ return ret;
+}
+
+/* ssl_get_client_disabled sets |*out_mask_a| and |*out_mask_k| to masks of
+ * disabled algorithms. */
+static void ssl_get_client_disabled(SSL *ssl, uint32_t *out_mask_a,
+ uint32_t *out_mask_k) {
+ int have_rsa = 0, have_ecdsa = 0;
+ *out_mask_a = 0;
+ *out_mask_k = 0;
+
+ /* Now go through all signature algorithms seeing if we support any for RSA or
+ * ECDSA. Do this for all versions not just TLS 1.2. */
+ const uint16_t *sigalgs;
+ size_t num_sigalgs = tls12_get_verify_sigalgs(ssl, &sigalgs);
+ for (size_t i = 0; i < num_sigalgs; i++) {
+ switch (sigalgs[i]) {
+ case SSL_SIGN_RSA_PSS_SHA512:
+ case SSL_SIGN_RSA_PSS_SHA384:
+ case SSL_SIGN_RSA_PSS_SHA256:
+ case SSL_SIGN_RSA_PKCS1_SHA512:
+ case SSL_SIGN_RSA_PKCS1_SHA384:
+ case SSL_SIGN_RSA_PKCS1_SHA256:
+ case SSL_SIGN_RSA_PKCS1_SHA1:
+ have_rsa = 1;
+ break;
+
+ case SSL_SIGN_ECDSA_SECP521R1_SHA512:
+ case SSL_SIGN_ECDSA_SECP384R1_SHA384:
+ case SSL_SIGN_ECDSA_SECP256R1_SHA256:
+ case SSL_SIGN_ECDSA_SHA1:
+ have_ecdsa = 1;
+ break;
+ }
+ }
+
+ /* Disable auth if we don't include any appropriate signature algorithms. */
+ if (!have_rsa) {
+ *out_mask_a |= SSL_aRSA;
+ }
+ if (!have_ecdsa) {
+ *out_mask_a |= SSL_aECDSA;
+ }
+
+ /* PSK requires a client callback. */
+ if (ssl->psk_client_callback == NULL) {
+ *out_mask_a |= SSL_aPSK;
+ *out_mask_k |= SSL_kPSK;
+ }
+}
+
+static int ssl_write_client_cipher_list(SSL *ssl, CBB *out,
+ uint16_t min_version,
+ uint16_t max_version) {
+ uint32_t mask_a, mask_k;
+ ssl_get_client_disabled(ssl, &mask_a, &mask_k);
+
+ CBB child;
+ if (!CBB_add_u16_length_prefixed(out, &child)) {
+ return 0;
+ }
+
+ /* Add a fake cipher suite. See draft-davidben-tls-grease-01. */
+ if (ssl->ctx->grease_enabled &&
+ !CBB_add_u16(&child, ssl_get_grease_value(ssl, ssl_grease_cipher))) {
+ return 0;
+ }
+
+ /* Add TLS 1.3 ciphers. Order ChaCha20-Poly1305 relative to AES-GCM based on
+ * hardware support. */
+ if (max_version >= TLS1_3_VERSION) {
+ if (!EVP_has_aes_hardware() &&
+ !CBB_add_u16(&child, TLS1_CK_CHACHA20_POLY1305_SHA256 & 0xffff)) {
+ return 0;
+ }
+ if (!CBB_add_u16(&child, TLS1_CK_AES_128_GCM_SHA256 & 0xffff) ||
+ !CBB_add_u16(&child, TLS1_CK_AES_256_GCM_SHA384 & 0xffff)) {
+ return 0;
+ }
+ if (EVP_has_aes_hardware() &&
+ !CBB_add_u16(&child, TLS1_CK_CHACHA20_POLY1305_SHA256 & 0xffff)) {
+ return 0;
+ }
+ }
+
+ if (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);
+ /* Skip disabled ciphers */
+ if ((cipher->algorithm_mkey & mask_k) ||
+ (cipher->algorithm_auth & mask_a)) {
+ continue;
+ }
+ if (SSL_CIPHER_get_min_version(cipher) > max_version ||
+ SSL_CIPHER_get_max_version(cipher) < min_version) {
+ continue;
+ }
+ any_enabled = 1;
+ if (!CBB_add_u16(&child, ssl_cipher_get_value(cipher))) {
+ return 0;
+ }
+ }
+
+ /* If all ciphers were disabled, return the error to the caller. */
+ if (!any_enabled && max_version < TLS1_3_VERSION) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CIPHERS_AVAILABLE);
+ return 0;
+ }
+ }
+
+ /* For SSLv3, the SCSV is added. Otherwise the renegotiation extension is
+ * added. */
+ if (max_version == SSL3_VERSION &&
+ !ssl->s3->initial_handshake_complete) {
+ if (!CBB_add_u16(&child, SSL3_CK_SCSV & 0xffff)) {
+ return 0;
+ }
+ }
+
+ if (ssl->mode & SSL_MODE_SEND_FALLBACK_SCSV) {
+ if (!CBB_add_u16(&child, SSL3_CK_FALLBACK_SCSV & 0xffff)) {
+ return 0;
+ }
+ }
+
+ return CBB_flush(out);
+}
+
+int ssl_write_client_hello(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ uint16_t min_version, max_version;
+ if (!ssl_get_version_range(ssl, &min_version, &max_version)) {
+ return 0;
+ }
+
+ CBB cbb, body;
+ if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_CLIENT_HELLO)) {
+ goto err;
+ }
+
+ /* Renegotiations do not participate in session resumption. */
+ int has_session = ssl->session != NULL &&
+ !ssl->s3->initial_handshake_complete;
+
+ CBB child;
+ if (!CBB_add_u16(&body, hs->client_version) ||
+ !CBB_add_bytes(&body, ssl->s3->client_random, SSL3_RANDOM_SIZE) ||
+ !CBB_add_u8_length_prefixed(&body, &child) ||
+ (has_session &&
+ !CBB_add_bytes(&child, ssl->session->session_id,
+ ssl->session->session_id_length))) {
+ goto err;
+ }
+
+ if (SSL_is_dtls(ssl)) {
+ if (!CBB_add_u8_length_prefixed(&body, &child) ||
+ !CBB_add_bytes(&child, ssl->d1->cookie, ssl->d1->cookie_len)) {
+ goto err;
+ }
+ }
+
+ size_t header_len =
+ SSL_is_dtls(ssl) ? DTLS1_HM_HEADER_LENGTH : SSL3_HM_HEADER_LENGTH;
+ if (!ssl_write_client_cipher_list(ssl, &body, min_version, max_version) ||
+ !CBB_add_u8(&body, 1 /* one compression method */) ||
+ !CBB_add_u8(&body, 0 /* null compression */) ||
+ !ssl_add_clienthello_tlsext(hs, &body, header_len + CBB_len(&body))) {
+ goto err;
+ }
+
+ uint8_t *msg = NULL;
+ size_t len;
+ if (!ssl->method->finish_message(ssl, &cbb, &msg, &len)) {
+ goto err;
+ }
+
+ /* Now that the length prefixes have been computed, fill in the placeholder
+ * PSK binder. */
+ if (hs->needs_psk_binder &&
+ !tls13_write_psk_binder(hs, msg, len)) {
+ OPENSSL_free(msg);
+ goto err;
+ }
+
+ return ssl->method->add_message(ssl, msg, len);
+
+ err:
+ CBB_cleanup(&cbb);
+ return 0;
+}
+
+static int ssl3_send_client_hello(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ /* The handshake buffer is reset on every ClientHello. Notably, in DTLS, we
+ * may send multiple ClientHellos if we receive HelloVerifyRequest. */
+ if (!SSL_TRANSCRIPT_init(&hs->transcript)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
+
+ uint16_t min_version, max_version;
+ if (!ssl_get_version_range(ssl, &min_version, &max_version)) {
+ return -1;
+ }
+
+ uint16_t max_wire_version = ssl->method->version_to_wire(max_version);
+ assert(hs->state == SSL3_ST_CW_CLNT_HELLO_A);
+ if (!ssl->s3->have_version) {
+ ssl->version = max_wire_version;
+ }
+
+ /* Always advertise the ClientHello version from the original maximum version,
+ * even on renegotiation. The static RSA key exchange uses this field, and
+ * some servers fail when it changes across handshakes. */
+ hs->client_version = max_wire_version;
+ if (max_version >= TLS1_3_VERSION) {
+ hs->client_version = ssl->method->version_to_wire(TLS1_2_VERSION);
+ }
+
+ /* If the configured session has expired or was created at a disabled
+ * version, drop it. */
+ if (ssl->session != NULL) {
+ uint16_t session_version;
+ if (ssl->session->is_server ||
+ !ssl->method->version_from_wire(&session_version,
+ ssl->session->ssl_version) ||
+ (session_version < TLS1_3_VERSION &&
+ ssl->session->session_id_length == 0) ||
+ ssl->session->not_resumable ||
+ !ssl_session_is_time_valid(ssl, ssl->session) ||
+ session_version < min_version || session_version > max_version) {
+ ssl_set_session(ssl, NULL);
+ }
+ }
+
+ /* If resending the ClientHello in DTLS after a HelloVerifyRequest, don't
+ * renegerate the client_random. The random must be reused. */
+ if ((!SSL_is_dtls(ssl) || !ssl->d1->send_cookie) &&
+ !RAND_bytes(ssl->s3->client_random, sizeof(ssl->s3->client_random))) {
+ return -1;
+ }
+
+ if (!ssl_write_client_hello(hs)) {
+ return -1;
+ }
+
+ return 1;
+}
+
+static int dtls1_get_hello_verify(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ int al;
+ CBS hello_verify_request, cookie;
+ uint16_t server_version;
+
+ int ret = ssl->method->ssl_get_message(ssl);
+ if (ret <= 0) {
+ return ret;
+ }
+
+ if (ssl->s3->tmp.message_type != DTLS1_MT_HELLO_VERIFY_REQUEST) {
+ ssl->d1->send_cookie = 0;
+ ssl->s3->tmp.reuse_message = 1;
+ return 1;
+ }
+
+ CBS_init(&hello_verify_request, ssl->init_msg, ssl->init_num);
+ if (!CBS_get_u16(&hello_verify_request, &server_version) ||
+ !CBS_get_u8_length_prefixed(&hello_verify_request, &cookie) ||
+ CBS_len(&hello_verify_request) != 0) {
+ al = SSL_AD_DECODE_ERROR;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ goto f_err;
+ }
+
+ if (CBS_len(&cookie) > sizeof(ssl->d1->cookie)) {
+ al = SSL_AD_ILLEGAL_PARAMETER;
+ goto f_err;
+ }
+
+ OPENSSL_memcpy(ssl->d1->cookie, CBS_data(&cookie), CBS_len(&cookie));
+ ssl->d1->cookie_len = CBS_len(&cookie);
+
+ ssl->d1->send_cookie = 1;
+ return 1;
+
+f_err:
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, al);
+ return -1;
+}
+
+static int ssl3_get_server_hello(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ int al = SSL_AD_INTERNAL_ERROR;
+ CBS server_hello, server_random, session_id;
+ uint16_t server_wire_version, cipher_suite;
+ uint8_t compression_method;
+
+ int ret = ssl->method->ssl_get_message(ssl);
+ if (ret <= 0) {
+ uint32_t err = ERR_peek_error();
+ if (ERR_GET_LIB(err) == ERR_LIB_SSL &&
+ ERR_GET_REASON(err) == SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE) {
+ /* Add a dedicated error code to the queue for a handshake_failure alert
+ * in response to ClientHello. This matches NSS's client behavior and
+ * gives a better error on a (probable) failure to negotiate initial
+ * parameters. Note: this error code comes after the original one.
+ *
+ * See https://crbug.com/446505. */
+ OPENSSL_PUT_ERROR(SSL, SSL_R_HANDSHAKE_FAILURE_ON_CLIENT_HELLO);
+ }
+ return ret;
+ }
+
+ if (ssl->s3->tmp.message_type != SSL3_MT_SERVER_HELLO &&
+ ssl->s3->tmp.message_type != SSL3_MT_HELLO_RETRY_REQUEST) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ CBS_init(&server_hello, ssl->init_msg, ssl->init_num);
+
+ if (!CBS_get_u16(&server_hello, &server_wire_version)) {
+ al = SSL_AD_DECODE_ERROR;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ goto f_err;
+ }
+
+ uint16_t min_version, max_version, server_version;
+ if (!ssl_get_version_range(ssl, &min_version, &max_version) ||
+ !ssl->method->version_from_wire(&server_version, server_wire_version) ||
+ server_version < min_version || server_version > max_version) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_PROTOCOL);
+ al = SSL_AD_PROTOCOL_VERSION;
+ goto f_err;
+ }
+
+ assert(ssl->s3->have_version == ssl->s3->initial_handshake_complete);
+ if (!ssl->s3->have_version) {
+ ssl->version = server_wire_version;
+ /* At this point, the connection's version is known and ssl->version is
+ * fixed. Begin enforcing the record-layer version. */
+ ssl->s3->have_version = 1;
+ } else if (server_wire_version != ssl->version) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SSL_VERSION);
+ al = SSL_AD_PROTOCOL_VERSION;
+ goto f_err;
+ }
+
+ if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) {
+ hs->state = SSL_ST_TLS13;
+ hs->do_tls13_handshake = tls13_client_handshake;
+ return 1;
+ }
+
+ ssl_clear_tls13_state(hs);
+
+ if (!ssl_check_message_type(ssl, SSL3_MT_SERVER_HELLO)) {
+ return -1;
+ }
+
+ if (!CBS_get_bytes(&server_hello, &server_random, SSL3_RANDOM_SIZE) ||
+ !CBS_get_u8_length_prefixed(&server_hello, &session_id) ||
+ CBS_len(&session_id) > SSL3_SESSION_ID_SIZE ||
+ !CBS_get_u16(&server_hello, &cipher_suite) ||
+ !CBS_get_u8(&server_hello, &compression_method)) {
+ al = SSL_AD_DECODE_ERROR;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ goto f_err;
+ }
+
+ /* Copy over the server random. */
+ OPENSSL_memcpy(ssl->s3->server_random, CBS_data(&server_random), SSL3_RANDOM_SIZE);
+
+ /* TODO(davidben): Implement the TLS 1.1 and 1.2 downgrade sentinels once TLS
+ * 1.3 is finalized and we are not implementing a draft version. */
+
+ if (!ssl->s3->initial_handshake_complete && ssl->session != NULL &&
+ ssl->session->session_id_length != 0 &&
+ CBS_mem_equal(&session_id, ssl->session->session_id,
+ ssl->session->session_id_length)) {
+ ssl->s3->session_reused = 1;
+ } else {
+ /* The session wasn't resumed. Create a fresh SSL_SESSION to
+ * fill out. */
+ ssl_set_session(ssl, NULL);
+ if (!ssl_get_new_session(hs, 0 /* client */)) {
+ goto f_err;
+ }
+ /* Note: session_id could be empty. */
+ hs->new_session->session_id_length = CBS_len(&session_id);
+ OPENSSL_memcpy(hs->new_session->session_id, CBS_data(&session_id),
+ CBS_len(&session_id));
+ }
+
+ const SSL_CIPHER *c = SSL_get_cipher_by_value(cipher_suite);
+ if (c == NULL) {
+ /* unknown cipher */
+ al = SSL_AD_ILLEGAL_PARAMETER;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CIPHER_RETURNED);
+ goto f_err;
+ }
+
+ /* The cipher must be allowed in the selected version and enabled. */
+ uint32_t mask_a, mask_k;
+ ssl_get_client_disabled(ssl, &mask_a, &mask_k);
+ if ((c->algorithm_mkey & mask_k) || (c->algorithm_auth & mask_a) ||
+ SSL_CIPHER_get_min_version(c) > ssl3_protocol_version(ssl) ||
+ SSL_CIPHER_get_max_version(c) < ssl3_protocol_version(ssl) ||
+ !sk_SSL_CIPHER_find(SSL_get_ciphers(ssl), NULL, c)) {
+ al = SSL_AD_ILLEGAL_PARAMETER;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CIPHER_RETURNED);
+ goto f_err;
+ }
+
+ if (ssl->session != NULL) {
+ if (ssl->session->ssl_version != ssl->version) {
+ al = SSL_AD_ILLEGAL_PARAMETER;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_OLD_SESSION_VERSION_NOT_RETURNED);
+ goto f_err;
+ }
+ if (ssl->session->cipher != c) {
+ al = SSL_AD_ILLEGAL_PARAMETER;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED);
+ goto f_err;
+ }
+ if (!ssl_session_is_context_valid(ssl, ssl->session)) {
+ /* This is actually a client application bug. */
+ al = SSL_AD_ILLEGAL_PARAMETER;
+ OPENSSL_PUT_ERROR(SSL,
+ SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT);
+ goto f_err;
+ }
+ } else {
+ hs->new_session->cipher = c;
+ }
+ hs->new_cipher = c;
+
+ /* Now that the cipher is known, initialize the handshake hash and hash the
+ * ServerHello. */
+ if (!SSL_TRANSCRIPT_init_hash(&hs->transcript, ssl3_protocol_version(ssl),
+ c->algorithm_prf) ||
+ !ssl_hash_current_message(hs)) {
+ goto f_err;
+ }
+
+ /* If doing a full handshake, the server may request a client certificate
+ * which requires hashing the handshake transcript. Otherwise, the handshake
+ * buffer may be released. */
+ if (ssl->session != NULL ||
+ !ssl_cipher_uses_certificate_auth(hs->new_cipher)) {
+ SSL_TRANSCRIPT_free_buffer(&hs->transcript);
+ }
+
+ /* Only the NULL compression algorithm is supported. */
+ if (compression_method != 0) {
+ al = SSL_AD_ILLEGAL_PARAMETER;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM);
+ goto f_err;
+ }
+
+ /* TLS extensions */
+ if (!ssl_parse_serverhello_tlsext(hs, &server_hello)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT);
+ goto err;
+ }
+
+ /* There should be nothing left over in the record. */
+ if (CBS_len(&server_hello) != 0) {
+ /* wrong packet length */
+ al = SSL_AD_DECODE_ERROR;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ goto f_err;
+ }
+
+ if (ssl->session != NULL &&
+ hs->extended_master_secret != ssl->session->extended_master_secret) {
+ al = SSL_AD_HANDSHAKE_FAILURE;
+ if (ssl->session->extended_master_secret) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION);
+ } else {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_RESUMED_NON_EMS_SESSION_WITH_EMS_EXTENSION);
+ }
+ goto f_err;
+ }
+
+ return 1;
+
+f_err:
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, al);
+err:
+ return -1;
+}
+
+static int ssl3_get_server_certificate(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ int ret = ssl->method->ssl_get_message(ssl);
+ if (ret <= 0) {
+ return ret;
+ }
+
+ if (!ssl_check_message_type(ssl, SSL3_MT_CERTIFICATE) ||
+ !ssl_hash_current_message(hs)) {
+ return -1;
+ }
+
+ CBS cbs;
+ 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);
+ EVP_PKEY_free(hs->peer_pubkey);
+ hs->peer_pubkey = NULL;
+ hs->new_session->certs = ssl_parse_cert_chain(&alert, &hs->peer_pubkey, NULL,
+ &cbs, ssl->ctx->pool);
+ if (hs->new_session->certs == NULL) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
+ return -1;
+ }
+
+ if (sk_CRYPTO_BUFFER_num(hs->new_session->certs) == 0 ||
+ CBS_len(&cbs) != 0 ||
+ !ssl->ctx->x509_method->session_cache_objects(hs->new_session)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ return -1;
+ }
+
+ if (!ssl_check_leaf_certificate(
+ hs, hs->peer_pubkey,
+ sk_CRYPTO_BUFFER_value(hs->new_session->certs, 0))) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+ return -1;
+ }
+
+ /* Disallow the server certificate from changing during a renegotiation. See
+ * https://mitls.org/pages/attacks/3SHAKE. We never resume on renegotiation,
+ * so this check is sufficient. */
+ if (ssl->s3->established_session != NULL) {
+ if (sk_CRYPTO_BUFFER_num(ssl->s3->established_session->certs) !=
+ sk_CRYPTO_BUFFER_num(hs->new_session->certs)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_SERVER_CERT_CHANGED);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+ return -1;
+ }
+
+ for (size_t i = 0; i < sk_CRYPTO_BUFFER_num(hs->new_session->certs); i++) {
+ const CRYPTO_BUFFER *old_cert =
+ sk_CRYPTO_BUFFER_value(ssl->s3->established_session->certs, i);
+ const CRYPTO_BUFFER *new_cert =
+ sk_CRYPTO_BUFFER_value(hs->new_session->certs, i);
+ if (CRYPTO_BUFFER_len(old_cert) != CRYPTO_BUFFER_len(new_cert) ||
+ OPENSSL_memcmp(CRYPTO_BUFFER_data(old_cert),
+ CRYPTO_BUFFER_data(new_cert),
+ CRYPTO_BUFFER_len(old_cert)) != 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_SERVER_CERT_CHANGED);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+ return -1;
+ }
+ }
+ }
+
+ return 1;
+}
+
+static int ssl3_get_cert_status(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ int al;
+ CBS certificate_status, ocsp_response;
+ uint8_t status_type;
+
+ int ret = ssl->method->ssl_get_message(ssl);
+ if (ret <= 0) {
+ return ret;
+ }
+
+ if (ssl->s3->tmp.message_type != SSL3_MT_CERTIFICATE_STATUS) {
+ /* A server may send status_request in ServerHello and then change
+ * its mind about sending CertificateStatus. */
+ ssl->s3->tmp.reuse_message = 1;
+ return 1;
+ }
+
+ if (!ssl_hash_current_message(hs)) {
+ return -1;
+ }
+
+ CBS_init(&certificate_status, ssl->init_msg, ssl->init_num);
+ if (!CBS_get_u8(&certificate_status, &status_type) ||
+ status_type != TLSEXT_STATUSTYPE_ocsp ||
+ !CBS_get_u24_length_prefixed(&certificate_status, &ocsp_response) ||
+ CBS_len(&ocsp_response) == 0 ||
+ CBS_len(&certificate_status) != 0) {
+ al = SSL_AD_DECODE_ERROR;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ goto f_err;
+ }
+
+ if (!CBS_stow(&ocsp_response, &hs->new_session->ocsp_response,
+ &hs->new_session->ocsp_response_length)) {
+ al = SSL_AD_INTERNAL_ERROR;
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto f_err;
+ }
+ return 1;
+
+f_err:
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, al);
+ return -1;
+}
+
+static int ssl3_verify_server_cert(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ if (!ssl->ctx->x509_method->session_verify_cert_chain(hs->new_session, ssl)) {
+ return -1;
+ }
+
+ return 1;
+}
+
+static int ssl3_get_server_key_exchange(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ int al;
+ DH *dh = NULL;
+ EC_KEY *ecdh = NULL;
+ EC_POINT *srvr_ecpoint = NULL;
+
+ int ret = ssl->method->ssl_get_message(ssl);
+ if (ret <= 0) {
+ return ret;
+ }
+
+ if (ssl->s3->tmp.message_type != SSL3_MT_SERVER_KEY_EXCHANGE) {
+ /* Some ciphers (pure PSK) have an optional ServerKeyExchange message. */
+ if (ssl_cipher_requires_server_key_exchange(hs->new_cipher)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ ssl->s3->tmp.reuse_message = 1;
+ return 1;
+ }
+
+ if (!ssl_hash_current_message(hs)) {
+ return -1;
+ }
+
+ /* Retain a copy of the original CBS to compute the signature over. */
+ CBS server_key_exchange;
+ CBS_init(&server_key_exchange, ssl->init_msg, ssl->init_num);
+ CBS server_key_exchange_orig = server_key_exchange;
+
+ uint32_t alg_k = hs->new_cipher->algorithm_mkey;
+ uint32_t alg_a = hs->new_cipher->algorithm_auth;
+
+ if (alg_a & SSL_aPSK) {
+ CBS psk_identity_hint;
+
+ /* Each of the PSK key exchanges begins with a psk_identity_hint. */
+ if (!CBS_get_u16_length_prefixed(&server_key_exchange,
+ &psk_identity_hint)) {
+ al = SSL_AD_DECODE_ERROR;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ goto f_err;
+ }
+
+ /* Store PSK identity hint for later use, hint is used in
+ * ssl3_send_client_key_exchange. Assume that the maximum length of a PSK
+ * identity hint can be as long as the maximum length of a PSK identity.
+ * Also do not allow NULL characters; identities are saved as C strings.
+ *
+ * TODO(davidben): Should invalid hints be ignored? It's a hint rather than
+ * a specific identity. */
+ if (CBS_len(&psk_identity_hint) > PSK_MAX_IDENTITY_LEN ||
+ CBS_contains_zero_byte(&psk_identity_hint)) {
+ al = SSL_AD_HANDSHAKE_FAILURE;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DATA_LENGTH_TOO_LONG);
+ goto f_err;
+ }
+
+ /* Save non-empty identity hints as a C string. Empty identity hints we
+ * treat as missing. Plain PSK makes it possible to send either no hint
+ * (omit ServerKeyExchange) or an empty hint, while ECDHE_PSK can only spell
+ * empty hint. Having different capabilities is odd, so we interpret empty
+ * and missing as identical. */
+ if (CBS_len(&psk_identity_hint) != 0 &&
+ !CBS_strdup(&psk_identity_hint, &hs->peer_psk_identity_hint)) {
+ al = SSL_AD_INTERNAL_ERROR;
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto f_err;
+ }
+ }
+
+ if (alg_k & SSL_kDHE) {
+ CBS dh_p, dh_g, dh_Ys;
+ if (!CBS_get_u16_length_prefixed(&server_key_exchange, &dh_p) ||
+ CBS_len(&dh_p) == 0 ||
+ !CBS_get_u16_length_prefixed(&server_key_exchange, &dh_g) ||
+ CBS_len(&dh_g) == 0 ||
+ !CBS_get_u16_length_prefixed(&server_key_exchange, &dh_Ys) ||
+ CBS_len(&dh_Ys) == 0) {
+ al = SSL_AD_DECODE_ERROR;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ goto f_err;
+ }
+
+ dh = DH_new();
+ if (dh == NULL) {
+ goto err;
+ }
+
+ dh->p = BN_bin2bn(CBS_data(&dh_p), CBS_len(&dh_p), NULL);
+ dh->g = BN_bin2bn(CBS_data(&dh_g), CBS_len(&dh_g), NULL);
+ if (dh->p == NULL || dh->g == NULL) {
+ goto err;
+ }
+
+ unsigned bits = DH_num_bits(dh);
+ if (bits < 1024) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_DH_P_LENGTH);
+ goto err;
+ } else if (bits > 4096) {
+ /* Overly large DHE groups are prohibitively expensive, so enforce a limit
+ * to prevent a server from causing us to perform too expensive of a
+ * computation. */
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DH_P_TOO_LONG);
+ goto err;
+ }
+
+ SSL_ECDH_CTX_init_for_dhe(&hs->ecdh_ctx, dh);
+ dh = NULL;
+
+ /* Save the peer public key for later. */
+ if (!CBS_stow(&dh_Ys, &hs->peer_key, &hs->peer_key_len)) {
+ goto err;
+ }
+ } else if (alg_k & SSL_kECDHE) {
+ /* Parse the server parameters. */
+ uint8_t group_type;
+ uint16_t group_id;
+ CBS point;
+ if (!CBS_get_u8(&server_key_exchange, &group_type) ||
+ group_type != NAMED_CURVE_TYPE ||
+ !CBS_get_u16(&server_key_exchange, &group_id) ||
+ !CBS_get_u8_length_prefixed(&server_key_exchange, &point)) {
+ al = SSL_AD_DECODE_ERROR;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ goto f_err;
+ }
+ hs->new_session->group_id = group_id;
+
+ /* Ensure the group is consistent with preferences. */
+ if (!tls1_check_group_id(ssl, group_id)) {
+ al = SSL_AD_ILLEGAL_PARAMETER;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE);
+ goto f_err;
+ }
+
+ /* Initialize ECDH and save the peer public key for later. */
+ if (!SSL_ECDH_CTX_init(&hs->ecdh_ctx, group_id) ||
+ !CBS_stow(&point, &hs->peer_key, &hs->peer_key_len)) {
+ goto err;
+ }
+ } else if (!(alg_k & SSL_kPSK)) {
+ al = SSL_AD_UNEXPECTED_MESSAGE;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE);
+ goto f_err;
+ }
+
+ /* At this point, |server_key_exchange| contains the signature, if any, while
+ * |server_key_exchange_orig| contains the entire message. From that, derive
+ * a CBS containing just the parameter. */
+ CBS parameter;
+ CBS_init(&parameter, CBS_data(&server_key_exchange_orig),
+ CBS_len(&server_key_exchange_orig) - CBS_len(&server_key_exchange));
+
+ /* ServerKeyExchange should be signed by the server's public key. */
+ if (ssl_cipher_uses_certificate_auth(hs->new_cipher)) {
+ uint16_t signature_algorithm = 0;
+ if (ssl3_protocol_version(ssl) >= TLS1_2_VERSION) {
+ if (!CBS_get_u16(&server_key_exchange, &signature_algorithm)) {
+ al = SSL_AD_DECODE_ERROR;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ goto f_err;
+ }
+ if (!tls12_check_peer_sigalg(ssl, &al, signature_algorithm)) {
+ goto f_err;
+ }
+ hs->new_session->peer_signature_algorithm = signature_algorithm;
+ } else if (hs->peer_pubkey->type == EVP_PKEY_RSA) {
+ signature_algorithm = SSL_SIGN_RSA_PKCS1_MD5_SHA1;
+ } else if (hs->peer_pubkey->type == EVP_PKEY_EC) {
+ signature_algorithm = SSL_SIGN_ECDSA_SHA1;
+ } else {
+ al = SSL_AD_UNSUPPORTED_CERTIFICATE;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE);
+ goto f_err;
+ }
+
+ /* The last field in |server_key_exchange| is the signature. */
+ CBS signature;
+ if (!CBS_get_u16_length_prefixed(&server_key_exchange, &signature) ||
+ CBS_len(&server_key_exchange) != 0) {
+ al = SSL_AD_DECODE_ERROR;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ goto f_err;
+ }
+
+ CBB transcript;
+ uint8_t *transcript_data;
+ size_t transcript_len;
+ if (!CBB_init(&transcript, 2*SSL3_RANDOM_SIZE + CBS_len(&parameter)) ||
+ !CBB_add_bytes(&transcript, ssl->s3->client_random, SSL3_RANDOM_SIZE) ||
+ !CBB_add_bytes(&transcript, ssl->s3->server_random, SSL3_RANDOM_SIZE) ||
+ !CBB_add_bytes(&transcript, CBS_data(&parameter), CBS_len(&parameter)) ||
+ !CBB_finish(&transcript, &transcript_data, &transcript_len)) {
+ CBB_cleanup(&transcript);
+ al = SSL_AD_INTERNAL_ERROR;
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ goto f_err;
+ }
+
+ int sig_ok = ssl_public_key_verify(
+ ssl, CBS_data(&signature), CBS_len(&signature), signature_algorithm,
+ hs->peer_pubkey, transcript_data, transcript_len);
+ OPENSSL_free(transcript_data);
+
+#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+ sig_ok = 1;
+ ERR_clear_error();
+#endif
+ if (!sig_ok) {
+ /* bad signature */
+ al = SSL_AD_DECRYPT_ERROR;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SIGNATURE);
+ goto f_err;
+ }
+ } else {
+ /* PSK ciphers are the only supported certificate-less ciphers. */
+ assert(alg_a == SSL_aPSK);
+
+ if (CBS_len(&server_key_exchange) > 0) {
+ al = SSL_AD_DECODE_ERROR;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_EXTRA_DATA_IN_MESSAGE);
+ goto f_err;
+ }
+ }
+ return 1;
+
+f_err:
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, al);
+err:
+ DH_free(dh);
+ EC_POINT_free(srvr_ecpoint);
+ EC_KEY_free(ecdh);
+ return -1;
+}
+
+static int ssl3_get_certificate_request(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ int msg_ret = ssl->method->ssl_get_message(ssl);
+ if (msg_ret <= 0) {
+ return msg_ret;
+ }
+
+ if (ssl->s3->tmp.message_type == SSL3_MT_SERVER_HELLO_DONE) {
+ ssl->s3->tmp.reuse_message = 1;
+ /* If we get here we don't need the handshake buffer as we won't be doing
+ * client auth. */
+ SSL_TRANSCRIPT_free_buffer(&hs->transcript);
+ return 1;
+ }
+
+ if (!ssl_check_message_type(ssl, SSL3_MT_CERTIFICATE_REQUEST) ||
+ !ssl_hash_current_message(hs)) {
+ return -1;
+ }
+
+ CBS cbs;
+ CBS_init(&cbs, ssl->init_msg, ssl->init_num);
+
+ /* Get the certificate types. */
+ CBS certificate_types;
+ if (!CBS_get_u8_length_prefixed(&cbs, &certificate_types)) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ return -1;
+ }
+
+ if (!CBS_stow(&certificate_types, &hs->certificate_types,
+ &hs->num_certificate_types)) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ return -1;
+ }
+
+ if (ssl3_protocol_version(ssl) >= TLS1_2_VERSION) {
+ CBS supported_signature_algorithms;
+ if (!CBS_get_u16_length_prefixed(&cbs, &supported_signature_algorithms) ||
+ !tls1_parse_peer_sigalgs(hs, &supported_signature_algorithms)) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ return -1;
+ }
+ }
+
+ uint8_t alert = SSL_AD_DECODE_ERROR;
+ STACK_OF(CRYPTO_BUFFER) *ca_names =
+ ssl_parse_client_CA_list(ssl, &alert, &cbs);
+ if (ca_names == NULL) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
+ return -1;
+ }
+
+ if (CBS_len(&cbs) != 0) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ sk_CRYPTO_BUFFER_pop_free(ca_names, CRYPTO_BUFFER_free);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ return -1;
+ }
+
+ hs->cert_request = 1;
+ sk_CRYPTO_BUFFER_pop_free(hs->ca_names, CRYPTO_BUFFER_free);
+ hs->ca_names = ca_names;
+ ssl->ctx->x509_method->hs_flush_cached_ca_names(hs);
+ return 1;
+}
+
+static int ssl3_get_server_hello_done(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ int ret = ssl->method->ssl_get_message(ssl);
+ if (ret <= 0) {
+ return ret;
+ }
+
+ if (!ssl_check_message_type(ssl, SSL3_MT_SERVER_HELLO_DONE) ||
+ !ssl_hash_current_message(hs)) {
+ return -1;
+ }
+
+ /* ServerHelloDone is empty. */
+ if (ssl->init_num > 0) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ return -1;
+ }
+
+ return 1;
+}
+
+static int ssl3_send_client_certificate(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ /* Call cert_cb to update the certificate. */
+ if (ssl->cert->cert_cb) {
+ int ret = ssl->cert->cert_cb(ssl, ssl->cert->cert_cb_arg);
+ if (ret < 0) {
+ ssl->rwstate = SSL_X509_LOOKUP;
+ return -1;
+ }
+ if (ret == 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_CB_ERROR);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ return -1;
+ }
+ }
+
+ if (!ssl_has_certificate(ssl)) {
+ /* Without a client certificate, the handshake buffer may be released. */
+ SSL_TRANSCRIPT_free_buffer(&hs->transcript);
+
+ /* In SSL 3.0, the Certificate message is replaced with a warning alert. */
+ if (ssl->version == SSL3_VERSION) {
+ if (!ssl->method->add_alert(ssl, SSL3_AL_WARNING,
+ SSL_AD_NO_CERTIFICATE)) {
+ return -1;
+ }
+ return 1;
+ }
+ }
+
+ if (!ssl->ctx->x509_method->ssl_auto_chain_if_needed(ssl) ||
+ !ssl3_output_cert_chain(ssl)) {
+ return -1;
+ }
+ return 1;
+}
+
+OPENSSL_COMPILE_ASSERT(sizeof(size_t) >= sizeof(unsigned),
+ SIZE_T_IS_SMALLER_THAN_UNSIGNED);
+
+static int ssl3_send_client_key_exchange(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ uint8_t *pms = NULL;
+ size_t pms_len = 0;
+ CBB cbb, body;
+ if (!ssl->method->init_message(ssl, &cbb, &body,
+ SSL3_MT_CLIENT_KEY_EXCHANGE)) {
+ goto err;
+ }
+
+ uint32_t alg_k = hs->new_cipher->algorithm_mkey;
+ uint32_t alg_a = hs->new_cipher->algorithm_auth;
+
+ /* If using a PSK key exchange, prepare the pre-shared key. */
+ unsigned psk_len = 0;
+ uint8_t psk[PSK_MAX_PSK_LEN];
+ if (alg_a & SSL_aPSK) {
+ if (ssl->psk_client_callback == NULL) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_PSK_NO_CLIENT_CB);
+ goto err;
+ }
+
+ char identity[PSK_MAX_IDENTITY_LEN + 1];
+ OPENSSL_memset(identity, 0, sizeof(identity));
+ psk_len =
+ ssl->psk_client_callback(ssl, hs->peer_psk_identity_hint, identity,
+ sizeof(identity), psk, sizeof(psk));
+ if (psk_len == 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_PSK_IDENTITY_NOT_FOUND);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
+ goto err;
+ }
+ assert(psk_len <= PSK_MAX_PSK_LEN);
+
+ OPENSSL_free(hs->new_session->psk_identity);
+ hs->new_session->psk_identity = BUF_strdup(identity);
+ if (hs->new_session->psk_identity == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ /* Write out psk_identity. */
+ CBB child;
+ if (!CBB_add_u16_length_prefixed(&body, &child) ||
+ !CBB_add_bytes(&child, (const uint8_t *)identity,
+ OPENSSL_strnlen(identity, sizeof(identity))) ||
+ !CBB_flush(&body)) {
+ goto err;
+ }
+ }
+
+ /* Depending on the key exchange method, compute |pms| and |pms_len|. */
+ if (alg_k & SSL_kRSA) {
+ pms_len = SSL_MAX_MASTER_KEY_LENGTH;
+ pms = OPENSSL_malloc(pms_len);
+ if (pms == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ RSA *rsa = EVP_PKEY_get0_RSA(hs->peer_pubkey);
+ if (rsa == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
+ pms[0] = hs->client_version >> 8;
+ pms[1] = hs->client_version & 0xff;
+ if (!RAND_bytes(&pms[2], SSL_MAX_MASTER_KEY_LENGTH - 2)) {
+ goto err;
+ }
+
+ CBB child, *enc_pms = &body;
+ size_t enc_pms_len;
+ /* In TLS, there is a length prefix. */
+ if (ssl->version > SSL3_VERSION) {
+ if (!CBB_add_u16_length_prefixed(&body, &child)) {
+ goto err;
+ }
+ enc_pms = &child;
+ }
+
+ uint8_t *ptr;
+ if (!CBB_reserve(enc_pms, &ptr, RSA_size(rsa)) ||
+ !RSA_encrypt(rsa, &enc_pms_len, ptr, RSA_size(rsa), pms, pms_len,
+ RSA_PKCS1_PADDING) ||
+ !CBB_did_write(enc_pms, enc_pms_len) ||
+ !CBB_flush(&body)) {
+ goto err;
+ }
+ } else if (alg_k & (SSL_kECDHE|SSL_kDHE)) {
+ /* Generate a keypair and serialize the public half. */
+ CBB child;
+ if (!SSL_ECDH_CTX_add_key(&hs->ecdh_ctx, &body, &child)) {
+ goto err;
+ }
+
+ /* Compute the premaster. */
+ uint8_t alert = SSL_AD_DECODE_ERROR;
+ if (!SSL_ECDH_CTX_accept(&hs->ecdh_ctx, &child, &pms, &pms_len, &alert,
+ hs->peer_key, hs->peer_key_len)) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
+ goto err;
+ }
+ if (!CBB_flush(&body)) {
+ goto err;
+ }
+
+ /* The key exchange state may now be discarded. */
+ SSL_ECDH_CTX_cleanup(&hs->ecdh_ctx);
+ OPENSSL_free(hs->peer_key);
+ hs->peer_key = NULL;
+ hs->peer_key_len = 0;
+ } else if (alg_k & SSL_kPSK) {
+ /* For plain PSK, other_secret is a block of 0s with the same length as
+ * the pre-shared key. */
+ pms_len = psk_len;
+ pms = OPENSSL_malloc(pms_len);
+ if (pms == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ OPENSSL_memset(pms, 0, pms_len);
+ } else {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
+ /* For a PSK cipher suite, other_secret is combined with the pre-shared
+ * key. */
+ if (alg_a & SSL_aPSK) {
+ CBB pms_cbb, child;
+ uint8_t *new_pms;
+ size_t new_pms_len;
+
+ CBB_zero(&pms_cbb);
+ if (!CBB_init(&pms_cbb, 2 + psk_len + 2 + pms_len) ||
+ !CBB_add_u16_length_prefixed(&pms_cbb, &child) ||
+ !CBB_add_bytes(&child, pms, pms_len) ||
+ !CBB_add_u16_length_prefixed(&pms_cbb, &child) ||
+ !CBB_add_bytes(&child, psk, psk_len) ||
+ !CBB_finish(&pms_cbb, &new_pms, &new_pms_len)) {
+ CBB_cleanup(&pms_cbb);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ OPENSSL_cleanse(pms, pms_len);
+ OPENSSL_free(pms);
+ pms = new_pms;
+ pms_len = new_pms_len;
+ }
+
+ /* The message must be added to the finished hash before calculating the
+ * master secret. */
+ if (!ssl_add_message_cbb(ssl, &cbb)) {
+ goto err;
+ }
+
+ hs->new_session->master_key_length = tls1_generate_master_secret(
+ hs, hs->new_session->master_key, pms, pms_len);
+ if (hs->new_session->master_key_length == 0) {
+ goto err;
+ }
+ hs->new_session->extended_master_secret = hs->extended_master_secret;
+ OPENSSL_cleanse(pms, pms_len);
+ OPENSSL_free(pms);
+
+ return 1;
+
+err:
+ CBB_cleanup(&cbb);
+ if (pms != NULL) {
+ OPENSSL_cleanse(pms, pms_len);
+ OPENSSL_free(pms);
+ }
+ return -1;
+}
+
+static int ssl3_send_cert_verify(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ assert(ssl_has_private_key(ssl));
+
+ CBB cbb, body, child;
+ if (!ssl->method->init_message(ssl, &cbb, &body,
+ SSL3_MT_CERTIFICATE_VERIFY)) {
+ goto err;
+ }
+
+ uint16_t signature_algorithm;
+ if (!tls1_choose_signature_algorithm(hs, &signature_algorithm)) {
+ goto err;
+ }
+ if (ssl3_protocol_version(ssl) >= TLS1_2_VERSION) {
+ /* Write out the digest type in TLS 1.2. */
+ if (!CBB_add_u16(&body, signature_algorithm)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ }
+
+ /* Set aside space for the signature. */
+ const size_t max_sig_len = ssl_private_key_max_signature_len(ssl);
+ uint8_t *ptr;
+ if (!CBB_add_u16_length_prefixed(&body, &child) ||
+ !CBB_reserve(&child, &ptr, max_sig_len)) {
+ goto err;
+ }
+
+ size_t sig_len = max_sig_len;
+ enum ssl_private_key_result_t sign_result;
+ if (hs->state == SSL3_ST_CW_CERT_VRFY_A) {
+ /* The SSL3 construction for CertificateVerify does not decompose into a
+ * single final digest and signature, and must be special-cased. */
+ if (ssl3_protocol_version(ssl) == SSL3_VERSION) {
+ if (ssl->cert->key_method != NULL) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_PROTOCOL_FOR_CUSTOM_KEY);
+ goto err;
+ }
+
+ uint8_t digest[EVP_MAX_MD_SIZE];
+ size_t digest_len;
+ if (!SSL_TRANSCRIPT_ssl3_cert_verify_hash(&hs->transcript, digest,
+ &digest_len, hs->new_session,
+ signature_algorithm)) {
+ goto err;
+ }
+
+ sign_result = ssl_private_key_success;
+
+ EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new(ssl->cert->privatekey, NULL);
+ if (pctx == NULL ||
+ !EVP_PKEY_sign_init(pctx) ||
+ !EVP_PKEY_sign(pctx, ptr, &sig_len, digest, digest_len)) {
+ EVP_PKEY_CTX_free(pctx);
+ sign_result = ssl_private_key_failure;
+ goto err;
+ }
+ EVP_PKEY_CTX_free(pctx);
+ } else {
+ sign_result = ssl_private_key_sign(
+ ssl, ptr, &sig_len, max_sig_len, signature_algorithm,
+ (const uint8_t *)hs->transcript.buffer->data,
+ hs->transcript.buffer->length);
+ }
+
+ /* The handshake buffer is no longer necessary. */
+ SSL_TRANSCRIPT_free_buffer(&hs->transcript);
+ } else {
+ assert(hs->state == SSL3_ST_CW_CERT_VRFY_B);
+ sign_result = ssl_private_key_complete(ssl, ptr, &sig_len, max_sig_len);
+ }
+
+ switch (sign_result) {
+ case ssl_private_key_success:
+ break;
+ case ssl_private_key_failure:
+ goto err;
+ case ssl_private_key_retry:
+ ssl->rwstate = SSL_PRIVATE_KEY_OPERATION;
+ hs->state = SSL3_ST_CW_CERT_VRFY_B;
+ goto err;
+ }
+
+ if (!CBB_did_write(&child, sig_len) ||
+ !ssl_add_message_cbb(ssl, &cbb)) {
+ goto err;
+ }
+
+ return 1;
+
+err:
+ CBB_cleanup(&cbb);
+ return -1;
+}
+
+static int ssl3_send_next_proto(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ static const uint8_t kZero[32] = {0};
+ size_t padding_len = 32 - ((ssl->s3->next_proto_negotiated_len + 2) % 32);
+
+ CBB cbb, body, child;
+ if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_NEXT_PROTO) ||
+ !CBB_add_u8_length_prefixed(&body, &child) ||
+ !CBB_add_bytes(&child, ssl->s3->next_proto_negotiated,
+ ssl->s3->next_proto_negotiated_len) ||
+ !CBB_add_u8_length_prefixed(&body, &child) ||
+ !CBB_add_bytes(&child, kZero, padding_len) ||
+ !ssl_add_message_cbb(ssl, &cbb)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ CBB_cleanup(&cbb);
+ return -1;
+ }
+
+ return 1;
+}
+
+static int ssl3_send_channel_id(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ if (!ssl_do_channel_id_callback(ssl)) {
+ return -1;
+ }
+
+ if (ssl->tlsext_channel_id_private == NULL) {
+ ssl->rwstate = SSL_CHANNEL_ID_LOOKUP;
+ return -1;
+ }
+
+ CBB cbb, body;
+ if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_CHANNEL_ID) ||
+ !tls1_write_channel_id(hs, &body) ||
+ !ssl_add_message_cbb(ssl, &cbb)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ CBB_cleanup(&cbb);
+ return -1;
+ }
+
+ return 1;
+}
+
+static int ssl3_get_new_session_ticket(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ int ret = ssl->method->ssl_get_message(ssl);
+ if (ret <= 0) {
+ return ret;
+ }
+
+ if (!ssl_check_message_type(ssl, SSL3_MT_NEW_SESSION_TICKET) ||
+ !ssl_hash_current_message(hs)) {
+ return -1;
+ }
+
+ CBS new_session_ticket, ticket;
+ uint32_t tlsext_tick_lifetime_hint;
+ CBS_init(&new_session_ticket, ssl->init_msg, ssl->init_num);
+ if (!CBS_get_u32(&new_session_ticket, &tlsext_tick_lifetime_hint) ||
+ !CBS_get_u16_length_prefixed(&new_session_ticket, &ticket) ||
+ CBS_len(&new_session_ticket) != 0) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ return -1;
+ }
+
+ if (CBS_len(&ticket) == 0) {
+ /* RFC 5077 allows a server to change its mind and send no ticket after
+ * negotiating the extension. The value of |ticket_expected| is checked in
+ * |ssl_update_cache| so is cleared here to avoid an unnecessary update. */
+ hs->ticket_expected = 0;
+ return 1;
+ }
+
+ int session_renewed = ssl->session != NULL;
+ SSL_SESSION *session = hs->new_session;
+ if (session_renewed) {
+ /* The server is sending a new ticket for an existing session. Sessions are
+ * immutable once established, so duplicate all but the ticket of the
+ * existing session. */
+ session = SSL_SESSION_dup(ssl->session, SSL_SESSION_INCLUDE_NONAUTH);
+ if (session == NULL) {
+ /* This should never happen. */
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ }
+
+ /* |tlsext_tick_lifetime_hint| is measured from when the ticket was issued. */
+ ssl_session_rebase_time(ssl, session);
+
+ if (!CBS_stow(&ticket, &session->tlsext_tick, &session->tlsext_ticklen)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ session->tlsext_tick_lifetime_hint = tlsext_tick_lifetime_hint;
+
+ /* Generate a session ID for this session based on the session ticket. We use
+ * the session ID mechanism for detecting ticket resumption. This also fits in
+ * with assumptions elsewhere in OpenSSL.*/
+ if (!EVP_Digest(CBS_data(&ticket), CBS_len(&ticket),
+ session->session_id, &session->session_id_length,
+ EVP_sha256(), NULL)) {
+ goto err;
+ }
+
+ if (session_renewed) {
+ session->not_resumable = 0;
+ SSL_SESSION_free(ssl->session);
+ ssl->session = session;
+ }
+
+ return 1;
+
+err:
+ if (session_renewed) {
+ SSL_SESSION_free(session);
+ }
+ return -1;
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/handshake_server.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/handshake_server.c
new file mode 100644
index 000000000..81e45ef07
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/handshake_server.c
@@ -0,0 +1,1953 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2007 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ *
+ * Portions of the attached software ("Contribution") are developed by
+ * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
+ *
+ * The Contribution is licensed pursuant to the OpenSSL open source
+ * license provided above.
+ *
+ * ECC cipher suite support in OpenSSL originally written by
+ * Vipul Gupta and Sumit Gupta of Sun Microsystems Laboratories.
+ *
+ */
+/* ====================================================================
+ * Copyright 2005 Nokia. All rights reserved.
+ *
+ * The portions of the attached software ("Contribution") is developed by
+ * Nokia Corporation and is licensed pursuant to the OpenSSL open source
+ * license.
+ *
+ * The Contribution, originally written by Mika Kousa and Pasi Eronen of
+ * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites
+ * support (see RFC 4279) to OpenSSL.
+ *
+ * No patent licenses or other rights except those expressly stated in
+ * the OpenSSL open source license shall be deemed granted or received
+ * expressly, by implication, estoppel, or otherwise.
+ *
+ * No assurances are provided by Nokia that the Contribution does not
+ * infringe the patent or other intellectual property rights of any third
+ * party or that the license provides you with all the necessary rights
+ * to make use of the Contribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN
+ * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA
+ * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY
+ * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
+ * OTHERWISE. */
+
+#include <openssl/ssl.h>
+
+#include <assert.h>
+#include <string.h>
+
+#include <openssl/bn.h>
+#include <openssl/buf.h>
+#include <openssl/bytestring.h>
+#include <openssl/cipher.h>
+#include <openssl/dh.h>
+#include <openssl/ec.h>
+#include <openssl/ecdsa.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#include <openssl/md5.h>
+#include <openssl/mem.h>
+#include <openssl/nid.h>
+#include <openssl/rand.h>
+#include <openssl/x509.h>
+
+#include "internal.h"
+#include "../crypto/internal.h"
+
+
+static int ssl3_process_client_hello(SSL_HANDSHAKE *hs);
+static int ssl3_select_certificate(SSL_HANDSHAKE *hs);
+static int ssl3_select_parameters(SSL_HANDSHAKE *hs);
+static int ssl3_send_server_hello(SSL_HANDSHAKE *hs);
+static int ssl3_send_server_certificate(SSL_HANDSHAKE *hs);
+static int ssl3_send_certificate_status(SSL_HANDSHAKE *hs);
+static int ssl3_send_server_key_exchange(SSL_HANDSHAKE *hs);
+static int ssl3_send_certificate_request(SSL_HANDSHAKE *hs);
+static int ssl3_send_server_hello_done(SSL_HANDSHAKE *hs);
+static int ssl3_get_client_certificate(SSL_HANDSHAKE *hs);
+static int ssl3_get_client_key_exchange(SSL_HANDSHAKE *hs);
+static int ssl3_get_cert_verify(SSL_HANDSHAKE *hs);
+static int ssl3_get_next_proto(SSL_HANDSHAKE *hs);
+static int ssl3_get_channel_id(SSL_HANDSHAKE *hs);
+static int ssl3_send_new_session_ticket(SSL_HANDSHAKE *hs);
+
+static struct CRYPTO_STATIC_MUTEX g_v2clienthello_lock =
+ CRYPTO_STATIC_MUTEX_INIT;
+static uint64_t g_v2clienthello_count = 0;
+
+uint64_t SSL_get_v2clienthello_count(void) {
+ CRYPTO_STATIC_MUTEX_lock_read(&g_v2clienthello_lock);
+ uint64_t ret = g_v2clienthello_count;
+ CRYPTO_STATIC_MUTEX_unlock_read(&g_v2clienthello_lock);
+ return ret;
+}
+
+int ssl3_accept(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ uint32_t alg_a;
+ int ret = -1;
+
+ assert(ssl->handshake_func == ssl3_accept);
+ assert(ssl->server);
+
+ for (;;) {
+ int state = hs->state;
+
+ switch (hs->state) {
+ case SSL_ST_INIT:
+ ssl_do_info_callback(ssl, SSL_CB_HANDSHAKE_START, 1);
+ hs->state = SSL3_ST_SR_CLNT_HELLO_A;
+ break;
+
+ case SSL3_ST_SR_CLNT_HELLO_A:
+ ret = ssl->method->ssl_get_message(ssl);
+ if (ret <= 0) {
+ goto end;
+ }
+ hs->state = SSL3_ST_SR_CLNT_HELLO_B;
+ break;
+
+ case SSL3_ST_SR_CLNT_HELLO_B:
+ ret = ssl3_process_client_hello(hs);
+ if (ret <= 0) {
+ goto end;
+ }
+ hs->state = SSL3_ST_SR_CLNT_HELLO_C;
+ break;
+
+ case SSL3_ST_SR_CLNT_HELLO_C:
+ ret = ssl3_select_certificate(hs);
+ if (ret <= 0) {
+ goto end;
+ }
+ if (hs->state != SSL_ST_TLS13) {
+ hs->state = SSL3_ST_SR_CLNT_HELLO_D;
+ }
+ break;
+
+ case SSL3_ST_SR_CLNT_HELLO_D:
+ ret = ssl3_select_parameters(hs);
+ if (ret <= 0) {
+ goto end;
+ }
+ ssl->method->received_flight(ssl);
+ hs->state = SSL3_ST_SW_SRVR_HELLO_A;
+ break;
+
+ case SSL3_ST_SW_SRVR_HELLO_A:
+ ret = ssl3_send_server_hello(hs);
+ if (ret <= 0) {
+ goto end;
+ }
+ if (ssl->session != NULL) {
+ hs->state = SSL3_ST_SW_SESSION_TICKET_A;
+ } else {
+ hs->state = SSL3_ST_SW_CERT_A;
+ }
+ break;
+
+ case SSL3_ST_SW_CERT_A:
+ if (ssl_cipher_uses_certificate_auth(hs->new_cipher)) {
+ ret = ssl3_send_server_certificate(hs);
+ if (ret <= 0) {
+ goto end;
+ }
+ }
+ hs->state = SSL3_ST_SW_CERT_STATUS_A;
+ break;
+
+ case SSL3_ST_SW_CERT_STATUS_A:
+ if (hs->certificate_status_expected) {
+ ret = ssl3_send_certificate_status(hs);
+ if (ret <= 0) {
+ goto end;
+ }
+ }
+ hs->state = SSL3_ST_SW_KEY_EXCH_A;
+ break;
+
+ case SSL3_ST_SW_KEY_EXCH_A:
+ case SSL3_ST_SW_KEY_EXCH_B:
+ alg_a = hs->new_cipher->algorithm_auth;
+
+ /* PSK ciphers send ServerKeyExchange if there is an identity hint. */
+ if (ssl_cipher_requires_server_key_exchange(hs->new_cipher) ||
+ ((alg_a & SSL_aPSK) && ssl->psk_identity_hint)) {
+ ret = ssl3_send_server_key_exchange(hs);
+ if (ret <= 0) {
+ goto end;
+ }
+ }
+
+ hs->state = SSL3_ST_SW_CERT_REQ_A;
+ break;
+
+ case SSL3_ST_SW_CERT_REQ_A:
+ if (hs->cert_request) {
+ ret = ssl3_send_certificate_request(hs);
+ if (ret <= 0) {
+ goto end;
+ }
+ }
+ hs->state = SSL3_ST_SW_SRVR_DONE_A;
+ break;
+
+ case SSL3_ST_SW_SRVR_DONE_A:
+ ret = ssl3_send_server_hello_done(hs);
+ if (ret <= 0) {
+ goto end;
+ }
+ hs->next_state = SSL3_ST_SR_CERT_A;
+ hs->state = SSL3_ST_SW_FLUSH;
+ break;
+
+ case SSL3_ST_SR_CERT_A:
+ if (hs->cert_request) {
+ ret = ssl3_get_client_certificate(hs);
+ if (ret <= 0) {
+ goto end;
+ }
+ }
+ hs->state = SSL3_ST_SR_KEY_EXCH_A;
+ break;
+
+ case SSL3_ST_SR_KEY_EXCH_A:
+ case SSL3_ST_SR_KEY_EXCH_B:
+ ret = ssl3_get_client_key_exchange(hs);
+ if (ret <= 0) {
+ goto end;
+ }
+ hs->state = SSL3_ST_SR_CERT_VRFY_A;
+ break;
+
+ case SSL3_ST_SR_CERT_VRFY_A:
+ ret = ssl3_get_cert_verify(hs);
+ if (ret <= 0) {
+ goto end;
+ }
+
+ hs->state = SSL3_ST_SR_CHANGE;
+ break;
+
+ case SSL3_ST_SR_CHANGE:
+ ret = ssl->method->read_change_cipher_spec(ssl);
+ if (ret <= 0) {
+ goto end;
+ }
+
+ if (!tls1_change_cipher_state(hs, SSL3_CHANGE_CIPHER_SERVER_READ)) {
+ ret = -1;
+ goto end;
+ }
+
+ hs->state = SSL3_ST_SR_NEXT_PROTO_A;
+ break;
+
+ case SSL3_ST_SR_NEXT_PROTO_A:
+ if (hs->next_proto_neg_seen) {
+ ret = ssl3_get_next_proto(hs);
+ if (ret <= 0) {
+ goto end;
+ }
+ }
+ hs->state = SSL3_ST_SR_CHANNEL_ID_A;
+ break;
+
+ case SSL3_ST_SR_CHANNEL_ID_A:
+ if (ssl->s3->tlsext_channel_id_valid) {
+ ret = ssl3_get_channel_id(hs);
+ if (ret <= 0) {
+ goto end;
+ }
+ }
+ hs->state = SSL3_ST_SR_FINISHED_A;
+ break;
+
+ case SSL3_ST_SR_FINISHED_A:
+ ret = ssl3_get_finished(hs);
+ if (ret <= 0) {
+ goto end;
+ }
+
+ ssl->method->received_flight(ssl);
+ if (ssl->session != NULL) {
+ hs->state = SSL_ST_OK;
+ } else {
+ hs->state = SSL3_ST_SW_SESSION_TICKET_A;
+ }
+
+ /* If this is a full handshake with ChannelID then record the handshake
+ * hashes in |hs->new_session| in case we need them to verify a
+ * ChannelID signature on a resumption of this session in the future. */
+ if (ssl->session == NULL && ssl->s3->tlsext_channel_id_valid) {
+ ret = tls1_record_handshake_hashes_for_channel_id(hs);
+ if (ret <= 0) {
+ goto end;
+ }
+ }
+ break;
+
+ case SSL3_ST_SW_SESSION_TICKET_A:
+ if (hs->ticket_expected) {
+ ret = ssl3_send_new_session_ticket(hs);
+ if (ret <= 0) {
+ goto end;
+ }
+ }
+ hs->state = SSL3_ST_SW_CHANGE;
+ break;
+
+ case SSL3_ST_SW_CHANGE:
+ if (!ssl->method->add_change_cipher_spec(ssl) ||
+ !tls1_change_cipher_state(hs, SSL3_CHANGE_CIPHER_SERVER_WRITE)) {
+ ret = -1;
+ goto end;
+ }
+
+ hs->state = SSL3_ST_SW_FINISHED_A;
+ break;
+
+ case SSL3_ST_SW_FINISHED_A:
+ ret = ssl3_send_finished(hs);
+ if (ret <= 0) {
+ goto end;
+ }
+ hs->state = SSL3_ST_SW_FLUSH;
+ if (ssl->session != NULL) {
+ hs->next_state = SSL3_ST_SR_CHANGE;
+ } else {
+ hs->next_state = SSL_ST_OK;
+ }
+ break;
+
+ case SSL3_ST_SW_FLUSH:
+ ret = ssl->method->flush_flight(ssl);
+ if (ret <= 0) {
+ goto end;
+ }
+
+ hs->state = hs->next_state;
+ if (hs->state != SSL_ST_OK) {
+ ssl->method->expect_flight(ssl);
+ }
+ break;
+
+ case SSL_ST_TLS13:
+ ret = tls13_handshake(hs);
+ if (ret <= 0) {
+ goto end;
+ }
+ hs->state = SSL_ST_OK;
+ break;
+
+ case SSL_ST_OK:
+ ssl->method->release_current_message(ssl, 1 /* free_buffer */);
+
+ /* If we aren't retaining peer certificates then we can discard it
+ * now. */
+ if (hs->new_session != NULL &&
+ ssl->retain_only_sha256_of_client_certs) {
+ sk_CRYPTO_BUFFER_pop_free(hs->new_session->certs, CRYPTO_BUFFER_free);
+ hs->new_session->certs = NULL;
+ ssl->ctx->x509_method->session_clear(hs->new_session);
+ }
+
+ SSL_SESSION_free(ssl->s3->established_session);
+ if (ssl->session != NULL) {
+ SSL_SESSION_up_ref(ssl->session);
+ ssl->s3->established_session = ssl->session;
+ } else {
+ ssl->s3->established_session = hs->new_session;
+ ssl->s3->established_session->not_resumable = 0;
+ hs->new_session = NULL;
+ }
+
+ if (hs->v2_clienthello) {
+ CRYPTO_STATIC_MUTEX_lock_write(&g_v2clienthello_lock);
+ g_v2clienthello_count++;
+ CRYPTO_STATIC_MUTEX_unlock_write(&g_v2clienthello_lock);
+ }
+
+ ssl->s3->initial_handshake_complete = 1;
+ ssl_update_cache(hs, SSL_SESS_CACHE_SERVER);
+
+ ssl_do_info_callback(ssl, SSL_CB_HANDSHAKE_DONE, 1);
+ ret = 1;
+ goto end;
+
+ default:
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_STATE);
+ ret = -1;
+ goto end;
+ }
+
+ if (hs->state != state) {
+ ssl_do_info_callback(ssl, SSL_CB_ACCEPT_LOOP, 1);
+ }
+ }
+
+end:
+ ssl_do_info_callback(ssl, SSL_CB_ACCEPT_EXIT, ret);
+ return ret;
+}
+
+int ssl_client_cipher_list_contains_cipher(const SSL_CLIENT_HELLO *client_hello,
+ uint16_t id) {
+ CBS cipher_suites;
+ CBS_init(&cipher_suites, client_hello->cipher_suites,
+ client_hello->cipher_suites_len);
+
+ while (CBS_len(&cipher_suites) > 0) {
+ uint16_t got_id;
+ if (!CBS_get_u16(&cipher_suites, &got_id)) {
+ return 0;
+ }
+
+ if (got_id == id) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int negotiate_version(SSL_HANDSHAKE *hs, uint8_t *out_alert,
+ const SSL_CLIENT_HELLO *client_hello) {
+ SSL *const ssl = hs->ssl;
+ assert(!ssl->s3->have_version);
+ uint16_t min_version, max_version;
+ if (!ssl_get_version_range(ssl, &min_version, &max_version)) {
+ *out_alert = SSL_AD_PROTOCOL_VERSION;
+ return 0;
+ }
+
+ uint16_t version = 0;
+ /* Check supported_versions extension if it is present. */
+ CBS supported_versions;
+ if (ssl_client_hello_get_extension(client_hello, &supported_versions,
+ TLSEXT_TYPE_supported_versions)) {
+ CBS versions;
+ if (!CBS_get_u8_length_prefixed(&supported_versions, &versions) ||
+ CBS_len(&supported_versions) != 0 ||
+ CBS_len(&versions) == 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ /* Choose the newest commonly-supported version advertised by the client.
+ * The client orders the versions according to its preferences, but we're
+ * not required to honor the client's preferences. */
+ int found_version = 0;
+ while (CBS_len(&versions) != 0) {
+ uint16_t ext_version;
+ if (!CBS_get_u16(&versions, &ext_version)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ if (!ssl->method->version_from_wire(&ext_version, ext_version)) {
+ continue;
+ }
+ if (min_version <= ext_version &&
+ ext_version <= max_version &&
+ (!found_version || version < ext_version)) {
+ version = ext_version;
+ found_version = 1;
+ }
+ }
+
+ if (!found_version) {
+ goto unsupported_protocol;
+ }
+ } else {
+ /* Process ClientHello.version instead. Note that versions beyond (D)TLS 1.2
+ * do not use this mechanism. */
+ if (SSL_is_dtls(ssl)) {
+ if (client_hello->version <= DTLS1_2_VERSION) {
+ version = TLS1_2_VERSION;
+ } else if (client_hello->version <= DTLS1_VERSION) {
+ version = TLS1_1_VERSION;
+ } else {
+ goto unsupported_protocol;
+ }
+ } else {
+ if (client_hello->version >= TLS1_2_VERSION) {
+ version = TLS1_2_VERSION;
+ } else if (client_hello->version >= TLS1_1_VERSION) {
+ version = TLS1_1_VERSION;
+ } else if (client_hello->version >= TLS1_VERSION) {
+ version = TLS1_VERSION;
+ } else if (client_hello->version >= SSL3_VERSION) {
+ version = SSL3_VERSION;
+ } else {
+ goto unsupported_protocol;
+ }
+ }
+
+ /* Apply our minimum and maximum version. */
+ if (version > max_version) {
+ version = max_version;
+ }
+
+ if (version < min_version) {
+ goto unsupported_protocol;
+ }
+ }
+
+ /* Handle FALLBACK_SCSV. */
+ if (ssl_client_cipher_list_contains_cipher(client_hello,
+ SSL3_CK_FALLBACK_SCSV & 0xffff) &&
+ version < max_version) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INAPPROPRIATE_FALLBACK);
+ *out_alert = SSL3_AD_INAPPROPRIATE_FALLBACK;
+ return 0;
+ }
+
+ hs->client_version = client_hello->version;
+ ssl->version = ssl->method->version_to_wire(version);
+
+ /* At this point, the connection's version is known and |ssl->version| is
+ * fixed. Begin enforcing the record-layer version. */
+ ssl->s3->have_version = 1;
+
+ return 1;
+
+unsupported_protocol:
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_PROTOCOL);
+ *out_alert = SSL_AD_PROTOCOL_VERSION;
+ return 0;
+}
+
+static 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) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ while (CBS_len(&cipher_suites) > 0) {
+ uint16_t cipher_suite;
+
+ if (!CBS_get_u16(&cipher_suites, &cipher_suite)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST);
+ goto err;
+ }
+
+ const SSL_CIPHER *c = SSL_get_cipher_by_value(cipher_suite);
+ if (c != NULL && !sk_SSL_CIPHER_push(sk, c)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ }
+
+ return sk;
+
+err:
+ sk_SSL_CIPHER_free(sk);
+ return NULL;
+}
+
+/* ssl_get_compatible_server_ciphers determines the key exchange and
+ * authentication cipher suite masks compatible with the server configuration
+ * and current ClientHello parameters of |hs|. It sets |*out_mask_k| to the key
+ * exchange mask and |*out_mask_a| to the authentication mask. */
+static void ssl_get_compatible_server_ciphers(SSL_HANDSHAKE *hs,
+ uint32_t *out_mask_k,
+ uint32_t *out_mask_a) {
+ SSL *const ssl = hs->ssl;
+ if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) {
+ *out_mask_k = SSL_kGENERIC;
+ *out_mask_a = SSL_aGENERIC;
+ return;
+ }
+
+ uint32_t mask_k = 0;
+ uint32_t mask_a = 0;
+
+ if (ssl_has_certificate(ssl)) {
+ int type = ssl_private_key_type(ssl);
+ if (type == NID_rsaEncryption) {
+ mask_k |= SSL_kRSA;
+ mask_a |= SSL_aRSA;
+ } else if (ssl_is_ecdsa_key_type(type)) {
+ mask_a |= SSL_aECDSA;
+ }
+ }
+
+ if (ssl->cert->dh_tmp != NULL || ssl->cert->dh_tmp_cb != NULL) {
+ mask_k |= SSL_kDHE;
+ }
+
+ /* Check for a shared group to consider ECDHE ciphers. */
+ uint16_t unused;
+ if (tls1_get_shared_group(hs, &unused)) {
+ mask_k |= SSL_kECDHE;
+ }
+
+ /* PSK requires a server callback. */
+ if (ssl->psk_server_callback != NULL) {
+ mask_k |= SSL_kPSK;
+ mask_a |= SSL_aPSK;
+ }
+
+ *out_mask_k = mask_k;
+ *out_mask_a = mask_a;
+}
+
+static const SSL_CIPHER *ssl3_choose_cipher(
+ SSL_HANDSHAKE *hs, const SSL_CLIENT_HELLO *client_hello,
+ const struct ssl_cipher_preference_list_st *server_pref) {
+ SSL *const ssl = hs->ssl;
+ const SSL_CIPHER *c, *ret = NULL;
+ STACK_OF(SSL_CIPHER) *srvr = server_pref->ciphers, *prio, *allow;
+ int ok;
+ size_t cipher_index;
+ uint32_t alg_k, alg_a, mask_k, mask_a;
+ /* in_group_flags will either be NULL, or will point to an array of bytes
+ * which indicate equal-preference groups in the |prio| stack. See the
+ * comment about |in_group_flags| in the |ssl_cipher_preference_list_st|
+ * struct. */
+ const uint8_t *in_group_flags;
+ /* group_min contains the minimal index so far found in a group, or -1 if no
+ * such value exists yet. */
+ int group_min = -1;
+
+ STACK_OF(SSL_CIPHER) *clnt = ssl_parse_client_cipher_list(client_hello);
+ if (clnt == NULL) {
+ return NULL;
+ }
+
+ if (ssl->options & SSL_OP_CIPHER_SERVER_PREFERENCE) {
+ prio = srvr;
+ in_group_flags = server_pref->in_group_flags;
+ allow = clnt;
+ } else {
+ prio = clnt;
+ in_group_flags = NULL;
+ allow = srvr;
+ }
+
+ ssl_get_compatible_server_ciphers(hs, &mask_k, &mask_a);
+
+ for (size_t i = 0; i < sk_SSL_CIPHER_num(prio); i++) {
+ c = sk_SSL_CIPHER_value(prio, i);
+
+ ok = 1;
+
+ /* Check the TLS version. */
+ if (SSL_CIPHER_get_min_version(c) > ssl3_protocol_version(ssl) ||
+ SSL_CIPHER_get_max_version(c) < ssl3_protocol_version(ssl)) {
+ ok = 0;
+ }
+
+ alg_k = c->algorithm_mkey;
+ alg_a = c->algorithm_auth;
+
+ ok = ok && (alg_k & mask_k) && (alg_a & mask_a);
+
+ if (ok && sk_SSL_CIPHER_find(allow, &cipher_index, c)) {
+ if (in_group_flags != NULL && in_group_flags[i] == 1) {
+ /* This element of |prio| is in a group. Update the minimum index found
+ * so far and continue looking. */
+ if (group_min == -1 || (size_t)group_min > cipher_index) {
+ group_min = cipher_index;
+ }
+ } else {
+ if (group_min != -1 && (size_t)group_min < cipher_index) {
+ cipher_index = group_min;
+ }
+ ret = sk_SSL_CIPHER_value(allow, cipher_index);
+ break;
+ }
+ }
+
+ 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;
+ }
+ }
+
+ sk_SSL_CIPHER_free(clnt);
+ return ret;
+}
+
+static int ssl3_process_client_hello(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ if (!ssl_check_message_type(ssl, SSL3_MT_CLIENT_HELLO)) {
+ return -1;
+ }
+
+ SSL_CLIENT_HELLO client_hello;
+ if (!ssl_client_hello_init(ssl, &client_hello, ssl->init_msg,
+ ssl->init_num)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ return -1;
+ }
+
+ /* Run the early callback. */
+ if (ssl->ctx->select_certificate_cb != NULL) {
+ switch (ssl->ctx->select_certificate_cb(&client_hello)) {
+ case 0:
+ ssl->rwstate = SSL_CERTIFICATE_SELECTION_PENDING;
+ return -1;
+
+ case -1:
+ /* Connection rejected. */
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CONNECTION_REJECTED);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
+ return -1;
+
+ default:
+ /* fallthrough */;
+ }
+ }
+
+ uint8_t alert = SSL_AD_DECODE_ERROR;
+ if (!negotiate_version(hs, &alert, &client_hello)) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
+ return -1;
+ }
+
+ /* Load the client random. */
+ if (client_hello.random_len != SSL3_RANDOM_SIZE) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
+ OPENSSL_memcpy(ssl->s3->client_random, client_hello.random,
+ client_hello.random_len);
+
+ /* Only null compression is supported. TLS 1.3 further requires the peer
+ * advertise no other compression. */
+ if (OPENSSL_memchr(client_hello.compression_methods, 0,
+ client_hello.compression_methods_len) == NULL ||
+ (ssl3_protocol_version(ssl) >= TLS1_3_VERSION &&
+ client_hello.compression_methods_len != 1)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_COMPRESSION_LIST);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+ return -1;
+ }
+
+ /* TLS extensions. */
+ if (!ssl_parse_clienthello_tlsext(hs, &client_hello)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT);
+ return -1;
+ }
+
+ return 1;
+}
+
+static int ssl3_select_certificate(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ /* Call |cert_cb| to update server certificates if required. */
+ if (ssl->cert->cert_cb != NULL) {
+ int rv = ssl->cert->cert_cb(ssl, ssl->cert->cert_cb_arg);
+ if (rv == 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_CB_ERROR);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ return -1;
+ }
+ if (rv < 0) {
+ ssl->rwstate = SSL_X509_LOOKUP;
+ return -1;
+ }
+ }
+
+ if (!ssl->ctx->x509_method->ssl_auto_chain_if_needed(ssl)) {
+ return -1;
+ }
+
+ if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) {
+ /* Jump to the TLS 1.3 state machine. */
+ hs->state = SSL_ST_TLS13;
+ hs->do_tls13_handshake = tls13_server_handshake;
+ return 1;
+ }
+
+ SSL_CLIENT_HELLO client_hello;
+ if (!ssl_client_hello_init(ssl, &client_hello, ssl->init_msg,
+ ssl->init_num)) {
+ return -1;
+ }
+
+ /* Negotiate the cipher suite. This must be done after |cert_cb| so the
+ * certificate is finalized. */
+ hs->new_cipher =
+ ssl3_choose_cipher(hs, &client_hello, ssl_get_cipher_preferences(ssl));
+ if (hs->new_cipher == NULL) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_SHARED_CIPHER);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
+ return -1;
+ }
+
+ return 1;
+}
+
+static int ssl3_select_parameters(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ uint8_t al = SSL_AD_INTERNAL_ERROR;
+ int ret = -1;
+ SSL_SESSION *session = NULL;
+
+ SSL_CLIENT_HELLO client_hello;
+ if (!ssl_client_hello_init(ssl, &client_hello, ssl->init_msg,
+ ssl->init_num)) {
+ return -1;
+ }
+
+ /* Determine whether we are doing session resumption. */
+ int tickets_supported = 0, renew_ticket = 0;
+ switch (ssl_get_prev_session(ssl, &session, &tickets_supported, &renew_ticket,
+ &client_hello)) {
+ case ssl_session_success:
+ break;
+ case ssl_session_error:
+ goto err;
+ case ssl_session_retry:
+ ssl->rwstate = SSL_PENDING_SESSION;
+ goto err;
+ case ssl_session_ticket_retry:
+ ssl->rwstate = SSL_PENDING_TICKET;
+ goto err;
+ }
+
+ if (session != NULL) {
+ if (session->extended_master_secret && !hs->extended_master_secret) {
+ /* A ClientHello without EMS that attempts to resume a session with EMS
+ * is fatal to the connection. */
+ al = SSL_AD_HANDSHAKE_FAILURE;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION);
+ goto f_err;
+ }
+
+ if (!ssl_session_is_resumable(hs, session) ||
+ /* If the client offers the EMS extension, but the previous session
+ * didn't use it, then negotiate a new session. */
+ hs->extended_master_secret != session->extended_master_secret) {
+ SSL_SESSION_free(session);
+ session = NULL;
+ }
+ }
+
+ if (session != NULL) {
+ /* Use the old session. */
+ hs->ticket_expected = renew_ticket;
+ ssl->session = session;
+ session = NULL;
+ ssl->s3->session_reused = 1;
+ } else {
+ hs->ticket_expected = tickets_supported;
+ ssl_set_session(ssl, NULL);
+ if (!ssl_get_new_session(hs, 1 /* server */)) {
+ goto err;
+ }
+
+ /* Clear the session ID if we want the session to be single-use. */
+ if (!(ssl->ctx->session_cache_mode & SSL_SESS_CACHE_SERVER)) {
+ hs->new_session->session_id_length = 0;
+ }
+ }
+
+ if (ssl->ctx->dos_protection_cb != NULL &&
+ ssl->ctx->dos_protection_cb(&client_hello) == 0) {
+ /* Connection rejected for DOS reasons. */
+ al = SSL_AD_INTERNAL_ERROR;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CONNECTION_REJECTED);
+ goto f_err;
+ }
+
+ if (ssl->session == NULL) {
+ hs->new_session->cipher = hs->new_cipher;
+
+ /* On new sessions, stash the SNI value in the session. */
+ if (hs->hostname != NULL) {
+ OPENSSL_free(hs->new_session->tlsext_hostname);
+ hs->new_session->tlsext_hostname = BUF_strdup(hs->hostname);
+ if (hs->new_session->tlsext_hostname == NULL) {
+ al = SSL_AD_INTERNAL_ERROR;
+ goto f_err;
+ }
+ }
+
+ /* Determine whether to request a client certificate. */
+ hs->cert_request = !!(ssl->verify_mode & SSL_VERIFY_PEER);
+ /* Only request a certificate if Channel ID isn't negotiated. */
+ if ((ssl->verify_mode & SSL_VERIFY_PEER_IF_NO_OBC) &&
+ ssl->s3->tlsext_channel_id_valid) {
+ hs->cert_request = 0;
+ }
+ /* CertificateRequest may only be sent in certificate-based ciphers. */
+ if (!ssl_cipher_uses_certificate_auth(hs->new_cipher)) {
+ hs->cert_request = 0;
+ }
+
+ if (!hs->cert_request) {
+ /* OpenSSL returns X509_V_OK when no certificates are requested. This is
+ * classed by them as a bug, but it's assumed by at least NGINX. */
+ hs->new_session->verify_result = X509_V_OK;
+ }
+ }
+
+ /* HTTP/2 negotiation depends on the cipher suite, so ALPN negotiation was
+ * deferred. Complete it now. */
+ if (!ssl_negotiate_alpn(hs, &al, &client_hello)) {
+ goto f_err;
+ }
+
+ /* Now that all parameters are known, initialize the handshake hash and hash
+ * the ClientHello. */
+ if (!SSL_TRANSCRIPT_init_hash(&hs->transcript, ssl3_protocol_version(ssl),
+ hs->new_cipher->algorithm_prf) ||
+ !ssl_hash_current_message(hs)) {
+ goto f_err;
+ }
+
+ /* Release the handshake buffer if client authentication isn't required. */
+ if (!hs->cert_request) {
+ SSL_TRANSCRIPT_free_buffer(&hs->transcript);
+ }
+
+ ret = 1;
+
+ if (0) {
+ f_err:
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, al);
+ }
+
+err:
+ SSL_SESSION_free(session);
+ return ret;
+}
+
+static int ssl3_send_server_hello(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+
+ /* We only accept ChannelIDs on connections with ECDHE in order to avoid a
+ * known attack while we fix ChannelID itself. */
+ if (ssl->s3->tlsext_channel_id_valid &&
+ (hs->new_cipher->algorithm_mkey & SSL_kECDHE) == 0) {
+ ssl->s3->tlsext_channel_id_valid = 0;
+ }
+
+ /* If this is a resumption and the original handshake didn't support
+ * ChannelID then we didn't record the original handshake hashes in the
+ * session and so cannot resume with ChannelIDs. */
+ if (ssl->session != NULL &&
+ ssl->session->original_handshake_hash_len == 0) {
+ ssl->s3->tlsext_channel_id_valid = 0;
+ }
+
+ struct OPENSSL_timeval now;
+ ssl_get_current_time(ssl, &now);
+ ssl->s3->server_random[0] = now.tv_sec >> 24;
+ ssl->s3->server_random[1] = now.tv_sec >> 16;
+ ssl->s3->server_random[2] = now.tv_sec >> 8;
+ ssl->s3->server_random[3] = now.tv_sec;
+ if (!RAND_bytes(ssl->s3->server_random + 4, SSL3_RANDOM_SIZE - 4)) {
+ return -1;
+ }
+
+ /* TODO(davidben): Implement the TLS 1.1 and 1.2 downgrade sentinels once TLS
+ * 1.3 is finalized and we are not implementing a draft version. */
+
+ const SSL_SESSION *session = hs->new_session;
+ if (ssl->session != NULL) {
+ session = ssl->session;
+ }
+
+ CBB cbb, body, session_id;
+ if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_SERVER_HELLO) ||
+ !CBB_add_u16(&body, ssl->version) ||
+ !CBB_add_bytes(&body, ssl->s3->server_random, SSL3_RANDOM_SIZE) ||
+ !CBB_add_u8_length_prefixed(&body, &session_id) ||
+ !CBB_add_bytes(&session_id, session->session_id,
+ session->session_id_length) ||
+ !CBB_add_u16(&body, ssl_cipher_get_value(hs->new_cipher)) ||
+ !CBB_add_u8(&body, 0 /* no compression */) ||
+ !ssl_add_serverhello_tlsext(hs, &body) ||
+ !ssl_add_message_cbb(ssl, &cbb)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ CBB_cleanup(&cbb);
+ return -1;
+ }
+
+ return 1;
+}
+
+static int ssl3_send_server_certificate(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ if (!ssl_has_certificate(ssl)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATE_SET);
+ return -1;
+ }
+
+ if (!ssl3_output_cert_chain(ssl)) {
+ return -1;
+ }
+ return 1;
+}
+
+static int ssl3_send_certificate_status(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ CBB cbb, body, ocsp_response;
+ if (!ssl->method->init_message(ssl, &cbb, &body,
+ SSL3_MT_CERTIFICATE_STATUS) ||
+ !CBB_add_u8(&body, TLSEXT_STATUSTYPE_ocsp) ||
+ !CBB_add_u24_length_prefixed(&body, &ocsp_response) ||
+ !CBB_add_bytes(&ocsp_response,
+ CRYPTO_BUFFER_data(ssl->cert->ocsp_response),
+ CRYPTO_BUFFER_len(ssl->cert->ocsp_response)) ||
+ !ssl_add_message_cbb(ssl, &cbb)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ CBB_cleanup(&cbb);
+ return -1;
+ }
+
+ return 1;
+}
+
+static int ssl3_send_server_key_exchange(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ CBB cbb, child;
+ CBB_zero(&cbb);
+
+ /* Put together the parameters. */
+ if (hs->state == SSL3_ST_SW_KEY_EXCH_A) {
+ uint32_t alg_k = hs->new_cipher->algorithm_mkey;
+ uint32_t alg_a = hs->new_cipher->algorithm_auth;
+
+ /* Pre-allocate enough room to comfortably fit an ECDHE public key. */
+ if (!CBB_init(&cbb, 128)) {
+ goto err;
+ }
+
+ /* PSK ciphers begin with an identity hint. */
+ if (alg_a & SSL_aPSK) {
+ size_t len =
+ (ssl->psk_identity_hint == NULL) ? 0 : strlen(ssl->psk_identity_hint);
+ if (!CBB_add_u16_length_prefixed(&cbb, &child) ||
+ !CBB_add_bytes(&child, (const uint8_t *)ssl->psk_identity_hint,
+ len)) {
+ goto err;
+ }
+ }
+
+ if (alg_k & SSL_kDHE) {
+ /* Determine the group to use. */
+ DH *params = ssl->cert->dh_tmp;
+ if (params == NULL && ssl->cert->dh_tmp_cb != NULL) {
+ params = ssl->cert->dh_tmp_cb(ssl, 0, 1024);
+ }
+ if (params == NULL) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_TMP_DH_KEY);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
+ goto err;
+ }
+
+ /* Set up DH, generate a key, and emit the public half. */
+ DH *dh = DHparams_dup(params);
+ if (dh == NULL) {
+ goto err;
+ }
+
+ SSL_ECDH_CTX_init_for_dhe(&hs->ecdh_ctx, dh);
+ if (!CBB_add_u16_length_prefixed(&cbb, &child) ||
+ !BN_bn2cbb_padded(&child, BN_num_bytes(params->p), params->p) ||
+ !CBB_add_u16_length_prefixed(&cbb, &child) ||
+ !BN_bn2cbb_padded(&child, BN_num_bytes(params->g), params->g) ||
+ !CBB_add_u16_length_prefixed(&cbb, &child) ||
+ !SSL_ECDH_CTX_offer(&hs->ecdh_ctx, &child)) {
+ goto err;
+ }
+ } else if (alg_k & SSL_kECDHE) {
+ /* Determine the group to use. */
+ uint16_t group_id;
+ if (!tls1_get_shared_group(hs, &group_id)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_TMP_ECDH_KEY);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
+ goto err;
+ }
+ hs->new_session->group_id = group_id;
+
+ /* Set up ECDH, generate a key, and emit the public half. */
+ if (!SSL_ECDH_CTX_init(&hs->ecdh_ctx, group_id) ||
+ !CBB_add_u8(&cbb, NAMED_CURVE_TYPE) ||
+ !CBB_add_u16(&cbb, group_id) ||
+ !CBB_add_u8_length_prefixed(&cbb, &child) ||
+ !SSL_ECDH_CTX_offer(&hs->ecdh_ctx, &child)) {
+ goto err;
+ }
+ } else {
+ assert(alg_k & SSL_kPSK);
+ }
+
+ if (!CBB_finish(&cbb, &hs->server_params, &hs->server_params_len)) {
+ goto err;
+ }
+ }
+
+ /* Assemble the message. */
+ CBB body;
+ if (!ssl->method->init_message(ssl, &cbb, &body,
+ SSL3_MT_SERVER_KEY_EXCHANGE) ||
+ !CBB_add_bytes(&body, hs->server_params, hs->server_params_len)) {
+ goto err;
+ }
+
+ /* Add a signature. */
+ if (ssl_cipher_uses_certificate_auth(hs->new_cipher)) {
+ if (!ssl_has_private_key(ssl)) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ goto err;
+ }
+
+ /* Determine the signature algorithm. */
+ uint16_t signature_algorithm;
+ if (!tls1_choose_signature_algorithm(hs, &signature_algorithm)) {
+ goto err;
+ }
+ if (ssl3_protocol_version(ssl) >= TLS1_2_VERSION) {
+ if (!CBB_add_u16(&body, signature_algorithm)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ goto err;
+ }
+ }
+
+ /* Add space for the signature. */
+ const size_t max_sig_len = ssl_private_key_max_signature_len(ssl);
+ uint8_t *ptr;
+ if (!CBB_add_u16_length_prefixed(&body, &child) ||
+ !CBB_reserve(&child, &ptr, max_sig_len)) {
+ goto err;
+ }
+
+ size_t sig_len;
+ enum ssl_private_key_result_t sign_result;
+ if (hs->state == SSL3_ST_SW_KEY_EXCH_A) {
+ CBB transcript;
+ uint8_t *transcript_data;
+ size_t transcript_len;
+ if (!CBB_init(&transcript,
+ 2 * SSL3_RANDOM_SIZE + hs->server_params_len) ||
+ !CBB_add_bytes(&transcript, ssl->s3->client_random,
+ SSL3_RANDOM_SIZE) ||
+ !CBB_add_bytes(&transcript, ssl->s3->server_random,
+ SSL3_RANDOM_SIZE) ||
+ !CBB_add_bytes(&transcript, hs->server_params,
+ hs->server_params_len) ||
+ !CBB_finish(&transcript, &transcript_data, &transcript_len)) {
+ CBB_cleanup(&transcript);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ goto err;
+ }
+
+ sign_result = ssl_private_key_sign(ssl, ptr, &sig_len, max_sig_len,
+ signature_algorithm, transcript_data,
+ transcript_len);
+ OPENSSL_free(transcript_data);
+ } else {
+ assert(hs->state == SSL3_ST_SW_KEY_EXCH_B);
+ sign_result = ssl_private_key_complete(ssl, ptr, &sig_len, max_sig_len);
+ }
+
+ switch (sign_result) {
+ case ssl_private_key_success:
+ if (!CBB_did_write(&child, sig_len)) {
+ goto err;
+ }
+ break;
+ case ssl_private_key_failure:
+ goto err;
+ case ssl_private_key_retry:
+ ssl->rwstate = SSL_PRIVATE_KEY_OPERATION;
+ hs->state = SSL3_ST_SW_KEY_EXCH_B;
+ goto err;
+ }
+ }
+
+ if (!ssl_add_message_cbb(ssl, &cbb)) {
+ goto err;
+ }
+
+ OPENSSL_free(hs->server_params);
+ hs->server_params = NULL;
+ hs->server_params_len = 0;
+
+ return 1;
+
+err:
+ CBB_cleanup(&cbb);
+ return -1;
+}
+
+static int add_cert_types(SSL *ssl, CBB *cbb) {
+ /* Get configured signature algorithms. */
+ int have_rsa_sign = 0;
+ int have_ecdsa_sign = 0;
+ const uint16_t *sig_algs;
+ size_t num_sig_algs = tls12_get_verify_sigalgs(ssl, &sig_algs);
+ for (size_t i = 0; i < num_sig_algs; i++) {
+ switch (sig_algs[i]) {
+ case SSL_SIGN_RSA_PKCS1_SHA512:
+ case SSL_SIGN_RSA_PKCS1_SHA384:
+ case SSL_SIGN_RSA_PKCS1_SHA256:
+ case SSL_SIGN_RSA_PKCS1_SHA1:
+ have_rsa_sign = 1;
+ break;
+
+ case SSL_SIGN_ECDSA_SECP521R1_SHA512:
+ case SSL_SIGN_ECDSA_SECP384R1_SHA384:
+ case SSL_SIGN_ECDSA_SECP256R1_SHA256:
+ case SSL_SIGN_ECDSA_SHA1:
+ have_ecdsa_sign = 1;
+ break;
+ }
+ }
+
+ if (have_rsa_sign && !CBB_add_u8(cbb, SSL3_CT_RSA_SIGN)) {
+ return 0;
+ }
+
+ /* ECDSA certs can be used with RSA cipher suites as well so we don't need to
+ * check for SSL_kECDH or SSL_kECDHE. */
+ if (ssl->version >= TLS1_VERSION && have_ecdsa_sign &&
+ !CBB_add_u8(cbb, TLS_CT_ECDSA_SIGN)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+static int ssl3_send_certificate_request(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ CBB cbb, body, cert_types, sigalgs_cbb;
+ if (!ssl->method->init_message(ssl, &cbb, &body,
+ SSL3_MT_CERTIFICATE_REQUEST) ||
+ !CBB_add_u8_length_prefixed(&body, &cert_types) ||
+ !add_cert_types(ssl, &cert_types)) {
+ goto err;
+ }
+
+ if (ssl3_protocol_version(ssl) >= TLS1_2_VERSION) {
+ const uint16_t *sigalgs;
+ size_t num_sigalgs = tls12_get_verify_sigalgs(ssl, &sigalgs);
+ if (!CBB_add_u16_length_prefixed(&body, &sigalgs_cbb)) {
+ goto err;
+ }
+
+ for (size_t i = 0; i < num_sigalgs; i++) {
+ if (!CBB_add_u16(&sigalgs_cbb, sigalgs[i])) {
+ goto err;
+ }
+ }
+ }
+
+ if (!ssl_add_client_CA_list(ssl, &body) ||
+ !ssl_add_message_cbb(ssl, &cbb)) {
+ goto err;
+ }
+
+ return 1;
+
+err:
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ CBB_cleanup(&cbb);
+ return -1;
+}
+
+static int ssl3_send_server_hello_done(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ CBB cbb, body;
+ if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_SERVER_HELLO_DONE) ||
+ !ssl_add_message_cbb(ssl, &cbb)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ CBB_cleanup(&cbb);
+ return -1;
+ }
+
+ return 1;
+}
+
+static int ssl3_get_client_certificate(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ assert(hs->cert_request);
+
+ int msg_ret = ssl->method->ssl_get_message(ssl);
+ if (msg_ret <= 0) {
+ return msg_ret;
+ }
+
+ if (ssl->s3->tmp.message_type != SSL3_MT_CERTIFICATE) {
+ if (ssl->version == SSL3_VERSION &&
+ ssl->s3->tmp.message_type == SSL3_MT_CLIENT_KEY_EXCHANGE) {
+ /* In SSL 3.0, the Certificate message is omitted to signal no
+ * certificate. */
+ if (ssl->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
+ return -1;
+ }
+
+ /* OpenSSL returns X509_V_OK when no certificates are received. This is
+ * classed by them as a bug, but it's assumed by at least NGINX. */
+ hs->new_session->verify_result = X509_V_OK;
+ ssl->s3->tmp.reuse_message = 1;
+ return 1;
+ }
+
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ if (!ssl_hash_current_message(hs)) {
+ return -1;
+ }
+
+ 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);
+ EVP_PKEY_free(hs->peer_pubkey);
+ hs->peer_pubkey = NULL;
+ 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);
+ if (hs->new_session->certs == NULL) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
+ return -1;
+ }
+
+ if (CBS_len(&certificate_msg) != 0 ||
+ !ssl->ctx->x509_method->session_cache_objects(hs->new_session)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ return -1;
+ }
+
+ if (sk_CRYPTO_BUFFER_num(hs->new_session->certs) == 0) {
+ /* No client certificate so the handshake buffer may be discarded. */
+ SSL_TRANSCRIPT_free_buffer(&hs->transcript);
+
+ /* In SSL 3.0, sending no certificate is signaled by omitting the
+ * Certificate message. */
+ if (ssl->version == SSL3_VERSION) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATES_RETURNED);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
+ return -1;
+ }
+
+ if (ssl->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
+ /* Fail for TLS only if we required a certificate */
+ OPENSSL_PUT_ERROR(SSL, SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
+ return -1;
+ }
+
+ /* OpenSSL returns X509_V_OK when no certificates are received. This is
+ * classed by them as a bug, but it's assumed by at least NGINX. */
+ hs->new_session->verify_result = X509_V_OK;
+ return 1;
+ }
+
+ /* The hash will have been filled in. */
+ if (ssl->retain_only_sha256_of_client_certs) {
+ hs->new_session->peer_sha256_valid = 1;
+ }
+
+ if (!ssl->ctx->x509_method->session_verify_cert_chain(hs->new_session, ssl)) {
+ return -1;
+ }
+
+ return 1;
+}
+
+static int ssl3_get_client_key_exchange(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ int al;
+ CBS client_key_exchange;
+ uint32_t alg_k;
+ uint32_t alg_a;
+ uint8_t *premaster_secret = NULL;
+ size_t premaster_secret_len = 0;
+ uint8_t *decrypt_buf = NULL;
+
+ unsigned psk_len = 0;
+ uint8_t psk[PSK_MAX_PSK_LEN];
+
+ if (hs->state == SSL3_ST_SR_KEY_EXCH_A) {
+ int ret = ssl->method->ssl_get_message(ssl);
+ if (ret <= 0) {
+ return ret;
+ }
+
+ if (!ssl_check_message_type(ssl, SSL3_MT_CLIENT_KEY_EXCHANGE) ||
+ !ssl_hash_current_message(hs)) {
+ return -1;
+ }
+ }
+
+ CBS_init(&client_key_exchange, ssl->init_msg, ssl->init_num);
+ alg_k = hs->new_cipher->algorithm_mkey;
+ alg_a = hs->new_cipher->algorithm_auth;
+
+ /* If using a PSK key exchange, prepare the pre-shared key. */
+ if (alg_a & SSL_aPSK) {
+ CBS psk_identity;
+
+ /* If using PSK, the ClientKeyExchange contains a psk_identity. If PSK,
+ * then this is the only field in the message. */
+ if (!CBS_get_u16_length_prefixed(&client_key_exchange, &psk_identity) ||
+ ((alg_k & SSL_kPSK) && CBS_len(&client_key_exchange) != 0)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ al = SSL_AD_DECODE_ERROR;
+ goto f_err;
+ }
+
+ if (ssl->psk_server_callback == NULL) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_PSK_NO_SERVER_CB);
+ al = SSL_AD_INTERNAL_ERROR;
+ goto f_err;
+ }
+
+ if (CBS_len(&psk_identity) > PSK_MAX_IDENTITY_LEN ||
+ CBS_contains_zero_byte(&psk_identity)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DATA_LENGTH_TOO_LONG);
+ al = SSL_AD_ILLEGAL_PARAMETER;
+ goto f_err;
+ }
+
+ if (!CBS_strdup(&psk_identity, &hs->new_session->psk_identity)) {
+ al = SSL_AD_INTERNAL_ERROR;
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto f_err;
+ }
+
+ /* Look up the key for the identity. */
+ psk_len = ssl->psk_server_callback(ssl, hs->new_session->psk_identity, psk,
+ sizeof(psk));
+ if (psk_len > PSK_MAX_PSK_LEN) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ al = SSL_AD_INTERNAL_ERROR;
+ goto f_err;
+ } else if (psk_len == 0) {
+ /* PSK related to the given identity not found */
+ OPENSSL_PUT_ERROR(SSL, SSL_R_PSK_IDENTITY_NOT_FOUND);
+ al = SSL_AD_UNKNOWN_PSK_IDENTITY;
+ goto f_err;
+ }
+ }
+
+ /* Depending on the key exchange method, compute |premaster_secret| and
+ * |premaster_secret_len|. */
+ if (alg_k & SSL_kRSA) {
+ /* Allocate a buffer large enough for an RSA decryption. */
+ const size_t rsa_size = ssl_private_key_max_signature_len(ssl);
+ decrypt_buf = OPENSSL_malloc(rsa_size);
+ if (decrypt_buf == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ enum ssl_private_key_result_t decrypt_result;
+ size_t decrypt_len;
+ if (hs->state == SSL3_ST_SR_KEY_EXCH_A) {
+ if (!ssl_has_private_key(ssl) ||
+ ssl_private_key_type(ssl) != NID_rsaEncryption) {
+ al = SSL_AD_HANDSHAKE_FAILURE;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_RSA_CERTIFICATE);
+ goto f_err;
+ }
+ CBS encrypted_premaster_secret;
+ if (ssl->version > SSL3_VERSION) {
+ if (!CBS_get_u16_length_prefixed(&client_key_exchange,
+ &encrypted_premaster_secret) ||
+ CBS_len(&client_key_exchange) != 0) {
+ al = SSL_AD_DECODE_ERROR;
+ OPENSSL_PUT_ERROR(SSL,
+ SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG);
+ goto f_err;
+ }
+ } else {
+ encrypted_premaster_secret = client_key_exchange;
+ }
+
+ /* Decrypt with no padding. PKCS#1 padding will be removed as part of the
+ * timing-sensitive code below. */
+ decrypt_result = ssl_private_key_decrypt(
+ ssl, decrypt_buf, &decrypt_len, rsa_size,
+ CBS_data(&encrypted_premaster_secret),
+ CBS_len(&encrypted_premaster_secret));
+ } else {
+ assert(hs->state == SSL3_ST_SR_KEY_EXCH_B);
+ /* Complete async decrypt. */
+ decrypt_result =
+ ssl_private_key_complete(ssl, decrypt_buf, &decrypt_len, rsa_size);
+ }
+
+ switch (decrypt_result) {
+ case ssl_private_key_success:
+ break;
+ case ssl_private_key_failure:
+ goto err;
+ case ssl_private_key_retry:
+ ssl->rwstate = SSL_PRIVATE_KEY_OPERATION;
+ hs->state = SSL3_ST_SR_KEY_EXCH_B;
+ goto err;
+ }
+
+ if (decrypt_len != rsa_size) {
+ al = SSL_AD_DECRYPT_ERROR;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECRYPTION_FAILED);
+ goto f_err;
+ }
+
+ /* Prepare a random premaster, to be used on invalid padding. See RFC 5246,
+ * section 7.4.7.1. */
+ premaster_secret_len = SSL_MAX_MASTER_KEY_LENGTH;
+ premaster_secret = OPENSSL_malloc(premaster_secret_len);
+ if (premaster_secret == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ if (!RAND_bytes(premaster_secret, premaster_secret_len)) {
+ goto err;
+ }
+
+ /* The smallest padded premaster is 11 bytes of overhead. Small keys are
+ * publicly invalid. */
+ if (decrypt_len < 11 + premaster_secret_len) {
+ al = SSL_AD_DECRYPT_ERROR;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECRYPTION_FAILED);
+ goto f_err;
+ }
+
+ /* Check the padding. See RFC 3447, section 7.2.2. */
+ size_t padding_len = decrypt_len - premaster_secret_len;
+ uint8_t good = constant_time_eq_int_8(decrypt_buf[0], 0) &
+ constant_time_eq_int_8(decrypt_buf[1], 2);
+ for (size_t i = 2; i < padding_len - 1; i++) {
+ good &= ~constant_time_is_zero_8(decrypt_buf[i]);
+ }
+ good &= constant_time_is_zero_8(decrypt_buf[padding_len - 1]);
+
+ /* The premaster secret must begin with |client_version|. This too must be
+ * checked in constant time (http://eprint.iacr.org/2003/052/). */
+ good &= constant_time_eq_8(decrypt_buf[padding_len],
+ (unsigned)(hs->client_version >> 8));
+ good &= constant_time_eq_8(decrypt_buf[padding_len + 1],
+ (unsigned)(hs->client_version & 0xff));
+
+ /* Select, in constant time, either the decrypted premaster or the random
+ * premaster based on |good|. */
+ for (size_t i = 0; i < premaster_secret_len; i++) {
+ premaster_secret[i] = constant_time_select_8(
+ good, decrypt_buf[padding_len + i], premaster_secret[i]);
+ }
+
+ OPENSSL_free(decrypt_buf);
+ decrypt_buf = NULL;
+ } else if (alg_k & (SSL_kECDHE|SSL_kDHE)) {
+ /* Parse the ClientKeyExchange. */
+ CBS peer_key;
+ if (!SSL_ECDH_CTX_get_key(&hs->ecdh_ctx, &client_key_exchange, &peer_key) ||
+ CBS_len(&client_key_exchange) != 0) {
+ al = SSL_AD_DECODE_ERROR;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ goto f_err;
+ }
+
+ /* Compute the premaster. */
+ uint8_t alert = SSL_AD_DECODE_ERROR;
+ if (!SSL_ECDH_CTX_finish(&hs->ecdh_ctx, &premaster_secret,
+ &premaster_secret_len, &alert, CBS_data(&peer_key),
+ CBS_len(&peer_key))) {
+ al = alert;
+ goto f_err;
+ }
+
+ /* The key exchange state may now be discarded. */
+ SSL_ECDH_CTX_cleanup(&hs->ecdh_ctx);
+ } else if (alg_k & SSL_kPSK) {
+ /* For plain PSK, other_secret is a block of 0s with the same length as the
+ * pre-shared key. */
+ premaster_secret_len = psk_len;
+ premaster_secret = OPENSSL_malloc(premaster_secret_len);
+ if (premaster_secret == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ OPENSSL_memset(premaster_secret, 0, premaster_secret_len);
+ } else {
+ al = SSL_AD_HANDSHAKE_FAILURE;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CIPHER_TYPE);
+ goto f_err;
+ }
+
+ /* For a PSK cipher suite, the actual pre-master secret is combined with the
+ * pre-shared key. */
+ if (alg_a & SSL_aPSK) {
+ CBB new_premaster, child;
+ uint8_t *new_data;
+ size_t new_len;
+
+ CBB_zero(&new_premaster);
+ if (!CBB_init(&new_premaster, 2 + psk_len + 2 + premaster_secret_len) ||
+ !CBB_add_u16_length_prefixed(&new_premaster, &child) ||
+ !CBB_add_bytes(&child, premaster_secret, premaster_secret_len) ||
+ !CBB_add_u16_length_prefixed(&new_premaster, &child) ||
+ !CBB_add_bytes(&child, psk, psk_len) ||
+ !CBB_finish(&new_premaster, &new_data, &new_len)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ CBB_cleanup(&new_premaster);
+ goto err;
+ }
+
+ OPENSSL_cleanse(premaster_secret, premaster_secret_len);
+ OPENSSL_free(premaster_secret);
+ premaster_secret = new_data;
+ premaster_secret_len = new_len;
+ }
+
+ /* Compute the master secret */
+ hs->new_session->master_key_length = tls1_generate_master_secret(
+ hs, hs->new_session->master_key, premaster_secret, premaster_secret_len);
+ if (hs->new_session->master_key_length == 0) {
+ goto err;
+ }
+ hs->new_session->extended_master_secret = hs->extended_master_secret;
+
+ OPENSSL_cleanse(premaster_secret, premaster_secret_len);
+ OPENSSL_free(premaster_secret);
+ return 1;
+
+f_err:
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, al);
+err:
+ if (premaster_secret != NULL) {
+ OPENSSL_cleanse(premaster_secret, premaster_secret_len);
+ OPENSSL_free(premaster_secret);
+ }
+ OPENSSL_free(decrypt_buf);
+
+ return -1;
+}
+
+static int ssl3_get_cert_verify(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ int al;
+ CBS certificate_verify, signature;
+
+ /* Only RSA and ECDSA client certificates are supported, so a
+ * CertificateVerify is required if and only if there's a client certificate.
+ * */
+ if (hs->peer_pubkey == NULL) {
+ SSL_TRANSCRIPT_free_buffer(&hs->transcript);
+ return 1;
+ }
+
+ int msg_ret = ssl->method->ssl_get_message(ssl);
+ if (msg_ret <= 0) {
+ return msg_ret;
+ }
+
+ if (!ssl_check_message_type(ssl, SSL3_MT_CERTIFICATE_VERIFY)) {
+ return -1;
+ }
+
+ CBS_init(&certificate_verify, ssl->init_msg, ssl->init_num);
+
+ /* Determine the digest type if needbe. */
+ uint16_t signature_algorithm = 0;
+ if (ssl3_protocol_version(ssl) >= TLS1_2_VERSION) {
+ if (!CBS_get_u16(&certificate_verify, &signature_algorithm)) {
+ al = SSL_AD_DECODE_ERROR;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ goto f_err;
+ }
+ if (!tls12_check_peer_sigalg(ssl, &al, signature_algorithm)) {
+ goto f_err;
+ }
+ hs->new_session->peer_signature_algorithm = signature_algorithm;
+ } else if (hs->peer_pubkey->type == EVP_PKEY_RSA) {
+ signature_algorithm = SSL_SIGN_RSA_PKCS1_MD5_SHA1;
+ } else if (hs->peer_pubkey->type == EVP_PKEY_EC) {
+ signature_algorithm = SSL_SIGN_ECDSA_SHA1;
+ } else {
+ al = SSL_AD_UNSUPPORTED_CERTIFICATE;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE);
+ goto f_err;
+ }
+
+ /* Parse and verify the signature. */
+ if (!CBS_get_u16_length_prefixed(&certificate_verify, &signature) ||
+ CBS_len(&certificate_verify) != 0) {
+ al = SSL_AD_DECODE_ERROR;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ goto f_err;
+ }
+
+ int sig_ok;
+ /* The SSL3 construction for CertificateVerify does not decompose into a
+ * single final digest and signature, and must be special-cased. */
+ if (ssl3_protocol_version(ssl) == SSL3_VERSION) {
+ uint8_t digest[EVP_MAX_MD_SIZE];
+ size_t digest_len;
+ if (!SSL_TRANSCRIPT_ssl3_cert_verify_hash(&hs->transcript, digest,
+ &digest_len, hs->new_session,
+ signature_algorithm)) {
+ goto err;
+ }
+
+ EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new(hs->peer_pubkey, NULL);
+ sig_ok = pctx != NULL &&
+ EVP_PKEY_verify_init(pctx) &&
+ EVP_PKEY_verify(pctx, CBS_data(&signature), CBS_len(&signature),
+ digest, digest_len);
+ EVP_PKEY_CTX_free(pctx);
+ } else {
+ sig_ok = ssl_public_key_verify(
+ ssl, CBS_data(&signature), CBS_len(&signature), signature_algorithm,
+ hs->peer_pubkey, (const uint8_t *)hs->transcript.buffer->data,
+ hs->transcript.buffer->length);
+ }
+
+#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+ sig_ok = 1;
+ ERR_clear_error();
+#endif
+ if (!sig_ok) {
+ al = SSL_AD_DECRYPT_ERROR;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SIGNATURE);
+ goto f_err;
+ }
+
+ /* The handshake buffer is no longer necessary, and we may hash the current
+ * message.*/
+ SSL_TRANSCRIPT_free_buffer(&hs->transcript);
+ if (!ssl_hash_current_message(hs)) {
+ goto err;
+ }
+
+ return 1;
+
+f_err:
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, al);
+err:
+ return 0;
+}
+
+/* ssl3_get_next_proto reads a Next Protocol Negotiation handshake message. It
+ * sets the next_proto member in s if found */
+static int ssl3_get_next_proto(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ int ret = ssl->method->ssl_get_message(ssl);
+ if (ret <= 0) {
+ return ret;
+ }
+
+ if (!ssl_check_message_type(ssl, SSL3_MT_NEXT_PROTO) ||
+ !ssl_hash_current_message(hs)) {
+ return -1;
+ }
+
+ CBS next_protocol, selected_protocol, padding;
+ CBS_init(&next_protocol, ssl->init_msg, ssl->init_num);
+ if (!CBS_get_u8_length_prefixed(&next_protocol, &selected_protocol) ||
+ !CBS_get_u8_length_prefixed(&next_protocol, &padding) ||
+ CBS_len(&next_protocol) != 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ return 0;
+ }
+
+ if (!CBS_stow(&selected_protocol, &ssl->s3->next_proto_negotiated,
+ &ssl->s3->next_proto_negotiated_len)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+/* ssl3_get_channel_id reads and verifies a ClientID handshake message. */
+static int ssl3_get_channel_id(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ int msg_ret = ssl->method->ssl_get_message(ssl);
+ if (msg_ret <= 0) {
+ return msg_ret;
+ }
+
+ if (!ssl_check_message_type(ssl, SSL3_MT_CHANNEL_ID) ||
+ !tls1_verify_channel_id(hs) ||
+ !ssl_hash_current_message(hs)) {
+ return -1;
+ }
+ return 1;
+}
+
+static int ssl3_send_new_session_ticket(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ const SSL_SESSION *session;
+ SSL_SESSION *session_copy = NULL;
+ if (ssl->session == NULL) {
+ /* Fix the timeout to measure from the ticket issuance time. */
+ ssl_session_rebase_time(ssl, hs->new_session);
+ session = hs->new_session;
+ } else {
+ /* We are renewing an existing session. Duplicate the session to adjust the
+ * timeout. */
+ session_copy = SSL_SESSION_dup(ssl->session, SSL_SESSION_INCLUDE_NONAUTH);
+ if (session_copy == NULL) {
+ return -1;
+ }
+
+ ssl_session_rebase_time(ssl, session_copy);
+ session = session_copy;
+ }
+
+ CBB cbb, body, ticket;
+ int ok =
+ ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_NEW_SESSION_TICKET) &&
+ CBB_add_u32(&body, session->timeout) &&
+ CBB_add_u16_length_prefixed(&body, &ticket) &&
+ ssl_encrypt_ticket(ssl, &ticket, session) &&
+ ssl_add_message_cbb(ssl, &cbb);
+
+ SSL_SESSION_free(session_copy);
+ CBB_cleanup(&cbb);
+
+ if (!ok) {
+ return -1;
+ }
+
+ return 1;
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/internal.h b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/internal.h
new file mode 100644
index 000000000..99980d843
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/internal.h
@@ -0,0 +1,2231 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2007 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ * ECC cipher suite support in OpenSSL originally developed by
+ * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
+ */
+/* ====================================================================
+ * Copyright 2005 Nokia. All rights reserved.
+ *
+ * The portions of the attached software ("Contribution") is developed by
+ * Nokia Corporation and is licensed pursuant to the OpenSSL open source
+ * license.
+ *
+ * The Contribution, originally written by Mika Kousa and Pasi Eronen of
+ * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites
+ * support (see RFC 4279) to OpenSSL.
+ *
+ * No patent licenses or other rights except those expressly stated in
+ * the OpenSSL open source license shall be deemed granted or received
+ * expressly, by implication, estoppel, or otherwise.
+ *
+ * No assurances are provided by Nokia that the Contribution does not
+ * infringe the patent or other intellectual property rights of any third
+ * party or that the license provides you with all the necessary rights
+ * to make use of the Contribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN
+ * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA
+ * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY
+ * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
+ * OTHERWISE.
+ */
+
+#ifndef OPENSSL_HEADER_SSL_INTERNAL_H
+#define OPENSSL_HEADER_SSL_INTERNAL_H
+
+#include <openssl/base.h>
+
+#include <openssl/aead.h>
+#include <openssl/ssl.h>
+#include <openssl/stack.h>
+
+
+#if defined(OPENSSL_WINDOWS)
+/* Windows defines struct timeval in winsock2.h. */
+OPENSSL_MSVC_PRAGMA(warning(push, 3))
+#include <winsock2.h>
+OPENSSL_MSVC_PRAGMA(warning(pop))
+#else
+#include <sys/time.h>
+#endif
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* Cipher suites. */
+
+/* Bits for |algorithm_mkey| (key exchange algorithm). */
+#define SSL_kRSA 0x00000001L
+#define SSL_kDHE 0x00000002L
+#define SSL_kECDHE 0x00000004L
+/* SSL_kPSK is only set for plain PSK, not ECDHE_PSK. */
+#define SSL_kPSK 0x00000008L
+#define SSL_kGENERIC 0x00000010L
+
+/* Bits for |algorithm_auth| (server authentication). */
+#define SSL_aRSA 0x00000001L
+#define SSL_aECDSA 0x00000002L
+/* SSL_aPSK is set for both PSK and ECDHE_PSK. */
+#define SSL_aPSK 0x00000004L
+#define SSL_aGENERIC 0x00000008L
+
+#define SSL_aCERT (SSL_aRSA | SSL_aECDSA)
+
+/* Bits for |algorithm_enc| (symmetric encryption). */
+#define SSL_3DES 0x00000001L
+#define SSL_AES128 0x00000002L
+#define SSL_AES256 0x00000004L
+#define SSL_AES128GCM 0x00000008L
+#define SSL_AES256GCM 0x00000010L
+#define SSL_eNULL 0x00000020L
+#define SSL_CHACHA20POLY1305 0x00000040L
+
+#define SSL_AES (SSL_AES128 | SSL_AES256 | SSL_AES128GCM | SSL_AES256GCM)
+
+/* Bits for |algorithm_mac| (symmetric authentication). */
+#define SSL_SHA1 0x00000001L
+#define SSL_SHA256 0x00000002L
+#define SSL_SHA384 0x00000004L
+/* SSL_AEAD is set for all AEADs. */
+#define SSL_AEAD 0x00000008L
+
+/* Bits for |algorithm_prf| (handshake digest). */
+#define SSL_HANDSHAKE_MAC_DEFAULT 0x1
+#define SSL_HANDSHAKE_MAC_SHA256 0x2
+#define SSL_HANDSHAKE_MAC_SHA384 0x4
+
+/* SSL_MAX_DIGEST is the number of digest types which exist. When adding a new
+ * one, update the table in ssl_cipher.c. */
+#define SSL_MAX_DIGEST 4
+
+/* ssl_cipher_get_evp_aead sets |*out_aead| to point to the correct EVP_AEAD
+ * object for |cipher| protocol version |version|. It sets |*out_mac_secret_len|
+ * and |*out_fixed_iv_len| to the MAC key length and fixed IV length,
+ * respectively. The MAC key length is zero except for legacy block and stream
+ * ciphers. It returns 1 on success and 0 on error. */
+int ssl_cipher_get_evp_aead(const EVP_AEAD **out_aead,
+ size_t *out_mac_secret_len,
+ size_t *out_fixed_iv_len,
+ const SSL_CIPHER *cipher, uint16_t version);
+
+/* ssl_get_handshake_digest returns the |EVP_MD| corresponding to
+ * |algorithm_prf| and the |version|. */
+const EVP_MD *ssl_get_handshake_digest(uint32_t algorithm_prf,
+ uint16_t version);
+
+/* ssl_create_cipher_list evaluates |rule_str| according to the ciphers in
+ * |ssl_method|. It sets |*out_cipher_list| to a newly-allocated
+ * |ssl_cipher_preference_list_st| containing the result. It returns 1 on
+ * success and 0 on failure. If |strict| is true, nonsense will be rejected. If
+ * false, nonsense will be silently ignored. An empty result is considered an
+ * error regardless of |strict|. */
+int ssl_create_cipher_list(
+ const SSL_PROTOCOL_METHOD *ssl_method,
+ struct ssl_cipher_preference_list_st **out_cipher_list,
+ const char *rule_str, int strict);
+
+/* ssl_cipher_get_value returns the cipher suite id of |cipher|. */
+uint16_t ssl_cipher_get_value(const SSL_CIPHER *cipher);
+
+/* ssl_cipher_get_key_type returns the |EVP_PKEY_*| value corresponding to the
+ * server key used in |cipher| or |EVP_PKEY_NONE| if there is none. */
+int ssl_cipher_get_key_type(const SSL_CIPHER *cipher);
+
+/* ssl_cipher_uses_certificate_auth returns one if |cipher| authenticates the
+ * server and, optionally, the client with a certificate. Otherwise it returns
+ * zero. */
+int ssl_cipher_uses_certificate_auth(const SSL_CIPHER *cipher);
+
+/* ssl_cipher_requires_server_key_exchange returns 1 if |cipher| requires a
+ * ServerKeyExchange message. Otherwise it returns 0.
+ *
+ * This function may return zero while still allowing |cipher| an optional
+ * ServerKeyExchange. This is the case for plain PSK ciphers. */
+int ssl_cipher_requires_server_key_exchange(const SSL_CIPHER *cipher);
+
+/* ssl_cipher_get_record_split_len, for TLS 1.0 CBC mode ciphers, returns the
+ * length of an encrypted 1-byte record, for use in record-splitting. Otherwise
+ * it returns zero. */
+size_t ssl_cipher_get_record_split_len(const SSL_CIPHER *cipher);
+
+
+/* Transcript layer. */
+
+/* SSL_TRANSCRIPT maintains the handshake transcript as a combination of a
+ * buffer and running hash. */
+typedef struct ssl_transcript_st {
+ /* buffer, if non-NULL, contains the handshake transcript. */
+ BUF_MEM *buffer;
+ /* hash, if initialized with an |EVP_MD|, maintains the handshake hash. For
+ * TLS 1.1 and below, it is the SHA-1 half. */
+ EVP_MD_CTX hash;
+ /* md5, if initialized with an |EVP_MD|, maintains the MD5 half of the
+ * handshake hash for TLS 1.1 and below. */
+ EVP_MD_CTX md5;
+} SSL_TRANSCRIPT;
+
+/* SSL_TRANSCRIPT_init initializes the handshake transcript. If called on an
+ * existing transcript, it resets the transcript and hash. It returns one on
+ * success and zero on failure. */
+int SSL_TRANSCRIPT_init(SSL_TRANSCRIPT *transcript);
+
+/* SSL_TRANSCRIPT_init_hash initializes the handshake hash based on the PRF and
+ * contents of the handshake transcript. Subsequent calls to
+ * |SSL_TRANSCRIPT_update| will update the rolling hash. It returns one on
+ * success and zero on failure. It is an error to call this function after the
+ * handshake buffer is released. */
+int SSL_TRANSCRIPT_init_hash(SSL_TRANSCRIPT *transcript, uint16_t version,
+ int algorithm_prf);
+
+/* SSL_TRANSCRIPT_cleanup cleans up the hash and transcript. */
+void SSL_TRANSCRIPT_cleanup(SSL_TRANSCRIPT *transcript);
+
+/* SSL_TRANSCRIPT_free_buffer releases the handshake buffer. Subsequent calls to
+ * |SSL_TRANSCRIPT_update| will not update the handshake buffer. */
+void SSL_TRANSCRIPT_free_buffer(SSL_TRANSCRIPT *transcript);
+
+/* SSL_TRANSCRIPT_digest_len returns the length of the PRF hash. */
+size_t SSL_TRANSCRIPT_digest_len(const SSL_TRANSCRIPT *transcript);
+
+/* SSL_TRANSCRIPT_md returns the PRF hash. For TLS 1.1 and below, this is
+ * |EVP_md5_sha1|. */
+const EVP_MD *SSL_TRANSCRIPT_md(const SSL_TRANSCRIPT *transcript);
+
+/* SSL_TRANSCRIPT_update adds |in| to the handshake buffer and handshake hash,
+ * whichever is enabled. It returns one on success and zero on failure. */
+int SSL_TRANSCRIPT_update(SSL_TRANSCRIPT *transcript, const uint8_t *in,
+ size_t in_len);
+
+/* SSL_TRANSCRIPT_get_hash writes the handshake hash to |out| which must have
+ * room for at least |SSL_TRANSCRIPT_digest_len| bytes. On success, it returns
+ * one and sets |*out_len| to the number of bytes written. Otherwise, it returns
+ * zero. */
+int SSL_TRANSCRIPT_get_hash(const SSL_TRANSCRIPT *transcript, uint8_t *out,
+ size_t *out_len);
+
+/* SSL_TRANSCRIPT_ssl3_cert_verify_hash writes the SSL 3.0 CertificateVerify
+ * hash into the bytes pointed to by |out| and writes the number of bytes to
+ * |*out_len|. |out| must have room for |EVP_MAX_MD_SIZE| bytes. It returns one
+ * on success and zero on failure. */
+int SSL_TRANSCRIPT_ssl3_cert_verify_hash(SSL_TRANSCRIPT *transcript,
+ uint8_t *out, size_t *out_len,
+ const SSL_SESSION *session,
+ int signature_algorithm);
+
+/* SSL_TRANSCRIPT_finish_mac computes the MAC for the Finished message into the
+ * bytes pointed by |out| and writes the number of bytes to |*out_len|. |out|
+ * must have room for |EVP_MAX_MD_SIZE| bytes. It returns one on success and
+ * zero on failure. */
+int SSL_TRANSCRIPT_finish_mac(SSL_TRANSCRIPT *transcript, uint8_t *out,
+ size_t *out_len, const SSL_SESSION *session,
+ int from_server, uint16_t version);
+
+/* tls1_prf computes the PRF function for |ssl|. It writes |out_len| bytes to
+ * |out|, using |secret| as the secret and |label| as the label. |seed1| and
+ * |seed2| are concatenated to form the seed parameter. It returns one on
+ * success and zero on failure. */
+int tls1_prf(const EVP_MD *digest, uint8_t *out, size_t out_len,
+ const uint8_t *secret, size_t secret_len, const char *label,
+ size_t label_len, const uint8_t *seed1, size_t seed1_len,
+ const uint8_t *seed2, size_t seed2_len);
+
+
+/* Encryption layer. */
+
+/* SSL_AEAD_CTX contains information about an AEAD that is being used to encrypt
+ * an SSL connection. */
+typedef struct ssl_aead_ctx_st {
+ const SSL_CIPHER *cipher;
+ EVP_AEAD_CTX ctx;
+ /* fixed_nonce contains any bytes of the nonce that are fixed for all
+ * records. */
+ uint8_t fixed_nonce[12];
+ uint8_t fixed_nonce_len, variable_nonce_len;
+ /* version is the protocol version that should be used with this AEAD. */
+ uint16_t version;
+ /* variable_nonce_included_in_record is non-zero if the variable nonce
+ * for a record is included as a prefix before the ciphertext. */
+ unsigned variable_nonce_included_in_record : 1;
+ /* random_variable_nonce is non-zero if the variable nonce is
+ * randomly generated, rather than derived from the sequence
+ * number. */
+ unsigned random_variable_nonce : 1;
+ /* omit_length_in_ad is non-zero if the length should be omitted in the
+ * AEAD's ad parameter. */
+ unsigned omit_length_in_ad : 1;
+ /* omit_version_in_ad is non-zero if the version should be omitted
+ * in the AEAD's ad parameter. */
+ unsigned omit_version_in_ad : 1;
+ /* omit_ad is non-zero if the AEAD's ad parameter should be omitted. */
+ unsigned omit_ad : 1;
+ /* xor_fixed_nonce is non-zero if the fixed nonce should be XOR'd into the
+ * variable nonce rather than prepended. */
+ unsigned xor_fixed_nonce : 1;
+} SSL_AEAD_CTX;
+
+/* SSL_AEAD_CTX_new creates a newly-allocated |SSL_AEAD_CTX| using the supplied
+ * key material. It returns NULL on error. Only one of |SSL_AEAD_CTX_open| or
+ * |SSL_AEAD_CTX_seal| may be used with the resulting object, depending on
+ * |direction|. |version| is the normalized protocol version, so DTLS 1.0 is
+ * represented as 0x0301, not 0xffef. */
+SSL_AEAD_CTX *SSL_AEAD_CTX_new(enum evp_aead_direction_t direction,
+ uint16_t version, const SSL_CIPHER *cipher,
+ const uint8_t *enc_key, size_t enc_key_len,
+ const uint8_t *mac_key, size_t mac_key_len,
+ const uint8_t *fixed_iv, size_t fixed_iv_len);
+
+/* SSL_AEAD_CTX_free frees |ctx|. */
+void SSL_AEAD_CTX_free(SSL_AEAD_CTX *ctx);
+
+/* SSL_AEAD_CTX_explicit_nonce_len returns the length of the explicit nonce for
+ * |ctx|, if any. |ctx| may be NULL to denote the null cipher. */
+size_t SSL_AEAD_CTX_explicit_nonce_len(const SSL_AEAD_CTX *ctx);
+
+/* SSL_AEAD_CTX_max_overhead returns the maximum overhead of calling
+ * |SSL_AEAD_CTX_seal|. |ctx| may be NULL to denote the null cipher. */
+size_t SSL_AEAD_CTX_max_overhead(const SSL_AEAD_CTX *ctx);
+
+/* SSL_AEAD_CTX_open authenticates and decrypts |in_len| bytes from |in|
+ * in-place. On success, it sets |*out| to the plaintext in |in| and returns
+ * one. Otherwise, it returns zero. |ctx| may be NULL to denote the null cipher.
+ * The output will always be |explicit_nonce_len| bytes ahead of |in|. */
+int SSL_AEAD_CTX_open(SSL_AEAD_CTX *ctx, CBS *out, uint8_t type,
+ uint16_t wire_version, const uint8_t seqnum[8],
+ uint8_t *in, size_t in_len);
+
+/* SSL_AEAD_CTX_seal encrypts and authenticates |in_len| bytes from |in| and
+ * writes the result to |out|. It returns one on success and zero on
+ * error. |ctx| may be NULL to denote the null cipher.
+ *
+ * If |in| and |out| alias then |out| + |explicit_nonce_len| must be == |in|. */
+int SSL_AEAD_CTX_seal(SSL_AEAD_CTX *ctx, uint8_t *out, size_t *out_len,
+ size_t max_out, uint8_t type, uint16_t wire_version,
+ const uint8_t seqnum[8], const uint8_t *in,
+ size_t in_len);
+
+
+/* DTLS replay bitmap. */
+
+/* DTLS1_BITMAP maintains a sliding window of 64 sequence numbers to detect
+ * replayed packets. It should be initialized by zeroing every field. */
+typedef struct dtls1_bitmap_st {
+ /* map is a bit mask of the last 64 sequence numbers. Bit
+ * |1<<i| corresponds to |max_seq_num - i|. */
+ uint64_t map;
+ /* max_seq_num is the largest sequence number seen so far as a 64-bit
+ * integer. */
+ uint64_t max_seq_num;
+} DTLS1_BITMAP;
+
+
+/* Record layer. */
+
+/* ssl_record_sequence_update increments the sequence number in |seq|. It
+ * returns one on success and zero on wraparound. */
+int ssl_record_sequence_update(uint8_t *seq, size_t seq_len);
+
+/* ssl_record_prefix_len returns the length of the prefix before the ciphertext
+ * of a record for |ssl|.
+ *
+ * TODO(davidben): Expose this as part of public API once the high-level
+ * buffer-free APIs are available. */
+size_t ssl_record_prefix_len(const SSL *ssl);
+
+enum ssl_open_record_t {
+ ssl_open_record_success,
+ ssl_open_record_discard,
+ ssl_open_record_partial,
+ ssl_open_record_close_notify,
+ ssl_open_record_fatal_alert,
+ ssl_open_record_error,
+};
+
+/* tls_open_record decrypts a record from |in| in-place.
+ *
+ * If the input did not contain a complete record, it returns
+ * |ssl_open_record_partial|. It sets |*out_consumed| to the total number of
+ * bytes necessary. It is guaranteed that a successful call to |tls_open_record|
+ * will consume at least that many bytes.
+ *
+ * Otherwise, it sets |*out_consumed| to the number of bytes of input
+ * consumed. Note that input may be consumed on all return codes if a record was
+ * decrypted.
+ *
+ * On success, it returns |ssl_open_record_success|. It sets |*out_type| to the
+ * record type and |*out| to the record body in |in|. Note that |*out| may be
+ * empty.
+ *
+ * If a record was successfully processed but should be discarded, it returns
+ * |ssl_open_record_discard|.
+ *
+ * If a record was successfully processed but is a close_notify or fatal alert,
+ * it returns |ssl_open_record_close_notify| or |ssl_open_record_fatal_alert|.
+ *
+ * On failure, it returns |ssl_open_record_error| and sets |*out_alert| to an
+ * alert to emit. */
+enum ssl_open_record_t tls_open_record(SSL *ssl, uint8_t *out_type, CBS *out,
+ size_t *out_consumed, uint8_t *out_alert,
+ uint8_t *in, size_t in_len);
+
+/* dtls_open_record implements |tls_open_record| for DTLS. It never returns
+ * |ssl_open_record_partial| but otherwise behaves analogously. */
+enum ssl_open_record_t dtls_open_record(SSL *ssl, uint8_t *out_type, CBS *out,
+ size_t *out_consumed,
+ uint8_t *out_alert, uint8_t *in,
+ size_t in_len);
+
+/* ssl_seal_align_prefix_len returns the length of the prefix before the start
+ * of the bulk of the ciphertext when sealing a record with |ssl|. Callers may
+ * use this to align buffers.
+ *
+ * Note when TLS 1.0 CBC record-splitting is enabled, this includes the one byte
+ * record and is the offset into second record's ciphertext. Thus sealing a
+ * small record may result in a smaller output than this value.
+ *
+ * TODO(davidben): Is this alignment valuable? Record-splitting makes this a
+ * mess. */
+size_t ssl_seal_align_prefix_len(const SSL *ssl);
+
+/* tls_seal_record seals a new record of type |type| and body |in| and writes it
+ * to |out|. At most |max_out| bytes will be written. It returns one on success
+ * and zero on error. If enabled, |tls_seal_record| implements TLS 1.0 CBC 1/n-1
+ * record splitting and may write two records concatenated.
+ *
+ * For a large record, the bulk of the ciphertext will begin
+ * |ssl_seal_align_prefix_len| bytes into out. Aligning |out| appropriately may
+ * improve performance. It writes at most |in_len| + |SSL_max_seal_overhead|
+ * bytes to |out|.
+ *
+ * |in| and |out| may not alias. */
+int tls_seal_record(SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out,
+ uint8_t type, const uint8_t *in, size_t in_len);
+
+enum dtls1_use_epoch_t {
+ dtls1_use_previous_epoch,
+ dtls1_use_current_epoch,
+};
+
+/* dtls_max_seal_overhead returns the maximum overhead, in bytes, of sealing a
+ * record. */
+size_t dtls_max_seal_overhead(const SSL *ssl, enum dtls1_use_epoch_t use_epoch);
+
+/* dtls_seal_prefix_len returns the number of bytes of prefix to reserve in
+ * front of the plaintext when sealing a record in-place. */
+size_t dtls_seal_prefix_len(const SSL *ssl, enum dtls1_use_epoch_t use_epoch);
+
+/* dtls_seal_record implements |tls_seal_record| for DTLS. |use_epoch| selects
+ * which epoch's cipher state to use. Unlike |tls_seal_record|, |in| and |out|
+ * may alias but, if they do, |in| must be exactly |dtls_seal_prefix_len| bytes
+ * ahead of |out|. */
+int dtls_seal_record(SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out,
+ uint8_t type, const uint8_t *in, size_t in_len,
+ enum dtls1_use_epoch_t use_epoch);
+
+/* ssl_process_alert processes |in| as an alert and updates |ssl|'s shutdown
+ * state. It returns one of |ssl_open_record_discard|, |ssl_open_record_error|,
+ * |ssl_open_record_close_notify|, or |ssl_open_record_fatal_alert| as
+ * appropriate. */
+enum ssl_open_record_t ssl_process_alert(SSL *ssl, uint8_t *out_alert,
+ const uint8_t *in, size_t in_len);
+
+
+/* Private key operations. */
+
+/* ssl_has_private_key returns one if |ssl| has a private key
+ * configured and zero otherwise. */
+int ssl_has_private_key(const SSL *ssl);
+
+/* ssl_is_ecdsa_key_type returns one if |type| is an ECDSA key type and zero
+ * otherwise. */
+int ssl_is_ecdsa_key_type(int type);
+
+/* ssl_private_key_* call the corresponding function on the
+ * |SSL_PRIVATE_KEY_METHOD| for |ssl|, if configured. Otherwise, they implement
+ * the operation with |EVP_PKEY|. */
+
+int ssl_private_key_type(SSL *ssl);
+
+size_t ssl_private_key_max_signature_len(SSL *ssl);
+
+enum ssl_private_key_result_t ssl_private_key_sign(
+ SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out,
+ uint16_t signature_algorithm, const uint8_t *in, size_t in_len);
+
+enum ssl_private_key_result_t ssl_private_key_decrypt(
+ SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out,
+ const uint8_t *in, size_t in_len);
+
+enum ssl_private_key_result_t ssl_private_key_complete(SSL *ssl, uint8_t *out,
+ size_t *out_len,
+ size_t max_out);
+
+/* ssl_private_key_supports_signature_algorithm returns one if |ssl|'s private
+ * key supports |signature_algorithm| and zero otherwise. */
+int ssl_private_key_supports_signature_algorithm(SSL *ssl,
+ uint16_t signature_algorithm);
+
+/* 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);
+
+
+/* Custom extensions */
+
+typedef struct ssl_handshake_st SSL_HANDSHAKE;
+
+/* ssl_custom_extension (a.k.a. SSL_CUSTOM_EXTENSION) is a structure that
+ * contains information about custom-extension callbacks. */
+struct ssl_custom_extension {
+ SSL_custom_ext_add_cb add_callback;
+ void *add_arg;
+ SSL_custom_ext_free_cb free_callback;
+ SSL_custom_ext_parse_cb parse_callback;
+ void *parse_arg;
+ uint16_t value;
+};
+
+void SSL_CUSTOM_EXTENSION_free(SSL_CUSTOM_EXTENSION *custom_extension);
+
+int custom_ext_add_clienthello(SSL_HANDSHAKE *hs, CBB *extensions);
+int custom_ext_parse_serverhello(SSL_HANDSHAKE *hs, int *out_alert,
+ uint16_t value, const CBS *extension);
+int custom_ext_parse_clienthello(SSL_HANDSHAKE *hs, int *out_alert,
+ uint16_t value, const CBS *extension);
+int custom_ext_add_serverhello(SSL_HANDSHAKE *hs, CBB *extensions);
+
+
+/* ECDH groups. */
+
+typedef struct ssl_ecdh_ctx_st SSL_ECDH_CTX;
+
+/* An SSL_ECDH_METHOD is an implementation of ECDH-like key exchanges for
+ * TLS. */
+typedef struct ssl_ecdh_method_st {
+ int nid;
+ uint16_t group_id;
+ const char name[8];
+
+ /* cleanup releases state in |ctx|. */
+ void (*cleanup)(SSL_ECDH_CTX *ctx);
+
+ /* offer generates a keypair and writes the public value to
+ * |out_public_key|. It returns one on success and zero on error. */
+ int (*offer)(SSL_ECDH_CTX *ctx, CBB *out_public_key);
+
+ /* accept performs a key exchange against the |peer_key| generated by |offer|.
+ * On success, it returns one, writes the public value to |out_public_key|,
+ * and sets |*out_secret| and |*out_secret_len| to a newly-allocated buffer
+ * containing the shared secret. The caller must release this buffer with
+ * |OPENSSL_free|. On failure, it returns zero and sets |*out_alert| to an
+ * alert to send to the peer. */
+ int (*accept)(SSL_ECDH_CTX *ctx, CBB *out_public_key, uint8_t **out_secret,
+ size_t *out_secret_len, uint8_t *out_alert,
+ const uint8_t *peer_key, size_t peer_key_len);
+
+ /* finish performs a key exchange against the |peer_key| generated by
+ * |accept|. On success, it returns one and sets |*out_secret| and
+ * |*out_secret_len| to a newly-allocated buffer containing the shared
+ * secret. The caller must release this buffer with |OPENSSL_free|. On
+ * failure, it returns zero and sets |*out_alert| to an alert to send to the
+ * peer. */
+ int (*finish)(SSL_ECDH_CTX *ctx, uint8_t **out_secret, size_t *out_secret_len,
+ uint8_t *out_alert, const uint8_t *peer_key,
+ size_t peer_key_len);
+
+ /* get_key initializes |out| with a length-prefixed key from |cbs|. It returns
+ * one on success and zero on error. */
+ int (*get_key)(CBS *cbs, CBS *out);
+
+ /* add_key initializes |out_contents| to receive a key. Typically it will then
+ * be passed to |offer| or |accept|. It returns one on success and zero on
+ * error. */
+ int (*add_key)(CBB *cbb, CBB *out_contents);
+} SSL_ECDH_METHOD;
+
+struct ssl_ecdh_ctx_st {
+ const SSL_ECDH_METHOD *method;
+ void *data;
+};
+
+/* ssl_nid_to_group_id looks up the group corresponding to |nid|. On success, it
+ * sets |*out_group_id| to the group ID and returns one. Otherwise, it returns
+ * zero. */
+int ssl_nid_to_group_id(uint16_t *out_group_id, int nid);
+
+/* ssl_name_to_group_id looks up the group corresponding to the |name| string
+ * of length |len|. On success, it sets |*out_group_id| to the group ID and
+ * returns one. Otherwise, it returns zero. */
+int ssl_name_to_group_id(uint16_t *out_group_id, const char *name, size_t len);
+
+/* SSL_ECDH_CTX_init sets up |ctx| for use with curve |group_id|. It returns one
+ * on success and zero on error. */
+int SSL_ECDH_CTX_init(SSL_ECDH_CTX *ctx, uint16_t group_id);
+
+/* SSL_ECDH_CTX_init_for_dhe sets up |ctx| for use with legacy DHE-based ciphers
+ * where the server specifies a group. It takes ownership of |params|. */
+void SSL_ECDH_CTX_init_for_dhe(SSL_ECDH_CTX *ctx, DH *params);
+
+/* SSL_ECDH_CTX_cleanup releases memory associated with |ctx|. It is legal to
+ * call it in the zero state. */
+void SSL_ECDH_CTX_cleanup(SSL_ECDH_CTX *ctx);
+
+/* SSL_ECDH_CTX_get_id returns the group ID for |ctx|. */
+uint16_t SSL_ECDH_CTX_get_id(const SSL_ECDH_CTX *ctx);
+
+/* SSL_ECDH_CTX_get_key calls the |get_key| method of |SSL_ECDH_METHOD|. */
+int SSL_ECDH_CTX_get_key(SSL_ECDH_CTX *ctx, CBS *cbs, CBS *out);
+
+/* SSL_ECDH_CTX_add_key calls the |add_key| method of |SSL_ECDH_METHOD|. */
+int SSL_ECDH_CTX_add_key(SSL_ECDH_CTX *ctx, CBB *cbb, CBB *out_contents);
+
+/* SSL_ECDH_CTX_offer calls the |offer| method of |SSL_ECDH_METHOD|. */
+int SSL_ECDH_CTX_offer(SSL_ECDH_CTX *ctx, CBB *out_public_key);
+
+/* SSL_ECDH_CTX_accept calls the |accept| method of |SSL_ECDH_METHOD|. */
+int SSL_ECDH_CTX_accept(SSL_ECDH_CTX *ctx, CBB *out_public_key,
+ uint8_t **out_secret, size_t *out_secret_len,
+ uint8_t *out_alert, const uint8_t *peer_key,
+ size_t peer_key_len);
+
+/* SSL_ECDH_CTX_finish the |finish| method of |SSL_ECDH_METHOD|. */
+int SSL_ECDH_CTX_finish(SSL_ECDH_CTX *ctx, uint8_t **out_secret,
+ size_t *out_secret_len, uint8_t *out_alert,
+ const uint8_t *peer_key, size_t peer_key_len);
+
+/* Handshake messages. */
+
+/* SSL_MAX_HANDSHAKE_FLIGHT is the number of messages, including
+ * ChangeCipherSpec, in the longest handshake flight. Currently this is the
+ * client's second leg in a full handshake when client certificates, NPN, and
+ * Channel ID, are all enabled. */
+#define SSL_MAX_HANDSHAKE_FLIGHT 7
+
+/* ssl_max_handshake_message_len returns the maximum number of bytes permitted
+ * in a handshake message for |ssl|. */
+size_t ssl_max_handshake_message_len(const SSL *ssl);
+
+/* dtls_clear_incoming_messages releases all buffered incoming messages. */
+void dtls_clear_incoming_messages(SSL *ssl);
+
+/* dtls_has_incoming_messages returns one if there are buffered incoming
+ * messages ahead of the current message and zero otherwise. */
+int dtls_has_incoming_messages(const SSL *ssl);
+
+typedef struct dtls_outgoing_message_st {
+ uint8_t *data;
+ uint32_t len;
+ uint16_t epoch;
+ char is_ccs;
+} DTLS_OUTGOING_MESSAGE;
+
+/* dtls_clear_outgoing_messages releases all buffered outgoing messages. */
+void dtls_clear_outgoing_messages(SSL *ssl);
+
+
+/* Callbacks. */
+
+/* ssl_do_info_callback calls |ssl|'s info callback, if set. */
+void ssl_do_info_callback(const SSL *ssl, int type, int value);
+
+/* ssl_do_msg_callback calls |ssl|'s message callback, if set. */
+void ssl_do_msg_callback(SSL *ssl, int is_write, int content_type,
+ const void *buf, size_t len);
+
+
+/* Transport buffers. */
+
+/* ssl_read_buffer returns a pointer to contents of the read buffer. */
+uint8_t *ssl_read_buffer(SSL *ssl);
+
+/* ssl_read_buffer_len returns the length of the read buffer. */
+size_t ssl_read_buffer_len(const SSL *ssl);
+
+/* ssl_read_buffer_extend_to extends the read buffer to the desired length. For
+ * TLS, it reads to the end of the buffer until the buffer is |len| bytes
+ * long. For DTLS, it reads a new packet and ignores |len|. It returns one on
+ * success, zero on EOF, and a negative number on error.
+ *
+ * It is an error to call |ssl_read_buffer_extend_to| in DTLS when the buffer is
+ * non-empty. */
+int ssl_read_buffer_extend_to(SSL *ssl, size_t len);
+
+/* ssl_read_buffer_consume consumes |len| bytes from the read buffer. It
+ * advances the data pointer and decrements the length. The memory consumed will
+ * remain valid until the next call to |ssl_read_buffer_extend| or it is
+ * discarded with |ssl_read_buffer_discard|. */
+void ssl_read_buffer_consume(SSL *ssl, size_t len);
+
+/* ssl_read_buffer_discard discards the consumed bytes from the read buffer. If
+ * the buffer is now empty, it releases memory used by it. */
+void ssl_read_buffer_discard(SSL *ssl);
+
+/* ssl_read_buffer_clear releases all memory associated with the read buffer and
+ * zero-initializes it. */
+void ssl_read_buffer_clear(SSL *ssl);
+
+/* ssl_write_buffer_is_pending returns one if the write buffer has pending data
+ * and zero if is empty. */
+int ssl_write_buffer_is_pending(const SSL *ssl);
+
+/* ssl_write_buffer_init initializes the write buffer. On success, it sets
+ * |*out_ptr| to the start of the write buffer with space for up to |max_len|
+ * bytes. It returns one on success and zero on failure. Call
+ * |ssl_write_buffer_set_len| to complete initialization. */
+int ssl_write_buffer_init(SSL *ssl, uint8_t **out_ptr, size_t max_len);
+
+/* ssl_write_buffer_set_len is called after |ssl_write_buffer_init| to complete
+ * initialization after |len| bytes are written to the buffer. */
+void ssl_write_buffer_set_len(SSL *ssl, size_t len);
+
+/* ssl_write_buffer_flush flushes the write buffer to the transport. It returns
+ * one on success and <= 0 on error. For DTLS, whether or not the write
+ * succeeds, the write buffer will be cleared. */
+int ssl_write_buffer_flush(SSL *ssl);
+
+/* ssl_write_buffer_clear releases all memory associated with the write buffer
+ * and zero-initializes it. */
+void ssl_write_buffer_clear(SSL *ssl);
+
+
+/* Certificate functions. */
+
+/* ssl_has_certificate returns one if a certificate and private key are
+ * configured and zero otherwise. */
+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 NULL 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 and |out_leaf_sha256| is non-NULL, it writes the
+ * SHA-256 hash of the leaf to |out_leaf_sha256|. */
+STACK_OF(CRYPTO_BUFFER) *ssl_parse_cert_chain(uint8_t *out_alert,
+ 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
+ * empty certificate list. It returns one on success and zero on error. */
+int ssl_add_cert_chain(SSL *ssl, CBB *cbb);
+
+/* ssl_cert_check_digital_signature_key_usage parses the DER-encoded, X.509
+ * certificate in |in| and returns one if doesn't specify a key usage or, if it
+ * does, if it includes digitalSignature. Otherwise it pushes to the error
+ * queue and returns zero. */
+int ssl_cert_check_digital_signature_key_usage(const CBS *in);
+
+/* ssl_cert_parse_pubkey extracts the public key from the DER-encoded, X.509
+ * certificate in |in|. It returns an allocated |EVP_PKEY| or else returns NULL
+ * and pushes to the error queue. */
+EVP_PKEY *ssl_cert_parse_pubkey(const CBS *in);
+
+/* ssl_parse_client_CA_list parses a CA list from |cbs| in the format used by a
+ * TLS CertificateRequest message. On success, it returns a newly-allocated
+ * |CRYPTO_BUFFER| list and advances |cbs|. Otherwise, it returns NULL and sets
+ * |*out_alert| to an alert to send to the peer. */
+STACK_OF(CRYPTO_BUFFER) *
+ ssl_parse_client_CA_list(SSL *ssl, uint8_t *out_alert, CBS *cbs);
+
+/* ssl_add_client_CA_list adds the configured CA list to |cbb| in the format
+ * used by a TLS CertificateRequest message. It returns one on success and zero
+ * on error. */
+int ssl_add_client_CA_list(SSL *ssl, CBB *cbb);
+
+/* ssl_check_leaf_certificate returns one if |pkey| and |leaf| are suitable as
+ * a server's leaf certificate for |hs|. Otherwise, it returns zero and pushes
+ * an error on the error queue. */
+int ssl_check_leaf_certificate(SSL_HANDSHAKE *hs, EVP_PKEY *pkey,
+ const CRYPTO_BUFFER *leaf);
+
+
+/* TLS 1.3 key derivation. */
+
+/* tls13_init_key_schedule initializes the handshake hash and key derivation
+ * state. The cipher suite and PRF hash must have been selected at this point.
+ * It returns one on success and zero on error. */
+int tls13_init_key_schedule(SSL_HANDSHAKE *hs);
+
+/* tls13_advance_key_schedule incorporates |in| into the key schedule with
+ * HKDF-Extract. It returns one on success and zero on error. */
+int tls13_advance_key_schedule(SSL_HANDSHAKE *hs, const uint8_t *in,
+ size_t len);
+
+/* tls13_set_traffic_key sets the read or write traffic keys to
+ * |traffic_secret|. It returns one on success and zero on error. */
+int tls13_set_traffic_key(SSL *ssl, enum evp_aead_direction_t direction,
+ const uint8_t *traffic_secret,
+ size_t traffic_secret_len);
+
+/* tls13_derive_handshake_secrets derives the handshake traffic secret. It
+ * returns one on success and zero on error. */
+int tls13_derive_handshake_secrets(SSL_HANDSHAKE *hs);
+
+/* tls13_rotate_traffic_key derives the next read or write traffic secret. It
+ * returns one on success and zero on error. */
+int tls13_rotate_traffic_key(SSL *ssl, enum evp_aead_direction_t direction);
+
+/* tls13_derive_application_secrets derives the initial application data traffic
+ * and exporter secrets based on the handshake transcripts and |master_secret|.
+ * It returns one on success and zero on error. */
+int tls13_derive_application_secrets(SSL_HANDSHAKE *hs);
+
+/* tls13_derive_resumption_secret derives the |resumption_secret|. */
+int tls13_derive_resumption_secret(SSL_HANDSHAKE *hs);
+
+/* tls13_export_keying_material provides an exporter interface to use the
+ * |exporter_secret|. */
+int tls13_export_keying_material(SSL *ssl, uint8_t *out, size_t out_len,
+ const char *label, size_t label_len,
+ const uint8_t *context, size_t context_len,
+ int use_context);
+
+/* tls13_finished_mac calculates the MAC of the handshake transcript to verify
+ * the integrity of the Finished message, and stores the result in |out| and
+ * length in |out_len|. |is_server| is 1 if this is for the Server Finished and
+ * 0 for the Client Finished. */
+int tls13_finished_mac(SSL_HANDSHAKE *hs, uint8_t *out,
+ size_t *out_len, int is_server);
+
+/* tls13_write_psk_binder calculates the PSK binder value and replaces the last
+ * bytes of |msg| with the resulting value. It returns 1 on success, and 0 on
+ * failure. */
+int tls13_write_psk_binder(SSL_HANDSHAKE *hs, uint8_t *msg, size_t len);
+
+/* tls13_verify_psk_binder verifies that the handshake transcript, truncated
+ * up to the binders has a valid signature using the value of |session|'s
+ * resumption secret. It returns 1 on success, and 0 on failure. */
+int tls13_verify_psk_binder(SSL_HANDSHAKE *hs, SSL_SESSION *session,
+ CBS *binders);
+
+
+/* Handshake functions. */
+
+enum ssl_hs_wait_t {
+ ssl_hs_error,
+ ssl_hs_ok,
+ ssl_hs_read_message,
+ ssl_hs_flush,
+ ssl_hs_flush_and_read_message,
+ ssl_hs_x509_lookup,
+ ssl_hs_channel_id_lookup,
+ ssl_hs_private_key_operation,
+ ssl_hs_pending_ticket,
+};
+
+struct ssl_handshake_st {
+ /* ssl is a non-owning pointer to the parent |SSL| object. */
+ SSL *ssl;
+
+ /* do_tls13_handshake runs the TLS 1.3 handshake. On completion, it returns
+ * |ssl_hs_ok|. Otherwise, it returns a value corresponding to what operation
+ * is needed to progress. */
+ enum ssl_hs_wait_t (*do_tls13_handshake)(SSL_HANDSHAKE *hs);
+
+ /* wait contains the operation |do_tls13_handshake| is currently blocking on
+ * or |ssl_hs_ok| if none. */
+ enum ssl_hs_wait_t wait;
+
+ /* state contains one of the SSL3_ST_* values. */
+ int state;
+
+ /* next_state is used when SSL_ST_FLUSH_DATA is entered */
+ int next_state;
+
+ /* tls13_state is the internal state for the TLS 1.3 handshake. Its values
+ * depend on |do_tls13_handshake| but the starting state is always zero. */
+ int tls13_state;
+
+ size_t hash_len;
+ uint8_t secret[EVP_MAX_MD_SIZE];
+ uint8_t client_handshake_secret[EVP_MAX_MD_SIZE];
+ uint8_t server_handshake_secret[EVP_MAX_MD_SIZE];
+ uint8_t client_traffic_secret_0[EVP_MAX_MD_SIZE];
+ uint8_t server_traffic_secret_0[EVP_MAX_MD_SIZE];
+
+ union {
+ /* sent is a bitset where the bits correspond to elements of kExtensions
+ * in t1_lib.c. Each bit is set if that extension was sent in a
+ * ClientHello. It's not used by servers. */
+ uint32_t sent;
+ /* received is a bitset, like |sent|, but is used by servers to record
+ * which extensions were received from a client. */
+ uint32_t received;
+ } extensions;
+
+ union {
+ /* sent is a bitset where the bits correspond to elements of
+ * |client_custom_extensions| in the |SSL_CTX|. Each bit is set if that
+ * extension was sent in a ClientHello. It's not used by servers. */
+ uint16_t sent;
+ /* received is a bitset, like |sent|, but is used by servers to record
+ * which custom extensions were received from a client. The bits here
+ * correspond to |server_custom_extensions|. */
+ uint16_t received;
+ } custom_extensions;
+
+ /* retry_group is the group ID selected by the server in HelloRetryRequest in
+ * TLS 1.3. */
+ uint16_t retry_group;
+
+ /* ecdh_ctx is the current ECDH instance. */
+ SSL_ECDH_CTX ecdh_ctx;
+
+ /* transcript is the current handshake transcript. */
+ SSL_TRANSCRIPT transcript;
+
+ /* cookie is the value of the cookie received from the server, if any. */
+ uint8_t *cookie;
+ size_t cookie_len;
+
+ /* key_share_bytes is the value of the previously sent KeyShare extension by
+ * the client in TLS 1.3. */
+ uint8_t *key_share_bytes;
+ size_t key_share_bytes_len;
+
+ /* public_key, for servers, is the key share to be sent to the client in TLS
+ * 1.3. */
+ uint8_t *public_key;
+ size_t public_key_len;
+
+ /* peer_sigalgs are the signature algorithms that the peer supports. These are
+ * taken from the contents of the signature algorithms extension for a server
+ * or from the CertificateRequest for a client. */
+ uint16_t *peer_sigalgs;
+ /* num_peer_sigalgs is the number of entries in |peer_sigalgs|. */
+ size_t num_peer_sigalgs;
+
+ /* peer_supported_group_list contains the supported group IDs advertised by
+ * the peer. This is only set on the server's end. The server does not
+ * advertise this extension to the client. */
+ uint16_t *peer_supported_group_list;
+ size_t peer_supported_group_list_len;
+
+ /* peer_key is the peer's ECDH key for a TLS 1.2 client. */
+ uint8_t *peer_key;
+ size_t peer_key_len;
+
+ /* server_params, in TLS 1.2, stores the ServerKeyExchange parameters to be
+ * signed while the signature is being computed. */
+ uint8_t *server_params;
+ size_t server_params_len;
+
+ /* peer_psk_identity_hint, on the client, is the psk_identity_hint sent by the
+ * server when using a TLS 1.2 PSK key exchange. */
+ char *peer_psk_identity_hint;
+
+ /* ca_names, on the client, contains the list of CAs received in a
+ * CertificateRequest message. */
+ STACK_OF(CRYPTO_BUFFER) *ca_names;
+
+ /* cached_x509_ca_names contains a cache of parsed versions of the elements
+ * of |ca_names|. */
+ STACK_OF(X509_NAME) *cached_x509_ca_names;
+
+ /* certificate_types, on the client, contains the set of certificate types
+ * received in a CertificateRequest message. */
+ uint8_t *certificate_types;
+ size_t num_certificate_types;
+
+ /* hostname, on the server, is the value of the SNI extension. */
+ char *hostname;
+
+ /* peer_pubkey is the public key parsed from the peer's leaf certificate. */
+ EVP_PKEY *peer_pubkey;
+
+ /* new_session is the new mutable session being established by the current
+ * handshake. It should not be cached. */
+ SSL_SESSION *new_session;
+
+ /* new_cipher is the cipher being negotiated in this handshake. */
+ const SSL_CIPHER *new_cipher;
+
+ /* key_block is the record-layer key block for TLS 1.2 and earlier. */
+ uint8_t *key_block;
+ uint8_t key_block_len;
+
+ /* session_tickets_sent, in TLS 1.3, is the number of tickets the server has
+ * sent. */
+ uint8_t session_tickets_sent;
+
+ /* scts_requested is one if the SCT extension is in the ClientHello. */
+ unsigned scts_requested:1;
+
+ /* needs_psk_binder if the ClientHello has a placeholder PSK binder to be
+ * filled in. */
+ unsigned needs_psk_binder:1;
+
+ unsigned received_hello_retry_request:1;
+
+ /* accept_psk_mode stores whether the client's PSK mode is compatible with our
+ * preferences. */
+ unsigned accept_psk_mode:1;
+
+ /* cert_request is one if a client certificate was requested and zero
+ * otherwise. */
+ unsigned cert_request:1;
+
+ /* certificate_status_expected is one if OCSP stapling was negotiated and the
+ * server is expected to send a CertificateStatus message. (This is used on
+ * both the client and server sides.) */
+ unsigned certificate_status_expected:1;
+
+ /* ocsp_stapling_requested is one if a client requested OCSP stapling. */
+ unsigned ocsp_stapling_requested:1;
+
+ /* should_ack_sni is used by a server and indicates that the SNI extension
+ * should be echoed in the ServerHello. */
+ unsigned should_ack_sni:1;
+
+ /* in_false_start is one if there is a pending client handshake in False
+ * Start. The client may write data at this point. */
+ unsigned in_false_start:1;
+
+ /* next_proto_neg_seen is one of NPN was negotiated. */
+ unsigned next_proto_neg_seen:1;
+
+ /* ticket_expected is one if a TLS 1.2 NewSessionTicket message is to be sent
+ * or received. */
+ unsigned ticket_expected:1;
+
+ /* v2_clienthello is one if we received a V2ClientHello. */
+ unsigned v2_clienthello:1;
+
+ /* extended_master_secret is one if the extended master secret extension is
+ * negotiated in this handshake. */
+ unsigned extended_master_secret:1;
+
+ /* client_version is the value sent or received in the ClientHello version. */
+ uint16_t client_version;
+} /* SSL_HANDSHAKE */;
+
+SSL_HANDSHAKE *ssl_handshake_new(SSL *ssl);
+
+/* ssl_handshake_free releases all memory associated with |hs|. */
+void ssl_handshake_free(SSL_HANDSHAKE *hs);
+
+/* ssl_check_message_type checks if the current message has type |type|. If so
+ * it returns one. Otherwise, it sends an alert and returns zero. */
+int ssl_check_message_type(SSL *ssl, int type);
+
+/* tls13_handshake runs the TLS 1.3 handshake. It returns one on success and <=
+ * 0 on error. */
+int tls13_handshake(SSL_HANDSHAKE *hs);
+
+/* The following are implementations of |do_tls13_handshake| for the client and
+ * server. */
+enum ssl_hs_wait_t tls13_client_handshake(SSL_HANDSHAKE *hs);
+enum ssl_hs_wait_t tls13_server_handshake(SSL_HANDSHAKE *hs);
+
+/* tls13_post_handshake processes a post-handshake message. It returns one on
+ * success and zero on failure. */
+int tls13_post_handshake(SSL *ssl);
+
+int tls13_process_certificate(SSL_HANDSHAKE *hs, int allow_anonymous);
+int tls13_process_certificate_verify(SSL_HANDSHAKE *hs);
+int tls13_process_finished(SSL_HANDSHAKE *hs);
+
+int tls13_add_certificate(SSL_HANDSHAKE *hs);
+enum ssl_private_key_result_t tls13_add_certificate_verify(SSL_HANDSHAKE *hs,
+ int is_first_run);
+int tls13_add_finished(SSL_HANDSHAKE *hs);
+int tls13_process_new_session_ticket(SSL *ssl);
+
+int ssl_ext_key_share_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t **out_secret,
+ size_t *out_secret_len,
+ uint8_t *out_alert, CBS *contents);
+int ssl_ext_key_share_parse_clienthello(SSL_HANDSHAKE *hs, int *out_found,
+ uint8_t **out_secret,
+ size_t *out_secret_len,
+ uint8_t *out_alert, CBS *contents);
+int ssl_ext_key_share_add_serverhello(SSL_HANDSHAKE *hs, CBB *out);
+
+int ssl_ext_pre_shared_key_parse_serverhello(SSL_HANDSHAKE *hs,
+ uint8_t *out_alert, CBS *contents);
+int ssl_ext_pre_shared_key_parse_clienthello(
+ SSL_HANDSHAKE *hs, CBS *out_ticket, CBS *out_binders,
+ uint32_t *out_obfuscated_ticket_age, uint8_t *out_alert, CBS *contents);
+int ssl_ext_pre_shared_key_add_serverhello(SSL_HANDSHAKE *hs, CBB *out);
+
+/* ssl_is_sct_list_valid does a shallow parse of the SCT list in |contents| and
+ * returns one iff it's valid. */
+int ssl_is_sct_list_valid(const CBS *contents);
+
+int ssl_write_client_hello(SSL_HANDSHAKE *hs);
+
+/* ssl_clear_tls13_state releases client state only needed for TLS 1.3. It
+ * should be called once the version is known to be TLS 1.2 or earlier. */
+void ssl_clear_tls13_state(SSL_HANDSHAKE *hs);
+
+enum ssl_cert_verify_context_t {
+ ssl_cert_verify_server,
+ ssl_cert_verify_client,
+ ssl_cert_verify_channel_id,
+};
+
+/* tls13_get_cert_verify_signature_input generates the message to be signed for
+ * TLS 1.3's CertificateVerify message. |cert_verify_context| determines the
+ * type of signature. It sets |*out| and |*out_len| to a newly allocated buffer
+ * containing the result. The caller must free it with |OPENSSL_free| to release
+ * it. This function returns one on success and zero on failure. */
+int tls13_get_cert_verify_signature_input(
+ SSL_HANDSHAKE *hs, uint8_t **out, size_t *out_len,
+ enum ssl_cert_verify_context_t cert_verify_context);
+
+/* ssl_negotiate_alpn negotiates the ALPN extension, if applicable. It returns
+ * one on successful negotiation or if nothing was negotiated. It returns zero
+ * and sets |*out_alert| to an alert on error. */
+int ssl_negotiate_alpn(SSL_HANDSHAKE *hs, uint8_t *out_alert,
+ const SSL_CLIENT_HELLO *client_hello);
+
+typedef struct {
+ uint16_t type;
+ int *out_present;
+ CBS *out_data;
+} SSL_EXTENSION_TYPE;
+
+/* ssl_parse_extensions parses a TLS extensions block out of |cbs| and advances
+ * it. It writes the parsed extensions to pointers denoted by |ext_types|. On
+ * success, it fills in the |out_present| and |out_data| fields and returns one.
+ * Otherwise, it sets |*out_alert| to an alert to send and returns zero. Unknown
+ * extensions are rejected unless |ignore_unknown| is 1. */
+int ssl_parse_extensions(const CBS *cbs, uint8_t *out_alert,
+ const SSL_EXTENSION_TYPE *ext_types,
+ size_t num_ext_types, int ignore_unknown);
+
+
+/* SSLKEYLOGFILE functions. */
+
+/* ssl_log_secret logs |secret| with label |label|, if logging is enabled for
+ * |ssl|. It returns one on success and zero on failure. */
+int ssl_log_secret(const SSL *ssl, const char *label, const uint8_t *secret,
+ size_t secret_len);
+
+
+/* ClientHello functions. */
+
+int ssl_client_hello_init(SSL *ssl, SSL_CLIENT_HELLO *out, const uint8_t *in,
+ size_t in_len);
+
+int ssl_client_hello_get_extension(const SSL_CLIENT_HELLO *client_hello,
+ CBS *out, uint16_t extension_type);
+
+int ssl_client_cipher_list_contains_cipher(const SSL_CLIENT_HELLO *client_hello,
+ uint16_t id);
+
+
+/* GREASE. */
+
+enum ssl_grease_index_t {
+ ssl_grease_cipher = 0,
+ ssl_grease_group,
+ ssl_grease_extension1,
+ ssl_grease_extension2,
+ ssl_grease_version,
+ ssl_grease_ticket_extension,
+};
+
+/* ssl_get_grease_value returns a GREASE value for |ssl|. For a given
+ * connection, the values for each index will be deterministic. This allows the
+ * same ClientHello be sent twice for a HelloRetryRequest or the same group be
+ * advertised in both supported_groups and key_shares. */
+uint16_t ssl_get_grease_value(const SSL *ssl, enum ssl_grease_index_t index);
+
+
+/* Signature algorithms. */
+
+/* tls1_parse_peer_sigalgs parses |sigalgs| as the list of peer signature
+ * algorithms and saves them on |hs|. It returns one on success and zero on
+ * error. */
+int tls1_parse_peer_sigalgs(SSL_HANDSHAKE *hs, const CBS *sigalgs);
+
+/* tls1_choose_signature_algorithm sets |*out| to a signature algorithm for use
+ * with |hs|'s private key based on the peer's preferences and the algorithms
+ * supported. It returns one on success and zero on error. */
+int tls1_choose_signature_algorithm(SSL_HANDSHAKE *hs, uint16_t *out);
+
+/* tls12_get_verify_sigalgs sets |*out| to the signature algorithms acceptable
+ * for the peer signature and returns the length of the list. */
+size_t tls12_get_verify_sigalgs(const SSL *ssl, const uint16_t **out);
+
+/* tls12_check_peer_sigalg checks if |sigalg| is acceptable for the peer
+ * signature. It returns one on success and zero on error, setting |*out_alert|
+ * to an alert to send. */
+int tls12_check_peer_sigalg(SSL *ssl, int *out_alert, uint16_t sigalg);
+
+
+/* Underdocumented functions.
+ *
+ * Functions below here haven't been touched up and may be underdocumented. */
+
+#define TLSEXT_CHANNEL_ID_SIZE 128
+
+/* From RFC4492, used in encoding the curve type in ECParameters */
+#define NAMED_CURVE_TYPE 3
+
+typedef struct cert_st {
+ EVP_PKEY *privatekey;
+
+ /* chain contains the certificate chain, with the leaf at the beginning. The
+ * first element of |chain| may be NULL to indicate that the leaf certificate
+ * has not yet been set.
+ * If |chain| != NULL -> len(chain) >= 1
+ * If |chain[0]| == NULL -> len(chain) >= 2.
+ * |chain[1..]| != NULL */
+ STACK_OF(CRYPTO_BUFFER) *chain;
+
+ /* x509_chain may contain a parsed copy of |chain[1..]|. This is only used as
+ * a cache in order to implement “get0” functions that return a non-owning
+ * pointer to the certificate chain. */
+ STACK_OF(X509) *x509_chain;
+
+ /* x509_leaf may contain a parsed copy of the first element of |chain|. This
+ * is only used as a cache in order to implement “get0” functions that return
+ * a non-owning pointer to the certificate chain. */
+ X509 *x509_leaf;
+
+ /* x509_stash contains the last |X509| object append to the chain. This is a
+ * workaround for some third-party code that continue to use an |X509| object
+ * even after passing ownership with an “add0” function. */
+ X509 *x509_stash;
+
+ /* key_method, if non-NULL, is a set of callbacks to call for private key
+ * operations. */
+ const SSL_PRIVATE_KEY_METHOD *key_method;
+
+ /* x509_method contains pointers to functions that might deal with |X509|
+ * compatibility, or might be a no-op, depending on the application. */
+ const SSL_X509_METHOD *x509_method;
+
+ DH *dh_tmp;
+ DH *(*dh_tmp_cb)(SSL *ssl, int is_export, int keysize);
+
+ /* sigalgs, if non-NULL, is the set of signature algorithms supported by
+ * |privatekey| in decreasing order of preference. */
+ uint16_t *sigalgs;
+ size_t num_sigalgs;
+
+ /* Certificate setup callback: if set is called whenever a
+ * certificate may be required (client or server). the callback
+ * can then examine any appropriate parameters and setup any
+ * certificates required. This allows advanced applications
+ * to select certificates on the fly: for example based on
+ * supported signature algorithms or curves. */
+ int (*cert_cb)(SSL *ssl, void *arg);
+ void *cert_cb_arg;
+
+ /* Optional X509_STORE for certificate validation. If NULL the parent SSL_CTX
+ * store is used instead. */
+ X509_STORE *verify_store;
+
+ /* Signed certificate timestamp list to be sent to the client, if requested */
+ CRYPTO_BUFFER *signed_cert_timestamp_list;
+
+ /* OCSP response to be sent to the client, if requested. */
+ CRYPTO_BUFFER *ocsp_response;
+
+ /* sid_ctx partitions the session space within a shared session cache or
+ * ticket key. Only sessions with a matching value will be accepted. */
+ uint8_t sid_ctx_length;
+ uint8_t sid_ctx[SSL_MAX_SID_CTX_LENGTH];
+} CERT;
+
+/* SSL_METHOD is a compatibility structure to support the legacy version-locked
+ * methods. */
+struct ssl_method_st {
+ /* version, if non-zero, is the only protocol version acceptable to an
+ * SSL_CTX initialized from this method. */
+ uint16_t version;
+ /* method is the underlying SSL_PROTOCOL_METHOD that initializes the
+ * SSL_CTX. */
+ const SSL_PROTOCOL_METHOD *method;
+ /* x509_method contains pointers to functions that might deal with |X509|
+ * compatibility, or might be a no-op, depending on the application. */
+ const SSL_X509_METHOD *x509_method;
+};
+
+/* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
+struct ssl_protocol_method_st {
+ /* is_dtls is one if the protocol is DTLS and zero otherwise. */
+ char is_dtls;
+ /* min_version is the minimum implemented version. */
+ uint16_t min_version;
+ /* max_version is the maximum implemented version. */
+ uint16_t max_version;
+ /* version_from_wire maps |wire_version| to a protocol version. On success, it
+ * sets |*out_version| to the result and returns one. If the version is
+ * unknown, it returns zero. */
+ int (*version_from_wire)(uint16_t *out_version, uint16_t wire_version);
+ /* version_to_wire maps |version| to the wire representation. It is an error
+ * to call it with an invalid version. */
+ uint16_t (*version_to_wire)(uint16_t version);
+ int (*ssl_new)(SSL *ssl);
+ void (*ssl_free)(SSL *ssl);
+ /* ssl_get_message reads the next handshake message. On success, it returns
+ * one and sets |ssl->s3->tmp.message_type|, |ssl->init_msg|, and
+ * |ssl->init_num|. Otherwise, it returns <= 0. */
+ int (*ssl_get_message)(SSL *ssl);
+ /* get_current_message sets |*out| to the current handshake message. This
+ * includes the protocol-specific message header. */
+ void (*get_current_message)(const SSL *ssl, CBS *out);
+ /* release_current_message is called to release the current handshake message.
+ * If |free_buffer| is one, buffers will also be released. */
+ void (*release_current_message)(SSL *ssl, int free_buffer);
+ /* read_app_data reads up to |len| bytes of application data into |buf|. On
+ * success, it returns the number of bytes read. Otherwise, it returns <= 0
+ * and sets |*out_got_handshake| to whether the failure was due to a
+ * post-handshake handshake message. If so, it fills in the current message as
+ * in |ssl_get_message|. */
+ int (*read_app_data)(SSL *ssl, int *out_got_handshake, uint8_t *buf, int len,
+ int peek);
+ int (*read_change_cipher_spec)(SSL *ssl);
+ void (*read_close_notify)(SSL *ssl);
+ int (*write_app_data)(SSL *ssl, const uint8_t *buf, int len);
+ int (*dispatch_alert)(SSL *ssl);
+ /* supports_cipher returns one if |cipher| is supported by this protocol and
+ * zero otherwise. */
+ int (*supports_cipher)(const SSL_CIPHER *cipher);
+ /* init_message begins a new handshake message of type |type|. |cbb| is the
+ * root CBB to be passed into |finish_message|. |*body| is set to a child CBB
+ * the caller should write to. It returns one on success and zero on error. */
+ int (*init_message)(SSL *ssl, CBB *cbb, CBB *body, uint8_t type);
+ /* finish_message finishes a handshake message. It sets |*out_msg| to a
+ * newly-allocated buffer with the serialized message. The caller must
+ * release it with |OPENSSL_free| when done. It returns one on success and
+ * zero on error. */
+ int (*finish_message)(SSL *ssl, CBB *cbb, uint8_t **out_msg, size_t *out_len);
+ /* add_message adds a handshake message to the pending flight. It returns one
+ * on success and zero on error. In either case, it takes ownership of |msg|
+ * and releases it with |OPENSSL_free| when done. */
+ int (*add_message)(SSL *ssl, uint8_t *msg, size_t len);
+ /* add_change_cipher_spec adds a ChangeCipherSpec record to the pending
+ * flight. It returns one on success and zero on error. */
+ int (*add_change_cipher_spec)(SSL *ssl);
+ /* add_alert adds an alert to the pending flight. It returns one on success
+ * and zero on error. */
+ int (*add_alert)(SSL *ssl, uint8_t level, uint8_t desc);
+ /* 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);
+ /* set_read_state sets |ssl|'s read cipher state to |aead_ctx|. It takes
+ * ownership of |aead_ctx|. It returns one on success and zero if changing the
+ * read state is forbidden at this point. */
+ int (*set_read_state)(SSL *ssl, SSL_AEAD_CTX *aead_ctx);
+ /* set_write_state sets |ssl|'s write cipher state to |aead_ctx|. It takes
+ * ownership of |aead_ctx|. It returns one on success and zero if changing the
+ * write state is forbidden at this point. */
+ int (*set_write_state)(SSL *ssl, SSL_AEAD_CTX *aead_ctx);
+};
+
+struct ssl_x509_method_st {
+ /* check_client_CA_list returns one if |names| is a good list of X.509
+ * distinguished names and zero otherwise. This is used to ensure that we can
+ * reject unparsable values at handshake time when using crypto/x509. */
+ int (*check_client_CA_list)(STACK_OF(CRYPTO_BUFFER) *names);
+
+ /* cert_clear frees and NULLs all X509 certificate-related state. */
+ void (*cert_clear)(CERT *cert);
+ /* cert_free frees all X509-related state. */
+ void (*cert_free)(CERT *cert);
+ /* cert_flush_cached_chain drops any cached |X509|-based certificate chain
+ * from |cert|. */
+ /* cert_dup duplicates any needed fields from |cert| to |new_cert|. */
+ void (*cert_dup)(CERT *new_cert, const CERT *cert);
+ void (*cert_flush_cached_chain)(CERT *cert);
+ /* cert_flush_cached_chain drops any cached |X509|-based leaf certificate
+ * from |cert|. */
+ void (*cert_flush_cached_leaf)(CERT *cert);
+
+ /* session_cache_objects fills out |sess->x509_peer| and |sess->x509_chain|
+ * from |sess->certs| and erases |sess->x509_chain_without_leaf|. It returns
+ * one on success or zero on error. */
+ int (*session_cache_objects)(SSL_SESSION *session);
+ /* session_dup duplicates any needed fields from |session| to |new_session|.
+ * It returns one on success or zero on error. */
+ int (*session_dup)(SSL_SESSION *new_session, const SSL_SESSION *session);
+ /* session_clear frees any X509-related state from |session|. */
+ void (*session_clear)(SSL_SESSION *session);
+ /* session_verify_cert_chain verifies the certificate chain in |session|,
+ * sets |session->verify_result| and returns one on success or zero on
+ * error. */
+ int (*session_verify_cert_chain)(SSL_SESSION *session, SSL *ssl);
+
+ /* hs_flush_cached_ca_names drops any cached |X509_NAME|s from |hs|. */
+ void (*hs_flush_cached_ca_names)(SSL_HANDSHAKE *hs);
+ /* ssl_new does any neccessary initialisation of |ssl|. It returns one on
+ * success or zero on error. */
+ int (*ssl_new)(SSL *ssl);
+ /* ssl_free frees anything created by |ssl_new|. */
+ void (*ssl_free)(SSL *ssl);
+ /* ssl_flush_cached_client_CA drops any cached |X509_NAME|s from |ssl|. */
+ void (*ssl_flush_cached_client_CA)(SSL *ssl);
+ /* ssl_auto_chain_if_needed runs the deprecated auto-chaining logic if
+ * necessary. On success, it updates |ssl|'s certificate configuration as
+ * needed and returns one. Otherwise, it returns zero. */
+ int (*ssl_auto_chain_if_needed)(SSL *ssl);
+ /* ssl_ctx_new does any neccessary initialisation of |ctx|. It returns one on
+ * success or zero on error. */
+ int (*ssl_ctx_new)(SSL_CTX *ctx);
+ /* ssl_ctx_free frees anything created by |ssl_ctx_new|. */
+ void (*ssl_ctx_free)(SSL_CTX *ctx);
+ /* ssl_ctx_flush_cached_client_CA drops any cached |X509_NAME|s from |ctx|. */
+ void (*ssl_ctx_flush_cached_client_CA)(SSL_CTX *ssl);
+};
+
+/* ssl_crypto_x509_method provides the |ssl_x509_method_st| functions using
+ * crypto/x509. */
+extern const struct ssl_x509_method_st ssl_crypto_x509_method;
+
+typedef struct ssl3_record_st {
+ /* type is the record type. */
+ uint8_t type;
+ /* length is the number of unconsumed bytes in the record. */
+ uint16_t length;
+ /* data is a non-owning pointer to the first unconsumed byte of the record. */
+ uint8_t *data;
+} SSL3_RECORD;
+
+typedef struct ssl3_buffer_st {
+ /* buf is the memory allocated for this buffer. */
+ uint8_t *buf;
+ /* offset is the offset into |buf| which the buffer contents start at. */
+ uint16_t offset;
+ /* len is the length of the buffer contents from |buf| + |offset|. */
+ uint16_t len;
+ /* cap is how much memory beyond |buf| + |offset| is available. */
+ uint16_t cap;
+} SSL3_BUFFER;
+
+/* An ssl_shutdown_t describes the shutdown state of one end of the connection,
+ * whether it is alive or has been shutdown via close_notify or fatal alert. */
+enum ssl_shutdown_t {
+ ssl_shutdown_none = 0,
+ ssl_shutdown_close_notify = 1,
+ ssl_shutdown_fatal_alert = 2,
+};
+
+typedef struct ssl3_state_st {
+ uint8_t read_sequence[8];
+ uint8_t write_sequence[8];
+
+ uint8_t server_random[SSL3_RANDOM_SIZE];
+ uint8_t client_random[SSL3_RANDOM_SIZE];
+
+ /* read_buffer holds data from the transport to be processed. */
+ SSL3_BUFFER read_buffer;
+ /* write_buffer holds data to be written to the transport. */
+ SSL3_BUFFER write_buffer;
+
+ SSL3_RECORD rrec; /* each decoded record goes in here */
+
+ /* partial write - check the numbers match */
+ unsigned int wnum; /* number of bytes sent so far */
+ int wpend_tot; /* number bytes written */
+ int wpend_type;
+ int wpend_ret; /* number of bytes submitted */
+ const uint8_t *wpend_buf;
+
+ /* recv_shutdown is the shutdown state for the receive half of the
+ * connection. */
+ enum ssl_shutdown_t recv_shutdown;
+
+ /* recv_shutdown is the shutdown state for the send half of the connection. */
+ enum ssl_shutdown_t send_shutdown;
+
+ int alert_dispatch;
+
+ int total_renegotiations;
+
+ /* early_data_skipped is the amount of early data that has been skipped by the
+ * record layer. */
+ uint16_t early_data_skipped;
+
+ /* empty_record_count is the number of consecutive empty records received. */
+ uint8_t empty_record_count;
+
+ /* warning_alert_count is the number of consecutive warning alerts
+ * received. */
+ uint8_t warning_alert_count;
+
+ /* key_update_count is the number of consecutive KeyUpdates received. */
+ uint8_t key_update_count;
+
+ /* skip_early_data instructs the record layer to skip unexpected early data
+ * messages when 0RTT is rejected. */
+ unsigned skip_early_data:1;
+
+ /* have_version is true if the connection's final version is known. Otherwise
+ * the version has not been negotiated yet. */
+ unsigned have_version:1;
+
+ /* v2_hello_done is true if the peer's V2ClientHello, if any, has been handled
+ * and future messages should use the record layer. */
+ unsigned v2_hello_done:1;
+
+ /* is_v2_hello is true if the current handshake message was derived from a
+ * V2ClientHello rather than received from the peer directly. */
+ unsigned is_v2_hello:1;
+
+ /* initial_handshake_complete is true if the initial handshake has
+ * completed. */
+ unsigned initial_handshake_complete:1;
+
+ /* session_reused indicates whether a session was resumed. */
+ unsigned session_reused:1;
+
+ unsigned send_connection_binding:1;
+
+ /* In a client, this means that the server supported Channel ID and that a
+ * Channel ID was sent. In a server it means that we echoed support for
+ * Channel IDs and that tlsext_channel_id will be valid after the
+ * handshake. */
+ unsigned tlsext_channel_id_valid:1;
+
+ uint8_t send_alert[2];
+
+ /* pending_flight is the pending outgoing flight. This is used to flush each
+ * handshake flight in a single write. */
+ BUF_MEM *pending_flight;
+
+ /* pending_flight_offset is the number of bytes of |pending_flight| which have
+ * been successfully written. */
+ uint32_t pending_flight_offset;
+
+ /* aead_read_ctx is the current read cipher state. */
+ SSL_AEAD_CTX *aead_read_ctx;
+
+ /* aead_write_ctx is the current write cipher state. */
+ SSL_AEAD_CTX *aead_write_ctx;
+
+ /* hs is the handshake state for the current handshake or NULL if there isn't
+ * one. */
+ SSL_HANDSHAKE *hs;
+
+ uint8_t write_traffic_secret[EVP_MAX_MD_SIZE];
+ uint8_t read_traffic_secret[EVP_MAX_MD_SIZE];
+ uint8_t exporter_secret[EVP_MAX_MD_SIZE];
+ uint8_t write_traffic_secret_len;
+ uint8_t read_traffic_secret_len;
+ uint8_t exporter_secret_len;
+
+ /* Connection binding to prevent renegotiation attacks */
+ uint8_t previous_client_finished[12];
+ uint8_t previous_client_finished_len;
+ uint8_t previous_server_finished_len;
+ uint8_t previous_server_finished[12];
+
+ /* State pertaining to the pending handshake.
+ *
+ * TODO(davidben): Move everything not needed after the handshake completes to
+ * |hs| and remove this. */
+ struct {
+ int message_type;
+
+ int reuse_message;
+
+ uint8_t new_mac_secret_len;
+ uint8_t new_key_len;
+ uint8_t new_fixed_iv_len;
+ } tmp;
+
+ /* established_session is the session established by the connection. This
+ * session is only filled upon the completion of the handshake and is
+ * immutable. */
+ SSL_SESSION *established_session;
+
+ /* Next protocol negotiation. For the client, this is the protocol that we
+ * sent in NextProtocol and is set when handling ServerHello extensions.
+ *
+ * For a server, this is the client's selected_protocol from NextProtocol and
+ * is set when handling the NextProtocol message, before the Finished
+ * message. */
+ uint8_t *next_proto_negotiated;
+ size_t next_proto_negotiated_len;
+
+ /* ALPN information
+ * (we are in the process of transitioning from NPN to ALPN.) */
+
+ /* In a server these point to the selected ALPN protocol after the
+ * ClientHello has been processed. In a client these contain the protocol
+ * that the server selected once the ServerHello has been processed. */
+ uint8_t *alpn_selected;
+ size_t alpn_selected_len;
+
+ /* For a server:
+ * If |tlsext_channel_id_valid| is true, then this contains the
+ * verified Channel ID from the client: a P256 point, (x,y), where
+ * each are big-endian values. */
+ uint8_t tlsext_channel_id[64];
+
+ /* ticket_age_skew is the difference, in seconds, between the client-sent
+ * ticket age and the server-computed value in TLS 1.3 server connections
+ * which resumed a session. */
+ int32_t ticket_age_skew;
+} SSL3_STATE;
+
+/* lengths of messages */
+#define DTLS1_COOKIE_LENGTH 256
+
+#define DTLS1_RT_HEADER_LENGTH 13
+
+#define DTLS1_HM_HEADER_LENGTH 12
+
+#define DTLS1_CCS_HEADER_LENGTH 1
+
+#define DTLS1_AL_HEADER_LENGTH 2
+
+struct hm_header_st {
+ uint8_t type;
+ uint32_t msg_len;
+ uint16_t seq;
+ uint32_t frag_off;
+ uint32_t frag_len;
+};
+
+/* An hm_fragment is an incoming DTLS message, possibly not yet assembled. */
+typedef struct hm_fragment_st {
+ /* type is the type of the message. */
+ uint8_t type;
+ /* seq is the sequence number of this message. */
+ uint16_t seq;
+ /* msg_len is the length of the message body. */
+ uint32_t msg_len;
+ /* data is a pointer to the message, including message header. It has length
+ * |DTLS1_HM_HEADER_LENGTH| + |msg_len|. */
+ uint8_t *data;
+ /* reassembly is a bitmask of |msg_len| bits corresponding to which parts of
+ * the message have been received. It is NULL if the message is complete. */
+ uint8_t *reassembly;
+} hm_fragment;
+
+struct OPENSSL_timeval {
+ uint64_t tv_sec;
+ uint32_t tv_usec;
+};
+
+typedef struct dtls1_state_st {
+ /* send_cookie is true if we are resending the ClientHello
+ * with a cookie from a HelloVerifyRequest. */
+ unsigned int send_cookie;
+
+ uint8_t cookie[DTLS1_COOKIE_LENGTH];
+ size_t cookie_len;
+
+ /* The current data and handshake epoch. This is initially undefined, and
+ * starts at zero once the initial handshake is completed. */
+ uint16_t r_epoch;
+ uint16_t w_epoch;
+
+ /* records being received in the current epoch */
+ DTLS1_BITMAP bitmap;
+
+ uint16_t handshake_write_seq;
+ uint16_t handshake_read_seq;
+
+ /* save last sequence number for retransmissions */
+ uint8_t last_write_sequence[8];
+
+ /* incoming_messages is a ring buffer of incoming handshake messages that have
+ * yet to be processed. The front of the ring buffer is message number
+ * |handshake_read_seq|, at position |handshake_read_seq| %
+ * |SSL_MAX_HANDSHAKE_FLIGHT|. */
+ hm_fragment *incoming_messages[SSL_MAX_HANDSHAKE_FLIGHT];
+
+ /* outgoing_messages is the queue of outgoing messages from the last handshake
+ * flight. */
+ DTLS_OUTGOING_MESSAGE outgoing_messages[SSL_MAX_HANDSHAKE_FLIGHT];
+ uint8_t outgoing_messages_len;
+
+ /* outgoing_written is the number of outgoing messages that have been
+ * written. */
+ uint8_t outgoing_written;
+ /* outgoing_offset is the number of bytes of the next outgoing message have
+ * been written. */
+ uint32_t outgoing_offset;
+
+ unsigned int mtu; /* max DTLS packet size */
+
+ /* num_timeouts is the number of times the retransmit timer has fired since
+ * the last time it was reset. */
+ unsigned int num_timeouts;
+
+ /* Indicates when the last handshake msg or heartbeat sent will
+ * timeout. */
+ struct OPENSSL_timeval next_timeout;
+
+ /* timeout_duration_ms is the timeout duration in milliseconds. */
+ unsigned timeout_duration_ms;
+} DTLS1_STATE;
+
+struct ssl_st {
+ /* method is the method table corresponding to the current protocol (DTLS or
+ * TLS). */
+ const SSL_PROTOCOL_METHOD *method;
+
+ /* version is the protocol version. */
+ int version;
+
+ /* max_version is the maximum acceptable protocol version. Note this version
+ * is normalized in DTLS. */
+ uint16_t max_version;
+
+ /* min_version is the minimum acceptable protocol version. Note this version
+ * is normalized in DTLS. */
+ uint16_t min_version;
+
+ uint16_t max_send_fragment;
+
+ /* There are 2 BIO's even though they are normally both the same. This is so
+ * data can be read and written to different handlers */
+
+ BIO *rbio; /* used by SSL_read */
+ BIO *wbio; /* used by SSL_write */
+
+ int (*handshake_func)(SSL_HANDSHAKE *hs);
+
+ BUF_MEM *init_buf; /* buffer used during init */
+
+ /* init_msg is a pointer to the current handshake message body. */
+ const uint8_t *init_msg;
+ /* init_num is the length of the current handshake message body. */
+ uint32_t init_num;
+
+ struct ssl3_state_st *s3; /* SSLv3 variables */
+ struct dtls1_state_st *d1; /* DTLSv1 variables */
+
+ /* callback that allows applications to peek at protocol messages */
+ void (*msg_callback)(int write_p, int version, int content_type,
+ const void *buf, size_t len, SSL *ssl, void *arg);
+ void *msg_callback_arg;
+
+ X509_VERIFY_PARAM *param;
+
+ /* crypto */
+ struct ssl_cipher_preference_list_st *cipher_list;
+
+ /* session info */
+
+ /* client cert? */
+ /* This is used to hold the server certificate used */
+ struct cert_st /* CERT */ *cert;
+
+ /* This holds a variable that indicates what we were doing when a 0 or -1 is
+ * returned. This is needed for non-blocking IO so we know what request
+ * needs re-doing when in SSL_accept or SSL_connect */
+ int rwstate;
+
+ /* initial_timeout_duration_ms is the default DTLS timeout duration in
+ * milliseconds. It's used to initialize the timer any time it's restarted. */
+ unsigned initial_timeout_duration_ms;
+
+ /* session is the configured session to be offered by the client. This session
+ * is immutable. */
+ SSL_SESSION *session;
+
+ int (*verify_callback)(int ok,
+ X509_STORE_CTX *ctx); /* fail if callback returns 0 */
+
+ void (*info_callback)(const SSL *ssl, int type, int value);
+
+ /* Server-only: psk_identity_hint is the identity hint to send in
+ * PSK-based key exchanges. */
+ char *psk_identity_hint;
+
+ unsigned int (*psk_client_callback)(SSL *ssl, const char *hint,
+ char *identity,
+ unsigned int max_identity_len,
+ uint8_t *psk, unsigned int max_psk_len);
+ unsigned int (*psk_server_callback)(SSL *ssl, const char *identity,
+ uint8_t *psk, unsigned int max_psk_len);
+
+ SSL_CTX *ctx;
+
+ /* extra application data */
+ CRYPTO_EX_DATA ex_data;
+
+ /* for server side, keep the list of CA_dn we can use */
+ STACK_OF(CRYPTO_BUFFER) *client_CA;
+
+ /* cached_x509_client_CA is a cache of parsed versions of the elements of
+ * |client_CA|. */
+ STACK_OF(X509_NAME) *cached_x509_client_CA;
+
+ uint32_t options; /* protocol behaviour */
+ uint32_t mode; /* API behaviour */
+ uint32_t max_cert_list;
+ char *tlsext_hostname;
+ size_t supported_group_list_len;
+ uint16_t *supported_group_list; /* our list */
+
+ /* session_ctx is the |SSL_CTX| used for the session cache and related
+ * settings. */
+ SSL_CTX *session_ctx;
+
+ /* srtp_profiles is the list of configured SRTP protection profiles for
+ * DTLS-SRTP. */
+ STACK_OF(SRTP_PROTECTION_PROFILE) *srtp_profiles;
+
+ /* srtp_profile is the selected SRTP protection profile for
+ * DTLS-SRTP. */
+ const SRTP_PROTECTION_PROFILE *srtp_profile;
+
+ /* The client's Channel ID private key. */
+ EVP_PKEY *tlsext_channel_id_private;
+
+ /* For a client, this contains the list of supported protocols in wire
+ * format. */
+ uint8_t *alpn_client_proto_list;
+ unsigned alpn_client_proto_list_len;
+
+ /* renegotiate_mode controls how peer renegotiation attempts are handled. */
+ enum ssl_renegotiate_mode_t renegotiate_mode;
+
+ /* verify_mode is a bitmask of |SSL_VERIFY_*| values. */
+ uint8_t verify_mode;
+
+ /* server is true iff the this SSL* is the server half. Note: before the SSL*
+ * is initialized by either SSL_set_accept_state or SSL_set_connect_state,
+ * the side is not determined. In this state, server is always false. */
+ unsigned server:1;
+
+ /* quiet_shutdown is true if the connection should not send a close_notify on
+ * shutdown. */
+ unsigned quiet_shutdown:1;
+
+ /* Enable signed certificate time stamps. Currently client only. */
+ unsigned signed_cert_timestamps_enabled:1;
+
+ /* ocsp_stapling_enabled is only used by client connections and indicates
+ * whether OCSP stapling will be requested. */
+ unsigned ocsp_stapling_enabled:1;
+
+ /* tlsext_channel_id_enabled is copied from the |SSL_CTX|. For a server,
+ * means that we'll accept Channel IDs from clients. For a client, means that
+ * we'll advertise support. */
+ unsigned tlsext_channel_id_enabled:1;
+
+ /* retain_only_sha256_of_client_certs is true if we should compute the SHA256
+ * hash of the peer's certificate and then discard it to save memory and
+ * session space. Only effective on the server side. */
+ unsigned retain_only_sha256_of_client_certs:1;
+};
+
+/* From draft-ietf-tls-tls13-18, used in determining PSK modes. */
+#define SSL_PSK_KE 0x0
+#define SSL_PSK_DHE_KE 0x1
+
+/* From draft-ietf-tls-tls13-16, used in determining whether to respond with a
+ * KeyUpdate. */
+#define SSL_KEY_UPDATE_NOT_REQUESTED 0
+#define SSL_KEY_UPDATE_REQUESTED 1
+
+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);
+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
+ * message on the error queue. */
+int ssl_compare_public_and_private_key(const EVP_PKEY *pubkey,
+ const EVP_PKEY *privkey);
+int ssl_cert_check_private_key(const CERT *cert, const EVP_PKEY *privkey);
+int ssl_get_new_session(SSL_HANDSHAKE *hs, int is_server);
+int ssl_encrypt_ticket(SSL *ssl, CBB *out, const SSL_SESSION *session);
+
+/* ssl_session_new returns a newly-allocated blank |SSL_SESSION| or NULL on
+ * error. */
+SSL_SESSION *ssl_session_new(const SSL_X509_METHOD *x509_method);
+
+/* SSL_SESSION_parse parses an |SSL_SESSION| from |cbs| and advances |cbs| over
+ * the parsed data. */
+SSL_SESSION *SSL_SESSION_parse(CBS *cbs, const SSL_X509_METHOD *x509_method,
+ CRYPTO_BUFFER_POOL *pool);
+
+/* ssl_session_is_context_valid returns one if |session|'s session ID context
+ * matches the one set on |ssl| and zero otherwise. */
+int ssl_session_is_context_valid(const SSL *ssl, const SSL_SESSION *session);
+
+/* ssl_session_is_time_valid returns one if |session| is still valid and zero if
+ * it has expired. */
+int ssl_session_is_time_valid(const SSL *ssl, const SSL_SESSION *session);
+
+/* ssl_session_is_resumable returns one if |session| is resumable for |hs| and
+ * zero otherwise. */
+int ssl_session_is_resumable(const SSL_HANDSHAKE *hs,
+ const SSL_SESSION *session);
+
+/* SSL_SESSION_get_digest returns the digest used in |session|. If the digest is
+ * invalid, it returns NULL. */
+const EVP_MD *SSL_SESSION_get_digest(const SSL_SESSION *session,
+ const SSL *ssl);
+
+void ssl_set_session(SSL *ssl, SSL_SESSION *session);
+
+enum ssl_session_result_t {
+ ssl_session_success,
+ ssl_session_error,
+ ssl_session_retry,
+ ssl_session_ticket_retry,
+};
+
+/* 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
+ * |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,
+ int *out_renew_ticket, const SSL_CLIENT_HELLO *client_hello);
+
+/* The following flags determine which parts of the session are duplicated. */
+#define SSL_SESSION_DUP_AUTH_ONLY 0x0
+#define SSL_SESSION_INCLUDE_TICKET 0x1
+#define SSL_SESSION_INCLUDE_NONAUTH 0x2
+#define SSL_SESSION_DUP_ALL \
+ (SSL_SESSION_INCLUDE_TICKET | SSL_SESSION_INCLUDE_NONAUTH)
+
+/* SSL_SESSION_dup returns a newly-allocated |SSL_SESSION| with a copy of the
+ * fields in |session| or NULL on error. The new session is non-resumable and
+ * must be explicitly marked resumable once it has been filled in. */
+OPENSSL_EXPORT SSL_SESSION *SSL_SESSION_dup(SSL_SESSION *session,
+ int dup_flags);
+
+/* ssl_session_rebase_time updates |session|'s start time to the current time,
+ * adjusting the timeout so the expiration time is unchanged. */
+void ssl_session_rebase_time(SSL *ssl, SSL_SESSION *session);
+
+/* ssl_session_renew_timeout calls |ssl_session_rebase_time| and renews
+ * |session|'s timeout to |timeout| (measured from the current time). The
+ * renewal is clamped to the session's auth_timeout. */
+void ssl_session_renew_timeout(SSL *ssl, SSL_SESSION *session,
+ uint32_t timeout);
+
+void ssl_cipher_preference_list_free(
+ struct ssl_cipher_preference_list_st *cipher_list);
+
+/* ssl_get_cipher_preferences returns the cipher preference list for TLS 1.2 and
+ * below. */
+const struct ssl_cipher_preference_list_st *ssl_get_cipher_preferences(
+ const SSL *ssl);
+
+void ssl_update_cache(SSL_HANDSHAKE *hs, int mode);
+
+int ssl3_get_finished(SSL_HANDSHAKE *hs);
+int ssl3_send_alert(SSL *ssl, int level, int desc);
+int ssl3_get_message(SSL *ssl);
+void ssl3_get_current_message(const SSL *ssl, CBS *out);
+void ssl3_release_current_message(SSL *ssl, int free_buffer);
+
+int ssl3_send_finished(SSL_HANDSHAKE *hs);
+int ssl3_dispatch_alert(SSL *ssl);
+int ssl3_read_app_data(SSL *ssl, int *out_got_handshake, uint8_t *buf, int len,
+ int peek);
+int ssl3_read_change_cipher_spec(SSL *ssl);
+void ssl3_read_close_notify(SSL *ssl);
+int ssl3_read_handshake_bytes(SSL *ssl, uint8_t *buf, int len);
+int ssl3_write_app_data(SSL *ssl, const uint8_t *buf, int len);
+int ssl3_output_cert_chain(SSL *ssl);
+
+int ssl3_new(SSL *ssl);
+void ssl3_free(SSL *ssl);
+int ssl3_accept(SSL_HANDSHAKE *hs);
+int ssl3_connect(SSL_HANDSHAKE *hs);
+
+int ssl3_init_message(SSL *ssl, CBB *cbb, CBB *body, uint8_t type);
+int ssl3_finish_message(SSL *ssl, CBB *cbb, uint8_t **out_msg, size_t *out_len);
+int ssl3_add_message(SSL *ssl, uint8_t *msg, size_t len);
+int ssl3_add_change_cipher_spec(SSL *ssl);
+int ssl3_add_alert(SSL *ssl, uint8_t level, uint8_t desc);
+int ssl3_flush_flight(SSL *ssl);
+
+int dtls1_init_message(SSL *ssl, CBB *cbb, CBB *body, uint8_t type);
+int dtls1_finish_message(SSL *ssl, CBB *cbb, uint8_t **out_msg,
+ size_t *out_len);
+int dtls1_add_message(SSL *ssl, uint8_t *msg, size_t len);
+int dtls1_add_change_cipher_spec(SSL *ssl);
+int dtls1_add_alert(SSL *ssl, uint8_t level, uint8_t desc);
+int dtls1_flush_flight(SSL *ssl);
+
+/* ssl_add_message_cbb finishes the handshake message in |cbb| and adds it to
+ * the pending flight. It returns one on success and zero on error. */
+int ssl_add_message_cbb(SSL *ssl, CBB *cbb);
+
+/* ssl_hash_current_message incorporates the current handshake message into the
+ * handshake hash. It returns one on success and zero on allocation failure. */
+int ssl_hash_current_message(SSL_HANDSHAKE *hs);
+
+/* dtls1_get_record reads a new input record. On success, it places it in
+ * |ssl->s3->rrec| and returns one. Otherwise it returns <= 0 on error or if
+ * more data is needed. */
+int dtls1_get_record(SSL *ssl);
+
+int dtls1_read_app_data(SSL *ssl, int *out_got_handshake, uint8_t *buf, int len,
+ int peek);
+int dtls1_read_change_cipher_spec(SSL *ssl);
+void dtls1_read_close_notify(SSL *ssl);
+
+int dtls1_write_app_data(SSL *ssl, const uint8_t *buf, int len);
+
+/* dtls1_write_record sends a record. It returns one on success and <= 0 on
+ * error. */
+int dtls1_write_record(SSL *ssl, int type, const uint8_t *buf, size_t len,
+ enum dtls1_use_epoch_t use_epoch);
+
+int dtls1_send_finished(SSL *ssl, int a, int b, const char *sender, int slen);
+int dtls1_retransmit_outgoing_messages(SSL *ssl);
+void dtls1_clear_record_buffer(SSL *ssl);
+int dtls1_parse_fragment(CBS *cbs, struct hm_header_st *out_hdr,
+ CBS *out_body);
+int dtls1_check_timeout_num(SSL *ssl);
+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);
+int dtls1_accept(SSL *ssl);
+int dtls1_connect(SSL *ssl);
+void dtls1_free(SSL *ssl);
+
+int dtls1_get_message(SSL *ssl);
+void dtls1_get_current_message(const SSL *ssl, CBS *out);
+void dtls1_release_current_message(SSL *ssl, int free_buffer);
+int dtls1_dispatch_alert(SSL *ssl);
+
+int tls1_change_cipher_state(SSL_HANDSHAKE *hs, int which);
+int tls1_generate_master_secret(SSL_HANDSHAKE *hs, uint8_t *out,
+ const uint8_t *premaster, size_t premaster_len);
+
+/* tls1_get_grouplist sets |*out_group_ids| and |*out_group_ids_len| to the
+ * locally-configured group preference list. */
+void tls1_get_grouplist(SSL *ssl, const uint16_t **out_group_ids,
+ size_t *out_group_ids_len);
+
+/* tls1_check_group_id returns one if |group_id| is consistent with
+ * locally-configured group preferences. */
+int tls1_check_group_id(SSL *ssl, uint16_t group_id);
+
+/* tls1_get_shared_group sets |*out_group_id| to the first preferred shared
+ * group between client and server preferences and returns one. If none may be
+ * found, it returns zero. */
+int tls1_get_shared_group(SSL_HANDSHAKE *hs, uint16_t *out_group_id);
+
+/* tls1_set_curves converts the array of |ncurves| NIDs pointed to by |curves|
+ * into a newly allocated array of TLS group IDs. On success, the function
+ * returns one and writes the array to |*out_group_ids| and its size to
+ * |*out_group_ids_len|. Otherwise, it returns zero. */
+int tls1_set_curves(uint16_t **out_group_ids, size_t *out_group_ids_len,
+ const int *curves, size_t ncurves);
+
+/* tls1_set_curves_list converts the string of curves pointed to by |curves|
+ * into a newly allocated array of TLS group IDs. On success, the function
+ * returns one and writes the array to |*out_group_ids| and its size to
+ * |*out_group_ids_len|. Otherwise, it returns zero. */
+int tls1_set_curves_list(uint16_t **out_group_ids, size_t *out_group_ids_len,
+ const char *curves);
+
+/* ssl_add_clienthello_tlsext writes ClientHello extensions to |out|. It
+ * returns one on success and zero on failure. The |header_len| argument is the
+ * length of the ClientHello written so far and is used to compute the padding
+ * length. (It does not include the record header.) */
+int ssl_add_clienthello_tlsext(SSL_HANDSHAKE *hs, CBB *out, size_t header_len);
+
+int ssl_add_serverhello_tlsext(SSL_HANDSHAKE *hs, CBB *out);
+int ssl_parse_clienthello_tlsext(SSL_HANDSHAKE *hs,
+ const SSL_CLIENT_HELLO *client_hello);
+int ssl_parse_serverhello_tlsext(SSL_HANDSHAKE *hs, CBS *cbs);
+
+#define tlsext_tick_md EVP_sha256
+
+/* ssl_process_ticket processes a session ticket from the client. It returns
+ * one of:
+ * |ssl_ticket_aead_success|: |*out_session| is set to the parsed session and
+ * |*out_renew_ticket| is set to whether the ticket should be renewed.
+ * |ssl_ticket_aead_ignore_ticket|: |*out_renew_ticket| is set to whether a
+ * fresh ticket should be sent, but the given ticket cannot be used.
+ * |ssl_ticket_aead_retry|: the ticket could not be immediately decrypted.
+ * 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,
+ const uint8_t *ticket, size_t ticket_len, const uint8_t *session_id,
+ size_t session_id_len);
+
+/* tls1_verify_channel_id processes the current message as a Channel ID message,
+ * and verifies the signature. If the key is valid, it saves the Channel ID and
+ * returns one. Otherwise, it returns zero. */
+int tls1_verify_channel_id(SSL_HANDSHAKE *hs);
+
+/* tls1_write_channel_id generates a Channel ID message and puts the output in
+ * |cbb|. |ssl->tlsext_channel_id_private| must already be set before calling.
+ * This function returns one on success and zero on error. */
+int tls1_write_channel_id(SSL_HANDSHAKE *hs, CBB *cbb);
+
+/* tls1_channel_id_hash computes the hash to be signed by Channel ID and writes
+ * it to |out|, which must contain at least |EVP_MAX_MD_SIZE| bytes. It returns
+ * one on success and zero on failure. */
+int tls1_channel_id_hash(SSL_HANDSHAKE *hs, uint8_t *out, size_t *out_len);
+
+int tls1_record_handshake_hashes_for_channel_id(SSL_HANDSHAKE *hs);
+
+/* ssl_do_channel_id_callback checks runs |ssl->ctx->channel_id_cb| if
+ * necessary. It returns one on success and zero on fatal error. Note that, on
+ * success, |ssl->tlsext_channel_id_private| may be unset, in which case the
+ * operation should be retried later. */
+int ssl_do_channel_id_callback(SSL *ssl);
+
+/* ssl3_can_false_start returns one if |ssl| is allowed to False Start and zero
+ * otherwise. */
+int ssl3_can_false_start(const SSL *ssl);
+
+/* ssl_get_version_range sets |*out_min_version| and |*out_max_version| to the
+ * minimum and maximum enabled protocol versions, respectively. */
+int ssl_get_version_range(const SSL *ssl, uint16_t *out_min_version,
+ uint16_t *out_max_version);
+
+/* ssl3_protocol_version returns |ssl|'s protocol version. It is an error to
+ * call this function before the version is determined. */
+uint16_t ssl3_protocol_version(const SSL *ssl);
+
+void ssl_get_current_time(const SSL *ssl, struct OPENSSL_timeval *out_clock);
+
+/* ssl_reset_error_state resets state for |SSL_get_error|. */
+void ssl_reset_error_state(SSL *ssl);
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#endif /* OPENSSL_HEADER_SSL_INTERNAL_H */
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/s3_both.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/s3_both.c
new file mode 100644
index 000000000..8fa51e932
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/s3_both.c
@@ -0,0 +1,821 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com). */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ * ECC cipher suite support in OpenSSL originally developed by
+ * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. */
+
+#include <openssl/ssl.h>
+
+#include <assert.h>
+#include <limits.h>
+#include <string.h>
+
+#include <openssl/buf.h>
+#include <openssl/bytestring.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/mem.h>
+#include <openssl/md5.h>
+#include <openssl/nid.h>
+#include <openssl/rand.h>
+#include <openssl/sha.h>
+
+#include "../crypto/internal.h"
+#include "internal.h"
+
+
+SSL_HANDSHAKE *ssl_handshake_new(SSL *ssl) {
+ SSL_HANDSHAKE *hs = OPENSSL_malloc(sizeof(SSL_HANDSHAKE));
+ if (hs == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ OPENSSL_memset(hs, 0, sizeof(SSL_HANDSHAKE));
+ hs->ssl = ssl;
+ hs->wait = ssl_hs_ok;
+ hs->state = SSL_ST_INIT;
+ if (!SSL_TRANSCRIPT_init(&hs->transcript)) {
+ ssl_handshake_free(hs);
+ return NULL;
+ }
+ return hs;
+}
+
+void ssl_handshake_free(SSL_HANDSHAKE *hs) {
+ if (hs == NULL) {
+ return;
+ }
+
+ OPENSSL_cleanse(hs->secret, sizeof(hs->secret));
+ OPENSSL_cleanse(hs->client_handshake_secret,
+ sizeof(hs->client_handshake_secret));
+ OPENSSL_cleanse(hs->server_handshake_secret,
+ sizeof(hs->server_handshake_secret));
+ OPENSSL_cleanse(hs->client_traffic_secret_0,
+ sizeof(hs->client_traffic_secret_0));
+ OPENSSL_cleanse(hs->server_traffic_secret_0,
+ sizeof(hs->server_traffic_secret_0));
+ SSL_ECDH_CTX_cleanup(&hs->ecdh_ctx);
+ SSL_TRANSCRIPT_cleanup(&hs->transcript);
+ OPENSSL_free(hs->cookie);
+ OPENSSL_free(hs->key_share_bytes);
+ OPENSSL_free(hs->public_key);
+ SSL_SESSION_free(hs->new_session);
+ OPENSSL_free(hs->peer_sigalgs);
+ OPENSSL_free(hs->peer_supported_group_list);
+ OPENSSL_free(hs->peer_key);
+ OPENSSL_free(hs->server_params);
+ OPENSSL_free(hs->peer_psk_identity_hint);
+ sk_CRYPTO_BUFFER_pop_free(hs->ca_names, CRYPTO_BUFFER_free);
+ hs->ssl->ctx->x509_method->hs_flush_cached_ca_names(hs);
+ OPENSSL_free(hs->certificate_types);
+
+ if (hs->key_block != NULL) {
+ OPENSSL_cleanse(hs->key_block, hs->key_block_len);
+ OPENSSL_free(hs->key_block);
+ }
+
+ OPENSSL_free(hs->hostname);
+ EVP_PKEY_free(hs->peer_pubkey);
+ OPENSSL_free(hs);
+}
+
+int ssl_check_message_type(SSL *ssl, int type) {
+ if (ssl->s3->tmp.message_type != type) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE);
+ ERR_add_error_dataf("got type %d, wanted type %d",
+ ssl->s3->tmp.message_type, type);
+ return 0;
+ }
+
+ return 1;
+}
+
+static int add_record_to_flight(SSL *ssl, uint8_t type, const uint8_t *in,
+ size_t in_len) {
+ /* We'll never add a flight while in the process of writing it out. */
+ assert(ssl->s3->pending_flight_offset == 0);
+
+ if (ssl->s3->pending_flight == NULL) {
+ ssl->s3->pending_flight = BUF_MEM_new();
+ if (ssl->s3->pending_flight == NULL) {
+ return 0;
+ }
+ }
+
+ size_t max_out = in_len + SSL_max_seal_overhead(ssl);
+ size_t new_cap = ssl->s3->pending_flight->length + max_out;
+ if (max_out < in_len || new_cap < max_out) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
+ return 0;
+ }
+
+ size_t len;
+ if (!BUF_MEM_reserve(ssl->s3->pending_flight, new_cap) ||
+ !tls_seal_record(ssl, (uint8_t *)ssl->s3->pending_flight->data +
+ ssl->s3->pending_flight->length,
+ &len, max_out, type, in, in_len)) {
+ return 0;
+ }
+
+ ssl->s3->pending_flight->length += len;
+ return 1;
+}
+
+int ssl3_init_message(SSL *ssl, CBB *cbb, CBB *body, uint8_t type) {
+ /* Pick a modest size hint to save most of the |realloc| calls. */
+ if (!CBB_init(cbb, 64) ||
+ !CBB_add_u8(cbb, type) ||
+ !CBB_add_u24_length_prefixed(cbb, body)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ CBB_cleanup(cbb);
+ return 0;
+ }
+
+ return 1;
+}
+
+int ssl3_finish_message(SSL *ssl, CBB *cbb, uint8_t **out_msg,
+ size_t *out_len) {
+ if (!CBB_finish(cbb, out_msg, out_len)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ return 1;
+}
+
+int ssl3_add_message(SSL *ssl, uint8_t *msg, size_t len) {
+ /* Add the message to the current flight, splitting into several records if
+ * needed. */
+ int ret = 0;
+ size_t added = 0;
+ do {
+ size_t todo = len - added;
+ if (todo > ssl->max_send_fragment) {
+ todo = ssl->max_send_fragment;
+ }
+
+ if (!add_record_to_flight(ssl, SSL3_RT_HANDSHAKE, msg + added, todo)) {
+ goto err;
+ }
+ added += todo;
+ } while (added < len);
+
+ ssl_do_msg_callback(ssl, 1 /* write */, SSL3_RT_HANDSHAKE, msg, len);
+ /* TODO(svaldez): Move this up a layer to fix abstraction for SSL_TRANSCRIPT
+ * on hs. */
+ if (ssl->s3->hs != NULL &&
+ !SSL_TRANSCRIPT_update(&ssl->s3->hs->transcript, msg, len)) {
+ goto err;
+ }
+ ret = 1;
+
+err:
+ OPENSSL_free(msg);
+ return ret;
+}
+
+int ssl3_add_change_cipher_spec(SSL *ssl) {
+ static const uint8_t kChangeCipherSpec[1] = {SSL3_MT_CCS};
+
+ if (!add_record_to_flight(ssl, SSL3_RT_CHANGE_CIPHER_SPEC, kChangeCipherSpec,
+ sizeof(kChangeCipherSpec))) {
+ return 0;
+ }
+
+ ssl_do_msg_callback(ssl, 1 /* write */, SSL3_RT_CHANGE_CIPHER_SPEC,
+ kChangeCipherSpec, sizeof(kChangeCipherSpec));
+ return 1;
+}
+
+int ssl3_add_alert(SSL *ssl, uint8_t level, uint8_t desc) {
+ uint8_t alert[2] = {level, desc};
+ if (!add_record_to_flight(ssl, SSL3_RT_ALERT, alert, sizeof(alert))) {
+ return 0;
+ }
+
+ ssl_do_msg_callback(ssl, 1 /* write */, SSL3_RT_ALERT, alert, sizeof(alert));
+ ssl_do_info_callback(ssl, SSL_CB_WRITE_ALERT, ((int)level << 8) | desc);
+ return 1;
+}
+
+int ssl_add_message_cbb(SSL *ssl, CBB *cbb) {
+ uint8_t *msg;
+ size_t len;
+ if (!ssl->method->finish_message(ssl, cbb, &msg, &len) ||
+ !ssl->method->add_message(ssl, msg, len)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+int ssl3_flush_flight(SSL *ssl) {
+ if (ssl->s3->pending_flight == NULL) {
+ return 1;
+ }
+
+ if (ssl->s3->pending_flight->length > 0xffffffff ||
+ ssl->s3->pending_flight->length > INT_MAX) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
+
+ /* The handshake flight buffer is mutually exclusive with application data.
+ *
+ * TODO(davidben): This will not be true when closure alerts use this. */
+ if (ssl_write_buffer_is_pending(ssl)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
+
+ /* Write the pending flight. */
+ while (ssl->s3->pending_flight_offset < ssl->s3->pending_flight->length) {
+ int ret = BIO_write(
+ ssl->wbio,
+ ssl->s3->pending_flight->data + ssl->s3->pending_flight_offset,
+ ssl->s3->pending_flight->length - ssl->s3->pending_flight_offset);
+ if (ret <= 0) {
+ ssl->rwstate = SSL_WRITING;
+ return ret;
+ }
+
+ ssl->s3->pending_flight_offset += ret;
+ }
+
+ if (BIO_flush(ssl->wbio) <= 0) {
+ ssl->rwstate = SSL_WRITING;
+ return -1;
+ }
+
+ BUF_MEM_free(ssl->s3->pending_flight);
+ ssl->s3->pending_flight = NULL;
+ ssl->s3->pending_flight_offset = 0;
+ return 1;
+}
+
+int ssl3_send_finished(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ const SSL_SESSION *session = SSL_get_session(ssl);
+
+ uint8_t finished[EVP_MAX_MD_SIZE];
+ size_t finished_len;
+ if (!SSL_TRANSCRIPT_finish_mac(&hs->transcript, finished, &finished_len,
+ session, ssl->server,
+ ssl3_protocol_version(ssl))) {
+ return 0;
+ }
+
+ /* Log the master secret, if logging is enabled. */
+ if (!ssl_log_secret(ssl, "CLIENT_RANDOM",
+ session->master_key,
+ session->master_key_length)) {
+ return 0;
+ }
+
+ /* Copy the Finished so we can use it for renegotiation checks. */
+ if (ssl->version != SSL3_VERSION) {
+ if (finished_len > sizeof(ssl->s3->previous_client_finished) ||
+ finished_len > sizeof(ssl->s3->previous_server_finished)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
+
+ if (ssl->server) {
+ OPENSSL_memcpy(ssl->s3->previous_server_finished, finished, finished_len);
+ ssl->s3->previous_server_finished_len = finished_len;
+ } else {
+ OPENSSL_memcpy(ssl->s3->previous_client_finished, finished, finished_len);
+ ssl->s3->previous_client_finished_len = finished_len;
+ }
+ }
+
+ CBB cbb, body;
+ if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_FINISHED) ||
+ !CBB_add_bytes(&body, finished, finished_len) ||
+ !ssl_add_message_cbb(ssl, &cbb)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ CBB_cleanup(&cbb);
+ return -1;
+ }
+
+ return 1;
+}
+
+int ssl3_get_finished(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ int ret = ssl->method->ssl_get_message(ssl);
+ if (ret <= 0) {
+ return ret;
+ }
+
+ if (!ssl_check_message_type(ssl, SSL3_MT_FINISHED)) {
+ return -1;
+ }
+
+ /* Snapshot the finished hash before incorporating the new message. */
+ uint8_t finished[EVP_MAX_MD_SIZE];
+ size_t finished_len;
+ if (!SSL_TRANSCRIPT_finish_mac(&hs->transcript, finished, &finished_len,
+ SSL_get_session(ssl), !ssl->server,
+ ssl3_protocol_version(ssl)) ||
+ !ssl_hash_current_message(hs)) {
+ return -1;
+ }
+
+ int finished_ok = ssl->init_num == finished_len &&
+ CRYPTO_memcmp(ssl->init_msg, finished, finished_len) == 0;
+#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+ finished_ok = 1;
+#endif
+ if (!finished_ok) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECRYPT_ERROR);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DIGEST_CHECK_FAILED);
+ return -1;
+ }
+
+ /* Copy the Finished so we can use it for renegotiation checks. */
+ if (ssl->version != SSL3_VERSION) {
+ if (finished_len > sizeof(ssl->s3->previous_client_finished) ||
+ finished_len > sizeof(ssl->s3->previous_server_finished)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
+
+ if (ssl->server) {
+ OPENSSL_memcpy(ssl->s3->previous_client_finished, finished, finished_len);
+ ssl->s3->previous_client_finished_len = finished_len;
+ } else {
+ OPENSSL_memcpy(ssl->s3->previous_server_finished, finished, finished_len);
+ ssl->s3->previous_server_finished_len = finished_len;
+ }
+ }
+
+ return 1;
+}
+
+int ssl3_output_cert_chain(SSL *ssl) {
+ CBB cbb, body;
+ if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_CERTIFICATE) ||
+ !ssl_add_cert_chain(ssl, &body) ||
+ !ssl_add_message_cbb(ssl, &cbb)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ CBB_cleanup(&cbb);
+ return 0;
+ }
+
+ return 1;
+}
+
+size_t ssl_max_handshake_message_len(const SSL *ssl) {
+ /* kMaxMessageLen is the default maximum message size for handshakes which do
+ * not accept peer certificate chains. */
+ static const size_t kMaxMessageLen = 16384;
+
+ if (SSL_in_init(ssl)) {
+ if ((!ssl->server || (ssl->verify_mode & SSL_VERIFY_PEER)) &&
+ kMaxMessageLen < ssl->max_cert_list) {
+ return ssl->max_cert_list;
+ }
+ return kMaxMessageLen;
+ }
+
+ if (ssl3_protocol_version(ssl) < TLS1_3_VERSION) {
+ /* In TLS 1.2 and below, the largest acceptable post-handshake message is
+ * a HelloRequest. */
+ return 0;
+ }
+
+ if (ssl->server) {
+ /* The largest acceptable post-handshake message for a server is a
+ * KeyUpdate. We will never initiate post-handshake auth. */
+ return 1;
+ }
+
+ /* Clients must accept NewSessionTicket and CertificateRequest, so allow the
+ * default size. */
+ return kMaxMessageLen;
+}
+
+static int extend_handshake_buffer(SSL *ssl, size_t length) {
+ if (!BUF_MEM_reserve(ssl->init_buf, length)) {
+ return -1;
+ }
+ while (ssl->init_buf->length < length) {
+ int ret = ssl3_read_handshake_bytes(
+ ssl, (uint8_t *)ssl->init_buf->data + ssl->init_buf->length,
+ length - ssl->init_buf->length);
+ if (ret <= 0) {
+ return ret;
+ }
+ ssl->init_buf->length += (size_t)ret;
+ }
+ return 1;
+}
+
+static int read_v2_client_hello(SSL *ssl) {
+ /* Read the first 5 bytes, the size of the TLS record header. This is
+ * sufficient to detect a V2ClientHello and ensures that we never read beyond
+ * the first record. */
+ int ret = ssl_read_buffer_extend_to(ssl, SSL3_RT_HEADER_LENGTH);
+ if (ret <= 0) {
+ return ret;
+ }
+ const uint8_t *p = ssl_read_buffer(ssl);
+
+ /* Some dedicated error codes for protocol mixups should the application wish
+ * to interpret them differently. (These do not overlap with ClientHello or
+ * V2ClientHello.) */
+ if (strncmp("GET ", (const char *)p, 4) == 0 ||
+ strncmp("POST ", (const char *)p, 5) == 0 ||
+ strncmp("HEAD ", (const char *)p, 5) == 0 ||
+ strncmp("PUT ", (const char *)p, 4) == 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_HTTP_REQUEST);
+ return -1;
+ }
+ if (strncmp("CONNE", (const char *)p, 5) == 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_HTTPS_PROXY_REQUEST);
+ return -1;
+ }
+
+ if ((p[0] & 0x80) == 0 || p[2] != SSL2_MT_CLIENT_HELLO ||
+ p[3] != SSL3_VERSION_MAJOR) {
+ /* Not a V2ClientHello. */
+ return 1;
+ }
+
+ /* Determine the length of the V2ClientHello. */
+ size_t msg_length = ((p[0] & 0x7f) << 8) | p[1];
+ if (msg_length > (1024 * 4)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_RECORD_TOO_LARGE);
+ return -1;
+ }
+ if (msg_length < SSL3_RT_HEADER_LENGTH - 2) {
+ /* Reject lengths that are too short early. We have already read
+ * |SSL3_RT_HEADER_LENGTH| bytes, so we should not attempt to process an
+ * (invalid) V2ClientHello which would be shorter than that. */
+ OPENSSL_PUT_ERROR(SSL, SSL_R_RECORD_LENGTH_MISMATCH);
+ return -1;
+ }
+
+ /* Read the remainder of the V2ClientHello. */
+ ret = ssl_read_buffer_extend_to(ssl, 2 + msg_length);
+ if (ret <= 0) {
+ return ret;
+ }
+
+ CBS v2_client_hello;
+ CBS_init(&v2_client_hello, ssl_read_buffer(ssl) + 2, msg_length);
+
+ /* The V2ClientHello without the length is incorporated into the handshake
+ * hash. This is only ever called at the start of the handshake, so hs is
+ * guaranteed to be non-NULL. */
+ if (!SSL_TRANSCRIPT_update(&ssl->s3->hs->transcript,
+ CBS_data(&v2_client_hello),
+ CBS_len(&v2_client_hello))) {
+ return -1;
+ }
+
+ ssl_do_msg_callback(ssl, 0 /* read */, 0 /* V2ClientHello */,
+ CBS_data(&v2_client_hello), CBS_len(&v2_client_hello));
+
+ uint8_t msg_type;
+ uint16_t version, cipher_spec_length, session_id_length, challenge_length;
+ CBS cipher_specs, session_id, challenge;
+ if (!CBS_get_u8(&v2_client_hello, &msg_type) ||
+ !CBS_get_u16(&v2_client_hello, &version) ||
+ !CBS_get_u16(&v2_client_hello, &cipher_spec_length) ||
+ !CBS_get_u16(&v2_client_hello, &session_id_length) ||
+ !CBS_get_u16(&v2_client_hello, &challenge_length) ||
+ !CBS_get_bytes(&v2_client_hello, &cipher_specs, cipher_spec_length) ||
+ !CBS_get_bytes(&v2_client_hello, &session_id, session_id_length) ||
+ !CBS_get_bytes(&v2_client_hello, &challenge, challenge_length) ||
+ CBS_len(&v2_client_hello) != 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ return -1;
+ }
+
+ /* msg_type has already been checked. */
+ assert(msg_type == SSL2_MT_CLIENT_HELLO);
+
+ /* The client_random is the V2ClientHello challenge. Truncate or
+ * left-pad with zeros as needed. */
+ size_t rand_len = CBS_len(&challenge);
+ if (rand_len > SSL3_RANDOM_SIZE) {
+ rand_len = SSL3_RANDOM_SIZE;
+ }
+ uint8_t random[SSL3_RANDOM_SIZE];
+ OPENSSL_memset(random, 0, SSL3_RANDOM_SIZE);
+ OPENSSL_memcpy(random + (SSL3_RANDOM_SIZE - rand_len), CBS_data(&challenge),
+ rand_len);
+
+ /* Write out an equivalent SSLv3 ClientHello. */
+ size_t max_v3_client_hello = SSL3_HM_HEADER_LENGTH + 2 /* version */ +
+ SSL3_RANDOM_SIZE + 1 /* session ID length */ +
+ 2 /* cipher list length */ +
+ CBS_len(&cipher_specs) / 3 * 2 +
+ 1 /* compression length */ + 1 /* compression */;
+ CBB client_hello, hello_body, cipher_suites;
+ CBB_zero(&client_hello);
+ if (!BUF_MEM_reserve(ssl->init_buf, max_v3_client_hello) ||
+ !CBB_init_fixed(&client_hello, (uint8_t *)ssl->init_buf->data,
+ ssl->init_buf->max) ||
+ !CBB_add_u8(&client_hello, SSL3_MT_CLIENT_HELLO) ||
+ !CBB_add_u24_length_prefixed(&client_hello, &hello_body) ||
+ !CBB_add_u16(&hello_body, version) ||
+ !CBB_add_bytes(&hello_body, random, SSL3_RANDOM_SIZE) ||
+ /* No session id. */
+ !CBB_add_u8(&hello_body, 0) ||
+ !CBB_add_u16_length_prefixed(&hello_body, &cipher_suites)) {
+ CBB_cleanup(&client_hello);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ return -1;
+ }
+
+ /* Copy the cipher suites. */
+ while (CBS_len(&cipher_specs) > 0) {
+ uint32_t cipher_spec;
+ if (!CBS_get_u24(&cipher_specs, &cipher_spec)) {
+ CBB_cleanup(&client_hello);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ return -1;
+ }
+
+ /* Skip SSLv2 ciphers. */
+ if ((cipher_spec & 0xff0000) != 0) {
+ continue;
+ }
+ if (!CBB_add_u16(&cipher_suites, cipher_spec)) {
+ CBB_cleanup(&client_hello);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
+ }
+
+ /* Add the null compression scheme and finish. */
+ if (!CBB_add_u8(&hello_body, 1) || !CBB_add_u8(&hello_body, 0) ||
+ !CBB_finish(&client_hello, NULL, &ssl->init_buf->length)) {
+ CBB_cleanup(&client_hello);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
+
+ /* Consume and discard the V2ClientHello. */
+ ssl_read_buffer_consume(ssl, 2 + msg_length);
+ ssl_read_buffer_discard(ssl);
+
+ ssl->s3->is_v2_hello = 1;
+ /* This is the first message, so hs must be non-NULL. */
+ ssl->s3->hs->v2_clienthello = 1;
+ return 1;
+}
+
+int ssl3_get_message(SSL *ssl) {
+ /* Re-create the handshake buffer if needed. */
+ if (ssl->init_buf == NULL) {
+ ssl->init_buf = BUF_MEM_new();
+ if (ssl->init_buf == NULL) {
+ return -1;
+ }
+ }
+
+ if (ssl->server && !ssl->s3->v2_hello_done) {
+ /* Bypass the record layer for the first message to handle V2ClientHello. */
+ int ret = read_v2_client_hello(ssl);
+ if (ret <= 0) {
+ return ret;
+ }
+ ssl->s3->v2_hello_done = 1;
+ }
+
+ if (ssl->s3->tmp.reuse_message) {
+ /* There must be a current message. */
+ assert(ssl->init_msg != NULL);
+ ssl->s3->tmp.reuse_message = 0;
+ } else {
+ ssl3_release_current_message(ssl, 0 /* don't free buffer */);
+ }
+
+ /* Read the message header, if we haven't yet. */
+ int ret = extend_handshake_buffer(ssl, SSL3_HM_HEADER_LENGTH);
+ if (ret <= 0) {
+ return ret;
+ }
+
+ /* Parse out the length. Cap it so the peer cannot force us to buffer up to
+ * 2^24 bytes. */
+ const uint8_t *p = (uint8_t *)ssl->init_buf->data;
+ size_t msg_len = (((uint32_t)p[1]) << 16) | (((uint32_t)p[2]) << 8) | p[3];
+ if (msg_len > ssl_max_handshake_message_len(ssl)) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_EXCESSIVE_MESSAGE_SIZE);
+ return -1;
+ }
+
+ /* Read the message body, if we haven't yet. */
+ ret = extend_handshake_buffer(ssl, SSL3_HM_HEADER_LENGTH + msg_len);
+ if (ret <= 0) {
+ return ret;
+ }
+
+ /* 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);
+
+ 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;
+ ssl->init_num = ssl->init_buf->length - SSL3_HM_HEADER_LENGTH;
+ return 1;
+}
+
+void ssl3_get_current_message(const SSL *ssl, CBS *out) {
+ CBS_init(out, (uint8_t *)ssl->init_buf->data, ssl->init_buf->length);
+}
+
+int ssl_hash_current_message(SSL_HANDSHAKE *hs) {
+ /* V2ClientHellos are hashed implicitly. */
+ if (hs->ssl->s3->is_v2_hello) {
+ return 1;
+ }
+
+ CBS cbs;
+ hs->ssl->method->get_current_message(hs->ssl, &cbs);
+ return SSL_TRANSCRIPT_update(&hs->transcript, CBS_data(&cbs), CBS_len(&cbs));
+}
+
+void ssl3_release_current_message(SSL *ssl, int free_buffer) {
+ if (ssl->init_msg != NULL) {
+ /* |init_buf| never contains data beyond the current message. */
+ assert(SSL3_HM_HEADER_LENGTH + ssl->init_num == ssl->init_buf->length);
+
+ /* Clear the current message. */
+ ssl->init_msg = NULL;
+ ssl->init_num = 0;
+ ssl->init_buf->length = 0;
+ ssl->s3->is_v2_hello = 0;
+ }
+
+ if (free_buffer) {
+ BUF_MEM_free(ssl->init_buf);
+ ssl->init_buf = NULL;
+ }
+}
+
+int ssl_parse_extensions(const CBS *cbs, uint8_t *out_alert,
+ const SSL_EXTENSION_TYPE *ext_types,
+ size_t num_ext_types, int ignore_unknown) {
+ /* Reset everything. */
+ for (size_t i = 0; i < num_ext_types; i++) {
+ *ext_types[i].out_present = 0;
+ CBS_init(ext_types[i].out_data, NULL, 0);
+ }
+
+ CBS copy = *cbs;
+ while (CBS_len(&copy) != 0) {
+ uint16_t type;
+ CBS data;
+ if (!CBS_get_u16(&copy, &type) ||
+ !CBS_get_u16_length_prefixed(&copy, &data)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT);
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ const SSL_EXTENSION_TYPE *ext_type = NULL;
+ for (size_t i = 0; i < num_ext_types; i++) {
+ if (type == ext_types[i].type) {
+ ext_type = &ext_types[i];
+ break;
+ }
+ }
+
+ if (ext_type == NULL) {
+ if (ignore_unknown) {
+ continue;
+ }
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
+ *out_alert = SSL_AD_UNSUPPORTED_EXTENSION;
+ return 0;
+ }
+
+ /* Duplicate ext_types are forbidden. */
+ if (*ext_type->out_present) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DUPLICATE_EXTENSION);
+ *out_alert = SSL_AD_ILLEGAL_PARAMETER;
+ return 0;
+ }
+
+ *ext_type->out_present = 1;
+ *ext_type->out_data = data;
+ }
+
+ return 1;
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/s3_lib.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/s3_lib.c
new file mode 100644
index 000000000..57a27c707
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/s3_lib.c
@@ -0,0 +1,220 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2007 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ *
+ * Portions of the attached software ("Contribution") are developed by
+ * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
+ *
+ * The Contribution is licensed pursuant to the OpenSSL open source
+ * license provided above.
+ *
+ * ECC cipher suite support in OpenSSL originally written by
+ * Vipul Gupta and Sumit Gupta of Sun Microsystems Laboratories.
+ *
+ */
+/* ====================================================================
+ * Copyright 2005 Nokia. All rights reserved.
+ *
+ * The portions of the attached software ("Contribution") is developed by
+ * Nokia Corporation and is licensed pursuant to the OpenSSL open source
+ * license.
+ *
+ * The Contribution, originally written by Mika Kousa and Pasi Eronen of
+ * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites
+ * support (see RFC 4279) to OpenSSL.
+ *
+ * No patent licenses or other rights except those expressly stated in
+ * the OpenSSL open source license shall be deemed granted or received
+ * expressly, by implication, estoppel, or otherwise.
+ *
+ * No assurances are provided by Nokia that the Contribution does not
+ * infringe the patent or other intellectual property rights of any third
+ * party or that the license provides you with all the necessary rights
+ * to make use of the Contribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN
+ * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA
+ * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY
+ * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
+ * OTHERWISE. */
+
+#include <openssl/ssl.h>
+
+#include <assert.h>
+#include <string.h>
+
+#include <openssl/buf.h>
+#include <openssl/dh.h>
+#include <openssl/digest.h>
+#include <openssl/err.h>
+#include <openssl/md5.h>
+#include <openssl/mem.h>
+#include <openssl/nid.h>
+
+#include "../crypto/internal.h"
+#include "internal.h"
+
+
+int ssl3_new(SSL *ssl) {
+ SSL3_STATE *s3;
+
+ s3 = OPENSSL_malloc(sizeof *s3);
+ if (s3 == NULL) {
+ return 0;
+ }
+ OPENSSL_memset(s3, 0, sizeof *s3);
+
+ s3->hs = ssl_handshake_new(ssl);
+ if (s3->hs == NULL) {
+ OPENSSL_free(s3);
+ return 0;
+ }
+
+ ssl->s3 = s3;
+
+ /* Set the version to the highest supported version.
+ *
+ * TODO(davidben): Move this field into |s3|, have it store the normalized
+ * protocol version, and implement this pre-negotiation quirk in |SSL_version|
+ * at the API boundary rather than in internal state. */
+ ssl->version = TLS1_2_VERSION;
+ return 1;
+}
+
+void ssl3_free(SSL *ssl) {
+ if (ssl == NULL || ssl->s3 == NULL) {
+ return;
+ }
+
+ ssl_read_buffer_clear(ssl);
+ ssl_write_buffer_clear(ssl);
+
+ SSL_SESSION_free(ssl->s3->established_session);
+ ssl_handshake_free(ssl->s3->hs);
+ OPENSSL_free(ssl->s3->next_proto_negotiated);
+ OPENSSL_free(ssl->s3->alpn_selected);
+ SSL_AEAD_CTX_free(ssl->s3->aead_read_ctx);
+ SSL_AEAD_CTX_free(ssl->s3->aead_write_ctx);
+ BUF_MEM_free(ssl->s3->pending_flight);
+
+ OPENSSL_cleanse(ssl->s3, sizeof *ssl->s3);
+ OPENSSL_free(ssl->s3);
+ ssl->s3 = NULL;
+}
+
+const struct ssl_cipher_preference_list_st *ssl_get_cipher_preferences(
+ const SSL *ssl) {
+ if (ssl->cipher_list != NULL) {
+ return ssl->cipher_list;
+ }
+
+ return ssl->ctx->cipher_list;
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/s3_pkt.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/s3_pkt.c
new file mode 100644
index 000000000..2f919caed
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/s3_pkt.c
@@ -0,0 +1,489 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com). */
+
+#include <openssl/ssl.h>
+
+#include <assert.h>
+#include <limits.h>
+#include <string.h>
+
+#include <openssl/buf.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/mem.h>
+#include <openssl/rand.h>
+
+#include "../crypto/internal.h"
+#include "internal.h"
+
+
+static int do_ssl3_write(SSL *ssl, int type, const uint8_t *buf, unsigned len);
+
+/* ssl3_get_record reads a new input record. On success, it places it in
+ * |ssl->s3->rrec| and returns one. Otherwise it returns <= 0 on error or if
+ * more data is needed. */
+static int ssl3_get_record(SSL *ssl) {
+again:
+ switch (ssl->s3->recv_shutdown) {
+ case ssl_shutdown_none:
+ break;
+ case ssl_shutdown_fatal_alert:
+ OPENSSL_PUT_ERROR(SSL, SSL_R_PROTOCOL_IS_SHUTDOWN);
+ return -1;
+ case ssl_shutdown_close_notify:
+ return 0;
+ }
+
+ CBS body;
+ uint8_t type, alert = SSL_AD_DECODE_ERROR;
+ size_t consumed;
+ enum ssl_open_record_t open_ret =
+ tls_open_record(ssl, &type, &body, &consumed, &alert,
+ ssl_read_buffer(ssl), ssl_read_buffer_len(ssl));
+ if (open_ret != ssl_open_record_partial) {
+ ssl_read_buffer_consume(ssl, consumed);
+ }
+ switch (open_ret) {
+ case ssl_open_record_partial: {
+ int read_ret = ssl_read_buffer_extend_to(ssl, consumed);
+ if (read_ret <= 0) {
+ return read_ret;
+ }
+ goto again;
+ }
+
+ case ssl_open_record_success:
+ if (CBS_len(&body) > 0xffff) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
+ return -1;
+ }
+
+ SSL3_RECORD *rr = &ssl->s3->rrec;
+ rr->type = type;
+ rr->length = (uint16_t)CBS_len(&body);
+ rr->data = (uint8_t *)CBS_data(&body);
+ return 1;
+
+ case ssl_open_record_discard:
+ goto again;
+
+ case ssl_open_record_close_notify:
+ return 0;
+
+ case ssl_open_record_fatal_alert:
+ return -1;
+
+ case ssl_open_record_error:
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
+ return -1;
+ }
+
+ assert(0);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return -1;
+}
+
+int ssl3_write_app_data(SSL *ssl, const uint8_t *buf, int len) {
+ assert(!SSL_in_init(ssl) || SSL_in_false_start(ssl));
+
+ unsigned tot, n, nw;
+
+ assert(ssl->s3->wnum <= INT_MAX);
+ tot = ssl->s3->wnum;
+ ssl->s3->wnum = 0;
+
+ /* Ensure that if we end up with a smaller value of data to write out than
+ * the the original len from a write which didn't complete for non-blocking
+ * I/O and also somehow ended up avoiding the check for this in
+ * ssl3_write_pending/SSL_R_BAD_WRITE_RETRY as it must never be possible to
+ * end up with (len-tot) as a large number that will then promptly send
+ * beyond the end of the users buffer ... so we trap and report the error in
+ * a way the user will notice. */
+ if (len < 0 || (size_t)len < tot) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_LENGTH);
+ return -1;
+ }
+
+ n = len - tot;
+ for (;;) {
+ /* max contains the maximum number of bytes that we can put into a
+ * record. */
+ unsigned max = ssl->max_send_fragment;
+ if (n > max) {
+ nw = max;
+ } else {
+ nw = n;
+ }
+
+ int ret = do_ssl3_write(ssl, SSL3_RT_APPLICATION_DATA, &buf[tot], nw);
+ if (ret <= 0) {
+ ssl->s3->wnum = tot;
+ return ret;
+ }
+
+ if (ret == (int)n || (ssl->mode & SSL_MODE_ENABLE_PARTIAL_WRITE)) {
+ return tot + ret;
+ }
+
+ n -= ret;
+ tot += ret;
+ }
+}
+
+static int ssl3_write_pending(SSL *ssl, int type, const uint8_t *buf,
+ unsigned int len) {
+ if (ssl->s3->wpend_tot > (int)len ||
+ (!(ssl->mode & SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER) &&
+ ssl->s3->wpend_buf != buf) ||
+ ssl->s3->wpend_type != type) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_WRITE_RETRY);
+ return -1;
+ }
+
+ int ret = ssl_write_buffer_flush(ssl);
+ if (ret <= 0) {
+ return ret;
+ }
+ return ssl->s3->wpend_ret;
+}
+
+/* do_ssl3_write writes an SSL record of the given type. */
+static int do_ssl3_write(SSL *ssl, int type, const uint8_t *buf, unsigned len) {
+ /* If there is still data from the previous record, flush it. */
+ if (ssl_write_buffer_is_pending(ssl)) {
+ return ssl3_write_pending(ssl, type, buf, len);
+ }
+
+ /* The handshake flight buffer is mutually exclusive with application data.
+ *
+ * TODO(davidben): This will not be true when closure alerts use this. */
+ if (ssl->s3->pending_flight != NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
+
+ if (len > SSL3_RT_MAX_PLAIN_LENGTH) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
+
+ if (len == 0) {
+ return 0;
+ }
+
+ size_t max_out = len + SSL_max_seal_overhead(ssl);
+ if (max_out < len) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
+ return -1;
+ }
+ uint8_t *out;
+ size_t ciphertext_len;
+ if (!ssl_write_buffer_init(ssl, &out, max_out) ||
+ !tls_seal_record(ssl, out, &ciphertext_len, max_out, type, buf, len)) {
+ return -1;
+ }
+ ssl_write_buffer_set_len(ssl, ciphertext_len);
+
+ /* memorize arguments so that ssl3_write_pending can detect bad write retries
+ * later */
+ ssl->s3->wpend_tot = len;
+ ssl->s3->wpend_buf = buf;
+ ssl->s3->wpend_type = type;
+ ssl->s3->wpend_ret = len;
+
+ /* we now just need to write the buffer */
+ return ssl3_write_pending(ssl, type, buf, len);
+}
+
+static int consume_record(SSL *ssl, uint8_t *out, int len, int peek) {
+ SSL3_RECORD *rr = &ssl->s3->rrec;
+
+ if (len <= 0) {
+ return len;
+ }
+
+ if (len > (int)rr->length) {
+ len = (int)rr->length;
+ }
+
+ OPENSSL_memcpy(out, rr->data, len);
+ if (!peek) {
+ rr->length -= len;
+ rr->data += len;
+ if (rr->length == 0) {
+ /* The record has been consumed, so we may now clear the buffer. */
+ ssl_read_buffer_discard(ssl);
+ }
+ }
+ return len;
+}
+
+int ssl3_read_app_data(SSL *ssl, int *out_got_handshake, uint8_t *buf, int len,
+ int peek) {
+ assert(!SSL_in_init(ssl));
+ assert(ssl->s3->initial_handshake_complete);
+ *out_got_handshake = 0;
+
+ SSL3_RECORD *rr = &ssl->s3->rrec;
+
+ for (;;) {
+ /* A previous iteration may have read a partial handshake message. Do not
+ * allow more app data in that case. */
+ int has_hs_data = ssl->init_buf != NULL && ssl->init_buf->length > 0;
+
+ /* Get new packet if necessary. */
+ if (rr->length == 0 && !has_hs_data) {
+ int ret = ssl3_get_record(ssl);
+ if (ret <= 0) {
+ return ret;
+ }
+ }
+
+ if (has_hs_data || rr->type == SSL3_RT_HANDSHAKE) {
+ /* Post-handshake data prior to TLS 1.3 is always renegotiation, which we
+ * never accept as a server. Otherwise |ssl3_get_message| will send
+ * |SSL_R_EXCESSIVE_MESSAGE_SIZE|. */
+ if (ssl->server && ssl3_protocol_version(ssl) < TLS1_3_VERSION) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_NO_RENEGOTIATION);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_RENEGOTIATION);
+ return -1;
+ }
+
+ /* Parse post-handshake handshake messages. */
+ int ret = ssl3_get_message(ssl);
+ if (ret <= 0) {
+ return ret;
+ }
+ *out_got_handshake = 1;
+ return -1;
+ }
+
+ if (rr->type != SSL3_RT_APPLICATION_DATA) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ if (rr->length != 0) {
+ return consume_record(ssl, buf, len, peek);
+ }
+
+ /* Discard empty records and loop again. */
+ }
+}
+
+int ssl3_read_change_cipher_spec(SSL *ssl) {
+ SSL3_RECORD *rr = &ssl->s3->rrec;
+
+ if (rr->length == 0) {
+ int ret = ssl3_get_record(ssl);
+ if (ret <= 0) {
+ return ret;
+ }
+ }
+
+ 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 ssl3_read_close_notify(SSL *ssl) {
+ /* Read records until an error or close_notify. */
+ while (ssl3_get_record(ssl) > 0) {
+ ;
+ }
+}
+
+int ssl3_read_handshake_bytes(SSL *ssl, uint8_t *buf, int len) {
+ SSL3_RECORD *rr = &ssl->s3->rrec;
+
+ for (;;) {
+ /* Get new packet if necessary. */
+ if (rr->length == 0) {
+ int ret = ssl3_get_record(ssl);
+ if (ret <= 0) {
+ return ret;
+ }
+ }
+
+ if (rr->type != SSL3_RT_HANDSHAKE) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ if (rr->length != 0) {
+ return consume_record(ssl, buf, len, 0 /* consume data */);
+ }
+
+ /* Discard empty records and loop again. */
+ }
+}
+
+int ssl3_send_alert(SSL *ssl, int level, int desc) {
+ /* It is illegal to send an alert when we've already sent a closing one. */
+ if (ssl->s3->send_shutdown != ssl_shutdown_none) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_PROTOCOL_IS_SHUTDOWN);
+ return -1;
+ }
+
+ if (level == SSL3_AL_WARNING && desc == SSL_AD_CLOSE_NOTIFY) {
+ ssl->s3->send_shutdown = ssl_shutdown_close_notify;
+ } else {
+ assert(level == SSL3_AL_FATAL);
+ ssl->s3->send_shutdown = ssl_shutdown_fatal_alert;
+ }
+
+ ssl->s3->alert_dispatch = 1;
+ ssl->s3->send_alert[0] = level;
+ ssl->s3->send_alert[1] = desc;
+ if (!ssl_write_buffer_is_pending(ssl)) {
+ /* Nothing is being written out, so the alert may be dispatched
+ * immediately. */
+ return ssl->method->dispatch_alert(ssl);
+ }
+
+ /* The alert will be dispatched later. */
+ return -1;
+}
+
+int ssl3_dispatch_alert(SSL *ssl) {
+ int ret = do_ssl3_write(ssl, SSL3_RT_ALERT, &ssl->s3->send_alert[0], 2);
+ if (ret <= 0) {
+ return ret;
+ }
+ ssl->s3->alert_dispatch = 0;
+
+ /* If the alert is fatal, flush the BIO now. */
+ if (ssl->s3->send_alert[0] == SSL3_AL_FATAL) {
+ BIO_flush(ssl->wbio);
+ }
+
+ ssl_do_msg_callback(ssl, 1 /* write */, SSL3_RT_ALERT, ssl->s3->send_alert,
+ 2);
+
+ int alert = (ssl->s3->send_alert[0] << 8) | ssl->s3->send_alert[1];
+ ssl_do_info_callback(ssl, SSL_CB_WRITE_ALERT, alert);
+
+ return 1;
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_aead_ctx.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_aead_ctx.c
new file mode 100644
index 000000000..1af4a5ab1
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_aead_ctx.c
@@ -0,0 +1,336 @@
+/* Copyright (c) 2015, 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 <openssl/ssl.h>
+
+#include <assert.h>
+#include <string.h>
+
+#include <openssl/aead.h>
+#include <openssl/err.h>
+#include <openssl/rand.h>
+#include <openssl/type_check.h>
+
+#include "../crypto/internal.h"
+#include "internal.h"
+
+
+SSL_AEAD_CTX *SSL_AEAD_CTX_new(enum evp_aead_direction_t direction,
+ uint16_t version, const SSL_CIPHER *cipher,
+ const uint8_t *enc_key, size_t enc_key_len,
+ const uint8_t *mac_key, size_t mac_key_len,
+ const uint8_t *fixed_iv, size_t fixed_iv_len) {
+ const EVP_AEAD *aead;
+ size_t expected_mac_key_len, expected_fixed_iv_len;
+ if (!ssl_cipher_get_evp_aead(&aead, &expected_mac_key_len,
+ &expected_fixed_iv_len, cipher, version) ||
+ /* Ensure the caller returned correct key sizes. */
+ expected_fixed_iv_len != fixed_iv_len ||
+ expected_mac_key_len != mac_key_len) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ uint8_t merged_key[EVP_AEAD_MAX_KEY_LENGTH];
+ if (mac_key_len > 0) {
+ /* This is a "stateful" AEAD (for compatibility with pre-AEAD cipher
+ * suites). */
+ if (mac_key_len + enc_key_len + fixed_iv_len > sizeof(merged_key)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+ OPENSSL_memcpy(merged_key, mac_key, mac_key_len);
+ OPENSSL_memcpy(merged_key + mac_key_len, enc_key, enc_key_len);
+ OPENSSL_memcpy(merged_key + mac_key_len + enc_key_len, fixed_iv,
+ fixed_iv_len);
+ enc_key = merged_key;
+ enc_key_len += mac_key_len;
+ enc_key_len += fixed_iv_len;
+ }
+
+ SSL_AEAD_CTX *aead_ctx = OPENSSL_malloc(sizeof(SSL_AEAD_CTX));
+ if (aead_ctx == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ OPENSSL_memset(aead_ctx, 0, sizeof(SSL_AEAD_CTX));
+ aead_ctx->cipher = cipher;
+ aead_ctx->version = version;
+
+ if (!EVP_AEAD_CTX_init_with_direction(
+ &aead_ctx->ctx, aead, enc_key, enc_key_len,
+ EVP_AEAD_DEFAULT_TAG_LENGTH, direction)) {
+ OPENSSL_free(aead_ctx);
+ return NULL;
+ }
+
+ assert(EVP_AEAD_nonce_length(aead) <= EVP_AEAD_MAX_NONCE_LENGTH);
+ OPENSSL_COMPILE_ASSERT(EVP_AEAD_MAX_NONCE_LENGTH < 256,
+ variable_nonce_len_doesnt_fit_in_uint8_t);
+ aead_ctx->variable_nonce_len = (uint8_t)EVP_AEAD_nonce_length(aead);
+ if (mac_key_len == 0) {
+ assert(fixed_iv_len <= sizeof(aead_ctx->fixed_nonce));
+ OPENSSL_memcpy(aead_ctx->fixed_nonce, fixed_iv, fixed_iv_len);
+ aead_ctx->fixed_nonce_len = fixed_iv_len;
+
+ if (cipher->algorithm_enc & SSL_CHACHA20POLY1305) {
+ /* The fixed nonce into the actual nonce (the sequence number). */
+ aead_ctx->xor_fixed_nonce = 1;
+ aead_ctx->variable_nonce_len = 8;
+ } else {
+ /* The fixed IV is prepended to the nonce. */
+ assert(fixed_iv_len <= aead_ctx->variable_nonce_len);
+ aead_ctx->variable_nonce_len -= fixed_iv_len;
+ }
+
+ /* AES-GCM uses an explicit nonce. */
+ if (cipher->algorithm_enc & (SSL_AES128GCM | SSL_AES256GCM)) {
+ aead_ctx->variable_nonce_included_in_record = 1;
+ }
+
+ /* The TLS 1.3 construction XORs the fixed nonce into the sequence number
+ * and omits the additional data. */
+ if (version >= TLS1_3_VERSION) {
+ aead_ctx->xor_fixed_nonce = 1;
+ aead_ctx->variable_nonce_len = 8;
+ aead_ctx->variable_nonce_included_in_record = 0;
+ aead_ctx->omit_ad = 1;
+ assert(fixed_iv_len >= aead_ctx->variable_nonce_len);
+ }
+ } else {
+ assert(version < TLS1_3_VERSION);
+ aead_ctx->variable_nonce_included_in_record = 1;
+ aead_ctx->random_variable_nonce = 1;
+ aead_ctx->omit_length_in_ad = 1;
+ aead_ctx->omit_version_in_ad = (version == SSL3_VERSION);
+ }
+
+ return aead_ctx;
+}
+
+void SSL_AEAD_CTX_free(SSL_AEAD_CTX *aead) {
+ if (aead == NULL) {
+ return;
+ }
+ EVP_AEAD_CTX_cleanup(&aead->ctx);
+ OPENSSL_free(aead);
+}
+
+size_t SSL_AEAD_CTX_explicit_nonce_len(const SSL_AEAD_CTX *aead) {
+#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+ aead = NULL;
+#endif
+
+ if (aead != NULL && aead->variable_nonce_included_in_record) {
+ return aead->variable_nonce_len;
+ }
+ return 0;
+}
+
+size_t SSL_AEAD_CTX_max_overhead(const SSL_AEAD_CTX *aead) {
+#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+ aead = NULL;
+#endif
+
+ if (aead == NULL) {
+ return 0;
+ }
+ return EVP_AEAD_max_overhead(aead->ctx.aead) +
+ SSL_AEAD_CTX_explicit_nonce_len(aead);
+}
+
+/* ssl_aead_ctx_get_ad writes the additional data for |aead| into |out| and
+ * returns the number of bytes written. */
+static size_t ssl_aead_ctx_get_ad(SSL_AEAD_CTX *aead, uint8_t out[13],
+ uint8_t type, uint16_t wire_version,
+ const uint8_t seqnum[8],
+ size_t plaintext_len) {
+ if (aead->omit_ad) {
+ return 0;
+ }
+
+ OPENSSL_memcpy(out, seqnum, 8);
+ size_t len = 8;
+ out[len++] = type;
+ if (!aead->omit_version_in_ad) {
+ out[len++] = (uint8_t)(wire_version >> 8);
+ out[len++] = (uint8_t)wire_version;
+ }
+ if (!aead->omit_length_in_ad) {
+ out[len++] = (uint8_t)(plaintext_len >> 8);
+ out[len++] = (uint8_t)plaintext_len;
+ }
+ return len;
+}
+
+int SSL_AEAD_CTX_open(SSL_AEAD_CTX *aead, CBS *out, uint8_t type,
+ uint16_t wire_version, const uint8_t seqnum[8],
+ uint8_t *in, size_t in_len) {
+#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+ aead = NULL;
+#endif
+
+ if (aead == NULL) {
+ /* Handle the initial NULL cipher. */
+ CBS_init(out, in, in_len);
+ return 1;
+ }
+
+ /* TLS 1.2 AEADs include the length in the AD and are assumed to have fixed
+ * overhead. Otherwise the parameter is unused. */
+ size_t plaintext_len = 0;
+ if (!aead->omit_length_in_ad) {
+ size_t overhead = SSL_AEAD_CTX_max_overhead(aead);
+ if (in_len < overhead) {
+ /* Publicly invalid. */
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_PACKET_LENGTH);
+ return 0;
+ }
+ plaintext_len = in_len - overhead;
+ }
+ uint8_t ad[13];
+ size_t ad_len = ssl_aead_ctx_get_ad(aead, ad, type, wire_version, seqnum,
+ plaintext_len);
+
+ /* Assemble the nonce. */
+ uint8_t nonce[EVP_AEAD_MAX_NONCE_LENGTH];
+ size_t nonce_len = 0;
+
+ /* Prepend the fixed nonce, or left-pad with zeros if XORing. */
+ if (aead->xor_fixed_nonce) {
+ nonce_len = aead->fixed_nonce_len - aead->variable_nonce_len;
+ OPENSSL_memset(nonce, 0, nonce_len);
+ } else {
+ OPENSSL_memcpy(nonce, aead->fixed_nonce, aead->fixed_nonce_len);
+ nonce_len += aead->fixed_nonce_len;
+ }
+
+ /* Add the variable nonce. */
+ if (aead->variable_nonce_included_in_record) {
+ if (in_len < aead->variable_nonce_len) {
+ /* Publicly invalid. */
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_PACKET_LENGTH);
+ return 0;
+ }
+ OPENSSL_memcpy(nonce + nonce_len, in, aead->variable_nonce_len);
+ in += aead->variable_nonce_len;
+ in_len -= aead->variable_nonce_len;
+ } else {
+ assert(aead->variable_nonce_len == 8);
+ OPENSSL_memcpy(nonce + nonce_len, seqnum, aead->variable_nonce_len);
+ }
+ nonce_len += aead->variable_nonce_len;
+
+ /* XOR the fixed nonce, if necessary. */
+ if (aead->xor_fixed_nonce) {
+ assert(nonce_len == aead->fixed_nonce_len);
+ for (size_t i = 0; i < aead->fixed_nonce_len; i++) {
+ nonce[i] ^= aead->fixed_nonce[i];
+ }
+ }
+
+ /* Decrypt in-place. */
+ size_t len;
+ if (!EVP_AEAD_CTX_open(&aead->ctx, in, &len, in_len, nonce, nonce_len,
+ in, in_len, ad, ad_len)) {
+ return 0;
+ }
+ CBS_init(out, in, len);
+ return 1;
+}
+
+int SSL_AEAD_CTX_seal(SSL_AEAD_CTX *aead, uint8_t *out, size_t *out_len,
+ size_t max_out, uint8_t type, uint16_t wire_version,
+ const uint8_t seqnum[8], const uint8_t *in,
+ size_t in_len) {
+#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+ aead = NULL;
+#endif
+
+ if (aead == NULL) {
+ /* Handle the initial NULL cipher. */
+ if (in_len > max_out) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL);
+ return 0;
+ }
+ OPENSSL_memmove(out, in, in_len);
+ *out_len = in_len;
+ return 1;
+ }
+
+ uint8_t ad[13];
+ size_t ad_len = ssl_aead_ctx_get_ad(aead, ad, type, wire_version, seqnum,
+ in_len);
+
+ /* Assemble the nonce. */
+ uint8_t nonce[EVP_AEAD_MAX_NONCE_LENGTH];
+ size_t nonce_len = 0;
+
+ /* Prepend the fixed nonce, or left-pad with zeros if XORing. */
+ if (aead->xor_fixed_nonce) {
+ nonce_len = aead->fixed_nonce_len - aead->variable_nonce_len;
+ OPENSSL_memset(nonce, 0, nonce_len);
+ } else {
+ OPENSSL_memcpy(nonce, aead->fixed_nonce, aead->fixed_nonce_len);
+ nonce_len += aead->fixed_nonce_len;
+ }
+
+ /* Select the variable nonce. */
+ if (aead->random_variable_nonce) {
+ assert(aead->variable_nonce_included_in_record);
+ if (!RAND_bytes(nonce + nonce_len, aead->variable_nonce_len)) {
+ return 0;
+ }
+ } else {
+ /* When sending we use the sequence number as the variable part of the
+ * nonce. */
+ assert(aead->variable_nonce_len == 8);
+ OPENSSL_memcpy(nonce + nonce_len, seqnum, aead->variable_nonce_len);
+ }
+ nonce_len += aead->variable_nonce_len;
+
+ /* Emit the variable nonce if included in the record. */
+ size_t extra_len = 0;
+ if (aead->variable_nonce_included_in_record) {
+ assert(!aead->xor_fixed_nonce);
+ if (max_out < aead->variable_nonce_len) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL);
+ return 0;
+ }
+ if (out < in + in_len && in < out + aead->variable_nonce_len) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_OUTPUT_ALIASES_INPUT);
+ return 0;
+ }
+ OPENSSL_memcpy(out, nonce + aead->fixed_nonce_len,
+ aead->variable_nonce_len);
+ extra_len = aead->variable_nonce_len;
+ out += aead->variable_nonce_len;
+ max_out -= aead->variable_nonce_len;
+ }
+
+ /* XOR the fixed nonce, if necessary. */
+ if (aead->xor_fixed_nonce) {
+ assert(nonce_len == aead->fixed_nonce_len);
+ for (size_t i = 0; i < aead->fixed_nonce_len; i++) {
+ nonce[i] ^= aead->fixed_nonce[i];
+ }
+ }
+
+ if (!EVP_AEAD_CTX_seal(&aead->ctx, out, out_len, max_out, nonce, nonce_len,
+ in, in_len, ad, ad_len)) {
+ return 0;
+ }
+ *out_len += extra_len;
+ return 1;
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_asn1.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_asn1.c
new file mode 100644
index 000000000..cfcc12a85
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_asn1.c
@@ -0,0 +1,824 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright 2005 Nokia. All rights reserved.
+ *
+ * The portions of the attached software ("Contribution") is developed by
+ * Nokia Corporation and is licensed pursuant to the OpenSSL open source
+ * license.
+ *
+ * The Contribution, originally written by Mika Kousa and Pasi Eronen of
+ * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites
+ * support (see RFC 4279) to OpenSSL.
+ *
+ * No patent licenses or other rights except those expressly stated in
+ * the OpenSSL open source license shall be deemed granted or received
+ * expressly, by implication, estoppel, or otherwise.
+ *
+ * No assurances are provided by Nokia that the Contribution does not
+ * infringe the patent or other intellectual property rights of any third
+ * party or that the license provides you with all the necessary rights
+ * to make use of the Contribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN
+ * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA
+ * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY
+ * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
+ * OTHERWISE. */
+
+#include <openssl/ssl.h>
+
+#include <limits.h>
+#include <string.h>
+
+#include <openssl/buf.h>
+#include <openssl/bytestring.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/x509.h>
+
+#include "../crypto/internal.h"
+#include "internal.h"
+
+
+/* An SSL_SESSION is serialized as the following ASN.1 structure:
+ *
+ * SSLSession ::= SEQUENCE {
+ * version INTEGER (1), -- session structure version
+ * sslVersion INTEGER, -- protocol version number
+ * cipher OCTET STRING, -- two bytes long
+ * sessionID OCTET STRING,
+ * masterKey OCTET STRING,
+ * time [1] INTEGER, -- seconds since UNIX epoch
+ * timeout [2] INTEGER, -- in seconds
+ * peer [3] Certificate OPTIONAL,
+ * sessionIDContext [4] OCTET STRING OPTIONAL,
+ * verifyResult [5] INTEGER OPTIONAL, -- one of X509_V_* codes
+ * hostName [6] OCTET STRING OPTIONAL,
+ * -- from server_name extension
+ * pskIdentity [8] OCTET STRING OPTIONAL,
+ * ticketLifetimeHint [9] INTEGER OPTIONAL, -- client-only
+ * ticket [10] OCTET STRING OPTIONAL, -- client-only
+ * peerSHA256 [13] OCTET STRING OPTIONAL,
+ * originalHandshakeHash [14] OCTET STRING OPTIONAL,
+ * signedCertTimestampList [15] OCTET STRING OPTIONAL,
+ * -- contents of SCT extension
+ * ocspResponse [16] OCTET STRING OPTIONAL,
+ * -- stapled OCSP response from the server
+ * extendedMasterSecret [17] BOOLEAN OPTIONAL,
+ * groupID [18] INTEGER OPTIONAL,
+ * -- For historical reasons, for legacy DHE or
+ * -- static RSA ciphers, this field contains
+ * -- another value to be discarded.
+ * certChain [19] SEQUENCE OF Certificate OPTIONAL,
+ * ticketAgeAdd [21] OCTET STRING OPTIONAL,
+ * isServer [22] BOOLEAN DEFAULT TRUE,
+ * peerSignatureAlgorithm [23] INTEGER OPTIONAL,
+ * ticketMaxEarlyData [24] INTEGER OPTIONAL,
+ * authTimeout [25] INTEGER OPTIONAL, -- defaults to timeout
+ * earlyALPN [26] OCTET STRING OPTIONAL,
+ * }
+ *
+ * Note: historically this serialization has included other optional
+ * fields. Their presence is currently treated as a parse error:
+ *
+ * keyArg [0] IMPLICIT OCTET STRING OPTIONAL,
+ * pskIdentityHint [7] OCTET STRING OPTIONAL,
+ * compressionMethod [11] OCTET STRING OPTIONAL,
+ * srpUsername [12] OCTET STRING OPTIONAL,
+ * ticketFlags [20] INTEGER OPTIONAL,
+ */
+
+static const unsigned kVersion = 1;
+
+static const int kTimeTag =
+ CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 1;
+static const int kTimeoutTag =
+ CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 2;
+static const int kPeerTag =
+ CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 3;
+static const int kSessionIDContextTag =
+ CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 4;
+static const int kVerifyResultTag =
+ CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 5;
+static const int kHostNameTag =
+ CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 6;
+static const int kPSKIdentityTag =
+ CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 8;
+static const int kTicketLifetimeHintTag =
+ CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 9;
+static const int kTicketTag =
+ CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 10;
+static const int kPeerSHA256Tag =
+ CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 13;
+static const int kOriginalHandshakeHashTag =
+ CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 14;
+static const int kSignedCertTimestampListTag =
+ CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 15;
+static const int kOCSPResponseTag =
+ CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 16;
+static const int kExtendedMasterSecretTag =
+ CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 17;
+static const int kGroupIDTag =
+ CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 18;
+static const int kCertChainTag =
+ CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 19;
+static const int kTicketAgeAddTag =
+ CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 21;
+static const int kIsServerTag =
+ CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 22;
+static const int kPeerSignatureAlgorithmTag =
+ CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 23;
+static const int kTicketMaxEarlyDataTag =
+ CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 24;
+static const int kAuthTimeoutTag =
+ CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 25;
+static const int kEarlyALPNTag =
+ CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 26;
+
+static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data,
+ size_t *out_len, int for_ticket) {
+ CBB cbb, session, child, child2;
+
+ if (in == NULL || in->cipher == NULL) {
+ return 0;
+ }
+
+ CBB_zero(&cbb);
+ if (!CBB_init(&cbb, 0) ||
+ !CBB_add_asn1(&cbb, &session, CBS_ASN1_SEQUENCE) ||
+ !CBB_add_asn1_uint64(&session, kVersion) ||
+ !CBB_add_asn1_uint64(&session, in->ssl_version) ||
+ !CBB_add_asn1(&session, &child, CBS_ASN1_OCTETSTRING) ||
+ !CBB_add_u16(&child, (uint16_t)(in->cipher->id & 0xffff)) ||
+ !CBB_add_asn1(&session, &child, CBS_ASN1_OCTETSTRING) ||
+ /* The session ID is irrelevant for a session ticket. */
+ !CBB_add_bytes(&child, in->session_id,
+ for_ticket ? 0 : in->session_id_length) ||
+ !CBB_add_asn1(&session, &child, CBS_ASN1_OCTETSTRING) ||
+ !CBB_add_bytes(&child, in->master_key, in->master_key_length) ||
+ !CBB_add_asn1(&session, &child, kTimeTag) ||
+ !CBB_add_asn1_uint64(&child, in->time) ||
+ !CBB_add_asn1(&session, &child, kTimeoutTag) ||
+ !CBB_add_asn1_uint64(&child, in->timeout)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ /* The peer certificate is only serialized if the SHA-256 isn't
+ * serialized instead. */
+ if (sk_CRYPTO_BUFFER_num(in->certs) > 0 && !in->peer_sha256_valid) {
+ const CRYPTO_BUFFER *buffer = sk_CRYPTO_BUFFER_value(in->certs, 0);
+ if (!CBB_add_asn1(&session, &child, kPeerTag) ||
+ !CBB_add_bytes(&child, CRYPTO_BUFFER_data(buffer),
+ CRYPTO_BUFFER_len(buffer))) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ }
+
+ /* Although it is OPTIONAL and usually empty, OpenSSL has
+ * historically always encoded the sid_ctx. */
+ if (!CBB_add_asn1(&session, &child, kSessionIDContextTag) ||
+ !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) ||
+ !CBB_add_bytes(&child2, in->sid_ctx, in->sid_ctx_length)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if (in->verify_result != X509_V_OK) {
+ if (!CBB_add_asn1(&session, &child, kVerifyResultTag) ||
+ !CBB_add_asn1_uint64(&child, in->verify_result)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ }
+
+ if (in->tlsext_hostname) {
+ if (!CBB_add_asn1(&session, &child, kHostNameTag) ||
+ !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) ||
+ !CBB_add_bytes(&child2, (const uint8_t *)in->tlsext_hostname,
+ strlen(in->tlsext_hostname))) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ }
+
+ if (in->psk_identity) {
+ if (!CBB_add_asn1(&session, &child, kPSKIdentityTag) ||
+ !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) ||
+ !CBB_add_bytes(&child2, (const uint8_t *)in->psk_identity,
+ strlen(in->psk_identity))) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ }
+
+ if (in->tlsext_tick_lifetime_hint > 0) {
+ if (!CBB_add_asn1(&session, &child, kTicketLifetimeHintTag) ||
+ !CBB_add_asn1_uint64(&child, in->tlsext_tick_lifetime_hint)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ }
+
+ if (in->tlsext_tick && !for_ticket) {
+ if (!CBB_add_asn1(&session, &child, kTicketTag) ||
+ !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) ||
+ !CBB_add_bytes(&child2, in->tlsext_tick, in->tlsext_ticklen)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ }
+
+ if (in->peer_sha256_valid) {
+ if (!CBB_add_asn1(&session, &child, kPeerSHA256Tag) ||
+ !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) ||
+ !CBB_add_bytes(&child2, in->peer_sha256, sizeof(in->peer_sha256))) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ }
+
+ if (in->original_handshake_hash_len > 0) {
+ if (!CBB_add_asn1(&session, &child, kOriginalHandshakeHashTag) ||
+ !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) ||
+ !CBB_add_bytes(&child2, in->original_handshake_hash,
+ in->original_handshake_hash_len)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ }
+
+ if (in->tlsext_signed_cert_timestamp_list_length > 0) {
+ if (!CBB_add_asn1(&session, &child, kSignedCertTimestampListTag) ||
+ !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) ||
+ !CBB_add_bytes(&child2, in->tlsext_signed_cert_timestamp_list,
+ in->tlsext_signed_cert_timestamp_list_length)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ }
+
+ if (in->ocsp_response_length > 0) {
+ if (!CBB_add_asn1(&session, &child, kOCSPResponseTag) ||
+ !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) ||
+ !CBB_add_bytes(&child2, in->ocsp_response, in->ocsp_response_length)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ }
+
+ if (in->extended_master_secret) {
+ if (!CBB_add_asn1(&session, &child, kExtendedMasterSecretTag) ||
+ !CBB_add_asn1(&child, &child2, CBS_ASN1_BOOLEAN) ||
+ !CBB_add_u8(&child2, 0xff)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ }
+
+ if (in->group_id > 0 &&
+ (!CBB_add_asn1(&session, &child, kGroupIDTag) ||
+ !CBB_add_asn1_uint64(&child, in->group_id))) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ /* The certificate chain is only serialized if the leaf's SHA-256 isn't
+ * serialized instead. */
+ if (in->certs != NULL &&
+ !in->peer_sha256_valid &&
+ sk_CRYPTO_BUFFER_num(in->certs) >= 2) {
+ if (!CBB_add_asn1(&session, &child, kCertChainTag)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ for (size_t i = 1; i < sk_CRYPTO_BUFFER_num(in->certs); i++) {
+ const CRYPTO_BUFFER *buffer = sk_CRYPTO_BUFFER_value(in->certs, i);
+ if (!CBB_add_bytes(&child, CRYPTO_BUFFER_data(buffer),
+ CRYPTO_BUFFER_len(buffer))) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ }
+ }
+
+ if (in->ticket_age_add_valid) {
+ if (!CBB_add_asn1(&session, &child, kTicketAgeAddTag) ||
+ !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) ||
+ !CBB_add_u32(&child2, in->ticket_age_add)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ }
+
+ if (!in->is_server) {
+ if (!CBB_add_asn1(&session, &child, kIsServerTag) ||
+ !CBB_add_asn1(&child, &child2, CBS_ASN1_BOOLEAN) ||
+ !CBB_add_u8(&child2, 0x00)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ }
+
+ if (in->peer_signature_algorithm != 0 &&
+ (!CBB_add_asn1(&session, &child, kPeerSignatureAlgorithmTag) ||
+ !CBB_add_asn1_uint64(&child, in->peer_signature_algorithm))) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if (in->ticket_max_early_data != 0 &&
+ (!CBB_add_asn1(&session, &child, kTicketMaxEarlyDataTag) ||
+ !CBB_add_asn1_uint64(&child, in->ticket_max_early_data))) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if (in->timeout != in->auth_timeout &&
+ (!CBB_add_asn1(&session, &child, kAuthTimeoutTag) ||
+ !CBB_add_asn1_uint64(&child, in->auth_timeout))) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if (in->early_alpn) {
+ if (!CBB_add_asn1(&session, &child, kEarlyALPNTag) ||
+ !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) ||
+ !CBB_add_bytes(&child2, (const uint8_t *)in->early_alpn,
+ in->early_alpn_len)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ }
+
+ if (!CBB_finish(&cbb, out_data, out_len)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ return 1;
+
+ err:
+ CBB_cleanup(&cbb);
+ return 0;
+}
+
+int SSL_SESSION_to_bytes(const SSL_SESSION *in, uint8_t **out_data,
+ size_t *out_len) {
+ if (in->not_resumable) {
+ /* If the caller has an unresumable session, e.g. if |SSL_get_session| were
+ * called on a TLS 1.3 or False Started connection, serialize with a
+ * placeholder value so it is not accidentally deserialized into a resumable
+ * one. */
+ static const char kNotResumableSession[] = "NOT RESUMABLE";
+
+ *out_len = strlen(kNotResumableSession);
+ *out_data = BUF_memdup(kNotResumableSession, *out_len);
+ if (*out_data == NULL) {
+ return 0;
+ }
+
+ return 1;
+ }
+
+ return SSL_SESSION_to_bytes_full(in, out_data, out_len, 0);
+}
+
+int SSL_SESSION_to_bytes_for_ticket(const SSL_SESSION *in, uint8_t **out_data,
+ size_t *out_len) {
+ return SSL_SESSION_to_bytes_full(in, out_data, out_len, 1);
+}
+
+int i2d_SSL_SESSION(SSL_SESSION *in, uint8_t **pp) {
+ uint8_t *out;
+ size_t len;
+
+ if (!SSL_SESSION_to_bytes(in, &out, &len)) {
+ return -1;
+ }
+
+ if (len > INT_MAX) {
+ OPENSSL_free(out);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
+ return -1;
+ }
+
+ if (pp) {
+ OPENSSL_memcpy(*pp, out, len);
+ *pp += len;
+ }
+ OPENSSL_free(out);
+
+ return len;
+}
+
+/* SSL_SESSION_parse_string gets an optional ASN.1 OCTET STRING
+ * explicitly tagged with |tag| from |cbs| and saves it in |*out|. On
+ * entry, if |*out| is not NULL, it frees the existing contents. If
+ * the element was not found, it sets |*out| to NULL. It returns one
+ * on success, whether or not the element was found, and zero on
+ * decode error. */
+static int SSL_SESSION_parse_string(CBS *cbs, char **out, unsigned tag) {
+ CBS value;
+ int present;
+ if (!CBS_get_optional_asn1_octet_string(cbs, &value, &present, tag)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
+ return 0;
+ }
+ if (present) {
+ if (CBS_contains_zero_byte(&value)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
+ return 0;
+ }
+ if (!CBS_strdup(&value, out)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ } else {
+ OPENSSL_free(*out);
+ *out = NULL;
+ }
+ return 1;
+}
+
+/* SSL_SESSION_parse_string gets an optional ASN.1 OCTET STRING
+ * explicitly tagged with |tag| from |cbs| and stows it in |*out_ptr|
+ * and |*out_len|. If |*out_ptr| is not NULL, it frees the existing
+ * contents. On entry, if the element was not found, it sets
+ * |*out_ptr| to NULL. It returns one on success, whether or not the
+ * element was found, and zero on decode error. */
+static int SSL_SESSION_parse_octet_string(CBS *cbs, uint8_t **out_ptr,
+ size_t *out_len, unsigned tag) {
+ CBS value;
+ if (!CBS_get_optional_asn1_octet_string(cbs, &value, NULL, tag)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
+ return 0;
+ }
+ if (!CBS_stow(&value, out_ptr, out_len)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ return 1;
+}
+
+/* SSL_SESSION_parse_bounded_octet_string parses an optional ASN.1 OCTET STRING
+ * explicitly tagged with |tag| of size at most |max_out|. */
+static int SSL_SESSION_parse_bounded_octet_string(
+ CBS *cbs, uint8_t *out, uint8_t *out_len, uint8_t max_out, unsigned tag) {
+ CBS value;
+ if (!CBS_get_optional_asn1_octet_string(cbs, &value, NULL, tag) ||
+ CBS_len(&value) > max_out) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
+ return 0;
+ }
+ OPENSSL_memcpy(out, CBS_data(&value), CBS_len(&value));
+ *out_len = (uint8_t)CBS_len(&value);
+ return 1;
+}
+
+static int SSL_SESSION_parse_long(CBS *cbs, long *out, unsigned tag,
+ long default_value) {
+ uint64_t value;
+ if (!CBS_get_optional_asn1_uint64(cbs, &value, tag,
+ (uint64_t)default_value) ||
+ value > LONG_MAX) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
+ return 0;
+ }
+ *out = (long)value;
+ return 1;
+}
+
+static int SSL_SESSION_parse_u32(CBS *cbs, uint32_t *out, unsigned tag,
+ uint32_t default_value) {
+ uint64_t value;
+ if (!CBS_get_optional_asn1_uint64(cbs, &value, tag,
+ (uint64_t)default_value) ||
+ value > 0xffffffff) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
+ return 0;
+ }
+ *out = (uint32_t)value;
+ return 1;
+}
+
+static int SSL_SESSION_parse_u16(CBS *cbs, uint16_t *out, unsigned tag,
+ uint16_t default_value) {
+ uint64_t value;
+ if (!CBS_get_optional_asn1_uint64(cbs, &value, tag,
+ (uint64_t)default_value) ||
+ value > 0xffff) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
+ return 0;
+ }
+ *out = (uint16_t)value;
+ return 1;
+}
+
+SSL_SESSION *SSL_SESSION_parse(CBS *cbs, const SSL_X509_METHOD *x509_method,
+ CRYPTO_BUFFER_POOL *pool) {
+ SSL_SESSION *ret = ssl_session_new(x509_method);
+ if (ret == NULL) {
+ goto err;
+ }
+
+ CBS session;
+ uint64_t version, ssl_version;
+ if (!CBS_get_asn1(cbs, &session, CBS_ASN1_SEQUENCE) ||
+ !CBS_get_asn1_uint64(&session, &version) ||
+ version != kVersion ||
+ !CBS_get_asn1_uint64(&session, &ssl_version)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
+ goto err;
+ }
+ ret->ssl_version = ssl_version;
+
+ CBS cipher;
+ uint16_t cipher_value;
+ if (!CBS_get_asn1(&session, &cipher, CBS_ASN1_OCTETSTRING) ||
+ !CBS_get_u16(&cipher, &cipher_value) ||
+ CBS_len(&cipher) != 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
+ goto err;
+ }
+ ret->cipher = SSL_get_cipher_by_value(cipher_value);
+ if (ret->cipher == NULL) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_CIPHER);
+ goto err;
+ }
+
+ CBS session_id, master_key;
+ if (!CBS_get_asn1(&session, &session_id, CBS_ASN1_OCTETSTRING) ||
+ CBS_len(&session_id) > SSL3_MAX_SSL_SESSION_ID_LENGTH ||
+ !CBS_get_asn1(&session, &master_key, CBS_ASN1_OCTETSTRING) ||
+ CBS_len(&master_key) > SSL_MAX_MASTER_KEY_LENGTH) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
+ goto err;
+ }
+ OPENSSL_memcpy(ret->session_id, CBS_data(&session_id), CBS_len(&session_id));
+ ret->session_id_length = CBS_len(&session_id);
+ OPENSSL_memcpy(ret->master_key, CBS_data(&master_key), CBS_len(&master_key));
+ ret->master_key_length = CBS_len(&master_key);
+
+ CBS child;
+ uint64_t timeout;
+ if (!CBS_get_asn1(&session, &child, kTimeTag) ||
+ !CBS_get_asn1_uint64(&child, &ret->time) ||
+ !CBS_get_asn1(&session, &child, kTimeoutTag) ||
+ !CBS_get_asn1_uint64(&child, &timeout) ||
+ timeout > UINT32_MAX) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
+ goto err;
+ }
+
+ ret->timeout = (uint32_t)timeout;
+
+ CBS peer;
+ int has_peer;
+ if (!CBS_get_optional_asn1(&session, &peer, &has_peer, kPeerTag) ||
+ (has_peer && CBS_len(&peer) == 0)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
+ goto err;
+ }
+ /* |peer| is processed with the certificate chain. */
+
+ if (!SSL_SESSION_parse_bounded_octet_string(
+ &session, ret->sid_ctx, &ret->sid_ctx_length, sizeof(ret->sid_ctx),
+ kSessionIDContextTag) ||
+ !SSL_SESSION_parse_long(&session, &ret->verify_result, kVerifyResultTag,
+ X509_V_OK) ||
+ !SSL_SESSION_parse_string(&session, &ret->tlsext_hostname,
+ kHostNameTag) ||
+ !SSL_SESSION_parse_string(&session, &ret->psk_identity,
+ kPSKIdentityTag) ||
+ !SSL_SESSION_parse_u32(&session, &ret->tlsext_tick_lifetime_hint,
+ kTicketLifetimeHintTag, 0) ||
+ !SSL_SESSION_parse_octet_string(&session, &ret->tlsext_tick,
+ &ret->tlsext_ticklen, kTicketTag)) {
+ goto err;
+ }
+
+ if (CBS_peek_asn1_tag(&session, kPeerSHA256Tag)) {
+ CBS peer_sha256;
+ if (!CBS_get_asn1(&session, &child, kPeerSHA256Tag) ||
+ !CBS_get_asn1(&child, &peer_sha256, CBS_ASN1_OCTETSTRING) ||
+ CBS_len(&peer_sha256) != sizeof(ret->peer_sha256) ||
+ CBS_len(&child) != 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
+ goto err;
+ }
+ OPENSSL_memcpy(ret->peer_sha256, CBS_data(&peer_sha256),
+ sizeof(ret->peer_sha256));
+ ret->peer_sha256_valid = 1;
+ } else {
+ ret->peer_sha256_valid = 0;
+ }
+
+ if (!SSL_SESSION_parse_bounded_octet_string(
+ &session, ret->original_handshake_hash,
+ &ret->original_handshake_hash_len,
+ sizeof(ret->original_handshake_hash), kOriginalHandshakeHashTag) ||
+ !SSL_SESSION_parse_octet_string(
+ &session, &ret->tlsext_signed_cert_timestamp_list,
+ &ret->tlsext_signed_cert_timestamp_list_length,
+ kSignedCertTimestampListTag) ||
+ !SSL_SESSION_parse_octet_string(
+ &session, &ret->ocsp_response, &ret->ocsp_response_length,
+ kOCSPResponseTag)) {
+ goto err;
+ }
+
+ int extended_master_secret;
+ if (!CBS_get_optional_asn1_bool(&session, &extended_master_secret,
+ kExtendedMasterSecretTag,
+ 0 /* default to false */)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
+ goto err;
+ }
+ ret->extended_master_secret = !!extended_master_secret;
+
+ uint32_t value;
+ if (!SSL_SESSION_parse_u32(&session, &value, kGroupIDTag, 0)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
+ goto err;
+ }
+
+ /* Historically, the group_id field was used for key-exchange-specific
+ * information. Discard all but the group ID. */
+ if (ret->cipher->algorithm_mkey & (SSL_kRSA | SSL_kDHE)) {
+ value = 0;
+ }
+
+ if (value > 0xffff) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
+ goto err;
+ }
+ ret->group_id = (uint16_t)value;
+
+ CBS cert_chain;
+ CBS_init(&cert_chain, NULL, 0);
+ int has_cert_chain;
+ if (!CBS_get_optional_asn1(&session, &cert_chain, &has_cert_chain,
+ kCertChainTag) ||
+ (has_cert_chain && CBS_len(&cert_chain) == 0)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
+ goto err;
+ }
+ if (has_cert_chain && !has_peer) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
+ goto err;
+ }
+ if (has_peer || has_cert_chain) {
+ ret->certs = sk_CRYPTO_BUFFER_new_null();
+ if (ret->certs == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ 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);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ }
+
+ while (CBS_len(&cert_chain) > 0) {
+ CBS cert;
+ if (!CBS_get_any_asn1_element(&cert_chain, &cert, NULL, NULL) ||
+ CBS_len(&cert) == 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
+ goto err;
+ }
+
+ /* 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)) {
+ CRYPTO_BUFFER_free(buffer);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ }
+ }
+
+ if (!x509_method->session_cache_objects(ret)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
+ goto err;
+ }
+
+ CBS age_add;
+ int age_add_present;
+ if (!CBS_get_optional_asn1_octet_string(&session, &age_add, &age_add_present,
+ kTicketAgeAddTag) ||
+ (age_add_present &&
+ !CBS_get_u32(&age_add, &ret->ticket_age_add)) ||
+ CBS_len(&age_add) != 0) {
+ goto err;
+ }
+ ret->ticket_age_add_valid = age_add_present;
+
+ int is_server;
+ if (!CBS_get_optional_asn1_bool(&session, &is_server, kIsServerTag,
+ 1 /* default to true */)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
+ goto err;
+ }
+ /* TODO: in time we can include |is_server| for servers too, then we can
+ enforce that client and server sessions are never mixed up. */
+
+ ret->is_server = is_server;
+
+ if (!SSL_SESSION_parse_u16(&session, &ret->peer_signature_algorithm,
+ kPeerSignatureAlgorithmTag, 0) ||
+ !SSL_SESSION_parse_u32(&session, &ret->ticket_max_early_data,
+ kTicketMaxEarlyDataTag, 0) ||
+ !SSL_SESSION_parse_u32(&session, &ret->auth_timeout, kAuthTimeoutTag,
+ ret->timeout) ||
+ !SSL_SESSION_parse_octet_string(&session, &ret->early_alpn,
+ &ret->early_alpn_len, kEarlyALPNTag) ||
+ CBS_len(&session) != 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
+ goto err;
+ }
+
+ return ret;
+
+err:
+ SSL_SESSION_free(ret);
+ return NULL;
+}
+
+SSL_SESSION *SSL_SESSION_from_bytes(const uint8_t *in, size_t in_len,
+ const SSL_CTX *ctx) {
+ CBS cbs;
+ CBS_init(&cbs, in, in_len);
+ SSL_SESSION *ret = SSL_SESSION_parse(&cbs, ctx->x509_method, ctx->pool);
+ if (ret == NULL) {
+ return NULL;
+ }
+ if (CBS_len(&cbs) != 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
+ SSL_SESSION_free(ret);
+ return NULL;
+ }
+ return ret;
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_buffer.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_buffer.c
new file mode 100644
index 000000000..c27db8ba8
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_buffer.c
@@ -0,0 +1,312 @@
+/* Copyright (c) 2015, 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 <openssl/ssl.h>
+
+#include <assert.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <openssl/bio.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/type_check.h>
+
+#include "../crypto/internal.h"
+#include "internal.h"
+
+
+OPENSSL_COMPILE_ASSERT(0xffff <= INT_MAX, uint16_fits_in_int);
+
+OPENSSL_COMPILE_ASSERT((SSL3_ALIGN_PAYLOAD & (SSL3_ALIGN_PAYLOAD - 1)) == 0,
+ align_to_a_power_of_two);
+
+/* setup_buffer initializes |buf| with capacity |cap|, aligned such that data
+ * written after |header_len| is aligned to a |SSL3_ALIGN_PAYLOAD|-byte
+ * boundary. It returns one on success and zero on error. */
+static int setup_buffer(SSL3_BUFFER *buf, size_t header_len, size_t cap) {
+ if (buf->buf != NULL || cap > 0xffff) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ /* Add up to |SSL3_ALIGN_PAYLOAD| - 1 bytes of slack for alignment. */
+ buf->buf = OPENSSL_malloc(cap + SSL3_ALIGN_PAYLOAD - 1);
+ if (buf->buf == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+
+ /* Arrange the buffer such that the record body is aligned. */
+ buf->offset = (0 - header_len - (uintptr_t)buf->buf) &
+ (SSL3_ALIGN_PAYLOAD - 1);
+ buf->len = 0;
+ buf->cap = cap;
+ return 1;
+}
+
+static void consume_buffer(SSL3_BUFFER *buf, size_t len) {
+ if (len > buf->len) {
+ abort();
+ }
+ buf->offset += (uint16_t)len;
+ buf->len -= (uint16_t)len;
+ buf->cap -= (uint16_t)len;
+}
+
+static void clear_buffer(SSL3_BUFFER *buf) {
+ OPENSSL_free(buf->buf);
+ OPENSSL_memset(buf, 0, sizeof(SSL3_BUFFER));
+}
+
+OPENSSL_COMPILE_ASSERT(DTLS1_RT_HEADER_LENGTH + SSL3_RT_MAX_ENCRYPTED_LENGTH <=
+ 0xffff,
+ maximum_read_buffer_too_large);
+
+/* setup_read_buffer initializes the read buffer if not already initialized. It
+ * returns one on success and zero on failure. */
+static int setup_read_buffer(SSL *ssl) {
+ SSL3_BUFFER *buf = &ssl->s3->read_buffer;
+
+ if (buf->buf != NULL) {
+ return 1;
+ }
+
+ size_t header_len = ssl_record_prefix_len(ssl);
+ size_t cap = SSL3_RT_MAX_ENCRYPTED_LENGTH;
+ if (SSL_is_dtls(ssl)) {
+ cap += DTLS1_RT_HEADER_LENGTH;
+ } else {
+ cap += SSL3_RT_HEADER_LENGTH;
+ }
+
+ return setup_buffer(buf, header_len, cap);
+}
+
+uint8_t *ssl_read_buffer(SSL *ssl) {
+ return ssl->s3->read_buffer.buf + ssl->s3->read_buffer.offset;
+}
+
+size_t ssl_read_buffer_len(const SSL *ssl) {
+ return ssl->s3->read_buffer.len;
+}
+
+static int dtls_read_buffer_next_packet(SSL *ssl) {
+ SSL3_BUFFER *buf = &ssl->s3->read_buffer;
+
+ if (buf->len > 0) {
+ /* It is an error to call |dtls_read_buffer_extend| when the read buffer is
+ * not empty. */
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
+
+ /* Read a single packet from |ssl->rbio|. |buf->cap| must fit in an int. */
+ int ret = BIO_read(ssl->rbio, buf->buf + buf->offset, (int)buf->cap);
+ if (ret <= 0) {
+ ssl->rwstate = SSL_READING;
+ return ret;
+ }
+ /* |BIO_read| was bound by |buf->cap|, so this cannot overflow. */
+ buf->len = (uint16_t)ret;
+ return 1;
+}
+
+static int tls_read_buffer_extend_to(SSL *ssl, size_t len) {
+ SSL3_BUFFER *buf = &ssl->s3->read_buffer;
+
+ if (len > buf->cap) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL);
+ return -1;
+ }
+
+ /* Read until the target length is reached. */
+ while (buf->len < len) {
+ /* The amount of data to read is bounded by |buf->cap|, which must fit in an
+ * int. */
+ int ret = BIO_read(ssl->rbio, buf->buf + buf->offset + buf->len,
+ (int)(len - buf->len));
+ if (ret <= 0) {
+ ssl->rwstate = SSL_READING;
+ return ret;
+ }
+ /* |BIO_read| was bound by |buf->cap - buf->len|, so this cannot
+ * overflow. */
+ buf->len += (uint16_t)ret;
+ }
+
+ return 1;
+}
+
+int ssl_read_buffer_extend_to(SSL *ssl, size_t len) {
+ /* |ssl_read_buffer_extend_to| implicitly discards any consumed data. */
+ ssl_read_buffer_discard(ssl);
+
+ if (!setup_read_buffer(ssl)) {
+ return -1;
+ }
+
+ if (ssl->rbio == NULL) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BIO_NOT_SET);
+ return -1;
+ }
+
+ int ret;
+ if (SSL_is_dtls(ssl)) {
+ /* |len| is ignored for a datagram transport. */
+ ret = dtls_read_buffer_next_packet(ssl);
+ } else {
+ ret = tls_read_buffer_extend_to(ssl, len);
+ }
+
+ if (ret <= 0) {
+ /* If the buffer was empty originally and remained empty after attempting to
+ * extend it, release the buffer until the next attempt. */
+ ssl_read_buffer_discard(ssl);
+ }
+ return ret;
+}
+
+void ssl_read_buffer_consume(SSL *ssl, size_t len) {
+ SSL3_BUFFER *buf = &ssl->s3->read_buffer;
+
+ consume_buffer(buf, len);
+
+ /* The TLS stack never reads beyond the current record, so there will never be
+ * unconsumed data. If read-ahead is ever reimplemented,
+ * |ssl_read_buffer_discard| will require a |memcpy| to shift the excess back
+ * to the front of the buffer, to ensure there is enough space for the next
+ * record. */
+ assert(SSL_is_dtls(ssl) || len == 0 || buf->len == 0);
+}
+
+void ssl_read_buffer_discard(SSL *ssl) {
+ if (ssl->s3->read_buffer.len == 0) {
+ ssl_read_buffer_clear(ssl);
+ }
+}
+
+void ssl_read_buffer_clear(SSL *ssl) {
+ clear_buffer(&ssl->s3->read_buffer);
+}
+
+
+int ssl_write_buffer_is_pending(const SSL *ssl) {
+ return ssl->s3->write_buffer.len > 0;
+}
+
+OPENSSL_COMPILE_ASSERT(SSL3_RT_HEADER_LENGTH * 2 +
+ SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD * 2 +
+ SSL3_RT_MAX_PLAIN_LENGTH <= 0xffff,
+ maximum_tls_write_buffer_too_large);
+
+OPENSSL_COMPILE_ASSERT(DTLS1_RT_HEADER_LENGTH +
+ SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD +
+ SSL3_RT_MAX_PLAIN_LENGTH <= 0xffff,
+ maximum_dtls_write_buffer_too_large);
+
+int ssl_write_buffer_init(SSL *ssl, uint8_t **out_ptr, size_t max_len) {
+ SSL3_BUFFER *buf = &ssl->s3->write_buffer;
+
+ if (buf->buf != NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ size_t header_len = ssl_seal_align_prefix_len(ssl);
+
+ /* TODO(davidben): This matches the original behavior in keeping the malloc
+ * size consistent. Does this matter? |cap| could just be |max_len|. */
+ size_t cap = SSL3_RT_MAX_PLAIN_LENGTH + SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD;
+ if (SSL_is_dtls(ssl)) {
+ cap += DTLS1_RT_HEADER_LENGTH;
+ } else {
+ cap += SSL3_RT_HEADER_LENGTH;
+ if (ssl->mode & SSL_MODE_CBC_RECORD_SPLITTING) {
+ cap += SSL3_RT_HEADER_LENGTH + SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD;
+ }
+ }
+
+ if (max_len > cap) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL);
+ return 0;
+ }
+
+ if (!setup_buffer(buf, header_len, cap)) {
+ return 0;
+ }
+ *out_ptr = buf->buf + buf->offset;
+ return 1;
+}
+
+void ssl_write_buffer_set_len(SSL *ssl, size_t len) {
+ SSL3_BUFFER *buf = &ssl->s3->write_buffer;
+
+ if (len > buf->cap) {
+ abort();
+ }
+ buf->len = len;
+}
+
+static int tls_write_buffer_flush(SSL *ssl) {
+ SSL3_BUFFER *buf = &ssl->s3->write_buffer;
+
+ while (buf->len > 0) {
+ int ret = BIO_write(ssl->wbio, buf->buf + buf->offset, buf->len);
+ if (ret <= 0) {
+ ssl->rwstate = SSL_WRITING;
+ return ret;
+ }
+ consume_buffer(buf, (size_t)ret);
+ }
+ ssl_write_buffer_clear(ssl);
+ return 1;
+}
+
+static int dtls_write_buffer_flush(SSL *ssl) {
+ SSL3_BUFFER *buf = &ssl->s3->write_buffer;
+ if (buf->len == 0) {
+ return 1;
+ }
+
+ int ret = BIO_write(ssl->wbio, buf->buf + buf->offset, buf->len);
+ if (ret <= 0) {
+ ssl->rwstate = SSL_WRITING;
+ /* If the write failed, drop the write buffer anyway. Datagram transports
+ * can't write half a packet, so the caller is expected to retry from the
+ * top. */
+ ssl_write_buffer_clear(ssl);
+ return ret;
+ }
+ ssl_write_buffer_clear(ssl);
+ return 1;
+}
+
+int ssl_write_buffer_flush(SSL *ssl) {
+ if (ssl->wbio == NULL) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BIO_NOT_SET);
+ return -1;
+ }
+
+ if (SSL_is_dtls(ssl)) {
+ return dtls_write_buffer_flush(ssl);
+ } else {
+ return tls_write_buffer_flush(ssl);
+ }
+}
+
+void ssl_write_buffer_clear(SSL *ssl) {
+ clear_buffer(&ssl->s3->write_buffer);
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_cert.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_cert.c
new file mode 100644
index 000000000..5013b2057
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_cert.c
@@ -0,0 +1,899 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2007 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ * ECC cipher suite support in OpenSSL originally developed by
+ * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. */
+
+#include <openssl/ssl.h>
+
+#include <assert.h>
+#include <limits.h>
+#include <string.h>
+
+#include <openssl/bn.h>
+#include <openssl/buf.h>
+#include <openssl/bytestring.h>
+#include <openssl/dh.h>
+#include <openssl/ec_key.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/sha.h>
+#include <openssl/x509.h>
+
+#include "../crypto/internal.h"
+#include "internal.h"
+
+
+CERT *ssl_cert_new(const SSL_X509_METHOD *x509_method) {
+ CERT *ret = OPENSSL_malloc(sizeof(CERT));
+ if (ret == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ OPENSSL_memset(ret, 0, sizeof(CERT));
+ ret->x509_method = x509_method;
+
+ return ret;
+}
+
+static CRYPTO_BUFFER *buffer_up_ref(CRYPTO_BUFFER *buffer) {
+ CRYPTO_BUFFER_up_ref(buffer);
+ return buffer;
+}
+
+CERT *ssl_cert_dup(CERT *cert) {
+ CERT *ret = OPENSSL_malloc(sizeof(CERT));
+ if (ret == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ OPENSSL_memset(ret, 0, sizeof(CERT));
+
+ ret->chain = sk_CRYPTO_BUFFER_deep_copy(cert->chain, buffer_up_ref,
+ CRYPTO_BUFFER_free);
+
+ if (cert->privatekey != NULL) {
+ EVP_PKEY_up_ref(cert->privatekey);
+ ret->privatekey = cert->privatekey;
+ }
+
+ ret->key_method = cert->key_method;
+ ret->x509_method = cert->x509_method;
+
+ if (cert->dh_tmp != NULL) {
+ ret->dh_tmp = DHparams_dup(cert->dh_tmp);
+ if (ret->dh_tmp == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_DH_LIB);
+ goto err;
+ }
+ }
+ ret->dh_tmp_cb = cert->dh_tmp_cb;
+
+ if (cert->sigalgs != NULL) {
+ ret->sigalgs =
+ BUF_memdup(cert->sigalgs, cert->num_sigalgs * sizeof(cert->sigalgs[0]));
+ if (ret->sigalgs == NULL) {
+ goto err;
+ }
+ }
+ ret->num_sigalgs = cert->num_sigalgs;
+
+ ret->cert_cb = cert->cert_cb;
+ ret->cert_cb_arg = cert->cert_cb_arg;
+
+ ret->x509_method->cert_dup(ret, cert);
+
+ if (cert->signed_cert_timestamp_list != NULL) {
+ CRYPTO_BUFFER_up_ref(cert->signed_cert_timestamp_list);
+ ret->signed_cert_timestamp_list = cert->signed_cert_timestamp_list;
+ }
+
+ if (cert->ocsp_response != NULL) {
+ CRYPTO_BUFFER_up_ref(cert->ocsp_response);
+ ret->ocsp_response = cert->ocsp_response;
+ }
+
+ ret->sid_ctx_length = cert->sid_ctx_length;
+ OPENSSL_memcpy(ret->sid_ctx, cert->sid_ctx, sizeof(ret->sid_ctx));
+
+ return ret;
+
+err:
+ ssl_cert_free(ret);
+ return NULL;
+}
+
+/* Free up and clear all certificates and chains */
+void ssl_cert_clear_certs(CERT *cert) {
+ if (cert == NULL) {
+ return;
+ }
+
+ cert->x509_method->cert_clear(cert);
+
+ sk_CRYPTO_BUFFER_pop_free(cert->chain, CRYPTO_BUFFER_free);
+ cert->chain = NULL;
+ EVP_PKEY_free(cert->privatekey);
+ cert->privatekey = NULL;
+ cert->key_method = NULL;
+}
+
+void ssl_cert_free(CERT *c) {
+ if (c == NULL) {
+ return;
+ }
+
+ DH_free(c->dh_tmp);
+
+ 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);
+
+ OPENSSL_free(c);
+}
+
+static void ssl_cert_set_cert_cb(CERT *c, int (*cb)(SSL *ssl, void *arg),
+ void *arg) {
+ c->cert_cb = cb;
+ c->cert_cb_arg = arg;
+}
+
+enum leaf_cert_and_privkey_result_t {
+ leaf_cert_and_privkey_error,
+ leaf_cert_and_privkey_ok,
+ leaf_cert_and_privkey_mismatch,
+};
+
+/* check_leaf_cert_and_privkey checks whether the certificate in |leaf_buffer|
+ * and the private key in |privkey| are suitable and coherent. It returns
+ * |leaf_cert_and_privkey_error| and pushes to the error queue if a problem is
+ * found. If the certificate and private key are valid, but incoherent, it
+ * returns |leaf_cert_and_privkey_mismatch|. Otherwise it returns
+ * |leaf_cert_and_privkey_ok|. */
+static enum leaf_cert_and_privkey_result_t check_leaf_cert_and_privkey(
+ CRYPTO_BUFFER *leaf_buffer, EVP_PKEY *privkey) {
+ enum leaf_cert_and_privkey_result_t ret = leaf_cert_and_privkey_error;
+
+ CBS cert_cbs;
+ CRYPTO_BUFFER_init_CBS(leaf_buffer, &cert_cbs);
+ EVP_PKEY *pubkey = ssl_cert_parse_pubkey(&cert_cbs);
+ if (pubkey == NULL) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ goto out;
+ }
+
+ if (!ssl_is_key_type_supported(pubkey->type)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CERTIFICATE_TYPE);
+ goto out;
+ }
+
+ /* An ECC certificate may be usable for ECDH or ECDSA. We only support ECDSA
+ * certificates, so sanity-check the key usage extension. */
+ if (pubkey->type == EVP_PKEY_EC &&
+ !ssl_cert_check_digital_signature_key_usage(&cert_cbs)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CERTIFICATE_TYPE);
+ goto out;
+ }
+
+ if (privkey != NULL &&
+ /* Sanity-check that the private key and the certificate match. */
+ !ssl_compare_public_and_private_key(pubkey, privkey)) {
+ ERR_clear_error();
+ ret = leaf_cert_and_privkey_mismatch;
+ goto out;
+ }
+
+ ret = leaf_cert_and_privkey_ok;
+
+out:
+ EVP_PKEY_free(pubkey);
+ return ret;
+}
+
+static int cert_set_chain_and_key(
+ CERT *cert, CRYPTO_BUFFER *const *certs, size_t num_certs,
+ EVP_PKEY *privkey, const SSL_PRIVATE_KEY_METHOD *privkey_method) {
+ if (num_certs == 0 ||
+ (privkey == NULL && privkey_method == NULL)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
+
+ if (privkey != NULL && privkey_method != NULL) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CANNOT_HAVE_BOTH_PRIVKEY_AND_METHOD);
+ return 0;
+ }
+
+ switch (check_leaf_cert_and_privkey(certs[0], privkey)) {
+ case leaf_cert_and_privkey_error:
+ return 0;
+ case leaf_cert_and_privkey_mismatch:
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CERTIFICATE_AND_PRIVATE_KEY_MISMATCH);
+ return 0;
+ case leaf_cert_and_privkey_ok:
+ break;
+ }
+
+ STACK_OF(CRYPTO_BUFFER) *certs_sk = sk_CRYPTO_BUFFER_new_null();
+ if (certs_sk == NULL) {
+ return 0;
+ }
+
+ for (size_t i = 0; i < num_certs; i++) {
+ if (!sk_CRYPTO_BUFFER_push(certs_sk, certs[i])) {
+ sk_CRYPTO_BUFFER_pop_free(certs_sk, CRYPTO_BUFFER_free);
+ return 0;
+ }
+ CRYPTO_BUFFER_up_ref(certs[i]);
+ }
+
+ EVP_PKEY_free(cert->privatekey);
+ cert->privatekey = privkey;
+ if (privkey != NULL) {
+ EVP_PKEY_up_ref(privkey);
+ }
+ cert->key_method = privkey_method;
+
+ sk_CRYPTO_BUFFER_pop_free(cert->chain, CRYPTO_BUFFER_free);
+ cert->chain = certs_sk;
+
+ return 1;
+}
+
+int SSL_set_chain_and_key(SSL *ssl, CRYPTO_BUFFER *const *certs,
+ size_t num_certs, EVP_PKEY *privkey,
+ const SSL_PRIVATE_KEY_METHOD *privkey_method) {
+ return cert_set_chain_and_key(ssl->cert, certs, num_certs, privkey,
+ privkey_method);
+}
+
+int SSL_CTX_set_chain_and_key(SSL_CTX *ctx, CRYPTO_BUFFER *const *certs,
+ size_t num_certs, EVP_PKEY *privkey,
+ const SSL_PRIVATE_KEY_METHOD *privkey_method) {
+ return cert_set_chain_and_key(ctx->cert, certs, num_certs, privkey,
+ privkey_method);
+}
+
+int ssl_set_cert(CERT *cert, CRYPTO_BUFFER *buffer) {
+ switch (check_leaf_cert_and_privkey(buffer, cert->privatekey)) {
+ case leaf_cert_and_privkey_error:
+ return 0;
+ case leaf_cert_and_privkey_mismatch:
+ /* don't fail for a cert/key mismatch, just free current private key
+ * (when switching to a different cert & key, first this function should
+ * be used, then |ssl_set_pkey|. */
+ EVP_PKEY_free(cert->privatekey);
+ cert->privatekey = NULL;
+ break;
+ case leaf_cert_and_privkey_ok:
+ break;
+ }
+
+ cert->x509_method->cert_flush_cached_leaf(cert);
+
+ 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);
+ return 1;
+ }
+
+ cert->chain = sk_CRYPTO_BUFFER_new_null();
+ if (cert->chain == NULL) {
+ return 0;
+ }
+
+ if (!sk_CRYPTO_BUFFER_push(cert->chain, buffer)) {
+ sk_CRYPTO_BUFFER_free(cert->chain);
+ cert->chain = NULL;
+ return 0;
+ }
+ CRYPTO_BUFFER_up_ref(buffer);
+
+ return 1;
+}
+
+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) {
+ return 0;
+ }
+
+ const int ok = ssl_set_cert(ctx->cert, buffer);
+ CRYPTO_BUFFER_free(buffer);
+ return ok;
+}
+
+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) {
+ return 0;
+ }
+
+ const int ok = ssl_set_cert(ssl->cert, buffer);
+ CRYPTO_BUFFER_free(buffer);
+ return ok;
+}
+
+int ssl_has_certificate(const SSL *ssl) {
+ return ssl->cert->chain != NULL &&
+ sk_CRYPTO_BUFFER_value(ssl->cert->chain, 0) != NULL &&
+ ssl_has_private_key(ssl);
+}
+
+STACK_OF(CRYPTO_BUFFER) *ssl_parse_cert_chain(uint8_t *out_alert,
+ EVP_PKEY **out_pubkey,
+ uint8_t *out_leaf_sha256,
+ CBS *cbs,
+ CRYPTO_BUFFER_POOL *pool) {
+ *out_pubkey = NULL;
+
+ STACK_OF(CRYPTO_BUFFER) *ret = sk_CRYPTO_BUFFER_new_null();
+ if (ret == NULL) {
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+
+ 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);
+ goto err;
+ }
+
+ 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);
+ goto err;
+ }
+
+ if (sk_CRYPTO_BUFFER_num(ret) == 0) {
+ *out_pubkey = ssl_cert_parse_pubkey(&certificate);
+ if (*out_pubkey == NULL) {
+ *out_alert = SSL_AD_DECODE_ERROR;
+ goto err;
+ }
+
+ /* Retain the hash of the leaf certificate if requested. */
+ if (out_leaf_sha256 != NULL) {
+ SHA256(CBS_data(&certificate), CBS_len(&certificate), out_leaf_sha256);
+ }
+ }
+
+ CRYPTO_BUFFER *buf =
+ CRYPTO_BUFFER_new_from_CBS(&certificate, pool);
+ if (buf == NULL) {
+ *out_alert = SSL_AD_DECODE_ERROR;
+ goto err;
+ }
+
+ if (!sk_CRYPTO_BUFFER_push(ret, buf)) {
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ CRYPTO_BUFFER_free(buf);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ }
+
+ return ret;
+
+err:
+ EVP_PKEY_free(*out_pubkey);
+ *out_pubkey = NULL;
+ sk_CRYPTO_BUFFER_pop_free(ret, CRYPTO_BUFFER_free);
+ return NULL;
+}
+
+int ssl_add_cert_chain(SSL *ssl, CBB *cbb) {
+ if (!ssl_has_certificate(ssl)) {
+ return CBB_add_u24(cbb, 0);
+ }
+
+ CBB certs;
+ if (!CBB_add_u24_length_prefixed(cbb, &certs)) {
+ goto err;
+ }
+
+ STACK_OF(CRYPTO_BUFFER) *chain = ssl->cert->chain;
+ for (size_t i = 0; i < sk_CRYPTO_BUFFER_num(chain); i++) {
+ CRYPTO_BUFFER *buffer = sk_CRYPTO_BUFFER_value(chain, i);
+ CBB child;
+ if (!CBB_add_u24_length_prefixed(&certs, &child) ||
+ !CBB_add_bytes(&child, CRYPTO_BUFFER_data(buffer),
+ CRYPTO_BUFFER_len(buffer)) ||
+ !CBB_flush(&certs)) {
+ goto err;
+ }
+ }
+
+ return CBB_flush(cbb);
+
+err:
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return 0;
+}
+
+/* ssl_cert_skip_to_spki parses a DER-encoded, X.509 certificate from |in| and
+ * positions |*out_tbs_cert| to cover the TBSCertificate, starting at the
+ * subjectPublicKeyInfo. */
+static int ssl_cert_skip_to_spki(const CBS *in, CBS *out_tbs_cert) {
+ /* From RFC 5280, section 4.1
+ * Certificate ::= SEQUENCE {
+ * tbsCertificate TBSCertificate,
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signatureValue BIT STRING }
+
+ * TBSCertificate ::= SEQUENCE {
+ * version [0] EXPLICIT Version DEFAULT v1,
+ * serialNumber CertificateSerialNumber,
+ * signature AlgorithmIdentifier,
+ * issuer Name,
+ * validity Validity,
+ * subject Name,
+ * subjectPublicKeyInfo SubjectPublicKeyInfo,
+ * ... } */
+ CBS buf = *in;
+
+ CBS toplevel;
+ if (!CBS_get_asn1(&buf, &toplevel, CBS_ASN1_SEQUENCE) ||
+ CBS_len(&buf) != 0 ||
+ !CBS_get_asn1(&toplevel, out_tbs_cert, CBS_ASN1_SEQUENCE) ||
+ /* version */
+ !CBS_get_optional_asn1(
+ out_tbs_cert, NULL, NULL,
+ CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 0) ||
+ /* serialNumber */
+ !CBS_get_asn1(out_tbs_cert, NULL, CBS_ASN1_INTEGER) ||
+ /* signature algorithm */
+ !CBS_get_asn1(out_tbs_cert, NULL, CBS_ASN1_SEQUENCE) ||
+ /* issuer */
+ !CBS_get_asn1(out_tbs_cert, NULL, CBS_ASN1_SEQUENCE) ||
+ /* validity */
+ !CBS_get_asn1(out_tbs_cert, NULL, CBS_ASN1_SEQUENCE) ||
+ /* subject */
+ !CBS_get_asn1(out_tbs_cert, NULL, CBS_ASN1_SEQUENCE)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+EVP_PKEY *ssl_cert_parse_pubkey(const CBS *in) {
+ CBS buf = *in, tbs_cert;
+ if (!ssl_cert_skip_to_spki(&buf, &tbs_cert)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CANNOT_PARSE_LEAF_CERT);
+ return NULL;
+ }
+
+ return EVP_parse_public_key(&tbs_cert);
+}
+
+int ssl_compare_public_and_private_key(const EVP_PKEY *pubkey,
+ const EVP_PKEY *privkey) {
+ if (EVP_PKEY_is_opaque(privkey)) {
+ /* We cannot check an opaque private key and have to trust that it
+ * matches. */
+ return 1;
+ }
+
+ int ret = 0;
+
+ switch (EVP_PKEY_cmp(pubkey, privkey)) {
+ case 1:
+ ret = 1;
+ break;
+ case 0:
+ OPENSSL_PUT_ERROR(X509, X509_R_KEY_VALUES_MISMATCH);
+ break;
+ case -1:
+ OPENSSL_PUT_ERROR(X509, X509_R_KEY_TYPE_MISMATCH);
+ break;
+ case -2:
+ OPENSSL_PUT_ERROR(X509, X509_R_UNKNOWN_KEY_TYPE);
+ default:
+ assert(0);
+ break;
+ }
+
+ return ret;
+}
+
+int ssl_cert_check_private_key(const CERT *cert, const EVP_PKEY *privkey) {
+ if (privkey == NULL) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_PRIVATE_KEY_ASSIGNED);
+ return 0;
+ }
+
+ if (cert->chain == NULL ||
+ sk_CRYPTO_BUFFER_value(cert->chain, 0) == NULL) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATE_ASSIGNED);
+ return 0;
+ }
+
+ CBS cert_cbs;
+ CRYPTO_BUFFER_init_CBS(sk_CRYPTO_BUFFER_value(cert->chain, 0), &cert_cbs);
+ EVP_PKEY *pubkey = ssl_cert_parse_pubkey(&cert_cbs);
+ if (!pubkey) {
+ OPENSSL_PUT_ERROR(X509, X509_R_UNKNOWN_KEY_TYPE);
+ return 0;
+ }
+
+ const int ok = ssl_compare_public_and_private_key(pubkey, privkey);
+ EVP_PKEY_free(pubkey);
+ return ok;
+}
+
+int ssl_cert_check_digital_signature_key_usage(const CBS *in) {
+ CBS buf = *in;
+
+ CBS tbs_cert, outer_extensions;
+ int has_extensions;
+ if (!ssl_cert_skip_to_spki(&buf, &tbs_cert) ||
+ /* subjectPublicKeyInfo */
+ !CBS_get_asn1(&tbs_cert, NULL, CBS_ASN1_SEQUENCE) ||
+ /* issuerUniqueID */
+ !CBS_get_optional_asn1(
+ &tbs_cert, NULL, NULL,
+ CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 1) ||
+ /* subjectUniqueID */
+ !CBS_get_optional_asn1(
+ &tbs_cert, NULL, NULL,
+ CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 2) ||
+ !CBS_get_optional_asn1(
+ &tbs_cert, &outer_extensions, &has_extensions,
+ CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 3)) {
+ goto parse_err;
+ }
+
+ if (!has_extensions) {
+ return 1;
+ }
+
+ CBS extensions;
+ if (!CBS_get_asn1(&outer_extensions, &extensions, CBS_ASN1_SEQUENCE)) {
+ goto parse_err;
+ }
+
+ while (CBS_len(&extensions) > 0) {
+ CBS extension, oid, contents;
+ if (!CBS_get_asn1(&extensions, &extension, CBS_ASN1_SEQUENCE) ||
+ !CBS_get_asn1(&extension, &oid, CBS_ASN1_OBJECT) ||
+ (CBS_peek_asn1_tag(&extension, CBS_ASN1_BOOLEAN) &&
+ !CBS_get_asn1(&extension, NULL, CBS_ASN1_BOOLEAN)) ||
+ !CBS_get_asn1(&extension, &contents, CBS_ASN1_OCTETSTRING) ||
+ CBS_len(&extension) != 0) {
+ goto parse_err;
+ }
+
+ static const uint8_t kKeyUsageOID[3] = {0x55, 0x1d, 0x0f};
+ if (CBS_len(&oid) != sizeof(kKeyUsageOID) ||
+ OPENSSL_memcmp(CBS_data(&oid), kKeyUsageOID, sizeof(kKeyUsageOID)) !=
+ 0) {
+ continue;
+ }
+
+ CBS bit_string;
+ if (!CBS_get_asn1(&contents, &bit_string, CBS_ASN1_BITSTRING) ||
+ CBS_len(&contents) != 0) {
+ goto parse_err;
+ }
+
+ /* This is the KeyUsage extension. See
+ * https://tools.ietf.org/html/rfc5280#section-4.2.1.3 */
+ if (!CBS_is_valid_asn1_bitstring(&bit_string)) {
+ goto parse_err;
+ }
+
+ if (!CBS_asn1_bitstring_has_bit(&bit_string, 0)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_ECC_CERT_NOT_FOR_SIGNING);
+ return 0;
+ }
+
+ return 1;
+ }
+
+ /* No KeyUsage extension found. */
+ return 1;
+
+parse_err:
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CANNOT_PARSE_LEAF_CERT);
+ return 0;
+}
+
+STACK_OF(CRYPTO_BUFFER) *
+ ssl_parse_client_CA_list(SSL *ssl, uint8_t *out_alert, CBS *cbs) {
+ CRYPTO_BUFFER_POOL *const pool = ssl->ctx->pool;
+
+ STACK_OF(CRYPTO_BUFFER) *ret = sk_CRYPTO_BUFFER_new_null();
+ if (ret == NULL) {
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+
+ CBS child;
+ if (!CBS_get_u16_length_prefixed(cbs, &child)) {
+ *out_alert = SSL_AD_DECODE_ERROR;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_LENGTH_MISMATCH);
+ goto err;
+ }
+
+ while (CBS_len(&child) > 0) {
+ CBS distinguished_name;
+ if (!CBS_get_u16_length_prefixed(&child, &distinguished_name)) {
+ *out_alert = SSL_AD_DECODE_ERROR;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CA_DN_TOO_LONG);
+ goto err;
+ }
+
+ CRYPTO_BUFFER *buffer =
+ CRYPTO_BUFFER_new_from_CBS(&distinguished_name, pool);
+ if (buffer == NULL ||
+ !sk_CRYPTO_BUFFER_push(ret, buffer)) {
+ CRYPTO_BUFFER_free(buffer);
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ }
+
+ if (!ssl->ctx->x509_method->check_client_CA_list(ret)) {
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ goto err;
+ }
+
+ return ret;
+
+err:
+ sk_CRYPTO_BUFFER_pop_free(ret, CRYPTO_BUFFER_free);
+ return NULL;
+}
+
+int ssl_add_client_CA_list(SSL *ssl, CBB *cbb) {
+ CBB child, name_cbb;
+ if (!CBB_add_u16_length_prefixed(cbb, &child)) {
+ return 0;
+ }
+
+ STACK_OF(CRYPTO_BUFFER) *names = ssl->client_CA;
+ if (names == NULL) {
+ names = ssl->ctx->client_CA;
+ }
+ if (names == NULL) {
+ 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);
+
+ if (!CBB_add_u16_length_prefixed(&child, &name_cbb) ||
+ !CBB_add_bytes(&name_cbb, CRYPTO_BUFFER_data(name),
+ CRYPTO_BUFFER_len(name))) {
+ return 0;
+ }
+ }
+
+ return CBB_flush(cbb);
+}
+
+void SSL_CTX_set_cert_cb(SSL_CTX *ctx, int (*cb)(SSL *ssl, void *arg),
+ void *arg) {
+ ssl_cert_set_cert_cb(ctx->cert, cb, arg);
+}
+
+void SSL_set_cert_cb(SSL *ssl, int (*cb)(SSL *ssl, void *arg), void *arg) {
+ ssl_cert_set_cert_cb(ssl->cert, cb, arg);
+}
+
+STACK_OF(CRYPTO_BUFFER) *SSL_get0_peer_certificates(const SSL *ssl) {
+ SSL_SESSION *session = SSL_get_session(ssl);
+ if (session == NULL) {
+ return NULL;
+ }
+
+ return session->certs;
+}
+
+STACK_OF(CRYPTO_BUFFER) *SSL_get0_server_requested_CAs(const SSL *ssl) {
+ if (ssl->s3->hs == NULL) {
+ return NULL;
+ }
+ return ssl->s3->hs->ca_names;
+}
+
+int ssl_check_leaf_certificate(SSL_HANDSHAKE *hs, EVP_PKEY *pkey,
+ const CRYPTO_BUFFER *leaf) {
+ SSL *const ssl = hs->ssl;
+ assert(ssl3_protocol_version(ssl) < TLS1_3_VERSION);
+
+ /* Check the certificate's type matches the cipher. */
+ int expected_type = ssl_cipher_get_key_type(hs->new_cipher);
+ assert(expected_type != EVP_PKEY_NONE);
+ if (pkey->type != expected_type) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CERTIFICATE_TYPE);
+ return 0;
+ }
+
+ if (hs->new_cipher->algorithm_auth & SSL_aECDSA) {
+ CBS leaf_cbs;
+ CBS_init(&leaf_cbs, CRYPTO_BUFFER_data(leaf), CRYPTO_BUFFER_len(leaf));
+ /* ECDSA and ECDH certificates use the same public key format. Instead,
+ * they are distinguished by the key usage extension in the certificate. */
+ if (!ssl_cert_check_digital_signature_key_usage(&leaf_cbs)) {
+ return 0;
+ }
+
+ EC_KEY *ec_key = EVP_PKEY_get0_EC_KEY(pkey);
+ if (ec_key == NULL) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECC_CERT);
+ return 0;
+ }
+
+ /* Check the key's group and point format are acceptable. */
+ uint16_t group_id;
+ if (!ssl_nid_to_group_id(
+ &group_id, EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key))) ||
+ !tls1_check_group_id(ssl, group_id) ||
+ EC_KEY_get_conv_form(ec_key) != POINT_CONVERSION_UNCOMPRESSED) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECC_CERT);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static int set_signed_cert_timestamp_list(CERT *cert, const uint8_t *list,
+ size_t list_len) {
+ CBS sct_list;
+ CBS_init(&sct_list, list, list_len);
+ if (!ssl_is_sct_list_valid(&sct_list)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SCT_LIST);
+ return 0;
+ }
+
+ CRYPTO_BUFFER_free(cert->signed_cert_timestamp_list);
+ cert->signed_cert_timestamp_list =
+ CRYPTO_BUFFER_new(CBS_data(&sct_list), CBS_len(&sct_list), NULL);
+ return cert->signed_cert_timestamp_list != NULL;
+}
+
+int SSL_CTX_set_signed_cert_timestamp_list(SSL_CTX *ctx, const uint8_t *list,
+ size_t list_len) {
+ return set_signed_cert_timestamp_list(ctx->cert, list, list_len);
+}
+
+int SSL_set_signed_cert_timestamp_list(SSL *ssl, const uint8_t *list,
+ size_t list_len) {
+ return set_signed_cert_timestamp_list(ssl->cert, list, list_len);
+}
+
+int SSL_CTX_set_ocsp_response(SSL_CTX *ctx, const uint8_t *response,
+ size_t response_len) {
+ CRYPTO_BUFFER_free(ctx->cert->ocsp_response);
+ ctx->cert->ocsp_response = CRYPTO_BUFFER_new(response, response_len, NULL);
+ return ctx->cert->ocsp_response != NULL;
+}
+
+int SSL_set_ocsp_response(SSL *ssl, const uint8_t *response,
+ size_t response_len) {
+ CRYPTO_BUFFER_free(ssl->cert->ocsp_response);
+ ssl->cert->ocsp_response = CRYPTO_BUFFER_new(response, response_len, NULL);
+ return ssl->cert->ocsp_response != NULL;
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_cipher.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_cipher.c
new file mode 100644
index 000000000..4ee3c1255
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_cipher.c
@@ -0,0 +1,1867 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2007 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ * ECC cipher suite support in OpenSSL originally developed by
+ * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
+ */
+/* ====================================================================
+ * Copyright 2005 Nokia. All rights reserved.
+ *
+ * The portions of the attached software ("Contribution") is developed by
+ * Nokia Corporation and is licensed pursuant to the OpenSSL open source
+ * license.
+ *
+ * The Contribution, originally written by Mika Kousa and Pasi Eronen of
+ * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites
+ * support (see RFC 4279) to OpenSSL.
+ *
+ * No patent licenses or other rights except those expressly stated in
+ * the OpenSSL open source license shall be deemed granted or received
+ * expressly, by implication, estoppel, or otherwise.
+ *
+ * No assurances are provided by Nokia that the Contribution does not
+ * infringe the patent or other intellectual property rights of any third
+ * party or that the license provides you with all the necessary rights
+ * to make use of the Contribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN
+ * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA
+ * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY
+ * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
+ * OTHERWISE. */
+
+#include <openssl/ssl.h>
+
+#include <assert.h>
+#include <string.h>
+
+#include <openssl/buf.h>
+#include <openssl/err.h>
+#include <openssl/md5.h>
+#include <openssl/mem.h>
+#include <openssl/sha.h>
+#include <openssl/stack.h>
+
+#include "internal.h"
+#include "../crypto/internal.h"
+
+
+/* kCiphers is an array of all supported ciphers, sorted by id. */
+static const SSL_CIPHER kCiphers[] = {
+ /* The RSA ciphers */
+ /* Cipher 02 */
+ {
+ SSL3_TXT_RSA_NULL_SHA,
+ SSL3_CK_RSA_NULL_SHA,
+ SSL_kRSA,
+ SSL_aRSA,
+ SSL_eNULL,
+ SSL_SHA1,
+ SSL_HANDSHAKE_MAC_DEFAULT,
+ },
+
+ /* Cipher 0A */
+ {
+ SSL3_TXT_RSA_DES_192_CBC3_SHA,
+ SSL3_CK_RSA_DES_192_CBC3_SHA,
+ SSL_kRSA,
+ SSL_aRSA,
+ SSL_3DES,
+ SSL_SHA1,
+ SSL_HANDSHAKE_MAC_DEFAULT,
+ },
+
+
+ /* New AES ciphersuites */
+
+ /* Cipher 2F */
+ {
+ TLS1_TXT_RSA_WITH_AES_128_SHA,
+ TLS1_CK_RSA_WITH_AES_128_SHA,
+ SSL_kRSA,
+ SSL_aRSA,
+ SSL_AES128,
+ SSL_SHA1,
+ SSL_HANDSHAKE_MAC_DEFAULT,
+ },
+
+ /* Cipher 33 */
+ {
+ TLS1_TXT_DHE_RSA_WITH_AES_128_SHA,
+ TLS1_CK_DHE_RSA_WITH_AES_128_SHA,
+ SSL_kDHE,
+ SSL_aRSA,
+ SSL_AES128,
+ SSL_SHA1,
+ SSL_HANDSHAKE_MAC_DEFAULT,
+ },
+
+ /* Cipher 35 */
+ {
+ TLS1_TXT_RSA_WITH_AES_256_SHA,
+ TLS1_CK_RSA_WITH_AES_256_SHA,
+ SSL_kRSA,
+ SSL_aRSA,
+ SSL_AES256,
+ SSL_SHA1,
+ SSL_HANDSHAKE_MAC_DEFAULT,
+ },
+
+ /* Cipher 39 */
+ {
+ TLS1_TXT_DHE_RSA_WITH_AES_256_SHA,
+ TLS1_CK_DHE_RSA_WITH_AES_256_SHA,
+ SSL_kDHE,
+ SSL_aRSA,
+ SSL_AES256,
+ SSL_SHA1,
+ SSL_HANDSHAKE_MAC_DEFAULT,
+ },
+
+
+ /* TLS v1.2 ciphersuites */
+
+ /* Cipher 3C */
+ {
+ TLS1_TXT_RSA_WITH_AES_128_SHA256,
+ TLS1_CK_RSA_WITH_AES_128_SHA256,
+ SSL_kRSA,
+ SSL_aRSA,
+ SSL_AES128,
+ SSL_SHA256,
+ SSL_HANDSHAKE_MAC_SHA256,
+ },
+
+ /* Cipher 3D */
+ {
+ TLS1_TXT_RSA_WITH_AES_256_SHA256,
+ TLS1_CK_RSA_WITH_AES_256_SHA256,
+ SSL_kRSA,
+ SSL_aRSA,
+ SSL_AES256,
+ SSL_SHA256,
+ SSL_HANDSHAKE_MAC_SHA256,
+ },
+
+ /* Cipher 67 */
+ {
+ TLS1_TXT_DHE_RSA_WITH_AES_128_SHA256,
+ TLS1_CK_DHE_RSA_WITH_AES_128_SHA256,
+ SSL_kDHE,
+ SSL_aRSA,
+ SSL_AES128,
+ SSL_SHA256,
+ SSL_HANDSHAKE_MAC_SHA256,
+ },
+
+ /* Cipher 6B */
+ {
+ TLS1_TXT_DHE_RSA_WITH_AES_256_SHA256,
+ TLS1_CK_DHE_RSA_WITH_AES_256_SHA256,
+ SSL_kDHE,
+ SSL_aRSA,
+ SSL_AES256,
+ SSL_SHA256,
+ SSL_HANDSHAKE_MAC_SHA256,
+ },
+
+ /* PSK cipher suites. */
+
+ /* Cipher 8C */
+ {
+ TLS1_TXT_PSK_WITH_AES_128_CBC_SHA,
+ TLS1_CK_PSK_WITH_AES_128_CBC_SHA,
+ SSL_kPSK,
+ SSL_aPSK,
+ SSL_AES128,
+ SSL_SHA1,
+ SSL_HANDSHAKE_MAC_DEFAULT,
+ },
+
+ /* Cipher 8D */
+ {
+ TLS1_TXT_PSK_WITH_AES_256_CBC_SHA,
+ TLS1_CK_PSK_WITH_AES_256_CBC_SHA,
+ SSL_kPSK,
+ SSL_aPSK,
+ SSL_AES256,
+ SSL_SHA1,
+ SSL_HANDSHAKE_MAC_DEFAULT,
+ },
+
+ /* GCM ciphersuites from RFC5288 */
+
+ /* Cipher 9C */
+ {
+ TLS1_TXT_RSA_WITH_AES_128_GCM_SHA256,
+ TLS1_CK_RSA_WITH_AES_128_GCM_SHA256,
+ SSL_kRSA,
+ SSL_aRSA,
+ SSL_AES128GCM,
+ SSL_AEAD,
+ SSL_HANDSHAKE_MAC_SHA256,
+ },
+
+ /* Cipher 9D */
+ {
+ TLS1_TXT_RSA_WITH_AES_256_GCM_SHA384,
+ TLS1_CK_RSA_WITH_AES_256_GCM_SHA384,
+ SSL_kRSA,
+ SSL_aRSA,
+ SSL_AES256GCM,
+ SSL_AEAD,
+ SSL_HANDSHAKE_MAC_SHA384,
+ },
+
+ /* Cipher 9E */
+ {
+ TLS1_TXT_DHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS1_CK_DHE_RSA_WITH_AES_128_GCM_SHA256,
+ SSL_kDHE,
+ SSL_aRSA,
+ SSL_AES128GCM,
+ SSL_AEAD,
+ SSL_HANDSHAKE_MAC_SHA256,
+ },
+
+ /* Cipher 9F */
+ {
+ TLS1_TXT_DHE_RSA_WITH_AES_256_GCM_SHA384,
+ TLS1_CK_DHE_RSA_WITH_AES_256_GCM_SHA384,
+ SSL_kDHE,
+ SSL_aRSA,
+ SSL_AES256GCM,
+ SSL_AEAD,
+ SSL_HANDSHAKE_MAC_SHA384,
+ },
+
+ /* TLS 1.3 suites. */
+
+ /* Cipher 1301 */
+ {
+ TLS1_TXT_AES_128_GCM_SHA256,
+ TLS1_CK_AES_128_GCM_SHA256,
+ SSL_kGENERIC,
+ SSL_aGENERIC,
+ SSL_AES128GCM,
+ SSL_AEAD,
+ SSL_HANDSHAKE_MAC_SHA256,
+ },
+
+ /* Cipher 1302 */
+ {
+ TLS1_TXT_AES_256_GCM_SHA384,
+ TLS1_CK_AES_256_GCM_SHA384,
+ SSL_kGENERIC,
+ SSL_aGENERIC,
+ SSL_AES256GCM,
+ SSL_AEAD,
+ SSL_HANDSHAKE_MAC_SHA384,
+ },
+
+ /* Cipher 1303 */
+ {
+ TLS1_TXT_CHACHA20_POLY1305_SHA256,
+ TLS1_CK_CHACHA20_POLY1305_SHA256,
+ SSL_kGENERIC,
+ SSL_aGENERIC,
+ SSL_CHACHA20POLY1305,
+ SSL_AEAD,
+ SSL_HANDSHAKE_MAC_SHA256,
+ },
+
+ /* Cipher C009 */
+ {
+ TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ TLS1_CK_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ SSL_kECDHE,
+ SSL_aECDSA,
+ SSL_AES128,
+ SSL_SHA1,
+ SSL_HANDSHAKE_MAC_DEFAULT,
+ },
+
+ /* Cipher C00A */
+ {
+ TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+ TLS1_CK_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+ SSL_kECDHE,
+ SSL_aECDSA,
+ SSL_AES256,
+ SSL_SHA1,
+ SSL_HANDSHAKE_MAC_DEFAULT,
+ },
+
+ /* Cipher C013 */
+ {
+ TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS1_CK_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ SSL_kECDHE,
+ SSL_aRSA,
+ SSL_AES128,
+ SSL_SHA1,
+ SSL_HANDSHAKE_MAC_DEFAULT,
+ },
+
+ /* Cipher C014 */
+ {
+ TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS1_CK_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ SSL_kECDHE,
+ SSL_aRSA,
+ SSL_AES256,
+ SSL_SHA1,
+ SSL_HANDSHAKE_MAC_DEFAULT,
+ },
+
+
+ /* HMAC based TLS v1.2 ciphersuites from RFC5289 */
+
+ /* Cipher C023 */
+ {
+ TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_SHA256,
+ TLS1_CK_ECDHE_ECDSA_WITH_AES_128_SHA256,
+ SSL_kECDHE,
+ SSL_aECDSA,
+ SSL_AES128,
+ SSL_SHA256,
+ SSL_HANDSHAKE_MAC_SHA256,
+ },
+
+ /* Cipher C024 */
+ {
+ TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_SHA384,
+ TLS1_CK_ECDHE_ECDSA_WITH_AES_256_SHA384,
+ SSL_kECDHE,
+ SSL_aECDSA,
+ SSL_AES256,
+ SSL_SHA384,
+ SSL_HANDSHAKE_MAC_SHA384,
+ },
+
+ /* Cipher C027 */
+ {
+ TLS1_TXT_ECDHE_RSA_WITH_AES_128_SHA256,
+ TLS1_CK_ECDHE_RSA_WITH_AES_128_SHA256,
+ SSL_kECDHE,
+ SSL_aRSA,
+ SSL_AES128,
+ SSL_SHA256,
+ SSL_HANDSHAKE_MAC_SHA256,
+ },
+
+ /* Cipher C028 */
+ {
+ TLS1_TXT_ECDHE_RSA_WITH_AES_256_SHA384,
+ TLS1_CK_ECDHE_RSA_WITH_AES_256_SHA384,
+ SSL_kECDHE,
+ SSL_aRSA,
+ SSL_AES256,
+ SSL_SHA384,
+ SSL_HANDSHAKE_MAC_SHA384,
+ },
+
+
+ /* GCM based TLS v1.2 ciphersuites from RFC5289 */
+
+ /* Cipher C02B */
+ {
+ TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ SSL_kECDHE,
+ SSL_aECDSA,
+ SSL_AES128GCM,
+ SSL_AEAD,
+ SSL_HANDSHAKE_MAC_SHA256,
+ },
+
+ /* Cipher C02C */
+ {
+ TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ SSL_kECDHE,
+ SSL_aECDSA,
+ SSL_AES256GCM,
+ SSL_AEAD,
+ SSL_HANDSHAKE_MAC_SHA384,
+ },
+
+ /* Cipher C02F */
+ {
+ TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ SSL_kECDHE,
+ SSL_aRSA,
+ SSL_AES128GCM,
+ SSL_AEAD,
+ SSL_HANDSHAKE_MAC_SHA256,
+ },
+
+ /* Cipher C030 */
+ {
+ TLS1_TXT_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ SSL_kECDHE,
+ SSL_aRSA,
+ SSL_AES256GCM,
+ SSL_AEAD,
+ SSL_HANDSHAKE_MAC_SHA384,
+ },
+
+ /* ECDHE-PSK cipher suites. */
+
+ /* Cipher C035 */
+ {
+ TLS1_TXT_ECDHE_PSK_WITH_AES_128_CBC_SHA,
+ TLS1_CK_ECDHE_PSK_WITH_AES_128_CBC_SHA,
+ SSL_kECDHE,
+ SSL_aPSK,
+ SSL_AES128,
+ SSL_SHA1,
+ SSL_HANDSHAKE_MAC_DEFAULT,
+ },
+
+ /* Cipher C036 */
+ {
+ TLS1_TXT_ECDHE_PSK_WITH_AES_256_CBC_SHA,
+ TLS1_CK_ECDHE_PSK_WITH_AES_256_CBC_SHA,
+ SSL_kECDHE,
+ SSL_aPSK,
+ SSL_AES256,
+ SSL_SHA1,
+ SSL_HANDSHAKE_MAC_DEFAULT,
+ },
+
+ /* ChaCha20-Poly1305 cipher suites. */
+
+ /* Cipher CCA8 */
+ {
+ TLS1_TXT_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
+ TLS1_CK_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
+ SSL_kECDHE,
+ SSL_aRSA,
+ SSL_CHACHA20POLY1305,
+ SSL_AEAD,
+ SSL_HANDSHAKE_MAC_SHA256,
+ },
+
+ /* Cipher CCA9 */
+ {
+ TLS1_TXT_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
+ TLS1_CK_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
+ SSL_kECDHE,
+ SSL_aECDSA,
+ SSL_CHACHA20POLY1305,
+ SSL_AEAD,
+ SSL_HANDSHAKE_MAC_SHA256,
+ },
+
+ /* Cipher CCAB */
+ {
+ TLS1_TXT_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256,
+ TLS1_CK_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256,
+ SSL_kECDHE,
+ SSL_aPSK,
+ SSL_CHACHA20POLY1305,
+ SSL_AEAD,
+ SSL_HANDSHAKE_MAC_SHA256,
+ },
+
+};
+
+static const size_t kCiphersLen = OPENSSL_ARRAY_SIZE(kCiphers);
+
+#define CIPHER_ADD 1
+#define CIPHER_KILL 2
+#define CIPHER_DEL 3
+#define CIPHER_ORD 4
+#define CIPHER_SPECIAL 5
+
+typedef struct cipher_order_st {
+ const SSL_CIPHER *cipher;
+ int active;
+ int in_group;
+ struct cipher_order_st *next, *prev;
+} CIPHER_ORDER;
+
+typedef struct cipher_alias_st {
+ /* name is the name of the cipher alias. */
+ const char *name;
+
+ /* The following fields are bitmasks for the corresponding fields on
+ * |SSL_CIPHER|. A cipher matches a cipher alias iff, for each bitmask, the
+ * bit corresponding to the cipher's value is set to 1. If any bitmask is
+ * all zeroes, the alias matches nothing. Use |~0u| for the default value. */
+ uint32_t algorithm_mkey;
+ uint32_t algorithm_auth;
+ uint32_t algorithm_enc;
+ uint32_t algorithm_mac;
+
+ /* min_version, if non-zero, matches all ciphers which were added in that
+ * particular protocol version. */
+ uint16_t min_version;
+} CIPHER_ALIAS;
+
+static const CIPHER_ALIAS kCipherAliases[] = {
+ /* "ALL" doesn't include eNULL. It must be explicitly enabled. */
+ {"ALL", ~0u, ~0u, ~SSL_eNULL, ~0u, 0},
+
+ /* The "COMPLEMENTOFDEFAULT" rule is omitted. It matches nothing. */
+
+ /* key exchange aliases
+ * (some of those using only a single bit here combine
+ * multiple key exchange algs according to the RFCs,
+ * e.g. kEDH combines DHE_DSS and DHE_RSA) */
+ {"kRSA", SSL_kRSA, ~0u, ~0u, ~0u, 0},
+
+ {"kDHE", SSL_kDHE, ~0u, ~0u, ~0u, 0},
+ {"kEDH", SSL_kDHE, ~0u, ~0u, ~0u, 0},
+ {"DH", SSL_kDHE, ~0u, ~0u, ~0u, 0},
+
+ {"kECDHE", SSL_kECDHE, ~0u, ~0u, ~0u, 0},
+ {"kEECDH", SSL_kECDHE, ~0u, ~0u, ~0u, 0},
+ {"ECDH", SSL_kECDHE, ~0u, ~0u, ~0u, 0},
+
+ {"kPSK", SSL_kPSK, ~0u, ~0u, ~0u, 0},
+
+ /* server authentication aliases */
+ {"aRSA", ~0u, SSL_aRSA, ~SSL_eNULL, ~0u, 0},
+ {"aECDSA", ~0u, SSL_aECDSA, ~0u, ~0u, 0},
+ {"ECDSA", ~0u, SSL_aECDSA, ~0u, ~0u, 0},
+ {"aPSK", ~0u, SSL_aPSK, ~0u, ~0u, 0},
+
+ /* aliases combining key exchange and server authentication */
+ {"DHE", SSL_kDHE, ~0u, ~0u, ~0u, 0},
+ {"EDH", SSL_kDHE, ~0u, ~0u, ~0u, 0},
+ {"ECDHE", SSL_kECDHE, ~0u, ~0u, ~0u, 0},
+ {"EECDH", SSL_kECDHE, ~0u, ~0u, ~0u, 0},
+ {"RSA", SSL_kRSA, SSL_aRSA, ~SSL_eNULL, ~0u, 0},
+ {"PSK", SSL_kPSK, SSL_aPSK, ~0u, ~0u, 0},
+
+ /* symmetric encryption aliases */
+ {"3DES", ~0u, ~0u, SSL_3DES, ~0u, 0},
+ {"AES128", ~0u, ~0u, SSL_AES128 | SSL_AES128GCM, ~0u, 0},
+ {"AES256", ~0u, ~0u, SSL_AES256 | SSL_AES256GCM, ~0u, 0},
+ {"AES", ~0u, ~0u, SSL_AES, ~0u, 0},
+ {"AESGCM", ~0u, ~0u, SSL_AES128GCM | SSL_AES256GCM, ~0u, 0},
+ {"CHACHA20", ~0u, ~0u, SSL_CHACHA20POLY1305, ~0u, 0},
+
+ /* MAC aliases */
+ {"SHA1", ~0u, ~0u, ~SSL_eNULL, SSL_SHA1, 0},
+ {"SHA", ~0u, ~0u, ~SSL_eNULL, SSL_SHA1, 0},
+ {"SHA256", ~0u, ~0u, ~0u, SSL_SHA256, 0},
+ {"SHA384", ~0u, ~0u, ~0u, SSL_SHA384, 0},
+
+ /* Legacy protocol minimum version aliases. "TLSv1" is intentionally the
+ * same as "SSLv3". */
+ {"SSLv3", ~0u, ~0u, ~SSL_eNULL, ~0u, SSL3_VERSION},
+ {"TLSv1", ~0u, ~0u, ~SSL_eNULL, ~0u, SSL3_VERSION},
+ {"TLSv1.2", ~0u, ~0u, ~SSL_eNULL, ~0u, TLS1_2_VERSION},
+
+ /* Legacy strength classes. */
+ {"HIGH", ~0u, ~0u, ~SSL_eNULL, ~0u, 0},
+ {"FIPS", ~0u, ~0u, ~SSL_eNULL, ~0u, 0},
+};
+
+static const size_t kCipherAliasesLen = OPENSSL_ARRAY_SIZE(kCipherAliases);
+
+static int ssl_cipher_id_cmp(const void *in_a, const void *in_b) {
+ const SSL_CIPHER *a = in_a;
+ const SSL_CIPHER *b = in_b;
+
+ if (a->id > b->id) {
+ return 1;
+ } else if (a->id < b->id) {
+ return -1;
+ } else {
+ return 0;
+ }
+}
+
+const SSL_CIPHER *SSL_get_cipher_by_value(uint16_t value) {
+ SSL_CIPHER c;
+
+ c.id = 0x03000000L | value;
+ return bsearch(&c, kCiphers, kCiphersLen, sizeof(SSL_CIPHER),
+ ssl_cipher_id_cmp);
+}
+
+int ssl_cipher_get_evp_aead(const EVP_AEAD **out_aead,
+ size_t *out_mac_secret_len,
+ size_t *out_fixed_iv_len,
+ const SSL_CIPHER *cipher, uint16_t version) {
+ *out_aead = NULL;
+ *out_mac_secret_len = 0;
+ *out_fixed_iv_len = 0;
+
+ if (cipher->algorithm_mac == SSL_AEAD) {
+ if (cipher->algorithm_enc == SSL_AES128GCM) {
+ *out_aead = EVP_aead_aes_128_gcm();
+ *out_fixed_iv_len = 4;
+ } else if (cipher->algorithm_enc == SSL_AES256GCM) {
+ *out_aead = EVP_aead_aes_256_gcm();
+ *out_fixed_iv_len = 4;
+ } else if (cipher->algorithm_enc == SSL_CHACHA20POLY1305) {
+ *out_aead = EVP_aead_chacha20_poly1305();
+ *out_fixed_iv_len = 12;
+ } else {
+ return 0;
+ }
+
+ /* In TLS 1.3, the iv_len is equal to the AEAD nonce length whereas the code
+ * above computes the TLS 1.2 construction. */
+ if (version >= TLS1_3_VERSION) {
+ *out_fixed_iv_len = EVP_AEAD_nonce_length(*out_aead);
+ }
+ } else if (cipher->algorithm_mac == SSL_SHA1) {
+ if (cipher->algorithm_enc == SSL_eNULL) {
+ if (version == SSL3_VERSION) {
+ *out_aead = EVP_aead_null_sha1_ssl3();
+ } else {
+ *out_aead = EVP_aead_null_sha1_tls();
+ }
+ } else if (cipher->algorithm_enc == SSL_3DES) {
+ if (version == SSL3_VERSION) {
+ *out_aead = EVP_aead_des_ede3_cbc_sha1_ssl3();
+ *out_fixed_iv_len = 8;
+ } else if (version == TLS1_VERSION) {
+ *out_aead = EVP_aead_des_ede3_cbc_sha1_tls_implicit_iv();
+ *out_fixed_iv_len = 8;
+ } else {
+ *out_aead = EVP_aead_des_ede3_cbc_sha1_tls();
+ }
+ } else if (cipher->algorithm_enc == SSL_AES128) {
+ if (version == SSL3_VERSION) {
+ *out_aead = EVP_aead_aes_128_cbc_sha1_ssl3();
+ *out_fixed_iv_len = 16;
+ } else if (version == TLS1_VERSION) {
+ *out_aead = EVP_aead_aes_128_cbc_sha1_tls_implicit_iv();
+ *out_fixed_iv_len = 16;
+ } else {
+ *out_aead = EVP_aead_aes_128_cbc_sha1_tls();
+ }
+ } else if (cipher->algorithm_enc == SSL_AES256) {
+ if (version == SSL3_VERSION) {
+ *out_aead = EVP_aead_aes_256_cbc_sha1_ssl3();
+ *out_fixed_iv_len = 16;
+ } else if (version == TLS1_VERSION) {
+ *out_aead = EVP_aead_aes_256_cbc_sha1_tls_implicit_iv();
+ *out_fixed_iv_len = 16;
+ } else {
+ *out_aead = EVP_aead_aes_256_cbc_sha1_tls();
+ }
+ } else {
+ return 0;
+ }
+
+ *out_mac_secret_len = SHA_DIGEST_LENGTH;
+ } else if (cipher->algorithm_mac == SSL_SHA256) {
+ if (cipher->algorithm_enc == SSL_AES128) {
+ *out_aead = EVP_aead_aes_128_cbc_sha256_tls();
+ } else if (cipher->algorithm_enc == SSL_AES256) {
+ *out_aead = EVP_aead_aes_256_cbc_sha256_tls();
+ } else {
+ return 0;
+ }
+
+ *out_mac_secret_len = SHA256_DIGEST_LENGTH;
+ } else if (cipher->algorithm_mac == SSL_SHA384) {
+ if (cipher->algorithm_enc != SSL_AES256) {
+ return 0;
+ }
+
+ *out_aead = EVP_aead_aes_256_cbc_sha384_tls();
+ *out_mac_secret_len = SHA384_DIGEST_LENGTH;
+ } else {
+ return 0;
+ }
+
+ return 1;
+}
+
+const EVP_MD *ssl_get_handshake_digest(uint32_t algorithm_prf,
+ uint16_t version) {
+ switch (algorithm_prf) {
+ case SSL_HANDSHAKE_MAC_DEFAULT:
+ return version >= TLS1_2_VERSION ? EVP_sha256() : EVP_md5_sha1();
+ case SSL_HANDSHAKE_MAC_SHA256:
+ return EVP_sha256();
+ case SSL_HANDSHAKE_MAC_SHA384:
+ return EVP_sha384();
+ default:
+ return NULL;
+ }
+}
+
+#define ITEM_SEP(a) \
+ (((a) == ':') || ((a) == ' ') || ((a) == ';') || ((a) == ','))
+
+/* rule_equals returns one iff the NUL-terminated string |rule| is equal to the
+ * |buf_len| bytes at |buf|. */
+static int rule_equals(const char *rule, const char *buf, size_t buf_len) {
+ /* |strncmp| alone only checks that |buf| is a prefix of |rule|. */
+ return strncmp(rule, buf, buf_len) == 0 && rule[buf_len] == '\0';
+}
+
+static void ll_append_tail(CIPHER_ORDER **head, CIPHER_ORDER *curr,
+ CIPHER_ORDER **tail) {
+ if (curr == *tail) {
+ return;
+ }
+ if (curr == *head) {
+ *head = curr->next;
+ }
+ if (curr->prev != NULL) {
+ curr->prev->next = curr->next;
+ }
+ if (curr->next != NULL) {
+ curr->next->prev = curr->prev;
+ }
+ (*tail)->next = curr;
+ curr->prev = *tail;
+ curr->next = NULL;
+ *tail = curr;
+}
+
+static void ll_append_head(CIPHER_ORDER **head, CIPHER_ORDER *curr,
+ CIPHER_ORDER **tail) {
+ if (curr == *head) {
+ return;
+ }
+ if (curr == *tail) {
+ *tail = curr->prev;
+ }
+ if (curr->next != NULL) {
+ curr->next->prev = curr->prev;
+ }
+ if (curr->prev != NULL) {
+ curr->prev->next = curr->next;
+ }
+ (*head)->prev = curr;
+ curr->next = *head;
+ curr->prev = NULL;
+ *head = curr;
+}
+
+static void ssl_cipher_collect_ciphers(const SSL_PROTOCOL_METHOD *ssl_method,
+ CIPHER_ORDER *co_list,
+ CIPHER_ORDER **head_p,
+ CIPHER_ORDER **tail_p) {
+ /* The set of ciphers is static, but some subset may be unsupported by
+ * |ssl_method|, so the list may be smaller. */
+ size_t co_list_num = 0;
+ for (size_t i = 0; i < kCiphersLen; i++) {
+ const SSL_CIPHER *cipher = &kCiphers[i];
+ if (ssl_method->supports_cipher(cipher) &&
+ /* TLS 1.3 ciphers do not participate in this mechanism. */
+ cipher->algorithm_mkey != SSL_kGENERIC) {
+ co_list[co_list_num].cipher = cipher;
+ co_list[co_list_num].next = NULL;
+ co_list[co_list_num].prev = NULL;
+ co_list[co_list_num].active = 0;
+ co_list[co_list_num].in_group = 0;
+ co_list_num++;
+ }
+ }
+
+ /* Prepare linked list from list entries. */
+ if (co_list_num > 0) {
+ co_list[0].prev = NULL;
+
+ if (co_list_num > 1) {
+ co_list[0].next = &co_list[1];
+
+ for (size_t i = 1; i < co_list_num - 1; i++) {
+ co_list[i].prev = &co_list[i - 1];
+ co_list[i].next = &co_list[i + 1];
+ }
+
+ co_list[co_list_num - 1].prev = &co_list[co_list_num - 2];
+ }
+
+ co_list[co_list_num - 1].next = NULL;
+
+ *head_p = &co_list[0];
+ *tail_p = &co_list[co_list_num - 1];
+ }
+}
+
+/* ssl_cipher_apply_rule applies the rule type |rule| to ciphers matching its
+ * parameters in the linked list from |*head_p| to |*tail_p|. It writes the new
+ * head and tail of the list to |*head_p| and |*tail_p|, respectively.
+ *
+ * - If |cipher_id| is non-zero, only that cipher is selected.
+ * - Otherwise, if |strength_bits| is non-negative, it selects ciphers
+ * of that strength.
+ * - Otherwise, it selects ciphers that match each bitmasks in |alg_*| and
+ * |min_version|. */
+static void ssl_cipher_apply_rule(
+ uint32_t cipher_id, uint32_t alg_mkey, uint32_t alg_auth,
+ uint32_t alg_enc, uint32_t alg_mac, uint16_t min_version, int rule,
+ int strength_bits, int in_group, CIPHER_ORDER **head_p,
+ CIPHER_ORDER **tail_p) {
+ CIPHER_ORDER *head, *tail, *curr, *next, *last;
+ const SSL_CIPHER *cp;
+ int reverse = 0;
+
+ if (cipher_id == 0 && strength_bits == -1 && min_version == 0 &&
+ (alg_mkey == 0 || alg_auth == 0 || alg_enc == 0 || alg_mac == 0)) {
+ /* The rule matches nothing, so bail early. */
+ return;
+ }
+
+ if (rule == CIPHER_DEL) {
+ /* needed to maintain sorting between currently deleted ciphers */
+ reverse = 1;
+ }
+
+ head = *head_p;
+ tail = *tail_p;
+
+ if (reverse) {
+ next = tail;
+ last = head;
+ } else {
+ next = head;
+ last = tail;
+ }
+
+ curr = NULL;
+ for (;;) {
+ if (curr == last) {
+ break;
+ }
+
+ curr = next;
+ if (curr == NULL) {
+ break;
+ }
+
+ next = reverse ? curr->prev : curr->next;
+ cp = curr->cipher;
+
+ /* Selection criteria is either a specific cipher, the value of
+ * |strength_bits|, or the algorithms used. */
+ if (cipher_id != 0) {
+ if (cipher_id != cp->id) {
+ continue;
+ }
+ } else if (strength_bits >= 0) {
+ if (strength_bits != SSL_CIPHER_get_bits(cp, NULL)) {
+ continue;
+ }
+ } else {
+ if (!(alg_mkey & cp->algorithm_mkey) ||
+ !(alg_auth & cp->algorithm_auth) ||
+ !(alg_enc & cp->algorithm_enc) ||
+ !(alg_mac & cp->algorithm_mac) ||
+ (min_version != 0 && SSL_CIPHER_get_min_version(cp) != min_version)) {
+ continue;
+ }
+ }
+
+ /* add the cipher if it has not been added yet. */
+ if (rule == CIPHER_ADD) {
+ /* reverse == 0 */
+ if (!curr->active) {
+ ll_append_tail(&head, curr, &tail);
+ curr->active = 1;
+ curr->in_group = in_group;
+ }
+ }
+
+ /* Move the added cipher to this location */
+ else if (rule == CIPHER_ORD) {
+ /* reverse == 0 */
+ if (curr->active) {
+ ll_append_tail(&head, curr, &tail);
+ curr->in_group = 0;
+ }
+ } else if (rule == CIPHER_DEL) {
+ /* reverse == 1 */
+ if (curr->active) {
+ /* most recently deleted ciphersuites get best positions
+ * for any future CIPHER_ADD (note that the CIPHER_DEL loop
+ * works in reverse to maintain the order) */
+ ll_append_head(&head, curr, &tail);
+ curr->active = 0;
+ curr->in_group = 0;
+ }
+ } else if (rule == CIPHER_KILL) {
+ /* reverse == 0 */
+ if (head == curr) {
+ head = curr->next;
+ } else {
+ curr->prev->next = curr->next;
+ }
+
+ if (tail == curr) {
+ tail = curr->prev;
+ }
+ curr->active = 0;
+ if (curr->next != NULL) {
+ curr->next->prev = curr->prev;
+ }
+ if (curr->prev != NULL) {
+ curr->prev->next = curr->next;
+ }
+ curr->next = NULL;
+ curr->prev = NULL;
+ }
+ }
+
+ *head_p = head;
+ *tail_p = tail;
+}
+
+static int ssl_cipher_strength_sort(CIPHER_ORDER **head_p,
+ CIPHER_ORDER **tail_p) {
+ int max_strength_bits, i, *number_uses;
+ CIPHER_ORDER *curr;
+
+ /* This routine sorts the ciphers with descending strength. The sorting must
+ * keep the pre-sorted sequence, so we apply the normal sorting routine as
+ * '+' movement to the end of the list. */
+ max_strength_bits = 0;
+ curr = *head_p;
+ while (curr != NULL) {
+ if (curr->active &&
+ SSL_CIPHER_get_bits(curr->cipher, NULL) > max_strength_bits) {
+ max_strength_bits = SSL_CIPHER_get_bits(curr->cipher, NULL);
+ }
+ curr = curr->next;
+ }
+
+ number_uses = OPENSSL_malloc((max_strength_bits + 1) * sizeof(int));
+ if (!number_uses) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ OPENSSL_memset(number_uses, 0, (max_strength_bits + 1) * sizeof(int));
+
+ /* Now find the strength_bits values actually used. */
+ curr = *head_p;
+ while (curr != NULL) {
+ if (curr->active) {
+ number_uses[SSL_CIPHER_get_bits(curr->cipher, NULL)]++;
+ }
+ curr = curr->next;
+ }
+
+ /* Go through the list of used strength_bits values in descending order. */
+ for (i = max_strength_bits; i >= 0; i--) {
+ if (number_uses[i] > 0) {
+ ssl_cipher_apply_rule(0, 0, 0, 0, 0, 0, CIPHER_ORD, i, 0, head_p, tail_p);
+ }
+ }
+
+ OPENSSL_free(number_uses);
+ return 1;
+}
+
+static int ssl_cipher_process_rulestr(const SSL_PROTOCOL_METHOD *ssl_method,
+ const char *rule_str,
+ CIPHER_ORDER **head_p,
+ CIPHER_ORDER **tail_p, int strict) {
+ uint32_t alg_mkey, alg_auth, alg_enc, alg_mac;
+ uint16_t min_version;
+ const char *l, *buf;
+ int multi, skip_rule, rule, ok, in_group = 0, has_group = 0;
+ size_t j, buf_len;
+ uint32_t cipher_id;
+ char ch;
+
+ l = rule_str;
+ for (;;) {
+ ch = *l;
+
+ if (ch == '\0') {
+ break; /* done */
+ }
+
+ if (in_group) {
+ if (ch == ']') {
+ if (*tail_p) {
+ (*tail_p)->in_group = 0;
+ }
+ in_group = 0;
+ l++;
+ continue;
+ }
+
+ if (ch == '|') {
+ rule = CIPHER_ADD;
+ l++;
+ continue;
+ } else if (!(ch >= 'a' && ch <= 'z') && !(ch >= 'A' && ch <= 'Z') &&
+ !(ch >= '0' && ch <= '9')) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_OPERATOR_IN_GROUP);
+ return 0;
+ } else {
+ rule = CIPHER_ADD;
+ }
+ } else if (ch == '-') {
+ rule = CIPHER_DEL;
+ l++;
+ } else if (ch == '+') {
+ rule = CIPHER_ORD;
+ l++;
+ } else if (ch == '!') {
+ rule = CIPHER_KILL;
+ l++;
+ } else if (ch == '@') {
+ rule = CIPHER_SPECIAL;
+ l++;
+ } else if (ch == '[') {
+ if (in_group) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NESTED_GROUP);
+ return 0;
+ }
+ in_group = 1;
+ has_group = 1;
+ l++;
+ continue;
+ } else {
+ rule = CIPHER_ADD;
+ }
+
+ /* If preference groups are enabled, the only legal operator is +.
+ * Otherwise the in_group bits will get mixed up. */
+ if (has_group && rule != CIPHER_ADD) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_MIXED_SPECIAL_OPERATOR_WITH_GROUPS);
+ return 0;
+ }
+
+ if (ITEM_SEP(ch)) {
+ l++;
+ continue;
+ }
+
+ multi = 0;
+ cipher_id = 0;
+ alg_mkey = ~0u;
+ alg_auth = ~0u;
+ alg_enc = ~0u;
+ alg_mac = ~0u;
+ min_version = 0;
+ skip_rule = 0;
+
+ for (;;) {
+ ch = *l;
+ buf = l;
+ buf_len = 0;
+ while (((ch >= 'A') && (ch <= 'Z')) || ((ch >= '0') && (ch <= '9')) ||
+ ((ch >= 'a') && (ch <= 'z')) || (ch == '-') || (ch == '.')) {
+ ch = *(++l);
+ buf_len++;
+ }
+
+ if (buf_len == 0) {
+ /* We hit something we cannot deal with, it is no command or separator
+ * nor alphanumeric, so we call this an error. */
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_COMMAND);
+ return 0;
+ }
+
+ if (rule == CIPHER_SPECIAL) {
+ break;
+ }
+
+ /* Look for a matching exact cipher. These aren't allowed in multipart
+ * rules. */
+ if (!multi && ch != '+') {
+ for (j = 0; j < kCiphersLen; j++) {
+ const SSL_CIPHER *cipher = &kCiphers[j];
+ if (rule_equals(cipher->name, buf, buf_len)) {
+ cipher_id = cipher->id;
+ break;
+ }
+ }
+ }
+ if (cipher_id == 0) {
+ /* If not an exact cipher, look for a matching cipher alias. */
+ for (j = 0; j < kCipherAliasesLen; j++) {
+ if (rule_equals(kCipherAliases[j].name, buf, buf_len)) {
+ alg_mkey &= kCipherAliases[j].algorithm_mkey;
+ alg_auth &= kCipherAliases[j].algorithm_auth;
+ alg_enc &= kCipherAliases[j].algorithm_enc;
+ alg_mac &= kCipherAliases[j].algorithm_mac;
+
+ if (min_version != 0 &&
+ min_version != kCipherAliases[j].min_version) {
+ skip_rule = 1;
+ } else {
+ min_version = kCipherAliases[j].min_version;
+ }
+ break;
+ }
+ }
+ if (j == kCipherAliasesLen) {
+ skip_rule = 1;
+ if (strict) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_COMMAND);
+ return 0;
+ }
+ }
+ }
+
+ /* Check for a multipart rule. */
+ if (ch != '+') {
+ break;
+ }
+ l++;
+ multi = 1;
+ }
+
+ /* Ok, we have the rule, now apply it. */
+ if (rule == CIPHER_SPECIAL) {
+ /* special command */
+ ok = 0;
+ if (buf_len == 8 && !strncmp(buf, "STRENGTH", 8)) {
+ ok = ssl_cipher_strength_sort(head_p, tail_p);
+ } else {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_COMMAND);
+ }
+
+ if (ok == 0) {
+ return 0;
+ }
+
+ /* 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)) {
+ l++;
+ }
+ } else if (!skip_rule) {
+ ssl_cipher_apply_rule(cipher_id, alg_mkey, alg_auth, alg_enc, alg_mac,
+ min_version, rule, -1, in_group, head_p, tail_p);
+ }
+ }
+
+ if (in_group) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_COMMAND);
+ return 0;
+ }
+
+ return 1;
+}
+
+int ssl_create_cipher_list(
+ const SSL_PROTOCOL_METHOD *ssl_method,
+ struct ssl_cipher_preference_list_st **out_cipher_list,
+ const char *rule_str, int strict) {
+ STACK_OF(SSL_CIPHER) *cipherstack = NULL;
+ CIPHER_ORDER *co_list = NULL, *head = NULL, *tail = NULL, *curr;
+ uint8_t *in_group_flags = NULL;
+ unsigned int num_in_group_flags = 0;
+ struct ssl_cipher_preference_list_st *pref_list = NULL;
+
+ /* Return with error if nothing to do. */
+ if (rule_str == NULL || out_cipher_list == NULL) {
+ return 0;
+ }
+
+ /* Now we have to collect the available ciphers from the compiled in ciphers.
+ * We cannot get more than the number compiled in, so it is used for
+ * allocation. */
+ co_list = OPENSSL_malloc(sizeof(CIPHER_ORDER) * kCiphersLen);
+ if (co_list == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+
+ ssl_cipher_collect_ciphers(ssl_method, co_list, &head, &tail);
+
+ /* Now arrange all ciphers by preference:
+ * TODO(davidben): Compute this order once and copy it. */
+
+ /* Everything else being equal, prefer ECDHE_ECDSA and ECDHE_RSA over other
+ * key exchange mechanisms */
+ ssl_cipher_apply_rule(0, SSL_kECDHE, SSL_aECDSA, ~0u, ~0u, 0, CIPHER_ADD, -1,
+ 0, &head, &tail);
+ ssl_cipher_apply_rule(0, SSL_kECDHE, ~0u, ~0u, ~0u, 0, CIPHER_ADD, -1, 0,
+ &head, &tail);
+ ssl_cipher_apply_rule(0, ~0u, ~0u, ~0u, ~0u, 0, CIPHER_DEL, -1, 0, &head,
+ &tail);
+
+ /* Order the bulk ciphers. First the preferred AEAD ciphers. We prefer
+ * CHACHA20 unless there is hardware support for fast and constant-time
+ * AES_GCM. Of the two CHACHA20 variants, the new one is preferred over the
+ * old one. */
+ if (EVP_has_aes_hardware()) {
+ ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_AES128GCM, ~0u, 0, CIPHER_ADD, -1, 0,
+ &head, &tail);
+ ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_AES256GCM, ~0u, 0, CIPHER_ADD, -1, 0,
+ &head, &tail);
+ ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_CHACHA20POLY1305, ~0u, 0, CIPHER_ADD,
+ -1, 0, &head, &tail);
+ } else {
+ ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_CHACHA20POLY1305, ~0u, 0, CIPHER_ADD,
+ -1, 0, &head, &tail);
+ ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_AES128GCM, ~0u, 0, CIPHER_ADD, -1, 0,
+ &head, &tail);
+ ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_AES256GCM, ~0u, 0, CIPHER_ADD, -1, 0,
+ &head, &tail);
+ }
+
+ /* Then the legacy non-AEAD ciphers: AES_128_CBC, AES_256_CBC,
+ * 3DES_EDE_CBC_SHA. */
+ ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_AES128, ~0u, 0, CIPHER_ADD, -1, 0,
+ &head, &tail);
+ ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_AES256, ~0u, 0, CIPHER_ADD, -1, 0,
+ &head, &tail);
+ ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_3DES, ~0u, 0, CIPHER_ADD, -1, 0, &head,
+ &tail);
+
+ /* Temporarily enable everything else for sorting */
+ ssl_cipher_apply_rule(0, ~0u, ~0u, ~0u, ~0u, 0, CIPHER_ADD, -1, 0, &head,
+ &tail);
+
+ /* Move ciphers without forward secrecy to the end. */
+ ssl_cipher_apply_rule(0, (SSL_kRSA | SSL_kPSK), ~0u, ~0u, ~0u, 0,
+ CIPHER_ORD, -1, 0, &head, &tail);
+
+ /* Now disable everything (maintaining the ordering!) */
+ ssl_cipher_apply_rule(0, ~0u, ~0u, ~0u, ~0u, 0, CIPHER_DEL, -1, 0, &head,
+ &tail);
+
+ /* If the rule_string begins with DEFAULT, apply the default rule before
+ * using the (possibly available) additional rules. */
+ const char *rule_p = rule_str;
+ if (strncmp(rule_str, "DEFAULT", 7) == 0) {
+ if (!ssl_cipher_process_rulestr(ssl_method, SSL_DEFAULT_CIPHER_LIST, &head,
+ &tail, strict)) {
+ goto err;
+ }
+ rule_p += 7;
+ if (*rule_p == ':') {
+ rule_p++;
+ }
+ }
+
+ if (*rule_p != '\0' &&
+ !ssl_cipher_process_rulestr(ssl_method, rule_p, &head, &tail, strict)) {
+ goto err;
+ }
+
+ /* Allocate new "cipherstack" for the result, return with error
+ * if we cannot get one. */
+ cipherstack = sk_SSL_CIPHER_new_null();
+ if (cipherstack == NULL) {
+ goto err;
+ }
+
+ in_group_flags = OPENSSL_malloc(kCiphersLen);
+ if (!in_group_flags) {
+ goto err;
+ }
+
+ /* The cipher selection for the list is done. The ciphers are added
+ * to the resulting precedence to the STACK_OF(SSL_CIPHER). */
+ for (curr = head; curr != NULL; curr = curr->next) {
+ if (curr->active) {
+ if (!sk_SSL_CIPHER_push(cipherstack, curr->cipher)) {
+ goto err;
+ }
+ in_group_flags[num_in_group_flags++] = curr->in_group;
+ }
+ }
+ OPENSSL_free(co_list); /* Not needed any longer */
+ co_list = NULL;
+
+ pref_list = OPENSSL_malloc(sizeof(struct ssl_cipher_preference_list_st));
+ if (!pref_list) {
+ goto err;
+ }
+ pref_list->ciphers = cipherstack;
+ pref_list->in_group_flags = OPENSSL_malloc(num_in_group_flags);
+ if (!pref_list->in_group_flags) {
+ goto err;
+ }
+ OPENSSL_memcpy(pref_list->in_group_flags, in_group_flags, num_in_group_flags);
+ OPENSSL_free(in_group_flags);
+ in_group_flags = NULL;
+ if (*out_cipher_list != NULL) {
+ ssl_cipher_preference_list_free(*out_cipher_list);
+ }
+ *out_cipher_list = pref_list;
+ pref_list = NULL;
+
+ /* Configuring an empty cipher list is an error but still updates the
+ * output. */
+ if (sk_SSL_CIPHER_num((*out_cipher_list)->ciphers) == 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CIPHER_MATCH);
+ return 0;
+ }
+
+ return 1;
+
+err:
+ OPENSSL_free(co_list);
+ OPENSSL_free(in_group_flags);
+ sk_SSL_CIPHER_free(cipherstack);
+ if (pref_list) {
+ OPENSSL_free(pref_list->in_group_flags);
+ }
+ OPENSSL_free(pref_list);
+ return 0;
+}
+
+uint32_t SSL_CIPHER_get_id(const SSL_CIPHER *cipher) { return cipher->id; }
+
+uint16_t ssl_cipher_get_value(const SSL_CIPHER *cipher) {
+ uint32_t id = cipher->id;
+ /* All ciphers are SSLv3. */
+ assert((id & 0xff000000) == 0x03000000);
+ return id & 0xffff;
+}
+
+int SSL_CIPHER_is_AES(const SSL_CIPHER *cipher) {
+ return (cipher->algorithm_enc & SSL_AES) != 0;
+}
+
+int SSL_CIPHER_has_SHA1_HMAC(const SSL_CIPHER *cipher) {
+ return (cipher->algorithm_mac & SSL_SHA1) != 0;
+}
+
+int SSL_CIPHER_has_SHA256_HMAC(const SSL_CIPHER *cipher) {
+ return (cipher->algorithm_mac & SSL_SHA256) != 0;
+}
+
+int SSL_CIPHER_is_AEAD(const SSL_CIPHER *cipher) {
+ return (cipher->algorithm_mac & SSL_AEAD) != 0;
+}
+
+int SSL_CIPHER_is_AESGCM(const SSL_CIPHER *cipher) {
+ return (cipher->algorithm_enc & (SSL_AES128GCM | SSL_AES256GCM)) != 0;
+}
+
+int SSL_CIPHER_is_AES128GCM(const SSL_CIPHER *cipher) {
+ return (cipher->algorithm_enc & SSL_AES128GCM) != 0;
+}
+
+int SSL_CIPHER_is_AES128CBC(const SSL_CIPHER *cipher) {
+ return (cipher->algorithm_enc & SSL_AES128) != 0;
+}
+
+int SSL_CIPHER_is_AES256CBC(const SSL_CIPHER *cipher) {
+ return (cipher->algorithm_enc & SSL_AES256) != 0;
+}
+
+int SSL_CIPHER_is_CHACHA20POLY1305(const SSL_CIPHER *cipher) {
+ return (cipher->algorithm_enc & SSL_CHACHA20POLY1305) != 0;
+}
+
+int SSL_CIPHER_is_NULL(const SSL_CIPHER *cipher) {
+ return (cipher->algorithm_enc & SSL_eNULL) != 0;
+}
+
+int SSL_CIPHER_is_block_cipher(const SSL_CIPHER *cipher) {
+ return (cipher->algorithm_enc & SSL_eNULL) == 0 &&
+ cipher->algorithm_mac != SSL_AEAD;
+}
+
+int SSL_CIPHER_is_ECDSA(const SSL_CIPHER *cipher) {
+ return (cipher->algorithm_auth & SSL_aECDSA) != 0;
+}
+
+int SSL_CIPHER_is_DHE(const SSL_CIPHER *cipher) {
+ return (cipher->algorithm_mkey & SSL_kDHE) != 0;
+}
+
+int SSL_CIPHER_is_ECDHE(const SSL_CIPHER *cipher) {
+ return (cipher->algorithm_mkey & SSL_kECDHE) != 0;
+}
+
+int SSL_CIPHER_is_static_RSA(const SSL_CIPHER *cipher) {
+ return (cipher->algorithm_mkey & SSL_kRSA) != 0;
+}
+
+uint16_t SSL_CIPHER_get_min_version(const SSL_CIPHER *cipher) {
+ if (cipher->algorithm_mkey == SSL_kGENERIC ||
+ cipher->algorithm_auth == SSL_aGENERIC) {
+ return TLS1_3_VERSION;
+ }
+
+ if (cipher->algorithm_prf != SSL_HANDSHAKE_MAC_DEFAULT) {
+ /* Cipher suites before TLS 1.2 use the default PRF, while all those added
+ * afterwards specify a particular hash. */
+ return TLS1_2_VERSION;
+ }
+ return SSL3_VERSION;
+}
+
+uint16_t SSL_CIPHER_get_max_version(const SSL_CIPHER *cipher) {
+ if (cipher->algorithm_mkey == SSL_kGENERIC ||
+ cipher->algorithm_auth == SSL_aGENERIC) {
+ return TLS1_3_VERSION;
+ }
+ return TLS1_2_VERSION;
+}
+
+/* return the actual cipher being used */
+const char *SSL_CIPHER_get_name(const SSL_CIPHER *cipher) {
+ if (cipher != NULL) {
+ return cipher->name;
+ }
+
+ return "(NONE)";
+}
+
+const char *SSL_CIPHER_get_kx_name(const SSL_CIPHER *cipher) {
+ if (cipher == NULL) {
+ return "";
+ }
+
+ switch (cipher->algorithm_mkey) {
+ case SSL_kRSA:
+ return "RSA";
+
+ case SSL_kDHE:
+ switch (cipher->algorithm_auth) {
+ case SSL_aRSA:
+ return "DHE_RSA";
+ default:
+ assert(0);
+ return "UNKNOWN";
+ }
+
+ case SSL_kECDHE:
+ switch (cipher->algorithm_auth) {
+ case SSL_aECDSA:
+ return "ECDHE_ECDSA";
+ case SSL_aRSA:
+ return "ECDHE_RSA";
+ case SSL_aPSK:
+ return "ECDHE_PSK";
+ default:
+ assert(0);
+ return "UNKNOWN";
+ }
+
+ case SSL_kPSK:
+ assert(cipher->algorithm_auth == SSL_aPSK);
+ return "PSK";
+
+ case SSL_kGENERIC:
+ assert(cipher->algorithm_auth == SSL_aGENERIC);
+ return "GENERIC";
+
+ default:
+ assert(0);
+ return "UNKNOWN";
+ }
+}
+
+static const char *ssl_cipher_get_enc_name(const SSL_CIPHER *cipher) {
+ switch (cipher->algorithm_enc) {
+ case SSL_3DES:
+ return "3DES_EDE_CBC";
+ case SSL_AES128:
+ return "AES_128_CBC";
+ case SSL_AES256:
+ return "AES_256_CBC";
+ case SSL_AES128GCM:
+ return "AES_128_GCM";
+ case SSL_AES256GCM:
+ return "AES_256_GCM";
+ case SSL_CHACHA20POLY1305:
+ return "CHACHA20_POLY1305";
+ break;
+ default:
+ assert(0);
+ return "UNKNOWN";
+ }
+}
+
+static const char *ssl_cipher_get_prf_name(const SSL_CIPHER *cipher) {
+ switch (cipher->algorithm_prf) {
+ case SSL_HANDSHAKE_MAC_DEFAULT:
+ /* Before TLS 1.2, the PRF component is the hash used in the HMAC, which
+ * is SHA-1 for all supported ciphers. */
+ assert(cipher->algorithm_mac == SSL_SHA1);
+ return "SHA";
+ case SSL_HANDSHAKE_MAC_SHA256:
+ return "SHA256";
+ case SSL_HANDSHAKE_MAC_SHA384:
+ return "SHA384";
+ }
+ assert(0);
+ return "UNKNOWN";
+}
+
+char *SSL_CIPHER_get_rfc_name(const SSL_CIPHER *cipher) {
+ if (cipher == NULL) {
+ return NULL;
+ }
+
+ const char *kx_name = SSL_CIPHER_get_kx_name(cipher);
+ const char *enc_name = ssl_cipher_get_enc_name(cipher);
+ const char *prf_name = ssl_cipher_get_prf_name(cipher);
+
+ /* The final name is TLS_{kx_name}_WITH_{enc_name}_{prf_name} or
+ * TLS_{enc_name}_{prf_name} depending on whether the cipher is AEAD-only. */
+ size_t len = 4 + strlen(enc_name) + 1 + strlen(prf_name) + 1;
+
+ if (cipher->algorithm_mkey != SSL_kGENERIC) {
+ len += strlen(kx_name) + 6;
+ }
+
+ char *ret = OPENSSL_malloc(len);
+ if (ret == NULL) {
+ return NULL;
+ }
+
+ if (BUF_strlcpy(ret, "TLS_", len) >= len ||
+ (cipher->algorithm_mkey != SSL_kGENERIC &&
+ (BUF_strlcat(ret, kx_name, len) >= len ||
+ BUF_strlcat(ret, "_WITH_", len) >= len)) ||
+ BUF_strlcat(ret, enc_name, len) >= len ||
+ BUF_strlcat(ret, "_", len) >= len ||
+ BUF_strlcat(ret, prf_name, len) >= len) {
+ assert(0);
+ OPENSSL_free(ret);
+ return NULL;
+ }
+
+ assert(strlen(ret) + 1 == len);
+ return ret;
+}
+
+int SSL_CIPHER_get_bits(const SSL_CIPHER *cipher, int *out_alg_bits) {
+ if (cipher == NULL) {
+ return 0;
+ }
+
+ int alg_bits, strength_bits;
+ switch (cipher->algorithm_enc) {
+ case SSL_AES128:
+ case SSL_AES128GCM:
+ alg_bits = 128;
+ strength_bits = 128;
+ break;
+
+ case SSL_AES256:
+ case SSL_AES256GCM:
+ case SSL_CHACHA20POLY1305:
+ alg_bits = 256;
+ strength_bits = 256;
+ break;
+
+ case SSL_3DES:
+ alg_bits = 168;
+ strength_bits = 112;
+ break;
+
+ case SSL_eNULL:
+ alg_bits = 0;
+ strength_bits = 0;
+ break;
+
+ default:
+ assert(0);
+ alg_bits = 0;
+ strength_bits = 0;
+ }
+
+ if (out_alg_bits != NULL) {
+ *out_alg_bits = alg_bits;
+ }
+ return strength_bits;
+}
+
+const char *SSL_CIPHER_description(const SSL_CIPHER *cipher, char *buf,
+ int len) {
+ const char *kx, *au, *enc, *mac;
+ uint32_t alg_mkey, alg_auth, alg_enc, alg_mac;
+
+ alg_mkey = cipher->algorithm_mkey;
+ alg_auth = cipher->algorithm_auth;
+ alg_enc = cipher->algorithm_enc;
+ alg_mac = cipher->algorithm_mac;
+
+ switch (alg_mkey) {
+ case SSL_kRSA:
+ kx = "RSA";
+ break;
+
+ case SSL_kDHE:
+ kx = "DH";
+ break;
+
+ case SSL_kECDHE:
+ kx = "ECDH";
+ break;
+
+ case SSL_kPSK:
+ kx = "PSK";
+ break;
+
+ case SSL_kGENERIC:
+ kx = "GENERIC";
+ break;
+
+ default:
+ kx = "unknown";
+ }
+
+ switch (alg_auth) {
+ case SSL_aRSA:
+ au = "RSA";
+ break;
+
+ case SSL_aECDSA:
+ au = "ECDSA";
+ break;
+
+ case SSL_aPSK:
+ au = "PSK";
+ break;
+
+ case SSL_aGENERIC:
+ au = "GENERIC";
+ break;
+
+ default:
+ au = "unknown";
+ break;
+ }
+
+ switch (alg_enc) {
+ case SSL_3DES:
+ enc = "3DES(168)";
+ break;
+
+ case SSL_AES128:
+ enc = "AES(128)";
+ break;
+
+ case SSL_AES256:
+ enc = "AES(256)";
+ break;
+
+ case SSL_AES128GCM:
+ enc = "AESGCM(128)";
+ break;
+
+ case SSL_AES256GCM:
+ enc = "AESGCM(256)";
+ break;
+
+ case SSL_CHACHA20POLY1305:
+ enc = "ChaCha20-Poly1305";
+ break;
+
+ case SSL_eNULL:
+ enc="None";
+ break;
+
+ default:
+ enc = "unknown";
+ break;
+ }
+
+ switch (alg_mac) {
+ case SSL_SHA1:
+ mac = "SHA1";
+ break;
+
+ case SSL_SHA256:
+ mac = "SHA256";
+ break;
+
+ case SSL_SHA384:
+ mac = "SHA384";
+ break;
+
+ case SSL_AEAD:
+ mac = "AEAD";
+ break;
+
+ default:
+ mac = "unknown";
+ break;
+ }
+
+ if (buf == NULL) {
+ len = 128;
+ buf = OPENSSL_malloc(len);
+ if (buf == NULL) {
+ return NULL;
+ }
+ } else if (len < 128) {
+ return "Buffer too small";
+ }
+
+ BIO_snprintf(buf, len, "%-23s Kx=%-8s Au=%-4s Enc=%-9s Mac=%-4s\n",
+ cipher->name, kx, au, enc, mac);
+ return buf;
+}
+
+const char *SSL_CIPHER_get_version(const SSL_CIPHER *cipher) {
+ return "TLSv1/SSLv3";
+}
+
+COMP_METHOD *SSL_COMP_get_compression_methods(void) { return NULL; }
+
+int SSL_COMP_add_compression_method(int id, COMP_METHOD *cm) { return 1; }
+
+const char *SSL_COMP_get_name(const COMP_METHOD *comp) { return NULL; }
+
+void SSL_COMP_free_compression_methods(void) {}
+
+int ssl_cipher_get_key_type(const SSL_CIPHER *cipher) {
+ uint32_t alg_a = cipher->algorithm_auth;
+
+ if (alg_a & SSL_aECDSA) {
+ return EVP_PKEY_EC;
+ } else if (alg_a & SSL_aRSA) {
+ return EVP_PKEY_RSA;
+ }
+
+ return EVP_PKEY_NONE;
+}
+
+int ssl_cipher_uses_certificate_auth(const SSL_CIPHER *cipher) {
+ return (cipher->algorithm_auth & SSL_aCERT) != 0;
+}
+
+int ssl_cipher_requires_server_key_exchange(const SSL_CIPHER *cipher) {
+ /* Ephemeral Diffie-Hellman key exchanges require a ServerKeyExchange. */
+ if (cipher->algorithm_mkey & SSL_kDHE ||
+ cipher->algorithm_mkey & SSL_kECDHE) {
+ return 1;
+ }
+
+ /* It is optional in all others. */
+ return 0;
+}
+
+size_t ssl_cipher_get_record_split_len(const SSL_CIPHER *cipher) {
+ size_t block_size;
+ switch (cipher->algorithm_enc) {
+ case SSL_3DES:
+ block_size = 8;
+ break;
+ case SSL_AES128:
+ case SSL_AES256:
+ block_size = 16;
+ break;
+ default:
+ return 0;
+ }
+
+ /* All supported TLS 1.0 ciphers use SHA-1. */
+ assert(cipher->algorithm_mac == SSL_SHA1);
+ size_t ret = 1 + SHA_DIGEST_LENGTH;
+ ret += block_size - (ret % block_size);
+ return ret;
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_ecdh.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_ecdh.c
new file mode 100644
index 000000000..f49d5661a
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_ecdh.c
@@ -0,0 +1,465 @@
+/* Copyright (c) 2015, 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 <openssl/ssl.h>
+
+#include <assert.h>
+#include <string.h>
+
+#include <openssl/bn.h>
+#include <openssl/bytestring.h>
+#include <openssl/curve25519.h>
+#include <openssl/ec.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/nid.h>
+
+#include "internal.h"
+#include "../crypto/internal.h"
+
+
+/* |EC_POINT| implementation. */
+
+static void ssl_ec_point_cleanup(SSL_ECDH_CTX *ctx) {
+ BIGNUM *private_key = (BIGNUM *)ctx->data;
+ BN_clear_free(private_key);
+}
+
+static int ssl_ec_point_offer(SSL_ECDH_CTX *ctx, CBB *out) {
+ assert(ctx->data == NULL);
+ BIGNUM *private_key = BN_new();
+ if (private_key == NULL) {
+ return 0;
+ }
+ ctx->data = private_key;
+
+ /* Set up a shared |BN_CTX| for all operations. */
+ BN_CTX *bn_ctx = BN_CTX_new();
+ if (bn_ctx == NULL) {
+ return 0;
+ }
+ BN_CTX_start(bn_ctx);
+
+ int ret = 0;
+ EC_POINT *public_key = NULL;
+ EC_GROUP *group = EC_GROUP_new_by_curve_name(ctx->method->nid);
+ if (group == NULL) {
+ goto err;
+ }
+
+ /* Generate a private key. */
+ if (!BN_rand_range_ex(private_key, 1, EC_GROUP_get0_order(group))) {
+ goto err;
+ }
+
+ /* Compute the corresponding public key and serialize it. */
+ public_key = EC_POINT_new(group);
+ if (public_key == NULL ||
+ !EC_POINT_mul(group, public_key, private_key, NULL, NULL, bn_ctx) ||
+ !EC_POINT_point2cbb(out, group, public_key, POINT_CONVERSION_UNCOMPRESSED,
+ bn_ctx)) {
+ goto err;
+ }
+
+ ret = 1;
+
+err:
+ EC_GROUP_free(group);
+ EC_POINT_free(public_key);
+ BN_CTX_end(bn_ctx);
+ BN_CTX_free(bn_ctx);
+ return ret;
+}
+
+static int ssl_ec_point_finish(SSL_ECDH_CTX *ctx, uint8_t **out_secret,
+ size_t *out_secret_len, uint8_t *out_alert,
+ const uint8_t *peer_key, size_t peer_key_len) {
+ BIGNUM *private_key = (BIGNUM *)ctx->data;
+ assert(private_key != NULL);
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+
+ /* Set up a shared |BN_CTX| for all operations. */
+ BN_CTX *bn_ctx = BN_CTX_new();
+ if (bn_ctx == NULL) {
+ return 0;
+ }
+ BN_CTX_start(bn_ctx);
+
+ int ret = 0;
+ EC_GROUP *group = EC_GROUP_new_by_curve_name(ctx->method->nid);
+ EC_POINT *peer_point = NULL, *result = NULL;
+ uint8_t *secret = NULL;
+ if (group == NULL) {
+ goto err;
+ }
+
+ /* Compute the x-coordinate of |peer_key| * |private_key|. */
+ peer_point = EC_POINT_new(group);
+ result = EC_POINT_new(group);
+ if (peer_point == NULL || result == NULL) {
+ goto err;
+ }
+ BIGNUM *x = BN_CTX_get(bn_ctx);
+ if (x == NULL) {
+ goto err;
+ }
+ if (!EC_POINT_oct2point(group, peer_point, peer_key, peer_key_len, bn_ctx)) {
+ *out_alert = SSL_AD_DECODE_ERROR;
+ goto err;
+ }
+ if (!EC_POINT_mul(group, result, NULL, peer_point, private_key, bn_ctx) ||
+ !EC_POINT_get_affine_coordinates_GFp(group, result, x, NULL, bn_ctx)) {
+ goto err;
+ }
+
+ /* Encode the x-coordinate left-padded with zeros. */
+ size_t secret_len = (EC_GROUP_get_degree(group) + 7) / 8;
+ secret = OPENSSL_malloc(secret_len);
+ if (secret == NULL || !BN_bn2bin_padded(secret, secret_len, x)) {
+ goto err;
+ }
+
+ *out_secret = secret;
+ *out_secret_len = secret_len;
+ secret = NULL;
+ ret = 1;
+
+err:
+ EC_GROUP_free(group);
+ EC_POINT_free(peer_point);
+ EC_POINT_free(result);
+ BN_CTX_end(bn_ctx);
+ BN_CTX_free(bn_ctx);
+ OPENSSL_free(secret);
+ return ret;
+}
+
+static int ssl_ec_point_accept(SSL_ECDH_CTX *ctx, CBB *out_public_key,
+ uint8_t **out_secret, size_t *out_secret_len,
+ uint8_t *out_alert, const uint8_t *peer_key,
+ size_t peer_key_len) {
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ if (!ssl_ec_point_offer(ctx, out_public_key) ||
+ !ssl_ec_point_finish(ctx, out_secret, out_secret_len, out_alert, peer_key,
+ peer_key_len)) {
+ return 0;
+ }
+ return 1;
+}
+
+/* X25119 implementation. */
+
+static void ssl_x25519_cleanup(SSL_ECDH_CTX *ctx) {
+ if (ctx->data == NULL) {
+ return;
+ }
+ OPENSSL_cleanse(ctx->data, 32);
+ OPENSSL_free(ctx->data);
+}
+
+static int ssl_x25519_offer(SSL_ECDH_CTX *ctx, CBB *out) {
+ assert(ctx->data == NULL);
+
+ ctx->data = OPENSSL_malloc(32);
+ if (ctx->data == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ uint8_t public_key[32];
+ X25519_keypair(public_key, (uint8_t *)ctx->data);
+ return CBB_add_bytes(out, public_key, sizeof(public_key));
+}
+
+static int ssl_x25519_finish(SSL_ECDH_CTX *ctx, uint8_t **out_secret,
+ size_t *out_secret_len, uint8_t *out_alert,
+ const uint8_t *peer_key, size_t peer_key_len) {
+ assert(ctx->data != NULL);
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+
+ uint8_t *secret = OPENSSL_malloc(32);
+ if (secret == NULL) {
+ return 0;
+ }
+
+ if (peer_key_len != 32 ||
+ !X25519(secret, (uint8_t *)ctx->data, peer_key)) {
+ OPENSSL_free(secret);
+ *out_alert = SSL_AD_DECODE_ERROR;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT);
+ return 0;
+ }
+
+ *out_secret = secret;
+ *out_secret_len = 32;
+ return 1;
+}
+
+static int ssl_x25519_accept(SSL_ECDH_CTX *ctx, CBB *out_public_key,
+ uint8_t **out_secret, size_t *out_secret_len,
+ uint8_t *out_alert, const uint8_t *peer_key,
+ size_t peer_key_len) {
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ if (!ssl_x25519_offer(ctx, out_public_key) ||
+ !ssl_x25519_finish(ctx, out_secret, out_secret_len, out_alert, peer_key,
+ peer_key_len)) {
+ return 0;
+ }
+ return 1;
+}
+
+
+/* Legacy DHE-based implementation. */
+
+static void ssl_dhe_cleanup(SSL_ECDH_CTX *ctx) {
+ DH_free((DH *)ctx->data);
+}
+
+static int ssl_dhe_offer(SSL_ECDH_CTX *ctx, CBB *out) {
+ DH *dh = (DH *)ctx->data;
+ /* The group must have been initialized already, but not the key. */
+ assert(dh != NULL);
+ assert(dh->priv_key == NULL);
+
+ /* Due to a bug in yaSSL, the public key must be zero padded to the size of
+ * the prime. */
+ return DH_generate_key(dh) &&
+ BN_bn2cbb_padded(out, BN_num_bytes(dh->p), dh->pub_key);
+}
+
+static int ssl_dhe_finish(SSL_ECDH_CTX *ctx, uint8_t **out_secret,
+ size_t *out_secret_len, uint8_t *out_alert,
+ const uint8_t *peer_key, size_t peer_key_len) {
+ DH *dh = (DH *)ctx->data;
+ assert(dh != NULL);
+ assert(dh->priv_key != NULL);
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+
+ int secret_len = 0;
+ uint8_t *secret = NULL;
+ BIGNUM *peer_point = BN_bin2bn(peer_key, peer_key_len, NULL);
+ if (peer_point == NULL) {
+ goto err;
+ }
+
+ secret = OPENSSL_malloc(DH_size(dh));
+ if (secret == NULL) {
+ goto err;
+ }
+ secret_len = DH_compute_key(secret, peer_point, dh);
+ if (secret_len <= 0) {
+ goto err;
+ }
+
+ *out_secret = secret;
+ *out_secret_len = (size_t)secret_len;
+ BN_free(peer_point);
+ return 1;
+
+err:
+ if (secret_len > 0) {
+ OPENSSL_cleanse(secret, (size_t)secret_len);
+ }
+ OPENSSL_free(secret);
+ BN_free(peer_point);
+ return 0;
+}
+
+static int ssl_dhe_accept(SSL_ECDH_CTX *ctx, CBB *out_public_key,
+ uint8_t **out_secret, size_t *out_secret_len,
+ uint8_t *out_alert, const uint8_t *peer_key,
+ size_t peer_key_len) {
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ if (!ssl_dhe_offer(ctx, out_public_key) ||
+ !ssl_dhe_finish(ctx, out_secret, out_secret_len, out_alert, peer_key,
+ peer_key_len)) {
+ return 0;
+ }
+ return 1;
+}
+
+static const SSL_ECDH_METHOD kDHEMethod = {
+ NID_undef, 0, "",
+ ssl_dhe_cleanup,
+ ssl_dhe_offer,
+ ssl_dhe_accept,
+ ssl_dhe_finish,
+ CBS_get_u16_length_prefixed,
+ CBB_add_u16_length_prefixed,
+};
+
+static const SSL_ECDH_METHOD kMethods[] = {
+ {
+ NID_X9_62_prime256v1,
+ SSL_CURVE_SECP256R1,
+ "P-256",
+ ssl_ec_point_cleanup,
+ ssl_ec_point_offer,
+ ssl_ec_point_accept,
+ ssl_ec_point_finish,
+ CBS_get_u8_length_prefixed,
+ CBB_add_u8_length_prefixed,
+ },
+ {
+ NID_secp384r1,
+ SSL_CURVE_SECP384R1,
+ "P-384",
+ ssl_ec_point_cleanup,
+ ssl_ec_point_offer,
+ ssl_ec_point_accept,
+ ssl_ec_point_finish,
+ CBS_get_u8_length_prefixed,
+ CBB_add_u8_length_prefixed,
+ },
+ {
+ NID_secp521r1,
+ SSL_CURVE_SECP521R1,
+ "P-521",
+ ssl_ec_point_cleanup,
+ ssl_ec_point_offer,
+ ssl_ec_point_accept,
+ ssl_ec_point_finish,
+ CBS_get_u8_length_prefixed,
+ CBB_add_u8_length_prefixed,
+ },
+ {
+ NID_X25519,
+ SSL_CURVE_X25519,
+ "X25519",
+ ssl_x25519_cleanup,
+ ssl_x25519_offer,
+ ssl_x25519_accept,
+ ssl_x25519_finish,
+ CBS_get_u8_length_prefixed,
+ CBB_add_u8_length_prefixed,
+ },
+};
+
+static const SSL_ECDH_METHOD *method_from_group_id(uint16_t group_id) {
+ for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kMethods); i++) {
+ if (kMethods[i].group_id == group_id) {
+ return &kMethods[i];
+ }
+ }
+ return NULL;
+}
+
+static const SSL_ECDH_METHOD *method_from_nid(int nid) {
+ for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kMethods); i++) {
+ if (kMethods[i].nid == nid) {
+ return &kMethods[i];
+ }
+ }
+ return NULL;
+}
+
+static const SSL_ECDH_METHOD *method_from_name(const char *name, size_t len) {
+ for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kMethods); i++) {
+ if (len == strlen(kMethods[i].name) &&
+ !strncmp(kMethods[i].name, name, len)) {
+ return &kMethods[i];
+ }
+ }
+ return NULL;
+}
+
+const char* SSL_get_curve_name(uint16_t group_id) {
+ const SSL_ECDH_METHOD *method = method_from_group_id(group_id);
+ if (method == NULL) {
+ return NULL;
+ }
+ return method->name;
+}
+
+int ssl_nid_to_group_id(uint16_t *out_group_id, int nid) {
+ const SSL_ECDH_METHOD *method = method_from_nid(nid);
+ if (method == NULL) {
+ return 0;
+ }
+ *out_group_id = method->group_id;
+ return 1;
+}
+
+int ssl_name_to_group_id(uint16_t *out_group_id, const char *name, size_t len) {
+ const SSL_ECDH_METHOD *method = method_from_name(name, len);
+ if (method == NULL) {
+ return 0;
+ }
+ *out_group_id = method->group_id;
+ return 1;
+}
+
+int SSL_ECDH_CTX_init(SSL_ECDH_CTX *ctx, uint16_t group_id) {
+ SSL_ECDH_CTX_cleanup(ctx);
+
+ const SSL_ECDH_METHOD *method = method_from_group_id(group_id);
+ if (method == NULL) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_ELLIPTIC_CURVE);
+ return 0;
+ }
+ ctx->method = method;
+ return 1;
+}
+
+void SSL_ECDH_CTX_init_for_dhe(SSL_ECDH_CTX *ctx, DH *params) {
+ SSL_ECDH_CTX_cleanup(ctx);
+
+ ctx->method = &kDHEMethod;
+ ctx->data = params;
+}
+
+void SSL_ECDH_CTX_cleanup(SSL_ECDH_CTX *ctx) {
+ if (ctx->method == NULL) {
+ return;
+ }
+ ctx->method->cleanup(ctx);
+ ctx->method = NULL;
+ ctx->data = NULL;
+}
+
+uint16_t SSL_ECDH_CTX_get_id(const SSL_ECDH_CTX *ctx) {
+ return ctx->method->group_id;
+}
+
+int SSL_ECDH_CTX_get_key(SSL_ECDH_CTX *ctx, CBS *cbs, CBS *out) {
+ if (ctx->method == NULL) {
+ return 0;
+ }
+ return ctx->method->get_key(cbs, out);
+}
+
+int SSL_ECDH_CTX_add_key(SSL_ECDH_CTX *ctx, CBB *cbb, CBB *out_contents) {
+ if (ctx->method == NULL) {
+ return 0;
+ }
+ return ctx->method->add_key(cbb, out_contents);
+}
+
+int SSL_ECDH_CTX_offer(SSL_ECDH_CTX *ctx, CBB *out_public_key) {
+ return ctx->method->offer(ctx, out_public_key);
+}
+
+int SSL_ECDH_CTX_accept(SSL_ECDH_CTX *ctx, CBB *out_public_key,
+ uint8_t **out_secret, size_t *out_secret_len,
+ uint8_t *out_alert, const uint8_t *peer_key,
+ size_t peer_key_len) {
+ return ctx->method->accept(ctx, out_public_key, out_secret, out_secret_len,
+ out_alert, peer_key, peer_key_len);
+}
+
+int SSL_ECDH_CTX_finish(SSL_ECDH_CTX *ctx, uint8_t **out_secret,
+ size_t *out_secret_len, uint8_t *out_alert,
+ const uint8_t *peer_key, size_t peer_key_len) {
+ return ctx->method->finish(ctx, out_secret, out_secret_len, out_alert,
+ peer_key, peer_key_len);
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_file.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_file.c
new file mode 100644
index 000000000..59351a32f
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_file.c
@@ -0,0 +1,575 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2007 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include <openssl/ssl.h>
+
+#include <errno.h>
+#include <string.h>
+
+#include <openssl/asn1.h>
+#include <openssl/bio.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/pem.h>
+#include <openssl/stack.h>
+#include <openssl/x509.h>
+
+#include "internal.h"
+
+
+static int xname_cmp(const X509_NAME **a, const X509_NAME **b) {
+ return X509_NAME_cmp(*a, *b);
+}
+
+/* TODO(davidben): Is there any reason this doesn't call
+ * |SSL_add_file_cert_subjects_to_stack|? */
+STACK_OF(X509_NAME) *SSL_load_client_CA_file(const char *file) {
+ BIO *in;
+ X509 *x = NULL;
+ X509_NAME *xn = NULL;
+ STACK_OF(X509_NAME) *ret = NULL, *sk;
+
+ sk = sk_X509_NAME_new(xname_cmp);
+ in = BIO_new(BIO_s_file());
+
+ if (sk == NULL || in == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if (!BIO_read_filename(in, file)) {
+ goto err;
+ }
+
+ for (;;) {
+ if (PEM_read_bio_X509(in, &x, NULL, NULL) == NULL) {
+ break;
+ }
+ if (ret == NULL) {
+ ret = sk_X509_NAME_new_null();
+ if (ret == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ }
+ xn = X509_get_subject_name(x);
+ if (xn == NULL) {
+ goto err;
+ }
+
+ /* Check for duplicates. */
+ if (sk_X509_NAME_find(sk, NULL, xn)) {
+ continue;
+ }
+
+ xn = X509_NAME_dup(xn);
+ if (xn == NULL ||
+ !sk_X509_NAME_push(sk /* non-owning */, xn) ||
+ !sk_X509_NAME_push(ret /* owning */, xn)) {
+ X509_NAME_free(xn);
+ goto err;
+ }
+ }
+
+ if (0) {
+ err:
+ sk_X509_NAME_pop_free(ret, X509_NAME_free);
+ ret = NULL;
+ }
+
+ sk_X509_NAME_free(sk);
+ BIO_free(in);
+ X509_free(x);
+ if (ret != NULL) {
+ ERR_clear_error();
+ }
+ return ret;
+}
+
+int SSL_add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack,
+ const char *file) {
+ BIO *in;
+ X509 *x = NULL;
+ X509_NAME *xn = NULL;
+ int ret = 0;
+ int (*oldcmp)(const X509_NAME **a, const X509_NAME **b);
+
+ oldcmp = sk_X509_NAME_set_cmp_func(stack, xname_cmp);
+ in = BIO_new(BIO_s_file());
+
+ if (in == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if (!BIO_read_filename(in, file)) {
+ goto err;
+ }
+
+ for (;;) {
+ if (PEM_read_bio_X509(in, &x, NULL, NULL) == NULL) {
+ break;
+ }
+ xn = X509_get_subject_name(x);
+ if (xn == NULL) {
+ goto err;
+ }
+
+ /* Check for duplicates. */
+ if (sk_X509_NAME_find(stack, NULL, xn)) {
+ continue;
+ }
+
+ xn = X509_NAME_dup(xn);
+ if (xn == NULL ||
+ !sk_X509_NAME_push(stack, xn)) {
+ X509_NAME_free(xn);
+ goto err;
+ }
+ }
+
+ ERR_clear_error();
+ ret = 1;
+
+err:
+ BIO_free(in);
+ X509_free(x);
+
+ (void) sk_X509_NAME_set_cmp_func(stack, oldcmp);
+
+ return ret;
+}
+
+int SSL_use_certificate_file(SSL *ssl, const char *file, int type) {
+ int reason_code;
+ BIO *in;
+ int ret = 0;
+ X509 *x = NULL;
+
+ in = BIO_new(BIO_s_file());
+ if (in == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
+ goto end;
+ }
+
+ if (BIO_read_filename(in, file) <= 0) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_SYS_LIB);
+ goto end;
+ }
+
+ if (type == SSL_FILETYPE_ASN1) {
+ reason_code = ERR_R_ASN1_LIB;
+ x = d2i_X509_bio(in, NULL);
+ } else if (type == SSL_FILETYPE_PEM) {
+ reason_code = ERR_R_PEM_LIB;
+ x = PEM_read_bio_X509(in, NULL, ssl->ctx->default_passwd_callback,
+ ssl->ctx->default_passwd_callback_userdata);
+ } else {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SSL_FILETYPE);
+ goto end;
+ }
+
+ if (x == NULL) {
+ OPENSSL_PUT_ERROR(SSL, reason_code);
+ goto end;
+ }
+
+ ret = SSL_use_certificate(ssl, x);
+
+end:
+ X509_free(x);
+ BIO_free(in);
+
+ return ret;
+}
+
+int SSL_use_RSAPrivateKey_file(SSL *ssl, const char *file, int type) {
+ int reason_code, ret = 0;
+ BIO *in;
+ RSA *rsa = NULL;
+
+ in = BIO_new(BIO_s_file());
+ if (in == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
+ goto end;
+ }
+
+ if (BIO_read_filename(in, file) <= 0) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_SYS_LIB);
+ goto end;
+ }
+
+ if (type == SSL_FILETYPE_ASN1) {
+ reason_code = ERR_R_ASN1_LIB;
+ rsa = d2i_RSAPrivateKey_bio(in, NULL);
+ } else if (type == SSL_FILETYPE_PEM) {
+ reason_code = ERR_R_PEM_LIB;
+ rsa =
+ PEM_read_bio_RSAPrivateKey(in, NULL, ssl->ctx->default_passwd_callback,
+ ssl->ctx->default_passwd_callback_userdata);
+ } else {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SSL_FILETYPE);
+ goto end;
+ }
+
+ if (rsa == NULL) {
+ OPENSSL_PUT_ERROR(SSL, reason_code);
+ goto end;
+ }
+ ret = SSL_use_RSAPrivateKey(ssl, rsa);
+ RSA_free(rsa);
+
+end:
+ BIO_free(in);
+ return ret;
+}
+
+int SSL_use_PrivateKey_file(SSL *ssl, const char *file, int type) {
+ int reason_code, ret = 0;
+ BIO *in;
+ EVP_PKEY *pkey = NULL;
+
+ in = BIO_new(BIO_s_file());
+ if (in == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
+ goto end;
+ }
+
+ if (BIO_read_filename(in, file) <= 0) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_SYS_LIB);
+ goto end;
+ }
+
+ if (type == SSL_FILETYPE_PEM) {
+ reason_code = ERR_R_PEM_LIB;
+ pkey = PEM_read_bio_PrivateKey(in, NULL, ssl->ctx->default_passwd_callback,
+ ssl->ctx->default_passwd_callback_userdata);
+ } else if (type == SSL_FILETYPE_ASN1) {
+ reason_code = ERR_R_ASN1_LIB;
+ pkey = d2i_PrivateKey_bio(in, NULL);
+ } else {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SSL_FILETYPE);
+ goto end;
+ }
+
+ if (pkey == NULL) {
+ OPENSSL_PUT_ERROR(SSL, reason_code);
+ goto end;
+ }
+ ret = SSL_use_PrivateKey(ssl, pkey);
+ EVP_PKEY_free(pkey);
+
+end:
+ BIO_free(in);
+ return ret;
+}
+
+int SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, int type) {
+ int reason_code;
+ BIO *in;
+ int ret = 0;
+ X509 *x = NULL;
+
+ in = BIO_new(BIO_s_file());
+ if (in == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
+ goto end;
+ }
+
+ if (BIO_read_filename(in, file) <= 0) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_SYS_LIB);
+ goto end;
+ }
+
+ if (type == SSL_FILETYPE_ASN1) {
+ reason_code = ERR_R_ASN1_LIB;
+ x = d2i_X509_bio(in, NULL);
+ } else if (type == SSL_FILETYPE_PEM) {
+ reason_code = ERR_R_PEM_LIB;
+ x = PEM_read_bio_X509(in, NULL, ctx->default_passwd_callback,
+ ctx->default_passwd_callback_userdata);
+ } else {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SSL_FILETYPE);
+ goto end;
+ }
+
+ if (x == NULL) {
+ OPENSSL_PUT_ERROR(SSL, reason_code);
+ goto end;
+ }
+
+ ret = SSL_CTX_use_certificate(ctx, x);
+
+end:
+ X509_free(x);
+ BIO_free(in);
+ return ret;
+}
+
+int SSL_CTX_use_RSAPrivateKey_file(SSL_CTX *ctx, const char *file, int type) {
+ int reason_code, ret = 0;
+ BIO *in;
+ RSA *rsa = NULL;
+
+ in = BIO_new(BIO_s_file());
+ if (in == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
+ goto end;
+ }
+
+ if (BIO_read_filename(in, file) <= 0) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_SYS_LIB);
+ goto end;
+ }
+
+ if (type == SSL_FILETYPE_ASN1) {
+ reason_code = ERR_R_ASN1_LIB;
+ rsa = d2i_RSAPrivateKey_bio(in, NULL);
+ } else if (type == SSL_FILETYPE_PEM) {
+ reason_code = ERR_R_PEM_LIB;
+ rsa = PEM_read_bio_RSAPrivateKey(in, NULL, ctx->default_passwd_callback,
+ ctx->default_passwd_callback_userdata);
+ } else {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SSL_FILETYPE);
+ goto end;
+ }
+
+ if (rsa == NULL) {
+ OPENSSL_PUT_ERROR(SSL, reason_code);
+ goto end;
+ }
+ ret = SSL_CTX_use_RSAPrivateKey(ctx, rsa);
+ RSA_free(rsa);
+
+end:
+ BIO_free(in);
+ return ret;
+}
+
+int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type) {
+ int reason_code, ret = 0;
+ BIO *in;
+ EVP_PKEY *pkey = NULL;
+
+ in = BIO_new(BIO_s_file());
+ if (in == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
+ goto end;
+ }
+
+ if (BIO_read_filename(in, file) <= 0) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_SYS_LIB);
+ goto end;
+ }
+
+ if (type == SSL_FILETYPE_PEM) {
+ reason_code = ERR_R_PEM_LIB;
+ pkey = PEM_read_bio_PrivateKey(in, NULL, ctx->default_passwd_callback,
+ ctx->default_passwd_callback_userdata);
+ } else if (type == SSL_FILETYPE_ASN1) {
+ reason_code = ERR_R_ASN1_LIB;
+ pkey = d2i_PrivateKey_bio(in, NULL);
+ } else {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SSL_FILETYPE);
+ goto end;
+ }
+
+ if (pkey == NULL) {
+ OPENSSL_PUT_ERROR(SSL, reason_code);
+ goto end;
+ }
+ ret = SSL_CTX_use_PrivateKey(ctx, pkey);
+ EVP_PKEY_free(pkey);
+
+end:
+ BIO_free(in);
+ return ret;
+}
+
+/* Read a file that contains our certificate in "PEM" format, possibly followed
+ * by a sequence of CA certificates that should be sent to the peer in the
+ * Certificate message. */
+int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file) {
+ BIO *in;
+ int ret = 0;
+ X509 *x = NULL;
+
+ ERR_clear_error(); /* clear error stack for SSL_CTX_use_certificate() */
+
+ in = BIO_new(BIO_s_file());
+ if (in == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
+ goto end;
+ }
+
+ if (BIO_read_filename(in, file) <= 0) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_SYS_LIB);
+ goto end;
+ }
+
+ x = PEM_read_bio_X509_AUX(in, NULL, ctx->default_passwd_callback,
+ ctx->default_passwd_callback_userdata);
+ if (x == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_PEM_LIB);
+ goto end;
+ }
+
+ ret = SSL_CTX_use_certificate(ctx, x);
+
+ if (ERR_peek_error() != 0) {
+ ret = 0; /* Key/certificate mismatch doesn't imply ret==0 ... */
+ }
+
+ if (ret) {
+ /* If we could set up our certificate, now proceed to the CA
+ * certificates. */
+ X509 *ca;
+ int r;
+ uint32_t err;
+
+ SSL_CTX_clear_chain_certs(ctx);
+
+ while ((ca = PEM_read_bio_X509(in, NULL, ctx->default_passwd_callback,
+ ctx->default_passwd_callback_userdata)) !=
+ NULL) {
+ r = SSL_CTX_add0_chain_cert(ctx, ca);
+ if (!r) {
+ X509_free(ca);
+ ret = 0;
+ goto end;
+ }
+ /* Note that we must not free r if it was successfully added to the chain
+ * (while we must free the main certificate, since its reference count is
+ * increased by SSL_CTX_use_certificate). */
+ }
+
+ /* When the while loop ends, it's usually just EOF. */
+ err = ERR_peek_last_error();
+ if (ERR_GET_LIB(err) == ERR_LIB_PEM &&
+ ERR_GET_REASON(err) == PEM_R_NO_START_LINE) {
+ ERR_clear_error();
+ } else {
+ ret = 0; /* some real error */
+ }
+ }
+
+end:
+ X509_free(x);
+ BIO_free(in);
+ return ret;
+}
+
+void SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx, pem_password_cb *cb) {
+ ctx->default_passwd_callback = cb;
+}
+
+void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx, void *data) {
+ ctx->default_passwd_callback_userdata = data;
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_lib.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_lib.c
new file mode 100644
index 000000000..d16c952f1
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_lib.c
@@ -0,0 +1,2709 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2007 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ * ECC cipher suite support in OpenSSL originally developed by
+ * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
+ */
+/* ====================================================================
+ * Copyright 2005 Nokia. All rights reserved.
+ *
+ * The portions of the attached software ("Contribution") is developed by
+ * Nokia Corporation and is licensed pursuant to the OpenSSL open source
+ * license.
+ *
+ * The Contribution, originally written by Mika Kousa and Pasi Eronen of
+ * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites
+ * support (see RFC 4279) to OpenSSL.
+ *
+ * No patent licenses or other rights except those expressly stated in
+ * the OpenSSL open source license shall be deemed granted or received
+ * expressly, by implication, estoppel, or otherwise.
+ *
+ * No assurances are provided by Nokia that the Contribution does not
+ * infringe the patent or other intellectual property rights of any third
+ * party or that the license provides you with all the necessary rights
+ * to make use of the Contribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN
+ * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA
+ * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY
+ * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
+ * OTHERWISE. */
+
+#include <openssl/ssl.h>
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <openssl/bytestring.h>
+#include <openssl/crypto.h>
+#include <openssl/dh.h>
+#include <openssl/err.h>
+#include <openssl/lhash.h>
+#include <openssl/mem.h>
+#include <openssl/rand.h>
+
+#include "internal.h"
+#include "../crypto/internal.h"
+
+#if defined(OPENSSL_WINDOWS)
+#include <sys/timeb.h>
+#else
+#include <sys/socket.h>
+#include <sys/time.h>
+#endif
+
+
+/* |SSL_R_UNKNOWN_PROTOCOL| is no longer emitted, but continue to define it
+ * to avoid downstream churn. */
+OPENSSL_DECLARE_ERROR_REASON(SSL, UNKNOWN_PROTOCOL)
+
+/* The following errors are no longer emitted, but are used in nginx without
+ * #ifdefs. */
+OPENSSL_DECLARE_ERROR_REASON(SSL, BLOCK_CIPHER_PAD_IS_WRONG)
+OPENSSL_DECLARE_ERROR_REASON(SSL, NO_CIPHERS_SPECIFIED)
+
+/* Some error codes are special. Ensure the make_errors.go script never
+ * regresses this. */
+OPENSSL_COMPILE_ASSERT(SSL_R_TLSV1_ALERT_NO_RENEGOTIATION ==
+ SSL_AD_NO_RENEGOTIATION + SSL_AD_REASON_OFFSET,
+ ssl_alert_reason_code_mismatch);
+
+/* kMaxHandshakeSize is the maximum size, in bytes, of a handshake message. */
+static const size_t kMaxHandshakeSize = (1u << 24) - 1;
+
+static CRYPTO_EX_DATA_CLASS g_ex_data_class_ssl =
+ CRYPTO_EX_DATA_CLASS_INIT_WITH_APP_DATA;
+static CRYPTO_EX_DATA_CLASS g_ex_data_class_ssl_ctx =
+ CRYPTO_EX_DATA_CLASS_INIT_WITH_APP_DATA;
+
+int SSL_library_init(void) {
+ CRYPTO_library_init();
+ return 1;
+}
+
+static uint32_t ssl_session_hash(const SSL_SESSION *sess) {
+ const uint8_t *session_id = sess->session_id;
+
+ uint8_t tmp_storage[sizeof(uint32_t)];
+ if (sess->session_id_length < sizeof(tmp_storage)) {
+ OPENSSL_memset(tmp_storage, 0, sizeof(tmp_storage));
+ OPENSSL_memcpy(tmp_storage, sess->session_id, sess->session_id_length);
+ session_id = tmp_storage;
+ }
+
+ uint32_t hash =
+ ((uint32_t)session_id[0]) |
+ ((uint32_t)session_id[1] << 8) |
+ ((uint32_t)session_id[2] << 16) |
+ ((uint32_t)session_id[3] << 24);
+
+ return hash;
+}
+
+/* NB: If this function (or indeed the hash function which uses a sort of
+ * coarser function than this one) is changed, ensure
+ * SSL_CTX_has_matching_session_id() is checked accordingly. It relies on being
+ * able to construct an SSL_SESSION that will collide with any existing session
+ * with a matching session ID. */
+static int ssl_session_cmp(const SSL_SESSION *a, const SSL_SESSION *b) {
+ if (a->ssl_version != b->ssl_version) {
+ return 1;
+ }
+
+ if (a->session_id_length != b->session_id_length) {
+ return 1;
+ }
+
+ return OPENSSL_memcmp(a->session_id, b->session_id, a->session_id_length);
+}
+
+SSL_CTX *SSL_CTX_new(const SSL_METHOD *method) {
+ SSL_CTX *ret = NULL;
+
+ if (method == NULL) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NULL_SSL_METHOD_PASSED);
+ return NULL;
+ }
+
+ ret = OPENSSL_malloc(sizeof(SSL_CTX));
+ if (ret == NULL) {
+ goto err;
+ }
+
+ OPENSSL_memset(ret, 0, sizeof(SSL_CTX));
+
+ ret->method = method->method;
+ ret->x509_method = method->x509_method;
+
+ CRYPTO_MUTEX_init(&ret->lock);
+
+ ret->session_cache_mode = SSL_SESS_CACHE_SERVER;
+ ret->session_cache_size = SSL_SESSION_CACHE_MAX_SIZE_DEFAULT;
+
+ ret->session_timeout = SSL_DEFAULT_SESSION_TIMEOUT;
+ ret->session_psk_dhe_timeout = SSL_DEFAULT_SESSION_PSK_DHE_TIMEOUT;
+
+ ret->references = 1;
+
+ ret->max_cert_list = SSL_MAX_CERT_LIST_DEFAULT;
+ ret->verify_mode = SSL_VERIFY_NONE;
+ ret->cert = ssl_cert_new(method->x509_method);
+ if (ret->cert == NULL) {
+ goto err;
+ }
+
+ ret->sessions = lh_SSL_SESSION_new(ssl_session_hash, ssl_session_cmp);
+ if (ret->sessions == NULL) {
+ goto err;
+ }
+
+ if (!ret->x509_method->ssl_ctx_new(ret)) {
+ goto err;
+ }
+
+ if (!SSL_CTX_set_strict_cipher_list(ret, SSL_DEFAULT_CIPHER_LIST)) {
+ goto err2;
+ }
+
+ ret->client_CA = sk_CRYPTO_BUFFER_new_null();
+ if (ret->client_CA == NULL) {
+ goto err;
+ }
+
+ CRYPTO_new_ex_data(&ret->ex_data);
+
+ ret->max_send_fragment = SSL3_RT_MAX_PLAIN_LENGTH;
+
+ /* Setup RFC4507 ticket keys */
+ if (!RAND_bytes(ret->tlsext_tick_key_name, 16) ||
+ !RAND_bytes(ret->tlsext_tick_hmac_key, 16) ||
+ !RAND_bytes(ret->tlsext_tick_aes_key, 16)) {
+ ret->options |= SSL_OP_NO_TICKET;
+ }
+
+ /* Disable the auto-chaining feature by default. Once this has stuck without
+ * problems, the feature will be removed entirely. */
+ ret->mode = SSL_MODE_NO_AUTO_CHAIN;
+
+ /* Lock the SSL_CTX to the specified version, for compatibility with legacy
+ * uses of SSL_METHOD. */
+ if (!SSL_CTX_set_max_proto_version(ret, method->version) ||
+ !SSL_CTX_set_min_proto_version(ret, method->version)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ goto err2;
+ }
+
+ return ret;
+
+err:
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+err2:
+ SSL_CTX_free(ret);
+ return NULL;
+}
+
+int SSL_CTX_up_ref(SSL_CTX *ctx) {
+ CRYPTO_refcount_inc(&ctx->references);
+ return 1;
+}
+
+void SSL_CTX_free(SSL_CTX *ctx) {
+ if (ctx == NULL ||
+ !CRYPTO_refcount_dec_and_test_zero(&ctx->references)) {
+ return;
+ }
+
+ /* Free internal session cache. However: the remove_cb() may reference the
+ * ex_data of SSL_CTX, thus the ex_data store can only be removed after the
+ * sessions were flushed. As the ex_data handling routines might also touch
+ * the session cache, the most secure solution seems to be: empty (flush) the
+ * cache, then free ex_data, then finally free the cache. (See ticket
+ * [openssl.org #212].) */
+ SSL_CTX_flush_sessions(ctx, 0);
+
+ CRYPTO_free_ex_data(&g_ex_data_class_ssl_ctx, ctx, &ctx->ex_data);
+
+ CRYPTO_MUTEX_cleanup(&ctx->lock);
+ lh_SSL_SESSION_free(ctx->sessions);
+ ssl_cipher_preference_list_free(ctx->cipher_list);
+ ssl_cert_free(ctx->cert);
+ sk_SSL_CUSTOM_EXTENSION_pop_free(ctx->client_custom_extensions,
+ SSL_CUSTOM_EXTENSION_free);
+ sk_SSL_CUSTOM_EXTENSION_pop_free(ctx->server_custom_extensions,
+ SSL_CUSTOM_EXTENSION_free);
+ sk_CRYPTO_BUFFER_pop_free(ctx->client_CA, CRYPTO_BUFFER_free);
+ ctx->x509_method->ssl_ctx_free(ctx);
+ sk_SRTP_PROTECTION_PROFILE_free(ctx->srtp_profiles);
+ OPENSSL_free(ctx->psk_identity_hint);
+ OPENSSL_free(ctx->supported_group_list);
+ OPENSSL_free(ctx->alpn_client_proto_list);
+ EVP_PKEY_free(ctx->tlsext_channel_id_private);
+
+ OPENSSL_free(ctx);
+}
+
+SSL *SSL_new(SSL_CTX *ctx) {
+ if (ctx == NULL) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NULL_SSL_CTX);
+ return NULL;
+ }
+ if (ctx->method == NULL) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION);
+ return NULL;
+ }
+
+ SSL *ssl = OPENSSL_malloc(sizeof(SSL));
+ if (ssl == NULL) {
+ goto err;
+ }
+ OPENSSL_memset(ssl, 0, sizeof(SSL));
+
+ ssl->min_version = ctx->min_version;
+ ssl->max_version = ctx->max_version;
+
+ /* RFC 6347 states that implementations SHOULD use an initial timer value of
+ * 1 second. */
+ ssl->initial_timeout_duration_ms = 1000;
+
+ ssl->options = ctx->options;
+ ssl->mode = ctx->mode;
+ ssl->max_cert_list = ctx->max_cert_list;
+
+ ssl->cert = ssl_cert_dup(ctx->cert);
+ if (ssl->cert == NULL) {
+ goto err;
+ }
+
+ ssl->msg_callback = ctx->msg_callback;
+ ssl->msg_callback_arg = ctx->msg_callback_arg;
+ ssl->verify_mode = ctx->verify_mode;
+ ssl->verify_callback = ctx->default_verify_callback;
+ ssl->retain_only_sha256_of_client_certs =
+ ctx->retain_only_sha256_of_client_certs;
+
+ ssl->quiet_shutdown = ctx->quiet_shutdown;
+ ssl->max_send_fragment = ctx->max_send_fragment;
+
+ SSL_CTX_up_ref(ctx);
+ ssl->ctx = ctx;
+ SSL_CTX_up_ref(ctx);
+ ssl->session_ctx = ctx;
+
+ if (!ssl->ctx->x509_method->ssl_new(ssl)) {
+ goto err;
+ }
+
+ if (ctx->supported_group_list) {
+ ssl->supported_group_list = BUF_memdup(ctx->supported_group_list,
+ ctx->supported_group_list_len * 2);
+ if (!ssl->supported_group_list) {
+ goto err;
+ }
+ ssl->supported_group_list_len = ctx->supported_group_list_len;
+ }
+
+ if (ctx->alpn_client_proto_list) {
+ ssl->alpn_client_proto_list = BUF_memdup(ctx->alpn_client_proto_list,
+ ctx->alpn_client_proto_list_len);
+ if (ssl->alpn_client_proto_list == NULL) {
+ goto err;
+ }
+ ssl->alpn_client_proto_list_len = ctx->alpn_client_proto_list_len;
+ }
+
+ ssl->method = ctx->method;
+
+ if (!ssl->method->ssl_new(ssl)) {
+ goto err;
+ }
+
+ ssl->rwstate = SSL_NOTHING;
+
+ CRYPTO_new_ex_data(&ssl->ex_data);
+
+ ssl->psk_identity_hint = NULL;
+ if (ctx->psk_identity_hint) {
+ ssl->psk_identity_hint = BUF_strdup(ctx->psk_identity_hint);
+ if (ssl->psk_identity_hint == NULL) {
+ goto err;
+ }
+ }
+ ssl->psk_client_callback = ctx->psk_client_callback;
+ ssl->psk_server_callback = ctx->psk_server_callback;
+
+ ssl->tlsext_channel_id_enabled = ctx->tlsext_channel_id_enabled;
+ if (ctx->tlsext_channel_id_private) {
+ EVP_PKEY_up_ref(ctx->tlsext_channel_id_private);
+ ssl->tlsext_channel_id_private = ctx->tlsext_channel_id_private;
+ }
+
+ ssl->signed_cert_timestamps_enabled = ctx->signed_cert_timestamps_enabled;
+ ssl->ocsp_stapling_enabled = ctx->ocsp_stapling_enabled;
+
+ return ssl;
+
+err:
+ SSL_free(ssl);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+
+ return NULL;
+}
+
+void SSL_free(SSL *ssl) {
+ if (ssl == NULL) {
+ return;
+ }
+
+ ssl->ctx->x509_method->ssl_free(ssl);
+ CRYPTO_free_ex_data(&g_ex_data_class_ssl, ssl, &ssl->ex_data);
+
+ BIO_free_all(ssl->rbio);
+ BIO_free_all(ssl->wbio);
+
+ BUF_MEM_free(ssl->init_buf);
+
+ /* add extra stuff */
+ ssl_cipher_preference_list_free(ssl->cipher_list);
+
+ SSL_SESSION_free(ssl->session);
+
+ ssl_cert_free(ssl->cert);
+
+ OPENSSL_free(ssl->tlsext_hostname);
+ SSL_CTX_free(ssl->session_ctx);
+ OPENSSL_free(ssl->supported_group_list);
+ OPENSSL_free(ssl->alpn_client_proto_list);
+ EVP_PKEY_free(ssl->tlsext_channel_id_private);
+ OPENSSL_free(ssl->psk_identity_hint);
+ sk_CRYPTO_BUFFER_pop_free(ssl->client_CA, CRYPTO_BUFFER_free);
+ sk_SRTP_PROTECTION_PROFILE_free(ssl->srtp_profiles);
+
+ if (ssl->method != NULL) {
+ ssl->method->ssl_free(ssl);
+ }
+ SSL_CTX_free(ssl->ctx);
+
+ OPENSSL_free(ssl);
+}
+
+void SSL_set_connect_state(SSL *ssl) {
+ ssl->server = 0;
+ ssl->handshake_func = ssl3_connect;
+}
+
+void SSL_set_accept_state(SSL *ssl) {
+ ssl->server = 1;
+ ssl->handshake_func = ssl3_accept;
+}
+
+void SSL_set0_rbio(SSL *ssl, BIO *rbio) {
+ BIO_free_all(ssl->rbio);
+ ssl->rbio = rbio;
+}
+
+void SSL_set0_wbio(SSL *ssl, BIO *wbio) {
+ BIO_free_all(ssl->wbio);
+ ssl->wbio = wbio;
+}
+
+void SSL_set_bio(SSL *ssl, BIO *rbio, BIO *wbio) {
+ /* For historical reasons, this function has many different cases in ownership
+ * handling. */
+
+ /* If nothing has changed, do nothing */
+ if (rbio == SSL_get_rbio(ssl) && wbio == SSL_get_wbio(ssl)) {
+ return;
+ }
+
+ /* If the two arguments are equal, one fewer reference is granted than
+ * taken. */
+ if (rbio != NULL && rbio == wbio) {
+ BIO_up_ref(rbio);
+ }
+
+ /* If only the wbio is changed, adopt only one reference. */
+ if (rbio == SSL_get_rbio(ssl)) {
+ SSL_set0_wbio(ssl, wbio);
+ return;
+ }
+
+ /* There is an asymmetry here for historical reasons. If only the rbio is
+ * changed AND the rbio and wbio were originally different, then we only adopt
+ * one reference. */
+ if (wbio == SSL_get_wbio(ssl) && SSL_get_rbio(ssl) != SSL_get_wbio(ssl)) {
+ SSL_set0_rbio(ssl, rbio);
+ return;
+ }
+
+ /* Otherwise, adopt both references. */
+ SSL_set0_rbio(ssl, rbio);
+ SSL_set0_wbio(ssl, wbio);
+}
+
+BIO *SSL_get_rbio(const SSL *ssl) { return ssl->rbio; }
+
+BIO *SSL_get_wbio(const SSL *ssl) { return ssl->wbio; }
+
+void ssl_reset_error_state(SSL *ssl) {
+ /* Functions which use |SSL_get_error| must reset I/O and error state on
+ * entry. */
+ ssl->rwstate = SSL_NOTHING;
+ ERR_clear_error();
+ ERR_clear_system_error();
+}
+
+int SSL_do_handshake(SSL *ssl) {
+ ssl_reset_error_state(ssl);
+
+ if (ssl->handshake_func == NULL) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CONNECTION_TYPE_NOT_SET);
+ return -1;
+ }
+
+ if (!SSL_in_init(ssl)) {
+ return 1;
+ }
+
+ if (ssl->s3->hs == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
+
+ /* Run the handshake. */
+ assert(ssl->s3->hs != NULL);
+ int ret = ssl->handshake_func(ssl->s3->hs);
+ if (ret <= 0) {
+ return ret;
+ }
+
+ /* Destroy the handshake object if the handshake has completely finished. */
+ if (!SSL_in_init(ssl)) {
+ ssl_handshake_free(ssl->s3->hs);
+ ssl->s3->hs = NULL;
+ }
+
+ return 1;
+}
+
+int SSL_connect(SSL *ssl) {
+ if (ssl->handshake_func == NULL) {
+ /* Not properly initialized yet */
+ SSL_set_connect_state(ssl);
+ }
+
+ return SSL_do_handshake(ssl);
+}
+
+int SSL_accept(SSL *ssl) {
+ if (ssl->handshake_func == NULL) {
+ /* Not properly initialized yet */
+ SSL_set_accept_state(ssl);
+ }
+
+ return SSL_do_handshake(ssl);
+}
+
+static int ssl_do_renegotiate(SSL *ssl) {
+ /* We do not accept renegotiations as a server or SSL 3.0. SSL 3.0 will be
+ * removed entirely in the future and requires retaining more data for
+ * renegotiation_info. */
+ if (ssl->server || ssl->version == SSL3_VERSION) {
+ goto no_renegotiation;
+ }
+
+ if (ssl->s3->tmp.message_type != SSL3_MT_HELLO_REQUEST ||
+ ssl->init_num != 0) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_HELLO_REQUEST);
+ return 0;
+ }
+
+ switch (ssl->renegotiate_mode) {
+ case ssl_renegotiate_ignore:
+ /* Ignore the HelloRequest. */
+ return 1;
+
+ case ssl_renegotiate_once:
+ if (ssl->s3->total_renegotiations != 0) {
+ goto no_renegotiation;
+ }
+ break;
+
+ case ssl_renegotiate_never:
+ goto no_renegotiation;
+
+ case ssl_renegotiate_freely:
+ break;
+ }
+
+ /* Renegotiation is only supported at quiescent points in the application
+ * protocol, namely in HTTPS, just before reading the HTTP response. Require
+ * the record-layer be idle and avoid complexities of sending a handshake
+ * record while an application_data record is being written. */
+ if (ssl_write_buffer_is_pending(ssl)) {
+ goto no_renegotiation;
+ }
+
+ /* Begin a new handshake. */
+ if (ssl->s3->hs != NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+ ssl->s3->hs = ssl_handshake_new(ssl);
+ if (ssl->s3->hs == NULL) {
+ return 0;
+ }
+
+ ssl->s3->total_renegotiations++;
+ return 1;
+
+no_renegotiation:
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_NO_RENEGOTIATION);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_RENEGOTIATION);
+ return 0;
+}
+
+static int ssl_do_post_handshake(SSL *ssl) {
+ if (ssl3_protocol_version(ssl) < TLS1_3_VERSION) {
+ return ssl_do_renegotiate(ssl);
+ }
+
+ return tls13_post_handshake(ssl);
+}
+
+static int ssl_read_impl(SSL *ssl, void *buf, int num, int peek) {
+ ssl_reset_error_state(ssl);
+
+ if (ssl->handshake_func == NULL) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNINITIALIZED);
+ return -1;
+ }
+
+ for (;;) {
+ /* Complete the current handshake, if any. False Start will cause
+ * |SSL_do_handshake| to return mid-handshake, so this may require multiple
+ * iterations. */
+ while (SSL_in_init(ssl)) {
+ int ret = SSL_do_handshake(ssl);
+ if (ret < 0) {
+ return ret;
+ }
+ if (ret == 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_HANDSHAKE_FAILURE);
+ return -1;
+ }
+ }
+
+ int got_handshake;
+ int ret = ssl->method->read_app_data(ssl, &got_handshake, buf, num, peek);
+ if (ret > 0 || !got_handshake) {
+ ssl->s3->key_update_count = 0;
+ return ret;
+ }
+
+ /* Handle the post-handshake message and try again. */
+ if (!ssl_do_post_handshake(ssl)) {
+ return -1;
+ }
+ ssl->method->release_current_message(ssl, 1 /* free buffer */);
+ }
+}
+
+int SSL_read(SSL *ssl, void *buf, int num) {
+ return ssl_read_impl(ssl, buf, num, 0 /* consume bytes */);
+}
+
+int SSL_peek(SSL *ssl, void *buf, int num) {
+ return ssl_read_impl(ssl, buf, num, 1 /* peek */);
+}
+
+int SSL_write(SSL *ssl, const void *buf, int num) {
+ ssl_reset_error_state(ssl);
+
+ if (ssl->handshake_func == NULL) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNINITIALIZED);
+ return -1;
+ }
+
+ if (ssl->s3->send_shutdown != ssl_shutdown_none) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_PROTOCOL_IS_SHUTDOWN);
+ return -1;
+ }
+
+ /* If necessary, complete the handshake implicitly. */
+ if (SSL_in_init(ssl) && !SSL_in_false_start(ssl)) {
+ int ret = SSL_do_handshake(ssl);
+ if (ret < 0) {
+ return ret;
+ }
+ if (ret == 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_HANDSHAKE_FAILURE);
+ return -1;
+ }
+ }
+
+ return ssl->method->write_app_data(ssl, buf, num);
+}
+
+int SSL_shutdown(SSL *ssl) {
+ ssl_reset_error_state(ssl);
+
+ if (ssl->handshake_func == NULL) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNINITIALIZED);
+ return -1;
+ }
+
+ /* If we are in the middle of a handshake, silently succeed. Consumers often
+ * call this function before |SSL_free|, whether the handshake succeeded or
+ * not. We assume the caller has already handled failed handshakes. */
+ if (SSL_in_init(ssl)) {
+ return 1;
+ }
+
+ if (ssl->quiet_shutdown) {
+ /* Do nothing if configured not to send a close_notify. */
+ ssl->s3->send_shutdown = ssl_shutdown_close_notify;
+ ssl->s3->recv_shutdown = ssl_shutdown_close_notify;
+ return 1;
+ }
+
+ /* This function completes in two stages. It sends a close_notify and then it
+ * waits for a close_notify to come in. Perform exactly one action and return
+ * whether or not it succeeds. */
+
+ if (ssl->s3->send_shutdown != ssl_shutdown_close_notify) {
+ /* Send a close_notify. */
+ if (ssl3_send_alert(ssl, SSL3_AL_WARNING, SSL_AD_CLOSE_NOTIFY) <= 0) {
+ return -1;
+ }
+ } else if (ssl->s3->alert_dispatch) {
+ /* Finish sending the close_notify. */
+ if (ssl->method->dispatch_alert(ssl) <= 0) {
+ return -1;
+ }
+ } else if (ssl->s3->recv_shutdown != ssl_shutdown_close_notify) {
+ /* Wait for the peer's close_notify. */
+ ssl->method->read_close_notify(ssl);
+ if (ssl->s3->recv_shutdown != ssl_shutdown_close_notify) {
+ return -1;
+ }
+ }
+
+ /* Return 0 for unidirectional shutdown and 1 for bidirectional shutdown. */
+ return ssl->s3->recv_shutdown == ssl_shutdown_close_notify;
+}
+
+int SSL_send_fatal_alert(SSL *ssl, uint8_t alert) {
+ if (ssl->s3->alert_dispatch) {
+ if (ssl->s3->send_alert[0] != SSL3_AL_FATAL ||
+ ssl->s3->send_alert[1] != alert) {
+ /* We are already attempting to write a different alert. */
+ OPENSSL_PUT_ERROR(SSL, SSL_R_PROTOCOL_IS_SHUTDOWN);
+ return -1;
+ }
+ return ssl->method->dispatch_alert(ssl);
+ }
+
+ return ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
+}
+
+void SSL_CTX_set_early_data_enabled(SSL_CTX *ctx, int enabled) {
+ ctx->enable_early_data = !!enabled;
+}
+
+static int bio_retry_reason_to_error(int reason) {
+ switch (reason) {
+ case BIO_RR_CONNECT:
+ return SSL_ERROR_WANT_CONNECT;
+ case BIO_RR_ACCEPT:
+ return SSL_ERROR_WANT_ACCEPT;
+ default:
+ return SSL_ERROR_SYSCALL;
+ }
+}
+
+int SSL_get_error(const SSL *ssl, int ret_code) {
+ if (ret_code > 0) {
+ return SSL_ERROR_NONE;
+ }
+
+ /* Make things return SSL_ERROR_SYSCALL when doing SSL_do_handshake etc,
+ * where we do encode the error */
+ uint32_t err = ERR_peek_error();
+ if (err != 0) {
+ if (ERR_GET_LIB(err) == ERR_LIB_SYS) {
+ return SSL_ERROR_SYSCALL;
+ }
+ return SSL_ERROR_SSL;
+ }
+
+ if (ret_code == 0) {
+ if (ssl->s3->recv_shutdown == ssl_shutdown_close_notify) {
+ return SSL_ERROR_ZERO_RETURN;
+ }
+ /* An EOF was observed which violates the protocol, and the underlying
+ * transport does not participate in the error queue. Bubble up to the
+ * caller. */
+ return SSL_ERROR_SYSCALL;
+ }
+
+ switch (ssl->rwstate) {
+ case SSL_PENDING_SESSION:
+ return SSL_ERROR_PENDING_SESSION;
+
+ case SSL_CERTIFICATE_SELECTION_PENDING:
+ return SSL_ERROR_PENDING_CERTIFICATE;
+
+ case SSL_READING: {
+ BIO *bio = SSL_get_rbio(ssl);
+ if (BIO_should_read(bio)) {
+ return SSL_ERROR_WANT_READ;
+ }
+
+ if (BIO_should_write(bio)) {
+ /* TODO(davidben): OpenSSL historically checked for writes on the read
+ * BIO. Can this be removed? */
+ return SSL_ERROR_WANT_WRITE;
+ }
+
+ if (BIO_should_io_special(bio)) {
+ return bio_retry_reason_to_error(BIO_get_retry_reason(bio));
+ }
+
+ break;
+ }
+
+ case SSL_WRITING: {
+ BIO *bio = SSL_get_wbio(ssl);
+ if (BIO_should_write(bio)) {
+ return SSL_ERROR_WANT_WRITE;
+ }
+
+ if (BIO_should_read(bio)) {
+ /* TODO(davidben): OpenSSL historically checked for reads on the write
+ * BIO. Can this be removed? */
+ return SSL_ERROR_WANT_READ;
+ }
+
+ if (BIO_should_io_special(bio)) {
+ return bio_retry_reason_to_error(BIO_get_retry_reason(bio));
+ }
+
+ break;
+ }
+
+ case SSL_X509_LOOKUP:
+ return SSL_ERROR_WANT_X509_LOOKUP;
+
+ case SSL_CHANNEL_ID_LOOKUP:
+ return SSL_ERROR_WANT_CHANNEL_ID_LOOKUP;
+
+ case SSL_PRIVATE_KEY_OPERATION:
+ return SSL_ERROR_WANT_PRIVATE_KEY_OPERATION;
+
+ case SSL_PENDING_TICKET:
+ return SSL_ERROR_PENDING_TICKET;
+ }
+
+ return SSL_ERROR_SYSCALL;
+}
+
+static int set_min_version(const SSL_PROTOCOL_METHOD *method, uint16_t *out,
+ uint16_t version) {
+ if (version == 0) {
+ *out = method->min_version;
+ return 1;
+ }
+
+ if (version == TLS1_3_VERSION) {
+ version = TLS1_3_DRAFT_VERSION;
+ }
+
+ return method->version_from_wire(out, version);
+}
+
+static int set_max_version(const SSL_PROTOCOL_METHOD *method, uint16_t *out,
+ uint16_t version) {
+ if (version == 0) {
+ *out = method->max_version;
+ /* TODO(svaldez): Enable TLS 1.3 by default once fully implemented. */
+ if (*out > TLS1_2_VERSION) {
+ *out = TLS1_2_VERSION;
+ }
+ return 1;
+ }
+
+ if (version == TLS1_3_VERSION) {
+ version = TLS1_3_DRAFT_VERSION;
+ }
+
+ return method->version_from_wire(out, version);
+}
+
+int SSL_CTX_set_min_proto_version(SSL_CTX *ctx, uint16_t version) {
+ return set_min_version(ctx->method, &ctx->min_version, version);
+}
+
+int SSL_CTX_set_max_proto_version(SSL_CTX *ctx, uint16_t version) {
+ return set_max_version(ctx->method, &ctx->max_version, version);
+}
+
+int SSL_set_min_proto_version(SSL *ssl, uint16_t version) {
+ return set_min_version(ssl->method, &ssl->min_version, version);
+}
+
+int SSL_set_max_proto_version(SSL *ssl, uint16_t version) {
+ return set_max_version(ssl->method, &ssl->max_version, version);
+}
+
+uint32_t SSL_CTX_set_options(SSL_CTX *ctx, uint32_t options) {
+ ctx->options |= options;
+ return ctx->options;
+}
+
+uint32_t SSL_CTX_clear_options(SSL_CTX *ctx, uint32_t options) {
+ ctx->options &= ~options;
+ return ctx->options;
+}
+
+uint32_t SSL_CTX_get_options(const SSL_CTX *ctx) { return ctx->options; }
+
+uint32_t SSL_set_options(SSL *ssl, uint32_t options) {
+ ssl->options |= options;
+ return ssl->options;
+}
+
+uint32_t SSL_clear_options(SSL *ssl, uint32_t options) {
+ ssl->options &= ~options;
+ return ssl->options;
+}
+
+uint32_t SSL_get_options(const SSL *ssl) { return ssl->options; }
+
+uint32_t SSL_CTX_set_mode(SSL_CTX *ctx, uint32_t mode) {
+ ctx->mode |= mode;
+ return ctx->mode;
+}
+
+uint32_t SSL_CTX_clear_mode(SSL_CTX *ctx, uint32_t mode) {
+ ctx->mode &= ~mode;
+ return ctx->mode;
+}
+
+uint32_t SSL_CTX_get_mode(const SSL_CTX *ctx) { return ctx->mode; }
+
+uint32_t SSL_set_mode(SSL *ssl, uint32_t mode) {
+ ssl->mode |= mode;
+ return ssl->mode;
+}
+
+uint32_t SSL_clear_mode(SSL *ssl, uint32_t mode) {
+ ssl->mode &= ~mode;
+ return ssl->mode;
+}
+
+uint32_t SSL_get_mode(const SSL *ssl) { return ssl->mode; }
+
+void SSL_CTX_set0_buffer_pool(SSL_CTX *ctx, CRYPTO_BUFFER_POOL *pool) {
+ ctx->pool = pool;
+}
+
+int SSL_get_tls_unique(const SSL *ssl, uint8_t *out, size_t *out_len,
+ size_t max_out) {
+ /* tls-unique is not defined for SSL 3.0 or TLS 1.3. */
+ if (!ssl->s3->initial_handshake_complete ||
+ ssl3_protocol_version(ssl) < TLS1_VERSION ||
+ ssl3_protocol_version(ssl) >= TLS1_3_VERSION) {
+ goto err;
+ }
+
+ /* The tls-unique value is the first Finished message in the handshake, which
+ * is the client's in a full handshake and the server's for a resumption. See
+ * https://tools.ietf.org/html/rfc5929#section-3.1. */
+ const uint8_t *finished = ssl->s3->previous_client_finished;
+ size_t finished_len = ssl->s3->previous_client_finished_len;
+ if (ssl->session != NULL) {
+ /* tls-unique is broken for resumed sessions unless EMS is used. */
+ if (!ssl->session->extended_master_secret) {
+ goto err;
+ }
+ finished = ssl->s3->previous_server_finished;
+ finished_len = ssl->s3->previous_server_finished_len;
+ }
+
+ *out_len = finished_len;
+ if (finished_len > max_out) {
+ *out_len = max_out;
+ }
+
+ OPENSSL_memcpy(out, finished, *out_len);
+ return 1;
+
+err:
+ *out_len = 0;
+ OPENSSL_memset(out, 0, max_out);
+ return 0;
+}
+
+static int set_session_id_context(CERT *cert, const uint8_t *sid_ctx,
+ size_t sid_ctx_len) {
+ if (sid_ctx_len > sizeof(cert->sid_ctx)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG);
+ return 0;
+ }
+
+ OPENSSL_COMPILE_ASSERT(sizeof(cert->sid_ctx) < 256, sid_ctx_too_large);
+ cert->sid_ctx_length = (uint8_t)sid_ctx_len;
+ OPENSSL_memcpy(cert->sid_ctx, sid_ctx, sid_ctx_len);
+ return 1;
+}
+
+int SSL_CTX_set_session_id_context(SSL_CTX *ctx, const uint8_t *sid_ctx,
+ size_t sid_ctx_len) {
+ return set_session_id_context(ctx->cert, sid_ctx, sid_ctx_len);
+}
+
+int SSL_set_session_id_context(SSL *ssl, const uint8_t *sid_ctx,
+ size_t sid_ctx_len) {
+ return set_session_id_context(ssl->cert, sid_ctx, sid_ctx_len);
+}
+
+const uint8_t *SSL_get0_session_id_context(const SSL *ssl, size_t *out_len) {
+ *out_len = ssl->cert->sid_ctx_length;
+ return ssl->cert->sid_ctx;
+}
+
+void ssl_cipher_preference_list_free(
+ struct ssl_cipher_preference_list_st *cipher_list) {
+ if (cipher_list == NULL) {
+ return;
+ }
+ sk_SSL_CIPHER_free(cipher_list->ciphers);
+ OPENSSL_free(cipher_list->in_group_flags);
+ OPENSSL_free(cipher_list);
+}
+
+void SSL_certs_clear(SSL *ssl) { ssl_cert_clear_certs(ssl->cert); }
+
+int SSL_get_fd(const SSL *ssl) { return SSL_get_rfd(ssl); }
+
+int SSL_get_rfd(const SSL *ssl) {
+ int ret = -1;
+ BIO *b = BIO_find_type(SSL_get_rbio(ssl), BIO_TYPE_DESCRIPTOR);
+ if (b != NULL) {
+ BIO_get_fd(b, &ret);
+ }
+ return ret;
+}
+
+int SSL_get_wfd(const SSL *ssl) {
+ int ret = -1;
+ BIO *b = BIO_find_type(SSL_get_wbio(ssl), BIO_TYPE_DESCRIPTOR);
+ if (b != NULL) {
+ BIO_get_fd(b, &ret);
+ }
+ return ret;
+}
+
+int SSL_set_fd(SSL *ssl, int fd) {
+ BIO *bio = BIO_new(BIO_s_socket());
+ if (bio == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
+ return 0;
+ }
+ BIO_set_fd(bio, fd, BIO_NOCLOSE);
+ SSL_set_bio(ssl, bio, bio);
+ return 1;
+}
+
+int SSL_set_wfd(SSL *ssl, int fd) {
+ BIO *rbio = SSL_get_rbio(ssl);
+ if (rbio == NULL || BIO_method_type(rbio) != BIO_TYPE_SOCKET ||
+ BIO_get_fd(rbio, NULL) != fd) {
+ BIO *bio = BIO_new(BIO_s_socket());
+ if (bio == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
+ return 0;
+ }
+ BIO_set_fd(bio, fd, BIO_NOCLOSE);
+ SSL_set0_wbio(ssl, bio);
+ } else {
+ /* Copy the rbio over to the wbio. */
+ BIO_up_ref(rbio);
+ SSL_set0_wbio(ssl, rbio);
+ }
+
+ return 1;
+}
+
+int SSL_set_rfd(SSL *ssl, int fd) {
+ BIO *wbio = SSL_get_wbio(ssl);
+ if (wbio == NULL || BIO_method_type(wbio) != BIO_TYPE_SOCKET ||
+ BIO_get_fd(wbio, NULL) != fd) {
+ BIO *bio = BIO_new(BIO_s_socket());
+ if (bio == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
+ return 0;
+ }
+ BIO_set_fd(bio, fd, BIO_NOCLOSE);
+ SSL_set0_rbio(ssl, bio);
+ } else {
+ /* Copy the wbio over to the rbio. */
+ BIO_up_ref(wbio);
+ SSL_set0_rbio(ssl, wbio);
+ }
+ return 1;
+}
+
+static size_t copy_finished(void *out, size_t out_len, const uint8_t *in,
+ size_t in_len) {
+ if (out_len > in_len) {
+ out_len = in_len;
+ }
+ OPENSSL_memcpy(out, in, out_len);
+ return in_len;
+}
+
+size_t SSL_get_finished(const SSL *ssl, void *buf, size_t count) {
+ if (!ssl->s3->initial_handshake_complete ||
+ ssl3_protocol_version(ssl) < TLS1_VERSION ||
+ ssl3_protocol_version(ssl) >= TLS1_3_VERSION) {
+ return 0;
+ }
+
+ if (ssl->server) {
+ return copy_finished(buf, count, ssl->s3->previous_server_finished,
+ ssl->s3->previous_server_finished_len);
+ }
+
+ return copy_finished(buf, count, ssl->s3->previous_client_finished,
+ ssl->s3->previous_client_finished_len);
+}
+
+size_t SSL_get_peer_finished(const SSL *ssl, void *buf, size_t count) {
+ if (!ssl->s3->initial_handshake_complete ||
+ ssl3_protocol_version(ssl) < TLS1_VERSION ||
+ ssl3_protocol_version(ssl) >= TLS1_3_VERSION) {
+ return 0;
+ }
+
+ if (ssl->server) {
+ return copy_finished(buf, count, ssl->s3->previous_client_finished,
+ ssl->s3->previous_client_finished_len);
+ }
+
+ return copy_finished(buf, count, ssl->s3->previous_server_finished,
+ ssl->s3->previous_server_finished_len);
+}
+
+int SSL_get_verify_mode(const SSL *ssl) { return ssl->verify_mode; }
+
+int SSL_get_extms_support(const SSL *ssl) {
+ /* TLS 1.3 does not require extended master secret and always reports as
+ * supporting it. */
+ if (!ssl->s3->have_version) {
+ return 0;
+ }
+ if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) {
+ return 1;
+ }
+
+ /* If the initial handshake completed, query the established session. */
+ if (ssl->s3->established_session != NULL) {
+ return ssl->s3->established_session->extended_master_secret;
+ }
+
+ /* Otherwise, query the in-progress handshake. */
+ if (ssl->s3->hs != NULL) {
+ return ssl->s3->hs->extended_master_secret;
+ }
+ assert(0);
+ return 0;
+}
+
+int SSL_CTX_get_read_ahead(const SSL_CTX *ctx) { return 0; }
+
+int SSL_get_read_ahead(const SSL *ssl) { return 0; }
+
+void SSL_CTX_set_read_ahead(SSL_CTX *ctx, int yes) { }
+
+void SSL_set_read_ahead(SSL *ssl, int yes) { }
+
+int SSL_pending(const SSL *ssl) {
+ if (ssl->s3->rrec.type != SSL3_RT_APPLICATION_DATA) {
+ return 0;
+ }
+ return ssl->s3->rrec.length;
+}
+
+/* Fix this so it checks all the valid key/cert options */
+int SSL_CTX_check_private_key(const SSL_CTX *ctx) {
+ return ssl_cert_check_private_key(ctx->cert, ctx->cert->privatekey);
+}
+
+/* Fix this function so that it takes an optional type parameter */
+int SSL_check_private_key(const SSL *ssl) {
+ return ssl_cert_check_private_key(ssl->cert, ssl->cert->privatekey);
+}
+
+long SSL_get_default_timeout(const SSL *ssl) {
+ return SSL_DEFAULT_SESSION_TIMEOUT;
+}
+
+int SSL_renegotiate(SSL *ssl) {
+ /* Caller-initiated renegotiation is not supported. */
+ OPENSSL_PUT_ERROR(SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return 0;
+}
+
+int SSL_renegotiate_pending(SSL *ssl) {
+ return SSL_in_init(ssl) && ssl->s3->initial_handshake_complete;
+}
+
+int SSL_total_renegotiations(const SSL *ssl) {
+ return ssl->s3->total_renegotiations;
+}
+
+size_t SSL_CTX_get_max_cert_list(const SSL_CTX *ctx) {
+ return ctx->max_cert_list;
+}
+
+void SSL_CTX_set_max_cert_list(SSL_CTX *ctx, size_t max_cert_list) {
+ if (max_cert_list > kMaxHandshakeSize) {
+ max_cert_list = kMaxHandshakeSize;
+ }
+ ctx->max_cert_list = (uint32_t)max_cert_list;
+}
+
+size_t SSL_get_max_cert_list(const SSL *ssl) {
+ return ssl->max_cert_list;
+}
+
+void SSL_set_max_cert_list(SSL *ssl, size_t max_cert_list) {
+ if (max_cert_list > kMaxHandshakeSize) {
+ max_cert_list = kMaxHandshakeSize;
+ }
+ ssl->max_cert_list = (uint32_t)max_cert_list;
+}
+
+int SSL_CTX_set_max_send_fragment(SSL_CTX *ctx, size_t max_send_fragment) {
+ if (max_send_fragment < 512) {
+ max_send_fragment = 512;
+ }
+ if (max_send_fragment > SSL3_RT_MAX_PLAIN_LENGTH) {
+ max_send_fragment = SSL3_RT_MAX_PLAIN_LENGTH;
+ }
+ ctx->max_send_fragment = (uint16_t)max_send_fragment;
+
+ return 1;
+}
+
+int SSL_set_max_send_fragment(SSL *ssl, size_t max_send_fragment) {
+ if (max_send_fragment < 512) {
+ max_send_fragment = 512;
+ }
+ if (max_send_fragment > SSL3_RT_MAX_PLAIN_LENGTH) {
+ max_send_fragment = SSL3_RT_MAX_PLAIN_LENGTH;
+ }
+ ssl->max_send_fragment = (uint16_t)max_send_fragment;
+
+ return 1;
+}
+
+int SSL_set_mtu(SSL *ssl, unsigned mtu) {
+ if (!SSL_is_dtls(ssl) || mtu < dtls1_min_mtu()) {
+ return 0;
+ }
+ ssl->d1->mtu = mtu;
+ return 1;
+}
+
+int SSL_get_secure_renegotiation_support(const SSL *ssl) {
+ if (!ssl->s3->have_version) {
+ return 0;
+ }
+ return ssl3_protocol_version(ssl) >= TLS1_3_VERSION ||
+ ssl->s3->send_connection_binding;
+}
+
+LHASH_OF(SSL_SESSION) *SSL_CTX_sessions(SSL_CTX *ctx) { return ctx->sessions; }
+
+size_t SSL_CTX_sess_number(const SSL_CTX *ctx) {
+ return lh_SSL_SESSION_num_items(ctx->sessions);
+}
+
+unsigned long SSL_CTX_sess_set_cache_size(SSL_CTX *ctx, unsigned long size) {
+ unsigned long ret = ctx->session_cache_size;
+ ctx->session_cache_size = size;
+ return ret;
+}
+
+unsigned long SSL_CTX_sess_get_cache_size(const SSL_CTX *ctx) {
+ return ctx->session_cache_size;
+}
+
+int SSL_CTX_set_session_cache_mode(SSL_CTX *ctx, int mode) {
+ int ret = ctx->session_cache_mode;
+ ctx->session_cache_mode = mode;
+ return ret;
+}
+
+int SSL_CTX_get_session_cache_mode(const SSL_CTX *ctx) {
+ return ctx->session_cache_mode;
+}
+
+
+int SSL_CTX_get_tlsext_ticket_keys(SSL_CTX *ctx, void *out, size_t len) {
+ if (out == NULL) {
+ return 48;
+ }
+ if (len != 48) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_TICKET_KEYS_LENGTH);
+ return 0;
+ }
+ uint8_t *out_bytes = out;
+ OPENSSL_memcpy(out_bytes, ctx->tlsext_tick_key_name, 16);
+ OPENSSL_memcpy(out_bytes + 16, ctx->tlsext_tick_hmac_key, 16);
+ OPENSSL_memcpy(out_bytes + 32, ctx->tlsext_tick_aes_key, 16);
+ return 1;
+}
+
+int SSL_CTX_set_tlsext_ticket_keys(SSL_CTX *ctx, const void *in, size_t len) {
+ if (in == NULL) {
+ return 48;
+ }
+ if (len != 48) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_TICKET_KEYS_LENGTH);
+ return 0;
+ }
+ const uint8_t *in_bytes = in;
+ OPENSSL_memcpy(ctx->tlsext_tick_key_name, in_bytes, 16);
+ OPENSSL_memcpy(ctx->tlsext_tick_hmac_key, in_bytes + 16, 16);
+ OPENSSL_memcpy(ctx->tlsext_tick_aes_key, in_bytes + 32, 16);
+ return 1;
+}
+
+int SSL_CTX_set_tlsext_ticket_key_cb(
+ SSL_CTX *ctx, int (*callback)(SSL *ssl, uint8_t *key_name, uint8_t *iv,
+ EVP_CIPHER_CTX *ctx, HMAC_CTX *hmac_ctx,
+ int encrypt)) {
+ ctx->tlsext_ticket_key_cb = callback;
+ return 1;
+}
+
+int SSL_CTX_set1_curves(SSL_CTX *ctx, const int *curves, size_t curves_len) {
+ return tls1_set_curves(&ctx->supported_group_list,
+ &ctx->supported_group_list_len, curves,
+ curves_len);
+}
+
+int SSL_set1_curves(SSL *ssl, const int *curves, size_t curves_len) {
+ return tls1_set_curves(&ssl->supported_group_list,
+ &ssl->supported_group_list_len, curves,
+ curves_len);
+}
+
+int SSL_CTX_set1_curves_list(SSL_CTX *ctx, const char *curves) {
+ return tls1_set_curves_list(&ctx->supported_group_list,
+ &ctx->supported_group_list_len, curves);
+}
+
+int SSL_set1_curves_list(SSL *ssl, const char *curves) {
+ return tls1_set_curves_list(&ssl->supported_group_list,
+ &ssl->supported_group_list_len, curves);
+}
+
+uint16_t SSL_get_curve_id(const SSL *ssl) {
+ /* TODO(davidben): This checks the wrong session if there is a renegotiation in
+ * progress. */
+ SSL_SESSION *session = SSL_get_session(ssl);
+ if (session == NULL) {
+ return 0;
+ }
+
+ return session->group_id;
+}
+
+int SSL_CTX_set_tmp_dh(SSL_CTX *ctx, const DH *dh) {
+ DH_free(ctx->cert->dh_tmp);
+ ctx->cert->dh_tmp = DHparams_dup(dh);
+ if (ctx->cert->dh_tmp == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_DH_LIB);
+ return 0;
+ }
+ return 1;
+}
+
+int SSL_set_tmp_dh(SSL *ssl, const DH *dh) {
+ DH_free(ssl->cert->dh_tmp);
+ ssl->cert->dh_tmp = DHparams_dup(dh);
+ if (ssl->cert->dh_tmp == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_DH_LIB);
+ return 0;
+ }
+ return 1;
+}
+
+OPENSSL_EXPORT STACK_OF(SSL_CIPHER) *SSL_CTX_get_ciphers(const SSL_CTX *ctx) {
+ return ctx->cipher_list->ciphers;
+}
+
+STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *ssl) {
+ if (ssl == NULL) {
+ return NULL;
+ }
+
+ const struct ssl_cipher_preference_list_st *prefs =
+ ssl_get_cipher_preferences(ssl);
+ if (prefs == NULL) {
+ return NULL;
+ }
+
+ return prefs->ciphers;
+}
+
+const char *SSL_get_cipher_list(const SSL *ssl, int n) {
+ if (ssl == NULL) {
+ return NULL;
+ }
+
+ STACK_OF(SSL_CIPHER) *sk = SSL_get_ciphers(ssl);
+ if (sk == NULL || n < 0 || (size_t)n >= sk_SSL_CIPHER_num(sk)) {
+ return NULL;
+ }
+
+ const SSL_CIPHER *c = sk_SSL_CIPHER_value(sk, n);
+ if (c == NULL) {
+ return NULL;
+ }
+
+ return c->name;
+}
+
+int SSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str) {
+ return ssl_create_cipher_list(ctx->method, &ctx->cipher_list, str,
+ 0 /* not strict */);
+}
+
+int SSL_CTX_set_strict_cipher_list(SSL_CTX *ctx, const char *str) {
+ return ssl_create_cipher_list(ctx->method, &ctx->cipher_list, str,
+ 1 /* strict */);
+}
+
+int SSL_set_cipher_list(SSL *ssl, const char *str) {
+ return ssl_create_cipher_list(ssl->ctx->method, &ssl->cipher_list, str,
+ 0 /* not strict */);
+}
+
+int SSL_set_strict_cipher_list(SSL *ssl, const char *str) {
+ return ssl_create_cipher_list(ssl->ctx->method, &ssl->cipher_list, str,
+ 1 /* strict */);
+}
+
+const char *SSL_get_servername(const SSL *ssl, const int type) {
+ if (type != TLSEXT_NAMETYPE_host_name) {
+ return NULL;
+ }
+
+ /* Historically, |SSL_get_servername| was also the configuration getter
+ * corresponding to |SSL_set_tlsext_host_name|. */
+ if (ssl->tlsext_hostname != NULL) {
+ return ssl->tlsext_hostname;
+ }
+
+ /* During the handshake, report the handshake value. */
+ if (ssl->s3->hs != NULL) {
+ return ssl->s3->hs->hostname;
+ }
+
+ /* SSL_get_servername may also be called after the handshake to look up the
+ * SNI value.
+ *
+ * TODO(davidben): This is almost unused. Can we remove it? */
+ SSL_SESSION *session = SSL_get_session(ssl);
+ if (session == NULL) {
+ return NULL;
+ }
+ return session->tlsext_hostname;
+}
+
+int SSL_get_servername_type(const SSL *ssl) {
+ SSL_SESSION *session = SSL_get_session(ssl);
+ if (session == NULL || session->tlsext_hostname == NULL) {
+ return -1;
+ }
+ return TLSEXT_NAMETYPE_host_name;
+}
+
+void SSL_CTX_enable_signed_cert_timestamps(SSL_CTX *ctx) {
+ ctx->signed_cert_timestamps_enabled = 1;
+}
+
+void SSL_CTX_i_promise_to_verify_certs_after_the_handshake(SSL_CTX *ctx) {
+ ctx->i_promise_to_verify_certs_after_the_handshake = 1;
+}
+
+void SSL_enable_signed_cert_timestamps(SSL *ssl) {
+ ssl->signed_cert_timestamps_enabled = 1;
+}
+
+void SSL_CTX_enable_ocsp_stapling(SSL_CTX *ctx) {
+ ctx->ocsp_stapling_enabled = 1;
+}
+
+void SSL_enable_ocsp_stapling(SSL *ssl) {
+ ssl->ocsp_stapling_enabled = 1;
+}
+
+void SSL_get0_signed_cert_timestamp_list(const SSL *ssl, const uint8_t **out,
+ size_t *out_len) {
+ SSL_SESSION *session = SSL_get_session(ssl);
+
+ *out_len = 0;
+ *out = NULL;
+ if (ssl->server || !session || !session->tlsext_signed_cert_timestamp_list) {
+ return;
+ }
+
+ *out = session->tlsext_signed_cert_timestamp_list;
+ *out_len = session->tlsext_signed_cert_timestamp_list_length;
+}
+
+void SSL_get0_ocsp_response(const SSL *ssl, const uint8_t **out,
+ size_t *out_len) {
+ SSL_SESSION *session = SSL_get_session(ssl);
+
+ *out_len = 0;
+ *out = NULL;
+ if (ssl->server || !session || !session->ocsp_response) {
+ return;
+ }
+ *out = session->ocsp_response;
+ *out_len = session->ocsp_response_length;
+}
+
+int SSL_set_tlsext_host_name(SSL *ssl, const char *name) {
+ OPENSSL_free(ssl->tlsext_hostname);
+ ssl->tlsext_hostname = NULL;
+
+ if (name == NULL) {
+ return 1;
+ }
+
+ size_t len = strlen(name);
+ if (len == 0 || len > TLSEXT_MAXLEN_host_name) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_SSL3_EXT_INVALID_SERVERNAME);
+ return 0;
+ }
+ ssl->tlsext_hostname = BUF_strdup(name);
+ if (ssl->tlsext_hostname == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ return 1;
+}
+
+int SSL_CTX_set_tlsext_servername_callback(
+ SSL_CTX *ctx, int (*callback)(SSL *ssl, int *out_alert, void *arg)) {
+ ctx->tlsext_servername_callback = callback;
+ return 1;
+}
+
+int SSL_CTX_set_tlsext_servername_arg(SSL_CTX *ctx, void *arg) {
+ ctx->tlsext_servername_arg = arg;
+ return 1;
+}
+
+int SSL_select_next_proto(uint8_t **out, uint8_t *out_len,
+ const uint8_t *server, unsigned server_len,
+ const uint8_t *client, unsigned client_len) {
+ unsigned int i, j;
+ const uint8_t *result;
+ int status = OPENSSL_NPN_UNSUPPORTED;
+
+ /* For each protocol in server preference order, see if we support it. */
+ for (i = 0; i < server_len;) {
+ for (j = 0; j < client_len;) {
+ if (server[i] == client[j] &&
+ OPENSSL_memcmp(&server[i + 1], &client[j + 1], server[i]) == 0) {
+ /* We found a match */
+ result = &server[i];
+ status = OPENSSL_NPN_NEGOTIATED;
+ goto found;
+ }
+ j += client[j];
+ j++;
+ }
+ i += server[i];
+ i++;
+ }
+
+ /* There's no overlap between our protocols and the server's list. */
+ result = client;
+ status = OPENSSL_NPN_NO_OVERLAP;
+
+found:
+ *out = (uint8_t *)result + 1;
+ *out_len = result[0];
+ return status;
+}
+
+void SSL_get0_next_proto_negotiated(const SSL *ssl, const uint8_t **out_data,
+ unsigned *out_len) {
+ *out_data = ssl->s3->next_proto_negotiated;
+ if (*out_data == NULL) {
+ *out_len = 0;
+ } else {
+ *out_len = ssl->s3->next_proto_negotiated_len;
+ }
+}
+
+void SSL_CTX_set_next_protos_advertised_cb(
+ SSL_CTX *ctx,
+ int (*cb)(SSL *ssl, const uint8_t **out, unsigned *out_len, void *arg),
+ void *arg) {
+ ctx->next_protos_advertised_cb = cb;
+ ctx->next_protos_advertised_cb_arg = arg;
+}
+
+void SSL_CTX_set_next_proto_select_cb(
+ SSL_CTX *ctx, int (*cb)(SSL *ssl, uint8_t **out, uint8_t *out_len,
+ const uint8_t *in, unsigned in_len, void *arg),
+ void *arg) {
+ ctx->next_proto_select_cb = cb;
+ ctx->next_proto_select_cb_arg = arg;
+}
+
+int SSL_CTX_set_alpn_protos(SSL_CTX *ctx, const uint8_t *protos,
+ unsigned protos_len) {
+ OPENSSL_free(ctx->alpn_client_proto_list);
+ ctx->alpn_client_proto_list = BUF_memdup(protos, protos_len);
+ if (!ctx->alpn_client_proto_list) {
+ return 1;
+ }
+ ctx->alpn_client_proto_list_len = protos_len;
+
+ return 0;
+}
+
+int SSL_set_alpn_protos(SSL *ssl, const uint8_t *protos, unsigned protos_len) {
+ OPENSSL_free(ssl->alpn_client_proto_list);
+ ssl->alpn_client_proto_list = BUF_memdup(protos, protos_len);
+ if (!ssl->alpn_client_proto_list) {
+ return 1;
+ }
+ ssl->alpn_client_proto_list_len = protos_len;
+
+ return 0;
+}
+
+void SSL_CTX_set_alpn_select_cb(SSL_CTX *ctx,
+ int (*cb)(SSL *ssl, const uint8_t **out,
+ uint8_t *out_len, const uint8_t *in,
+ unsigned in_len, void *arg),
+ void *arg) {
+ ctx->alpn_select_cb = cb;
+ ctx->alpn_select_cb_arg = arg;
+}
+
+void SSL_get0_alpn_selected(const SSL *ssl, const uint8_t **out_data,
+ unsigned *out_len) {
+ *out_data = NULL;
+ if (ssl->s3) {
+ *out_data = ssl->s3->alpn_selected;
+ }
+ if (*out_data == NULL) {
+ *out_len = 0;
+ } else {
+ *out_len = ssl->s3->alpn_selected_len;
+ }
+}
+
+
+void SSL_CTX_set_tls_channel_id_enabled(SSL_CTX *ctx, int enabled) {
+ ctx->tlsext_channel_id_enabled = !!enabled;
+}
+
+int SSL_CTX_enable_tls_channel_id(SSL_CTX *ctx) {
+ SSL_CTX_set_tls_channel_id_enabled(ctx, 1);
+ return 1;
+}
+
+void SSL_set_tls_channel_id_enabled(SSL *ssl, int enabled) {
+ ssl->tlsext_channel_id_enabled = !!enabled;
+}
+
+int SSL_enable_tls_channel_id(SSL *ssl) {
+ SSL_set_tls_channel_id_enabled(ssl, 1);
+ return 1;
+}
+
+static int is_p256_key(EVP_PKEY *private_key) {
+ const EC_KEY *ec_key = EVP_PKEY_get0_EC_KEY(private_key);
+ return ec_key != NULL &&
+ EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key)) ==
+ NID_X9_62_prime256v1;
+}
+
+int SSL_CTX_set1_tls_channel_id(SSL_CTX *ctx, EVP_PKEY *private_key) {
+ if (!is_p256_key(private_key)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CHANNEL_ID_NOT_P256);
+ return 0;
+ }
+
+ EVP_PKEY_free(ctx->tlsext_channel_id_private);
+ EVP_PKEY_up_ref(private_key);
+ ctx->tlsext_channel_id_private = private_key;
+ ctx->tlsext_channel_id_enabled = 1;
+
+ return 1;
+}
+
+int SSL_set1_tls_channel_id(SSL *ssl, EVP_PKEY *private_key) {
+ if (!is_p256_key(private_key)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CHANNEL_ID_NOT_P256);
+ return 0;
+ }
+
+ EVP_PKEY_free(ssl->tlsext_channel_id_private);
+ EVP_PKEY_up_ref(private_key);
+ ssl->tlsext_channel_id_private = private_key;
+ ssl->tlsext_channel_id_enabled = 1;
+
+ return 1;
+}
+
+size_t SSL_get_tls_channel_id(SSL *ssl, uint8_t *out, size_t max_out) {
+ if (!ssl->s3->tlsext_channel_id_valid) {
+ return 0;
+ }
+ OPENSSL_memcpy(out, ssl->s3->tlsext_channel_id,
+ (max_out < 64) ? max_out : 64);
+ return 64;
+}
+
+size_t SSL_get0_certificate_types(SSL *ssl, const uint8_t **out_types) {
+ if (ssl->server || ssl->s3->hs == NULL) {
+ *out_types = NULL;
+ return 0;
+ }
+ *out_types = ssl->s3->hs->certificate_types;
+ return ssl->s3->hs->num_certificate_types;
+}
+
+void ssl_update_cache(SSL_HANDSHAKE *hs, int mode) {
+ SSL *const ssl = hs->ssl;
+ SSL_CTX *ctx = ssl->session_ctx;
+ /* Never cache sessions with empty session IDs. */
+ if (ssl->s3->established_session->session_id_length == 0 ||
+ (ctx->session_cache_mode & mode) != mode) {
+ return;
+ }
+
+ /* Clients never use the internal session cache. */
+ int use_internal_cache = ssl->server && !(ctx->session_cache_mode &
+ SSL_SESS_CACHE_NO_INTERNAL_STORE);
+
+ /* A client may see new sessions on abbreviated handshakes if the server
+ * decides to renew the ticket. Once the handshake is completed, it should be
+ * inserted into the cache. */
+ if (ssl->s3->established_session != ssl->session ||
+ (!ssl->server && hs->ticket_expected)) {
+ if (use_internal_cache) {
+ SSL_CTX_add_session(ctx, ssl->s3->established_session);
+ }
+ if (ctx->new_session_cb != NULL) {
+ SSL_SESSION_up_ref(ssl->s3->established_session);
+ if (!ctx->new_session_cb(ssl, ssl->s3->established_session)) {
+ /* |new_session_cb|'s return value signals whether it took ownership. */
+ SSL_SESSION_free(ssl->s3->established_session);
+ }
+ }
+ }
+
+ if (use_internal_cache &&
+ !(ctx->session_cache_mode & SSL_SESS_CACHE_NO_AUTO_CLEAR)) {
+ /* Automatically flush the internal session cache every 255 connections. */
+ int flush_cache = 0;
+ CRYPTO_MUTEX_lock_write(&ctx->lock);
+ ctx->handshakes_since_cache_flush++;
+ if (ctx->handshakes_since_cache_flush >= 255) {
+ flush_cache = 1;
+ ctx->handshakes_since_cache_flush = 0;
+ }
+ CRYPTO_MUTEX_unlock_write(&ctx->lock);
+
+ if (flush_cache) {
+ struct OPENSSL_timeval now;
+ ssl_get_current_time(ssl, &now);
+ SSL_CTX_flush_sessions(ctx, now.tv_sec);
+ }
+ }
+}
+
+static const char *ssl_get_version(int version) {
+ switch (version) {
+ /* Report TLS 1.3 draft version as TLS 1.3 in the public API. */
+ case TLS1_3_DRAFT_VERSION:
+ return "TLSv1.3";
+
+ case TLS1_2_VERSION:
+ return "TLSv1.2";
+
+ case TLS1_1_VERSION:
+ return "TLSv1.1";
+
+ case TLS1_VERSION:
+ return "TLSv1";
+
+ case SSL3_VERSION:
+ return "SSLv3";
+
+ case DTLS1_VERSION:
+ return "DTLSv1";
+
+ case DTLS1_2_VERSION:
+ return "DTLSv1.2";
+
+ default:
+ return "unknown";
+ }
+}
+
+const char *SSL_get_version(const SSL *ssl) {
+ return ssl_get_version(ssl->version);
+}
+
+const char *SSL_SESSION_get_version(const SSL_SESSION *session) {
+ return ssl_get_version(session->ssl_version);
+}
+
+EVP_PKEY *SSL_get_privatekey(const SSL *ssl) {
+ if (ssl->cert != NULL) {
+ return ssl->cert->privatekey;
+ }
+
+ return NULL;
+}
+
+EVP_PKEY *SSL_CTX_get0_privatekey(const SSL_CTX *ctx) {
+ if (ctx->cert != NULL) {
+ return ctx->cert->privatekey;
+ }
+
+ return NULL;
+}
+
+const SSL_CIPHER *SSL_get_current_cipher(const SSL *ssl) {
+ if (ssl->s3->aead_write_ctx == NULL) {
+ return NULL;
+ }
+ return ssl->s3->aead_write_ctx->cipher;
+}
+
+int SSL_session_reused(const SSL *ssl) {
+ return ssl->s3->session_reused;
+}
+
+const COMP_METHOD *SSL_get_current_compression(SSL *ssl) { return NULL; }
+
+const COMP_METHOD *SSL_get_current_expansion(SSL *ssl) { return NULL; }
+
+int *SSL_get_server_tmp_key(SSL *ssl, EVP_PKEY **out_key) { return 0; }
+
+void SSL_CTX_set_quiet_shutdown(SSL_CTX *ctx, int mode) {
+ ctx->quiet_shutdown = (mode != 0);
+}
+
+int SSL_CTX_get_quiet_shutdown(const SSL_CTX *ctx) {
+ return ctx->quiet_shutdown;
+}
+
+void SSL_set_quiet_shutdown(SSL *ssl, int mode) {
+ ssl->quiet_shutdown = (mode != 0);
+}
+
+int SSL_get_quiet_shutdown(const SSL *ssl) { return ssl->quiet_shutdown; }
+
+void SSL_set_shutdown(SSL *ssl, int mode) {
+ /* It is an error to clear any bits that have already been set. (We can't try
+ * to get a second close_notify or send two.) */
+ assert((SSL_get_shutdown(ssl) & mode) == SSL_get_shutdown(ssl));
+
+ if (mode & SSL_RECEIVED_SHUTDOWN &&
+ ssl->s3->recv_shutdown == ssl_shutdown_none) {
+ ssl->s3->recv_shutdown = ssl_shutdown_close_notify;
+ }
+
+ if (mode & SSL_SENT_SHUTDOWN &&
+ ssl->s3->send_shutdown == ssl_shutdown_none) {
+ ssl->s3->send_shutdown = ssl_shutdown_close_notify;
+ }
+}
+
+int SSL_get_shutdown(const SSL *ssl) {
+ int ret = 0;
+ if (ssl->s3->recv_shutdown != ssl_shutdown_none) {
+ /* Historically, OpenSSL set |SSL_RECEIVED_SHUTDOWN| on both close_notify
+ * and fatal alert. */
+ ret |= SSL_RECEIVED_SHUTDOWN;
+ }
+ if (ssl->s3->send_shutdown == ssl_shutdown_close_notify) {
+ /* Historically, OpenSSL set |SSL_SENT_SHUTDOWN| on only close_notify. */
+ ret |= SSL_SENT_SHUTDOWN;
+ }
+ return ret;
+}
+
+int SSL_version(const SSL *ssl) {
+ /* Report TLS 1.3 draft version as TLS 1.3 in the public API. */
+ if (ssl->version == TLS1_3_DRAFT_VERSION) {
+ return TLS1_3_VERSION;
+ }
+
+ return ssl->version;
+}
+
+SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl) { return ssl->ctx; }
+
+SSL_CTX *SSL_set_SSL_CTX(SSL *ssl, SSL_CTX *ctx) {
+ if (ssl->ctx == ctx) {
+ return ssl->ctx;
+ }
+
+ /* One cannot change the X.509 callbacks during a connection. */
+ if (ssl->ctx->x509_method != ctx->x509_method) {
+ assert(0);
+ return NULL;
+ }
+
+ if (ctx == NULL) {
+ ctx = ssl->session_ctx;
+ }
+
+ ssl_cert_free(ssl->cert);
+ ssl->cert = ssl_cert_dup(ctx->cert);
+
+ SSL_CTX_up_ref(ctx);
+ SSL_CTX_free(ssl->ctx);
+ ssl->ctx = ctx;
+
+ return ssl->ctx;
+}
+
+void SSL_set_info_callback(SSL *ssl,
+ void (*cb)(const SSL *ssl, int type, int value)) {
+ ssl->info_callback = cb;
+}
+
+void (*SSL_get_info_callback(const SSL *ssl))(const SSL *ssl, int type,
+ int value) {
+ return ssl->info_callback;
+}
+
+int SSL_state(const SSL *ssl) {
+ return SSL_in_init(ssl) ? SSL_ST_INIT : SSL_ST_OK;
+}
+
+void SSL_set_state(SSL *ssl, int state) { }
+
+char *SSL_get_shared_ciphers(const SSL *ssl, char *buf, int len) {
+ if (len <= 0) {
+ return NULL;
+ }
+ buf[0] = '\0';
+ return buf;
+}
+
+int SSL_get_ex_new_index(long argl, void *argp, CRYPTO_EX_unused *unused,
+ CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func) {
+ int index;
+ if (!CRYPTO_get_ex_new_index(&g_ex_data_class_ssl, &index, argl, argp,
+ dup_func, free_func)) {
+ return -1;
+ }
+ return index;
+}
+
+int SSL_set_ex_data(SSL *ssl, int idx, void *arg) {
+ return CRYPTO_set_ex_data(&ssl->ex_data, idx, arg);
+}
+
+void *SSL_get_ex_data(const SSL *ssl, int idx) {
+ return CRYPTO_get_ex_data(&ssl->ex_data, idx);
+}
+
+int SSL_CTX_get_ex_new_index(long argl, void *argp, CRYPTO_EX_unused *unused,
+ CRYPTO_EX_dup *dup_func,
+ CRYPTO_EX_free *free_func) {
+ int index;
+ if (!CRYPTO_get_ex_new_index(&g_ex_data_class_ssl_ctx, &index, argl, argp,
+ dup_func, free_func)) {
+ return -1;
+ }
+ 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);
+}
+
+void *SSL_CTX_get_ex_data(const SSL_CTX *ctx, int idx) {
+ return CRYPTO_get_ex_data(&ctx->ex_data, idx);
+}
+
+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)) {
+}
+
+void SSL_set_tmp_rsa_callback(SSL *ssl, RSA *(*cb)(SSL *ssl, int is_export,
+ int keylength)) {
+}
+
+void SSL_CTX_set_tmp_dh_callback(SSL_CTX *ctx,
+ DH *(*callback)(SSL *ssl, int is_export,
+ int keylength)) {
+ ctx->cert->dh_tmp_cb = callback;
+}
+
+void SSL_set_tmp_dh_callback(SSL *ssl, DH *(*callback)(SSL *ssl, int is_export,
+ int keylength)) {
+ ssl->cert->dh_tmp_cb = callback;
+}
+
+int SSL_CTX_use_psk_identity_hint(SSL_CTX *ctx, const char *identity_hint) {
+ if (identity_hint != NULL && strlen(identity_hint) > PSK_MAX_IDENTITY_LEN) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DATA_LENGTH_TOO_LONG);
+ return 0;
+ }
+
+ OPENSSL_free(ctx->psk_identity_hint);
+
+ if (identity_hint != NULL) {
+ ctx->psk_identity_hint = BUF_strdup(identity_hint);
+ if (ctx->psk_identity_hint == NULL) {
+ return 0;
+ }
+ } else {
+ ctx->psk_identity_hint = NULL;
+ }
+
+ return 1;
+}
+
+int SSL_use_psk_identity_hint(SSL *ssl, const char *identity_hint) {
+ if (ssl == NULL) {
+ return 0;
+ }
+
+ if (identity_hint != NULL && strlen(identity_hint) > PSK_MAX_IDENTITY_LEN) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DATA_LENGTH_TOO_LONG);
+ return 0;
+ }
+
+ /* Clear currently configured hint, if any. */
+ OPENSSL_free(ssl->psk_identity_hint);
+ ssl->psk_identity_hint = NULL;
+
+ /* Treat the empty hint as not supplying one. Plain PSK makes it possible to
+ * send either no hint (omit ServerKeyExchange) or an empty hint, while
+ * ECDHE_PSK can only spell empty hint. Having different capabilities is odd,
+ * so we interpret empty and missing as identical. */
+ if (identity_hint != NULL && identity_hint[0] != '\0') {
+ ssl->psk_identity_hint = BUF_strdup(identity_hint);
+ if (ssl->psk_identity_hint == NULL) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+const char *SSL_get_psk_identity_hint(const SSL *ssl) {
+ if (ssl == NULL) {
+ return NULL;
+ }
+ return ssl->psk_identity_hint;
+}
+
+const char *SSL_get_psk_identity(const SSL *ssl) {
+ if (ssl == NULL) {
+ return NULL;
+ }
+ SSL_SESSION *session = SSL_get_session(ssl);
+ if (session == NULL) {
+ return NULL;
+ }
+ return session->psk_identity;
+}
+
+void SSL_set_psk_client_callback(
+ SSL *ssl, unsigned (*cb)(SSL *ssl, const char *hint, char *identity,
+ unsigned max_identity_len, uint8_t *psk,
+ unsigned max_psk_len)) {
+ ssl->psk_client_callback = cb;
+}
+
+void SSL_CTX_set_psk_client_callback(
+ SSL_CTX *ctx, unsigned (*cb)(SSL *ssl, const char *hint, char *identity,
+ unsigned max_identity_len, uint8_t *psk,
+ unsigned max_psk_len)) {
+ ctx->psk_client_callback = cb;
+}
+
+void SSL_set_psk_server_callback(
+ SSL *ssl, unsigned (*cb)(SSL *ssl, const char *identity, uint8_t *psk,
+ unsigned max_psk_len)) {
+ ssl->psk_server_callback = cb;
+}
+
+void SSL_CTX_set_psk_server_callback(
+ SSL_CTX *ctx, unsigned (*cb)(SSL *ssl, const char *identity,
+ uint8_t *psk, unsigned max_psk_len)) {
+ ctx->psk_server_callback = cb;
+}
+
+void SSL_CTX_set_msg_callback(SSL_CTX *ctx,
+ void (*cb)(int write_p, int version,
+ int content_type, const void *buf,
+ size_t len, SSL *ssl, void *arg)) {
+ ctx->msg_callback = cb;
+}
+
+void SSL_CTX_set_msg_callback_arg(SSL_CTX *ctx, void *arg) {
+ ctx->msg_callback_arg = arg;
+}
+
+void SSL_set_msg_callback(SSL *ssl,
+ void (*cb)(int write_p, int version, int content_type,
+ const void *buf, size_t len, SSL *ssl,
+ void *arg)) {
+ ssl->msg_callback = cb;
+}
+
+void SSL_set_msg_callback_arg(SSL *ssl, void *arg) {
+ ssl->msg_callback_arg = arg;
+}
+
+void SSL_CTX_set_keylog_callback(SSL_CTX *ctx,
+ void (*cb)(const SSL *ssl, const char *line)) {
+ ctx->keylog_callback = cb;
+}
+
+void (*SSL_CTX_get_keylog_callback(const SSL_CTX *ctx))(const SSL *ssl,
+ const char *line) {
+ return ctx->keylog_callback;
+}
+
+void SSL_CTX_set_current_time_cb(SSL_CTX *ctx,
+ void (*cb)(const SSL *ssl,
+ struct timeval *out_clock)) {
+ ctx->current_time_cb = cb;
+}
+
+static int cbb_add_hex(CBB *cbb, const uint8_t *in, size_t in_len) {
+ static const char hextable[] = "0123456789abcdef";
+ uint8_t *out;
+
+ if (!CBB_add_space(cbb, &out, in_len * 2)) {
+ return 0;
+ }
+
+ for (size_t i = 0; i < in_len; i++) {
+ *(out++) = (uint8_t)hextable[in[i] >> 4];
+ *(out++) = (uint8_t)hextable[in[i] & 0xf];
+ }
+
+ return 1;
+}
+
+int ssl_log_secret(const SSL *ssl, const char *label, const uint8_t *secret,
+ size_t secret_len) {
+ if (ssl->ctx->keylog_callback == NULL) {
+ return 1;
+ }
+
+ CBB cbb;
+ uint8_t *out;
+ size_t out_len;
+ if (!CBB_init(&cbb, strlen(label) + 1 + SSL3_RANDOM_SIZE * 2 + 1 +
+ secret_len * 2 + 1) ||
+ !CBB_add_bytes(&cbb, (const uint8_t *)label, strlen(label)) ||
+ !CBB_add_bytes(&cbb, (const uint8_t *)" ", 1) ||
+ !cbb_add_hex(&cbb, ssl->s3->client_random, SSL3_RANDOM_SIZE) ||
+ !CBB_add_bytes(&cbb, (const uint8_t *)" ", 1) ||
+ !cbb_add_hex(&cbb, secret, secret_len) ||
+ !CBB_add_u8(&cbb, 0 /* NUL */) ||
+ !CBB_finish(&cbb, &out, &out_len)) {
+ CBB_cleanup(&cbb);
+ return 0;
+ }
+
+ ssl->ctx->keylog_callback(ssl, (const char *)out);
+ OPENSSL_free(out);
+ return 1;
+}
+
+int SSL_is_init_finished(const SSL *ssl) {
+ return !SSL_in_init(ssl);
+}
+
+int SSL_in_init(const SSL *ssl) {
+ SSL_HANDSHAKE *hs = ssl->s3->hs;
+ return hs != NULL && hs->state != SSL_ST_OK;
+}
+
+int SSL_in_false_start(const SSL *ssl) {
+ if (ssl->s3->hs == NULL) {
+ return 0;
+ }
+ return ssl->s3->hs->in_false_start;
+}
+
+int SSL_cutthrough_complete(const SSL *ssl) {
+ return SSL_in_false_start(ssl);
+}
+
+void SSL_get_structure_sizes(size_t *ssl_size, size_t *ssl_ctx_size,
+ size_t *ssl_session_size) {
+ *ssl_size = sizeof(SSL);
+ *ssl_ctx_size = sizeof(SSL_CTX);
+ *ssl_session_size = sizeof(SSL_SESSION);
+}
+
+int ssl3_can_false_start(const SSL *ssl) {
+ const SSL_CIPHER *const cipher = SSL_get_current_cipher(ssl);
+
+ /* False Start only for TLS 1.2 with an ECDHE+AEAD cipher and ALPN or NPN. */
+ return !SSL_is_dtls(ssl) &&
+ SSL_version(ssl) == TLS1_2_VERSION &&
+ (ssl->s3->alpn_selected != NULL ||
+ ssl->s3->next_proto_negotiated != NULL) &&
+ cipher != NULL &&
+ cipher->algorithm_mkey == SSL_kECDHE &&
+ cipher->algorithm_mac == SSL_AEAD;
+}
+
+const struct {
+ uint16_t version;
+ uint32_t flag;
+} kVersions[] = {
+ {SSL3_VERSION, SSL_OP_NO_SSLv3},
+ {TLS1_VERSION, SSL_OP_NO_TLSv1},
+ {TLS1_1_VERSION, SSL_OP_NO_TLSv1_1},
+ {TLS1_2_VERSION, SSL_OP_NO_TLSv1_2},
+ {TLS1_3_VERSION, SSL_OP_NO_TLSv1_3},
+};
+
+static const size_t kVersionsLen = OPENSSL_ARRAY_SIZE(kVersions);
+
+int ssl_get_version_range(const SSL *ssl, uint16_t *out_min_version,
+ uint16_t *out_max_version) {
+ /* For historical reasons, |SSL_OP_NO_DTLSv1| aliases |SSL_OP_NO_TLSv1|, but
+ * DTLS 1.0 should be mapped to TLS 1.1. */
+ uint32_t options = ssl->options;
+ if (SSL_is_dtls(ssl)) {
+ options &= ~SSL_OP_NO_TLSv1_1;
+ if (options & SSL_OP_NO_DTLSv1) {
+ options |= SSL_OP_NO_TLSv1_1;
+ }
+ }
+
+ uint16_t min_version = ssl->min_version;
+ uint16_t max_version = ssl->max_version;
+
+ /* Bound the range to only those implemented in this protocol. */
+ if (min_version < ssl->method->min_version) {
+ min_version = ssl->method->min_version;
+ }
+ if (max_version > ssl->method->max_version) {
+ max_version = ssl->method->max_version;
+ }
+
+ /* OpenSSL's API for controlling versions entails blacklisting individual
+ * protocols. This has two problems. First, on the client, the protocol can
+ * only express a contiguous range of versions. Second, a library consumer
+ * trying to set a maximum version cannot disable protocol versions that get
+ * added in a future version of the library.
+ *
+ * To account for both of these, OpenSSL interprets the client-side bitmask
+ * as a min/max range by picking the lowest contiguous non-empty range of
+ * enabled protocols. Note that this means it is impossible to set a maximum
+ * version of the higest supported TLS version in a future-proof way. */
+ int any_enabled = 0;
+ for (size_t i = 0; i < kVersionsLen; i++) {
+ /* Only look at the versions already enabled. */
+ if (min_version > kVersions[i].version) {
+ continue;
+ }
+ if (max_version < kVersions[i].version) {
+ break;
+ }
+
+ if (!(options & kVersions[i].flag)) {
+ /* The minimum version is the first enabled version. */
+ if (!any_enabled) {
+ any_enabled = 1;
+ min_version = kVersions[i].version;
+ }
+ continue;
+ }
+
+ /* If there is a disabled version after the first enabled one, all versions
+ * after it are implicitly disabled. */
+ if (any_enabled) {
+ max_version = kVersions[i-1].version;
+ break;
+ }
+ }
+
+ if (!any_enabled) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SSL_VERSION);
+ return 0;
+ }
+
+ *out_min_version = min_version;
+ *out_max_version = max_version;
+ return 1;
+}
+
+uint16_t ssl3_protocol_version(const SSL *ssl) {
+ assert(ssl->s3->have_version);
+ uint16_t version;
+ if (!ssl->method->version_from_wire(&version, ssl->version)) {
+ /* TODO(davidben): Use the internal version representation for ssl->version
+ * and map to the public API representation at API boundaries. */
+ assert(0);
+ return 0;
+ }
+
+ return version;
+}
+
+int SSL_is_server(const SSL *ssl) { return ssl->server; }
+
+int SSL_is_dtls(const SSL *ssl) { return ssl->method->is_dtls; }
+
+void SSL_CTX_set_select_certificate_cb(SSL_CTX *ctx,
+ int (*cb)(const SSL_CLIENT_HELLO *)) {
+ ctx->select_certificate_cb = cb;
+}
+
+void SSL_CTX_set_dos_protection_cb(SSL_CTX *ctx,
+ int (*cb)(const SSL_CLIENT_HELLO *)) {
+ ctx->dos_protection_cb = cb;
+}
+
+void SSL_set_renegotiate_mode(SSL *ssl, enum ssl_renegotiate_mode_t mode) {
+ ssl->renegotiate_mode = mode;
+}
+
+int SSL_get_ivs(const SSL *ssl, const uint8_t **out_read_iv,
+ const uint8_t **out_write_iv, size_t *out_iv_len) {
+ if (ssl->s3->aead_read_ctx == NULL || ssl->s3->aead_write_ctx == NULL) {
+ return 0;
+ }
+
+ size_t write_iv_len;
+ if (!EVP_AEAD_CTX_get_iv(&ssl->s3->aead_read_ctx->ctx, out_read_iv,
+ out_iv_len) ||
+ !EVP_AEAD_CTX_get_iv(&ssl->s3->aead_write_ctx->ctx, out_write_iv,
+ &write_iv_len) ||
+ *out_iv_len != write_iv_len) {
+ return 0;
+ }
+
+ return 1;
+}
+
+static uint64_t be_to_u64(const uint8_t in[8]) {
+ return (((uint64_t)in[0]) << 56) | (((uint64_t)in[1]) << 48) |
+ (((uint64_t)in[2]) << 40) | (((uint64_t)in[3]) << 32) |
+ (((uint64_t)in[4]) << 24) | (((uint64_t)in[5]) << 16) |
+ (((uint64_t)in[6]) << 8) | ((uint64_t)in[7]);
+}
+
+uint64_t SSL_get_read_sequence(const SSL *ssl) {
+ /* TODO(davidben): Internally represent sequence numbers as uint64_t. */
+ if (SSL_is_dtls(ssl)) {
+ /* max_seq_num already includes the epoch. */
+ assert(ssl->d1->r_epoch == (ssl->d1->bitmap.max_seq_num >> 48));
+ return ssl->d1->bitmap.max_seq_num;
+ }
+ return be_to_u64(ssl->s3->read_sequence);
+}
+
+uint64_t SSL_get_write_sequence(const SSL *ssl) {
+ uint64_t ret = be_to_u64(ssl->s3->write_sequence);
+ if (SSL_is_dtls(ssl)) {
+ assert((ret >> 48) == 0);
+ ret |= ((uint64_t)ssl->d1->w_epoch) << 48;
+ }
+ return ret;
+}
+
+uint16_t SSL_get_peer_signature_algorithm(const SSL *ssl) {
+ /* TODO(davidben): This checks the wrong session if there is a renegotiation
+ * in progress. */
+ SSL_SESSION *session = SSL_get_session(ssl);
+ if (session == NULL) {
+ return 0;
+ }
+
+ return session->peer_signature_algorithm;
+}
+
+size_t SSL_get_client_random(const SSL *ssl, uint8_t *out, size_t max_out) {
+ if (max_out == 0) {
+ return sizeof(ssl->s3->client_random);
+ }
+ if (max_out > sizeof(ssl->s3->client_random)) {
+ max_out = sizeof(ssl->s3->client_random);
+ }
+ OPENSSL_memcpy(out, ssl->s3->client_random, max_out);
+ return max_out;
+}
+
+size_t SSL_get_server_random(const SSL *ssl, uint8_t *out, size_t max_out) {
+ if (max_out == 0) {
+ return sizeof(ssl->s3->server_random);
+ }
+ if (max_out > sizeof(ssl->s3->server_random)) {
+ max_out = sizeof(ssl->s3->server_random);
+ }
+ OPENSSL_memcpy(out, ssl->s3->server_random, max_out);
+ return max_out;
+}
+
+const SSL_CIPHER *SSL_get_pending_cipher(const SSL *ssl) {
+ SSL_HANDSHAKE *hs = ssl->s3->hs;
+ if (hs == NULL) {
+ return NULL;
+ }
+ return hs->new_cipher;
+}
+
+void SSL_set_retain_only_sha256_of_client_certs(SSL *ssl, int enabled) {
+ ssl->retain_only_sha256_of_client_certs = !!enabled;
+}
+
+void SSL_CTX_set_retain_only_sha256_of_client_certs(SSL_CTX *ctx, int enabled) {
+ ctx->retain_only_sha256_of_client_certs = !!enabled;
+}
+
+void SSL_CTX_set_grease_enabled(SSL_CTX *ctx, int enabled) {
+ ctx->grease_enabled = !!enabled;
+}
+
+int32_t SSL_get_ticket_age_skew(const SSL *ssl) {
+ return ssl->s3->ticket_age_skew;
+}
+
+int SSL_clear(SSL *ssl) {
+ /* In OpenSSL, reusing a client |SSL| with |SSL_clear| causes the previously
+ * established session to be offered the next time around. wpa_supplicant
+ * depends on this behavior, so emulate it. */
+ SSL_SESSION *session = NULL;
+ if (!ssl->server && ssl->s3->established_session != NULL) {
+ session = ssl->s3->established_session;
+ SSL_SESSION_up_ref(session);
+ }
+
+ /* TODO(davidben): Some state on |ssl| is reset both in |SSL_new| and
+ * |SSL_clear| because it is per-connection state rather than configuration
+ * state. Per-connection state should be on |ssl->s3| and |ssl->d1| so it is
+ * naturally reset at the right points between |SSL_new|, |SSL_clear|, and
+ * |ssl3_new|. */
+
+ ssl->rwstate = SSL_NOTHING;
+
+ BUF_MEM_free(ssl->init_buf);
+ ssl->init_buf = NULL;
+ ssl->init_msg = NULL;
+ ssl->init_num = 0;
+
+ /* The ssl->d1->mtu is simultaneously configuration (preserved across
+ * clear) and connection-specific state (gets reset).
+ *
+ * TODO(davidben): Avoid this. */
+ unsigned mtu = 0;
+ if (ssl->d1 != NULL) {
+ mtu = ssl->d1->mtu;
+ }
+
+ ssl->method->ssl_free(ssl);
+ if (!ssl->method->ssl_new(ssl)) {
+ SSL_SESSION_free(session);
+ return 0;
+ }
+
+ if (SSL_is_dtls(ssl) && (SSL_get_options(ssl) & SSL_OP_NO_QUERY_MTU)) {
+ ssl->d1->mtu = mtu;
+ }
+
+ if (session != NULL) {
+ SSL_set_session(ssl, session);
+ SSL_SESSION_free(session);
+ }
+
+ return 1;
+}
+
+void ssl_do_info_callback(const SSL *ssl, int type, int value) {
+ void (*cb)(const SSL *ssl, int type, int value) = NULL;
+ if (ssl->info_callback != NULL) {
+ cb = ssl->info_callback;
+ } else if (ssl->ctx->info_callback != NULL) {
+ cb = ssl->ctx->info_callback;
+ }
+
+ if (cb != NULL) {
+ cb(ssl, type, value);
+ }
+}
+
+void ssl_do_msg_callback(SSL *ssl, int is_write, int content_type,
+ const void *buf, size_t len) {
+ if (ssl->msg_callback == NULL) {
+ return;
+ }
+
+ /* |version| is zero when calling for |SSL3_RT_HEADER| and |SSL2_VERSION| for
+ * a V2ClientHello. */
+ int version;
+ switch (content_type) {
+ case 0:
+ /* V2ClientHello */
+ version = SSL2_VERSION;
+ break;
+ case SSL3_RT_HEADER:
+ version = 0;
+ break;
+ default:
+ version = SSL_version(ssl);
+ }
+
+ ssl->msg_callback(is_write, version, content_type, buf, len, ssl,
+ ssl->msg_callback_arg);
+}
+
+int SSL_CTX_sess_connect(const SSL_CTX *ctx) { return 0; }
+int SSL_CTX_sess_connect_good(const SSL_CTX *ctx) { return 0; }
+int SSL_CTX_sess_connect_renegotiate(const SSL_CTX *ctx) { return 0; }
+int SSL_CTX_sess_accept(const SSL_CTX *ctx) { return 0; }
+int SSL_CTX_sess_accept_renegotiate(const SSL_CTX *ctx) { return 0; }
+int SSL_CTX_sess_accept_good(const SSL_CTX *ctx) { return 0; }
+int SSL_CTX_sess_hits(const SSL_CTX *ctx) { return 0; }
+int SSL_CTX_sess_cb_hits(const SSL_CTX *ctx) { return 0; }
+int SSL_CTX_sess_misses(const SSL_CTX *ctx) { return 0; }
+int SSL_CTX_sess_timeouts(const SSL_CTX *ctx) { return 0; }
+int SSL_CTX_sess_cache_full(const SSL_CTX *ctx) { return 0; }
+
+int SSL_num_renegotiations(const SSL *ssl) {
+ return SSL_total_renegotiations(ssl);
+}
+
+int SSL_CTX_need_tmp_RSA(const SSL_CTX *ctx) { return 0; }
+int SSL_need_tmp_RSA(const SSL *ssl) { return 0; }
+int SSL_CTX_set_tmp_rsa(SSL_CTX *ctx, const RSA *rsa) { return 1; }
+int SSL_set_tmp_rsa(SSL *ssl, const RSA *rsa) { return 1; }
+void ERR_load_SSL_strings(void) {}
+void SSL_load_error_strings(void) {}
+int SSL_cache_hit(SSL *ssl) { return SSL_session_reused(ssl); }
+
+int SSL_CTX_set_tmp_ecdh(SSL_CTX *ctx, const EC_KEY *ec_key) {
+ if (ec_key == NULL || EC_KEY_get0_group(ec_key) == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
+ int nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key));
+ return SSL_CTX_set1_curves(ctx, &nid, 1);
+}
+
+int SSL_set_tmp_ecdh(SSL *ssl, const EC_KEY *ec_key) {
+ if (ec_key == NULL || EC_KEY_get0_group(ec_key) == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
+ int nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key));
+ return SSL_set1_curves(ssl, &nid, 1);
+}
+
+void ssl_get_current_time(const SSL *ssl, struct OPENSSL_timeval *out_clock) {
+ if (ssl->ctx->current_time_cb != NULL) {
+ /* TODO(davidben): Update current_time_cb to use OPENSSL_timeval. See
+ * https://crbug.com/boringssl/155. */
+ struct timeval clock;
+ ssl->ctx->current_time_cb(ssl, &clock);
+ if (clock.tv_sec < 0) {
+ assert(0);
+ out_clock->tv_sec = 0;
+ out_clock->tv_usec = 0;
+ } else {
+ out_clock->tv_sec = (uint64_t)clock.tv_sec;
+ out_clock->tv_usec = (uint32_t)clock.tv_usec;
+ }
+ return;
+ }
+
+#if defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE)
+ out_clock->tv_sec = 1234;
+ out_clock->tv_usec = 1234;
+#elif defined(OPENSSL_WINDOWS)
+ struct _timeb time;
+ _ftime(&time);
+ if (time.time < 0) {
+ assert(0);
+ out_clock->tv_sec = 0;
+ out_clock->tv_usec = 0;
+ } else {
+ out_clock->tv_sec = time.time;
+ out_clock->tv_usec = time.millitm * 1000;
+ }
+#else
+ struct timeval clock;
+ gettimeofday(&clock, NULL);
+ if (clock.tv_sec < 0) {
+ assert(0);
+ out_clock->tv_sec = 0;
+ out_clock->tv_usec = 0;
+ } else {
+ out_clock->tv_sec = (uint64_t)clock.tv_sec;
+ out_clock->tv_usec = (uint32_t)clock.tv_usec;
+ }
+#endif
+}
+
+int SSL_CTX_set_min_version(SSL_CTX *ctx, uint16_t version) {
+ return SSL_CTX_set_min_proto_version(ctx, version);
+}
+
+int SSL_CTX_set_max_version(SSL_CTX *ctx, uint16_t version) {
+ return SSL_CTX_set_max_proto_version(ctx, version);
+}
+
+int SSL_set_min_version(SSL *ssl, uint16_t version) {
+ return SSL_set_min_proto_version(ssl, version);
+}
+
+int SSL_set_max_version(SSL *ssl, uint16_t version) {
+ return SSL_set_max_proto_version(ssl, version);
+}
+
+void SSL_CTX_set_ticket_aead_method(SSL_CTX *ctx,
+ const SSL_TICKET_AEAD_METHOD *aead_method) {
+ ctx->ticket_aead_method = aead_method;
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_privkey.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_privkey.c
new file mode 100644
index 000000000..e988827f5
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_privkey.c
@@ -0,0 +1,678 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#include <openssl/ssl.h>
+
+#include <limits.h>
+
+#include <openssl/ec.h>
+#include <openssl/ec_key.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/mem.h>
+#include <openssl/type_check.h>
+
+#include "internal.h"
+
+
+int ssl_is_key_type_supported(int key_type) {
+ return key_type == EVP_PKEY_RSA || key_type == EVP_PKEY_EC;
+}
+
+static int ssl_set_pkey(CERT *cert, EVP_PKEY *pkey) {
+ if (!ssl_is_key_type_supported(pkey->type)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CERTIFICATE_TYPE);
+ return 0;
+ }
+
+ if (cert->chain != NULL &&
+ sk_CRYPTO_BUFFER_value(cert->chain, 0) != NULL &&
+ /* Sanity-check that the private key and the certificate match. */
+ !ssl_cert_check_private_key(cert, pkey)) {
+ return 0;
+ }
+
+ EVP_PKEY_free(cert->privatekey);
+ EVP_PKEY_up_ref(pkey);
+ cert->privatekey = pkey;
+
+ return 1;
+}
+
+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) {
+ 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;
+}
+
+int SSL_use_PrivateKey(SSL *ssl, EVP_PKEY *pkey) {
+ if (pkey == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
+
+ return ssl_set_pkey(ssl->cert, pkey);
+}
+
+int SSL_use_PrivateKey_ASN1(int type, SSL *ssl, const uint8_t *der,
+ size_t der_len) {
+ if (der_len > LONG_MAX) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
+ return 0;
+ }
+
+ const uint8_t *p = der;
+ EVP_PKEY *pkey = d2i_PrivateKey(type, NULL, &p, (long)der_len);
+ if (pkey == NULL || 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;
+}
+
+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) {
+ 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;
+}
+
+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) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_ASN1_LIB);
+ return 0;
+ }
+
+ int ret = SSL_CTX_use_RSAPrivateKey(ctx, rsa);
+ RSA_free(rsa);
+ return ret;
+}
+
+int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey) {
+ if (pkey == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
+
+ return ssl_set_pkey(ctx->cert, pkey);
+}
+
+int SSL_CTX_use_PrivateKey_ASN1(int type, SSL_CTX *ctx, const uint8_t *der,
+ size_t der_len) {
+ if (der_len > LONG_MAX) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
+ return 0;
+ }
+
+ const uint8_t *p = der;
+ EVP_PKEY *pkey = d2i_PrivateKey(type, NULL, &p, (long)der_len);
+ if (pkey == NULL || 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;
+}
+
+void SSL_set_private_key_method(SSL *ssl,
+ const SSL_PRIVATE_KEY_METHOD *key_method) {
+ ssl->cert->key_method = key_method;
+}
+
+void SSL_CTX_set_private_key_method(SSL_CTX *ctx,
+ const SSL_PRIVATE_KEY_METHOD *key_method) {
+ ctx->cert->key_method = key_method;
+}
+
+static int set_signing_algorithm_prefs(CERT *cert, const uint16_t *prefs,
+ size_t num_prefs) {
+ OPENSSL_free(cert->sigalgs);
+
+ cert->num_sigalgs = 0;
+ cert->sigalgs = BUF_memdup(prefs, num_prefs * sizeof(prefs[0]));
+ if (cert->sigalgs == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ cert->num_sigalgs = num_prefs;
+
+ return 1;
+}
+
+int SSL_CTX_set_signing_algorithm_prefs(SSL_CTX *ctx, const uint16_t *prefs,
+ size_t num_prefs) {
+ return set_signing_algorithm_prefs(ctx->cert, prefs, num_prefs);
+}
+
+
+int SSL_set_signing_algorithm_prefs(SSL *ssl, const uint16_t *prefs,
+ size_t num_prefs) {
+ return set_signing_algorithm_prefs(ssl->cert, prefs, num_prefs);
+}
+
+int SSL_set_private_key_digest_prefs(SSL *ssl, const int *digest_nids,
+ size_t num_digests) {
+ OPENSSL_free(ssl->cert->sigalgs);
+
+ OPENSSL_COMPILE_ASSERT(sizeof(int) >= 2 * sizeof(uint16_t),
+ digest_list_conversion_cannot_overflow);
+
+ ssl->cert->num_sigalgs = 0;
+ ssl->cert->sigalgs = OPENSSL_malloc(sizeof(uint16_t) * 2 * num_digests);
+ if (ssl->cert->sigalgs == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+
+ /* Convert the digest list to a signature algorithms list.
+ *
+ * TODO(davidben): Replace this API with one that can express RSA-PSS, etc. */
+ for (size_t i = 0; i < num_digests; i++) {
+ switch (digest_nids[i]) {
+ case NID_sha1:
+ ssl->cert->sigalgs[ssl->cert->num_sigalgs] = SSL_SIGN_RSA_PKCS1_SHA1;
+ ssl->cert->sigalgs[ssl->cert->num_sigalgs + 1] = SSL_SIGN_ECDSA_SHA1;
+ ssl->cert->num_sigalgs += 2;
+ break;
+ case NID_sha256:
+ ssl->cert->sigalgs[ssl->cert->num_sigalgs] = SSL_SIGN_RSA_PKCS1_SHA256;
+ ssl->cert->sigalgs[ssl->cert->num_sigalgs + 1] =
+ SSL_SIGN_ECDSA_SECP256R1_SHA256;
+ ssl->cert->num_sigalgs += 2;
+ break;
+ case NID_sha384:
+ ssl->cert->sigalgs[ssl->cert->num_sigalgs] = SSL_SIGN_RSA_PKCS1_SHA384;
+ ssl->cert->sigalgs[ssl->cert->num_sigalgs + 1] =
+ SSL_SIGN_ECDSA_SECP384R1_SHA384;
+ ssl->cert->num_sigalgs += 2;
+ break;
+ case NID_sha512:
+ ssl->cert->sigalgs[ssl->cert->num_sigalgs] = SSL_SIGN_RSA_PKCS1_SHA512;
+ ssl->cert->sigalgs[ssl->cert->num_sigalgs + 1] =
+ SSL_SIGN_ECDSA_SECP521R1_SHA512;
+ ssl->cert->num_sigalgs += 2;
+ break;
+ }
+ }
+
+ return 1;
+}
+
+int ssl_has_private_key(const SSL *ssl) {
+ return ssl->cert->privatekey != NULL || ssl->cert->key_method != NULL;
+}
+
+int ssl_is_ecdsa_key_type(int type) {
+ switch (type) {
+ case NID_secp224r1:
+ case NID_X9_62_prime256v1:
+ case NID_secp384r1:
+ case NID_secp521r1:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+int ssl_private_key_type(SSL *ssl) {
+ if (ssl->cert->key_method != NULL) {
+ return ssl->cert->key_method->type(ssl);
+ }
+ switch (EVP_PKEY_id(ssl->cert->privatekey)) {
+ case EVP_PKEY_RSA:
+ return NID_rsaEncryption;
+ case EVP_PKEY_EC:
+ return EC_GROUP_get_curve_name(
+ EC_KEY_get0_group(EVP_PKEY_get0_EC_KEY(ssl->cert->privatekey)));
+ default:
+ return NID_undef;
+ }
+}
+
+size_t ssl_private_key_max_signature_len(SSL *ssl) {
+ if (ssl->cert->key_method != NULL) {
+ return ssl->cert->key_method->max_signature_len(ssl);
+ }
+ return EVP_PKEY_size(ssl->cert->privatekey);
+}
+
+/* TODO(davidben): Forbid RSA-PKCS1 in TLS 1.3. For now we allow it because NSS
+ * has yet to start doing RSA-PSS, so enforcing it would complicate interop
+ * testing. */
+static int is_rsa_pkcs1(const EVP_MD **out_md, uint16_t sigalg) {
+ switch (sigalg) {
+ case SSL_SIGN_RSA_PKCS1_MD5_SHA1:
+ *out_md = EVP_md5_sha1();
+ return 1;
+ case SSL_SIGN_RSA_PKCS1_SHA1:
+ *out_md = EVP_sha1();
+ return 1;
+ case SSL_SIGN_RSA_PKCS1_SHA256:
+ *out_md = EVP_sha256();
+ return 1;
+ case SSL_SIGN_RSA_PKCS1_SHA384:
+ *out_md = EVP_sha384();
+ return 1;
+ case SSL_SIGN_RSA_PKCS1_SHA512:
+ *out_md = EVP_sha512();
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static int ssl_sign_rsa_pkcs1(SSL *ssl, uint8_t *out, size_t *out_len,
+ size_t max_out, const EVP_MD *md,
+ const uint8_t *in, size_t in_len) {
+ EVP_MD_CTX ctx;
+ EVP_MD_CTX_init(&ctx);
+ *out_len = max_out;
+ int ret = EVP_DigestSignInit(&ctx, NULL, md, NULL, ssl->cert->privatekey) &&
+ EVP_DigestSignUpdate(&ctx, in, in_len) &&
+ EVP_DigestSignFinal(&ctx, out, out_len);
+ EVP_MD_CTX_cleanup(&ctx);
+ return ret;
+}
+
+static int ssl_verify_rsa_pkcs1(SSL *ssl, const uint8_t *signature,
+ size_t signature_len, const EVP_MD *md,
+ EVP_PKEY *pkey, const uint8_t *in,
+ size_t in_len) {
+ if (pkey->type != EVP_PKEY_RSA) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SIGNATURE_TYPE);
+ return 0;
+ }
+
+ EVP_MD_CTX md_ctx;
+ EVP_MD_CTX_init(&md_ctx);
+ int ret = EVP_DigestVerifyInit(&md_ctx, NULL, md, NULL, pkey) &&
+ EVP_DigestVerifyUpdate(&md_ctx, in, in_len) &&
+ EVP_DigestVerifyFinal(&md_ctx, signature, signature_len);
+ EVP_MD_CTX_cleanup(&md_ctx);
+ return ret;
+}
+
+static int is_ecdsa(int *out_curve, const EVP_MD **out_md, uint16_t sigalg) {
+ switch (sigalg) {
+ case SSL_SIGN_ECDSA_SHA1:
+ *out_curve = NID_undef;
+ *out_md = EVP_sha1();
+ return 1;
+ case SSL_SIGN_ECDSA_SECP256R1_SHA256:
+ *out_curve = NID_X9_62_prime256v1;
+ *out_md = EVP_sha256();
+ return 1;
+ case SSL_SIGN_ECDSA_SECP384R1_SHA384:
+ *out_curve = NID_secp384r1;
+ *out_md = EVP_sha384();
+ return 1;
+ case SSL_SIGN_ECDSA_SECP521R1_SHA512:
+ *out_curve = NID_secp521r1;
+ *out_md = EVP_sha512();
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static int ssl_sign_ecdsa(SSL *ssl, uint8_t *out, size_t *out_len,
+ size_t max_out, int curve, const EVP_MD *md,
+ const uint8_t *in, size_t in_len) {
+ EC_KEY *ec_key = EVP_PKEY_get0_EC_KEY(ssl->cert->privatekey);
+ if (ec_key == NULL) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SIGNATURE_TYPE);
+ return 0;
+ }
+
+ /* In TLS 1.3, the curve is also specified by the signature algorithm. */
+ if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION &&
+ (curve == NID_undef ||
+ EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key)) != curve)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SIGNATURE_TYPE);
+ return 0;
+ }
+
+ EVP_MD_CTX ctx;
+ EVP_MD_CTX_init(&ctx);
+ *out_len = max_out;
+ int ret = EVP_DigestSignInit(&ctx, NULL, md, NULL, ssl->cert->privatekey) &&
+ EVP_DigestSignUpdate(&ctx, in, in_len) &&
+ EVP_DigestSignFinal(&ctx, out, out_len);
+ EVP_MD_CTX_cleanup(&ctx);
+ return ret;
+}
+
+static int ssl_verify_ecdsa(SSL *ssl, const uint8_t *signature,
+ size_t signature_len, int curve, const EVP_MD *md,
+ EVP_PKEY *pkey, const uint8_t *in, size_t in_len) {
+ EC_KEY *ec_key = EVP_PKEY_get0_EC_KEY(pkey);
+ if (ec_key == NULL) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SIGNATURE_TYPE);
+ return 0;
+ }
+
+ /* In TLS 1.3, the curve is also specified by the signature algorithm. */
+ if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION &&
+ (curve == NID_undef ||
+ EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key)) != curve)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SIGNATURE_TYPE);
+ return 0;
+ }
+
+ EVP_MD_CTX md_ctx;
+ EVP_MD_CTX_init(&md_ctx);
+ int ret = EVP_DigestVerifyInit(&md_ctx, NULL, md, NULL, pkey) &&
+ EVP_DigestVerifyUpdate(&md_ctx, in, in_len) &&
+ EVP_DigestVerifyFinal(&md_ctx, signature, signature_len);
+ EVP_MD_CTX_cleanup(&md_ctx);
+ return ret;
+}
+
+static int is_rsa_pss(const EVP_MD **out_md, uint16_t sigalg) {
+ switch (sigalg) {
+ case SSL_SIGN_RSA_PSS_SHA256:
+ *out_md = EVP_sha256();
+ return 1;
+ case SSL_SIGN_RSA_PSS_SHA384:
+ *out_md = EVP_sha384();
+ return 1;
+ case SSL_SIGN_RSA_PSS_SHA512:
+ *out_md = EVP_sha512();
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static int ssl_sign_rsa_pss(SSL *ssl, uint8_t *out, size_t *out_len,
+ size_t max_out, const EVP_MD *md,
+ const uint8_t *in, size_t in_len) {
+ EVP_MD_CTX ctx;
+ EVP_MD_CTX_init(&ctx);
+ *out_len = max_out;
+ EVP_PKEY_CTX *pctx;
+ int ret =
+ EVP_DigestSignInit(&ctx, &pctx, md, NULL, ssl->cert->privatekey) &&
+ EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) &&
+ EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, -1 /* salt len = hash len */) &&
+ EVP_DigestSignUpdate(&ctx, in, in_len) &&
+ EVP_DigestSignFinal(&ctx, out, out_len);
+ EVP_MD_CTX_cleanup(&ctx);
+ return ret;
+}
+
+static int ssl_verify_rsa_pss(SSL *ssl, const uint8_t *signature,
+ size_t signature_len, const EVP_MD *md,
+ EVP_PKEY *pkey, const uint8_t *in,
+ size_t in_len) {
+ if (pkey->type != EVP_PKEY_RSA) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SIGNATURE_TYPE);
+ return 0;
+ }
+
+ EVP_MD_CTX md_ctx;
+ EVP_MD_CTX_init(&md_ctx);
+ EVP_PKEY_CTX *pctx;
+ int ret =
+ EVP_DigestVerifyInit(&md_ctx, &pctx, md, NULL, pkey) &&
+ EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) &&
+ EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, -1 /* salt len = hash len */) &&
+ EVP_DigestVerifyUpdate(&md_ctx, in, in_len) &&
+ EVP_DigestVerifyFinal(&md_ctx, signature, signature_len);
+ EVP_MD_CTX_cleanup(&md_ctx);
+ return ret;
+}
+
+enum ssl_private_key_result_t ssl_private_key_sign(
+ SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out,
+ uint16_t signature_algorithm, const uint8_t *in, size_t in_len) {
+ if (ssl->cert->key_method != NULL) {
+ if (ssl->cert->key_method->sign != NULL) {
+ return ssl->cert->key_method->sign(ssl, out, out_len, max_out,
+ signature_algorithm, in, in_len);
+ }
+
+ /* TODO(davidben): Remove support for |sign_digest|-only
+ * |SSL_PRIVATE_KEY_METHOD|s. */
+ const EVP_MD *md;
+ int curve;
+ if (!is_rsa_pkcs1(&md, signature_algorithm) &&
+ !is_ecdsa(&curve, &md, signature_algorithm)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_PROTOCOL_FOR_CUSTOM_KEY);
+ return ssl_private_key_failure;
+ }
+
+ uint8_t hash[EVP_MAX_MD_SIZE];
+ unsigned hash_len;
+ if (!EVP_Digest(in, in_len, hash, &hash_len, md, NULL)) {
+ return ssl_private_key_failure;
+ }
+
+ return ssl->cert->key_method->sign_digest(ssl, out, out_len, max_out, md,
+ hash, hash_len);
+ }
+
+ const EVP_MD *md;
+ if (is_rsa_pkcs1(&md, signature_algorithm) &&
+ ssl3_protocol_version(ssl) < TLS1_3_VERSION) {
+ return ssl_sign_rsa_pkcs1(ssl, out, out_len, max_out, md, in, in_len)
+ ? ssl_private_key_success
+ : ssl_private_key_failure;
+ }
+
+ int curve;
+ if (is_ecdsa(&curve, &md, signature_algorithm)) {
+ return ssl_sign_ecdsa(ssl, out, out_len, max_out, curve, md, in, in_len)
+ ? ssl_private_key_success
+ : ssl_private_key_failure;
+ }
+
+ if (is_rsa_pss(&md, signature_algorithm)) {
+ return ssl_sign_rsa_pss(ssl, out, out_len, max_out, md, in, in_len)
+ ? ssl_private_key_success
+ : ssl_private_key_failure;
+ }
+
+ OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SIGNATURE_TYPE);
+ return ssl_private_key_failure;
+}
+
+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) {
+ const EVP_MD *md;
+ if (is_rsa_pkcs1(&md, signature_algorithm) &&
+ ssl3_protocol_version(ssl) < TLS1_3_VERSION) {
+ return ssl_verify_rsa_pkcs1(ssl, signature, signature_len, md, pkey, in,
+ in_len);
+ }
+
+ int curve;
+ if (is_ecdsa(&curve, &md, signature_algorithm)) {
+ return ssl_verify_ecdsa(ssl, signature, signature_len, curve, md, pkey, in,
+ in_len);
+ }
+
+ if (is_rsa_pss(&md, signature_algorithm)) {
+ return ssl_verify_rsa_pss(ssl, signature, signature_len, md, pkey, in,
+ in_len);
+ }
+
+ OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SIGNATURE_TYPE);
+ return 0;
+}
+
+enum ssl_private_key_result_t ssl_private_key_decrypt(
+ SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out,
+ const uint8_t *in, size_t in_len) {
+ if (ssl->cert->key_method != NULL) {
+ return ssl->cert->key_method->decrypt(ssl, out, out_len, max_out, in,
+ in_len);
+ }
+
+ RSA *rsa = EVP_PKEY_get0_RSA(ssl->cert->privatekey);
+ if (rsa == NULL) {
+ /* Decrypt operations are only supported for RSA keys. */
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return ssl_private_key_failure;
+ }
+
+ /* Decrypt with no padding. PKCS#1 padding will be removed as part
+ * of the timing-sensitive code by the caller. */
+ if (!RSA_decrypt(rsa, out_len, out, max_out, in, in_len, RSA_NO_PADDING)) {
+ return ssl_private_key_failure;
+ }
+ return ssl_private_key_success;
+}
+
+enum ssl_private_key_result_t ssl_private_key_complete(SSL *ssl, uint8_t *out,
+ size_t *out_len,
+ size_t max_out) {
+ /* Only custom keys may be asynchronous. */
+ return ssl->cert->key_method->complete(ssl, out, out_len, max_out);
+}
+
+int ssl_private_key_supports_signature_algorithm(SSL *ssl,
+ uint16_t signature_algorithm) {
+ const EVP_MD *md;
+ if (is_rsa_pkcs1(&md, signature_algorithm) &&
+ ssl3_protocol_version(ssl) < TLS1_3_VERSION) {
+ return ssl_private_key_type(ssl) == NID_rsaEncryption;
+ }
+
+ int curve;
+ if (is_ecdsa(&curve, &md, signature_algorithm)) {
+ int type = ssl_private_key_type(ssl);
+ if (!ssl_is_ecdsa_key_type(type)) {
+ return 0;
+ }
+
+ /* Prior to TLS 1.3, ECDSA curves did not match the signature algorithm. */
+ if (ssl3_protocol_version(ssl) < TLS1_3_VERSION) {
+ return 1;
+ }
+
+ return curve != NID_undef && type == curve;
+ }
+
+ if (is_rsa_pss(&md, signature_algorithm)) {
+ if (ssl_private_key_type(ssl) != NID_rsaEncryption) {
+ return 0;
+ }
+
+ /* Ensure the RSA key is large enough for the hash. RSASSA-PSS requires that
+ * emLen be at least hLen + sLen + 2. Both hLen and sLen are the size of the
+ * hash in TLS. Reasonable RSA key sizes are large enough for the largest
+ * defined RSASSA-PSS algorithm, but 1024-bit RSA is slightly too large for
+ * SHA-512. 1024-bit RSA is sometimes used for test credentials, so check
+ * the size to fall back to another algorithm. */
+ if (ssl_private_key_max_signature_len(ssl) < 2 * EVP_MD_size(md) + 2) {
+ return 0;
+ }
+
+ /* RSA-PSS is only supported by message-based private keys. */
+ if (ssl->cert->key_method != NULL && ssl->cert->key_method->sign == NULL) {
+ return 0;
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_privkey_cc.cc b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_privkey_cc.cc
new file mode 100644
index 000000000..653308c12
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_privkey_cc.cc
@@ -0,0 +1,76 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#include <openssl/ssl.h>
+
+#include <openssl/err.h>
+#include <openssl/rsa.h>
+
+
+/* This function has been converted to C++ to check if all of libssl's
+ * consumers' toolchains are capable of handling C++11. Once all problems in
+ * consumer toolchains are found and fixed, we will convert the rest of
+ * libssl. */
+
+int SSL_use_RSAPrivateKey_ASN1(SSL *ssl, const uint8_t *der, size_t der_len) {
+ bssl::UniquePtr<RSA> rsa(RSA_private_key_from_bytes(der, der_len));
+ if (!rsa) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_ASN1_LIB);
+ return 0;
+ }
+
+ return SSL_use_RSAPrivateKey(ssl, rsa.get());
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_session.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_session.c
new file mode 100644
index 000000000..05ae05973
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_session.c
@@ -0,0 +1,1147 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2006 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* ====================================================================
+ * Copyright 2005 Nokia. All rights reserved.
+ *
+ * The portions of the attached software ("Contribution") is developed by
+ * Nokia Corporation and is licensed pursuant to the OpenSSL open source
+ * license.
+ *
+ * The Contribution, originally written by Mika Kousa and Pasi Eronen of
+ * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites
+ * support (see RFC 4279) to OpenSSL.
+ *
+ * No patent licenses or other rights except those expressly stated in
+ * the OpenSSL open source license shall be deemed granted or received
+ * expressly, by implication, estoppel, or otherwise.
+ *
+ * No assurances are provided by Nokia that the Contribution does not
+ * infringe the patent or other intellectual property rights of any third
+ * party or that the license provides you with all the necessary rights
+ * to make use of the Contribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN
+ * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA
+ * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY
+ * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
+ * OTHERWISE. */
+
+#include <openssl/ssl.h>
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <openssl/err.h>
+#include <openssl/lhash.h>
+#include <openssl/mem.h>
+#include <openssl/rand.h>
+
+#include "internal.h"
+#include "../crypto/internal.h"
+
+
+/* The address of this is a magic value, a pointer to which is returned by
+ * SSL_magic_pending_session_ptr(). It allows a session callback to indicate
+ * that it needs to asynchronously fetch session information. */
+static const char g_pending_session_magic = 0;
+
+static CRYPTO_EX_DATA_CLASS g_ex_data_class =
+ CRYPTO_EX_DATA_CLASS_INIT_WITH_APP_DATA;
+
+static void SSL_SESSION_list_remove(SSL_CTX *ctx, SSL_SESSION *session);
+static void SSL_SESSION_list_add(SSL_CTX *ctx, SSL_SESSION *session);
+static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *session, int lock);
+
+SSL_SESSION *ssl_session_new(const SSL_X509_METHOD *x509_method) {
+ SSL_SESSION *session = OPENSSL_malloc(sizeof(SSL_SESSION));
+ if (session == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ OPENSSL_memset(session, 0, sizeof(SSL_SESSION));
+
+ session->x509_method = x509_method;
+ session->verify_result = X509_V_ERR_INVALID_CALL;
+ session->references = 1;
+ session->timeout = SSL_DEFAULT_SESSION_TIMEOUT;
+ session->auth_timeout = SSL_DEFAULT_SESSION_TIMEOUT;
+ session->time = time(NULL);
+ CRYPTO_new_ex_data(&session->ex_data);
+ return session;
+}
+
+SSL_SESSION *SSL_SESSION_new(const SSL_CTX *ctx) {
+ return ssl_session_new(ctx->x509_method);
+}
+
+SSL_SESSION *SSL_SESSION_dup(SSL_SESSION *session, int dup_flags) {
+ SSL_SESSION *new_session = ssl_session_new(session->x509_method);
+ if (new_session == NULL) {
+ goto err;
+ }
+
+ new_session->is_server = session->is_server;
+ new_session->ssl_version = session->ssl_version;
+ new_session->sid_ctx_length = session->sid_ctx_length;
+ OPENSSL_memcpy(new_session->sid_ctx, session->sid_ctx, session->sid_ctx_length);
+
+ /* Copy the key material. */
+ new_session->master_key_length = session->master_key_length;
+ OPENSSL_memcpy(new_session->master_key, session->master_key,
+ session->master_key_length);
+ new_session->cipher = session->cipher;
+
+ /* Copy authentication state. */
+ if (session->psk_identity != NULL) {
+ new_session->psk_identity = BUF_strdup(session->psk_identity);
+ if (new_session->psk_identity == NULL) {
+ goto err;
+ }
+ }
+ if (session->certs != NULL) {
+ new_session->certs = sk_CRYPTO_BUFFER_new_null();
+ if (new_session->certs == NULL) {
+ goto err;
+ }
+ for (size_t i = 0; i < sk_CRYPTO_BUFFER_num(session->certs); i++) {
+ CRYPTO_BUFFER *buffer = sk_CRYPTO_BUFFER_value(session->certs, i);
+ if (!sk_CRYPTO_BUFFER_push(new_session->certs, buffer)) {
+ goto err;
+ }
+ CRYPTO_BUFFER_up_ref(buffer);
+ }
+ }
+
+ if (!session->x509_method->session_dup(new_session, session)) {
+ goto err;
+ }
+
+ new_session->verify_result = session->verify_result;
+
+ new_session->ocsp_response_length = session->ocsp_response_length;
+ if (session->ocsp_response != NULL) {
+ new_session->ocsp_response = BUF_memdup(session->ocsp_response,
+ session->ocsp_response_length);
+ if (new_session->ocsp_response == NULL) {
+ goto err;
+ }
+ }
+
+ new_session->tlsext_signed_cert_timestamp_list_length =
+ session->tlsext_signed_cert_timestamp_list_length;
+ if (session->tlsext_signed_cert_timestamp_list != NULL) {
+ new_session->tlsext_signed_cert_timestamp_list =
+ BUF_memdup(session->tlsext_signed_cert_timestamp_list,
+ session->tlsext_signed_cert_timestamp_list_length);
+ if (new_session->tlsext_signed_cert_timestamp_list == NULL) {
+ goto err;
+ }
+ }
+
+ OPENSSL_memcpy(new_session->peer_sha256, session->peer_sha256,
+ SHA256_DIGEST_LENGTH);
+ new_session->peer_sha256_valid = session->peer_sha256_valid;
+
+ if (session->tlsext_hostname != NULL) {
+ new_session->tlsext_hostname = BUF_strdup(session->tlsext_hostname);
+ if (new_session->tlsext_hostname == NULL) {
+ goto err;
+ }
+ }
+
+ new_session->peer_signature_algorithm = session->peer_signature_algorithm;
+
+ new_session->timeout = session->timeout;
+ new_session->auth_timeout = session->auth_timeout;
+ new_session->time = session->time;
+
+ /* Copy non-authentication connection properties. */
+ if (dup_flags & SSL_SESSION_INCLUDE_NONAUTH) {
+ new_session->session_id_length = session->session_id_length;
+ OPENSSL_memcpy(new_session->session_id, session->session_id,
+ session->session_id_length);
+
+ new_session->group_id = session->group_id;
+
+ OPENSSL_memcpy(new_session->original_handshake_hash,
+ session->original_handshake_hash,
+ session->original_handshake_hash_len);
+ new_session->original_handshake_hash_len =
+ session->original_handshake_hash_len;
+ new_session->tlsext_tick_lifetime_hint = session->tlsext_tick_lifetime_hint;
+ new_session->ticket_age_add = session->ticket_age_add;
+ new_session->ticket_max_early_data = session->ticket_max_early_data;
+ new_session->extended_master_secret = session->extended_master_secret;
+
+ if (session->early_alpn != NULL) {
+ new_session->early_alpn =
+ BUF_memdup(session->early_alpn, session->early_alpn_len);
+ if (new_session->early_alpn == NULL) {
+ goto err;
+ }
+ }
+ new_session->early_alpn_len = session->early_alpn_len;
+ }
+
+ /* Copy the ticket. */
+ if (dup_flags & SSL_SESSION_INCLUDE_TICKET) {
+ if (session->tlsext_tick != NULL) {
+ new_session->tlsext_tick =
+ BUF_memdup(session->tlsext_tick, session->tlsext_ticklen);
+ if (new_session->tlsext_tick == NULL) {
+ goto err;
+ }
+ }
+ new_session->tlsext_ticklen = session->tlsext_ticklen;
+ }
+
+ /* The new_session does not get a copy of the ex_data. */
+
+ new_session->not_resumable = 1;
+ return new_session;
+
+err:
+ SSL_SESSION_free(new_session);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ return 0;
+}
+
+void ssl_session_rebase_time(SSL *ssl, SSL_SESSION *session) {
+ struct OPENSSL_timeval now;
+ ssl_get_current_time(ssl, &now);
+
+ /* To avoid overflows and underflows, if we've gone back in time, update the
+ * time, but mark the session expired. */
+ if (session->time > now.tv_sec) {
+ session->time = now.tv_sec;
+ session->timeout = 0;
+ session->auth_timeout = 0;
+ return;
+ }
+
+ /* Adjust the session time and timeouts. If the session has already expired,
+ * clamp the timeouts at zero. */
+ uint64_t delta = now.tv_sec - session->time;
+ session->time = now.tv_sec;
+ if (session->timeout < delta) {
+ session->timeout = 0;
+ } else {
+ session->timeout -= delta;
+ }
+ if (session->auth_timeout < delta) {
+ session->auth_timeout = 0;
+ } else {
+ session->auth_timeout -= delta;
+ }
+}
+
+void ssl_session_renew_timeout(SSL *ssl, SSL_SESSION *session,
+ uint32_t timeout) {
+ /* Rebase the timestamp relative to the current time so |timeout| is measured
+ * correctly. */
+ ssl_session_rebase_time(ssl, session);
+
+ if (session->timeout > timeout) {
+ return;
+ }
+
+ session->timeout = timeout;
+ if (session->timeout > session->auth_timeout) {
+ session->timeout = session->auth_timeout;
+ }
+}
+
+int SSL_SESSION_up_ref(SSL_SESSION *session) {
+ CRYPTO_refcount_inc(&session->references);
+ return 1;
+}
+
+void SSL_SESSION_free(SSL_SESSION *session) {
+ if (session == NULL ||
+ !CRYPTO_refcount_dec_and_test_zero(&session->references)) {
+ return;
+ }
+
+ CRYPTO_free_ex_data(&g_ex_data_class, session, &session->ex_data);
+
+ OPENSSL_cleanse(session->master_key, sizeof(session->master_key));
+ OPENSSL_cleanse(session->session_id, sizeof(session->session_id));
+ sk_CRYPTO_BUFFER_pop_free(session->certs, CRYPTO_BUFFER_free);
+ session->x509_method->session_clear(session);
+ OPENSSL_free(session->tlsext_hostname);
+ OPENSSL_free(session->tlsext_tick);
+ OPENSSL_free(session->tlsext_signed_cert_timestamp_list);
+ OPENSSL_free(session->ocsp_response);
+ OPENSSL_free(session->psk_identity);
+ OPENSSL_free(session->early_alpn);
+ OPENSSL_cleanse(session, sizeof(*session));
+ OPENSSL_free(session);
+}
+
+const uint8_t *SSL_SESSION_get_id(const SSL_SESSION *session,
+ unsigned *out_len) {
+ if (out_len != NULL) {
+ *out_len = session->session_id_length;
+ }
+ return session->session_id;
+}
+
+uint32_t SSL_SESSION_get_timeout(const SSL_SESSION *session) {
+ return session->timeout;
+}
+
+uint64_t SSL_SESSION_get_time(const SSL_SESSION *session) {
+ if (session == NULL) {
+ /* NULL should crash, but silently accept it here for compatibility. */
+ return 0;
+ }
+ return session->time;
+}
+
+X509 *SSL_SESSION_get0_peer(const SSL_SESSION *session) {
+ return session->x509_peer;
+}
+
+size_t SSL_SESSION_get_master_key(const SSL_SESSION *session, uint8_t *out,
+ size_t max_out) {
+ /* TODO(davidben): Fix master_key_length's type and remove these casts. */
+ if (max_out == 0) {
+ return (size_t)session->master_key_length;
+ }
+ if (max_out > (size_t)session->master_key_length) {
+ max_out = (size_t)session->master_key_length;
+ }
+ OPENSSL_memcpy(out, session->master_key, max_out);
+ return max_out;
+}
+
+uint64_t SSL_SESSION_set_time(SSL_SESSION *session, uint64_t time) {
+ if (session == NULL) {
+ return 0;
+ }
+
+ session->time = time;
+ return time;
+}
+
+uint32_t SSL_SESSION_set_timeout(SSL_SESSION *session, uint32_t timeout) {
+ if (session == NULL) {
+ return 0;
+ }
+
+ session->timeout = timeout;
+ session->auth_timeout = timeout;
+ return 1;
+}
+
+int SSL_SESSION_set1_id_context(SSL_SESSION *session, const uint8_t *sid_ctx,
+ size_t sid_ctx_len) {
+ if (sid_ctx_len > sizeof(session->sid_ctx)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG);
+ return 0;
+ }
+
+ assert(sizeof(session->sid_ctx) < 256);
+ session->sid_ctx_length = (uint8_t)sid_ctx_len;
+ OPENSSL_memcpy(session->sid_ctx, sid_ctx, sid_ctx_len);
+
+ return 1;
+}
+
+SSL_SESSION *SSL_magic_pending_session_ptr(void) {
+ return (SSL_SESSION *)&g_pending_session_magic;
+}
+
+SSL_SESSION *SSL_get_session(const SSL *ssl) {
+ /* Once the handshake completes we return the established session. Otherwise
+ * we return the intermediate session, either |session| (for resumption) or
+ * |new_session| if doing a full handshake. */
+ if (!SSL_in_init(ssl)) {
+ return ssl->s3->established_session;
+ }
+ if (ssl->s3->hs->new_session != NULL) {
+ return ssl->s3->hs->new_session;
+ }
+ return ssl->session;
+}
+
+SSL_SESSION *SSL_get1_session(SSL *ssl) {
+ SSL_SESSION *ret = SSL_get_session(ssl);
+ if (ret != NULL) {
+ SSL_SESSION_up_ref(ret);
+ }
+ return ret;
+}
+
+int SSL_SESSION_get_ex_new_index(long argl, void *argp,
+ CRYPTO_EX_unused *unused,
+ CRYPTO_EX_dup *dup_func,
+ CRYPTO_EX_free *free_func) {
+ int index;
+ if (!CRYPTO_get_ex_new_index(&g_ex_data_class, &index, argl, argp, dup_func,
+ free_func)) {
+ return -1;
+ }
+ return index;
+}
+
+int SSL_SESSION_set_ex_data(SSL_SESSION *session, int idx, void *arg) {
+ return CRYPTO_set_ex_data(&session->ex_data, idx, arg);
+}
+
+void *SSL_SESSION_get_ex_data(const SSL_SESSION *session, int idx) {
+ return CRYPTO_get_ex_data(&session->ex_data, idx);
+}
+
+const EVP_MD *SSL_SESSION_get_digest(const SSL_SESSION *session,
+ const SSL *ssl) {
+ uint16_t version;
+ if (!ssl->method->version_from_wire(&version, session->ssl_version)) {
+ return NULL;
+ }
+
+ return ssl_get_handshake_digest(session->cipher->algorithm_prf, version);
+}
+
+int ssl_get_new_session(SSL_HANDSHAKE *hs, int is_server) {
+ SSL *const ssl = hs->ssl;
+ if (ssl->mode & SSL_MODE_NO_SESSION_CREATION) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_SESSION_MAY_NOT_BE_CREATED);
+ return 0;
+ }
+
+ SSL_SESSION *session = ssl_session_new(ssl->ctx->x509_method);
+ if (session == NULL) {
+ return 0;
+ }
+
+ session->is_server = is_server;
+ session->ssl_version = ssl->version;
+
+ /* Fill in the time from the |SSL_CTX|'s clock. */
+ struct OPENSSL_timeval now;
+ ssl_get_current_time(ssl, &now);
+ session->time = now.tv_sec;
+
+ uint16_t version = ssl3_protocol_version(ssl);
+ if (version >= TLS1_3_VERSION) {
+ /* TLS 1.3 uses tickets as authenticators, so we are willing to use them for
+ * longer. */
+ session->timeout = ssl->session_ctx->session_psk_dhe_timeout;
+ session->auth_timeout = SSL_DEFAULT_SESSION_AUTH_TIMEOUT;
+ } else {
+ /* TLS 1.2 resumption does not incorporate new key material, so we use a
+ * much shorter timeout. */
+ session->timeout = ssl->session_ctx->session_timeout;
+ session->auth_timeout = ssl->session_ctx->session_timeout;
+ }
+
+ if (is_server) {
+ if (hs->ticket_expected || version >= TLS1_3_VERSION) {
+ /* Don't set session IDs for sessions resumed with tickets. This will keep
+ * them out of the session cache. */
+ session->session_id_length = 0;
+ } else {
+ session->session_id_length = SSL3_SSL_SESSION_ID_LENGTH;
+ if (!RAND_bytes(session->session_id, session->session_id_length)) {
+ goto err;
+ }
+ }
+ } else {
+ session->session_id_length = 0;
+ }
+
+ if (ssl->cert->sid_ctx_length > sizeof(session->sid_ctx)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ OPENSSL_memcpy(session->sid_ctx, ssl->cert->sid_ctx,
+ ssl->cert->sid_ctx_length);
+ session->sid_ctx_length = ssl->cert->sid_ctx_length;
+
+ /* The session is marked not resumable until it is completely filled in. */
+ session->not_resumable = 1;
+ session->verify_result = X509_V_ERR_INVALID_CALL;
+
+ SSL_SESSION_free(hs->new_session);
+ hs->new_session = session;
+ ssl_set_session(ssl, NULL);
+ return 1;
+
+err:
+ SSL_SESSION_free(session);
+ return 0;
+}
+
+static int ssl_encrypt_ticket_with_cipher_ctx(SSL *ssl, CBB *out,
+ const uint8_t *session_buf,
+ size_t session_len) {
+ int ret = 0;
+
+ EVP_CIPHER_CTX ctx;
+ EVP_CIPHER_CTX_init(&ctx);
+ HMAC_CTX hctx;
+ HMAC_CTX_init(&hctx);
+
+ /* If the session is too long, emit a dummy value rather than abort the
+ * connection. */
+ static const size_t kMaxTicketOverhead =
+ 16 + EVP_MAX_IV_LENGTH + EVP_MAX_BLOCK_LENGTH + EVP_MAX_MD_SIZE;
+ if (session_len > 0xffff - kMaxTicketOverhead) {
+ static const char kTicketPlaceholder[] = "TICKET TOO LARGE";
+ if (CBB_add_bytes(out, (const uint8_t *)kTicketPlaceholder,
+ strlen(kTicketPlaceholder))) {
+ ret = 1;
+ }
+ goto err;
+ }
+
+ /* Initialize HMAC and cipher contexts. If callback present it does all the
+ * work otherwise use generated values from parent ctx. */
+ SSL_CTX *tctx = ssl->session_ctx;
+ uint8_t iv[EVP_MAX_IV_LENGTH];
+ uint8_t key_name[16];
+ if (tctx->tlsext_ticket_key_cb != NULL) {
+ if (tctx->tlsext_ticket_key_cb(ssl, key_name, iv, &ctx, &hctx,
+ 1 /* encrypt */) < 0) {
+ goto err;
+ }
+ } else {
+ if (!RAND_bytes(iv, 16) ||
+ !EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL,
+ tctx->tlsext_tick_aes_key, iv) ||
+ !HMAC_Init_ex(&hctx, tctx->tlsext_tick_hmac_key, 16, tlsext_tick_md(),
+ NULL)) {
+ goto err;
+ }
+ OPENSSL_memcpy(key_name, tctx->tlsext_tick_key_name, 16);
+ }
+
+ uint8_t *ptr;
+ if (!CBB_add_bytes(out, key_name, 16) ||
+ !CBB_add_bytes(out, iv, EVP_CIPHER_CTX_iv_length(&ctx)) ||
+ !CBB_reserve(out, &ptr, session_len + EVP_MAX_BLOCK_LENGTH)) {
+ goto err;
+ }
+
+ size_t total = 0;
+#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+ OPENSSL_memcpy(ptr, session_buf, session_len);
+ total = session_len;
+#else
+ int len;
+ if (!EVP_EncryptUpdate(&ctx, ptr + total, &len, session_buf, session_len)) {
+ goto err;
+ }
+ total += len;
+ if (!EVP_EncryptFinal_ex(&ctx, ptr + total, &len)) {
+ goto err;
+ }
+ total += len;
+#endif
+ if (!CBB_did_write(out, total)) {
+ goto err;
+ }
+
+ unsigned hlen;
+ if (!HMAC_Update(&hctx, CBB_data(out), CBB_len(out)) ||
+ !CBB_reserve(out, &ptr, EVP_MAX_MD_SIZE) ||
+ !HMAC_Final(&hctx, ptr, &hlen) ||
+ !CBB_did_write(out, hlen)) {
+ goto err;
+ }
+
+ ret = 1;
+
+err:
+ EVP_CIPHER_CTX_cleanup(&ctx);
+ HMAC_CTX_cleanup(&hctx);
+ return ret;
+}
+
+static int ssl_encrypt_ticket_with_method(SSL *ssl, CBB *out,
+ const uint8_t *session_buf,
+ size_t session_len) {
+ const SSL_TICKET_AEAD_METHOD *method = ssl->session_ctx->ticket_aead_method;
+ const size_t max_overhead = method->max_overhead(ssl);
+ const size_t max_out = session_len + max_overhead;
+ if (max_out < max_overhead) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
+ return 0;
+ }
+
+ uint8_t *ptr;
+ if (!CBB_reserve(out, &ptr, max_out)) {
+ return 0;
+ }
+
+ size_t out_len;
+ if (!method->seal(ssl, ptr, &out_len, max_out, session_buf, session_len)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_TICKET_ENCRYPTION_FAILED);
+ return 0;
+ }
+
+ if (!CBB_did_write(out, out_len)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+int ssl_encrypt_ticket(SSL *ssl, CBB *out, const SSL_SESSION *session) {
+ /* Serialize the SSL_SESSION to be encoded into the ticket. */
+ uint8_t *session_buf = NULL;
+ size_t session_len;
+ if (!SSL_SESSION_to_bytes_for_ticket(session, &session_buf, &session_len)) {
+ return -1;
+ }
+
+ int ret = 0;
+ if (ssl->session_ctx->ticket_aead_method) {
+ ret = ssl_encrypt_ticket_with_method(ssl, out, session_buf, session_len);
+ } else {
+ ret =
+ ssl_encrypt_ticket_with_cipher_ctx(ssl, out, session_buf, session_len);
+ }
+
+ OPENSSL_free(session_buf);
+ return ret;
+}
+
+int ssl_session_is_context_valid(const SSL *ssl, const SSL_SESSION *session) {
+ if (session == NULL) {
+ return 0;
+ }
+
+ return session->sid_ctx_length == ssl->cert->sid_ctx_length &&
+ OPENSSL_memcmp(session->sid_ctx, ssl->cert->sid_ctx,
+ ssl->cert->sid_ctx_length) == 0;
+}
+
+int ssl_session_is_time_valid(const SSL *ssl, const SSL_SESSION *session) {
+ if (session == NULL) {
+ return 0;
+ }
+
+ struct OPENSSL_timeval now;
+ ssl_get_current_time(ssl, &now);
+
+ /* Reject tickets from the future to avoid underflow. */
+ if (now.tv_sec < session->time) {
+ return 0;
+ }
+
+ return session->timeout > now.tv_sec - session->time;
+}
+
+int ssl_session_is_resumable(const SSL_HANDSHAKE *hs,
+ const SSL_SESSION *session) {
+ const SSL *const ssl = hs->ssl;
+ return ssl_session_is_context_valid(ssl, session) &&
+ /* The session must have been created by the same type of end point as
+ * we're now using it with. */
+ ssl->server == session->is_server &&
+ /* The session must not be expired. */
+ ssl_session_is_time_valid(ssl, session) &&
+ /* Only resume if the session's version matches the negotiated
+ * version. */
+ ssl->version == session->ssl_version &&
+ /* Only resume if the session's cipher matches the negotiated one. */
+ hs->new_cipher == session->cipher &&
+ /* If the session contains a client certificate (either the full
+ * certificate or just the hash) then require that the form of the
+ * certificate matches the current configuration. */
+ ((sk_CRYPTO_BUFFER_num(session->certs) == 0 &&
+ !session->peer_sha256_valid) ||
+ session->peer_sha256_valid ==
+ ssl->retain_only_sha256_of_client_certs);
+}
+
+/* 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. */
+static enum ssl_session_result_t ssl_lookup_session(
+ SSL *ssl, SSL_SESSION **out_session, const uint8_t *session_id,
+ size_t session_id_len) {
+ *out_session = NULL;
+
+ if (session_id_len == 0 || session_id_len > SSL_MAX_SSL_SESSION_ID_LENGTH) {
+ return ssl_session_success;
+ }
+
+ SSL_SESSION *session = NULL;
+ /* Try the internal cache, if it exists. */
+ if (!(ssl->session_ctx->session_cache_mode &
+ SSL_SESS_CACHE_NO_INTERNAL_LOOKUP)) {
+ SSL_SESSION data;
+ data.ssl_version = ssl->version;
+ data.session_id_length = session_id_len;
+ 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);
+ }
+ /* 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) {
+ int copy = 1;
+ session = ssl->session_ctx->get_session_cb(ssl, (uint8_t *)session_id,
+ session_id_len, &copy);
+
+ if (session == NULL) {
+ return ssl_session_success;
+ }
+
+ if (session == SSL_magic_pending_session_ptr()) {
+ return ssl_session_retry;
+ }
+
+ /* Increment reference count now if the session callback asks us to do so
+ * (note that if the session structures returned by the callback are shared
+ * 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);
+ }
+
+ /* 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);
+ }
+ }
+
+ if (session != NULL &&
+ !ssl_session_is_time_valid(ssl, session)) {
+ /* The session was from the cache, so remove it. */
+ SSL_CTX_remove_session(ssl->session_ctx, session);
+ SSL_SESSION_free(session);
+ session = NULL;
+ }
+
+ *out_session = session;
+ return ssl_session_success;
+}
+
+enum ssl_session_result_t ssl_get_prev_session(
+ SSL *ssl, 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;
+ int renew_ticket = 0;
+
+ /* If tickets are disabled, always behave as if no tickets are present. */
+ const uint8_t *ticket = NULL;
+ size_t ticket_len = 0;
+ const int tickets_supported =
+ !(SSL_get_options(ssl) & SSL_OP_NO_TICKET) &&
+ ssl->version > SSL3_VERSION &&
+ SSL_early_callback_ctx_extension_get(
+ client_hello, TLSEXT_TYPE_session_ticket, &ticket, &ticket_len);
+ if (tickets_supported && ticket_len > 0) {
+ switch (ssl_process_ticket(ssl, &session, &renew_ticket, ticket, ticket_len,
+ client_hello->session_id,
+ client_hello->session_id_len)) {
+ case ssl_ticket_aead_success:
+ break;
+ case ssl_ticket_aead_ignore_ticket:
+ assert(session == NULL);
+ break;
+ case ssl_ticket_aead_error:
+ return ssl_session_error;
+ case ssl_ticket_aead_retry:
+ return ssl_session_ticket_retry;
+ }
+ } else {
+ /* The client didn't send a ticket, so the session ID is a real ID. */
+ enum ssl_session_result_t lookup_ret = ssl_lookup_session(
+ ssl, &session, client_hello->session_id, client_hello->session_id_len);
+ if (lookup_ret != ssl_session_success) {
+ return lookup_ret;
+ }
+ }
+
+ *out_session = session;
+ *out_tickets_supported = tickets_supported;
+ *out_renew_ticket = renew_ticket;
+ return ssl_session_success;
+}
+
+int SSL_CTX_add_session(SSL_CTX *ctx, SSL_SESSION *session) {
+ /* Although |session| is inserted into two structures (a doubly-linked list
+ * and the hash table), |ctx| only takes one reference. */
+ SSL_SESSION_up_ref(session);
+
+ SSL_SESSION *old_session;
+ CRYPTO_MUTEX_lock_write(&ctx->lock);
+ if (!lh_SSL_SESSION_insert(ctx->sessions, &old_session, session)) {
+ CRYPTO_MUTEX_unlock_write(&ctx->lock);
+ SSL_SESSION_free(session);
+ return 0;
+ }
+
+ if (old_session != NULL) {
+ if (old_session == session) {
+ /* |session| was already in the cache. */
+ CRYPTO_MUTEX_unlock_write(&ctx->lock);
+ SSL_SESSION_free(old_session);
+ return 0;
+ }
+
+ /* There was a session ID collision. |old_session| must be removed from
+ * the linked list and released. */
+ SSL_SESSION_list_remove(ctx, old_session);
+ SSL_SESSION_free(old_session);
+ }
+
+ SSL_SESSION_list_add(ctx, session);
+
+ /* Enforce any cache size limits. */
+ if (SSL_CTX_sess_get_cache_size(ctx) > 0) {
+ while (SSL_CTX_sess_number(ctx) > SSL_CTX_sess_get_cache_size(ctx)) {
+ if (!remove_session_lock(ctx, ctx->session_cache_tail, 0)) {
+ break;
+ }
+ }
+ }
+
+ CRYPTO_MUTEX_unlock_write(&ctx->lock);
+ return 1;
+}
+
+int SSL_CTX_remove_session(SSL_CTX *ctx, SSL_SESSION *session) {
+ return remove_session_lock(ctx, session, 1);
+}
+
+static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *session, int lock) {
+ int ret = 0;
+
+ if (session != NULL && session->session_id_length != 0) {
+ if (lock) {
+ CRYPTO_MUTEX_lock_write(&ctx->lock);
+ }
+ SSL_SESSION *found_session = lh_SSL_SESSION_retrieve(ctx->sessions,
+ session);
+ if (found_session == session) {
+ ret = 1;
+ found_session = lh_SSL_SESSION_delete(ctx->sessions, session);
+ SSL_SESSION_list_remove(ctx, session);
+ }
+
+ if (lock) {
+ CRYPTO_MUTEX_unlock_write(&ctx->lock);
+ }
+
+ if (ret) {
+ found_session->not_resumable = 1;
+ if (ctx->remove_session_cb != NULL) {
+ ctx->remove_session_cb(ctx, found_session);
+ }
+ SSL_SESSION_free(found_session);
+ }
+ }
+
+ return ret;
+}
+
+int SSL_set_session(SSL *ssl, SSL_SESSION *session) {
+ /* SSL_set_session may only be called before the handshake has started. */
+ if (ssl->s3->initial_handshake_complete ||
+ ssl->s3->hs == NULL ||
+ ssl->s3->hs->state != SSL_ST_INIT) {
+ abort();
+ }
+
+ ssl_set_session(ssl, session);
+ return 1;
+}
+
+void ssl_set_session(SSL *ssl, SSL_SESSION *session) {
+ if (ssl->session == session) {
+ return;
+ }
+
+ SSL_SESSION_free(ssl->session);
+ ssl->session = session;
+ if (session != NULL) {
+ SSL_SESSION_up_ref(session);
+ }
+}
+
+uint32_t SSL_CTX_set_timeout(SSL_CTX *ctx, uint32_t timeout) {
+ if (ctx == NULL) {
+ return 0;
+ }
+
+ /* Historically, zero was treated as |SSL_DEFAULT_SESSION_TIMEOUT|. */
+ if (timeout == 0) {
+ timeout = SSL_DEFAULT_SESSION_TIMEOUT;
+ }
+
+ uint32_t old_timeout = ctx->session_timeout;
+ ctx->session_timeout = timeout;
+ return old_timeout;
+}
+
+uint32_t SSL_CTX_get_timeout(const SSL_CTX *ctx) {
+ if (ctx == NULL) {
+ return 0;
+ }
+
+ return ctx->session_timeout;
+}
+
+void SSL_CTX_set_session_psk_dhe_timeout(SSL_CTX *ctx, uint32_t timeout) {
+ ctx->session_psk_dhe_timeout = timeout;
+}
+
+typedef struct timeout_param_st {
+ SSL_CTX *ctx;
+ uint64_t time;
+ LHASH_OF(SSL_SESSION) *cache;
+} TIMEOUT_PARAM;
+
+static void timeout_doall_arg(SSL_SESSION *session, void *void_param) {
+ TIMEOUT_PARAM *param = void_param;
+
+ if (param->time == 0 ||
+ session->time + session->timeout < session->time ||
+ param->time > (session->time + session->timeout)) {
+ /* timeout */
+ /* The reason we don't call SSL_CTX_remove_session() is to
+ * save on locking overhead */
+ (void) lh_SSL_SESSION_delete(param->cache, session);
+ SSL_SESSION_list_remove(param->ctx, session);
+ session->not_resumable = 1;
+ if (param->ctx->remove_session_cb != NULL) {
+ param->ctx->remove_session_cb(param->ctx, session);
+ }
+ SSL_SESSION_free(session);
+ }
+}
+
+void SSL_CTX_flush_sessions(SSL_CTX *ctx, uint64_t time) {
+ TIMEOUT_PARAM tp;
+
+ tp.ctx = ctx;
+ tp.cache = ctx->sessions;
+ if (tp.cache == NULL) {
+ return;
+ }
+ tp.time = time;
+ CRYPTO_MUTEX_lock_write(&ctx->lock);
+ lh_SSL_SESSION_doall_arg(tp.cache, timeout_doall_arg, &tp);
+ CRYPTO_MUTEX_unlock_write(&ctx->lock);
+}
+
+/* locked by SSL_CTX in the calling function */
+static void SSL_SESSION_list_remove(SSL_CTX *ctx, SSL_SESSION *session) {
+ if (session->next == NULL || session->prev == NULL) {
+ return;
+ }
+
+ if (session->next == (SSL_SESSION *)&ctx->session_cache_tail) {
+ /* last element in list */
+ if (session->prev == (SSL_SESSION *)&ctx->session_cache_head) {
+ /* only one element in list */
+ ctx->session_cache_head = NULL;
+ ctx->session_cache_tail = NULL;
+ } else {
+ ctx->session_cache_tail = session->prev;
+ session->prev->next = (SSL_SESSION *)&(ctx->session_cache_tail);
+ }
+ } else {
+ if (session->prev == (SSL_SESSION *)&ctx->session_cache_head) {
+ /* first element in list */
+ ctx->session_cache_head = session->next;
+ session->next->prev = (SSL_SESSION *)&(ctx->session_cache_head);
+ } else { /* middle of list */
+ session->next->prev = session->prev;
+ session->prev->next = session->next;
+ }
+ }
+ session->prev = session->next = NULL;
+}
+
+static void SSL_SESSION_list_add(SSL_CTX *ctx, SSL_SESSION *session) {
+ if (session->next != NULL && session->prev != NULL) {
+ SSL_SESSION_list_remove(ctx, session);
+ }
+
+ if (ctx->session_cache_head == NULL) {
+ ctx->session_cache_head = session;
+ ctx->session_cache_tail = session;
+ session->prev = (SSL_SESSION *)&(ctx->session_cache_head);
+ session->next = (SSL_SESSION *)&(ctx->session_cache_tail);
+ } else {
+ session->next = ctx->session_cache_head;
+ session->next->prev = session;
+ session->prev = (SSL_SESSION *)&(ctx->session_cache_head);
+ ctx->session_cache_head = session;
+ }
+}
+
+void SSL_CTX_sess_set_new_cb(SSL_CTX *ctx,
+ int (*cb)(SSL *ssl, SSL_SESSION *session)) {
+ ctx->new_session_cb = cb;
+}
+
+int (*SSL_CTX_sess_get_new_cb(SSL_CTX *ctx))(SSL *ssl, SSL_SESSION *session) {
+ return ctx->new_session_cb;
+}
+
+void SSL_CTX_sess_set_remove_cb(
+ SSL_CTX *ctx, void (*cb)(SSL_CTX *ctx, SSL_SESSION *session)) {
+ ctx->remove_session_cb = cb;
+}
+
+void (*SSL_CTX_sess_get_remove_cb(SSL_CTX *ctx))(SSL_CTX *ctx,
+ SSL_SESSION *session) {
+ return ctx->remove_session_cb;
+}
+
+void SSL_CTX_sess_set_get_cb(SSL_CTX *ctx,
+ SSL_SESSION *(*cb)(SSL *ssl,
+ uint8_t *id, int id_len,
+ int *out_copy)) {
+ ctx->get_session_cb = cb;
+}
+
+SSL_SESSION *(*SSL_CTX_sess_get_get_cb(SSL_CTX *ctx))(
+ SSL *ssl, uint8_t *id, int id_len, int *out_copy) {
+ return ctx->get_session_cb;
+}
+
+void SSL_CTX_set_info_callback(
+ SSL_CTX *ctx, void (*cb)(const SSL *ssl, int type, int value)) {
+ ctx->info_callback = cb;
+}
+
+void (*SSL_CTX_get_info_callback(SSL_CTX *ctx))(const SSL *ssl, int type,
+ int value) {
+ return ctx->info_callback;
+}
+
+void SSL_CTX_set_channel_id_cb(SSL_CTX *ctx,
+ void (*cb)(SSL *ssl, EVP_PKEY **pkey)) {
+ ctx->channel_id_cb = cb;
+}
+
+void (*SSL_CTX_get_channel_id_cb(SSL_CTX *ctx))(SSL *ssl, EVP_PKEY **pkey) {
+ return ctx->channel_id_cb;
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_stat.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_stat.c
new file mode 100644
index 000000000..571b4a9a2
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_stat.c
@@ -0,0 +1,443 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright 2005 Nokia. All rights reserved.
+ *
+ * The portions of the attached software ("Contribution") is developed by
+ * Nokia Corporation and is licensed pursuant to the OpenSSL open source
+ * license.
+ *
+ * The Contribution, originally written by Mika Kousa and Pasi Eronen of
+ * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites
+ * support (see RFC 4279) to OpenSSL.
+ *
+ * No patent licenses or other rights except those expressly stated in
+ * the OpenSSL open source license shall be deemed granted or received
+ * expressly, by implication, estoppel, or otherwise.
+ *
+ * No assurances are provided by Nokia that the Contribution does not
+ * infringe the patent or other intellectual property rights of any third
+ * party or that the license provides you with all the necessary rights
+ * to make use of the Contribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN
+ * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA
+ * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY
+ * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
+ * OTHERWISE.
+ */
+
+#include <openssl/ssl.h>
+
+#include <assert.h>
+
+#include "internal.h"
+
+
+static int ssl_state(const SSL *ssl) {
+ if (ssl->s3->hs == NULL) {
+ assert(ssl->s3->initial_handshake_complete);
+ return SSL_ST_OK;
+ }
+
+ return ssl->s3->hs->state;
+}
+
+const char *SSL_state_string_long(const SSL *ssl) {
+ switch (ssl_state(ssl)) {
+ case SSL_ST_ACCEPT:
+ return "before accept initialization";
+
+ case SSL_ST_CONNECT:
+ return "before connect initialization";
+
+ case SSL_ST_OK:
+ return "SSL negotiation finished successfully";
+
+ case SSL_ST_RENEGOTIATE:
+ return "SSL renegotiate ciphers";
+
+ /* SSLv3 additions */
+ case SSL3_ST_CW_CLNT_HELLO_A:
+ return "SSLv3 write client hello A";
+
+ case SSL3_ST_CR_SRVR_HELLO_A:
+ return "SSLv3 read server hello A";
+
+ case SSL3_ST_CR_CERT_A:
+ return "SSLv3 read server certificate A";
+
+ case SSL3_ST_CR_KEY_EXCH_A:
+ return "SSLv3 read server key exchange A";
+
+ case SSL3_ST_CR_CERT_REQ_A:
+ return "SSLv3 read server certificate request A";
+
+ case SSL3_ST_CR_SESSION_TICKET_A:
+ return "SSLv3 read server session ticket A";
+
+ case SSL3_ST_CR_SRVR_DONE_A:
+ return "SSLv3 read server done A";
+
+ case SSL3_ST_CW_CERT_A:
+ return "SSLv3 write client certificate A";
+
+ case SSL3_ST_CW_KEY_EXCH_A:
+ return "SSLv3 write client key exchange A";
+
+ case SSL3_ST_CW_CERT_VRFY_A:
+ return "SSLv3 write certificate verify A";
+
+ case SSL3_ST_CW_CERT_VRFY_B:
+ return "SSLv3 write certificate verify B";
+
+ case SSL3_ST_CW_CHANGE:
+ case SSL3_ST_SW_CHANGE:
+ return "SSLv3 write change cipher spec";
+
+ case SSL3_ST_CW_FINISHED_A:
+ case SSL3_ST_SW_FINISHED_A:
+ return "SSLv3 write finished A";
+
+ case SSL3_ST_CR_CHANGE:
+ case SSL3_ST_SR_CHANGE:
+ return "SSLv3 read change cipher spec";
+
+ case SSL3_ST_CR_FINISHED_A:
+ case SSL3_ST_SR_FINISHED_A:
+ return "SSLv3 read finished A";
+
+ case SSL3_ST_CW_FLUSH:
+ case SSL3_ST_SW_FLUSH:
+ return "SSLv3 flush data";
+
+ case SSL3_ST_SR_CLNT_HELLO_A:
+ return "SSLv3 read client hello A";
+
+ case SSL3_ST_SR_CLNT_HELLO_B:
+ return "SSLv3 read client hello B";
+
+ case SSL3_ST_SR_CLNT_HELLO_C:
+ return "SSLv3 read client hello C";
+
+ case SSL3_ST_SW_SRVR_HELLO_A:
+ return "SSLv3 write server hello A";
+
+ case SSL3_ST_SW_CERT_A:
+ return "SSLv3 write certificate A";
+
+ case SSL3_ST_SW_KEY_EXCH_A:
+ return "SSLv3 write key exchange A";
+
+ case SSL3_ST_SW_CERT_REQ_A:
+ return "SSLv3 write certificate request A";
+
+ case SSL3_ST_SW_SESSION_TICKET_A:
+ return "SSLv3 write session ticket A";
+
+ case SSL3_ST_SW_SRVR_DONE_A:
+ return "SSLv3 write server done A";
+
+ case SSL3_ST_SR_CERT_A:
+ return "SSLv3 read client certificate A";
+
+ case SSL3_ST_SR_KEY_EXCH_A:
+ return "SSLv3 read client key exchange A";
+
+ case SSL3_ST_SR_KEY_EXCH_B:
+ return "SSLv3 read client key exchange B";
+
+ case SSL3_ST_SR_CERT_VRFY_A:
+ return "SSLv3 read certificate verify A";
+
+ /* DTLS */
+ case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A:
+ return "DTLS1 read hello verify request A";
+
+ default:
+ return "unknown state";
+ }
+}
+
+const char *SSL_state_string(const SSL *ssl) {
+ switch (ssl_state(ssl)) {
+ case SSL_ST_ACCEPT:
+ return "AINIT ";
+
+ case SSL_ST_CONNECT:
+ return "CINIT ";
+
+ case SSL_ST_OK:
+ return "SSLOK ";
+
+ /* SSLv3 additions */
+ case SSL3_ST_SW_FLUSH:
+ case SSL3_ST_CW_FLUSH:
+ return "3FLUSH";
+
+ case SSL3_ST_CW_CLNT_HELLO_A:
+ return "3WCH_A";
+
+ case SSL3_ST_CR_SRVR_HELLO_A:
+ return "3RSH_A";
+
+ case SSL3_ST_CR_CERT_A:
+ return "3RSC_A";
+
+ case SSL3_ST_CR_KEY_EXCH_A:
+ return "3RSKEA";
+
+ case SSL3_ST_CR_CERT_REQ_A:
+ return "3RCR_A";
+
+ case SSL3_ST_CR_SRVR_DONE_A:
+ return "3RSD_A";
+
+ case SSL3_ST_CW_CERT_A:
+ return "3WCC_A";
+
+ case SSL3_ST_CW_KEY_EXCH_A:
+ return "3WCKEA";
+
+ case SSL3_ST_CW_CERT_VRFY_A:
+ return "3WCV_A";
+
+ case SSL3_ST_CW_CERT_VRFY_B:
+ return "3WCV_B";
+
+ case SSL3_ST_SW_CHANGE:
+ case SSL3_ST_CW_CHANGE:
+ return "3WCCS_";
+
+ case SSL3_ST_SW_FINISHED_A:
+ case SSL3_ST_CW_FINISHED_A:
+ return "3WFINA";
+
+ case SSL3_ST_CR_CHANGE:
+ case SSL3_ST_SR_CHANGE:
+ return "3RCCS_";
+
+ case SSL3_ST_SR_FINISHED_A:
+ case SSL3_ST_CR_FINISHED_A:
+ return "3RFINA";
+
+ case SSL3_ST_SR_CLNT_HELLO_A:
+ return "3RCH_A";
+
+ case SSL3_ST_SR_CLNT_HELLO_B:
+ return "3RCH_B";
+
+ case SSL3_ST_SR_CLNT_HELLO_C:
+ return "3RCH_C";
+
+ case SSL3_ST_SW_SRVR_HELLO_A:
+ return "3WSH_A";
+
+ case SSL3_ST_SW_CERT_A:
+ return "3WSC_A";
+
+ case SSL3_ST_SW_KEY_EXCH_A:
+ return "3WSKEA";
+
+ case SSL3_ST_SW_KEY_EXCH_B:
+ return "3WSKEB";
+
+ case SSL3_ST_SW_CERT_REQ_A:
+ return "3WCR_A";
+
+ case SSL3_ST_SW_SRVR_DONE_A:
+ return "3WSD_A";
+
+ case SSL3_ST_SR_CERT_A:
+ return "3RCC_A";
+
+ case SSL3_ST_SR_KEY_EXCH_A:
+ return "3RCKEA";
+
+ case SSL3_ST_SR_CERT_VRFY_A:
+ return "3RCV_A";
+
+ /* DTLS */
+ case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A:
+ return "DRCHVA";
+
+ default:
+ return "UNKWN ";
+ }
+}
+
+const char *SSL_alert_type_string_long(int value) {
+ value >>= 8;
+ if (value == SSL3_AL_WARNING) {
+ return "warning";
+ } else if (value == SSL3_AL_FATAL) {
+ return "fatal";
+ }
+
+ return "unknown";
+}
+
+const char *SSL_alert_type_string(int value) {
+ return "!";
+}
+
+const char *SSL_alert_desc_string(int value) {
+ return "!!";
+}
+
+const char *SSL_alert_desc_string_long(int value) {
+ switch (value & 0xff) {
+ case SSL3_AD_CLOSE_NOTIFY:
+ return "close notify";
+
+ case SSL3_AD_UNEXPECTED_MESSAGE:
+ return "unexpected_message";
+
+ case SSL3_AD_BAD_RECORD_MAC:
+ return "bad record mac";
+
+ case SSL3_AD_DECOMPRESSION_FAILURE:
+ return "decompression failure";
+
+ case SSL3_AD_HANDSHAKE_FAILURE:
+ return "handshake failure";
+
+ case SSL3_AD_NO_CERTIFICATE:
+ return "no certificate";
+
+ case SSL3_AD_BAD_CERTIFICATE:
+ return "bad certificate";
+
+ case SSL3_AD_UNSUPPORTED_CERTIFICATE:
+ return "unsupported certificate";
+
+ case SSL3_AD_CERTIFICATE_REVOKED:
+ return "certificate revoked";
+
+ case SSL3_AD_CERTIFICATE_EXPIRED:
+ return "certificate expired";
+
+ case SSL3_AD_CERTIFICATE_UNKNOWN:
+ return "certificate unknown";
+
+ case SSL3_AD_ILLEGAL_PARAMETER:
+ return "illegal parameter";
+
+ case TLS1_AD_DECRYPTION_FAILED:
+ return "decryption failed";
+
+ case TLS1_AD_RECORD_OVERFLOW:
+ return "record overflow";
+
+ case TLS1_AD_UNKNOWN_CA:
+ return "unknown CA";
+
+ case TLS1_AD_ACCESS_DENIED:
+ return "access denied";
+
+ case TLS1_AD_DECODE_ERROR:
+ return "decode error";
+
+ case TLS1_AD_DECRYPT_ERROR:
+ return "decrypt error";
+
+ case TLS1_AD_EXPORT_RESTRICTION:
+ return "export restriction";
+
+ case TLS1_AD_PROTOCOL_VERSION:
+ return "protocol version";
+
+ case TLS1_AD_INSUFFICIENT_SECURITY:
+ return "insufficient security";
+
+ case TLS1_AD_INTERNAL_ERROR:
+ return "internal error";
+
+ case SSL3_AD_INAPPROPRIATE_FALLBACK:
+ return "inappropriate fallback";
+
+ case TLS1_AD_USER_CANCELLED:
+ return "user canceled";
+
+ case TLS1_AD_NO_RENEGOTIATION:
+ return "no renegotiation";
+
+ case TLS1_AD_UNSUPPORTED_EXTENSION:
+ return "unsupported extension";
+
+ case TLS1_AD_CERTIFICATE_UNOBTAINABLE:
+ return "certificate unobtainable";
+
+ case TLS1_AD_UNRECOGNIZED_NAME:
+ return "unrecognized name";
+
+ case TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE:
+ return "bad certificate status response";
+
+ case TLS1_AD_BAD_CERTIFICATE_HASH_VALUE:
+ return "bad certificate hash value";
+
+ case TLS1_AD_UNKNOWN_PSK_IDENTITY:
+ return "unknown PSK identity";
+
+ case TLS1_AD_CERTIFICATE_REQUIRED:
+ return "certificate required";
+
+ default:
+ return "unknown";
+ }
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_test.cc b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_test.cc
new file mode 100644
index 000000000..6b150e8c6
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_test.cc
@@ -0,0 +1,3531 @@
+/* Copyright (c) 2014, 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 <string.h>
+#include <time.h>
+
+#include <algorithm>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include <openssl/base64.h>
+#include <openssl/bio.h>
+#include <openssl/cipher.h>
+#include <openssl/crypto.h>
+#include <openssl/err.h>
+#include <openssl/hmac.h>
+#include <openssl/pem.h>
+#include <openssl/sha.h>
+#include <openssl/ssl.h>
+#include <openssl/rand.h>
+#include <openssl/x509.h>
+
+#include "internal.h"
+#include "../crypto/internal.h"
+#include "../crypto/test/test_util.h"
+
+#if defined(OPENSSL_WINDOWS)
+/* Windows defines struct timeval in winsock2.h. */
+OPENSSL_MSVC_PRAGMA(warning(push, 3))
+#include <winsock2.h>
+OPENSSL_MSVC_PRAGMA(warning(pop))
+#else
+#include <sys/time.h>
+#endif
+
+
+struct ExpectedCipher {
+ unsigned long id;
+ int in_group_flag;
+};
+
+struct CipherTest {
+ // The rule string to apply.
+ const char *rule;
+ // The list of expected ciphers, in order.
+ std::vector<ExpectedCipher> expected;
+ // True if this cipher list should fail in strict mode.
+ bool strict_fail;
+};
+
+struct CurveTest {
+ // The rule string to apply.
+ const char *rule;
+ // The list of expected curves, in order.
+ std::vector<uint16_t> expected;
+};
+
+static const CipherTest kCipherTests[] = {
+ // Selecting individual ciphers should work.
+ {
+ "ECDHE-ECDSA-CHACHA20-POLY1305:"
+ "ECDHE-RSA-CHACHA20-POLY1305:"
+ "ECDHE-ECDSA-AES128-GCM-SHA256:"
+ "ECDHE-RSA-AES128-GCM-SHA256",
+ {
+ {TLS1_CK_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, 0},
+ {TLS1_CK_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, 0},
+ {TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0},
+ {TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0},
+ },
+ false,
+ },
+ // + reorders selected ciphers to the end, keeping their relative order.
+ {
+ "ECDHE-ECDSA-CHACHA20-POLY1305:"
+ "ECDHE-RSA-CHACHA20-POLY1305:"
+ "ECDHE-ECDSA-AES128-GCM-SHA256:"
+ "ECDHE-RSA-AES128-GCM-SHA256:"
+ "+aRSA",
+ {
+ {TLS1_CK_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, 0},
+ {TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0},
+ {TLS1_CK_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, 0},
+ {TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0},
+ },
+ false,
+ },
+ // ! banishes ciphers from future selections.
+ {
+ "!aRSA:"
+ "ECDHE-ECDSA-CHACHA20-POLY1305:"
+ "ECDHE-RSA-CHACHA20-POLY1305:"
+ "ECDHE-ECDSA-AES128-GCM-SHA256:"
+ "ECDHE-RSA-AES128-GCM-SHA256",
+ {
+ {TLS1_CK_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, 0},
+ {TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0},
+ },
+ false,
+ },
+ // Multiple masks can be ANDed in a single rule.
+ {
+ "kRSA+AESGCM+AES128",
+ {
+ {TLS1_CK_RSA_WITH_AES_128_GCM_SHA256, 0},
+ },
+ false,
+ },
+ // - removes selected ciphers, but preserves their order for future
+ // selections. Select AES_128_GCM, but order the key exchanges RSA, DHE_RSA,
+ // ECDHE_RSA.
+ {
+ "ALL:-kECDHE:-kDHE:-kRSA:-ALL:"
+ "AESGCM+AES128+aRSA",
+ {
+ {TLS1_CK_RSA_WITH_AES_128_GCM_SHA256, 0},
+ {TLS1_CK_DHE_RSA_WITH_AES_128_GCM_SHA256, 0},
+ {TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0},
+ },
+ false,
+ },
+ // Unknown selectors are no-ops, except in strict mode.
+ {
+ "ECDHE-ECDSA-CHACHA20-POLY1305:"
+ "ECDHE-RSA-CHACHA20-POLY1305:"
+ "ECDHE-ECDSA-AES128-GCM-SHA256:"
+ "ECDHE-RSA-AES128-GCM-SHA256:"
+ "BOGUS1",
+ {
+ {TLS1_CK_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, 0},
+ {TLS1_CK_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, 0},
+ {TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0},
+ {TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0},
+ },
+ true,
+ },
+ // Unknown selectors are no-ops, except in strict mode.
+ {
+ "ECDHE-ECDSA-CHACHA20-POLY1305:"
+ "ECDHE-RSA-CHACHA20-POLY1305:"
+ "ECDHE-ECDSA-AES128-GCM-SHA256:"
+ "ECDHE-RSA-AES128-GCM-SHA256:"
+ "-BOGUS2:+BOGUS3:!BOGUS4",
+ {
+ {TLS1_CK_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, 0},
+ {TLS1_CK_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, 0},
+ {TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0},
+ {TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0},
+ },
+ true,
+ },
+ // Square brackets specify equi-preference groups.
+ {
+ "[ECDHE-ECDSA-CHACHA20-POLY1305|ECDHE-ECDSA-AES128-GCM-SHA256]:"
+ "[ECDHE-RSA-CHACHA20-POLY1305]:"
+ "ECDHE-RSA-AES128-GCM-SHA256",
+ {
+ {TLS1_CK_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, 1},
+ {TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0},
+ {TLS1_CK_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, 0},
+ {TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0},
+ },
+ false,
+ },
+ // @STRENGTH performs a stable strength-sort of the selected ciphers and
+ // only the selected ciphers.
+ {
+ // To simplify things, banish all but {ECDHE_RSA,RSA} x
+ // {CHACHA20,AES_256_CBC,AES_128_CBC} x SHA1.
+ "!kEDH:!AESGCM:!3DES:!SHA256:!SHA384:"
+ // Order some ciphers backwards by strength.
+ "ALL:-CHACHA20:-AES256:-AES128:-ALL:"
+ // Select ECDHE ones and sort them by strength. Ties should resolve
+ // based on the order above.
+ "kECDHE:@STRENGTH:-ALL:"
+ // Now bring back everything uses RSA. ECDHE_RSA should be first, sorted
+ // by strength. Then RSA, backwards by strength.
+ "aRSA",
+ {
+ {TLS1_CK_ECDHE_RSA_WITH_AES_256_CBC_SHA, 0},
+ {TLS1_CK_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, 0},
+ {TLS1_CK_ECDHE_RSA_WITH_AES_128_CBC_SHA, 0},
+ {TLS1_CK_RSA_WITH_AES_128_SHA, 0},
+ {TLS1_CK_RSA_WITH_AES_256_SHA, 0},
+ },
+ false,
+ },
+ // Exact ciphers may not be used in multi-part rules; they are treated
+ // as unknown aliases.
+ {
+ "ECDHE-ECDSA-AES128-GCM-SHA256:"
+ "ECDHE-RSA-AES128-GCM-SHA256:"
+ "!ECDHE-RSA-AES128-GCM-SHA256+RSA:"
+ "!ECDSA+ECDHE-ECDSA-AES128-GCM-SHA256",
+ {
+ {TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0},
+ {TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0},
+ },
+ true,
+ },
+ // SSLv3 matches everything that existed before TLS 1.2.
+ {
+ "AES128-SHA:AES128-SHA256:!SSLv3",
+ {
+ {TLS1_CK_RSA_WITH_AES_128_SHA256, 0},
+ },
+ false,
+ },
+ // TLSv1.2 matches everything added in TLS 1.2.
+ {
+ "AES128-SHA:AES128-SHA256:!TLSv1.2",
+ {
+ {TLS1_CK_RSA_WITH_AES_128_SHA, 0},
+ },
+ false,
+ },
+ // The two directives have no intersection. But each component is valid, so
+ // even in strict mode it is accepted.
+ {
+ "AES128-SHA:AES128-SHA256:!TLSv1.2+SSLv3",
+ {
+ {TLS1_CK_RSA_WITH_AES_128_SHA, 0},
+ {TLS1_CK_RSA_WITH_AES_128_SHA256, 0},
+ },
+ false,
+ },
+};
+
+static const char *kBadRules[] = {
+ // Invalid brackets.
+ "[ECDHE-RSA-CHACHA20-POLY1305|ECDHE-RSA-AES128-GCM-SHA256",
+ "RSA]",
+ "[[RSA]]",
+ // Operators inside brackets.
+ "[+RSA]",
+ // Unknown directive.
+ "@BOGUS",
+ // Empty cipher lists error at SSL_CTX_set_cipher_list.
+ "",
+ "BOGUS",
+ // COMPLEMENTOFDEFAULT is empty.
+ "COMPLEMENTOFDEFAULT",
+ // Invalid command.
+ "?BAR",
+ // Special operators are not allowed if groups are used.
+ "[ECDHE-RSA-CHACHA20-POLY1305|ECDHE-RSA-AES128-GCM-SHA256]:+FOO",
+ "[ECDHE-RSA-CHACHA20-POLY1305|ECDHE-RSA-AES128-GCM-SHA256]:!FOO",
+ "[ECDHE-RSA-CHACHA20-POLY1305|ECDHE-RSA-AES128-GCM-SHA256]:-FOO",
+ "[ECDHE-RSA-CHACHA20-POLY1305|ECDHE-RSA-AES128-GCM-SHA256]:@STRENGTH",
+ // Opcode supplied, but missing selector.
+ "+",
+};
+
+static const char *kMustNotIncludeNull[] = {
+ "ALL",
+ "DEFAULT",
+ "HIGH",
+ "FIPS",
+ "SHA",
+ "SHA1",
+ "RSA",
+ "SSLv3",
+ "TLSv1",
+ "TLSv1.2",
+};
+
+static const CurveTest kCurveTests[] = {
+ {
+ "P-256",
+ { SSL_CURVE_SECP256R1 },
+ },
+ {
+ "P-256:P-384:P-521:X25519",
+ {
+ SSL_CURVE_SECP256R1,
+ SSL_CURVE_SECP384R1,
+ SSL_CURVE_SECP521R1,
+ SSL_CURVE_X25519,
+ },
+ },
+};
+
+static const char *kBadCurvesLists[] = {
+ "",
+ ":",
+ "::",
+ "P-256::X25519",
+ "RSA:P-256",
+ "P-256:RSA",
+ "X25519:P-256:",
+ ":X25519:P-256",
+};
+
+static void PrintCipherPreferenceList(ssl_cipher_preference_list_st *list) {
+ bool in_group = false;
+ for (size_t i = 0; i < sk_SSL_CIPHER_num(list->ciphers); i++) {
+ const SSL_CIPHER *cipher = sk_SSL_CIPHER_value(list->ciphers, i);
+ if (!in_group && list->in_group_flags[i]) {
+ fprintf(stderr, "\t[\n");
+ in_group = true;
+ }
+ fprintf(stderr, "\t");
+ if (in_group) {
+ fprintf(stderr, " ");
+ }
+ fprintf(stderr, "%s\n", SSL_CIPHER_get_name(cipher));
+ if (in_group && !list->in_group_flags[i]) {
+ fprintf(stderr, "\t]\n");
+ in_group = false;
+ }
+ }
+}
+
+static bool TestCipherRule(const CipherTest &t) {
+ bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
+ if (!ctx) {
+ return false;
+ }
+
+ if (!SSL_CTX_set_cipher_list(ctx.get(), t.rule)) {
+ fprintf(stderr, "Error testing cipher rule '%s'\n", t.rule);
+ return false;
+ }
+
+ if (!SSL_CTX_set_strict_cipher_list(ctx.get(), t.rule) != t.strict_fail) {
+ fprintf(stderr, "Unexpected strict failure result testing cipher rule '%s':"
+ " expected %d\n", t.rule, t.strict_fail);
+ return false;
+ }
+
+ // Compare the two lists.
+ if (sk_SSL_CIPHER_num(ctx->cipher_list->ciphers) != t.expected.size()) {
+ fprintf(stderr, "Error: cipher rule '%s' evaluated to:\n", t.rule);
+ PrintCipherPreferenceList(ctx->cipher_list);
+ return false;
+ }
+
+ for (size_t i = 0; i < t.expected.size(); i++) {
+ const SSL_CIPHER *cipher =
+ sk_SSL_CIPHER_value(ctx->cipher_list->ciphers, i);
+ if (t.expected[i].id != SSL_CIPHER_get_id(cipher) ||
+ t.expected[i].in_group_flag != ctx->cipher_list->in_group_flags[i]) {
+ fprintf(stderr, "Error: cipher rule '%s' evaluated to:\n", t.rule);
+ PrintCipherPreferenceList(ctx->cipher_list);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool TestRuleDoesNotIncludeNull(const char *rule) {
+ bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(SSLv23_server_method()));
+ if (!ctx) {
+ return false;
+ }
+ if (!SSL_CTX_set_strict_cipher_list(ctx.get(), rule)) {
+ fprintf(stderr, "Error: cipher rule '%s' failed\n", rule);
+ return false;
+ }
+ for (size_t i = 0; i < sk_SSL_CIPHER_num(ctx->cipher_list->ciphers); i++) {
+ if (SSL_CIPHER_is_NULL(sk_SSL_CIPHER_value(ctx->cipher_list->ciphers, i))) {
+ fprintf(stderr, "Error: cipher rule '%s' includes NULL\n",rule);
+ return false;
+ }
+ }
+ return true;
+}
+
+static bool TestCipherRules() {
+ for (const CipherTest &test : kCipherTests) {
+ if (!TestCipherRule(test)) {
+ return false;
+ }
+ }
+
+ for (const char *rule : kBadRules) {
+ bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(SSLv23_server_method()));
+ if (!ctx) {
+ return false;
+ }
+ if (SSL_CTX_set_cipher_list(ctx.get(), rule)) {
+ fprintf(stderr, "Cipher rule '%s' unexpectedly succeeded\n", rule);
+ return false;
+ }
+ ERR_clear_error();
+ }
+
+ for (const char *rule : kMustNotIncludeNull) {
+ if (!TestRuleDoesNotIncludeNull(rule)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool TestCurveRule(const CurveTest &t) {
+ bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
+ if (!ctx) {
+ return false;
+ }
+
+ if (!SSL_CTX_set1_curves_list(ctx.get(), t.rule)) {
+ fprintf(stderr, "Error testing curves list '%s'\n", t.rule);
+ return false;
+ }
+
+ // Compare the two lists.
+ if (ctx->supported_group_list_len != t.expected.size()) {
+ fprintf(stderr, "Error testing curves list '%s': length\n", t.rule);
+ return false;
+ }
+
+ for (size_t i = 0; i < t.expected.size(); i++) {
+ if (t.expected[i] != ctx->supported_group_list[i]) {
+ fprintf(stderr, "Error testing curves list '%s': mismatch\n", t.rule);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool TestCurveRules() {
+ for (const CurveTest &test : kCurveTests) {
+ if (!TestCurveRule(test)) {
+ return false;
+ }
+ }
+
+ for (const char *rule : kBadCurvesLists) {
+ bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(SSLv23_server_method()));
+ if (!ctx) {
+ return false;
+ }
+ if (SSL_CTX_set1_curves_list(ctx.get(), rule)) {
+ fprintf(stderr, "Curves list '%s' unexpectedly succeeded\n", rule);
+ return false;
+ }
+ ERR_clear_error();
+ }
+
+ return true;
+}
+
+// kOpenSSLSession is a serialized SSL_SESSION.
+static const char kOpenSSLSession[] =
+ "MIIFqgIBAQICAwMEAsAvBCAG5Q1ndq4Yfmbeo1zwLkNRKmCXGdNgWvGT3cskV0yQ"
+ "kAQwJlrlzkAWBOWiLj/jJ76D7l+UXoizP2KI2C7I2FccqMmIfFmmkUy32nIJ0mZH"
+ "IWoJoQYCBFRDO46iBAICASyjggR6MIIEdjCCA16gAwIBAgIIK9dUvsPWSlUwDQYJ"
+ "KoZIhvcNAQEFBQAwSTELMAkGA1UEBhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMx"
+ "JTAjBgNVBAMTHEdvb2dsZSBJbnRlcm5ldCBBdXRob3JpdHkgRzIwHhcNMTQxMDA4"
+ "MTIwNzU3WhcNMTUwMTA2MDAwMDAwWjBoMQswCQYDVQQGEwJVUzETMBEGA1UECAwK"
+ "Q2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzETMBEGA1UECgwKR29v"
+ "Z2xlIEluYzEXMBUGA1UEAwwOd3d3Lmdvb2dsZS5jb20wggEiMA0GCSqGSIb3DQEB"
+ "AQUAA4IBDwAwggEKAoIBAQCcKeLrplAC+Lofy8t/wDwtB6eu72CVp0cJ4V3lknN6"
+ "huH9ct6FFk70oRIh/VBNBBz900jYy+7111Jm1b8iqOTQ9aT5C7SEhNcQFJvqzH3e"
+ "MPkb6ZSWGm1yGF7MCQTGQXF20Sk/O16FSjAynU/b3oJmOctcycWYkY0ytS/k3LBu"
+ "Id45PJaoMqjB0WypqvNeJHC3q5JjCB4RP7Nfx5jjHSrCMhw8lUMW4EaDxjaR9KDh"
+ "PLgjsk+LDIySRSRDaCQGhEOWLJZVLzLo4N6/UlctCHEllpBUSvEOyFga52qroGjg"
+ "rf3WOQ925MFwzd6AK+Ich0gDRg8sQfdLH5OuP1cfLfU1AgMBAAGjggFBMIIBPTAd"
+ "BgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwGQYDVR0RBBIwEIIOd3d3Lmdv"
+ "b2dsZS5jb20waAYIKwYBBQUHAQEEXDBaMCsGCCsGAQUFBzAChh9odHRwOi8vcGtp"
+ "Lmdvb2dsZS5jb20vR0lBRzIuY3J0MCsGCCsGAQUFBzABhh9odHRwOi8vY2xpZW50"
+ "czEuZ29vZ2xlLmNvbS9vY3NwMB0GA1UdDgQWBBQ7a+CcxsZByOpc+xpYFcIbnUMZ"
+ "hTAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFErdBhYbvPZotXb1gba7Yhq6WoEv"
+ "MBcGA1UdIAQQMA4wDAYKKwYBBAHWeQIFATAwBgNVHR8EKTAnMCWgI6Ahhh9odHRw"
+ "Oi8vcGtpLmdvb2dsZS5jb20vR0lBRzIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCa"
+ "OXCBdoqUy5bxyq+Wrh1zsyyCFim1PH5VU2+yvDSWrgDY8ibRGJmfff3r4Lud5kal"
+ "dKs9k8YlKD3ITG7P0YT/Rk8hLgfEuLcq5cc0xqmE42xJ+Eo2uzq9rYorc5emMCxf"
+ "5L0TJOXZqHQpOEcuptZQ4OjdYMfSxk5UzueUhA3ogZKRcRkdB3WeWRp+nYRhx4St"
+ "o2rt2A0MKmY9165GHUqMK9YaaXHDXqBu7Sefr1uSoAP9gyIJKeihMivsGqJ1TD6Z"
+ "cc6LMe+dN2P8cZEQHtD1y296ul4Mivqk3jatUVL8/hCwgch9A8O4PGZq9WqBfEWm"
+ "IyHh1dPtbg1lOXdYCWtjpAIEAKUDAgEUqQUCAwGJwKqBpwSBpBwUQvoeOk0Kg36S"
+ "YTcLEkXqKwOBfF9vE4KX0NxeLwjcDTpsuh3qXEaZ992r1N38VDcyS6P7I6HBYN9B"
+ "sNHM362zZnY27GpTw+Kwd751CLoXFPoaMOe57dbBpXoro6Pd3BTbf/Tzr88K06yE"
+ "OTDKPNj3+inbMaVigtK4PLyPq+Topyzvx9USFgRvyuoxn0Hgb+R0A3j6SLRuyOdA"
+ "i4gv7Y5oliyntgMBAQA=";
+
+// kCustomSession is a custom serialized SSL_SESSION generated by
+// filling in missing fields from |kOpenSSLSession|. This includes
+// providing |peer_sha256|, so |peer| is not serialized.
+static const char kCustomSession[] =
+ "MIIBdgIBAQICAwMEAsAvBCAG5Q1ndq4Yfmbeo1zwLkNRKmCXGdNgWvGT3cskV0yQ"
+ "kAQwJlrlzkAWBOWiLj/jJ76D7l+UXoizP2KI2C7I2FccqMmIfFmmkUy32nIJ0mZH"
+ "IWoJoQYCBFRDO46iBAICASykAwQBAqUDAgEUphAEDnd3dy5nb29nbGUuY29tqAcE"
+ "BXdvcmxkqQUCAwGJwKqBpwSBpBwUQvoeOk0Kg36SYTcLEkXqKwOBfF9vE4KX0Nxe"
+ "LwjcDTpsuh3qXEaZ992r1N38VDcyS6P7I6HBYN9BsNHM362zZnY27GpTw+Kwd751"
+ "CLoXFPoaMOe57dbBpXoro6Pd3BTbf/Tzr88K06yEOTDKPNj3+inbMaVigtK4PLyP"
+ "q+Topyzvx9USFgRvyuoxn0Hgb+R0A3j6SLRuyOdAi4gv7Y5oliynrSIEIAYGBgYG"
+ "BgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGrgMEAQevAwQBBLADBAEF";
+
+// kBoringSSLSession is a serialized SSL_SESSION generated from bssl client.
+static const char kBoringSSLSession[] =
+ "MIIRwQIBAQICAwMEAsAvBCDdoGxGK26mR+8lM0uq6+k9xYuxPnwAjpcF9n0Yli9R"
+ "kQQwbyshfWhdi5XQ1++7n2L1qqrcVlmHBPpr6yknT/u4pUrpQB5FZ7vqvNn8MdHf"
+ "9rWgoQYCBFXgs7uiBAICHCCjggR6MIIEdjCCA16gAwIBAgIIf+yfD7Y6UicwDQYJ"
+ "KoZIhvcNAQELBQAwSTELMAkGA1UEBhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMx"
+ "JTAjBgNVBAMTHEdvb2dsZSBJbnRlcm5ldCBBdXRob3JpdHkgRzIwHhcNMTUwODEy"
+ "MTQ1MzE1WhcNMTUxMTEwMDAwMDAwWjBoMQswCQYDVQQGEwJVUzETMBEGA1UECAwK"
+ "Q2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzETMBEGA1UECgwKR29v"
+ "Z2xlIEluYzEXMBUGA1UEAwwOd3d3Lmdvb2dsZS5jb20wggEiMA0GCSqGSIb3DQEB"
+ "AQUAA4IBDwAwggEKAoIBAQC0MeG5YGQ0t+IeJeoneP/PrhEaieibeKYkbKVLNZpo"
+ "PLuBinvhkXZo3DC133NpCBpy6ZktBwamqyixAyuk/NU6OjgXqwwxfQ7di1AInLIU"
+ "792c7hFyNXSUCG7At8Ifi3YwBX9Ba6u/1d6rWTGZJrdCq3QU11RkKYyTq2KT5mce"
+ "Tv9iGKqSkSTlp8puy/9SZ/3DbU3U+BuqCFqeSlz7zjwFmk35acdCilpJlVDDN5C/"
+ "RCh8/UKc8PaL+cxlt531qoTENvYrflBno14YEZlCBZsPiFeUSILpKEj3Ccwhy0eL"
+ "EucWQ72YZU8mUzXBoXGn0zA0crFl5ci/2sTBBGZsylNBAgMBAAGjggFBMIIBPTAd"
+ "BgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwGQYDVR0RBBIwEIIOd3d3Lmdv"
+ "b2dsZS5jb20waAYIKwYBBQUHAQEEXDBaMCsGCCsGAQUFBzAChh9odHRwOi8vcGtp"
+ "Lmdvb2dsZS5jb20vR0lBRzIuY3J0MCsGCCsGAQUFBzABhh9odHRwOi8vY2xpZW50"
+ "czEuZ29vZ2xlLmNvbS9vY3NwMB0GA1UdDgQWBBS/bzHxcE73Q4j3slC4BLbMtLjG"
+ "GjAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFErdBhYbvPZotXb1gba7Yhq6WoEv"
+ "MBcGA1UdIAQQMA4wDAYKKwYBBAHWeQIFATAwBgNVHR8EKTAnMCWgI6Ahhh9odHRw"
+ "Oi8vcGtpLmdvb2dsZS5jb20vR0lBRzIuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQAb"
+ "qdWPZEHk0X7iKPCTHL6S3w6q1eR67goxZGFSM1lk1hjwyu7XcLJuvALVV9uY3ovE"
+ "kQZSHwT+pyOPWQhsSjO+1GyjvCvK/CAwiUmBX+bQRGaqHsRcio7xSbdVcajQ3bXd"
+ "X+s0WdbOpn6MStKAiBVloPlSxEI8pxY6x/BBCnTIk/+DMB17uZlOjG3vbAnkDkP+"
+ "n0OTucD9sHV7EVj9XUxi51nOfNBCN/s7lpUjDS/NJ4k3iwOtbCPswiot8vLO779a"
+ "f07vR03r349Iz/KTzk95rlFtX0IU+KYNxFNsanIXZ+C9FYGRXkwhHcvFb4qMUB1y"
+ "TTlM80jBMOwyjZXmjRAhpAIEAKUDAgEUqQUCAwGJwKqBpwSBpOgebbmn9NRUtMWH"
+ "+eJpqA5JLMFSMCChOsvKey3toBaCNGU7HfAEiiXNuuAdCBoK262BjQc2YYfqFzqH"
+ "zuppopXCvhohx7j/tnCNZIMgLYt/O9SXK2RYI5z8FhCCHvB4CbD5G0LGl5EFP27s"
+ "Jb6S3aTTYPkQe8yZSlxevg6NDwmTogLO9F7UUkaYmVcMQhzssEE2ZRYNwSOU6KjE"
+ "0Yj+8fAiBtbQriIEIN2L8ZlpaVrdN5KFNdvcmOxJu81P8q53X55xQyGTnGWwsgMC"
+ "ARezggvvMIIEdjCCA16gAwIBAgIIf+yfD7Y6UicwDQYJKoZIhvcNAQELBQAwSTEL"
+ "MAkGA1UEBhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2ds"
+ "ZSBJbnRlcm5ldCBBdXRob3JpdHkgRzIwHhcNMTUwODEyMTQ1MzE1WhcNMTUxMTEw"
+ "MDAwMDAwWjBoMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQG"
+ "A1UEBwwNTW91bnRhaW4gVmlldzETMBEGA1UECgwKR29vZ2xlIEluYzEXMBUGA1UE"
+ "AwwOd3d3Lmdvb2dsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB"
+ "AQC0MeG5YGQ0t+IeJeoneP/PrhEaieibeKYkbKVLNZpoPLuBinvhkXZo3DC133Np"
+ "CBpy6ZktBwamqyixAyuk/NU6OjgXqwwxfQ7di1AInLIU792c7hFyNXSUCG7At8If"
+ "i3YwBX9Ba6u/1d6rWTGZJrdCq3QU11RkKYyTq2KT5mceTv9iGKqSkSTlp8puy/9S"
+ "Z/3DbU3U+BuqCFqeSlz7zjwFmk35acdCilpJlVDDN5C/RCh8/UKc8PaL+cxlt531"
+ "qoTENvYrflBno14YEZlCBZsPiFeUSILpKEj3Ccwhy0eLEucWQ72YZU8mUzXBoXGn"
+ "0zA0crFl5ci/2sTBBGZsylNBAgMBAAGjggFBMIIBPTAdBgNVHSUEFjAUBggrBgEF"
+ "BQcDAQYIKwYBBQUHAwIwGQYDVR0RBBIwEIIOd3d3Lmdvb2dsZS5jb20waAYIKwYB"
+ "BQUHAQEEXDBaMCsGCCsGAQUFBzAChh9odHRwOi8vcGtpLmdvb2dsZS5jb20vR0lB"
+ "RzIuY3J0MCsGCCsGAQUFBzABhh9odHRwOi8vY2xpZW50czEuZ29vZ2xlLmNvbS9v"
+ "Y3NwMB0GA1UdDgQWBBS/bzHxcE73Q4j3slC4BLbMtLjGGjAMBgNVHRMBAf8EAjAA"
+ "MB8GA1UdIwQYMBaAFErdBhYbvPZotXb1gba7Yhq6WoEvMBcGA1UdIAQQMA4wDAYK"
+ "KwYBBAHWeQIFATAwBgNVHR8EKTAnMCWgI6Ahhh9odHRwOi8vcGtpLmdvb2dsZS5j"
+ "b20vR0lBRzIuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQAbqdWPZEHk0X7iKPCTHL6S"
+ "3w6q1eR67goxZGFSM1lk1hjwyu7XcLJuvALVV9uY3ovEkQZSHwT+pyOPWQhsSjO+"
+ "1GyjvCvK/CAwiUmBX+bQRGaqHsRcio7xSbdVcajQ3bXdX+s0WdbOpn6MStKAiBVl"
+ "oPlSxEI8pxY6x/BBCnTIk/+DMB17uZlOjG3vbAnkDkP+n0OTucD9sHV7EVj9XUxi"
+ "51nOfNBCN/s7lpUjDS/NJ4k3iwOtbCPswiot8vLO779af07vR03r349Iz/KTzk95"
+ "rlFtX0IU+KYNxFNsanIXZ+C9FYGRXkwhHcvFb4qMUB1yTTlM80jBMOwyjZXmjRAh"
+ "MIID8DCCAtigAwIBAgIDAjqDMA0GCSqGSIb3DQEBCwUAMEIxCzAJBgNVBAYTAlVT"
+ "MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i"
+ "YWwgQ0EwHhcNMTMwNDA1MTUxNTU2WhcNMTYxMjMxMjM1OTU5WjBJMQswCQYDVQQG"
+ "EwJVUzETMBEGA1UEChMKR29vZ2xlIEluYzElMCMGA1UEAxMcR29vZ2xlIEludGVy"
+ "bmV0IEF1dGhvcml0eSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB"
+ "AJwqBHdc2FCROgajguDYUEi8iT/xGXAaiEZ+4I/F8YnOIe5a/mENtzJEiaB0C1NP"
+ "VaTOgmKV7utZX8bhBYASxF6UP7xbSDj0U/ck5vuR6RXEz/RTDfRK/J9U3n2+oGtv"
+ "h8DQUB8oMANA2ghzUWx//zo8pzcGjr1LEQTrfSTe5vn8MXH7lNVg8y5Kr0LSy+rE"
+ "ahqyzFPdFUuLH8gZYR/Nnag+YyuENWllhMgZxUYi+FOVvuOAShDGKuy6lyARxzmZ"
+ "EASg8GF6lSWMTlJ14rbtCMoU/M4iarNOz0YDl5cDfsCx3nuvRTPPuj5xt970JSXC"
+ "DTWJnZ37DhF5iR43xa+OcmkCAwEAAaOB5zCB5DAfBgNVHSMEGDAWgBTAephojYn7"
+ "qwVkDBF9qn1luMrMTjAdBgNVHQ4EFgQUSt0GFhu89mi1dvWBtrtiGrpagS8wDgYD"
+ "VR0PAQH/BAQDAgEGMC4GCCsGAQUFBwEBBCIwIDAeBggrBgEFBQcwAYYSaHR0cDov"
+ "L2cuc3ltY2QuY29tMBIGA1UdEwEB/wQIMAYBAf8CAQAwNQYDVR0fBC4wLDAqoCig"
+ "JoYkaHR0cDovL2cuc3ltY2IuY29tL2NybHMvZ3RnbG9iYWwuY3JsMBcGA1UdIAQQ"
+ "MA4wDAYKKwYBBAHWeQIFATANBgkqhkiG9w0BAQsFAAOCAQEAqvqpIM1qZ4PtXtR+"
+ "3h3Ef+AlBgDFJPupyC1tft6dgmUsgWM0Zj7pUsIItMsv91+ZOmqcUHqFBYx90SpI"
+ "hNMJbHzCzTWf84LuUt5oX+QAihcglvcpjZpNy6jehsgNb1aHA30DP9z6eX0hGfnI"
+ "Oi9RdozHQZJxjyXON/hKTAAj78Q1EK7gI4BzfE00LshukNYQHpmEcxpw8u1VDu4X"
+ "Bupn7jLrLN1nBz/2i8Jw3lsA5rsb0zYaImxssDVCbJAJPZPpZAkiDoUGn8JzIdPm"
+ "X4DkjYUiOnMDsWCOrmji9D6X52ASCWg23jrW4kOVWzeBkoEfu43XrVJkFleW2V40"
+ "fsg12DCCA30wggLmoAMCAQICAxK75jANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQG"
+ "EwJVUzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUg"
+ "Q2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTAyMDUyMTA0MDAwMFoXDTE4MDgyMTA0"
+ "MDAwMFowQjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xGzAZ"
+ "BgNVBAMTEkdlb1RydXN0IEdsb2JhbCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP"
+ "ADCCAQoCggEBANrMGGMw/fQXIxpWflvfPGw45HG3eJHUvKHYTPioQ7YD6U0hBwiI"
+ "2lgvZjkpvQV4i5046AW3an5xpObEYKaw74DkiSgPniXW7YPzraaRx5jJQhg1FJ2t"
+ "mEaSLk/K8YdDwRaVVy1Q74ktgHpXrfLuX2vSAI25FPgUFTXZwEaje3LIkb/JVSvN"
+ "0Jc+nCZkzN/Ogxlxyk7m1NV7qRnNVd7I7NJeOFPlXE+MLf5QIzb8ZubLjqQ5GQC3"
+ "lQI5kQsO/jgu0R0FmvZNPm8PBx2vLB6PYDni+jZTEznUXiYr2z2oFL0y6xgDKFIE"
+ "ceWrMz3hOLsHNoRinHnqFjD0X8Ar6HFr5PkCAwEAAaOB8DCB7TAfBgNVHSMEGDAW"
+ "gBRI5mj5K9KylddH2CMgEE8zmJCf1DAdBgNVHQ4EFgQUwHqYaI2J+6sFZAwRfap9"
+ "ZbjKzE4wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwOgYDVR0fBDMw"
+ "MTAvoC2gK4YpaHR0cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9zZWN1cmVjYS5j"
+ "cmwwTgYDVR0gBEcwRTBDBgRVHSAAMDswOQYIKwYBBQUHAgEWLWh0dHBzOi8vd3d3"
+ "Lmdlb3RydXN0LmNvbS9yZXNvdXJjZXMvcmVwb3NpdG9yeTANBgkqhkiG9w0BAQUF"
+ "AAOBgQB24RJuTksWEoYwBrKBCM/wCMfHcX5m7sLt1Dsf//DwyE7WQziwuTB9GNBV"
+ "g6JqyzYRnOhIZqNtf7gT1Ef+i1pcc/yu2RsyGTirlzQUqpbS66McFAhJtrvlke+D"
+ "NusdVm/K2rxzY5Dkf3s+Iss9B+1fOHSc4wNQTqGvmO5h8oQ/Eg==";
+
+// kBadSessionExtraField is a custom serialized SSL_SESSION generated by replacing
+// the final (optional) element of |kCustomSession| with tag number 30.
+static const char kBadSessionExtraField[] =
+ "MIIBdgIBAQICAwMEAsAvBCAG5Q1ndq4Yfmbeo1zwLkNRKmCXGdNgWvGT3cskV0yQ"
+ "kAQwJlrlzkAWBOWiLj/jJ76D7l+UXoizP2KI2C7I2FccqMmIfFmmkUy32nIJ0mZH"
+ "IWoJoQYCBFRDO46iBAICASykAwQBAqUDAgEUphAEDnd3dy5nb29nbGUuY29tqAcE"
+ "BXdvcmxkqQUCAwGJwKqBpwSBpBwUQvoeOk0Kg36SYTcLEkXqKwOBfF9vE4KX0Nxe"
+ "LwjcDTpsuh3qXEaZ992r1N38VDcyS6P7I6HBYN9BsNHM362zZnY27GpTw+Kwd751"
+ "CLoXFPoaMOe57dbBpXoro6Pd3BTbf/Tzr88K06yEOTDKPNj3+inbMaVigtK4PLyP"
+ "q+Topyzvx9USFgRvyuoxn0Hgb+R0A3j6SLRuyOdAi4gv7Y5oliynrSIEIAYGBgYG"
+ "BgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGrgMEAQevAwQBBL4DBAEF";
+
+// kBadSessionVersion is a custom serialized SSL_SESSION generated by replacing
+// the version of |kCustomSession| with 2.
+static const char kBadSessionVersion[] =
+ "MIIBdgIBAgICAwMEAsAvBCAG5Q1ndq4Yfmbeo1zwLkNRKmCXGdNgWvGT3cskV0yQ"
+ "kAQwJlrlzkAWBOWiLj/jJ76D7l+UXoizP2KI2C7I2FccqMmIfFmmkUy32nIJ0mZH"
+ "IWoJoQYCBFRDO46iBAICASykAwQBAqUDAgEUphAEDnd3dy5nb29nbGUuY29tqAcE"
+ "BXdvcmxkqQUCAwGJwKqBpwSBpBwUQvoeOk0Kg36SYTcLEkXqKwOBfF9vE4KX0Nxe"
+ "LwjcDTpsuh3qXEaZ992r1N38VDcyS6P7I6HBYN9BsNHM362zZnY27GpTw+Kwd751"
+ "CLoXFPoaMOe57dbBpXoro6Pd3BTbf/Tzr88K06yEOTDKPNj3+inbMaVigtK4PLyP"
+ "q+Topyzvx9USFgRvyuoxn0Hgb+R0A3j6SLRuyOdAi4gv7Y5oliynrSIEIAYGBgYG"
+ "BgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGrgMEAQevAwQBBLADBAEF";
+
+// kBadSessionTrailingData is a custom serialized SSL_SESSION with trailing data
+// appended.
+static const char kBadSessionTrailingData[] =
+ "MIIBdgIBAQICAwMEAsAvBCAG5Q1ndq4Yfmbeo1zwLkNRKmCXGdNgWvGT3cskV0yQ"
+ "kAQwJlrlzkAWBOWiLj/jJ76D7l+UXoizP2KI2C7I2FccqMmIfFmmkUy32nIJ0mZH"
+ "IWoJoQYCBFRDO46iBAICASykAwQBAqUDAgEUphAEDnd3dy5nb29nbGUuY29tqAcE"
+ "BXdvcmxkqQUCAwGJwKqBpwSBpBwUQvoeOk0Kg36SYTcLEkXqKwOBfF9vE4KX0Nxe"
+ "LwjcDTpsuh3qXEaZ992r1N38VDcyS6P7I6HBYN9BsNHM362zZnY27GpTw+Kwd751"
+ "CLoXFPoaMOe57dbBpXoro6Pd3BTbf/Tzr88K06yEOTDKPNj3+inbMaVigtK4PLyP"
+ "q+Topyzvx9USFgRvyuoxn0Hgb+R0A3j6SLRuyOdAi4gv7Y5oliynrSIEIAYGBgYG"
+ "BgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGrgMEAQevAwQBBLADBAEFAAAA";
+
+static bool DecodeBase64(std::vector<uint8_t> *out, const char *in) {
+ size_t len;
+ if (!EVP_DecodedLength(&len, strlen(in))) {
+ fprintf(stderr, "EVP_DecodedLength failed\n");
+ return false;
+ }
+
+ out->resize(len);
+ if (!EVP_DecodeBase64(out->data(), &len, len, (const uint8_t *)in,
+ strlen(in))) {
+ fprintf(stderr, "EVP_DecodeBase64 failed\n");
+ return false;
+ }
+ out->resize(len);
+ return true;
+}
+
+static bool TestSSL_SESSIONEncoding(const char *input_b64) {
+ const uint8_t *cptr;
+ uint8_t *ptr;
+
+ // Decode the input.
+ std::vector<uint8_t> input;
+ if (!DecodeBase64(&input, input_b64)) {
+ return false;
+ }
+
+ // Verify the SSL_SESSION decodes.
+ bssl::UniquePtr<SSL_CTX> ssl_ctx(SSL_CTX_new(TLS_method()));
+ if (!ssl_ctx) {
+ return false;
+ }
+ bssl::UniquePtr<SSL_SESSION> session(
+ SSL_SESSION_from_bytes(input.data(), input.size(), ssl_ctx.get()));
+ if (!session) {
+ fprintf(stderr, "SSL_SESSION_from_bytes failed\n");
+ return false;
+ }
+
+ // Verify the SSL_SESSION encoding round-trips.
+ size_t encoded_len;
+ bssl::UniquePtr<uint8_t> encoded;
+ uint8_t *encoded_raw;
+ if (!SSL_SESSION_to_bytes(session.get(), &encoded_raw, &encoded_len)) {
+ fprintf(stderr, "SSL_SESSION_to_bytes failed\n");
+ return false;
+ }
+ encoded.reset(encoded_raw);
+ if (encoded_len != input.size() ||
+ OPENSSL_memcmp(input.data(), encoded.get(), input.size()) != 0) {
+ fprintf(stderr, "SSL_SESSION_to_bytes did not round-trip\n");
+ hexdump(stderr, "Before: ", input.data(), input.size());
+ hexdump(stderr, "After: ", encoded_raw, encoded_len);
+ return false;
+ }
+
+ // Verify the SSL_SESSION also decodes with the legacy API.
+ cptr = input.data();
+ session.reset(d2i_SSL_SESSION(NULL, &cptr, input.size()));
+ if (!session || cptr != input.data() + input.size()) {
+ fprintf(stderr, "d2i_SSL_SESSION failed\n");
+ return false;
+ }
+
+ // Verify the SSL_SESSION encoding round-trips via the legacy API.
+ int len = i2d_SSL_SESSION(session.get(), NULL);
+ if (len < 0 || (size_t)len != input.size()) {
+ fprintf(stderr, "i2d_SSL_SESSION(NULL) returned invalid length\n");
+ return false;
+ }
+
+ encoded.reset((uint8_t *)OPENSSL_malloc(input.size()));
+ if (!encoded) {
+ fprintf(stderr, "malloc failed\n");
+ return false;
+ }
+
+ ptr = encoded.get();
+ len = i2d_SSL_SESSION(session.get(), &ptr);
+ if (len < 0 || (size_t)len != input.size()) {
+ fprintf(stderr, "i2d_SSL_SESSION returned invalid length\n");
+ return false;
+ }
+ if (ptr != encoded.get() + input.size()) {
+ fprintf(stderr, "i2d_SSL_SESSION did not advance ptr correctly\n");
+ return false;
+ }
+ if (OPENSSL_memcmp(input.data(), encoded.get(), input.size()) != 0) {
+ fprintf(stderr, "i2d_SSL_SESSION did not round-trip\n");
+ return false;
+ }
+
+ return true;
+}
+
+static bool TestBadSSL_SESSIONEncoding(const char *input_b64) {
+ std::vector<uint8_t> input;
+ if (!DecodeBase64(&input, input_b64)) {
+ return false;
+ }
+
+ // Verify that the SSL_SESSION fails to decode.
+ bssl::UniquePtr<SSL_CTX> ssl_ctx(SSL_CTX_new(TLS_method()));
+ if (!ssl_ctx) {
+ return false;
+ }
+ bssl::UniquePtr<SSL_SESSION> session(
+ SSL_SESSION_from_bytes(input.data(), input.size(), ssl_ctx.get()));
+ if (session) {
+ fprintf(stderr, "SSL_SESSION_from_bytes unexpectedly succeeded\n");
+ return false;
+ }
+ ERR_clear_error();
+ return true;
+}
+
+static bool TestDefaultVersion(uint16_t min_version, uint16_t max_version,
+ const SSL_METHOD *(*method)(void)) {
+ bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(method()));
+ if (!ctx) {
+ return false;
+ }
+ if (ctx->min_version != min_version || ctx->max_version != max_version) {
+ fprintf(stderr, "Got min %04x, max %04x; wanted min %04x, max %04x\n",
+ ctx->min_version, ctx->max_version, min_version, max_version);
+ return false;
+ }
+ return true;
+}
+
+static bool CipherGetRFCName(std::string *out, uint16_t value) {
+ const SSL_CIPHER *cipher = SSL_get_cipher_by_value(value);
+ if (cipher == NULL) {
+ return false;
+ }
+ bssl::UniquePtr<char> rfc_name(SSL_CIPHER_get_rfc_name(cipher));
+ if (!rfc_name) {
+ return false;
+ }
+ out->assign(rfc_name.get());
+ return true;
+}
+
+typedef struct {
+ int id;
+ const char *rfc_name;
+} CIPHER_RFC_NAME_TEST;
+
+static const CIPHER_RFC_NAME_TEST kCipherRFCNameTests[] = {
+ {SSL3_CK_RSA_DES_192_CBC3_SHA, "TLS_RSA_WITH_3DES_EDE_CBC_SHA"},
+ {TLS1_CK_RSA_WITH_AES_128_SHA, "TLS_RSA_WITH_AES_128_CBC_SHA"},
+ {TLS1_CK_DHE_RSA_WITH_AES_256_SHA, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA"},
+ {TLS1_CK_DHE_RSA_WITH_AES_256_SHA256,
+ "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256"},
+ {TLS1_CK_ECDHE_RSA_WITH_AES_128_SHA256,
+ "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256"},
+ {TLS1_CK_ECDHE_RSA_WITH_AES_256_SHA384,
+ "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384"},
+ {TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"},
+ {TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"},
+ {TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"},
+ {TLS1_CK_ECDHE_PSK_WITH_AES_128_CBC_SHA,
+ "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA"},
+ {TLS1_CK_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
+ "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256"},
+ {TLS1_CK_AES_256_GCM_SHA384, "TLS_AES_256_GCM_SHA384"},
+ {TLS1_CK_AES_128_GCM_SHA256, "TLS_AES_128_GCM_SHA256"},
+ {TLS1_CK_CHACHA20_POLY1305_SHA256, "TLS_CHACHA20_POLY1305_SHA256"},
+};
+
+static bool TestCipherGetRFCName(void) {
+ for (size_t i = 0;
+ i < OPENSSL_ARRAY_SIZE(kCipherRFCNameTests); i++) {
+ const CIPHER_RFC_NAME_TEST *test = &kCipherRFCNameTests[i];
+ std::string rfc_name;
+ if (!CipherGetRFCName(&rfc_name, test->id & 0xffff)) {
+ fprintf(stderr, "SSL_CIPHER_get_rfc_name failed\n");
+ return false;
+ }
+ if (rfc_name != test->rfc_name) {
+ fprintf(stderr, "SSL_CIPHER_get_rfc_name: got '%s', wanted '%s'\n",
+ rfc_name.c_str(), test->rfc_name);
+ return false;
+ }
+ }
+ return true;
+}
+
+// CreateSessionWithTicket returns a sample |SSL_SESSION| with the specified
+// version and ticket length or nullptr on failure.
+static bssl::UniquePtr<SSL_SESSION> CreateSessionWithTicket(uint16_t version,
+ size_t ticket_len) {
+ std::vector<uint8_t> der;
+ if (!DecodeBase64(&der, kOpenSSLSession)) {
+ return nullptr;
+ }
+
+ bssl::UniquePtr<SSL_CTX> ssl_ctx(SSL_CTX_new(TLS_method()));
+ if (!ssl_ctx) {
+ return nullptr;
+ }
+ bssl::UniquePtr<SSL_SESSION> session(
+ SSL_SESSION_from_bytes(der.data(), der.size(), ssl_ctx.get()));
+ if (!session) {
+ return nullptr;
+ }
+
+ session->ssl_version = version;
+
+ // Swap out the ticket for a garbage one.
+ OPENSSL_free(session->tlsext_tick);
+ session->tlsext_tick = reinterpret_cast<uint8_t*>(OPENSSL_malloc(ticket_len));
+ if (session->tlsext_tick == nullptr) {
+ return nullptr;
+ }
+ OPENSSL_memset(session->tlsext_tick, 'a', ticket_len);
+ session->tlsext_ticklen = ticket_len;
+
+ // Fix up the timeout.
+#if defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE)
+ session->time = 1234;
+#else
+ session->time = time(NULL);
+#endif
+ return session;
+}
+
+static bool GetClientHello(SSL *ssl, std::vector<uint8_t> *out) {
+ bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_mem()));
+ if (!bio) {
+ return false;
+ }
+ // Do not configure a reading BIO, but record what's written to a memory BIO.
+ BIO_up_ref(bio.get());
+ SSL_set_bio(ssl, nullptr /* rbio */, bio.get());
+ int ret = SSL_connect(ssl);
+ if (ret > 0) {
+ // SSL_connect should fail without a BIO to write to.
+ return false;
+ }
+ ERR_clear_error();
+
+ const uint8_t *client_hello;
+ size_t client_hello_len;
+ if (!BIO_mem_contents(bio.get(), &client_hello, &client_hello_len)) {
+ return false;
+ }
+ *out = std::vector<uint8_t>(client_hello, client_hello + client_hello_len);
+ return true;
+}
+
+// GetClientHelloLen creates a client SSL connection with the specified version
+// and ticket length. It returns the length of the ClientHello, not including
+// the record header, on success and zero on error.
+static size_t GetClientHelloLen(uint16_t max_version, uint16_t session_version,
+ size_t ticket_len) {
+ bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
+ bssl::UniquePtr<SSL_SESSION> session =
+ CreateSessionWithTicket(session_version, ticket_len);
+ if (!ctx || !session) {
+ return 0;
+ }
+
+ // Set a one-element cipher list so the baseline ClientHello is unpadded.
+ bssl::UniquePtr<SSL> ssl(SSL_new(ctx.get()));
+ if (!ssl || !SSL_set_session(ssl.get(), session.get()) ||
+ !SSL_set_strict_cipher_list(ssl.get(), "ECDHE-RSA-AES128-GCM-SHA256") ||
+ !SSL_set_max_proto_version(ssl.get(), max_version)) {
+ return 0;
+ }
+
+ std::vector<uint8_t> client_hello;
+ if (!GetClientHello(ssl.get(), &client_hello) ||
+ client_hello.size() <= SSL3_RT_HEADER_LENGTH) {
+ return 0;
+ }
+
+ return client_hello.size() - SSL3_RT_HEADER_LENGTH;
+}
+
+struct PaddingTest {
+ size_t input_len, padded_len;
+};
+
+static const PaddingTest kPaddingTests[] = {
+ // ClientHellos of length below 0x100 do not require padding.
+ {0xfe, 0xfe},
+ {0xff, 0xff},
+ // ClientHellos of length 0x100 through 0x1fb are padded up to 0x200.
+ {0x100, 0x200},
+ {0x123, 0x200},
+ {0x1fb, 0x200},
+ // ClientHellos of length 0x1fc through 0x1ff get padded beyond 0x200. The
+ // padding extension takes a minimum of four bytes plus one required content
+ // byte. (To work around yet more server bugs, we avoid empty final
+ // extensions.)
+ {0x1fc, 0x201},
+ {0x1fd, 0x202},
+ {0x1fe, 0x203},
+ {0x1ff, 0x204},
+ // Finally, larger ClientHellos need no padding.
+ {0x200, 0x200},
+ {0x201, 0x201},
+};
+
+static bool TestPaddingExtension(uint16_t max_version,
+ uint16_t session_version) {
+ // Sample a baseline length.
+ size_t base_len = GetClientHelloLen(max_version, session_version, 1);
+ if (base_len == 0) {
+ return false;
+ }
+
+ for (const PaddingTest &test : kPaddingTests) {
+ if (base_len > test.input_len) {
+ fprintf(stderr,
+ "Baseline ClientHello too long (max_version = %04x, "
+ "session_version = %04x).\n",
+ max_version, session_version);
+ return false;
+ }
+
+ size_t padded_len = GetClientHelloLen(max_version, session_version,
+ 1 + test.input_len - base_len);
+ if (padded_len != test.padded_len) {
+ fprintf(stderr,
+ "%u-byte ClientHello padded to %u bytes, not %u (max_version = "
+ "%04x, session_version = %04x).\n",
+ static_cast<unsigned>(test.input_len),
+ static_cast<unsigned>(padded_len),
+ static_cast<unsigned>(test.padded_len), max_version,
+ session_version);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// Test that |SSL_get_client_CA_list| echoes back the configured parameter even
+// before configuring as a server.
+TEST(SSLTest, ClientCAList) {
+ bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
+ ASSERT_TRUE(ctx);
+ bssl::UniquePtr<SSL> ssl(SSL_new(ctx.get()));
+ ASSERT_TRUE(ssl);
+
+ bssl::UniquePtr<X509_NAME> name(X509_NAME_new());
+ ASSERT_TRUE(name);
+
+ bssl::UniquePtr<X509_NAME> name_dup(X509_NAME_dup(name.get()));
+ ASSERT_TRUE(name_dup);
+
+ bssl::UniquePtr<STACK_OF(X509_NAME)> stack(sk_X509_NAME_new_null());
+ ASSERT_TRUE(stack);
+
+ ASSERT_TRUE(sk_X509_NAME_push(stack.get(), name_dup.get()));
+ name_dup.release();
+
+ // |SSL_set_client_CA_list| takes ownership.
+ SSL_set_client_CA_list(ssl.get(), stack.release());
+
+ STACK_OF(X509_NAME) *result = SSL_get_client_CA_list(ssl.get());
+ ASSERT_TRUE(result);
+ ASSERT_EQ(1u, sk_X509_NAME_num(result));
+ EXPECT_EQ(0, X509_NAME_cmp(sk_X509_NAME_value(result, 0), name.get()));
+}
+
+static void AppendSession(SSL_SESSION *session, void *arg) {
+ std::vector<SSL_SESSION*> *out =
+ reinterpret_cast<std::vector<SSL_SESSION*>*>(arg);
+ out->push_back(session);
+}
+
+// ExpectCache returns true if |ctx|'s session cache consists of |expected|, in
+// order.
+static bool ExpectCache(SSL_CTX *ctx,
+ const std::vector<SSL_SESSION*> &expected) {
+ // Check the linked list.
+ SSL_SESSION *ptr = ctx->session_cache_head;
+ for (SSL_SESSION *session : expected) {
+ if (ptr != session) {
+ return false;
+ }
+ // TODO(davidben): This is an absurd way to denote the end of the list.
+ if (ptr->next ==
+ reinterpret_cast<SSL_SESSION *>(&ctx->session_cache_tail)) {
+ ptr = nullptr;
+ } else {
+ ptr = ptr->next;
+ }
+ }
+ if (ptr != nullptr) {
+ return false;
+ }
+
+ // Check the hash table.
+ std::vector<SSL_SESSION*> actual, expected_copy;
+ lh_SSL_SESSION_doall_arg(SSL_CTX_sessions(ctx), AppendSession, &actual);
+ expected_copy = expected;
+
+ std::sort(actual.begin(), actual.end());
+ std::sort(expected_copy.begin(), expected_copy.end());
+
+ return actual == expected_copy;
+}
+
+static bssl::UniquePtr<SSL_SESSION> CreateTestSession(uint32_t number) {
+ bssl::UniquePtr<SSL_CTX> ssl_ctx(SSL_CTX_new(TLS_method()));
+ if (!ssl_ctx) {
+ return nullptr;
+ }
+ bssl::UniquePtr<SSL_SESSION> ret(SSL_SESSION_new(ssl_ctx.get()));
+ if (!ret) {
+ return nullptr;
+ }
+
+ ret->session_id_length = SSL3_SSL_SESSION_ID_LENGTH;
+ OPENSSL_memset(ret->session_id, 0, ret->session_id_length);
+ OPENSSL_memcpy(ret->session_id, &number, sizeof(number));
+ return ret;
+}
+
+// Test that the internal session cache behaves as expected.
+static bool TestInternalSessionCache() {
+ bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
+ if (!ctx) {
+ return false;
+ }
+
+ // Prepare 10 test sessions.
+ std::vector<bssl::UniquePtr<SSL_SESSION>> sessions;
+ for (int i = 0; i < 10; i++) {
+ bssl::UniquePtr<SSL_SESSION> session = CreateTestSession(i);
+ if (!session) {
+ return false;
+ }
+ sessions.push_back(std::move(session));
+ }
+
+ SSL_CTX_sess_set_cache_size(ctx.get(), 5);
+
+ // Insert all the test sessions.
+ for (const auto &session : sessions) {
+ if (!SSL_CTX_add_session(ctx.get(), session.get())) {
+ return false;
+ }
+ }
+
+ // Only the last five should be in the list.
+ std::vector<SSL_SESSION*> expected = {
+ sessions[9].get(),
+ sessions[8].get(),
+ sessions[7].get(),
+ sessions[6].get(),
+ sessions[5].get(),
+ };
+ if (!ExpectCache(ctx.get(), expected)) {
+ return false;
+ }
+
+ // Inserting an element already in the cache should fail.
+ if (SSL_CTX_add_session(ctx.get(), sessions[7].get()) ||
+ !ExpectCache(ctx.get(), expected)) {
+ return false;
+ }
+
+ // Although collisions should be impossible (256-bit session IDs), the cache
+ // must handle them gracefully.
+ bssl::UniquePtr<SSL_SESSION> collision(CreateTestSession(7));
+ if (!collision || !SSL_CTX_add_session(ctx.get(), collision.get())) {
+ return false;
+ }
+ expected = {
+ collision.get(),
+ sessions[9].get(),
+ sessions[8].get(),
+ sessions[6].get(),
+ sessions[5].get(),
+ };
+ if (!ExpectCache(ctx.get(), expected)) {
+ return false;
+ }
+
+ // Removing sessions behaves correctly.
+ if (!SSL_CTX_remove_session(ctx.get(), sessions[6].get())) {
+ return false;
+ }
+ expected = {
+ collision.get(),
+ sessions[9].get(),
+ sessions[8].get(),
+ sessions[5].get(),
+ };
+ if (!ExpectCache(ctx.get(), expected)) {
+ return false;
+ }
+
+ // Removing sessions requires an exact match.
+ if (SSL_CTX_remove_session(ctx.get(), sessions[0].get()) ||
+ SSL_CTX_remove_session(ctx.get(), sessions[7].get()) ||
+ !ExpectCache(ctx.get(), expected)) {
+ return false;
+ }
+
+ return true;
+}
+
+static uint16_t EpochFromSequence(uint64_t seq) {
+ return static_cast<uint16_t>(seq >> 48);
+}
+
+static bssl::UniquePtr<X509> GetTestCertificate() {
+ static const char kCertPEM[] =
+ "-----BEGIN CERTIFICATE-----\n"
+ "MIICWDCCAcGgAwIBAgIJAPuwTC6rEJsMMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV\n"
+ "BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX\n"
+ "aWRnaXRzIFB0eSBMdGQwHhcNMTQwNDIzMjA1MDQwWhcNMTcwNDIyMjA1MDQwWjBF\n"
+ "MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50\n"
+ "ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB\n"
+ "gQDYK8imMuRi/03z0K1Zi0WnvfFHvwlYeyK9Na6XJYaUoIDAtB92kWdGMdAQhLci\n"
+ "HnAjkXLI6W15OoV3gA/ElRZ1xUpxTMhjP6PyY5wqT5r6y8FxbiiFKKAnHmUcrgfV\n"
+ "W28tQ+0rkLGMryRtrukXOgXBv7gcrmU7G1jC2a7WqmeI8QIDAQABo1AwTjAdBgNV\n"
+ "HQ4EFgQUi3XVrMsIvg4fZbf6Vr5sp3Xaha8wHwYDVR0jBBgwFoAUi3XVrMsIvg4f\n"
+ "Zbf6Vr5sp3Xaha8wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQA76Hht\n"
+ "ldY9avcTGSwbwoiuIqv0jTL1fHFnzy3RHMLDh+Lpvolc5DSrSJHCP5WuK0eeJXhr\n"
+ "T5oQpHL9z/cCDLAKCKRa4uV0fhEdOWBqyR9p8y5jJtye72t6CuFUV5iqcpF4BH4f\n"
+ "j2VNHwsSrJwkD4QUGlUtH7vwnQmyCFxZMmWAJg==\n"
+ "-----END CERTIFICATE-----\n";
+ bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(kCertPEM, strlen(kCertPEM)));
+ return bssl::UniquePtr<X509>(
+ PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr));
+}
+
+static bssl::UniquePtr<EVP_PKEY> GetTestKey() {
+ static const char kKeyPEM[] =
+ "-----BEGIN RSA PRIVATE KEY-----\n"
+ "MIICXgIBAAKBgQDYK8imMuRi/03z0K1Zi0WnvfFHvwlYeyK9Na6XJYaUoIDAtB92\n"
+ "kWdGMdAQhLciHnAjkXLI6W15OoV3gA/ElRZ1xUpxTMhjP6PyY5wqT5r6y8FxbiiF\n"
+ "KKAnHmUcrgfVW28tQ+0rkLGMryRtrukXOgXBv7gcrmU7G1jC2a7WqmeI8QIDAQAB\n"
+ "AoGBAIBy09Fd4DOq/Ijp8HeKuCMKTHqTW1xGHshLQ6jwVV2vWZIn9aIgmDsvkjCe\n"
+ "i6ssZvnbjVcwzSoByhjN8ZCf/i15HECWDFFh6gt0P5z0MnChwzZmvatV/FXCT0j+\n"
+ "WmGNB/gkehKjGXLLcjTb6dRYVJSCZhVuOLLcbWIV10gggJQBAkEA8S8sGe4ezyyZ\n"
+ "m4e9r95g6s43kPqtj5rewTsUxt+2n4eVodD+ZUlCULWVNAFLkYRTBCASlSrm9Xhj\n"
+ "QpmWAHJUkQJBAOVzQdFUaewLtdOJoPCtpYoY1zd22eae8TQEmpGOR11L6kbxLQsk\n"
+ "aMly/DOnOaa82tqAGTdqDEZgSNmCeKKknmECQAvpnY8GUOVAubGR6c+W90iBuQLj\n"
+ "LtFp/9ihd2w/PoDwrHZaoUYVcT4VSfJQog/k7kjE4MYXYWL8eEKg3WTWQNECQQDk\n"
+ "104Wi91Umd1PzF0ijd2jXOERJU1wEKe6XLkYYNHWQAe5l4J4MWj9OdxFXAxIuuR/\n"
+ "tfDwbqkta4xcux67//khAkEAvvRXLHTaa6VFzTaiiO8SaFsHV3lQyXOtMrBpB5jd\n"
+ "moZWgjHvB2W9Ckn7sDqsPB+U2tyX0joDdQEyuiMECDY8oQ==\n"
+ "-----END RSA PRIVATE KEY-----\n";
+ bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(kKeyPEM, strlen(kKeyPEM)));
+ return bssl::UniquePtr<EVP_PKEY>(
+ PEM_read_bio_PrivateKey(bio.get(), nullptr, nullptr, nullptr));
+}
+
+static bssl::UniquePtr<X509> GetECDSATestCertificate() {
+ static const char kCertPEM[] =
+ "-----BEGIN CERTIFICATE-----\n"
+ "MIIBzzCCAXagAwIBAgIJANlMBNpJfb/rMAkGByqGSM49BAEwRTELMAkGA1UEBhMC\n"
+ "QVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdp\n"
+ "dHMgUHR5IEx0ZDAeFw0xNDA0MjMyMzIxNTdaFw0xNDA1MjMyMzIxNTdaMEUxCzAJ\n"
+ "BgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5l\n"
+ "dCBXaWRnaXRzIFB0eSBMdGQwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATmK2ni\n"
+ "v2Wfl74vHg2UikzVl2u3qR4NRvvdqakendy6WgHn1peoChj5w8SjHlbifINI2xYa\n"
+ "HPUdfvGULUvPciLBo1AwTjAdBgNVHQ4EFgQUq4TSrKuV8IJOFngHVVdf5CaNgtEw\n"
+ "HwYDVR0jBBgwFoAUq4TSrKuV8IJOFngHVVdf5CaNgtEwDAYDVR0TBAUwAwEB/zAJ\n"
+ "BgcqhkjOPQQBA0gAMEUCIQDyoDVeUTo2w4J5m+4nUIWOcAZ0lVfSKXQA9L4Vh13E\n"
+ "BwIgfB55FGohg/B6dGh5XxSZmmi08cueFV7mHzJSYV51yRQ=\n"
+ "-----END CERTIFICATE-----\n";
+ bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(kCertPEM, strlen(kCertPEM)));
+ return bssl::UniquePtr<X509>(PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr));
+}
+
+static bssl::UniquePtr<EVP_PKEY> GetECDSATestKey() {
+ static const char kKeyPEM[] =
+ "-----BEGIN PRIVATE KEY-----\n"
+ "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgBw8IcnrUoEqc3VnJ\n"
+ "TYlodwi1b8ldMHcO6NHJzgqLtGqhRANCAATmK2niv2Wfl74vHg2UikzVl2u3qR4N\n"
+ "Rvvdqakendy6WgHn1peoChj5w8SjHlbifINI2xYaHPUdfvGULUvPciLB\n"
+ "-----END PRIVATE KEY-----\n";
+ bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(kKeyPEM, strlen(kKeyPEM)));
+ return bssl::UniquePtr<EVP_PKEY>(
+ PEM_read_bio_PrivateKey(bio.get(), nullptr, nullptr, nullptr));
+}
+
+static bssl::UniquePtr<CRYPTO_BUFFER> BufferFromPEM(const char *pem) {
+ bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(pem, strlen(pem)));
+ char *name, *header;
+ uint8_t *data;
+ long data_len;
+ if (!PEM_read_bio(bio.get(), &name, &header, &data,
+ &data_len)) {
+ return nullptr;
+ }
+ OPENSSL_free(name);
+ OPENSSL_free(header);
+
+ auto ret = bssl::UniquePtr<CRYPTO_BUFFER>(
+ CRYPTO_BUFFER_new(data, data_len, nullptr));
+ OPENSSL_free(data);
+ return ret;
+}
+
+static bssl::UniquePtr<CRYPTO_BUFFER> GetChainTestCertificateBuffer() {
+ static const char kCertPEM[] =
+ "-----BEGIN CERTIFICATE-----\n"
+ "MIIC0jCCAbqgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwDzENMAsGA1UEAwwEQiBD\n"
+ "QTAeFw0xNjAyMjgyMDI3MDNaFw0yNjAyMjUyMDI3MDNaMBgxFjAUBgNVBAMMDUNs\n"
+ "aWVudCBDZXJ0IEEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDRvaz8\n"
+ "CC/cshpCafJo4jLkHEoBqDLhdgFelJoAiQUyIqyWl2O7YHPnpJH+TgR7oelzNzt/\n"
+ "kLRcH89M/TszB6zqyLTC4aqmvzKL0peD/jL2LWBucR0WXIvjA3zoRuF/x86+rYH3\n"
+ "tHb+xs2PSs8EGL/Ev+ss+qTzTGEn26fuGNHkNw6tOwPpc+o8+wUtzf/kAthamo+c\n"
+ "IDs2rQ+lP7+aLZTLeU/q4gcLutlzcK5imex5xy2jPkweq48kijK0kIzl1cPlA5d1\n"
+ "z7C8jU50Pj9X9sQDJTN32j7UYRisJeeYQF8GaaN8SbrDI6zHgKzrRLyxDt/KQa9V\n"
+ "iLeXANgZi+Xx9KgfAgMBAAGjLzAtMAwGA1UdEwEB/wQCMAAwHQYDVR0lBBYwFAYI\n"
+ "KwYBBQUHAwEGCCsGAQUFBwMCMA0GCSqGSIb3DQEBCwUAA4IBAQBFEVbmYl+2RtNw\n"
+ "rDftRDF1v2QUbcN2ouSnQDHxeDQdSgasLzT3ui8iYu0Rw2WWcZ0DV5e0ztGPhWq7\n"
+ "AO0B120aFRMOY+4+bzu9Q2FFkQqc7/fKTvTDzIJI5wrMnFvUfzzvxh3OHWMYSs/w\n"
+ "giq33hTKeHEq6Jyk3btCny0Ycecyc3yGXH10sizUfiHlhviCkDuESk8mFDwDDzqW\n"
+ "ZF0IipzFbEDHoIxLlm3GQxpiLoEV4k8KYJp3R5KBLFyxM6UGPz8h72mIPCJp2RuK\n"
+ "MYgF91UDvVzvnYm6TfseM2+ewKirC00GOrZ7rEcFvtxnKSqYf4ckqfNdSU1Y+RRC\n"
+ "1ngWZ7Ih\n"
+ "-----END CERTIFICATE-----\n";
+ return BufferFromPEM(kCertPEM);
+}
+
+static bssl::UniquePtr<X509> X509FromBuffer(
+ bssl::UniquePtr<CRYPTO_BUFFER> buffer) {
+ if (!buffer) {
+ return nullptr;
+ }
+ const uint8_t *derp = CRYPTO_BUFFER_data(buffer.get());
+ return bssl::UniquePtr<X509>(
+ d2i_X509(NULL, &derp, CRYPTO_BUFFER_len(buffer.get())));
+}
+
+static bssl::UniquePtr<X509> GetChainTestCertificate() {
+ return X509FromBuffer(GetChainTestCertificateBuffer());
+}
+
+static bssl::UniquePtr<CRYPTO_BUFFER> GetChainTestIntermediateBuffer() {
+ static const char kCertPEM[] =
+ "-----BEGIN CERTIFICATE-----\n"
+ "MIICwjCCAaqgAwIBAgICEAEwDQYJKoZIhvcNAQELBQAwFDESMBAGA1UEAwwJQyBS\n"
+ "b290IENBMB4XDTE2MDIyODIwMjcwM1oXDTI2MDIyNTIwMjcwM1owDzENMAsGA1UE\n"
+ "AwwEQiBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALsSCYmDip2D\n"
+ "GkjFxw7ykz26JSjELkl6ArlYjFJ3aT/SCh8qbS4gln7RH8CPBd78oFdfhIKQrwtZ\n"
+ "3/q21ykD9BAS3qHe2YdcJfm8/kWAy5DvXk6NXU4qX334KofBAEpgdA/igEFq1P1l\n"
+ "HAuIfZCpMRfT+i5WohVsGi8f/NgpRvVaMONLNfgw57mz1lbtFeBEISmX0kbsuJxF\n"
+ "Qj/Bwhi5/0HAEXG8e7zN4cEx0yPRvmOATRdVb/8dW2pwOHRJq9R5M0NUkIsTSnL7\n"
+ "6N/z8hRAHMsV3IudC5Yd7GXW1AGu9a+iKU+Q4xcZCoj0DC99tL4VKujrV1kAeqsM\n"
+ "cz5/dKzi6+cCAwEAAaMjMCEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC\n"
+ "AQYwDQYJKoZIhvcNAQELBQADggEBAIIeZiEeNhWWQ8Y4D+AGDwqUUeG8NjCbKrXQ\n"
+ "BlHg5wZ8xftFaiP1Dp/UAezmx2LNazdmuwrYB8lm3FVTyaPDTKEGIPS4wJKHgqH1\n"
+ "QPDhqNm85ey7TEtI9oYjsNim/Rb+iGkIAMXaxt58SzxbjvP0kMr1JfJIZbic9vye\n"
+ "NwIspMFIpP3FB8ywyu0T0hWtCQgL4J47nigCHpOu58deP88fS/Nyz/fyGVWOZ76b\n"
+ "WhWwgM3P3X95fQ3d7oFPR/bVh0YV+Cf861INwplokXgXQ3/TCQ+HNXeAMWn3JLWv\n"
+ "XFwk8owk9dq/kQGdndGgy3KTEW4ctPX5GNhf3LJ9Q7dLji4ReQ4=\n"
+ "-----END CERTIFICATE-----\n";
+ return BufferFromPEM(kCertPEM);
+}
+
+static bssl::UniquePtr<X509> GetChainTestIntermediate() {
+ return X509FromBuffer(GetChainTestIntermediateBuffer());
+}
+
+static bssl::UniquePtr<EVP_PKEY> GetChainTestKey() {
+ static const char kKeyPEM[] =
+ "-----BEGIN PRIVATE KEY-----\n"
+ "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDRvaz8CC/cshpC\n"
+ "afJo4jLkHEoBqDLhdgFelJoAiQUyIqyWl2O7YHPnpJH+TgR7oelzNzt/kLRcH89M\n"
+ "/TszB6zqyLTC4aqmvzKL0peD/jL2LWBucR0WXIvjA3zoRuF/x86+rYH3tHb+xs2P\n"
+ "Ss8EGL/Ev+ss+qTzTGEn26fuGNHkNw6tOwPpc+o8+wUtzf/kAthamo+cIDs2rQ+l\n"
+ "P7+aLZTLeU/q4gcLutlzcK5imex5xy2jPkweq48kijK0kIzl1cPlA5d1z7C8jU50\n"
+ "Pj9X9sQDJTN32j7UYRisJeeYQF8GaaN8SbrDI6zHgKzrRLyxDt/KQa9ViLeXANgZ\n"
+ "i+Xx9KgfAgMBAAECggEBAK0VjSJzkyPaamcyTVSWjo7GdaBGcK60lk657RjR+lK0\n"
+ "YJ7pkej4oM2hdsVZFsP8Cs4E33nXLa/0pDsRov/qrp0WQm2skwqGMC1I/bZ0WRPk\n"
+ "wHaDrBBfESWnJDX/AGpVtlyOjPmgmK6J2usMPihQUDkKdAYrVWJePrMIxt1q6BMe\n"
+ "iczs3qriMmtY3bUc4UyUwJ5fhDLjshHvfuIpYQyI6EXZM6dZksn9LylXJnigY6QJ\n"
+ "HxOYO0BDwOsZ8yQ8J8afLk88i0GizEkgE1z3REtQUwgWfxr1WV/ud+T6/ZhSAgH9\n"
+ "042mQvSFZnIUSEsmCvjhWuAunfxHKCTcAoYISWfzWpkCgYEA7gpf3HHU5Tn+CgUn\n"
+ "1X5uGpG3DmcMgfeGgs2r2f/IIg/5Ac1dfYILiybL1tN9zbyLCJfcbFpWBc9hJL6f\n"
+ "CPc5hUiwWFJqBJewxQkC1Ae/HakHbip+IZ+Jr0842O4BAArvixk4Lb7/N2Ct9sTE\n"
+ "NJO6RtK9lbEZ5uK61DglHy8CS2UCgYEA4ZC1o36kPAMQBggajgnucb2yuUEelk0f\n"
+ "AEr+GI32MGE+93xMr7rAhBoqLg4AITyIfEnOSQ5HwagnIHonBbv1LV/Gf9ursx8Z\n"
+ "YOGbvT8zzzC+SU1bkDzdjAYnFQVGIjMtKOBJ3K07++ypwX1fr4QsQ8uKL8WSOWwt\n"
+ "Z3Bym6XiZzMCgYADnhy+2OwHX85AkLt+PyGlPbmuelpyTzS4IDAQbBa6jcuW/2wA\n"
+ "UE2km75VUXmD+u2R/9zVuLm99NzhFhSMqlUxdV1YukfqMfP5yp1EY6m/5aW7QuIP\n"
+ "2MDa7TVL9rIFMiVZ09RKvbBbQxjhuzPQKL6X/PPspnhiTefQ+dl2k9xREQKBgHDS\n"
+ "fMfGNEeAEKezrfSVqxphE9/tXms3L+ZpnCaT+yu/uEr5dTIAawKoQ6i9f/sf1/Sy\n"
+ "xedsqR+IB+oKrzIDDWMgoJybN4pkZ8E5lzhVQIjFjKgFdWLzzqyW9z1gYfABQPlN\n"
+ "FiS20WX0vgP1vcKAjdNrHzc9zyHBpgQzDmAj3NZZAoGBAI8vKCKdH7w3aL5CNkZQ\n"
+ "2buIeWNA2HZazVwAGG5F2TU/LmXfRKnG6dX5bkU+AkBZh56jNZy//hfFSewJB4Kk\n"
+ "buB7ERSdaNbO21zXt9FEA3+z0RfMd/Zv2vlIWOSB5nzl/7UKti3sribK6s9ZVLfi\n"
+ "SxpiPQ8d/hmSGwn4ksrWUsJD\n"
+ "-----END PRIVATE KEY-----\n";
+ bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(kKeyPEM, strlen(kKeyPEM)));
+ return bssl::UniquePtr<EVP_PKEY>(
+ PEM_read_bio_PrivateKey(bio.get(), nullptr, nullptr, nullptr));
+}
+
+static bool CompleteHandshakes(SSL *client, SSL *server) {
+ // Drive both their handshakes to completion.
+ for (;;) {
+ int client_ret = SSL_do_handshake(client);
+ int client_err = SSL_get_error(client, client_ret);
+ if (client_err != SSL_ERROR_NONE &&
+ client_err != SSL_ERROR_WANT_READ &&
+ client_err != SSL_ERROR_WANT_WRITE &&
+ client_err != SSL_ERROR_PENDING_TICKET) {
+ fprintf(stderr, "Client error: %d\n", client_err);
+ return false;
+ }
+
+ int server_ret = SSL_do_handshake(server);
+ int server_err = SSL_get_error(server, server_ret);
+ if (server_err != SSL_ERROR_NONE &&
+ server_err != SSL_ERROR_WANT_READ &&
+ server_err != SSL_ERROR_WANT_WRITE &&
+ server_err != SSL_ERROR_PENDING_TICKET) {
+ fprintf(stderr, "Server error: %d\n", server_err);
+ return false;
+ }
+
+ if (client_ret == 1 && server_ret == 1) {
+ break;
+ }
+ }
+
+ return true;
+}
+
+static bool ConnectClientAndServer(bssl::UniquePtr<SSL> *out_client,
+ bssl::UniquePtr<SSL> *out_server,
+ SSL_CTX *client_ctx, SSL_CTX *server_ctx,
+ SSL_SESSION *session) {
+ bssl::UniquePtr<SSL> client(SSL_new(client_ctx)), server(SSL_new(server_ctx));
+ if (!client || !server) {
+ return false;
+ }
+ SSL_set_connect_state(client.get());
+ SSL_set_accept_state(server.get());
+
+ SSL_set_session(client.get(), session);
+
+ BIO *bio1, *bio2;
+ if (!BIO_new_bio_pair(&bio1, 0, &bio2, 0)) {
+ return false;
+ }
+ // SSL_set_bio takes ownership.
+ SSL_set_bio(client.get(), bio1, bio1);
+ SSL_set_bio(server.get(), bio2, bio2);
+
+ if (!CompleteHandshakes(client.get(), server.get())) {
+ return false;
+ }
+
+ *out_client = std::move(client);
+ *out_server = std::move(server);
+ return true;
+}
+
+static bool TestSequenceNumber(bool is_dtls, const SSL_METHOD *method,
+ uint16_t version) {
+ bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(method));
+ bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(method));
+ if (!server_ctx || !client_ctx ||
+ !SSL_CTX_set_min_proto_version(client_ctx.get(), version) ||
+ !SSL_CTX_set_max_proto_version(client_ctx.get(), version) ||
+ !SSL_CTX_set_min_proto_version(server_ctx.get(), version) ||
+ !SSL_CTX_set_max_proto_version(server_ctx.get(), version)) {
+ return false;
+ }
+
+ bssl::UniquePtr<X509> cert = GetTestCertificate();
+ bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
+ if (!cert || !key || !SSL_CTX_use_certificate(server_ctx.get(), cert.get()) ||
+ !SSL_CTX_use_PrivateKey(server_ctx.get(), key.get())) {
+ return false;
+ }
+
+ bssl::UniquePtr<SSL> client, server;
+ if (!ConnectClientAndServer(&client, &server, client_ctx.get(),
+ server_ctx.get(), nullptr /* no session */)) {
+ return false;
+ }
+
+ // Drain any post-handshake messages to ensure there are no unread records
+ // on either end.
+ uint8_t byte = 0;
+ if (SSL_read(client.get(), &byte, 1) > 0 ||
+ SSL_read(server.get(), &byte, 1) > 0) {
+ fprintf(stderr, "Received unexpected data.\n");
+ return false;
+ }
+
+ uint64_t client_read_seq = SSL_get_read_sequence(client.get());
+ uint64_t client_write_seq = SSL_get_write_sequence(client.get());
+ uint64_t server_read_seq = SSL_get_read_sequence(server.get());
+ uint64_t server_write_seq = SSL_get_write_sequence(server.get());
+
+ if (is_dtls) {
+ // Both client and server must be at epoch 1.
+ if (EpochFromSequence(client_read_seq) != 1 ||
+ EpochFromSequence(client_write_seq) != 1 ||
+ EpochFromSequence(server_read_seq) != 1 ||
+ EpochFromSequence(server_write_seq) != 1) {
+ fprintf(stderr, "Bad epochs.\n");
+ return false;
+ }
+
+ // The next record to be written should exceed the largest received.
+ if (client_write_seq <= server_read_seq ||
+ server_write_seq <= client_read_seq) {
+ fprintf(stderr, "Inconsistent sequence numbers.\n");
+ return false;
+ }
+ } else {
+ // The next record to be written should equal the next to be received.
+ if (client_write_seq != server_read_seq ||
+ server_write_seq != client_read_seq) {
+ fprintf(stderr, "Inconsistent sequence numbers.\n");
+ return false;
+ }
+ }
+
+ // Send a record from client to server.
+ if (SSL_write(client.get(), &byte, 1) != 1 ||
+ SSL_read(server.get(), &byte, 1) != 1) {
+ fprintf(stderr, "Could not send byte.\n");
+ return false;
+ }
+
+ // The client write and server read sequence numbers should have
+ // incremented.
+ if (client_write_seq + 1 != SSL_get_write_sequence(client.get()) ||
+ server_read_seq + 1 != SSL_get_read_sequence(server.get())) {
+ fprintf(stderr, "Sequence numbers did not increment.\n");
+ return false;
+ }
+
+ return true;
+}
+
+static bool TestOneSidedShutdown(bool is_dtls, const SSL_METHOD *method,
+ uint16_t version) {
+ // SSL_shutdown is a no-op in DTLS.
+ if (is_dtls) {
+ return true;
+ }
+
+ bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(method));
+ bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(method));
+ bssl::UniquePtr<X509> cert = GetTestCertificate();
+ bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
+ if (!client_ctx || !server_ctx || !cert || !key ||
+ !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) ||
+ !SSL_CTX_use_certificate(server_ctx.get(), cert.get()) ||
+ !SSL_CTX_use_PrivateKey(server_ctx.get(), key.get())) {
+ return false;
+ }
+
+ bssl::UniquePtr<SSL> client, server;
+ if (!ConnectClientAndServer(&client, &server, client_ctx.get(),
+ server_ctx.get(), nullptr /* no session */)) {
+ return false;
+ }
+
+ // Shut down half the connection. SSL_shutdown will return 0 to signal only
+ // one side has shut down.
+ if (SSL_shutdown(client.get()) != 0) {
+ fprintf(stderr, "Could not shutdown.\n");
+ return false;
+ }
+
+ // Reading from the server should consume the EOF.
+ uint8_t byte;
+ if (SSL_read(server.get(), &byte, 1) != 0 ||
+ SSL_get_error(server.get(), 0) != SSL_ERROR_ZERO_RETURN) {
+ fprintf(stderr, "Connection was not shut down cleanly.\n");
+ return false;
+ }
+
+ // However, the server may continue to write data and then shut down the
+ // connection.
+ byte = 42;
+ if (SSL_write(server.get(), &byte, 1) != 1 ||
+ SSL_read(client.get(), &byte, 1) != 1 ||
+ byte != 42) {
+ fprintf(stderr, "Could not send byte.\n");
+ return false;
+ }
+
+ // The server may then shutdown the connection.
+ if (SSL_shutdown(server.get()) != 1 ||
+ SSL_shutdown(client.get()) != 1) {
+ fprintf(stderr, "Could not complete shutdown.\n");
+ return false;
+ }
+
+ return true;
+}
+
+TEST(SSLTest, SessionDuplication) {
+ bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
+ bssl::UniquePtr<SSL_CTX> 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 */));
+
+ SSL_SESSION *session0 = SSL_get_session(client.get());
+ bssl::UniquePtr<SSL_SESSION> session1(
+ SSL_SESSION_dup(session0, SSL_SESSION_DUP_ALL));
+ ASSERT_TRUE(session1);
+
+ session1->not_resumable = 0;
+
+ uint8_t *s0_bytes, *s1_bytes;
+ size_t s0_len, s1_len;
+
+ ASSERT_TRUE(SSL_SESSION_to_bytes(session0, &s0_bytes, &s0_len));
+ bssl::UniquePtr<uint8_t> free_s0(s0_bytes);
+
+ ASSERT_TRUE(SSL_SESSION_to_bytes(session1.get(), &s1_bytes, &s1_len));
+ bssl::UniquePtr<uint8_t> free_s1(s1_bytes);
+
+ EXPECT_EQ(Bytes(s0_bytes, s0_len), Bytes(s1_bytes, s1_len));
+}
+
+static void ExpectFDs(const SSL *ssl, int rfd, int wfd) {
+ EXPECT_EQ(rfd, SSL_get_rfd(ssl));
+ EXPECT_EQ(wfd, SSL_get_wfd(ssl));
+
+ // The wrapper BIOs are always equal when fds are equal, even if set
+ // individually.
+ if (rfd == wfd) {
+ EXPECT_EQ(SSL_get_rbio(ssl), SSL_get_wbio(ssl));
+ }
+}
+
+TEST(SSLTest, SetFD) {
+ bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
+ ASSERT_TRUE(ctx);
+
+ // Test setting different read and write FDs.
+ bssl::UniquePtr<SSL> ssl(SSL_new(ctx.get()));
+ ASSERT_TRUE(ssl);
+ EXPECT_TRUE(SSL_set_rfd(ssl.get(), 1));
+ EXPECT_TRUE(SSL_set_wfd(ssl.get(), 2));
+ ExpectFDs(ssl.get(), 1, 2);
+
+ // Test setting the same FD.
+ ssl.reset(SSL_new(ctx.get()));
+ ASSERT_TRUE(ssl);
+ EXPECT_TRUE(SSL_set_fd(ssl.get(), 1));
+ ExpectFDs(ssl.get(), 1, 1);
+
+ // Test setting the same FD one side at a time.
+ ssl.reset(SSL_new(ctx.get()));
+ ASSERT_TRUE(ssl);
+ EXPECT_TRUE(SSL_set_rfd(ssl.get(), 1));
+ EXPECT_TRUE(SSL_set_wfd(ssl.get(), 1));
+ ExpectFDs(ssl.get(), 1, 1);
+
+ // Test setting the same FD in the other order.
+ ssl.reset(SSL_new(ctx.get()));
+ ASSERT_TRUE(ssl);
+ EXPECT_TRUE(SSL_set_wfd(ssl.get(), 1));
+ EXPECT_TRUE(SSL_set_rfd(ssl.get(), 1));
+ ExpectFDs(ssl.get(), 1, 1);
+
+ // Test changing the read FD partway through.
+ ssl.reset(SSL_new(ctx.get()));
+ ASSERT_TRUE(ssl);
+ EXPECT_TRUE(SSL_set_fd(ssl.get(), 1));
+ EXPECT_TRUE(SSL_set_rfd(ssl.get(), 2));
+ ExpectFDs(ssl.get(), 2, 1);
+
+ // Test changing the write FD partway through.
+ ssl.reset(SSL_new(ctx.get()));
+ ASSERT_TRUE(ssl);
+ EXPECT_TRUE(SSL_set_fd(ssl.get(), 1));
+ EXPECT_TRUE(SSL_set_wfd(ssl.get(), 2));
+ ExpectFDs(ssl.get(), 1, 2);
+
+ // Test a no-op change to the read FD partway through.
+ ssl.reset(SSL_new(ctx.get()));
+ ASSERT_TRUE(ssl);
+ EXPECT_TRUE(SSL_set_fd(ssl.get(), 1));
+ EXPECT_TRUE(SSL_set_rfd(ssl.get(), 1));
+ ExpectFDs(ssl.get(), 1, 1);
+
+ // Test a no-op change to the write FD partway through.
+ ssl.reset(SSL_new(ctx.get()));
+ ASSERT_TRUE(ssl);
+ EXPECT_TRUE(SSL_set_fd(ssl.get(), 1));
+ EXPECT_TRUE(SSL_set_wfd(ssl.get(), 1));
+ ExpectFDs(ssl.get(), 1, 1);
+
+ // ASan builds will implicitly test that the internal |BIO| reference-counting
+ // is correct.
+}
+
+TEST(SSLTest, SetBIO) {
+ bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
+ ASSERT_TRUE(ctx);
+
+ bssl::UniquePtr<SSL> ssl(SSL_new(ctx.get()));
+ bssl::UniquePtr<BIO> bio1(BIO_new(BIO_s_mem())), bio2(BIO_new(BIO_s_mem())),
+ bio3(BIO_new(BIO_s_mem()));
+ ASSERT_TRUE(ssl);
+ ASSERT_TRUE(bio1);
+ ASSERT_TRUE(bio2);
+ ASSERT_TRUE(bio3);
+
+ // SSL_set_bio takes one reference when the parameters are the same.
+ BIO_up_ref(bio1.get());
+ SSL_set_bio(ssl.get(), bio1.get(), bio1.get());
+
+ // Repeating the call does nothing.
+ SSL_set_bio(ssl.get(), bio1.get(), bio1.get());
+
+ // It takes one reference each when the parameters are different.
+ BIO_up_ref(bio2.get());
+ BIO_up_ref(bio3.get());
+ SSL_set_bio(ssl.get(), bio2.get(), bio3.get());
+
+ // Repeating the call does nothing.
+ SSL_set_bio(ssl.get(), bio2.get(), bio3.get());
+
+ // It takes one reference when changing only wbio.
+ BIO_up_ref(bio1.get());
+ SSL_set_bio(ssl.get(), bio2.get(), bio1.get());
+
+ // It takes one reference when changing only rbio and the two are different.
+ BIO_up_ref(bio3.get());
+ SSL_set_bio(ssl.get(), bio3.get(), bio1.get());
+
+ // If setting wbio to rbio, it takes no additional references.
+ SSL_set_bio(ssl.get(), bio3.get(), bio3.get());
+
+ // From there, wbio may be switched to something else.
+ BIO_up_ref(bio1.get());
+ SSL_set_bio(ssl.get(), bio3.get(), bio1.get());
+
+ // If setting rbio to wbio, it takes no additional references.
+ SSL_set_bio(ssl.get(), bio1.get(), bio1.get());
+
+ // From there, rbio may be switched to something else, but, for historical
+ // reasons, it takes a reference to both parameters.
+ BIO_up_ref(bio1.get());
+ BIO_up_ref(bio2.get());
+ SSL_set_bio(ssl.get(), bio2.get(), bio1.get());
+
+ // ASAN builds will implicitly test that the internal |BIO| reference-counting
+ // is correct.
+}
+
+static int VerifySucceed(X509_STORE_CTX *store_ctx, void *arg) { return 1; }
+
+static bool TestGetPeerCertificate(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 both client and server to accept any certificate.
+ bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(method));
+ if (!ctx ||
+ !SSL_CTX_use_certificate(ctx.get(), cert.get()) ||
+ !SSL_CTX_use_PrivateKey(ctx.get(), key.get()) ||
+ !SSL_CTX_set_min_proto_version(ctx.get(), version) ||
+ !SSL_CTX_set_max_proto_version(ctx.get(), version)) {
+ return false;
+ }
+ SSL_CTX_set_verify(
+ ctx.get(), SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr);
+ SSL_CTX_set_cert_verify_callback(ctx.get(), VerifySucceed, NULL);
+
+ bssl::UniquePtr<SSL> client, server;
+ if (!ConnectClientAndServer(&client, &server, ctx.get(), 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 || X509_cmp(cert.get(), peer.get()) != 0) {
+ fprintf(stderr, "Server peer certificate did not match.\n");
+ return false;
+ }
+
+ peer.reset(SSL_get_peer_certificate(client.get()));
+ if (!peer || X509_cmp(cert.get(), peer.get()) != 0) {
+ fprintf(stderr, "Client peer certificate did not match.\n");
+ return false;
+ }
+
+ // However, for historical reasons, the 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) {
+ fprintf(stderr, "Client peer chain was incorrect.\n");
+ return false;
+ }
+
+ if (sk_X509_num(SSL_get_peer_cert_chain(server.get())) != 0) {
+ fprintf(stderr, "Server peer chain was incorrect.\n");
+ return false;
+ }
+
+ return true;
+}
+
+static bool TestRetainOnlySHA256OfCerts(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;
+ }
+
+ uint8_t *cert_der = NULL;
+ int cert_der_len = i2d_X509(cert.get(), &cert_der);
+ if (cert_der_len < 0) {
+ return false;
+ }
+ bssl::UniquePtr<uint8_t> free_cert_der(cert_der);
+
+ uint8_t cert_sha256[SHA256_DIGEST_LENGTH];
+ SHA256(cert_der, cert_der_len, cert_sha256);
+
+ // Configure both client and server to accept any certificate, but the
+ // server must retain only the SHA-256 of the peer.
+ bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(method));
+ if (!ctx ||
+ !SSL_CTX_use_certificate(ctx.get(), cert.get()) ||
+ !SSL_CTX_use_PrivateKey(ctx.get(), key.get()) ||
+ !SSL_CTX_set_min_proto_version(ctx.get(), version) ||
+ !SSL_CTX_set_max_proto_version(ctx.get(), version)) {
+ return false;
+ }
+ SSL_CTX_set_verify(
+ ctx.get(), SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr);
+ SSL_CTX_set_cert_verify_callback(ctx.get(), VerifySucceed, NULL);
+ SSL_CTX_set_retain_only_sha256_of_client_certs(ctx.get(), 1);
+
+ bssl::UniquePtr<SSL> client, server;
+ if (!ConnectClientAndServer(&client, &server, ctx.get(), ctx.get(),
+ nullptr /* no session */)) {
+ return false;
+ }
+
+ // The peer certificate has been dropped.
+ bssl::UniquePtr<X509> peer(SSL_get_peer_certificate(server.get()));
+ if (peer) {
+ fprintf(stderr, "Peer certificate was retained.\n");
+ return false;
+ }
+
+ SSL_SESSION *session = SSL_get_session(server.get());
+ if (!session->peer_sha256_valid) {
+ fprintf(stderr, "peer_sha256_valid was not set.\n");
+ return false;
+ }
+
+ if (OPENSSL_memcmp(cert_sha256, session->peer_sha256, SHA256_DIGEST_LENGTH) !=
+ 0) {
+ fprintf(stderr, "peer_sha256 did not match.\n");
+ return false;
+ }
+
+ return true;
+}
+
+static bool ClientHelloMatches(uint16_t version, const uint8_t *expected,
+ size_t expected_len) {
+ bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
+ if (!ctx ||
+ !SSL_CTX_set_max_proto_version(ctx.get(), version) ||
+ // Our default cipher list varies by CPU capabilities, so manually place
+ // the ChaCha20 ciphers in front.
+ !SSL_CTX_set_strict_cipher_list(ctx.get(), "CHACHA20:ALL")) {
+ return false;
+ }
+
+ bssl::UniquePtr<SSL> ssl(SSL_new(ctx.get()));
+ if (!ssl) {
+ return false;
+ }
+ std::vector<uint8_t> client_hello;
+ if (!GetClientHello(ssl.get(), &client_hello)) {
+ return false;
+ }
+
+ // Zero the client_random.
+ constexpr size_t kRandomOffset = 1 + 2 + 2 + // record header
+ 1 + 3 + // handshake message header
+ 2; // client_version
+ if (client_hello.size() < kRandomOffset + SSL3_RANDOM_SIZE) {
+ fprintf(stderr, "ClientHello for version %04x too short.\n", version);
+ return false;
+ }
+ OPENSSL_memset(client_hello.data() + kRandomOffset, 0, SSL3_RANDOM_SIZE);
+
+ if (client_hello.size() != expected_len ||
+ OPENSSL_memcmp(client_hello.data(), expected, expected_len) != 0) {
+ fprintf(stderr, "ClientHello for version %04x did not match:\n", version);
+ fprintf(stderr, "Got:\n\t");
+ for (size_t i = 0; i < client_hello.size(); i++) {
+ fprintf(stderr, "0x%02x, ", client_hello[i]);
+ }
+ fprintf(stderr, "\nWanted:\n\t");
+ for (size_t i = 0; i < expected_len; i++) {
+ fprintf(stderr, "0x%02x, ", expected[i]);
+ }
+ fprintf(stderr, "\n");
+ return false;
+ }
+
+ return true;
+}
+
+// Tests that our ClientHellos do not change unexpectedly.
+static bool TestClientHello() {
+ static const uint8_t kSSL3ClientHello[] = {
+ 0x16,
+ 0x03, 0x00,
+ 0x00, 0x3f,
+ 0x01,
+ 0x00, 0x00, 0x3b,
+ 0x03, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00,
+ 0x00, 0x14,
+ 0xc0, 0x09,
+ 0xc0, 0x13,
+ 0x00, 0x33,
+ 0xc0, 0x0a,
+ 0xc0, 0x14,
+ 0x00, 0x39,
+ 0x00, 0x2f,
+ 0x00, 0x35,
+ 0x00, 0x0a,
+ 0x00, 0xff, 0x01, 0x00,
+ };
+ if (!ClientHelloMatches(SSL3_VERSION, kSSL3ClientHello,
+ sizeof(kSSL3ClientHello))) {
+ return false;
+ }
+
+ static const uint8_t kTLS1ClientHello[] = {
+ 0x16,
+ 0x03, 0x01,
+ 0x00, 0x5e,
+ 0x01,
+ 0x00, 0x00, 0x5a,
+ 0x03, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00,
+ 0x00, 0x12,
+ 0xc0, 0x09,
+ 0xc0, 0x13,
+ 0x00, 0x33,
+ 0xc0, 0x0a,
+ 0xc0, 0x14,
+ 0x00, 0x39,
+ 0x00, 0x2f,
+ 0x00, 0x35,
+ 0x00, 0x0a,
+ 0x01, 0x00, 0x00, 0x1f, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x17, 0x00,
+ 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00,
+ 0x0a, 0x00, 0x08, 0x00, 0x06, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18,
+ };
+ if (!ClientHelloMatches(TLS1_VERSION, kTLS1ClientHello,
+ sizeof(kTLS1ClientHello))) {
+ return false;
+ }
+
+ static const uint8_t kTLS11ClientHello[] = {
+ 0x16,
+ 0x03, 0x01,
+ 0x00, 0x5e,
+ 0x01,
+ 0x00, 0x00, 0x5a,
+ 0x03, 0x02,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00,
+ 0x00, 0x12,
+ 0xc0, 0x09,
+ 0xc0, 0x13,
+ 0x00, 0x33,
+ 0xc0, 0x0a,
+ 0xc0, 0x14,
+ 0x00, 0x39,
+ 0x00, 0x2f,
+ 0x00, 0x35,
+ 0x00, 0x0a,
+ 0x01, 0x00, 0x00, 0x1f, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x17, 0x00,
+ 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00,
+ 0x0a, 0x00, 0x08, 0x00, 0x06, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18,
+ };
+ if (!ClientHelloMatches(TLS1_1_VERSION, kTLS11ClientHello,
+ sizeof(kTLS11ClientHello))) {
+ return false;
+ }
+
+ // kTLS12ClientHello assumes RSA-PSS, which is disabled for Android system
+ // builds.
+#if defined(BORINGSSL_ANDROID_SYSTEM)
+ return true;
+#endif
+
+ static const uint8_t kTLS12ClientHello[] = {
+ 0x16, 0x03, 0x01, 0x00, 0x9a, 0x01, 0x00, 0x00, 0x96, 0x03, 0x03, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0xcc, 0xa9,
+ 0xcc, 0xa8, 0xc0, 0x2b, 0xc0, 0x2f, 0x00, 0x9e, 0xc0, 0x2c, 0xc0, 0x30,
+ 0x00, 0x9f, 0xc0, 0x09, 0xc0, 0x23, 0xc0, 0x13, 0xc0, 0x27, 0x00, 0x33,
+ 0x00, 0x67, 0xc0, 0x0a, 0xc0, 0x24, 0xc0, 0x14, 0xc0, 0x28, 0x00, 0x39,
+ 0x00, 0x6b, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x2f, 0x00, 0x3c, 0x00, 0x35,
+ 0x00, 0x3d, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x37, 0xff, 0x01, 0x00, 0x01,
+ 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x0d, 0x00,
+ 0x14, 0x00, 0x12, 0x04, 0x03, 0x08, 0x04, 0x04, 0x01, 0x05, 0x03, 0x08,
+ 0x05, 0x05, 0x01, 0x08, 0x06, 0x06, 0x01, 0x02, 0x01, 0x00, 0x0b, 0x00,
+ 0x02, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x06, 0x00, 0x1d, 0x00,
+ 0x17, 0x00, 0x18,
+ };
+ if (!ClientHelloMatches(TLS1_2_VERSION, kTLS12ClientHello,
+ sizeof(kTLS12ClientHello))) {
+ return false;
+ }
+
+ // TODO(davidben): Add a change detector for TLS 1.3 once the spec and our
+ // implementation has settled enough that it won't change.
+
+ return true;
+}
+
+static bssl::UniquePtr<SSL_SESSION> g_last_session;
+
+static int SaveLastSession(SSL *ssl, SSL_SESSION *session) {
+ // Save the most recent session.
+ g_last_session.reset(session);
+ return 1;
+}
+
+static bssl::UniquePtr<SSL_SESSION> CreateClientSession(SSL_CTX *client_ctx,
+ SSL_CTX *server_ctx) {
+ g_last_session = nullptr;
+ SSL_CTX_sess_set_new_cb(client_ctx, SaveLastSession);
+
+ // Connect client and server to get a session.
+ bssl::UniquePtr<SSL> client, server;
+ if (!ConnectClientAndServer(&client, &server, client_ctx, server_ctx,
+ nullptr /* no session */)) {
+ fprintf(stderr, "Failed to connect client and server.\n");
+ return nullptr;
+ }
+
+ // Run the read loop to account for post-handshake tickets in TLS 1.3.
+ SSL_read(client.get(), nullptr, 0);
+
+ SSL_CTX_sess_set_new_cb(client_ctx, nullptr);
+
+ if (!g_last_session) {
+ fprintf(stderr, "Client did not receive a session.\n");
+ return nullptr;
+ }
+ return std::move(g_last_session);
+}
+
+static bool ExpectSessionReused(SSL_CTX *client_ctx, SSL_CTX *server_ctx,
+ SSL_SESSION *session,
+ bool reused) {
+ bssl::UniquePtr<SSL> client, server;
+ if (!ConnectClientAndServer(&client, &server, client_ctx,
+ server_ctx, session)) {
+ fprintf(stderr, "Failed to connect client and server.\n");
+ return false;
+ }
+
+ if (SSL_session_reused(client.get()) != SSL_session_reused(server.get())) {
+ fprintf(stderr, "Client and server were inconsistent.\n");
+ return false;
+ }
+
+ bool was_reused = !!SSL_session_reused(client.get());
+ if (was_reused != reused) {
+ fprintf(stderr, "Session was%s reused, but we expected the opposite.\n",
+ was_reused ? "" : " not");
+ return false;
+ }
+
+ return true;
+}
+
+static bssl::UniquePtr<SSL_SESSION> ExpectSessionRenewed(SSL_CTX *client_ctx,
+ SSL_CTX *server_ctx,
+ SSL_SESSION *session) {
+ g_last_session = nullptr;
+ SSL_CTX_sess_set_new_cb(client_ctx, SaveLastSession);
+
+ bssl::UniquePtr<SSL> client, server;
+ if (!ConnectClientAndServer(&client, &server, client_ctx,
+ server_ctx, session)) {
+ fprintf(stderr, "Failed to connect client and server.\n");
+ return nullptr;
+ }
+
+ if (SSL_session_reused(client.get()) != SSL_session_reused(server.get())) {
+ fprintf(stderr, "Client and server were inconsistent.\n");
+ return nullptr;
+ }
+
+ if (!SSL_session_reused(client.get())) {
+ fprintf(stderr, "Session was not reused.\n");
+ return nullptr;
+ }
+
+ // Run the read loop to account for post-handshake tickets in TLS 1.3.
+ SSL_read(client.get(), nullptr, 0);
+
+ SSL_CTX_sess_set_new_cb(client_ctx, nullptr);
+
+ if (!g_last_session) {
+ fprintf(stderr, "Client did not receive a renewed session.\n");
+ return nullptr;
+ }
+ return std::move(g_last_session);
+}
+
+static int SwitchSessionIDContextSNI(SSL *ssl, int *out_alert, void *arg) {
+ static const uint8_t kContext[] = {3};
+
+ if (!SSL_set_session_id_context(ssl, kContext, sizeof(kContext))) {
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
+ }
+
+ return SSL_TLSEXT_ERR_OK;
+}
+
+static int SwitchSessionIDContextEarly(const SSL_CLIENT_HELLO *client_hello) {
+ static const uint8_t kContext[] = {3};
+
+ if (!SSL_set_session_id_context(client_hello->ssl, kContext,
+ sizeof(kContext))) {
+ return -1;
+ }
+
+ return 1;
+}
+
+static bool TestSessionIDContext(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;
+ }
+
+ static const uint8_t kContext1[] = {1};
+ static const uint8_t kContext2[] = {2};
+
+ bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(method));
+ bssl::UniquePtr<SSL_CTX> 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_session_id_context(server_ctx.get(), kContext1,
+ sizeof(kContext1)) ||
+ !SSL_CTX_set_min_proto_version(client_ctx.get(), version) ||
+ !SSL_CTX_set_max_proto_version(client_ctx.get(), version) ||
+ !SSL_CTX_set_min_proto_version(server_ctx.get(), version) ||
+ !SSL_CTX_set_max_proto_version(server_ctx.get(), version)) {
+ return false;
+ }
+
+ SSL_CTX_set_session_cache_mode(client_ctx.get(), SSL_SESS_CACHE_BOTH);
+ SSL_CTX_set_session_cache_mode(server_ctx.get(), SSL_SESS_CACHE_BOTH);
+
+ bssl::UniquePtr<SSL_SESSION> session =
+ CreateClientSession(client_ctx.get(), server_ctx.get());
+ if (!session) {
+ fprintf(stderr, "Error getting session.\n");
+ return false;
+ }
+
+ if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(), session.get(),
+ true /* expect session reused */)) {
+ fprintf(stderr, "Error resuming session.\n");
+ return false;
+ }
+
+ // Change the session ID context.
+ if (!SSL_CTX_set_session_id_context(server_ctx.get(), kContext2,
+ sizeof(kContext2))) {
+ return false;
+ }
+
+ if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(), session.get(),
+ false /* expect session not reused */)) {
+ fprintf(stderr, "Error connecting with a different context.\n");
+ return false;
+ }
+
+ // Change the session ID context back and install an SNI callback to switch
+ // it.
+ if (!SSL_CTX_set_session_id_context(server_ctx.get(), kContext1,
+ sizeof(kContext1))) {
+ return false;
+ }
+
+ SSL_CTX_set_tlsext_servername_callback(server_ctx.get(),
+ SwitchSessionIDContextSNI);
+
+ if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(), session.get(),
+ false /* expect session not reused */)) {
+ fprintf(stderr, "Error connecting with a context switch on SNI callback.\n");
+ return false;
+ }
+
+ // Switch the session ID context with the early callback instead.
+ SSL_CTX_set_tlsext_servername_callback(server_ctx.get(), nullptr);
+ SSL_CTX_set_select_certificate_cb(server_ctx.get(),
+ SwitchSessionIDContextEarly);
+
+ if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(), session.get(),
+ false /* expect session not reused */)) {
+ fprintf(stderr,
+ "Error connecting with a context switch on early callback.\n");
+ return false;
+ }
+
+ return true;
+}
+
+static timeval g_current_time;
+
+static void CurrentTimeCallback(const SSL *ssl, timeval *out_clock) {
+ *out_clock = g_current_time;
+}
+
+static void FrozenTimeCallback(const SSL *ssl, timeval *out_clock) {
+ out_clock->tv_sec = 1000;
+ out_clock->tv_usec = 0;
+}
+
+static int RenewTicketCallback(SSL *ssl, uint8_t *key_name, uint8_t *iv,
+ EVP_CIPHER_CTX *ctx, HMAC_CTX *hmac_ctx,
+ int encrypt) {
+ static const uint8_t kZeros[16] = {0};
+
+ if (encrypt) {
+ OPENSSL_memcpy(key_name, kZeros, sizeof(kZeros));
+ RAND_bytes(iv, 16);
+ } else if (OPENSSL_memcmp(key_name, kZeros, 16) != 0) {
+ return 0;
+ }
+
+ if (!HMAC_Init_ex(hmac_ctx, kZeros, sizeof(kZeros), EVP_sha256(), NULL) ||
+ !EVP_CipherInit_ex(ctx, EVP_aes_128_cbc(), NULL, kZeros, iv, encrypt)) {
+ return -1;
+ }
+
+ // Returning two from the callback in decrypt mode renews the
+ // session in TLS 1.2 and below.
+ return encrypt ? 1 : 2;
+}
+
+static bool GetServerTicketTime(long *out, const SSL_SESSION *session) {
+ if (session->tlsext_ticklen < 16 + 16 + SHA256_DIGEST_LENGTH) {
+ return false;
+ }
+
+ const uint8_t *ciphertext = session->tlsext_tick + 16 + 16;
+ size_t len = session->tlsext_ticklen - 16 - 16 - SHA256_DIGEST_LENGTH;
+ std::unique_ptr<uint8_t[]> plaintext(new uint8_t[len]);
+
+#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+ // Fuzzer-mode tickets are unencrypted.
+ OPENSSL_memcpy(plaintext.get(), ciphertext, len);
+#else
+ static const uint8_t kZeros[16] = {0};
+ const uint8_t *iv = session->tlsext_tick + 16;
+ bssl::ScopedEVP_CIPHER_CTX ctx;
+ int len1, len2;
+ if (!EVP_DecryptInit_ex(ctx.get(), EVP_aes_128_cbc(), nullptr, kZeros, iv) ||
+ !EVP_DecryptUpdate(ctx.get(), plaintext.get(), &len1, ciphertext, len) ||
+ !EVP_DecryptFinal_ex(ctx.get(), plaintext.get() + len1, &len2)) {
+ return false;
+ }
+
+ len = static_cast<size_t>(len1 + len2);
+#endif
+
+ bssl::UniquePtr<SSL_CTX> ssl_ctx(SSL_CTX_new(TLS_method()));
+ if (!ssl_ctx) {
+ return false;
+ }
+ bssl::UniquePtr<SSL_SESSION> server_session(
+ SSL_SESSION_from_bytes(plaintext.get(), len, ssl_ctx.get()));
+ if (!server_session) {
+ return false;
+ }
+
+ *out = server_session->time;
+ return true;
+}
+
+static bool TestSessionTimeout(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;
+ }
+
+ for (bool server_test : std::vector<bool>{false, true}) {
+ static const time_t kStartTime = 1000;
+ g_current_time.tv_sec = kStartTime;
+
+ // We are willing to use a longer lifetime for TLS 1.3 sessions as
+ // resumptions still perform ECDHE.
+ const time_t timeout = version == TLS1_3_VERSION
+ ? SSL_DEFAULT_SESSION_PSK_DHE_TIMEOUT
+ : SSL_DEFAULT_SESSION_TIMEOUT;
+
+ bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(method));
+ bssl::UniquePtr<SSL_CTX> 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(client_ctx.get(), version) ||
+ !SSL_CTX_set_max_proto_version(client_ctx.get(), version) ||
+ !SSL_CTX_set_min_proto_version(server_ctx.get(), version) ||
+ !SSL_CTX_set_max_proto_version(server_ctx.get(), version)) {
+ return false;
+ }
+
+ SSL_CTX_set_session_cache_mode(client_ctx.get(), SSL_SESS_CACHE_BOTH);
+ SSL_CTX_set_session_cache_mode(server_ctx.get(), SSL_SESS_CACHE_BOTH);
+
+ // Both client and server must enforce session timeouts. We configure the
+ // other side with a frozen clock so it never expires tickets.
+ if (server_test) {
+ SSL_CTX_set_current_time_cb(client_ctx.get(), FrozenTimeCallback);
+ SSL_CTX_set_current_time_cb(server_ctx.get(), CurrentTimeCallback);
+ } else {
+ SSL_CTX_set_current_time_cb(client_ctx.get(), CurrentTimeCallback);
+ SSL_CTX_set_current_time_cb(server_ctx.get(), FrozenTimeCallback);
+ }
+
+ // Configure a ticket callback which renews tickets.
+ SSL_CTX_set_tlsext_ticket_key_cb(server_ctx.get(), RenewTicketCallback);
+
+ bssl::UniquePtr<SSL_SESSION> session =
+ CreateClientSession(client_ctx.get(), server_ctx.get());
+ if (!session) {
+ fprintf(stderr, "Error getting session.\n");
+ return false;
+ }
+
+ // Advance the clock just behind the timeout.
+ g_current_time.tv_sec += timeout - 1;
+
+ if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(), session.get(),
+ true /* expect session reused */)) {
+ fprintf(stderr, "Error resuming session.\n");
+ return false;
+ }
+
+ // Advance the clock one more second.
+ g_current_time.tv_sec++;
+
+ if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(), session.get(),
+ false /* expect session not reused */)) {
+ fprintf(stderr, "Error resuming session.\n");
+ return false;
+ }
+
+ // Rewind the clock to before the session was minted.
+ g_current_time.tv_sec = kStartTime - 1;
+
+ if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(), session.get(),
+ false /* expect session not reused */)) {
+ fprintf(stderr, "Error resuming session.\n");
+ return false;
+ }
+
+ // SSL 3.0 cannot renew sessions.
+ if (version == SSL3_VERSION) {
+ continue;
+ }
+
+ // Renew the session 10 seconds before expiration.
+ time_t new_start_time = kStartTime + timeout - 10;
+ g_current_time.tv_sec = new_start_time;
+ bssl::UniquePtr<SSL_SESSION> new_session =
+ ExpectSessionRenewed(client_ctx.get(), server_ctx.get(), session.get());
+ if (!new_session) {
+ fprintf(stderr, "Error renewing session.\n");
+ return false;
+ }
+
+ // This new session is not the same object as before.
+ if (session.get() == new_session.get()) {
+ fprintf(stderr, "New and old sessions alias.\n");
+ return false;
+ }
+
+ // Check the sessions have timestamps measured from issuance.
+ long session_time = 0;
+ if (server_test) {
+ if (!GetServerTicketTime(&session_time, new_session.get())) {
+ fprintf(stderr, "Failed to decode session ticket.\n");
+ return false;
+ }
+ } else {
+ session_time = new_session->time;
+ }
+
+ if (session_time != g_current_time.tv_sec) {
+ fprintf(stderr, "New session is not measured from issuance.\n");
+ return false;
+ }
+
+ if (version == TLS1_3_VERSION) {
+ // Renewal incorporates fresh key material in TLS 1.3, so we extend the
+ // lifetime TLS 1.3.
+ g_current_time.tv_sec = new_start_time + timeout - 1;
+ if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(),
+ new_session.get(),
+ true /* expect session reused */)) {
+ fprintf(stderr, "Error resuming renewed session.\n");
+ return false;
+ }
+
+ // The new session expires after the new timeout.
+ g_current_time.tv_sec = new_start_time + timeout + 1;
+ if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(),
+ new_session.get(),
+ false /* expect session ot reused */)) {
+ fprintf(stderr, "Renewed session's lifetime is too long.\n");
+ return false;
+ }
+
+ // Renew the session until it begins just past the auth timeout.
+ time_t auth_end_time = kStartTime + SSL_DEFAULT_SESSION_AUTH_TIMEOUT;
+ while (new_start_time < auth_end_time - 1000) {
+ // Get as close as possible to target start time.
+ new_start_time =
+ std::min(auth_end_time - 1000, new_start_time + timeout - 1);
+ g_current_time.tv_sec = new_start_time;
+ new_session = ExpectSessionRenewed(client_ctx.get(), server_ctx.get(),
+ new_session.get());
+ if (!new_session) {
+ fprintf(stderr, "Error renewing session.\n");
+ return false;
+ }
+ }
+
+ // Now the session's lifetime is bound by the auth timeout.
+ g_current_time.tv_sec = auth_end_time - 1;
+ if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(),
+ new_session.get(),
+ true /* expect session reused */)) {
+ fprintf(stderr, "Error resuming renewed session.\n");
+ return false;
+ }
+
+ g_current_time.tv_sec = auth_end_time + 1;
+ if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(),
+ new_session.get(),
+ false /* expect session ot reused */)) {
+ fprintf(stderr, "Renewed session's lifetime is too long.\n");
+ return false;
+ }
+ } else {
+ // The new session is usable just before the old expiration.
+ g_current_time.tv_sec = kStartTime + timeout - 1;
+ if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(),
+ new_session.get(),
+ true /* expect session reused */)) {
+ fprintf(stderr, "Error resuming renewed session.\n");
+ return false;
+ }
+
+ // Renewal does not extend the lifetime, so it is not usable beyond the
+ // old expiration.
+ g_current_time.tv_sec = kStartTime + timeout + 1;
+ if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(),
+ new_session.get(),
+ false /* expect session not reused */)) {
+ fprintf(stderr, "Renewed session's lifetime is too long.\n");
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+static int SwitchContext(SSL *ssl, int *out_alert, void *arg) {
+ SSL_CTX *ctx = reinterpret_cast<SSL_CTX*>(arg);
+ SSL_set_SSL_CTX(ssl, ctx);
+ return SSL_TLSEXT_ERR_OK;
+}
+
+static bool TestSNICallback(bool is_dtls, const SSL_METHOD *method,
+ uint16_t version) {
+ // SSL 3.0 lacks extensions.
+ if (version == SSL3_VERSION) {
+ return true;
+ }
+
+ bssl::UniquePtr<X509> cert = GetTestCertificate();
+ bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
+ bssl::UniquePtr<X509> cert2 = GetECDSATestCertificate();
+ bssl::UniquePtr<EVP_PKEY> key2 = GetECDSATestKey();
+ if (!cert || !key || !cert2 || !key2) {
+ return false;
+ }
+
+ // Test that switching the |SSL_CTX| at the SNI callback behaves correctly.
+ static const uint16_t kECDSAWithSHA256 = SSL_SIGN_ECDSA_SECP256R1_SHA256;
+
+ static const uint8_t kSCTList[] = {0, 6, 0, 4, 5, 6, 7, 8};
+ static const uint8_t kOCSPResponse[] = {1, 2, 3, 4};
+
+ bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(method));
+ bssl::UniquePtr<SSL_CTX> server_ctx2(SSL_CTX_new(method));
+ bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(method));
+ if (!server_ctx || !server_ctx2 || !client_ctx ||
+ !SSL_CTX_use_certificate(server_ctx.get(), cert.get()) ||
+ !SSL_CTX_use_PrivateKey(server_ctx.get(), key.get()) ||
+ !SSL_CTX_use_certificate(server_ctx2.get(), cert2.get()) ||
+ !SSL_CTX_use_PrivateKey(server_ctx2.get(), key2.get()) ||
+ !SSL_CTX_set_signed_cert_timestamp_list(server_ctx2.get(), kSCTList,
+ sizeof(kSCTList)) ||
+ !SSL_CTX_set_ocsp_response(server_ctx2.get(), kOCSPResponse,
+ sizeof(kOCSPResponse)) ||
+ // Historically signing preferences would be lost in some cases with the
+ // SNI callback, which triggers the TLS 1.2 SHA-1 default. To ensure
+ // this doesn't happen when |version| is TLS 1.2, configure the private
+ // key to only sign SHA-256.
+ !SSL_CTX_set_signing_algorithm_prefs(server_ctx2.get(), &kECDSAWithSHA256,
+ 1) ||
+ !SSL_CTX_set_min_proto_version(client_ctx.get(), version) ||
+ !SSL_CTX_set_max_proto_version(client_ctx.get(), version) ||
+ !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(server_ctx2.get(), version) ||
+ !SSL_CTX_set_max_proto_version(server_ctx2.get(), version)) {
+ return false;
+ }
+
+ SSL_CTX_set_tlsext_servername_callback(server_ctx.get(), SwitchContext);
+ SSL_CTX_set_tlsext_servername_arg(server_ctx.get(), server_ctx2.get());
+
+ SSL_CTX_enable_signed_cert_timestamps(client_ctx.get());
+ SSL_CTX_enable_ocsp_stapling(client_ctx.get());
+
+ bssl::UniquePtr<SSL> client, server;
+ if (!ConnectClientAndServer(&client, &server, client_ctx.get(),
+ server_ctx.get(), nullptr)) {
+ fprintf(stderr, "Handshake failed.\n");
+ return false;
+ }
+
+ // The client should have received |cert2|.
+ bssl::UniquePtr<X509> peer(SSL_get_peer_certificate(client.get()));
+ if (!peer || X509_cmp(peer.get(), cert2.get()) != 0) {
+ fprintf(stderr, "Incorrect certificate received.\n");
+ return false;
+ }
+
+ // The client should have received |server_ctx2|'s SCT list.
+ const uint8_t *data;
+ size_t len;
+ SSL_get0_signed_cert_timestamp_list(client.get(), &data, &len);
+ if (Bytes(kSCTList) != Bytes(data, len)) {
+ fprintf(stderr, "Incorrect SCT list received.\n");
+ return false;
+ }
+
+ // The client should have received |server_ctx2|'s OCSP response.
+ SSL_get0_ocsp_response(client.get(), &data, &len);
+ if (Bytes(kOCSPResponse) != Bytes(data, len)) {
+ fprintf(stderr, "Incorrect OCSP response received.\n");
+ return false;
+ }
+
+ return true;
+}
+
+// Test that the early callback can swap the maximum version.
+TEST(SSLTest, EarlyCallbackVersionSwitch) {
+ bssl::UniquePtr<X509> cert = GetTestCertificate();
+ bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
+ bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(TLS_method()));
+ bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
+ ASSERT_TRUE(cert);
+ ASSERT_TRUE(key);
+ ASSERT_TRUE(server_ctx);
+ ASSERT_TRUE(client_ctx);
+ ASSERT_TRUE(SSL_CTX_use_certificate(server_ctx.get(), cert.get()));
+ ASSERT_TRUE(SSL_CTX_use_PrivateKey(server_ctx.get(), key.get()));
+ ASSERT_TRUE(SSL_CTX_set_max_proto_version(client_ctx.get(), TLS1_3_VERSION));
+ ASSERT_TRUE(SSL_CTX_set_max_proto_version(server_ctx.get(), TLS1_3_VERSION));
+
+ SSL_CTX_set_select_certificate_cb(
+ server_ctx.get(), [](const SSL_CLIENT_HELLO *client_hello) -> int {
+ if (!SSL_set_max_proto_version(client_hello->ssl, TLS1_2_VERSION)) {
+ return -1;
+ }
+
+ return 1;
+ });
+
+ bssl::UniquePtr<SSL> client, server;
+ ASSERT_TRUE(ConnectClientAndServer(&client, &server, client_ctx.get(),
+ server_ctx.get(), nullptr));
+ EXPECT_EQ(TLS1_2_VERSION, SSL_version(client.get()));
+}
+
+TEST(SSLTest, SetVersion) {
+ bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
+ ASSERT_TRUE(ctx);
+
+ // Set valid TLS versions.
+ EXPECT_TRUE(SSL_CTX_set_max_proto_version(ctx.get(), TLS1_VERSION));
+ EXPECT_TRUE(SSL_CTX_set_max_proto_version(ctx.get(), TLS1_1_VERSION));
+ EXPECT_TRUE(SSL_CTX_set_min_proto_version(ctx.get(), TLS1_VERSION));
+ EXPECT_TRUE(SSL_CTX_set_min_proto_version(ctx.get(), TLS1_1_VERSION));
+
+ // Invalid TLS versions are rejected.
+ EXPECT_FALSE(SSL_CTX_set_max_proto_version(ctx.get(), DTLS1_VERSION));
+ EXPECT_FALSE(SSL_CTX_set_max_proto_version(ctx.get(), 0x0200));
+ EXPECT_FALSE(SSL_CTX_set_max_proto_version(ctx.get(), 0x1234));
+ EXPECT_FALSE(SSL_CTX_set_min_proto_version(ctx.get(), DTLS1_VERSION));
+ EXPECT_FALSE(SSL_CTX_set_min_proto_version(ctx.get(), 0x0200));
+ EXPECT_FALSE(SSL_CTX_set_min_proto_version(ctx.get(), 0x1234));
+
+ // Zero is the default version.
+ EXPECT_TRUE(SSL_CTX_set_max_proto_version(ctx.get(), 0));
+ EXPECT_EQ(TLS1_2_VERSION, ctx->max_version);
+ EXPECT_TRUE(SSL_CTX_set_min_proto_version(ctx.get(), 0));
+ EXPECT_EQ(SSL3_VERSION, ctx->min_version);
+
+ ctx.reset(SSL_CTX_new(DTLS_method()));
+ ASSERT_TRUE(ctx);
+
+ EXPECT_TRUE(SSL_CTX_set_max_proto_version(ctx.get(), DTLS1_VERSION));
+ EXPECT_TRUE(SSL_CTX_set_max_proto_version(ctx.get(), DTLS1_2_VERSION));
+ EXPECT_TRUE(SSL_CTX_set_min_proto_version(ctx.get(), DTLS1_VERSION));
+ EXPECT_TRUE(SSL_CTX_set_min_proto_version(ctx.get(), DTLS1_2_VERSION));
+
+ EXPECT_FALSE(SSL_CTX_set_max_proto_version(ctx.get(), TLS1_VERSION));
+ EXPECT_FALSE(SSL_CTX_set_max_proto_version(ctx.get(), 0xfefe /* DTLS 1.1 */));
+ EXPECT_FALSE(SSL_CTX_set_max_proto_version(ctx.get(), 0xfffe /* DTLS 0.1 */));
+ EXPECT_FALSE(SSL_CTX_set_max_proto_version(ctx.get(), 0x1234));
+ EXPECT_FALSE(SSL_CTX_set_min_proto_version(ctx.get(), TLS1_VERSION));
+ EXPECT_FALSE(SSL_CTX_set_min_proto_version(ctx.get(), 0xfefe /* DTLS 1.1 */));
+ EXPECT_FALSE(SSL_CTX_set_min_proto_version(ctx.get(), 0xfffe /* DTLS 0.1 */));
+ EXPECT_FALSE(SSL_CTX_set_min_proto_version(ctx.get(), 0x1234));
+
+ EXPECT_TRUE(SSL_CTX_set_max_proto_version(ctx.get(), 0));
+ EXPECT_EQ(TLS1_2_VERSION, ctx->max_version);
+ EXPECT_TRUE(SSL_CTX_set_min_proto_version(ctx.get(), 0));
+ EXPECT_EQ(TLS1_1_VERSION, ctx->min_version);
+}
+
+static const char *GetVersionName(uint16_t version) {
+ switch (version) {
+ case SSL3_VERSION:
+ return "SSLv3";
+ case TLS1_VERSION:
+ return "TLSv1";
+ case TLS1_1_VERSION:
+ return "TLSv1.1";
+ case TLS1_2_VERSION:
+ return "TLSv1.2";
+ case TLS1_3_VERSION:
+ return "TLSv1.3";
+ case DTLS1_VERSION:
+ return "DTLSv1";
+ case DTLS1_2_VERSION:
+ return "DTLSv1.2";
+ default:
+ return "???";
+ }
+}
+
+static bool TestVersion(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;
+ }
+
+ bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(method));
+ bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(method));
+ bssl::UniquePtr<SSL> client, server;
+ 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(client_ctx.get(), version) ||
+ !SSL_CTX_set_max_proto_version(client_ctx.get(), version) ||
+ !SSL_CTX_set_min_proto_version(server_ctx.get(), version) ||
+ !SSL_CTX_set_max_proto_version(server_ctx.get(), version) ||
+ !ConnectClientAndServer(&client, &server, client_ctx.get(),
+ server_ctx.get(), nullptr /* no session */)) {
+ fprintf(stderr, "Failed to connect.\n");
+ return false;
+ }
+
+ if (SSL_version(client.get()) != version ||
+ SSL_version(server.get()) != version) {
+ fprintf(stderr, "Version mismatch. Got %04x and %04x, wanted %04x.\n",
+ SSL_version(client.get()), SSL_version(server.get()), version);
+ return false;
+ }
+
+ // Test the version name is reported as expected.
+ const char *version_name = GetVersionName(version);
+ if (strcmp(version_name, SSL_get_version(client.get())) != 0 ||
+ strcmp(version_name, SSL_get_version(server.get())) != 0) {
+ fprintf(stderr, "Version name mismatch. Got '%s' and '%s', wanted '%s'.\n",
+ SSL_get_version(client.get()), SSL_get_version(server.get()),
+ version_name);
+ return false;
+ }
+
+ // Test SSL_SESSION reports the same name.
+ const char *client_name =
+ SSL_SESSION_get_version(SSL_get_session(client.get()));
+ const char *server_name =
+ SSL_SESSION_get_version(SSL_get_session(server.get()));
+ if (strcmp(version_name, client_name) != 0 ||
+ strcmp(version_name, server_name) != 0) {
+ fprintf(stderr,
+ "Session version name mismatch. Got '%s' and '%s', wanted '%s'.\n",
+ client_name, server_name, version_name);
+ return false;
+ }
+
+ return true;
+}
+
+// Tests that that |SSL_get_pending_cipher| is available during the ALPN
+// selection callback.
+static bool TestALPNCipherAvailable(bool is_dtls, const SSL_METHOD *method,
+ uint16_t version) {
+ // SSL 3.0 lacks extensions.
+ if (version == SSL3_VERSION) {
+ return true;
+ }
+
+ static const uint8_t kALPNProtos[] = {0x03, 'f', 'o', 'o'};
+
+ bssl::UniquePtr<X509> cert = GetTestCertificate();
+ bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
+ if (!cert || !key) {
+ return false;
+ }
+
+ bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(method));
+ if (!ctx || !SSL_CTX_use_certificate(ctx.get(), cert.get()) ||
+ !SSL_CTX_use_PrivateKey(ctx.get(), key.get()) ||
+ !SSL_CTX_set_min_proto_version(ctx.get(), version) ||
+ !SSL_CTX_set_max_proto_version(ctx.get(), version) ||
+ SSL_CTX_set_alpn_protos(ctx.get(), kALPNProtos, sizeof(kALPNProtos)) !=
+ 0) {
+ return false;
+ }
+
+ // The ALPN callback does not fail the handshake on error, so have the
+ // callback write a boolean.
+ std::pair<uint16_t, bool> callback_state(version, false);
+ SSL_CTX_set_alpn_select_cb(
+ ctx.get(),
+ [](SSL *ssl, const uint8_t **out, uint8_t *out_len, const uint8_t *in,
+ unsigned in_len, void *arg) -> int {
+ auto state = reinterpret_cast<std::pair<uint16_t, bool> *>(arg);
+ if (SSL_get_pending_cipher(ssl) != nullptr &&
+ SSL_version(ssl) == state->first) {
+ state->second = true;
+ }
+ return SSL_TLSEXT_ERR_NOACK;
+ },
+ &callback_state);
+
+ bssl::UniquePtr<SSL> client, server;
+ if (!ConnectClientAndServer(&client, &server, ctx.get(), ctx.get(),
+ nullptr /* no session */)) {
+ return false;
+ }
+
+ if (!callback_state.second) {
+ fprintf(stderr, "The pending cipher was not known in the ALPN callback.\n");
+ return false;
+ }
+
+ return true;
+}
+
+static bool TestSSLClearSessionResumption(bool is_dtls,
+ const SSL_METHOD *method,
+ uint16_t version) {
+ // Skip this for TLS 1.3. TLS 1.3's ticket mechanism is incompatible with this
+ // API pattern.
+ if (version == TLS1_3_VERSION) {
+ return true;
+ }
+
+ bssl::UniquePtr<X509> cert = GetTestCertificate();
+ bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
+ bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(method));
+ bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(method));
+ if (!cert || !key || !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(client_ctx.get(), version) ||
+ !SSL_CTX_set_max_proto_version(client_ctx.get(), version) ||
+ !SSL_CTX_set_min_proto_version(server_ctx.get(), version) ||
+ !SSL_CTX_set_max_proto_version(server_ctx.get(), version)) {
+ return false;
+ }
+
+ // Connect a client and a server.
+ bssl::UniquePtr<SSL> client, server;
+ if (!ConnectClientAndServer(&client, &server, client_ctx.get(),
+ server_ctx.get(), nullptr /* no session */)) {
+ return false;
+ }
+
+ if (SSL_session_reused(client.get()) ||
+ SSL_session_reused(server.get())) {
+ fprintf(stderr, "Session unexpectedly reused.\n");
+ return false;
+ }
+
+ // Reset everything.
+ if (!SSL_clear(client.get()) ||
+ !SSL_clear(server.get())) {
+ fprintf(stderr, "SSL_clear failed.\n");
+ return false;
+ }
+
+ // Attempt to connect a second time.
+ if (!CompleteHandshakes(client.get(), server.get())) {
+ fprintf(stderr, "Could not reuse SSL objects.\n");
+ return false;
+ }
+
+ // |SSL_clear| should implicitly offer the previous session to the server.
+ if (!SSL_session_reused(client.get()) ||
+ !SSL_session_reused(server.get())) {
+ fprintf(stderr, "Session was not reused in second try.\n");
+ return false;
+ }
+
+ return true;
+}
+
+static bool ChainsEqual(STACK_OF(X509) *chain,
+ const std::vector<X509 *> &expected) {
+ if (sk_X509_num(chain) != expected.size()) {
+ return false;
+ }
+
+ for (size_t i = 0; i < expected.size(); i++) {
+ if (X509_cmp(sk_X509_value(chain, i), expected[i]) != 0) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool TestAutoChain(bool is_dtls, const SSL_METHOD *method,
+ uint16_t version) {
+ bssl::UniquePtr<X509> cert = GetChainTestCertificate();
+ bssl::UniquePtr<X509> intermediate = GetChainTestIntermediate();
+ bssl::UniquePtr<EVP_PKEY> key = GetChainTestKey();
+ if (!cert || !intermediate || !key) {
+ return false;
+ }
+
+ // Configure both client and server to accept any certificate. Add
+ // |intermediate| to the cert store.
+ bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(method));
+ if (!ctx ||
+ !SSL_CTX_use_certificate(ctx.get(), cert.get()) ||
+ !SSL_CTX_use_PrivateKey(ctx.get(), key.get()) ||
+ !SSL_CTX_set_min_proto_version(ctx.get(), version) ||
+ !SSL_CTX_set_max_proto_version(ctx.get(), version) ||
+ !X509_STORE_add_cert(SSL_CTX_get_cert_store(ctx.get()),
+ intermediate.get())) {
+ return false;
+ }
+ SSL_CTX_set_verify(
+ ctx.get(), SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr);
+ SSL_CTX_set_cert_verify_callback(ctx.get(), VerifySucceed, NULL);
+
+ // By default, the client and server should each only send the leaf.
+ bssl::UniquePtr<SSL> client, server;
+ if (!ConnectClientAndServer(&client, &server, ctx.get(), ctx.get(),
+ nullptr /* no session */)) {
+ return false;
+ }
+
+ if (!ChainsEqual(SSL_get_peer_full_cert_chain(client.get()), {cert.get()})) {
+ fprintf(stderr, "Client-received chain did not match.\n");
+ return false;
+ }
+
+ if (!ChainsEqual(SSL_get_peer_full_cert_chain(server.get()), {cert.get()})) {
+ fprintf(stderr, "Server-received chain did not match.\n");
+ return false;
+ }
+
+ // If auto-chaining is enabled, then the intermediate is sent.
+ SSL_CTX_clear_mode(ctx.get(), SSL_MODE_NO_AUTO_CHAIN);
+ if (!ConnectClientAndServer(&client, &server, ctx.get(), ctx.get(),
+ nullptr /* no session */)) {
+ return false;
+ }
+
+ if (!ChainsEqual(SSL_get_peer_full_cert_chain(client.get()),
+ {cert.get(), intermediate.get()})) {
+ fprintf(stderr, "Client-received chain did not match (auto-chaining).\n");
+ return false;
+ }
+
+ if (!ChainsEqual(SSL_get_peer_full_cert_chain(server.get()),
+ {cert.get(), intermediate.get()})) {
+ fprintf(stderr, "Server-received chain did not match (auto-chaining).\n");
+ return false;
+ }
+
+ // Auto-chaining does not override explicitly-configured intermediates.
+ if (!SSL_CTX_add1_chain_cert(ctx.get(), cert.get()) ||
+ !ConnectClientAndServer(&client, &server, ctx.get(), ctx.get(),
+ nullptr /* no session */)) {
+ return false;
+ }
+
+ if (!ChainsEqual(SSL_get_peer_full_cert_chain(client.get()),
+ {cert.get(), cert.get()})) {
+ fprintf(stderr,
+ "Client-received chain did not match (auto-chaining, explicit "
+ "intermediate).\n");
+ return false;
+ }
+
+ if (!ChainsEqual(SSL_get_peer_full_cert_chain(server.get()),
+ {cert.get(), cert.get()})) {
+ fprintf(stderr,
+ "Server-received chain did not match (auto-chaining, explicit "
+ "intermediate).\n");
+ return false;
+ }
+
+ return true;
+}
+
+static bool ExpectBadWriteRetry() {
+ int err = ERR_get_error();
+ if (ERR_GET_LIB(err) != ERR_LIB_SSL ||
+ ERR_GET_REASON(err) != SSL_R_BAD_WRITE_RETRY) {
+ char buf[ERR_ERROR_STRING_BUF_LEN];
+ ERR_error_string_n(err, buf, sizeof(buf));
+ fprintf(stderr, "Wanted SSL_R_BAD_WRITE_RETRY, got: %s.\n", buf);
+ return false;
+ }
+
+ if (ERR_peek_error() != 0) {
+ fprintf(stderr, "Unexpected error following SSL_R_BAD_WRITE_RETRY.\n");
+ return false;
+ }
+
+ return true;
+}
+
+static bool TestSSLWriteRetry(bool is_dtls, const SSL_METHOD *method,
+ uint16_t version) {
+ if (is_dtls) {
+ return true;
+ }
+
+ for (bool enable_partial_write : std::vector<bool>{false, true}) {
+ // Connect a client and server.
+ bssl::UniquePtr<X509> cert = GetTestCertificate();
+ bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
+ bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(method));
+ bssl::UniquePtr<SSL> client, server;
+ if (!cert || !key || !ctx ||
+ !SSL_CTX_use_certificate(ctx.get(), cert.get()) ||
+ !SSL_CTX_use_PrivateKey(ctx.get(), key.get()) ||
+ !SSL_CTX_set_min_proto_version(ctx.get(), version) ||
+ !SSL_CTX_set_max_proto_version(ctx.get(), version) ||
+ !ConnectClientAndServer(&client, &server, ctx.get(), ctx.get(),
+ nullptr /* no session */)) {
+ return false;
+ }
+
+ if (enable_partial_write) {
+ SSL_set_mode(client.get(), SSL_MODE_ENABLE_PARTIAL_WRITE);
+ }
+
+ // Write without reading until the buffer is full and we have an unfinished
+ // write. Keep a count so we may reread it again later. "hello!" will be
+ // written in two chunks, "hello" and "!".
+ char data[] = "hello!";
+ static const int kChunkLen = 5; // The length of "hello".
+ unsigned count = 0;
+ for (;;) {
+ int ret = SSL_write(client.get(), data, kChunkLen);
+ if (ret <= 0) {
+ int err = SSL_get_error(client.get(), ret);
+ if (SSL_get_error(client.get(), ret) == SSL_ERROR_WANT_WRITE) {
+ break;
+ }
+ fprintf(stderr, "SSL_write failed in unexpected way: %d\n", err);
+ return false;
+ }
+
+ if (ret != 5) {
+ fprintf(stderr, "SSL_write wrote %d bytes, expected 5.\n", ret);
+ return false;
+ }
+
+ count++;
+ }
+
+ // Retrying with the same parameters is legal.
+ if (SSL_get_error(client.get(), SSL_write(client.get(), data, kChunkLen)) !=
+ SSL_ERROR_WANT_WRITE) {
+ fprintf(stderr, "SSL_write retry unexpectedly failed.\n");
+ return false;
+ }
+
+ // Retrying with the same buffer but shorter length is not legal.
+ if (SSL_get_error(client.get(),
+ SSL_write(client.get(), data, kChunkLen - 1)) !=
+ SSL_ERROR_SSL ||
+ !ExpectBadWriteRetry()) {
+ fprintf(stderr, "SSL_write retry did not fail as expected.\n");
+ return false;
+ }
+
+ // Retrying with a different buffer pointer is not legal.
+ char data2[] = "hello";
+ if (SSL_get_error(client.get(), SSL_write(client.get(), data2,
+ kChunkLen)) != SSL_ERROR_SSL ||
+ !ExpectBadWriteRetry()) {
+ fprintf(stderr, "SSL_write retry did not fail as expected.\n");
+ return false;
+ }
+
+ // With |SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER|, the buffer may move.
+ SSL_set_mode(client.get(), SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+ if (SSL_get_error(client.get(),
+ SSL_write(client.get(), data2, kChunkLen)) !=
+ SSL_ERROR_WANT_WRITE) {
+ fprintf(stderr, "SSL_write retry unexpectedly failed.\n");
+ return false;
+ }
+
+ // |SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER| does not disable length checks.
+ if (SSL_get_error(client.get(),
+ SSL_write(client.get(), data2, kChunkLen - 1)) !=
+ SSL_ERROR_SSL ||
+ !ExpectBadWriteRetry()) {
+ fprintf(stderr, "SSL_write retry did not fail as expected.\n");
+ return false;
+ }
+
+ // Retrying with a larger buffer is legal.
+ if (SSL_get_error(client.get(),
+ SSL_write(client.get(), data, kChunkLen + 1)) !=
+ SSL_ERROR_WANT_WRITE) {
+ fprintf(stderr, "SSL_write retry unexpectedly failed.\n");
+ return false;
+ }
+
+ // Drain the buffer.
+ char buf[20];
+ for (unsigned i = 0; i < count; i++) {
+ if (SSL_read(server.get(), buf, sizeof(buf)) != kChunkLen ||
+ OPENSSL_memcmp(buf, "hello", kChunkLen) != 0) {
+ fprintf(stderr, "Failed to read initial records.\n");
+ return false;
+ }
+ }
+
+ // Now that there is space, a retry with a larger buffer should flush the
+ // pending record, skip over that many bytes of input (on assumption they
+ // are the same), and write the remainder. If SSL_MODE_ENABLE_PARTIAL_WRITE
+ // is set, this will complete in two steps.
+ char data3[] = "_____!";
+ if (enable_partial_write) {
+ if (SSL_write(client.get(), data3, kChunkLen + 1) != kChunkLen ||
+ SSL_write(client.get(), data3 + kChunkLen, 1) != 1) {
+ fprintf(stderr, "SSL_write retry failed.\n");
+ return false;
+ }
+ } else if (SSL_write(client.get(), data3, kChunkLen + 1) != kChunkLen + 1) {
+ fprintf(stderr, "SSL_write retry failed.\n");
+ return false;
+ }
+
+ // Check the last write was correct. The data will be spread over two
+ // records, so SSL_read returns twice.
+ if (SSL_read(server.get(), buf, sizeof(buf)) != kChunkLen ||
+ OPENSSL_memcmp(buf, "hello", kChunkLen) != 0 ||
+ SSL_read(server.get(), buf, sizeof(buf)) != 1 ||
+ buf[0] != '!') {
+ fprintf(stderr, "Failed to read write retry.\n");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool ForEachVersion(bool (*test_func)(bool is_dtls,
+ const SSL_METHOD *method,
+ uint16_t version)) {
+ static uint16_t kTLSVersions[] = {
+ SSL3_VERSION,
+ TLS1_VERSION,
+ TLS1_1_VERSION,
+ TLS1_2_VERSION,
+// TLS 1.3 requires RSA-PSS, which is disabled for Android system builds.
+#if !defined(BORINGSSL_ANDROID_SYSTEM)
+ TLS1_3_VERSION,
+#endif
+ };
+
+ static uint16_t kDTLSVersions[] = {
+ DTLS1_VERSION, DTLS1_2_VERSION,
+ };
+
+ for (uint16_t version : kTLSVersions) {
+ if (!test_func(false, TLS_method(), version)) {
+ fprintf(stderr, "Test failed at TLS version %04x.\n", version);
+ return false;
+ }
+ }
+
+ for (uint16_t version : kDTLSVersions) {
+ if (!test_func(true, DTLS_method(), version)) {
+ fprintf(stderr, "Test failed at DTLS version %04x.\n", version);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+TEST(SSLTest, AddChainCertHack) {
+ // Ensure that we don't accidently break the hack that we have in place to
+ // keep curl and serf happy when they use an |X509| even after transfering
+ // ownership.
+
+ bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
+ ASSERT_TRUE(ctx);
+ X509 *cert = GetTestCertificate().release();
+ ASSERT_TRUE(cert);
+ SSL_CTX_add0_chain_cert(ctx.get(), cert);
+
+ // This should not trigger a use-after-free.
+ X509_cmp(cert, cert);
+}
+
+TEST(SSLTest, GetCertificate) {
+ bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
+ ASSERT_TRUE(ctx);
+ bssl::UniquePtr<X509> cert = GetTestCertificate();
+ ASSERT_TRUE(cert);
+ ASSERT_TRUE(SSL_CTX_use_certificate(ctx.get(), cert.get()));
+ bssl::UniquePtr<SSL> ssl(SSL_new(ctx.get()));
+ ASSERT_TRUE(ssl);
+
+ X509 *cert2 = SSL_CTX_get0_certificate(ctx.get());
+ ASSERT_TRUE(cert2);
+ X509 *cert3 = SSL_get_certificate(ssl.get());
+ ASSERT_TRUE(cert3);
+
+ // The old and new certificates must be identical.
+ EXPECT_EQ(0, X509_cmp(cert.get(), cert2));
+ EXPECT_EQ(0, X509_cmp(cert.get(), cert3));
+
+ uint8_t *der = nullptr;
+ long der_len = i2d_X509(cert.get(), &der);
+ ASSERT_LT(0, der_len);
+ bssl::UniquePtr<uint8_t> free_der(der);
+
+ uint8_t *der2 = nullptr;
+ long der2_len = i2d_X509(cert2, &der2);
+ ASSERT_LT(0, der2_len);
+ bssl::UniquePtr<uint8_t> free_der2(der2);
+
+ uint8_t *der3 = nullptr;
+ long der3_len = i2d_X509(cert3, &der3);
+ ASSERT_LT(0, der3_len);
+ bssl::UniquePtr<uint8_t> free_der3(der3);
+
+ // They must also encode identically.
+ EXPECT_EQ(Bytes(der, der_len), Bytes(der2, der2_len));
+ EXPECT_EQ(Bytes(der, der_len), Bytes(der3, der3_len));
+}
+
+TEST(SSLTest, SetChainAndKeyMismatch) {
+ bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_with_buffers_method()));
+ ASSERT_TRUE(ctx);
+
+ bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
+ ASSERT_TRUE(key);
+ bssl::UniquePtr<CRYPTO_BUFFER> leaf = GetChainTestCertificateBuffer();
+ ASSERT_TRUE(leaf);
+ std::vector<CRYPTO_BUFFER*> chain = {
+ leaf.get(),
+ };
+
+ // Should fail because |GetTestKey| doesn't match the chain-test certificate.
+ ASSERT_FALSE(SSL_CTX_set_chain_and_key(ctx.get(), &chain[0], chain.size(),
+ key.get(), nullptr));
+ ERR_clear_error();
+}
+
+TEST(SSLTest, SetChainAndKey) {
+ bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_with_buffers_method()));
+ ASSERT_TRUE(client_ctx);
+ bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(TLS_with_buffers_method()));
+ ASSERT_TRUE(server_ctx);
+
+ bssl::UniquePtr<EVP_PKEY> key = GetChainTestKey();
+ ASSERT_TRUE(key);
+ bssl::UniquePtr<CRYPTO_BUFFER> leaf = GetChainTestCertificateBuffer();
+ ASSERT_TRUE(leaf);
+ bssl::UniquePtr<CRYPTO_BUFFER> intermediate =
+ GetChainTestIntermediateBuffer();
+ ASSERT_TRUE(intermediate);
+ std::vector<CRYPTO_BUFFER*> chain = {
+ leaf.get(), intermediate.get(),
+ };
+ ASSERT_TRUE(SSL_CTX_set_chain_and_key(server_ctx.get(), &chain[0],
+ chain.size(), key.get(), nullptr));
+
+ SSL_CTX_i_promise_to_verify_certs_after_the_handshake(client_ctx.get());
+
+ bssl::UniquePtr<SSL> client, server;
+ ASSERT_TRUE(ConnectClientAndServer(&client, &server, client_ctx.get(),
+ server_ctx.get(),
+ nullptr /* no session */));
+}
+
+// Configuring the empty cipher list, though an error, should still modify the
+// configuration.
+TEST(SSLTest, EmptyCipherList) {
+ bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
+ ASSERT_TRUE(ctx);
+
+ // Initially, the cipher list is not empty.
+ EXPECT_NE(0u, sk_SSL_CIPHER_num(SSL_CTX_get_ciphers(ctx.get())));
+
+ // Configuring the empty cipher list fails.
+ EXPECT_FALSE(SSL_CTX_set_cipher_list(ctx.get(), ""));
+ ERR_clear_error();
+
+ // But the cipher list is still updated to empty.
+ EXPECT_EQ(0u, sk_SSL_CIPHER_num(SSL_CTX_get_ciphers(ctx.get())));
+}
+
+// ssl_test_ticket_aead_failure_mode enumerates the possible ways in which the
+// test |SSL_TICKET_AEAD_METHOD| can fail.
+enum ssl_test_ticket_aead_failure_mode {
+ ssl_test_ticket_aead_ok = 0,
+ ssl_test_ticket_aead_seal_fail,
+ ssl_test_ticket_aead_open_soft_fail,
+ ssl_test_ticket_aead_open_hard_fail,
+};
+
+struct ssl_test_ticket_aead_state {
+ unsigned retry_count;
+ ssl_test_ticket_aead_failure_mode failure_mode;
+};
+
+static int ssl_test_ticket_aead_ex_index_dup(CRYPTO_EX_DATA *to,
+ const CRYPTO_EX_DATA *from,
+ void **from_d, int index,
+ long argl, void *argp) {
+ abort();
+}
+
+static void ssl_test_ticket_aead_ex_index_free(void *parent, void *ptr,
+ CRYPTO_EX_DATA *ad, int index,
+ long argl, void *argp) {
+ auto state = reinterpret_cast<ssl_test_ticket_aead_state*>(ptr);
+ if (state == nullptr) {
+ return;
+ }
+
+ OPENSSL_free(state);
+}
+
+static CRYPTO_once_t g_ssl_test_ticket_aead_ex_index_once = CRYPTO_ONCE_INIT;
+static int g_ssl_test_ticket_aead_ex_index;
+
+static int ssl_test_ticket_aead_get_ex_index() {
+ CRYPTO_once(&g_ssl_test_ticket_aead_ex_index_once, [] {
+ g_ssl_test_ticket_aead_ex_index = SSL_get_ex_new_index(
+ 0, nullptr, nullptr, ssl_test_ticket_aead_ex_index_dup,
+ ssl_test_ticket_aead_ex_index_free);
+ });
+ return g_ssl_test_ticket_aead_ex_index;
+}
+
+static size_t ssl_test_ticket_aead_max_overhead(SSL *ssl) {
+ return 1;
+}
+
+static int ssl_test_ticket_aead_seal(SSL *ssl, uint8_t *out, size_t *out_len,
+ size_t max_out_len, const uint8_t *in,
+ size_t in_len) {
+ auto state = reinterpret_cast<ssl_test_ticket_aead_state *>(
+ SSL_get_ex_data(ssl, ssl_test_ticket_aead_get_ex_index()));
+
+ if (state->failure_mode == ssl_test_ticket_aead_seal_fail ||
+ max_out_len < in_len + 1) {
+ return 0;
+ }
+
+ OPENSSL_memmove(out, in, in_len);
+ out[in_len] = 0xff;
+ *out_len = in_len + 1;
+
+ return 1;
+}
+
+static ssl_ticket_aead_result_t ssl_test_ticket_aead_open(
+ SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out_len,
+ const uint8_t *in, size_t in_len) {
+ auto state = reinterpret_cast<ssl_test_ticket_aead_state *>(
+ SSL_get_ex_data(ssl, ssl_test_ticket_aead_get_ex_index()));
+
+ if (state->retry_count > 0) {
+ state->retry_count--;
+ return ssl_ticket_aead_retry;
+ }
+
+ switch (state->failure_mode) {
+ case ssl_test_ticket_aead_ok:
+ break;
+ case ssl_test_ticket_aead_seal_fail:
+ // If |seal| failed then there shouldn't be any ticket to try and
+ // decrypt.
+ abort();
+ break;
+ case ssl_test_ticket_aead_open_soft_fail:
+ return ssl_ticket_aead_ignore_ticket;
+ case ssl_test_ticket_aead_open_hard_fail:
+ return ssl_ticket_aead_error;
+ }
+
+ if (in_len == 0 || in[in_len - 1] != 0xff) {
+ return ssl_ticket_aead_ignore_ticket;
+ }
+
+ if (max_out_len < in_len - 1) {
+ return ssl_ticket_aead_error;
+ }
+
+ OPENSSL_memmove(out, in, in_len - 1);
+ *out_len = in_len - 1;
+ return ssl_ticket_aead_success;
+}
+
+static const SSL_TICKET_AEAD_METHOD kSSLTestTicketMethod = {
+ ssl_test_ticket_aead_max_overhead,
+ ssl_test_ticket_aead_seal,
+ ssl_test_ticket_aead_open,
+};
+
+static void ConnectClientAndServerWithTicketMethod(
+ bssl::UniquePtr<SSL> *out_client, bssl::UniquePtr<SSL> *out_server,
+ SSL_CTX *client_ctx, SSL_CTX *server_ctx, unsigned retry_count,
+ ssl_test_ticket_aead_failure_mode failure_mode, SSL_SESSION *session) {
+ bssl::UniquePtr<SSL> client(SSL_new(client_ctx)), server(SSL_new(server_ctx));
+ ASSERT_TRUE(client);
+ ASSERT_TRUE(server);
+ SSL_set_connect_state(client.get());
+ SSL_set_accept_state(server.get());
+
+ auto state = reinterpret_cast<ssl_test_ticket_aead_state *>(
+ OPENSSL_malloc(sizeof(ssl_test_ticket_aead_state)));
+ ASSERT_TRUE(state);
+ OPENSSL_memset(state, 0, sizeof(ssl_test_ticket_aead_state));
+ state->retry_count = retry_count;
+ state->failure_mode = failure_mode;
+
+ ASSERT_TRUE(SSL_set_ex_data(server.get(), ssl_test_ticket_aead_get_ex_index(),
+ state));
+
+ SSL_set_session(client.get(), session);
+
+ BIO *bio1, *bio2;
+ ASSERT_TRUE(BIO_new_bio_pair(&bio1, 0, &bio2, 0));
+
+ // SSL_set_bio takes ownership.
+ SSL_set_bio(client.get(), bio1, bio1);
+ SSL_set_bio(server.get(), bio2, bio2);
+
+ if (CompleteHandshakes(client.get(), server.get())) {
+ *out_client = std::move(client);
+ *out_server = std::move(server);
+ } else {
+ out_client->reset();
+ out_server->reset();
+ }
+}
+
+class TicketAEADMethodTest
+ : public ::testing::TestWithParam<testing::tuple<
+ uint16_t, unsigned, ssl_test_ticket_aead_failure_mode>> {};
+
+TEST_P(TicketAEADMethodTest, Resume) {
+ bssl::UniquePtr<X509> cert = GetTestCertificate();
+ ASSERT_TRUE(cert);
+ bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
+ ASSERT_TRUE(key);
+
+ bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(TLS_method()));
+ ASSERT_TRUE(server_ctx);
+ bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
+ ASSERT_TRUE(client_ctx);
+
+ const uint16_t version = testing::get<0>(GetParam());
+ const unsigned retry_count = testing::get<1>(GetParam());
+ const ssl_test_ticket_aead_failure_mode failure_mode =
+ testing::get<2>(GetParam());
+
+ ASSERT_TRUE(SSL_CTX_use_certificate(server_ctx.get(), cert.get()));
+ ASSERT_TRUE(SSL_CTX_use_PrivateKey(server_ctx.get(), key.get()));
+ ASSERT_TRUE(SSL_CTX_set_min_proto_version(client_ctx.get(), version));
+ ASSERT_TRUE(SSL_CTX_set_max_proto_version(client_ctx.get(), version));
+ ASSERT_TRUE(SSL_CTX_set_min_proto_version(server_ctx.get(), version));
+ ASSERT_TRUE(SSL_CTX_set_max_proto_version(server_ctx.get(), version));
+
+ SSL_CTX_set_session_cache_mode(client_ctx.get(), SSL_SESS_CACHE_BOTH);
+ SSL_CTX_set_session_cache_mode(server_ctx.get(), SSL_SESS_CACHE_BOTH);
+ SSL_CTX_set_current_time_cb(client_ctx.get(), FrozenTimeCallback);
+ SSL_CTX_set_current_time_cb(server_ctx.get(), FrozenTimeCallback);
+ SSL_CTX_sess_set_new_cb(client_ctx.get(), SaveLastSession);
+
+ SSL_CTX_set_ticket_aead_method(server_ctx.get(), &kSSLTestTicketMethod);
+
+ bssl::UniquePtr<SSL> client, server;
+ ConnectClientAndServerWithTicketMethod(&client, &server, client_ctx.get(),
+ server_ctx.get(), retry_count,
+ failure_mode, nullptr);
+ switch (failure_mode) {
+ case ssl_test_ticket_aead_ok:
+ case ssl_test_ticket_aead_open_hard_fail:
+ case ssl_test_ticket_aead_open_soft_fail:
+ ASSERT_TRUE(client);
+ break;
+ case ssl_test_ticket_aead_seal_fail:
+ EXPECT_FALSE(client);
+ return;
+ }
+ EXPECT_FALSE(SSL_session_reused(client.get()));
+ EXPECT_FALSE(SSL_session_reused(server.get()));
+
+ // Run the read loop to account for post-handshake tickets in TLS 1.3.
+ SSL_read(client.get(), nullptr, 0);
+
+ bssl::UniquePtr<SSL_SESSION> session = std::move(g_last_session);
+ ConnectClientAndServerWithTicketMethod(&client, &server, client_ctx.get(),
+ server_ctx.get(), retry_count,
+ failure_mode, session.get());
+ switch (failure_mode) {
+ case ssl_test_ticket_aead_ok:
+ ASSERT_TRUE(client);
+ EXPECT_TRUE(SSL_session_reused(client.get()));
+ EXPECT_TRUE(SSL_session_reused(server.get()));
+ break;
+ case ssl_test_ticket_aead_seal_fail:
+ abort();
+ break;
+ case ssl_test_ticket_aead_open_hard_fail:
+ EXPECT_FALSE(client);
+ break;
+ case ssl_test_ticket_aead_open_soft_fail:
+ ASSERT_TRUE(client);
+ EXPECT_FALSE(SSL_session_reused(client.get()));
+ EXPECT_FALSE(SSL_session_reused(server.get()));
+ }
+}
+
+INSTANTIATE_TEST_CASE_P(
+ TicketAEADMethodTests, TicketAEADMethodTest,
+ testing::Combine(
+ testing::Values(TLS1_2_VERSION, TLS1_3_VERSION),
+ testing::Values(0, 1, 2),
+ testing::Values(ssl_test_ticket_aead_ok,
+ ssl_test_ticket_aead_seal_fail,
+ ssl_test_ticket_aead_open_soft_fail,
+ ssl_test_ticket_aead_open_hard_fail)));
+
+// TODO(davidben): Convert this file to GTest properly.
+TEST(SSLTest, AllTests) {
+ if (!TestCipherRules() ||
+ !TestCurveRules() ||
+ !TestSSL_SESSIONEncoding(kOpenSSLSession) ||
+ !TestSSL_SESSIONEncoding(kCustomSession) ||
+ !TestSSL_SESSIONEncoding(kBoringSSLSession) ||
+ !TestBadSSL_SESSIONEncoding(kBadSessionExtraField) ||
+ !TestBadSSL_SESSIONEncoding(kBadSessionVersion) ||
+ !TestBadSSL_SESSIONEncoding(kBadSessionTrailingData) ||
+ // TODO(svaldez): Update this when TLS 1.3 is enabled by default.
+ !TestDefaultVersion(SSL3_VERSION, TLS1_2_VERSION, &TLS_method) ||
+ !TestDefaultVersion(SSL3_VERSION, SSL3_VERSION, &SSLv3_method) ||
+ !TestDefaultVersion(TLS1_VERSION, TLS1_VERSION, &TLSv1_method) ||
+ !TestDefaultVersion(TLS1_1_VERSION, TLS1_1_VERSION, &TLSv1_1_method) ||
+ !TestDefaultVersion(TLS1_2_VERSION, TLS1_2_VERSION, &TLSv1_2_method) ||
+ !TestDefaultVersion(TLS1_1_VERSION, TLS1_2_VERSION, &DTLS_method) ||
+ !TestDefaultVersion(TLS1_1_VERSION, TLS1_1_VERSION, &DTLSv1_method) ||
+ !TestDefaultVersion(TLS1_2_VERSION, TLS1_2_VERSION, &DTLSv1_2_method) ||
+ !TestCipherGetRFCName() ||
+ // Test the padding extension at TLS 1.2.
+ !TestPaddingExtension(TLS1_2_VERSION, TLS1_2_VERSION) ||
+ // Test the padding extension at TLS 1.3 with a TLS 1.2 session, so there
+ // will be no PSK binder after the padding extension.
+ !TestPaddingExtension(TLS1_3_VERSION, TLS1_2_VERSION) ||
+ // Test the padding extension at TLS 1.3 with a TLS 1.3 session, so there
+ // will be a PSK binder after the padding extension.
+ !TestPaddingExtension(TLS1_3_VERSION, TLS1_3_DRAFT_VERSION) ||
+ !TestInternalSessionCache() ||
+ !ForEachVersion(TestSequenceNumber) ||
+ !ForEachVersion(TestOneSidedShutdown) ||
+ !ForEachVersion(TestGetPeerCertificate) ||
+ !ForEachVersion(TestRetainOnlySHA256OfCerts) ||
+ !TestClientHello() ||
+ !ForEachVersion(TestSessionIDContext) ||
+ !ForEachVersion(TestSessionTimeout) ||
+ !ForEachVersion(TestSNICallback) ||
+ !ForEachVersion(TestVersion) ||
+ !ForEachVersion(TestALPNCipherAvailable) ||
+ !ForEachVersion(TestSSLClearSessionResumption) ||
+ !ForEachVersion(TestAutoChain) ||
+ !ForEachVersion(TestSSLWriteRetry)) {
+ ADD_FAILURE() << "Tests failed";
+ }
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_transcript.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_transcript.c
new file mode 100644
index 000000000..9cc37778c
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_transcript.c
@@ -0,0 +1,405 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2007 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* ====================================================================
+ * Copyright 2005 Nokia. All rights reserved.
+ *
+ * The portions of the attached software ("Contribution") is developed by
+ * Nokia Corporation and is licensed pursuant to the OpenSSL open source
+ * license.
+ *
+ * The Contribution, originally written by Mika Kousa and Pasi Eronen of
+ * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites
+ * support (see RFC 4279) to OpenSSL.
+ *
+ * No patent licenses or other rights except those expressly stated in
+ * the OpenSSL open source license shall be deemed granted or received
+ * expressly, by implication, estoppel, or otherwise.
+ *
+ * No assurances are provided by Nokia that the Contribution does not
+ * infringe the patent or other intellectual property rights of any third
+ * party or that the license provides you with all the necessary rights
+ * to make use of the Contribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN
+ * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA
+ * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY
+ * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
+ * OTHERWISE. */
+
+#include <openssl/ssl.h>
+
+#include <assert.h>
+#include <string.h>
+
+#include <openssl/buf.h>
+#include <openssl/digest.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/md5.h>
+#include <openssl/nid.h>
+#include <openssl/sha.h>
+
+#include "../crypto/internal.h"
+#include "internal.h"
+
+
+int SSL_TRANSCRIPT_init(SSL_TRANSCRIPT *transcript) {
+ SSL_TRANSCRIPT_cleanup(transcript);
+ transcript->buffer = BUF_MEM_new();
+ return transcript->buffer != NULL;
+}
+
+/* init_digest_with_data calls |EVP_DigestInit_ex| on |ctx| with |md| and then
+ * writes the data in |buf| to it. */
+static int init_digest_with_data(EVP_MD_CTX *ctx, const EVP_MD *md,
+ const BUF_MEM *buf) {
+ if (!EVP_DigestInit_ex(ctx, md, NULL)) {
+ return 0;
+ }
+ EVP_DigestUpdate(ctx, buf->data, buf->length);
+ return 1;
+}
+
+int SSL_TRANSCRIPT_init_hash(SSL_TRANSCRIPT *transcript, uint16_t version,
+ int algorithm_prf) {
+ const EVP_MD *md = ssl_get_handshake_digest(algorithm_prf, version);
+
+ /* To support SSL 3.0's Finished and CertificateVerify constructions,
+ * EVP_md5_sha1() is split into MD5 and SHA-1 halves. When SSL 3.0 is removed,
+ * we can simplify this. */
+ if (md == EVP_md5_sha1()) {
+ if (!init_digest_with_data(&transcript->md5, EVP_md5(),
+ transcript->buffer)) {
+ return 0;
+ }
+ md = EVP_sha1();
+ }
+
+ if (!init_digest_with_data(&transcript->hash, md, transcript->buffer)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+void SSL_TRANSCRIPT_cleanup(SSL_TRANSCRIPT *transcript) {
+ SSL_TRANSCRIPT_free_buffer(transcript);
+ EVP_MD_CTX_cleanup(&transcript->hash);
+ EVP_MD_CTX_cleanup(&transcript->md5);
+}
+
+void SSL_TRANSCRIPT_free_buffer(SSL_TRANSCRIPT *transcript) {
+ BUF_MEM_free(transcript->buffer);
+ transcript->buffer = NULL;
+}
+
+size_t SSL_TRANSCRIPT_digest_len(const SSL_TRANSCRIPT *transcript) {
+ return EVP_MD_size(SSL_TRANSCRIPT_md(transcript));
+}
+
+const EVP_MD *SSL_TRANSCRIPT_md(const SSL_TRANSCRIPT *transcript) {
+ if (EVP_MD_CTX_md(&transcript->md5) != NULL) {
+ return EVP_md5_sha1();
+ }
+ return EVP_MD_CTX_md(&transcript->hash);
+}
+
+int SSL_TRANSCRIPT_update(SSL_TRANSCRIPT *transcript, const uint8_t *in,
+ size_t in_len) {
+ /* Depending on the state of the handshake, either the handshake buffer may be
+ * active, the rolling hash, or both. */
+ if (transcript->buffer != NULL) {
+ size_t new_len = transcript->buffer->length + in_len;
+ if (new_len < in_len) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
+ return 0;
+ }
+ if (!BUF_MEM_grow(transcript->buffer, new_len)) {
+ return 0;
+ }
+ OPENSSL_memcpy(transcript->buffer->data + new_len - in_len, in, in_len);
+ }
+
+ if (EVP_MD_CTX_md(&transcript->hash) != NULL) {
+ EVP_DigestUpdate(&transcript->hash, in, in_len);
+ }
+ if (EVP_MD_CTX_md(&transcript->md5) != NULL) {
+ EVP_DigestUpdate(&transcript->md5, in, in_len);
+ }
+
+ return 1;
+}
+
+int SSL_TRANSCRIPT_get_hash(const SSL_TRANSCRIPT *transcript, uint8_t *out,
+ size_t *out_len) {
+ int ret = 0;
+ EVP_MD_CTX ctx;
+ EVP_MD_CTX_init(&ctx);
+ unsigned md5_len = 0;
+ if (EVP_MD_CTX_md(&transcript->md5) != NULL) {
+ if (!EVP_MD_CTX_copy_ex(&ctx, &transcript->md5) ||
+ !EVP_DigestFinal_ex(&ctx, out, &md5_len)) {
+ goto err;
+ }
+ }
+
+ unsigned len;
+ if (!EVP_MD_CTX_copy_ex(&ctx, &transcript->hash) ||
+ !EVP_DigestFinal_ex(&ctx, out + md5_len, &len)) {
+ goto err;
+ }
+
+ *out_len = md5_len + len;
+ ret = 1;
+
+err:
+ EVP_MD_CTX_cleanup(&ctx);
+ return ret;
+}
+
+static int ssl3_handshake_mac(SSL_TRANSCRIPT *transcript,
+ const SSL_SESSION *session,
+ const EVP_MD_CTX *ctx_template,
+ const char *sender, size_t sender_len,
+ uint8_t *p, size_t *out_len) {
+ unsigned int len;
+ size_t npad, n;
+ unsigned int i;
+ uint8_t md_buf[EVP_MAX_MD_SIZE];
+ EVP_MD_CTX ctx;
+
+ EVP_MD_CTX_init(&ctx);
+ if (!EVP_MD_CTX_copy_ex(&ctx, ctx_template)) {
+ EVP_MD_CTX_cleanup(&ctx);
+ OPENSSL_PUT_ERROR(SSL, ERR_LIB_EVP);
+ return 0;
+ }
+
+ static const uint8_t kPad1[48] = {
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ };
+
+ static const uint8_t kPad2[48] = {
+ 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+ 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+ 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+ 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+ };
+
+ n = EVP_MD_CTX_size(&ctx);
+
+ npad = (48 / n) * n;
+ if (sender != NULL) {
+ EVP_DigestUpdate(&ctx, sender, sender_len);
+ }
+ EVP_DigestUpdate(&ctx, session->master_key, session->master_key_length);
+ EVP_DigestUpdate(&ctx, kPad1, npad);
+ EVP_DigestFinal_ex(&ctx, md_buf, &i);
+
+ if (!EVP_DigestInit_ex(&ctx, EVP_MD_CTX_md(&ctx), NULL)) {
+ EVP_MD_CTX_cleanup(&ctx);
+ OPENSSL_PUT_ERROR(SSL, ERR_LIB_EVP);
+ return 0;
+ }
+ EVP_DigestUpdate(&ctx, session->master_key, session->master_key_length);
+ EVP_DigestUpdate(&ctx, kPad2, npad);
+ EVP_DigestUpdate(&ctx, md_buf, i);
+ EVP_DigestFinal_ex(&ctx, p, &len);
+
+ EVP_MD_CTX_cleanup(&ctx);
+
+ *out_len = len;
+ return 1;
+}
+
+int SSL_TRANSCRIPT_ssl3_cert_verify_hash(SSL_TRANSCRIPT *transcript,
+ uint8_t *out, size_t *out_len,
+ const SSL_SESSION *session,
+ int signature_algorithm) {
+ if (SSL_TRANSCRIPT_md(transcript) != EVP_md5_sha1()) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ if (signature_algorithm == SSL_SIGN_RSA_PKCS1_MD5_SHA1) {
+ size_t md5_len, len;
+ if (!ssl3_handshake_mac(transcript, session, &transcript->md5, NULL, 0, out,
+ &md5_len) ||
+ !ssl3_handshake_mac(transcript, session, &transcript->hash, NULL, 0,
+ out + md5_len, &len)) {
+ return 0;
+ }
+ *out_len = md5_len + len;
+ return 1;
+ }
+
+ if (signature_algorithm == SSL_SIGN_ECDSA_SHA1) {
+ return ssl3_handshake_mac(transcript, session, &transcript->hash, NULL, 0,
+ out, out_len);
+ }
+
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return 0;
+}
+
+int SSL_TRANSCRIPT_finish_mac(SSL_TRANSCRIPT *transcript, uint8_t *out,
+ size_t *out_len, const SSL_SESSION *session,
+ int from_server, uint16_t version) {
+ if (version == SSL3_VERSION) {
+ if (SSL_TRANSCRIPT_md(transcript) != EVP_md5_sha1()) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ const char *sender = from_server ? SSL3_MD_SERVER_FINISHED_CONST
+ : SSL3_MD_CLIENT_FINISHED_CONST;
+ const size_t sender_len = 4;
+ size_t md5_len, len;
+ if (!ssl3_handshake_mac(transcript, session, &transcript->md5, sender,
+ sender_len, out, &md5_len) ||
+ !ssl3_handshake_mac(transcript, session, &transcript->hash, sender,
+ sender_len, out + md5_len, &len)) {
+ return 0;
+ }
+
+ *out_len = md5_len + len;
+ return 1;
+ }
+
+ /* At this point, the handshake should have released the handshake buffer on
+ * its own. */
+ assert(transcript->buffer == NULL);
+
+ const char *label = TLS_MD_CLIENT_FINISH_CONST;
+ size_t label_len = TLS_MD_SERVER_FINISH_CONST_SIZE;
+ if (from_server) {
+ label = TLS_MD_SERVER_FINISH_CONST;
+ label_len = TLS_MD_SERVER_FINISH_CONST_SIZE;
+ }
+
+ uint8_t digests[EVP_MAX_MD_SIZE];
+ size_t digests_len;
+ if (!SSL_TRANSCRIPT_get_hash(transcript, digests, &digests_len)) {
+ return 0;
+ }
+
+ static const size_t kFinishedLen = 12;
+ if (!tls1_prf(SSL_TRANSCRIPT_md(transcript), out, kFinishedLen,
+ session->master_key, session->master_key_length, label,
+ label_len, digests, digests_len, NULL, 0)) {
+ return 0;
+ }
+
+ *out_len = kFinishedLen;
+ return 1;
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_x509.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_x509.c
new file mode 100644
index 000000000..65405aafd
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/ssl_x509.c
@@ -0,0 +1,1344 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2007 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ * ECC cipher suite support in OpenSSL originally developed by
+ * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
+ */
+/* ====================================================================
+ * Copyright 2005 Nokia. All rights reserved.
+ *
+ * The portions of the attached software ("Contribution") is developed by
+ * Nokia Corporation and is licensed pursuant to the OpenSSL open source
+ * license.
+ *
+ * The Contribution, originally written by Mika Kousa and Pasi Eronen of
+ * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites
+ * support (see RFC 4279) to OpenSSL.
+ *
+ * No patent licenses or other rights except those expressly stated in
+ * the OpenSSL open source license shall be deemed granted or received
+ * expressly, by implication, estoppel, or otherwise.
+ *
+ * No assurances are provided by Nokia that the Contribution does not
+ * infringe the patent or other intellectual property rights of any third
+ * party or that the license provides you with all the necessary rights
+ * to make use of the Contribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN
+ * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA
+ * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY
+ * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
+ * OTHERWISE. */
+
+#include <openssl/ssl.h>
+
+#include <assert.h>
+
+#include <openssl/asn1.h>
+#include <openssl/bytestring.h>
+#include <openssl/err.h>
+#include <openssl/pem.h>
+#include <openssl/stack.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/x509_vfy.h>
+
+#include "internal.h"
+#include "../crypto/internal.h"
+
+
+/* check_ssl_x509_method asserts that |ssl| has the X509-based method
+ * installed. Calling an X509-based method on an |ssl| with a different method
+ * will likely misbehave and possibly crash or leak memory. */
+static void check_ssl_x509_method(const SSL *ssl) {
+ assert(ssl == NULL || ssl->ctx->x509_method == &ssl_crypto_x509_method);
+}
+
+/* check_ssl_ctx_x509_method acts like |check_ssl_x509_method|, but for an
+ * |SSL_CTX|. */
+static void check_ssl_ctx_x509_method(const SSL_CTX *ctx) {
+ assert(ctx == NULL || ctx->x509_method == &ssl_crypto_x509_method);
+}
+
+X509 *SSL_get_peer_certificate(const SSL *ssl) {
+ check_ssl_x509_method(ssl);
+ if (ssl == NULL) {
+ return NULL;
+ }
+ SSL_SESSION *session = SSL_get_session(ssl);
+ if (session == NULL || session->x509_peer == NULL) {
+ return NULL;
+ }
+ X509_up_ref(session->x509_peer);
+ return session->x509_peer;
+}
+
+STACK_OF(X509) *SSL_get_peer_cert_chain(const SSL *ssl) {
+ check_ssl_x509_method(ssl);
+ if (ssl == NULL) {
+ return NULL;
+ }
+ SSL_SESSION *session = SSL_get_session(ssl);
+ if (session == NULL ||
+ session->x509_chain == NULL) {
+ return NULL;
+ }
+
+ if (!ssl->server) {
+ return session->x509_chain;
+ }
+
+ /* OpenSSL historically didn't include the leaf certificate in the returned
+ * certificate chain, but only for servers. */
+ if (session->x509_chain_without_leaf == NULL) {
+ session->x509_chain_without_leaf = sk_X509_new_null();
+ if (session->x509_chain_without_leaf == NULL) {
+ return NULL;
+ }
+
+ for (size_t i = 1; i < sk_X509_num(session->x509_chain); i++) {
+ X509 *cert = sk_X509_value(session->x509_chain, i);
+ if (!sk_X509_push(session->x509_chain_without_leaf, cert)) {
+ sk_X509_pop_free(session->x509_chain_without_leaf, X509_free);
+ session->x509_chain_without_leaf = NULL;
+ return NULL;
+ }
+ X509_up_ref(cert);
+ }
+ }
+
+ return session->x509_chain_without_leaf;
+}
+
+STACK_OF(X509) *SSL_get_peer_full_cert_chain(const SSL *ssl) {
+ check_ssl_x509_method(ssl);
+ SSL_SESSION *session = SSL_get_session(ssl);
+ if (session == NULL) {
+ return NULL;
+ }
+
+ return session->x509_chain;
+}
+
+int SSL_CTX_set_purpose(SSL_CTX *ctx, int purpose) {
+ check_ssl_ctx_x509_method(ctx);
+ return X509_VERIFY_PARAM_set_purpose(ctx->param, purpose);
+}
+
+int SSL_set_purpose(SSL *ssl, int purpose) {
+ check_ssl_x509_method(ssl);
+ return X509_VERIFY_PARAM_set_purpose(ssl->param, purpose);
+}
+
+int SSL_CTX_set_trust(SSL_CTX *ctx, int trust) {
+ check_ssl_ctx_x509_method(ctx);
+ return X509_VERIFY_PARAM_set_trust(ctx->param, trust);
+}
+
+int SSL_set_trust(SSL *ssl, int trust) {
+ check_ssl_x509_method(ssl);
+ return X509_VERIFY_PARAM_set_trust(ssl->param, trust);
+}
+
+int SSL_CTX_set1_param(SSL_CTX *ctx, const X509_VERIFY_PARAM *param) {
+ check_ssl_ctx_x509_method(ctx);
+ return X509_VERIFY_PARAM_set1(ctx->param, param);
+}
+
+int SSL_set1_param(SSL *ssl, const X509_VERIFY_PARAM *param) {
+ check_ssl_x509_method(ssl);
+ return X509_VERIFY_PARAM_set1(ssl->param, param);
+}
+
+X509_VERIFY_PARAM *SSL_CTX_get0_param(SSL_CTX *ctx) {
+ check_ssl_ctx_x509_method(ctx);
+ return ctx->param;
+}
+
+X509_VERIFY_PARAM *SSL_get0_param(SSL *ssl) {
+ check_ssl_x509_method(ssl);
+ return ssl->param;
+}
+
+int SSL_get_verify_depth(const SSL *ssl) {
+ check_ssl_x509_method(ssl);
+ return X509_VERIFY_PARAM_get_depth(ssl->param);
+}
+
+int (*SSL_get_verify_callback(const SSL *ssl))(int, X509_STORE_CTX *) {
+ check_ssl_x509_method(ssl);
+ return ssl->verify_callback;
+}
+
+int SSL_CTX_get_verify_mode(const SSL_CTX *ctx) {
+ check_ssl_ctx_x509_method(ctx);
+ return ctx->verify_mode;
+}
+
+int SSL_CTX_get_verify_depth(const SSL_CTX *ctx) {
+ check_ssl_ctx_x509_method(ctx);
+ return X509_VERIFY_PARAM_get_depth(ctx->param);
+}
+
+int (*SSL_CTX_get_verify_callback(const SSL_CTX *ctx))(
+ int ok, X509_STORE_CTX *store_ctx) {
+ check_ssl_ctx_x509_method(ctx);
+ return ctx->default_verify_callback;
+}
+
+void SSL_set_verify(SSL *ssl, int mode,
+ int (*callback)(int ok, X509_STORE_CTX *store_ctx)) {
+ check_ssl_x509_method(ssl);
+ ssl->verify_mode = mode;
+ if (callback != NULL) {
+ ssl->verify_callback = callback;
+ }
+}
+
+void SSL_set_verify_depth(SSL *ssl, int depth) {
+ check_ssl_x509_method(ssl);
+ X509_VERIFY_PARAM_set_depth(ssl->param, depth);
+}
+
+void SSL_CTX_set_cert_verify_callback(SSL_CTX *ctx,
+ int (*cb)(X509_STORE_CTX *store_ctx,
+ void *arg),
+ void *arg) {
+ check_ssl_ctx_x509_method(ctx);
+ ctx->app_verify_callback = cb;
+ ctx->app_verify_arg = arg;
+}
+
+void SSL_CTX_set_verify(SSL_CTX *ctx, int mode,
+ int (*cb)(int, X509_STORE_CTX *)) {
+ check_ssl_ctx_x509_method(ctx);
+ ctx->verify_mode = mode;
+ ctx->default_verify_callback = cb;
+}
+
+void SSL_CTX_set_verify_depth(SSL_CTX *ctx, int depth) {
+ check_ssl_ctx_x509_method(ctx);
+ X509_VERIFY_PARAM_set_depth(ctx->param, depth);
+}
+
+int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx) {
+ check_ssl_ctx_x509_method(ctx);
+ return X509_STORE_set_default_paths(ctx->cert_store);
+}
+
+int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *ca_file,
+ const char *ca_dir) {
+ check_ssl_ctx_x509_method(ctx);
+ return X509_STORE_load_locations(ctx->cert_store, ca_file, ca_dir);
+}
+
+void SSL_set_verify_result(SSL *ssl, long result) {
+ check_ssl_x509_method(ssl);
+ if (result != X509_V_OK) {
+ abort();
+ }
+}
+
+long SSL_get_verify_result(const SSL *ssl) {
+ check_ssl_x509_method(ssl);
+ SSL_SESSION *session = SSL_get_session(ssl);
+ if (session == NULL) {
+ return X509_V_ERR_INVALID_CALL;
+ }
+ return session->verify_result;
+}
+
+X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *ctx) {
+ check_ssl_ctx_x509_method(ctx);
+ return ctx->cert_store;
+}
+
+void SSL_CTX_set_cert_store(SSL_CTX *ctx, X509_STORE *store) {
+ check_ssl_ctx_x509_method(ctx);
+ X509_STORE_free(ctx->cert_store);
+ ctx->cert_store = store;
+}
+
+/* x509_to_buffer returns a |CRYPTO_BUFFER| that contains the serialised
+ * contents of |x509|. */
+static 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);
+ OPENSSL_free(buf);
+
+ return buffer;
+}
+
+/* new_leafless_chain returns a fresh stack of buffers set to {NULL}. */
+static STACK_OF(CRYPTO_BUFFER) *new_leafless_chain(void) {
+ STACK_OF(CRYPTO_BUFFER) *chain = sk_CRYPTO_BUFFER_new_null();
+ if (chain == NULL) {
+ return NULL;
+ }
+
+ if (!sk_CRYPTO_BUFFER_push(chain, NULL)) {
+ sk_CRYPTO_BUFFER_free(chain);
+ return NULL;
+ }
+
+ return chain;
+}
+
+/* ssl_cert_set_chain sets elements 1.. of |cert->chain| to the serialised
+ * forms of elements of |chain|. It returns one on success or zero on error, in
+ * 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;
+
+ if (cert->chain != NULL) {
+ new_chain = sk_CRYPTO_BUFFER_new_null();
+ if (new_chain == NULL) {
+ return 0;
+ }
+
+ CRYPTO_BUFFER *leaf = sk_CRYPTO_BUFFER_value(cert->chain, 0);
+ if (!sk_CRYPTO_BUFFER_push(new_chain, leaf)) {
+ goto err;
+ }
+ /* |leaf| might be NULL if it's a “leafless” chain. */
+ if (leaf != NULL) {
+ CRYPTO_BUFFER_up_ref(leaf);
+ }
+ }
+
+ 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;
+ }
+ }
+
+ 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;
+ }
+ }
+
+ sk_CRYPTO_BUFFER_pop_free(cert->chain, CRYPTO_BUFFER_free);
+ cert->chain = new_chain;
+
+ 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) {
+ X509_free(cert->x509_leaf);
+ cert->x509_leaf = NULL;
+}
+
+static void ssl_crypto_x509_cert_flush_cached_chain(CERT *cert) {
+ sk_X509_pop_free(cert->x509_chain, X509_free);
+ cert->x509_chain = NULL;
+}
+
+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);
+ 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) +
+ CRYPTO_BUFFER_len(buffer);
+ X509_NAME_free(name);
+ if (!ok) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static void ssl_crypto_x509_cert_clear(CERT *cert) {
+ ssl_crypto_x509_cert_flush_cached_leaf(cert);
+ ssl_crypto_x509_cert_flush_cached_chain(cert);
+
+ X509_free(cert->x509_stash);
+ cert->x509_stash = NULL;
+}
+
+static void ssl_crypto_x509_cert_free(CERT *cert) {
+ ssl_crypto_x509_cert_clear(cert);
+ X509_STORE_free(cert->verify_store);
+}
+
+static void ssl_crypto_x509_cert_dup(CERT *new_cert, const CERT *cert) {
+ if (cert->verify_store != NULL) {
+ X509_STORE_up_ref(cert->verify_store);
+ new_cert->verify_store = cert->verify_store;
+ }
+}
+
+static int ssl_crypto_x509_session_cache_objects(SSL_SESSION *sess) {
+ STACK_OF(X509) *chain = NULL;
+ const size_t num_certs = sk_CRYPTO_BUFFER_num(sess->certs);
+
+ if (num_certs > 0) {
+ chain = sk_X509_new_null();
+ if (chain == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ }
+
+ 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) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ goto err;
+ }
+ if (!sk_X509_push(chain, x509)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ X509_free(x509);
+ goto err;
+ }
+ if (i == 0) {
+ leaf = x509;
+ }
+ }
+
+ sk_X509_pop_free(sess->x509_chain, X509_free);
+ sess->x509_chain = chain;
+ sk_X509_pop_free(sess->x509_chain_without_leaf, X509_free);
+ sess->x509_chain_without_leaf = NULL;
+
+ X509_free(sess->x509_peer);
+ if (leaf != NULL) {
+ X509_up_ref(leaf);
+ }
+ sess->x509_peer = leaf;
+
+ return 1;
+
+err:
+ sk_X509_pop_free(chain, X509_free);
+ return 0;
+}
+
+static int ssl_crypto_x509_session_dup(SSL_SESSION *new_session,
+ const SSL_SESSION *session) {
+ if (session->x509_peer != NULL) {
+ X509_up_ref(session->x509_peer);
+ new_session->x509_peer = session->x509_peer;
+ }
+ if (session->x509_chain != NULL) {
+ new_session->x509_chain = X509_chain_up_ref(session->x509_chain);
+ if (new_session->x509_chain == NULL) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static void ssl_crypto_x509_session_clear(SSL_SESSION *session) {
+ X509_free(session->x509_peer);
+ session->x509_peer = NULL;
+ sk_X509_pop_free(session->x509_chain, X509_free);
+ session->x509_chain = NULL;
+ sk_X509_pop_free(session->x509_chain_without_leaf, X509_free);
+ session->x509_chain_without_leaf = NULL;
+}
+
+static int ssl_verify_alarm_type(long type) {
+ switch (type) {
+ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
+ case X509_V_ERR_UNABLE_TO_GET_CRL:
+ case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER:
+ return SSL_AD_UNKNOWN_CA;
+
+ case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
+ case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
+ case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
+ case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
+ case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
+ case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
+ case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
+ case X509_V_ERR_CERT_NOT_YET_VALID:
+ case X509_V_ERR_CRL_NOT_YET_VALID:
+ case X509_V_ERR_CERT_UNTRUSTED:
+ case X509_V_ERR_CERT_REJECTED:
+ case X509_V_ERR_HOSTNAME_MISMATCH:
+ case X509_V_ERR_EMAIL_MISMATCH:
+ case X509_V_ERR_IP_ADDRESS_MISMATCH:
+ return SSL_AD_BAD_CERTIFICATE;
+
+ case X509_V_ERR_CERT_SIGNATURE_FAILURE:
+ case X509_V_ERR_CRL_SIGNATURE_FAILURE:
+ return SSL_AD_DECRYPT_ERROR;
+
+ case X509_V_ERR_CERT_HAS_EXPIRED:
+ case X509_V_ERR_CRL_HAS_EXPIRED:
+ return SSL_AD_CERTIFICATE_EXPIRED;
+
+ case X509_V_ERR_CERT_REVOKED:
+ return SSL_AD_CERTIFICATE_REVOKED;
+
+ case X509_V_ERR_UNSPECIFIED:
+ case X509_V_ERR_OUT_OF_MEM:
+ case X509_V_ERR_INVALID_CALL:
+ case X509_V_ERR_STORE_LOOKUP:
+ return SSL_AD_INTERNAL_ERROR;
+
+ case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
+ case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
+ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
+ case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
+ case X509_V_ERR_CERT_CHAIN_TOO_LONG:
+ case X509_V_ERR_PATH_LENGTH_EXCEEDED:
+ case X509_V_ERR_INVALID_CA:
+ return SSL_AD_UNKNOWN_CA;
+
+ case X509_V_ERR_APPLICATION_VERIFICATION:
+ return SSL_AD_HANDSHAKE_FAILURE;
+
+ case X509_V_ERR_INVALID_PURPOSE:
+ return SSL_AD_UNSUPPORTED_CERTIFICATE;
+
+ default:
+ return SSL_AD_CERTIFICATE_UNKNOWN;
+ }
+}
+
+static int ssl_crypto_x509_session_verify_cert_chain(SSL_SESSION *session,
+ SSL *ssl) {
+ STACK_OF(X509) *const cert_chain = session->x509_chain;
+ if (cert_chain == NULL || sk_X509_num(cert_chain) == 0) {
+ return 0;
+ }
+
+ X509_STORE *verify_store = ssl->ctx->cert_store;
+ if (ssl->cert->verify_store != NULL) {
+ verify_store = ssl->cert->verify_store;
+ }
+
+ 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)) {
+ 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;
+ }
+
+ /* 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");
+
+ /* Anything non-default in "param" should overwrite anything in the ctx. */
+ X509_VERIFY_PARAM_set1(X509_STORE_CTX_get0_param(&ctx), ssl->param);
+
+ if (ssl->verify_callback) {
+ X509_STORE_CTX_set_verify_cb(&ctx, 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);
+ } else {
+ verify_ret = X509_verify_cert(&ctx);
+ }
+
+ 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) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, ssl_verify_alarm_type(ctx.error));
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CERTIFICATE_VERIFY_FAILED);
+ goto err;
+ }
+
+ ERR_clear_error();
+ ret = 1;
+
+err:
+ X509_STORE_CTX_cleanup(&ctx);
+ return ret;
+}
+
+static void ssl_crypto_x509_hs_flush_cached_ca_names(SSL_HANDSHAKE *hs) {
+ sk_X509_NAME_pop_free(hs->cached_x509_ca_names, X509_NAME_free);
+ hs->cached_x509_ca_names = NULL;
+}
+
+static int ssl_crypto_x509_ssl_new(SSL *ssl) {
+ ssl->param = X509_VERIFY_PARAM_new();
+ if (ssl->param == NULL) {
+ return 0;
+ }
+ X509_VERIFY_PARAM_inherit(ssl->param, ssl->ctx->param);
+ return 1;
+}
+
+static void ssl_crypto_x509_ssl_flush_cached_client_CA(SSL *ssl) {
+ sk_X509_NAME_pop_free(ssl->cached_x509_client_CA, X509_NAME_free);
+ ssl->cached_x509_client_CA = NULL;
+}
+
+static void ssl_crypto_x509_ssl_free(SSL *ssl) {
+ ssl_crypto_x509_ssl_flush_cached_client_CA(ssl);
+ X509_VERIFY_PARAM_free(ssl->param);
+}
+
+static int ssl_crypto_x509_ssl_auto_chain_if_needed(SSL *ssl) {
+ /* Only build a chain if there are no intermediates configured and the feature
+ * isn't disabled. */
+ if ((ssl->mode & SSL_MODE_NO_AUTO_CHAIN) ||
+ !ssl_has_certificate(ssl) ||
+ ssl->cert->chain == NULL ||
+ sk_CRYPTO_BUFFER_num(ssl->cert->chain) > 1) {
+ return 1;
+ }
+
+ 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);
+ 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);
+ ERR_clear_error();
+
+ /* Remove the leaf from the generated 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) {
+ return 0;
+ }
+
+ ssl_crypto_x509_cert_flush_cached_chain(ssl->cert);
+
+ return 1;
+}
+
+static void ssl_crypto_x509_ssl_ctx_flush_cached_client_CA(SSL_CTX *ctx) {
+ sk_X509_NAME_pop_free(ctx->cached_x509_client_CA, X509_NAME_free);
+ ctx->cached_x509_client_CA = NULL;
+}
+
+static int ssl_crypto_x509_ssl_ctx_new(SSL_CTX *ctx) {
+ ctx->cert_store = X509_STORE_new();
+ ctx->param = X509_VERIFY_PARAM_new();
+ return (ctx->cert_store != NULL && ctx->param != NULL);
+}
+
+static void ssl_crypto_x509_ssl_ctx_free(SSL_CTX *ctx) {
+ ssl_crypto_x509_ssl_ctx_flush_cached_client_CA(ctx);
+ X509_VERIFY_PARAM_free(ctx->param);
+ X509_STORE_free(ctx->cert_store);
+}
+
+const SSL_X509_METHOD ssl_crypto_x509_method = {
+ ssl_crypto_x509_check_client_CA_list,
+ ssl_crypto_x509_cert_clear,
+ ssl_crypto_x509_cert_free,
+ ssl_crypto_x509_cert_dup,
+ ssl_crypto_x509_cert_flush_cached_chain,
+ ssl_crypto_x509_cert_flush_cached_leaf,
+ ssl_crypto_x509_session_cache_objects,
+ ssl_crypto_x509_session_dup,
+ ssl_crypto_x509_session_clear,
+ ssl_crypto_x509_session_verify_cert_chain,
+ ssl_crypto_x509_hs_flush_cached_ca_names,
+ ssl_crypto_x509_ssl_new,
+ ssl_crypto_x509_ssl_free,
+ ssl_crypto_x509_ssl_flush_cached_client_CA,
+ ssl_crypto_x509_ssl_auto_chain_if_needed,
+ ssl_crypto_x509_ssl_ctx_new,
+ ssl_crypto_x509_ssl_ctx_free,
+ ssl_crypto_x509_ssl_ctx_flush_cached_client_CA,
+};
+
+static int ssl_use_certificate(CERT *cert, X509 *x) {
+ if (x == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
+
+ CRYPTO_BUFFER *buffer = x509_to_buffer(x);
+ if (buffer == NULL) {
+ return 0;
+ }
+
+ const int ok = ssl_set_cert(cert, buffer);
+ CRYPTO_BUFFER_free(buffer);
+ return ok;
+}
+
+int SSL_use_certificate(SSL *ssl, X509 *x) {
+ check_ssl_x509_method(ssl);
+ return ssl_use_certificate(ssl->cert, x);
+}
+
+int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x) {
+ check_ssl_ctx_x509_method(ctx);
+ return ssl_use_certificate(ctx->cert, x);
+}
+
+/* ssl_cert_cache_leaf_cert sets |cert->x509_leaf|, if currently NULL, from the
+ * first element of |cert->chain|. */
+static int ssl_cert_cache_leaf_cert(CERT *cert) {
+ assert(cert->x509_method);
+
+ if (cert->x509_leaf != NULL ||
+ cert->chain == NULL) {
+ return 1;
+ }
+
+ CRYPTO_BUFFER *leaf = sk_CRYPTO_BUFFER_value(cert->chain, 0);
+ if (!leaf) {
+ return 1;
+ }
+
+ cert->x509_leaf = X509_parse_from_buffer(leaf);
+ return cert->x509_leaf != NULL;
+}
+
+static X509 *ssl_cert_get0_leaf(CERT *cert) {
+ if (cert->x509_leaf == NULL &&
+ !ssl_cert_cache_leaf_cert(cert)) {
+ return NULL;
+ }
+
+ return cert->x509_leaf;
+}
+
+X509 *SSL_get_certificate(const SSL *ssl) {
+ check_ssl_x509_method(ssl);
+ return ssl_cert_get0_leaf(ssl->cert);
+}
+
+X509 *SSL_CTX_get0_certificate(const SSL_CTX *ctx) {
+ check_ssl_ctx_x509_method(ctx);
+ CRYPTO_MUTEX_lock_write((CRYPTO_MUTEX *) &ctx->lock);
+ X509 *ret = ssl_cert_get0_leaf(ctx->cert);
+ CRYPTO_MUTEX_unlock_write((CRYPTO_MUTEX *) &ctx->lock);
+ return ret;
+}
+
+static int ssl_cert_set0_chain(CERT *cert, STACK_OF(X509) *chain) {
+ if (!ssl_cert_set_chain(cert, chain)) {
+ return 0;
+ }
+
+ sk_X509_pop_free(chain, X509_free);
+ ssl_crypto_x509_cert_flush_cached_chain(cert);
+ return 1;
+}
+
+static int ssl_cert_set1_chain(CERT *cert, STACK_OF(X509) *chain) {
+ if (!ssl_cert_set_chain(cert, chain)) {
+ return 0;
+ }
+
+ ssl_crypto_x509_cert_flush_cached_chain(cert);
+ return 1;
+}
+
+static int ssl_cert_append_cert(CERT *cert, X509 *x509) {
+ assert(cert->x509_method);
+
+ CRYPTO_BUFFER *buffer = x509_to_buffer(x509);
+ if (buffer == NULL) {
+ return 0;
+ }
+
+ if (cert->chain != NULL) {
+ if (!sk_CRYPTO_BUFFER_push(cert->chain, buffer)) {
+ CRYPTO_BUFFER_free(buffer);
+ return 0;
+ }
+
+ return 1;
+ }
+
+ cert->chain = new_leafless_chain();
+ if (cert->chain == NULL ||
+ !sk_CRYPTO_BUFFER_push(cert->chain, buffer)) {
+ CRYPTO_BUFFER_free(buffer);
+ sk_CRYPTO_BUFFER_free(cert->chain);
+ cert->chain = NULL;
+ return 0;
+ }
+
+ return 1;
+}
+
+static int ssl_cert_add0_chain_cert(CERT *cert, X509 *x509) {
+ if (!ssl_cert_append_cert(cert, x509)) {
+ return 0;
+ }
+
+ X509_free(cert->x509_stash);
+ cert->x509_stash = x509;
+ ssl_crypto_x509_cert_flush_cached_chain(cert);
+ return 1;
+}
+
+static int ssl_cert_add1_chain_cert(CERT *cert, X509 *x509) {
+ if (!ssl_cert_append_cert(cert, x509)) {
+ return 0;
+ }
+
+ ssl_crypto_x509_cert_flush_cached_chain(cert);
+ return 1;
+}
+
+int SSL_CTX_set0_chain(SSL_CTX *ctx, STACK_OF(X509) *chain) {
+ check_ssl_ctx_x509_method(ctx);
+ return ssl_cert_set0_chain(ctx->cert, chain);
+}
+
+int SSL_CTX_set1_chain(SSL_CTX *ctx, STACK_OF(X509) *chain) {
+ check_ssl_ctx_x509_method(ctx);
+ return ssl_cert_set1_chain(ctx->cert, chain);
+}
+
+int SSL_set0_chain(SSL *ssl, STACK_OF(X509) *chain) {
+ check_ssl_x509_method(ssl);
+ return ssl_cert_set0_chain(ssl->cert, chain);
+}
+
+int SSL_set1_chain(SSL *ssl, STACK_OF(X509) *chain) {
+ check_ssl_x509_method(ssl);
+ return ssl_cert_set1_chain(ssl->cert, chain);
+}
+
+int SSL_CTX_add0_chain_cert(SSL_CTX *ctx, X509 *x509) {
+ check_ssl_ctx_x509_method(ctx);
+ return ssl_cert_add0_chain_cert(ctx->cert, x509);
+}
+
+int SSL_CTX_add1_chain_cert(SSL_CTX *ctx, X509 *x509) {
+ check_ssl_ctx_x509_method(ctx);
+ return ssl_cert_add1_chain_cert(ctx->cert, x509);
+}
+
+int SSL_CTX_add_extra_chain_cert(SSL_CTX *ctx, X509 *x509) {
+ check_ssl_ctx_x509_method(ctx);
+ return SSL_CTX_add0_chain_cert(ctx, x509);
+}
+
+int SSL_add0_chain_cert(SSL *ssl, X509 *x509) {
+ check_ssl_x509_method(ssl);
+ return ssl_cert_add0_chain_cert(ssl->cert, x509);
+}
+
+int SSL_add1_chain_cert(SSL *ssl, X509 *x509) {
+ check_ssl_x509_method(ssl);
+ return ssl_cert_add1_chain_cert(ssl->cert, x509);
+}
+
+int SSL_CTX_clear_chain_certs(SSL_CTX *ctx) {
+ check_ssl_ctx_x509_method(ctx);
+ return SSL_CTX_set0_chain(ctx, NULL);
+}
+
+int SSL_CTX_clear_extra_chain_certs(SSL_CTX *ctx) {
+ check_ssl_ctx_x509_method(ctx);
+ return SSL_CTX_clear_chain_certs(ctx);
+}
+
+int SSL_clear_chain_certs(SSL *ssl) {
+ check_ssl_x509_method(ssl);
+ return SSL_set0_chain(ssl, NULL);
+}
+
+/* ssl_cert_cache_chain_certs fills in |cert->x509_chain| from elements 1.. of
+ * |cert->chain|. */
+static int ssl_cert_cache_chain_certs(CERT *cert) {
+ assert(cert->x509_method);
+
+ if (cert->x509_chain != NULL ||
+ cert->chain == NULL ||
+ sk_CRYPTO_BUFFER_num(cert->chain) < 2) {
+ return 1;
+ }
+
+ STACK_OF(X509) *chain = sk_X509_new_null();
+ if (chain == NULL) {
+ 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;
+ }
+ }
+
+ cert->x509_chain = chain;
+ 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) {
+ check_ssl_ctx_x509_method(ctx);
+ CRYPTO_MUTEX_lock_write((CRYPTO_MUTEX *) &ctx->lock);
+ const int ret = ssl_cert_cache_chain_certs(ctx->cert);
+ CRYPTO_MUTEX_unlock_write((CRYPTO_MUTEX *) &ctx->lock);
+
+ if (!ret) {
+ *out_chain = NULL;
+ return 0;
+ }
+
+ *out_chain = ctx->cert->x509_chain;
+ return 1;
+}
+
+int SSL_CTX_get_extra_chain_certs(const SSL_CTX *ctx,
+ STACK_OF(X509) **out_chain) {
+ return SSL_CTX_get0_chain_certs(ctx, out_chain);
+}
+
+int SSL_get0_chain_certs(const SSL *ssl, STACK_OF(X509) **out_chain) {
+ check_ssl_x509_method(ssl);
+ if (!ssl_cert_cache_chain_certs(ssl->cert)) {
+ *out_chain = NULL;
+ return 0;
+ }
+
+ *out_chain = ssl->cert->x509_chain;
+ return 1;
+}
+
+static SSL_SESSION *ssl_session_new_with_crypto_x509(void) {
+ return ssl_session_new(&ssl_crypto_x509_method);
+}
+
+SSL_SESSION *d2i_SSL_SESSION_bio(BIO *bio, SSL_SESSION **out) {
+ return ASN1_d2i_bio_of(SSL_SESSION, ssl_session_new_with_crypto_x509,
+ d2i_SSL_SESSION, bio, out);
+}
+
+int i2d_SSL_SESSION_bio(BIO *bio, const SSL_SESSION *session) {
+ return ASN1_i2d_bio_of(SSL_SESSION, i2d_SSL_SESSION, bio, session);
+}
+
+IMPLEMENT_PEM_rw(SSL_SESSION, SSL_SESSION, PEM_STRING_SSL_SESSION, SSL_SESSION)
+
+SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const uint8_t **pp, long length) {
+ if (length < 0) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return NULL;
+ }
+
+ CBS cbs;
+ CBS_init(&cbs, *pp, length);
+
+ SSL_SESSION *ret = SSL_SESSION_parse(&cbs, &ssl_crypto_x509_method,
+ NULL /* no buffer pool */);
+ if (ret == NULL) {
+ return NULL;
+ }
+
+ if (a) {
+ SSL_SESSION_free(*a);
+ *a = ret;
+ }
+ *pp = CBS_data(&cbs);
+ return ret;
+}
+
+STACK_OF(X509_NAME) *SSL_dup_CA_list(STACK_OF(X509_NAME) *list) {
+ return sk_X509_NAME_deep_copy(list, X509_NAME_dup, X509_NAME_free);
+}
+
+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) {
+ return;
+ }
+
+ for (size_t i = 0; i < sk_X509_NAME_num(name_list); i++) {
+ X509_NAME *name = sk_X509_NAME_value(name_list, i);
+ uint8_t *outp = NULL;
+ int len = i2d_X509_NAME(name, &outp);
+ if (len < 0) {
+ goto err;
+ }
+
+ 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;
+ }
+ }
+
+ sk_CRYPTO_BUFFER_pop_free(*ca_list, CRYPTO_BUFFER_free);
+ *ca_list = buffers;
+ return;
+
+err:
+ sk_CRYPTO_BUFFER_pop_free(buffers, CRYPTO_BUFFER_free);
+}
+
+void SSL_set_client_CA_list(SSL *ssl, STACK_OF(X509_NAME) *name_list) {
+ check_ssl_x509_method(ssl);
+ ssl->ctx->x509_method->ssl_flush_cached_client_CA(ssl);
+ set_client_CA_list(&ssl->client_CA, name_list, ssl->ctx->pool);
+ sk_X509_NAME_pop_free(name_list, X509_NAME_free);
+}
+
+void SSL_CTX_set_client_CA_list(SSL_CTX *ctx, STACK_OF(X509_NAME) *name_list) {
+ check_ssl_ctx_x509_method(ctx);
+ ctx->x509_method->ssl_ctx_flush_cached_client_CA(ctx);
+ set_client_CA_list(&ctx->client_CA, name_list, ctx->pool);
+ sk_X509_NAME_pop_free(name_list, X509_NAME_free);
+}
+
+static STACK_OF(X509_NAME) *
+ buffer_names_to_x509(const STACK_OF(CRYPTO_BUFFER) *names,
+ STACK_OF(X509_NAME) **cached) {
+ if (names == NULL) {
+ return NULL;
+ }
+
+ if (*cached != NULL) {
+ return *cached;
+ }
+
+ STACK_OF(X509_NAME) *new_cache = sk_X509_NAME_new_null();
+ if (new_cache == NULL) {
+ 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);
+ const uint8_t *inp = CRYPTO_BUFFER_data(buffer);
+ X509_NAME *name = d2i_X509_NAME(NULL, &inp, CRYPTO_BUFFER_len(buffer));
+ if (name == NULL ||
+ inp != CRYPTO_BUFFER_data(buffer) + CRYPTO_BUFFER_len(buffer) ||
+ !sk_X509_NAME_push(new_cache, name)) {
+ X509_NAME_free(name);
+ goto err;
+ }
+ }
+
+ *cached = new_cache;
+ return new_cache;
+
+err:
+ sk_X509_NAME_pop_free(new_cache, X509_NAME_free);
+ return NULL;
+}
+
+STACK_OF(X509_NAME) *SSL_get_client_CA_list(const SSL *ssl) {
+ check_ssl_x509_method(ssl);
+ /* For historical reasons, this function is used both to query configuration
+ * state on a server as well as handshake state on a client. However, whether
+ * |ssl| is a client or server is not known until explicitly configured with
+ * |SSL_set_connect_state|. If |handshake_func| is NULL, |ssl| is in an
+ * indeterminate mode and |ssl->server| is unset. */
+ if (ssl->handshake_func != NULL && !ssl->server) {
+ if (ssl->s3->hs != NULL) {
+ return buffer_names_to_x509(ssl->s3->hs->ca_names,
+ &ssl->s3->hs->cached_x509_ca_names);
+ }
+
+ return NULL;
+ }
+
+ if (ssl->client_CA != NULL) {
+ return buffer_names_to_x509(
+ ssl->client_CA, (STACK_OF(X509_NAME) **)&ssl->cached_x509_client_CA);
+ }
+ return buffer_names_to_x509(ssl->ctx->client_CA,
+ &ssl->ctx->cached_x509_client_CA);
+}
+
+STACK_OF(X509_NAME) *SSL_CTX_get_client_CA_list(const SSL_CTX *ctx) {
+ check_ssl_ctx_x509_method(ctx);
+ CRYPTO_MUTEX_lock_write((CRYPTO_MUTEX *) &ctx->lock);
+ STACK_OF(X509_NAME) *ret = buffer_names_to_x509(
+ ctx->client_CA, (STACK_OF(X509_NAME) **)&ctx->cached_x509_client_CA);
+ CRYPTO_MUTEX_unlock_write((CRYPTO_MUTEX *) &ctx->lock);
+ return ret;
+}
+
+static int add_client_CA(STACK_OF(CRYPTO_BUFFER) **names, X509 *x509,
+ CRYPTO_BUFFER_POOL *pool) {
+ if (x509 == NULL) {
+ return 0;
+ }
+
+ uint8_t *outp = NULL;
+ int len = i2d_X509_NAME(X509_get_subject_name(x509), &outp);
+ if (len < 0) {
+ return 0;
+ }
+
+ CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new(outp, len, pool);
+ OPENSSL_free(outp);
+ if (buffer == NULL) {
+ return 0;
+ }
+
+ int alloced = 0;
+ if (*names == NULL) {
+ *names = sk_CRYPTO_BUFFER_new_null();
+ alloced = 1;
+
+ if (*names == NULL) {
+ CRYPTO_BUFFER_free(buffer);
+ return 0;
+ }
+ }
+
+ if (!sk_CRYPTO_BUFFER_push(*names, buffer)) {
+ CRYPTO_BUFFER_free(buffer);
+ if (alloced) {
+ sk_CRYPTO_BUFFER_pop_free(*names, CRYPTO_BUFFER_free);
+ *names = NULL;
+ }
+ return 0;
+ }
+
+ return 1;
+}
+
+int SSL_add_client_CA(SSL *ssl, X509 *x509) {
+ check_ssl_x509_method(ssl);
+ if (!add_client_CA(&ssl->client_CA, x509, ssl->ctx->pool)) {
+ return 0;
+ }
+
+ ssl_crypto_x509_ssl_flush_cached_client_CA(ssl);
+ return 1;
+}
+
+int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x509) {
+ check_ssl_ctx_x509_method(ctx);
+ if (!add_client_CA(&ctx->client_CA, x509, ctx->pool)) {
+ return 0;
+ }
+
+ ssl_crypto_x509_ssl_ctx_flush_cached_client_CA(ctx);
+ return 1;
+}
+
+static int do_client_cert_cb(SSL *ssl, void *arg) {
+ if (ssl_has_certificate(ssl) || ssl->ctx->client_cert_cb == NULL) {
+ return 1;
+ }
+
+ X509 *x509 = NULL;
+ EVP_PKEY *pkey = NULL;
+ int ret = ssl->ctx->client_cert_cb(ssl, &x509, &pkey);
+ if (ret < 0) {
+ return -1;
+ }
+
+ if (ret != 0) {
+ if (!SSL_use_certificate(ssl, x509) ||
+ !SSL_use_PrivateKey(ssl, pkey)) {
+ return 0;
+ }
+ }
+
+ X509_free(x509);
+ EVP_PKEY_free(pkey);
+ return 1;
+}
+
+void SSL_CTX_set_client_cert_cb(SSL_CTX *ctx, int (*cb)(SSL *ssl,
+ X509 **out_x509,
+ EVP_PKEY **out_pkey)) {
+ check_ssl_ctx_x509_method(ctx);
+ /* Emulate the old client certificate callback with the new one. */
+ SSL_CTX_set_cert_cb(ctx, do_client_cert_cb, NULL);
+ ctx->client_cert_cb = cb;
+}
+
+static int set_cert_store(X509_STORE **store_ptr, X509_STORE *new_store,
+ int take_ref) {
+ X509_STORE_free(*store_ptr);
+ *store_ptr = new_store;
+
+ if (new_store != NULL && take_ref) {
+ X509_STORE_up_ref(new_store);
+ }
+
+ return 1;
+}
+
+int SSL_get_ex_data_X509_STORE_CTX_idx(void) {
+ /* The ex_data index to go from |X509_STORE_CTX| to |SSL| always uses the
+ * reserved app_data slot. Before ex_data was introduced, app_data was used.
+ * Avoid breaking any software which assumes |X509_STORE_CTX_get_app_data|
+ * works. */
+ return 0;
+}
+
+int SSL_CTX_set0_verify_cert_store(SSL_CTX *ctx, X509_STORE *store) {
+ check_ssl_ctx_x509_method(ctx);
+ return set_cert_store(&ctx->cert->verify_store, store, 0);
+}
+
+int SSL_CTX_set1_verify_cert_store(SSL_CTX *ctx, X509_STORE *store) {
+ check_ssl_ctx_x509_method(ctx);
+ return set_cert_store(&ctx->cert->verify_store, store, 1);
+}
+
+int SSL_set0_verify_cert_store(SSL *ssl, X509_STORE *store) {
+ check_ssl_x509_method(ssl);
+ return set_cert_store(&ssl->cert->verify_store, store, 0);
+}
+
+int SSL_set1_verify_cert_store(SSL *ssl, X509_STORE *store) {
+ check_ssl_x509_method(ssl);
+ return set_cert_store(&ssl->cert->verify_store, store, 1);
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/t1_enc.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/t1_enc.c
new file mode 100644
index 000000000..9f11e0566
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/t1_enc.c
@@ -0,0 +1,561 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2007 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* ====================================================================
+ * Copyright 2005 Nokia. All rights reserved.
+ *
+ * The portions of the attached software ("Contribution") is developed by
+ * Nokia Corporation and is licensed pursuant to the OpenSSL open source
+ * license.
+ *
+ * The Contribution, originally written by Mika Kousa and Pasi Eronen of
+ * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites
+ * support (see RFC 4279) to OpenSSL.
+ *
+ * No patent licenses or other rights except those expressly stated in
+ * the OpenSSL open source license shall be deemed granted or received
+ * expressly, by implication, estoppel, or otherwise.
+ *
+ * No assurances are provided by Nokia that the Contribution does not
+ * infringe the patent or other intellectual property rights of any third
+ * party or that the license provides you with all the necessary rights
+ * to make use of the Contribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN
+ * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA
+ * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY
+ * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
+ * OTHERWISE. */
+
+#include <openssl/ssl.h>
+
+#include <assert.h>
+#include <string.h>
+
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#include <openssl/md5.h>
+#include <openssl/mem.h>
+#include <openssl/nid.h>
+#include <openssl/rand.h>
+
+#include "../crypto/internal.h"
+#include "internal.h"
+
+
+/* tls1_P_hash computes the TLS P_<hash> function as described in RFC 5246,
+ * section 5. It XORs |out_len| bytes to |out|, using |md| as the hash and
+ * |secret| as the secret. |seed1| through |seed3| are concatenated to form the
+ * seed parameter. It returns one on success and zero on failure. */
+static int tls1_P_hash(uint8_t *out, size_t out_len, const EVP_MD *md,
+ const uint8_t *secret, size_t secret_len,
+ const uint8_t *seed1, size_t seed1_len,
+ const uint8_t *seed2, size_t seed2_len,
+ const uint8_t *seed3, size_t seed3_len) {
+ HMAC_CTX ctx, ctx_tmp, ctx_init;
+ uint8_t A1[EVP_MAX_MD_SIZE];
+ unsigned A1_len;
+ int ret = 0;
+
+ size_t chunk = EVP_MD_size(md);
+
+ HMAC_CTX_init(&ctx);
+ HMAC_CTX_init(&ctx_tmp);
+ HMAC_CTX_init(&ctx_init);
+ if (!HMAC_Init_ex(&ctx_init, secret, secret_len, md, NULL) ||
+ !HMAC_CTX_copy_ex(&ctx, &ctx_init) ||
+ !HMAC_Update(&ctx, seed1, seed1_len) ||
+ !HMAC_Update(&ctx, seed2, seed2_len) ||
+ !HMAC_Update(&ctx, seed3, seed3_len) ||
+ !HMAC_Final(&ctx, A1, &A1_len)) {
+ goto err;
+ }
+
+ for (;;) {
+ unsigned len;
+ uint8_t hmac[EVP_MAX_MD_SIZE];
+ if (!HMAC_CTX_copy_ex(&ctx, &ctx_init) ||
+ !HMAC_Update(&ctx, A1, A1_len) ||
+ /* Save a copy of |ctx| to compute the next A1 value below. */
+ (out_len > chunk && !HMAC_CTX_copy_ex(&ctx_tmp, &ctx)) ||
+ !HMAC_Update(&ctx, seed1, seed1_len) ||
+ !HMAC_Update(&ctx, seed2, seed2_len) ||
+ !HMAC_Update(&ctx, seed3, seed3_len) ||
+ !HMAC_Final(&ctx, hmac, &len)) {
+ goto err;
+ }
+ assert(len == chunk);
+
+ /* XOR the result into |out|. */
+ if (len > out_len) {
+ len = out_len;
+ }
+ unsigned i;
+ for (i = 0; i < len; i++) {
+ out[i] ^= hmac[i];
+ }
+ out += len;
+ out_len -= len;
+
+ if (out_len == 0) {
+ break;
+ }
+
+ /* Calculate the next A1 value. */
+ if (!HMAC_Final(&ctx_tmp, A1, &A1_len)) {
+ goto err;
+ }
+ }
+
+ ret = 1;
+
+err:
+ HMAC_CTX_cleanup(&ctx);
+ HMAC_CTX_cleanup(&ctx_tmp);
+ HMAC_CTX_cleanup(&ctx_init);
+ OPENSSL_cleanse(A1, sizeof(A1));
+ return ret;
+}
+
+int tls1_prf(const EVP_MD *digest, uint8_t *out, size_t out_len,
+ const uint8_t *secret, size_t secret_len, const char *label,
+ size_t label_len, const uint8_t *seed1, size_t seed1_len,
+ const uint8_t *seed2, size_t seed2_len) {
+ if (out_len == 0) {
+ return 1;
+ }
+
+ OPENSSL_memset(out, 0, out_len);
+
+ if (digest == EVP_md5_sha1()) {
+ /* If using the MD5/SHA1 PRF, |secret| is partitioned between SHA-1 and
+ * MD5, MD5 first. */
+ size_t secret_half = secret_len - (secret_len / 2);
+ if (!tls1_P_hash(out, out_len, EVP_md5(), secret, secret_half,
+ (const uint8_t *)label, label_len, seed1, seed1_len, seed2,
+ seed2_len)) {
+ return 0;
+ }
+
+ /* Note that, if |secret_len| is odd, the two halves share a byte. */
+ secret = secret + (secret_len - secret_half);
+ secret_len = secret_half;
+
+ digest = EVP_sha1();
+ }
+
+ if (!tls1_P_hash(out, out_len, digest, secret, secret_len,
+ (const uint8_t *)label, label_len, seed1, seed1_len, seed2,
+ seed2_len)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+static int ssl3_prf(uint8_t *out, size_t out_len, const uint8_t *secret,
+ size_t secret_len, const char *label, size_t label_len,
+ const uint8_t *seed1, size_t seed1_len,
+ const uint8_t *seed2, size_t seed2_len) {
+ EVP_MD_CTX md5;
+ EVP_MD_CTX sha1;
+ uint8_t buf[16], smd[SHA_DIGEST_LENGTH];
+ uint8_t c = 'A';
+ size_t i, j, k;
+
+ k = 0;
+ EVP_MD_CTX_init(&md5);
+ EVP_MD_CTX_init(&sha1);
+ for (i = 0; i < out_len; i += MD5_DIGEST_LENGTH) {
+ k++;
+ if (k > sizeof(buf)) {
+ /* bug: 'buf' is too small for this ciphersuite */
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ for (j = 0; j < k; j++) {
+ buf[j] = c;
+ }
+ c++;
+ if (!EVP_DigestInit_ex(&sha1, EVP_sha1(), NULL)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_LIB_EVP);
+ return 0;
+ }
+ EVP_DigestUpdate(&sha1, buf, k);
+ EVP_DigestUpdate(&sha1, secret, secret_len);
+ /* |label| is ignored for SSLv3. */
+ if (seed1_len) {
+ EVP_DigestUpdate(&sha1, seed1, seed1_len);
+ }
+ if (seed2_len) {
+ EVP_DigestUpdate(&sha1, seed2, seed2_len);
+ }
+ EVP_DigestFinal_ex(&sha1, smd, NULL);
+
+ if (!EVP_DigestInit_ex(&md5, EVP_md5(), NULL)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_LIB_EVP);
+ return 0;
+ }
+ EVP_DigestUpdate(&md5, secret, secret_len);
+ EVP_DigestUpdate(&md5, smd, SHA_DIGEST_LENGTH);
+ if (i + MD5_DIGEST_LENGTH > out_len) {
+ EVP_DigestFinal_ex(&md5, smd, NULL);
+ OPENSSL_memcpy(out, smd, out_len - i);
+ } else {
+ EVP_DigestFinal_ex(&md5, out, NULL);
+ }
+
+ out += MD5_DIGEST_LENGTH;
+ }
+
+ OPENSSL_cleanse(smd, SHA_DIGEST_LENGTH);
+ EVP_MD_CTX_cleanup(&md5);
+ EVP_MD_CTX_cleanup(&sha1);
+
+ return 1;
+}
+
+static int tls1_setup_key_block(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ if (hs->key_block_len != 0) {
+ return 1;
+ }
+
+ SSL_SESSION *session = ssl->session;
+ if (hs->new_session != NULL) {
+ session = hs->new_session;
+ }
+
+ const EVP_AEAD *aead = NULL;
+ size_t mac_secret_len, fixed_iv_len;
+ if (session->cipher == NULL ||
+ !ssl_cipher_get_evp_aead(&aead, &mac_secret_len, &fixed_iv_len,
+ session->cipher, ssl3_protocol_version(ssl))) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CIPHER_OR_HASH_UNAVAILABLE);
+ return 0;
+ }
+ size_t key_len = EVP_AEAD_key_length(aead);
+ if (mac_secret_len > 0) {
+ /* For "stateful" AEADs (i.e. compatibility with pre-AEAD cipher suites) the
+ * key length reported by |EVP_AEAD_key_length| will include the MAC key
+ * bytes and initial implicit IV. */
+ if (key_len < mac_secret_len + fixed_iv_len) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+ key_len -= mac_secret_len + fixed_iv_len;
+ }
+
+ assert(mac_secret_len < 256);
+ assert(key_len < 256);
+ assert(fixed_iv_len < 256);
+
+ ssl->s3->tmp.new_mac_secret_len = (uint8_t)mac_secret_len;
+ ssl->s3->tmp.new_key_len = (uint8_t)key_len;
+ ssl->s3->tmp.new_fixed_iv_len = (uint8_t)fixed_iv_len;
+
+ size_t key_block_len = SSL_get_key_block_len(ssl);
+
+ uint8_t *keyblock = OPENSSL_malloc(key_block_len);
+ if (keyblock == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+
+ if (!SSL_generate_key_block(ssl, keyblock, key_block_len)) {
+ OPENSSL_free(keyblock);
+ return 0;
+ }
+
+ assert(key_block_len < 256);
+ hs->key_block_len = (uint8_t)key_block_len;
+ hs->key_block = keyblock;
+ return 1;
+}
+
+int tls1_change_cipher_state(SSL_HANDSHAKE *hs, int which) {
+ SSL *const ssl = hs->ssl;
+ /* Ensure the key block is set up. */
+ if (!tls1_setup_key_block(hs)) {
+ return 0;
+ }
+
+ /* is_read is true if we have just read a ChangeCipherSpec message - i.e. we
+ * need to update the read cipherspec. Otherwise we have just written one. */
+ const char is_read = (which & SSL3_CC_READ) != 0;
+ /* use_client_keys is true if we wish to use the keys for the "client write"
+ * direction. This is the case if we're a client sending a ChangeCipherSpec,
+ * or a server reading a client's ChangeCipherSpec. */
+ const char use_client_keys = which == SSL3_CHANGE_CIPHER_CLIENT_WRITE ||
+ which == SSL3_CHANGE_CIPHER_SERVER_READ;
+
+ size_t mac_secret_len = ssl->s3->tmp.new_mac_secret_len;
+ size_t key_len = ssl->s3->tmp.new_key_len;
+ size_t iv_len = ssl->s3->tmp.new_fixed_iv_len;
+ assert((mac_secret_len + key_len + iv_len) * 2 == hs->key_block_len);
+
+ const uint8_t *key_data = hs->key_block;
+ const uint8_t *client_write_mac_secret = key_data;
+ key_data += mac_secret_len;
+ const uint8_t *server_write_mac_secret = key_data;
+ key_data += mac_secret_len;
+ const uint8_t *client_write_key = key_data;
+ key_data += key_len;
+ const uint8_t *server_write_key = key_data;
+ key_data += key_len;
+ const uint8_t *client_write_iv = key_data;
+ key_data += iv_len;
+ const uint8_t *server_write_iv = key_data;
+ key_data += iv_len;
+
+ const uint8_t *mac_secret, *key, *iv;
+ if (use_client_keys) {
+ mac_secret = client_write_mac_secret;
+ key = client_write_key;
+ iv = client_write_iv;
+ } else {
+ mac_secret = server_write_mac_secret;
+ key = server_write_key;
+ iv = server_write_iv;
+ }
+
+ SSL_AEAD_CTX *aead_ctx = SSL_AEAD_CTX_new(
+ is_read ? evp_aead_open : evp_aead_seal, ssl3_protocol_version(ssl),
+ hs->new_cipher, key, key_len, mac_secret, mac_secret_len, iv, iv_len);
+ if (aead_ctx == NULL) {
+ return 0;
+ }
+
+ if (is_read) {
+ return ssl->method->set_read_state(ssl, aead_ctx);
+ }
+
+ return ssl->method->set_write_state(ssl, aead_ctx);
+}
+
+size_t SSL_get_key_block_len(const SSL *ssl) {
+ return 2 * ((size_t)ssl->s3->tmp.new_mac_secret_len +
+ (size_t)ssl->s3->tmp.new_key_len +
+ (size_t)ssl->s3->tmp.new_fixed_iv_len);
+}
+
+int SSL_generate_key_block(const SSL *ssl, uint8_t *out, size_t out_len) {
+ if (ssl3_protocol_version(ssl) == SSL3_VERSION) {
+ return ssl3_prf(out, out_len, SSL_get_session(ssl)->master_key,
+ SSL_get_session(ssl)->master_key_length,
+ TLS_MD_KEY_EXPANSION_CONST, TLS_MD_KEY_EXPANSION_CONST_SIZE,
+ ssl->s3->server_random, SSL3_RANDOM_SIZE,
+ ssl->s3->client_random, SSL3_RANDOM_SIZE);
+ }
+
+ const EVP_MD *digest = ssl_get_handshake_digest(
+ SSL_get_session(ssl)->cipher->algorithm_prf, ssl3_protocol_version(ssl));
+ if (digest == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+ return tls1_prf(digest, out, out_len, SSL_get_session(ssl)->master_key,
+ SSL_get_session(ssl)->master_key_length,
+ TLS_MD_KEY_EXPANSION_CONST, TLS_MD_KEY_EXPANSION_CONST_SIZE,
+ ssl->s3->server_random, SSL3_RANDOM_SIZE,
+ ssl->s3->client_random, SSL3_RANDOM_SIZE);
+}
+
+int tls1_generate_master_secret(SSL_HANDSHAKE *hs, uint8_t *out,
+ const uint8_t *premaster,
+ size_t premaster_len) {
+ const SSL *ssl = hs->ssl;
+ if (hs->extended_master_secret) {
+ uint8_t digests[EVP_MAX_MD_SIZE];
+ size_t digests_len;
+ if (!SSL_TRANSCRIPT_get_hash(&hs->transcript, digests, &digests_len) ||
+ !tls1_prf(SSL_TRANSCRIPT_md(&hs->transcript), out,
+ SSL3_MASTER_SECRET_SIZE, premaster, premaster_len,
+ TLS_MD_EXTENDED_MASTER_SECRET_CONST,
+ TLS_MD_EXTENDED_MASTER_SECRET_CONST_SIZE, digests,
+ digests_len, NULL, 0)) {
+ return 0;
+ }
+ } else {
+ if (ssl3_protocol_version(ssl) == SSL3_VERSION) {
+ if (!ssl3_prf(out, SSL3_MASTER_SECRET_SIZE, premaster, premaster_len,
+ TLS_MD_MASTER_SECRET_CONST, TLS_MD_MASTER_SECRET_CONST_SIZE,
+ ssl->s3->client_random, SSL3_RANDOM_SIZE,
+ ssl->s3->server_random, SSL3_RANDOM_SIZE)) {
+ return 0;
+ }
+ } else {
+ if (!tls1_prf(SSL_TRANSCRIPT_md(&hs->transcript), out,
+ SSL3_MASTER_SECRET_SIZE, premaster, premaster_len,
+ TLS_MD_MASTER_SECRET_CONST, TLS_MD_MASTER_SECRET_CONST_SIZE,
+ ssl->s3->client_random, SSL3_RANDOM_SIZE,
+ ssl->s3->server_random, SSL3_RANDOM_SIZE)) {
+ return 0;
+ }
+ }
+ }
+
+ return SSL3_MASTER_SECRET_SIZE;
+}
+
+int SSL_export_keying_material(SSL *ssl, uint8_t *out, size_t out_len,
+ const char *label, size_t label_len,
+ const uint8_t *context, size_t context_len,
+ int use_context) {
+ if (!ssl->s3->have_version || ssl->version == SSL3_VERSION) {
+ return 0;
+ }
+
+ /* Exporters may not be used in the middle of a renegotiation. */
+ if (SSL_in_init(ssl) && !SSL_in_false_start(ssl)) {
+ return 0;
+ }
+
+ if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) {
+ return tls13_export_keying_material(ssl, out, out_len, label, label_len,
+ context, context_len, use_context);
+ }
+
+ size_t seed_len = 2 * SSL3_RANDOM_SIZE;
+ if (use_context) {
+ if (context_len >= 1u << 16) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
+ return 0;
+ }
+ seed_len += 2 + context_len;
+ }
+ uint8_t *seed = OPENSSL_malloc(seed_len);
+ if (seed == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+
+ OPENSSL_memcpy(seed, ssl->s3->client_random, SSL3_RANDOM_SIZE);
+ OPENSSL_memcpy(seed + SSL3_RANDOM_SIZE, ssl->s3->server_random,
+ SSL3_RANDOM_SIZE);
+ if (use_context) {
+ seed[2 * SSL3_RANDOM_SIZE] = (uint8_t)(context_len >> 8);
+ seed[2 * SSL3_RANDOM_SIZE + 1] = (uint8_t)context_len;
+ OPENSSL_memcpy(seed + 2 * SSL3_RANDOM_SIZE + 2, context, context_len);
+ }
+
+ const EVP_MD *digest = ssl_get_handshake_digest(
+ SSL_get_session(ssl)->cipher->algorithm_prf, ssl3_protocol_version(ssl));
+ if (digest == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+ int ret = tls1_prf(digest, out, out_len, SSL_get_session(ssl)->master_key,
+ SSL_get_session(ssl)->master_key_length, label, label_len,
+ seed, seed_len, NULL, 0);
+ OPENSSL_free(seed);
+ return ret;
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/t1_lib.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/t1_lib.c
new file mode 100644
index 000000000..759d87bfd
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/t1_lib.c
@@ -0,0 +1,3562 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2007 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com). */
+
+#include <openssl/ssl.h>
+
+#include <assert.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <openssl/bytestring.h>
+#include <openssl/digest.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#include <openssl/mem.h>
+#include <openssl/nid.h>
+#include <openssl/rand.h>
+#include <openssl/type_check.h>
+
+#include "internal.h"
+#include "../crypto/internal.h"
+
+
+static int ssl_check_clienthello_tlsext(SSL_HANDSHAKE *hs);
+
+static int compare_uint16_t(const void *p1, const void *p2) {
+ uint16_t u1 = *((const uint16_t *)p1);
+ uint16_t u2 = *((const uint16_t *)p2);
+ if (u1 < u2) {
+ return -1;
+ } else if (u1 > u2) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+/* Per http://tools.ietf.org/html/rfc5246#section-7.4.1.4, there may not be
+ * more than one extension of the same type in a ClientHello or ServerHello.
+ * This function does an initial scan over the extensions block to filter those
+ * out. */
+static int tls1_check_duplicate_extensions(const CBS *cbs) {
+ CBS extensions = *cbs;
+ size_t num_extensions = 0, i = 0;
+ uint16_t *extension_types = NULL;
+ int ret = 0;
+
+ /* First pass: count the extensions. */
+ while (CBS_len(&extensions) > 0) {
+ uint16_t type;
+ CBS extension;
+
+ if (!CBS_get_u16(&extensions, &type) ||
+ !CBS_get_u16_length_prefixed(&extensions, &extension)) {
+ goto done;
+ }
+
+ num_extensions++;
+ }
+
+ if (num_extensions == 0) {
+ return 1;
+ }
+
+ extension_types = OPENSSL_malloc(sizeof(uint16_t) * num_extensions);
+ if (extension_types == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto done;
+ }
+
+ /* Second pass: gather the extension types. */
+ extensions = *cbs;
+ for (i = 0; i < num_extensions; i++) {
+ CBS extension;
+
+ if (!CBS_get_u16(&extensions, &extension_types[i]) ||
+ !CBS_get_u16_length_prefixed(&extensions, &extension)) {
+ /* This should not happen. */
+ goto done;
+ }
+ }
+ assert(CBS_len(&extensions) == 0);
+
+ /* Sort the extensions and make sure there are no duplicates. */
+ qsort(extension_types, num_extensions, sizeof(uint16_t), compare_uint16_t);
+ for (i = 1; i < num_extensions; i++) {
+ if (extension_types[i - 1] == extension_types[i]) {
+ goto done;
+ }
+ }
+
+ ret = 1;
+
+done:
+ OPENSSL_free(extension_types);
+ return ret;
+}
+
+int ssl_client_hello_init(SSL *ssl, SSL_CLIENT_HELLO *out, const uint8_t *in,
+ size_t in_len) {
+ OPENSSL_memset(out, 0, sizeof(*out));
+ out->ssl = ssl;
+ out->client_hello = in;
+ out->client_hello_len = in_len;
+
+ CBS client_hello, random, session_id;
+ CBS_init(&client_hello, out->client_hello, out->client_hello_len);
+ if (!CBS_get_u16(&client_hello, &out->version) ||
+ !CBS_get_bytes(&client_hello, &random, SSL3_RANDOM_SIZE) ||
+ !CBS_get_u8_length_prefixed(&client_hello, &session_id) ||
+ CBS_len(&session_id) > SSL_MAX_SSL_SESSION_ID_LENGTH) {
+ return 0;
+ }
+
+ out->random = CBS_data(&random);
+ out->random_len = CBS_len(&random);
+ out->session_id = CBS_data(&session_id);
+ out->session_id_len = CBS_len(&session_id);
+
+ /* Skip past DTLS cookie */
+ if (SSL_is_dtls(out->ssl)) {
+ CBS cookie;
+ if (!CBS_get_u8_length_prefixed(&client_hello, &cookie) ||
+ CBS_len(&cookie) > DTLS1_COOKIE_LENGTH) {
+ return 0;
+ }
+ }
+
+ CBS cipher_suites, compression_methods;
+ if (!CBS_get_u16_length_prefixed(&client_hello, &cipher_suites) ||
+ CBS_len(&cipher_suites) < 2 || (CBS_len(&cipher_suites) & 1) != 0 ||
+ !CBS_get_u8_length_prefixed(&client_hello, &compression_methods) ||
+ CBS_len(&compression_methods) < 1) {
+ return 0;
+ }
+
+ out->cipher_suites = CBS_data(&cipher_suites);
+ out->cipher_suites_len = CBS_len(&cipher_suites);
+ out->compression_methods = CBS_data(&compression_methods);
+ out->compression_methods_len = CBS_len(&compression_methods);
+
+ /* If the ClientHello ends here then it's valid, but doesn't have any
+ * extensions. (E.g. SSLv3.) */
+ if (CBS_len(&client_hello) == 0) {
+ out->extensions = NULL;
+ out->extensions_len = 0;
+ return 1;
+ }
+
+ /* Extract extensions and check it is valid. */
+ CBS extensions;
+ if (!CBS_get_u16_length_prefixed(&client_hello, &extensions) ||
+ !tls1_check_duplicate_extensions(&extensions) ||
+ CBS_len(&client_hello) != 0) {
+ return 0;
+ }
+
+ out->extensions = CBS_data(&extensions);
+ out->extensions_len = CBS_len(&extensions);
+
+ return 1;
+}
+
+int ssl_client_hello_get_extension(const SSL_CLIENT_HELLO *client_hello,
+ CBS *out, uint16_t extension_type) {
+ CBS extensions;
+ CBS_init(&extensions, client_hello->extensions, client_hello->extensions_len);
+ while (CBS_len(&extensions) != 0) {
+ /* Decode the next extension. */
+ uint16_t type;
+ CBS extension;
+ if (!CBS_get_u16(&extensions, &type) ||
+ !CBS_get_u16_length_prefixed(&extensions, &extension)) {
+ return 0;
+ }
+
+ if (type == extension_type) {
+ *out = extension;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+int SSL_early_callback_ctx_extension_get(const SSL_CLIENT_HELLO *client_hello,
+ uint16_t extension_type,
+ const uint8_t **out_data,
+ size_t *out_len) {
+ CBS cbs;
+ if (!ssl_client_hello_get_extension(client_hello, &cbs, extension_type)) {
+ return 0;
+ }
+
+ *out_data = CBS_data(&cbs);
+ *out_len = CBS_len(&cbs);
+ return 1;
+}
+
+static const uint16_t kDefaultGroups[] = {
+ SSL_CURVE_X25519,
+ SSL_CURVE_SECP256R1,
+ SSL_CURVE_SECP384R1,
+};
+
+void tls1_get_grouplist(SSL *ssl, const uint16_t **out_group_ids,
+ size_t *out_group_ids_len) {
+ *out_group_ids = ssl->supported_group_list;
+ *out_group_ids_len = ssl->supported_group_list_len;
+ if (!*out_group_ids) {
+ *out_group_ids = kDefaultGroups;
+ *out_group_ids_len = OPENSSL_ARRAY_SIZE(kDefaultGroups);
+ }
+}
+
+int tls1_get_shared_group(SSL_HANDSHAKE *hs, uint16_t *out_group_id) {
+ SSL *const ssl = hs->ssl;
+ assert(ssl->server);
+
+ const uint16_t *groups, *pref, *supp;
+ size_t groups_len, pref_len, supp_len;
+ tls1_get_grouplist(ssl, &groups, &groups_len);
+
+ /* Clients are not required to send a supported_groups extension. In this
+ * case, the server is free to pick any group it likes. See RFC 4492,
+ * section 4, paragraph 3.
+ *
+ * However, in the interests of compatibility, we will skip ECDH if the
+ * client didn't send an extension because we can't be sure that they'll
+ * support our favoured group. Thus we do not special-case an emtpy
+ * |peer_supported_group_list|. */
+
+ if (ssl->options & SSL_OP_CIPHER_SERVER_PREFERENCE) {
+ pref = groups;
+ pref_len = groups_len;
+ supp = hs->peer_supported_group_list;
+ supp_len = hs->peer_supported_group_list_len;
+ } else {
+ pref = hs->peer_supported_group_list;
+ pref_len = hs->peer_supported_group_list_len;
+ supp = groups;
+ supp_len = groups_len;
+ }
+
+ for (size_t i = 0; i < pref_len; i++) {
+ for (size_t j = 0; j < supp_len; j++) {
+ if (pref[i] == supp[j]) {
+ *out_group_id = pref[i];
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+int tls1_set_curves(uint16_t **out_group_ids, size_t *out_group_ids_len,
+ const int *curves, size_t ncurves) {
+ uint16_t *group_ids;
+
+ group_ids = OPENSSL_malloc(ncurves * sizeof(uint16_t));
+ if (group_ids == NULL) {
+ return 0;
+ }
+
+ for (size_t i = 0; i < ncurves; i++) {
+ if (!ssl_nid_to_group_id(&group_ids[i], curves[i])) {
+ OPENSSL_free(group_ids);
+ return 0;
+ }
+ }
+
+ OPENSSL_free(*out_group_ids);
+ *out_group_ids = group_ids;
+ *out_group_ids_len = ncurves;
+
+ return 1;
+}
+
+int tls1_set_curves_list(uint16_t **out_group_ids, size_t *out_group_ids_len,
+ const char *curves) {
+ uint16_t *group_ids = NULL;
+ size_t ncurves = 0;
+
+ const char *col;
+ const char *ptr = curves;
+
+ do {
+ col = strchr(ptr, ':');
+
+ uint16_t group_id;
+ if (!ssl_name_to_group_id(&group_id, ptr,
+ col ? (size_t)(col - ptr) : strlen(ptr))) {
+ goto err;
+ }
+
+ uint16_t *new_group_ids = OPENSSL_realloc(group_ids,
+ (ncurves + 1) * sizeof(uint16_t));
+ if (new_group_ids == NULL) {
+ goto err;
+ }
+ group_ids = new_group_ids;
+
+ group_ids[ncurves] = group_id;
+ ncurves++;
+
+ if (col) {
+ ptr = col + 1;
+ }
+ } while (col);
+
+ OPENSSL_free(*out_group_ids);
+ *out_group_ids = group_ids;
+ *out_group_ids_len = ncurves;
+
+ return 1;
+
+err:
+ OPENSSL_free(group_ids);
+ return 0;
+}
+
+int tls1_check_group_id(SSL *ssl, uint16_t group_id) {
+ const uint16_t *groups;
+ size_t groups_len;
+ tls1_get_grouplist(ssl, &groups, &groups_len);
+ for (size_t i = 0; i < groups_len; i++) {
+ if (groups[i] == group_id) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* kVerifySignatureAlgorithms is the default list of accepted signature
+ * algorithms for verifying.
+ *
+ * For now, RSA-PSS signature algorithms are not enabled on Android's system
+ * BoringSSL. Once the change in Chrome has stuck and the values are finalized,
+ * restore them. */
+static const uint16_t kVerifySignatureAlgorithms[] = {
+ /* Prefer SHA-256 algorithms. */
+ SSL_SIGN_ECDSA_SECP256R1_SHA256,
+#if !defined(BORINGSSL_ANDROID_SYSTEM)
+ SSL_SIGN_RSA_PSS_SHA256,
+#endif
+ SSL_SIGN_RSA_PKCS1_SHA256,
+
+ /* Larger hashes are acceptable. */
+ SSL_SIGN_ECDSA_SECP384R1_SHA384,
+#if !defined(BORINGSSL_ANDROID_SYSTEM)
+ SSL_SIGN_RSA_PSS_SHA384,
+#endif
+ SSL_SIGN_RSA_PKCS1_SHA384,
+
+ /* TODO(davidben): Remove this. */
+#if defined(BORINGSSL_ANDROID_SYSTEM)
+ SSL_SIGN_ECDSA_SECP521R1_SHA512,
+#endif
+#if !defined(BORINGSSL_ANDROID_SYSTEM)
+ SSL_SIGN_RSA_PSS_SHA512,
+#endif
+ SSL_SIGN_RSA_PKCS1_SHA512,
+
+ /* For now, SHA-1 is still accepted but least preferable. */
+ SSL_SIGN_RSA_PKCS1_SHA1,
+
+};
+
+/* kSignSignatureAlgorithms is the default list of supported signature
+ * algorithms for signing.
+ *
+ * For now, RSA-PSS signature algorithms are not enabled on Android's system
+ * BoringSSL. Once the change in Chrome has stuck and the values are finalized,
+ * restore them. */
+static const uint16_t kSignSignatureAlgorithms[] = {
+ /* Prefer SHA-256 algorithms. */
+ SSL_SIGN_ECDSA_SECP256R1_SHA256,
+#if !defined(BORINGSSL_ANDROID_SYSTEM)
+ SSL_SIGN_RSA_PSS_SHA256,
+#endif
+ SSL_SIGN_RSA_PKCS1_SHA256,
+
+ /* If needed, sign larger hashes.
+ *
+ * TODO(davidben): Determine which of these may be pruned. */
+ SSL_SIGN_ECDSA_SECP384R1_SHA384,
+#if !defined(BORINGSSL_ANDROID_SYSTEM)
+ SSL_SIGN_RSA_PSS_SHA384,
+#endif
+ SSL_SIGN_RSA_PKCS1_SHA384,
+
+ SSL_SIGN_ECDSA_SECP521R1_SHA512,
+#if !defined(BORINGSSL_ANDROID_SYSTEM)
+ SSL_SIGN_RSA_PSS_SHA512,
+#endif
+ SSL_SIGN_RSA_PKCS1_SHA512,
+
+ /* If the peer supports nothing else, sign with SHA-1. */
+ SSL_SIGN_ECDSA_SHA1,
+ SSL_SIGN_RSA_PKCS1_SHA1,
+};
+
+size_t tls12_get_verify_sigalgs(const SSL *ssl, const uint16_t **out) {
+ *out = kVerifySignatureAlgorithms;
+ return OPENSSL_ARRAY_SIZE(kVerifySignatureAlgorithms);
+}
+
+int tls12_check_peer_sigalg(SSL *ssl, int *out_alert, uint16_t sigalg) {
+ const uint16_t *verify_sigalgs;
+ size_t num_verify_sigalgs = tls12_get_verify_sigalgs(ssl, &verify_sigalgs);
+ for (size_t i = 0; i < num_verify_sigalgs; i++) {
+ if (sigalg == verify_sigalgs[i]) {
+ return 1;
+ }
+ }
+
+ OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SIGNATURE_TYPE);
+ *out_alert = SSL_AD_ILLEGAL_PARAMETER;
+ return 0;
+}
+
+/* tls_extension represents a TLS extension that is handled internally. The
+ * |init| function is called for each handshake, before any other functions of
+ * the extension. Then the add and parse callbacks are called as needed.
+ *
+ * The parse callbacks receive a |CBS| that contains the contents of the
+ * extension (i.e. not including the type and length bytes). If an extension is
+ * not received then the parse callbacks will be called with a NULL CBS so that
+ * they can do any processing needed to handle the absence of an extension.
+ *
+ * The add callbacks receive a |CBB| to which the extension can be appended but
+ * the function is responsible for appending the type and length bytes too.
+ *
+ * All callbacks return one for success and zero for error. If a parse function
+ * returns zero then a fatal alert with value |*out_alert| will be sent. If
+ * |*out_alert| isn't set, then a |decode_error| alert will be sent. */
+struct tls_extension {
+ uint16_t value;
+ void (*init)(SSL_HANDSHAKE *hs);
+
+ int (*add_clienthello)(SSL_HANDSHAKE *hs, CBB *out);
+ int (*parse_serverhello)(SSL_HANDSHAKE *hs, uint8_t *out_alert,
+ CBS *contents);
+
+ int (*parse_clienthello)(SSL_HANDSHAKE *hs, uint8_t *out_alert,
+ CBS *contents);
+ int (*add_serverhello)(SSL_HANDSHAKE *hs, CBB *out);
+};
+
+static int forbid_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert,
+ CBS *contents) {
+ if (contents != NULL) {
+ /* Servers MUST NOT send this extension. */
+ *out_alert = SSL_AD_UNSUPPORTED_EXTENSION;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
+ return 0;
+ }
+
+ return 1;
+}
+
+static int ignore_parse_clienthello(SSL_HANDSHAKE *hs, uint8_t *out_alert,
+ CBS *contents) {
+ /* This extension from the client is handled elsewhere. */
+ return 1;
+}
+
+static int dont_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) {
+ return 1;
+}
+
+/* Server name indication (SNI).
+ *
+ * https://tools.ietf.org/html/rfc6066#section-3. */
+
+static int ext_sni_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
+ SSL *const ssl = hs->ssl;
+ if (ssl->tlsext_hostname == NULL) {
+ return 1;
+ }
+
+ CBB contents, server_name_list, name;
+ if (!CBB_add_u16(out, TLSEXT_TYPE_server_name) ||
+ !CBB_add_u16_length_prefixed(out, &contents) ||
+ !CBB_add_u16_length_prefixed(&contents, &server_name_list) ||
+ !CBB_add_u8(&server_name_list, TLSEXT_NAMETYPE_host_name) ||
+ !CBB_add_u16_length_prefixed(&server_name_list, &name) ||
+ !CBB_add_bytes(&name, (const uint8_t *)ssl->tlsext_hostname,
+ strlen(ssl->tlsext_hostname)) ||
+ !CBB_flush(out)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+static int ext_sni_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert,
+ CBS *contents) {
+ SSL *const ssl = hs->ssl;
+ if (contents == NULL) {
+ return 1;
+ }
+
+ if (CBS_len(contents) != 0) {
+ return 0;
+ }
+
+ assert(ssl->tlsext_hostname != NULL);
+
+ if (ssl->session == NULL) {
+ OPENSSL_free(hs->new_session->tlsext_hostname);
+ hs->new_session->tlsext_hostname = BUF_strdup(ssl->tlsext_hostname);
+ if (!hs->new_session->tlsext_hostname) {
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static int ext_sni_parse_clienthello(SSL_HANDSHAKE *hs, uint8_t *out_alert,
+ CBS *contents) {
+ if (contents == NULL) {
+ return 1;
+ }
+
+ CBS server_name_list, host_name;
+ uint8_t name_type;
+ if (!CBS_get_u16_length_prefixed(contents, &server_name_list) ||
+ !CBS_get_u8(&server_name_list, &name_type) ||
+ /* Although the server_name extension was intended to be extensible to
+ * new name types and multiple names, OpenSSL 1.0.x had a bug which meant
+ * different name types will cause an error. Further, RFC 4366 originally
+ * defined syntax inextensibly. RFC 6066 corrected this mistake, but
+ * adding new name types is no longer feasible.
+ *
+ * Act as if the extensibility does not exist to simplify parsing. */
+ !CBS_get_u16_length_prefixed(&server_name_list, &host_name) ||
+ CBS_len(&server_name_list) != 0 ||
+ CBS_len(contents) != 0) {
+ return 0;
+ }
+
+ if (name_type != TLSEXT_NAMETYPE_host_name ||
+ CBS_len(&host_name) == 0 ||
+ CBS_len(&host_name) > TLSEXT_MAXLEN_host_name ||
+ CBS_contains_zero_byte(&host_name)) {
+ *out_alert = SSL_AD_UNRECOGNIZED_NAME;
+ return 0;
+ }
+
+ /* Copy the hostname as a string. */
+ if (!CBS_strdup(&host_name, &hs->hostname)) {
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ return 0;
+ }
+
+ hs->should_ack_sni = 1;
+ return 1;
+}
+
+static int ext_sni_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) {
+ if (hs->ssl->s3->session_reused ||
+ !hs->should_ack_sni) {
+ return 1;
+ }
+
+ if (!CBB_add_u16(out, TLSEXT_TYPE_server_name) ||
+ !CBB_add_u16(out, 0 /* length */)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/* Renegotiation indication.
+ *
+ * https://tools.ietf.org/html/rfc5746 */
+
+static int ext_ri_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
+ SSL *const ssl = hs->ssl;
+ uint16_t min_version, max_version;
+ if (!ssl_get_version_range(ssl, &min_version, &max_version)) {
+ return 0;
+ }
+
+ /* Renegotiation indication is not necessary in TLS 1.3. */
+ if (min_version >= TLS1_3_VERSION) {
+ return 1;
+ }
+
+ assert(ssl->s3->initial_handshake_complete ==
+ (ssl->s3->previous_client_finished_len != 0));
+
+ CBB contents, prev_finished;
+ if (!CBB_add_u16(out, TLSEXT_TYPE_renegotiate) ||
+ !CBB_add_u16_length_prefixed(out, &contents) ||
+ !CBB_add_u8_length_prefixed(&contents, &prev_finished) ||
+ !CBB_add_bytes(&prev_finished, ssl->s3->previous_client_finished,
+ ssl->s3->previous_client_finished_len) ||
+ !CBB_flush(out)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+static int ext_ri_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert,
+ CBS *contents) {
+ SSL *const ssl = hs->ssl;
+ if (contents != NULL && ssl3_protocol_version(ssl) >= TLS1_3_VERSION) {
+ return 0;
+ }
+
+ /* Servers may not switch between omitting the extension and supporting it.
+ * See RFC 5746, sections 3.5 and 4.2. */
+ if (ssl->s3->initial_handshake_complete &&
+ (contents != NULL) != ssl->s3->send_connection_binding) {
+ *out_alert = SSL_AD_HANDSHAKE_FAILURE;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_RENEGOTIATION_MISMATCH);
+ return 0;
+ }
+
+ if (contents == NULL) {
+ /* Strictly speaking, if we want to avoid an attack we should *always* see
+ * RI even on initial ServerHello because the client doesn't see any
+ * renegotiation during an attack. However this would mean we could not
+ * connect to any server which doesn't support RI.
+ *
+ * OpenSSL has |SSL_OP_LEGACY_SERVER_CONNECT| to control this, but in
+ * practical terms every client sets it so it's just assumed here. */
+ return 1;
+ }
+
+ const size_t expected_len = ssl->s3->previous_client_finished_len +
+ ssl->s3->previous_server_finished_len;
+
+ /* Check for logic errors */
+ assert(!expected_len || ssl->s3->previous_client_finished_len);
+ assert(!expected_len || ssl->s3->previous_server_finished_len);
+ assert(ssl->s3->initial_handshake_complete ==
+ (ssl->s3->previous_client_finished_len != 0));
+ assert(ssl->s3->initial_handshake_complete ==
+ (ssl->s3->previous_server_finished_len != 0));
+
+ /* Parse out the extension contents. */
+ CBS renegotiated_connection;
+ if (!CBS_get_u8_length_prefixed(contents, &renegotiated_connection) ||
+ CBS_len(contents) != 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_RENEGOTIATION_ENCODING_ERR);
+ *out_alert = SSL_AD_ILLEGAL_PARAMETER;
+ return 0;
+ }
+
+ /* Check that the extension matches. */
+ if (CBS_len(&renegotiated_connection) != expected_len) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_RENEGOTIATION_MISMATCH);
+ *out_alert = SSL_AD_HANDSHAKE_FAILURE;
+ return 0;
+ }
+
+ const uint8_t *d = CBS_data(&renegotiated_connection);
+ if (CRYPTO_memcmp(d, ssl->s3->previous_client_finished,
+ ssl->s3->previous_client_finished_len)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_RENEGOTIATION_MISMATCH);
+ *out_alert = SSL_AD_HANDSHAKE_FAILURE;
+ return 0;
+ }
+ d += ssl->s3->previous_client_finished_len;
+
+ if (CRYPTO_memcmp(d, ssl->s3->previous_server_finished,
+ ssl->s3->previous_server_finished_len)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_RENEGOTIATION_MISMATCH);
+ *out_alert = SSL_AD_ILLEGAL_PARAMETER;
+ return 0;
+ }
+ ssl->s3->send_connection_binding = 1;
+
+ return 1;
+}
+
+static int ext_ri_parse_clienthello(SSL_HANDSHAKE *hs, uint8_t *out_alert,
+ CBS *contents) {
+ SSL *const ssl = hs->ssl;
+ /* Renegotiation isn't supported as a server so this function should never be
+ * called after the initial handshake. */
+ assert(!ssl->s3->initial_handshake_complete);
+
+ if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) {
+ return 1;
+ }
+
+ if (contents == NULL) {
+ return 1;
+ }
+
+ CBS renegotiated_connection;
+ if (!CBS_get_u8_length_prefixed(contents, &renegotiated_connection) ||
+ CBS_len(contents) != 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_RENEGOTIATION_ENCODING_ERR);
+ return 0;
+ }
+
+ /* Check that the extension matches. We do not support renegotiation as a
+ * server, so this must be empty. */
+ if (CBS_len(&renegotiated_connection) != 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_RENEGOTIATION_MISMATCH);
+ *out_alert = SSL_AD_HANDSHAKE_FAILURE;
+ return 0;
+ }
+
+ ssl->s3->send_connection_binding = 1;
+
+ return 1;
+}
+
+static int ext_ri_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) {
+ SSL *const ssl = hs->ssl;
+ /* Renegotiation isn't supported as a server so this function should never be
+ * called after the initial handshake. */
+ assert(!ssl->s3->initial_handshake_complete);
+
+ if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) {
+ return 1;
+ }
+
+ if (!CBB_add_u16(out, TLSEXT_TYPE_renegotiate) ||
+ !CBB_add_u16(out, 1 /* length */) ||
+ !CBB_add_u8(out, 0 /* empty renegotiation info */)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/* Extended Master Secret.
+ *
+ * https://tools.ietf.org/html/rfc7627 */
+
+static int ext_ems_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
+ uint16_t min_version, max_version;
+ if (!ssl_get_version_range(hs->ssl, &min_version, &max_version)) {
+ return 0;
+ }
+
+ /* Extended master secret is not necessary in TLS 1.3. */
+ if (min_version >= TLS1_3_VERSION || max_version <= SSL3_VERSION) {
+ return 1;
+ }
+
+ if (!CBB_add_u16(out, TLSEXT_TYPE_extended_master_secret) ||
+ !CBB_add_u16(out, 0 /* length */)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+static int ext_ems_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert,
+ CBS *contents) {
+ SSL *const ssl = hs->ssl;
+
+ if (contents != NULL) {
+ if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION ||
+ ssl->version == SSL3_VERSION ||
+ CBS_len(contents) != 0) {
+ return 0;
+ }
+
+ hs->extended_master_secret = 1;
+ }
+
+ /* Whether EMS is negotiated may not change on renegotiation. */
+ if (ssl->s3->established_session != NULL &&
+ hs->extended_master_secret !=
+ ssl->s3->established_session->extended_master_secret) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_RENEGOTIATION_EMS_MISMATCH);
+ *out_alert = SSL_AD_ILLEGAL_PARAMETER;
+ return 0;
+ }
+
+ return 1;
+}
+
+static int ext_ems_parse_clienthello(SSL_HANDSHAKE *hs, uint8_t *out_alert,
+ CBS *contents) {
+ uint16_t version = ssl3_protocol_version(hs->ssl);
+ if (version >= TLS1_3_VERSION ||
+ version == SSL3_VERSION) {
+ return 1;
+ }
+
+ if (contents == NULL) {
+ return 1;
+ }
+
+ if (CBS_len(contents) != 0) {
+ return 0;
+ }
+
+ hs->extended_master_secret = 1;
+ return 1;
+}
+
+static int ext_ems_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) {
+ if (!hs->extended_master_secret) {
+ return 1;
+ }
+
+ if (!CBB_add_u16(out, TLSEXT_TYPE_extended_master_secret) ||
+ !CBB_add_u16(out, 0 /* length */)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/* Session tickets.
+ *
+ * https://tools.ietf.org/html/rfc5077 */
+
+static int ext_ticket_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
+ SSL *const ssl = hs->ssl;
+ uint16_t min_version, max_version;
+ if (!ssl_get_version_range(ssl, &min_version, &max_version)) {
+ return 0;
+ }
+
+ /* TLS 1.3 uses a different ticket extension. */
+ if (min_version >= TLS1_3_VERSION ||
+ SSL_get_options(ssl) & SSL_OP_NO_TICKET) {
+ return 1;
+ }
+
+ const uint8_t *ticket_data = NULL;
+ int ticket_len = 0;
+
+ /* Renegotiation does not participate in session resumption. However, still
+ * advertise the extension to avoid potentially breaking servers which carry
+ * over the state from the previous handshake, such as OpenSSL servers
+ * without upstream's 3c3f0259238594d77264a78944d409f2127642c4. */
+ uint16_t session_version;
+ if (!ssl->s3->initial_handshake_complete &&
+ ssl->session != NULL &&
+ ssl->session->tlsext_tick != NULL &&
+ /* Don't send TLS 1.3 session tickets in the ticket extension. */
+ ssl->method->version_from_wire(&session_version,
+ ssl->session->ssl_version) &&
+ session_version < TLS1_3_VERSION) {
+ ticket_data = ssl->session->tlsext_tick;
+ ticket_len = ssl->session->tlsext_ticklen;
+ }
+
+ CBB ticket;
+ if (!CBB_add_u16(out, TLSEXT_TYPE_session_ticket) ||
+ !CBB_add_u16_length_prefixed(out, &ticket) ||
+ !CBB_add_bytes(&ticket, ticket_data, ticket_len) ||
+ !CBB_flush(out)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+static int ext_ticket_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert,
+ CBS *contents) {
+ SSL *const ssl = hs->ssl;
+ if (contents == NULL) {
+ return 1;
+ }
+
+ if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) {
+ return 0;
+ }
+
+ /* If |SSL_OP_NO_TICKET| is set then no extension will have been sent and
+ * this function should never be called, even if the server tries to send the
+ * extension. */
+ assert((SSL_get_options(ssl) & SSL_OP_NO_TICKET) == 0);
+
+ if (CBS_len(contents) != 0) {
+ return 0;
+ }
+
+ hs->ticket_expected = 1;
+ return 1;
+}
+
+static int ext_ticket_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) {
+ if (!hs->ticket_expected) {
+ return 1;
+ }
+
+ /* If |SSL_OP_NO_TICKET| is set, |ticket_expected| should never be true. */
+ assert((SSL_get_options(hs->ssl) & SSL_OP_NO_TICKET) == 0);
+
+ if (!CBB_add_u16(out, TLSEXT_TYPE_session_ticket) ||
+ !CBB_add_u16(out, 0 /* length */)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/* Signature Algorithms.
+ *
+ * https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */
+
+static int ext_sigalgs_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
+ SSL *const ssl = hs->ssl;
+ uint16_t min_version, max_version;
+ if (!ssl_get_version_range(ssl, &min_version, &max_version)) {
+ return 0;
+ }
+
+ if (max_version < TLS1_2_VERSION) {
+ return 1;
+ }
+
+ const uint16_t *sigalgs;
+ const size_t num_sigalgs = tls12_get_verify_sigalgs(ssl, &sigalgs);
+
+ CBB contents, sigalgs_cbb;
+ if (!CBB_add_u16(out, TLSEXT_TYPE_signature_algorithms) ||
+ !CBB_add_u16_length_prefixed(out, &contents) ||
+ !CBB_add_u16_length_prefixed(&contents, &sigalgs_cbb)) {
+ return 0;
+ }
+
+ for (size_t i = 0; i < num_sigalgs; i++) {
+ if (!CBB_add_u16(&sigalgs_cbb, sigalgs[i])) {
+ return 0;
+ }
+ }
+
+ if (!CBB_flush(out)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+static int ext_sigalgs_parse_clienthello(SSL_HANDSHAKE *hs, uint8_t *out_alert,
+ CBS *contents) {
+ OPENSSL_free(hs->peer_sigalgs);
+ hs->peer_sigalgs = NULL;
+ hs->num_peer_sigalgs = 0;
+
+ if (contents == NULL) {
+ return 1;
+ }
+
+ CBS supported_signature_algorithms;
+ if (!CBS_get_u16_length_prefixed(contents, &supported_signature_algorithms) ||
+ CBS_len(contents) != 0 ||
+ CBS_len(&supported_signature_algorithms) == 0 ||
+ !tls1_parse_peer_sigalgs(hs, &supported_signature_algorithms)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/* OCSP Stapling.
+ *
+ * https://tools.ietf.org/html/rfc6066#section-8 */
+
+static int ext_ocsp_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
+ SSL *const ssl = hs->ssl;
+ if (!ssl->ocsp_stapling_enabled) {
+ return 1;
+ }
+
+ CBB contents;
+ if (!CBB_add_u16(out, TLSEXT_TYPE_status_request) ||
+ !CBB_add_u16_length_prefixed(out, &contents) ||
+ !CBB_add_u8(&contents, TLSEXT_STATUSTYPE_ocsp) ||
+ !CBB_add_u16(&contents, 0 /* empty responder ID list */) ||
+ !CBB_add_u16(&contents, 0 /* empty request extensions */) ||
+ !CBB_flush(out)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+static int ext_ocsp_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert,
+ CBS *contents) {
+ SSL *const ssl = hs->ssl;
+ if (contents == NULL) {
+ return 1;
+ }
+
+ /* TLS 1.3 OCSP responses are included in the Certificate extensions. */
+ if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) {
+ return 0;
+ }
+
+ /* OCSP stapling is forbidden on non-certificate ciphers. */
+ if (CBS_len(contents) != 0 ||
+ !ssl_cipher_uses_certificate_auth(hs->new_cipher)) {
+ return 0;
+ }
+
+ /* Note this does not check for resumption in TLS 1.2. Sending
+ * status_request here does not make sense, but OpenSSL does so and the
+ * specification does not say anything. Tolerate it but ignore it. */
+
+ hs->certificate_status_expected = 1;
+ return 1;
+}
+
+static int ext_ocsp_parse_clienthello(SSL_HANDSHAKE *hs, uint8_t *out_alert,
+ CBS *contents) {
+ if (contents == NULL) {
+ return 1;
+ }
+
+ uint8_t status_type;
+ if (!CBS_get_u8(contents, &status_type)) {
+ return 0;
+ }
+
+ /* We cannot decide whether OCSP stapling will occur yet because the correct
+ * SSL_CTX might not have been selected. */
+ hs->ocsp_stapling_requested = status_type == TLSEXT_STATUSTYPE_ocsp;
+
+ return 1;
+}
+
+static int ext_ocsp_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) {
+ SSL *const ssl = hs->ssl;
+ if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION ||
+ !hs->ocsp_stapling_requested ||
+ ssl->cert->ocsp_response == NULL ||
+ ssl->s3->session_reused ||
+ !ssl_cipher_uses_certificate_auth(hs->new_cipher)) {
+ return 1;
+ }
+
+ hs->certificate_status_expected = 1;
+
+ return CBB_add_u16(out, TLSEXT_TYPE_status_request) &&
+ CBB_add_u16(out, 0 /* length */);
+}
+
+
+/* Next protocol negotiation.
+ *
+ * https://htmlpreview.github.io/?https://github.com/agl/technotes/blob/master/nextprotoneg.html */
+
+static int ext_npn_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
+ SSL *const ssl = hs->ssl;
+ if (ssl->s3->initial_handshake_complete ||
+ ssl->ctx->next_proto_select_cb == NULL ||
+ SSL_is_dtls(ssl)) {
+ return 1;
+ }
+
+ if (!CBB_add_u16(out, TLSEXT_TYPE_next_proto_neg) ||
+ !CBB_add_u16(out, 0 /* length */)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+static int ext_npn_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert,
+ CBS *contents) {
+ SSL *const ssl = hs->ssl;
+ if (contents == NULL) {
+ return 1;
+ }
+
+ if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) {
+ return 0;
+ }
+
+ /* If any of these are false then we should never have sent the NPN
+ * extension in the ClientHello and thus this function should never have been
+ * called. */
+ assert(!ssl->s3->initial_handshake_complete);
+ assert(!SSL_is_dtls(ssl));
+ assert(ssl->ctx->next_proto_select_cb != NULL);
+
+ if (ssl->s3->alpn_selected != NULL) {
+ /* NPN and ALPN may not be negotiated in the same connection. */
+ *out_alert = SSL_AD_ILLEGAL_PARAMETER;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NEGOTIATED_BOTH_NPN_AND_ALPN);
+ return 0;
+ }
+
+ const uint8_t *const orig_contents = CBS_data(contents);
+ const size_t orig_len = CBS_len(contents);
+
+ while (CBS_len(contents) != 0) {
+ CBS proto;
+ if (!CBS_get_u8_length_prefixed(contents, &proto) ||
+ CBS_len(&proto) == 0) {
+ return 0;
+ }
+ }
+
+ uint8_t *selected;
+ uint8_t selected_len;
+ if (ssl->ctx->next_proto_select_cb(
+ ssl, &selected, &selected_len, orig_contents, orig_len,
+ ssl->ctx->next_proto_select_cb_arg) != SSL_TLSEXT_ERR_OK) {
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ return 0;
+ }
+
+ OPENSSL_free(ssl->s3->next_proto_negotiated);
+ ssl->s3->next_proto_negotiated = BUF_memdup(selected, selected_len);
+ if (ssl->s3->next_proto_negotiated == NULL) {
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ return 0;
+ }
+
+ ssl->s3->next_proto_negotiated_len = selected_len;
+ hs->next_proto_neg_seen = 1;
+
+ return 1;
+}
+
+static int ext_npn_parse_clienthello(SSL_HANDSHAKE *hs, uint8_t *out_alert,
+ CBS *contents) {
+ SSL *const ssl = hs->ssl;
+ if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) {
+ return 1;
+ }
+
+ if (contents != NULL && CBS_len(contents) != 0) {
+ return 0;
+ }
+
+ if (contents == NULL ||
+ ssl->s3->initial_handshake_complete ||
+ ssl->ctx->next_protos_advertised_cb == NULL ||
+ SSL_is_dtls(ssl)) {
+ return 1;
+ }
+
+ hs->next_proto_neg_seen = 1;
+ return 1;
+}
+
+static int ext_npn_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) {
+ SSL *const ssl = hs->ssl;
+ /* |next_proto_neg_seen| might have been cleared when an ALPN extension was
+ * parsed. */
+ if (!hs->next_proto_neg_seen) {
+ return 1;
+ }
+
+ const uint8_t *npa;
+ unsigned npa_len;
+
+ if (ssl->ctx->next_protos_advertised_cb(
+ ssl, &npa, &npa_len, ssl->ctx->next_protos_advertised_cb_arg) !=
+ SSL_TLSEXT_ERR_OK) {
+ hs->next_proto_neg_seen = 0;
+ return 1;
+ }
+
+ CBB contents;
+ if (!CBB_add_u16(out, TLSEXT_TYPE_next_proto_neg) ||
+ !CBB_add_u16_length_prefixed(out, &contents) ||
+ !CBB_add_bytes(&contents, npa, npa_len) ||
+ !CBB_flush(out)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/* Signed certificate timestamps.
+ *
+ * https://tools.ietf.org/html/rfc6962#section-3.3.1 */
+
+static int ext_sct_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
+ SSL *const ssl = hs->ssl;
+ if (!ssl->signed_cert_timestamps_enabled) {
+ return 1;
+ }
+
+ if (!CBB_add_u16(out, TLSEXT_TYPE_certificate_timestamp) ||
+ !CBB_add_u16(out, 0 /* length */)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+static int ext_sct_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert,
+ CBS *contents) {
+ SSL *const ssl = hs->ssl;
+ if (contents == NULL) {
+ return 1;
+ }
+
+ /* TLS 1.3 SCTs are included in the Certificate extensions. */
+ if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) {
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ /* If this is false then we should never have sent the SCT extension in the
+ * ClientHello and thus this function should never have been called. */
+ assert(ssl->signed_cert_timestamps_enabled);
+
+ if (!ssl_is_sct_list_valid(contents)) {
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ /* Session resumption uses the original session information. The extension
+ * should not be sent on resumption, but RFC 6962 did not make it a
+ * requirement, so tolerate this.
+ *
+ * TODO(davidben): Enforce this anyway. */
+ if (!ssl->s3->session_reused &&
+ !CBS_stow(contents, &hs->new_session->tlsext_signed_cert_timestamp_list,
+ &hs->new_session->tlsext_signed_cert_timestamp_list_length)) {
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ return 0;
+ }
+
+ return 1;
+}
+
+static int ext_sct_parse_clienthello(SSL_HANDSHAKE *hs, uint8_t *out_alert,
+ CBS *contents) {
+ if (contents == NULL) {
+ return 1;
+ }
+
+ if (CBS_len(contents) != 0) {
+ return 0;
+ }
+
+ hs->scts_requested = 1;
+ return 1;
+}
+
+static int ext_sct_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) {
+ SSL *const ssl = hs->ssl;
+ /* The extension shouldn't be sent when resuming sessions. */
+ if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION ||
+ ssl->s3->session_reused ||
+ ssl->cert->signed_cert_timestamp_list == NULL) {
+ return 1;
+ }
+
+ CBB contents;
+ return CBB_add_u16(out, TLSEXT_TYPE_certificate_timestamp) &&
+ CBB_add_u16_length_prefixed(out, &contents) &&
+ CBB_add_bytes(
+ &contents,
+ CRYPTO_BUFFER_data(ssl->cert->signed_cert_timestamp_list),
+ CRYPTO_BUFFER_len(ssl->cert->signed_cert_timestamp_list)) &&
+ CBB_flush(out);
+}
+
+
+/* Application-level Protocol Negotiation.
+ *
+ * https://tools.ietf.org/html/rfc7301 */
+
+static int ext_alpn_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
+ SSL *const ssl = hs->ssl;
+ if (ssl->alpn_client_proto_list == NULL ||
+ ssl->s3->initial_handshake_complete) {
+ return 1;
+ }
+
+ CBB contents, proto_list;
+ if (!CBB_add_u16(out, TLSEXT_TYPE_application_layer_protocol_negotiation) ||
+ !CBB_add_u16_length_prefixed(out, &contents) ||
+ !CBB_add_u16_length_prefixed(&contents, &proto_list) ||
+ !CBB_add_bytes(&proto_list, ssl->alpn_client_proto_list,
+ ssl->alpn_client_proto_list_len) ||
+ !CBB_flush(out)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+static int ext_alpn_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert,
+ CBS *contents) {
+ SSL *const ssl = hs->ssl;
+ if (contents == NULL) {
+ return 1;
+ }
+
+ assert(!ssl->s3->initial_handshake_complete);
+ assert(ssl->alpn_client_proto_list != NULL);
+
+ if (hs->next_proto_neg_seen) {
+ /* NPN and ALPN may not be negotiated in the same connection. */
+ *out_alert = SSL_AD_ILLEGAL_PARAMETER;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NEGOTIATED_BOTH_NPN_AND_ALPN);
+ return 0;
+ }
+
+ /* The extension data consists of a ProtocolNameList which must have
+ * exactly one ProtocolName. Each of these is length-prefixed. */
+ CBS protocol_name_list, protocol_name;
+ if (!CBS_get_u16_length_prefixed(contents, &protocol_name_list) ||
+ CBS_len(contents) != 0 ||
+ !CBS_get_u8_length_prefixed(&protocol_name_list, &protocol_name) ||
+ /* Empty protocol names are forbidden. */
+ CBS_len(&protocol_name) == 0 ||
+ CBS_len(&protocol_name_list) != 0) {
+ return 0;
+ }
+
+ /* Check that the protcol name is one of the ones we advertised. */
+ int protocol_ok = 0;
+ CBS client_protocol_name_list, client_protocol_name;
+ CBS_init(&client_protocol_name_list, ssl->alpn_client_proto_list,
+ ssl->alpn_client_proto_list_len);
+ while (CBS_len(&client_protocol_name_list) > 0) {
+ if (!CBS_get_u8_length_prefixed(&client_protocol_name_list,
+ &client_protocol_name)) {
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ return 0;
+ }
+
+ if (CBS_len(&client_protocol_name) == CBS_len(&protocol_name) &&
+ OPENSSL_memcmp(CBS_data(&client_protocol_name),
+ CBS_data(&protocol_name),
+ CBS_len(&protocol_name)) == 0) {
+ protocol_ok = 1;
+ break;
+ }
+ }
+
+ if (!protocol_ok) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_ALPN_PROTOCOL);
+ *out_alert = SSL_AD_ILLEGAL_PARAMETER;
+ return 0;
+ }
+
+ if (!CBS_stow(&protocol_name, &ssl->s3->alpn_selected,
+ &ssl->s3->alpn_selected_len)) {
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ return 0;
+ }
+
+ return 1;
+}
+
+int ssl_negotiate_alpn(SSL_HANDSHAKE *hs, uint8_t *out_alert,
+ const SSL_CLIENT_HELLO *client_hello) {
+ SSL *const ssl = hs->ssl;
+ CBS contents;
+ if (ssl->ctx->alpn_select_cb == NULL ||
+ !ssl_client_hello_get_extension(
+ client_hello, &contents,
+ TLSEXT_TYPE_application_layer_protocol_negotiation)) {
+ /* Ignore ALPN if not configured or no extension was supplied. */
+ return 1;
+ }
+
+ /* ALPN takes precedence over NPN. */
+ hs->next_proto_neg_seen = 0;
+
+ CBS protocol_name_list;
+ if (!CBS_get_u16_length_prefixed(&contents, &protocol_name_list) ||
+ CBS_len(&contents) != 0 ||
+ CBS_len(&protocol_name_list) < 2) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT);
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ /* Validate the protocol list. */
+ CBS protocol_name_list_copy = protocol_name_list;
+ while (CBS_len(&protocol_name_list_copy) > 0) {
+ CBS protocol_name;
+
+ if (!CBS_get_u8_length_prefixed(&protocol_name_list_copy, &protocol_name) ||
+ /* Empty protocol names are forbidden. */
+ CBS_len(&protocol_name) == 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT);
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ }
+
+ const uint8_t *selected;
+ uint8_t selected_len;
+ if (ssl->ctx->alpn_select_cb(
+ ssl, &selected, &selected_len, CBS_data(&protocol_name_list),
+ CBS_len(&protocol_name_list),
+ ssl->ctx->alpn_select_cb_arg) == SSL_TLSEXT_ERR_OK) {
+ OPENSSL_free(ssl->s3->alpn_selected);
+ ssl->s3->alpn_selected = BUF_memdup(selected, selected_len);
+ if (ssl->s3->alpn_selected == NULL) {
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ ssl->s3->alpn_selected_len = selected_len;
+ }
+
+ return 1;
+}
+
+static int ext_alpn_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) {
+ SSL *const ssl = hs->ssl;
+ if (ssl->s3->alpn_selected == NULL) {
+ return 1;
+ }
+
+ CBB contents, proto_list, proto;
+ if (!CBB_add_u16(out, TLSEXT_TYPE_application_layer_protocol_negotiation) ||
+ !CBB_add_u16_length_prefixed(out, &contents) ||
+ !CBB_add_u16_length_prefixed(&contents, &proto_list) ||
+ !CBB_add_u8_length_prefixed(&proto_list, &proto) ||
+ !CBB_add_bytes(&proto, ssl->s3->alpn_selected,
+ ssl->s3->alpn_selected_len) ||
+ !CBB_flush(out)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/* Channel ID.
+ *
+ * https://tools.ietf.org/html/draft-balfanz-tls-channelid-01 */
+
+static void ext_channel_id_init(SSL_HANDSHAKE *hs) {
+ hs->ssl->s3->tlsext_channel_id_valid = 0;
+}
+
+static int ext_channel_id_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
+ SSL *const ssl = hs->ssl;
+ if (!ssl->tlsext_channel_id_enabled ||
+ SSL_is_dtls(ssl)) {
+ return 1;
+ }
+
+ if (!CBB_add_u16(out, TLSEXT_TYPE_channel_id) ||
+ !CBB_add_u16(out, 0 /* length */)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+static int ext_channel_id_parse_serverhello(SSL_HANDSHAKE *hs,
+ uint8_t *out_alert, CBS *contents) {
+ SSL *const ssl = hs->ssl;
+ if (contents == NULL) {
+ return 1;
+ }
+
+ assert(!SSL_is_dtls(ssl));
+ assert(ssl->tlsext_channel_id_enabled);
+
+ if (CBS_len(contents) != 0) {
+ return 0;
+ }
+
+ ssl->s3->tlsext_channel_id_valid = 1;
+ return 1;
+}
+
+static int ext_channel_id_parse_clienthello(SSL_HANDSHAKE *hs,
+ uint8_t *out_alert, CBS *contents) {
+ SSL *const ssl = hs->ssl;
+ if (contents == NULL ||
+ !ssl->tlsext_channel_id_enabled ||
+ SSL_is_dtls(ssl)) {
+ return 1;
+ }
+
+ if (CBS_len(contents) != 0) {
+ return 0;
+ }
+
+ ssl->s3->tlsext_channel_id_valid = 1;
+ return 1;
+}
+
+static int ext_channel_id_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) {
+ SSL *const ssl = hs->ssl;
+ if (!ssl->s3->tlsext_channel_id_valid) {
+ return 1;
+ }
+
+ if (!CBB_add_u16(out, TLSEXT_TYPE_channel_id) ||
+ !CBB_add_u16(out, 0 /* length */)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/* Secure Real-time Transport Protocol (SRTP) extension.
+ *
+ * https://tools.ietf.org/html/rfc5764 */
+
+
+static void ext_srtp_init(SSL_HANDSHAKE *hs) {
+ hs->ssl->srtp_profile = NULL;
+}
+
+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) {
+ return 1;
+ }
+
+ CBB contents, profile_ids;
+ if (!CBB_add_u16(out, TLSEXT_TYPE_srtp) ||
+ !CBB_add_u16_length_prefixed(out, &contents) ||
+ !CBB_add_u16_length_prefixed(&contents, &profile_ids)) {
+ 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)) {
+ return 0;
+ }
+ }
+
+ if (!CBB_add_u8(&contents, 0 /* empty use_mki value */) ||
+ !CBB_flush(out)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+static int ext_srtp_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert,
+ CBS *contents) {
+ SSL *const ssl = hs->ssl;
+ if (contents == NULL) {
+ return 1;
+ }
+
+ /* The extension consists of a u16-prefixed profile ID list containing a
+ * single uint16_t profile ID, then followed by a u8-prefixed srtp_mki field.
+ *
+ * See https://tools.ietf.org/html/rfc5764#section-4.1.1 */
+ CBS profile_ids, srtp_mki;
+ uint16_t profile_id;
+ if (!CBS_get_u16_length_prefixed(contents, &profile_ids) ||
+ !CBS_get_u16(&profile_ids, &profile_id) ||
+ CBS_len(&profile_ids) != 0 ||
+ !CBS_get_u8_length_prefixed(contents, &srtp_mki) ||
+ CBS_len(contents) != 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST);
+ return 0;
+ }
+
+ if (CBS_len(&srtp_mki) != 0) {
+ /* Must be no MKI, since we never offer one. */
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SRTP_MKI_VALUE);
+ *out_alert = SSL_AD_ILLEGAL_PARAMETER;
+ return 0;
+ }
+
+ STACK_OF(SRTP_PROTECTION_PROFILE) *profiles = SSL_get_srtp_profiles(ssl);
+
+ /* 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);
+
+ if (profile->id == profile_id) {
+ ssl->srtp_profile = profile;
+ return 1;
+ }
+ }
+
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST);
+ *out_alert = SSL_AD_ILLEGAL_PARAMETER;
+ return 0;
+}
+
+static int ext_srtp_parse_clienthello(SSL_HANDSHAKE *hs, uint8_t *out_alert,
+ CBS *contents) {
+ SSL *const ssl = hs->ssl;
+ if (contents == NULL) {
+ return 1;
+ }
+
+ CBS profile_ids, srtp_mki;
+ if (!CBS_get_u16_length_prefixed(contents, &profile_ids) ||
+ CBS_len(&profile_ids) < 2 ||
+ !CBS_get_u8_length_prefixed(contents, &srtp_mki) ||
+ CBS_len(contents) != 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST);
+ return 0;
+ }
+ /* Discard the MKI value for now. */
+
+ const STACK_OF(SRTP_PROTECTION_PROFILE) *server_profiles =
+ 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);
+
+ CBS profile_ids_tmp;
+ CBS_init(&profile_ids_tmp, CBS_data(&profile_ids), CBS_len(&profile_ids));
+
+ while (CBS_len(&profile_ids_tmp) > 0) {
+ uint16_t profile_id;
+ if (!CBS_get_u16(&profile_ids_tmp, &profile_id)) {
+ return 0;
+ }
+
+ if (server_profile->id == profile_id) {
+ ssl->srtp_profile = server_profile;
+ return 1;
+ }
+ }
+ }
+
+ return 1;
+}
+
+static int ext_srtp_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) {
+ SSL *const ssl = hs->ssl;
+ if (ssl->srtp_profile == NULL) {
+ return 1;
+ }
+
+ CBB contents, profile_ids;
+ if (!CBB_add_u16(out, TLSEXT_TYPE_srtp) ||
+ !CBB_add_u16_length_prefixed(out, &contents) ||
+ !CBB_add_u16_length_prefixed(&contents, &profile_ids) ||
+ !CBB_add_u16(&profile_ids, ssl->srtp_profile->id) ||
+ !CBB_add_u8(&contents, 0 /* empty MKI */) ||
+ !CBB_flush(out)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/* EC point formats.
+ *
+ * https://tools.ietf.org/html/rfc4492#section-5.1.2 */
+
+static int ext_ec_point_add_extension(SSL_HANDSHAKE *hs, CBB *out) {
+ CBB contents, formats;
+ if (!CBB_add_u16(out, TLSEXT_TYPE_ec_point_formats) ||
+ !CBB_add_u16_length_prefixed(out, &contents) ||
+ !CBB_add_u8_length_prefixed(&contents, &formats) ||
+ !CBB_add_u8(&formats, TLSEXT_ECPOINTFORMAT_uncompressed) ||
+ !CBB_flush(out)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+static int ext_ec_point_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
+ uint16_t min_version, max_version;
+ if (!ssl_get_version_range(hs->ssl, &min_version, &max_version)) {
+ return 0;
+ }
+
+ /* The point format extension is unneccessary in TLS 1.3. */
+ if (min_version >= TLS1_3_VERSION) {
+ return 1;
+ }
+
+ return ext_ec_point_add_extension(hs, out);
+}
+
+static int ext_ec_point_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert,
+ CBS *contents) {
+ if (contents == NULL) {
+ return 1;
+ }
+
+ if (ssl3_protocol_version(hs->ssl) >= TLS1_3_VERSION) {
+ return 0;
+ }
+
+ CBS ec_point_format_list;
+ if (!CBS_get_u8_length_prefixed(contents, &ec_point_format_list) ||
+ CBS_len(contents) != 0) {
+ return 0;
+ }
+
+ /* Per RFC 4492, section 5.1.2, implementations MUST support the uncompressed
+ * point format. */
+ if (OPENSSL_memchr(CBS_data(&ec_point_format_list),
+ TLSEXT_ECPOINTFORMAT_uncompressed,
+ CBS_len(&ec_point_format_list)) == NULL) {
+ *out_alert = SSL_AD_ILLEGAL_PARAMETER;
+ return 0;
+ }
+
+ return 1;
+}
+
+static int ext_ec_point_parse_clienthello(SSL_HANDSHAKE *hs, uint8_t *out_alert,
+ CBS *contents) {
+ if (ssl3_protocol_version(hs->ssl) >= TLS1_3_VERSION) {
+ return 1;
+ }
+
+ return ext_ec_point_parse_serverhello(hs, out_alert, contents);
+}
+
+static int ext_ec_point_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) {
+ SSL *const ssl = hs->ssl;
+ if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) {
+ return 1;
+ }
+
+ const uint32_t alg_k = hs->new_cipher->algorithm_mkey;
+ const uint32_t alg_a = hs->new_cipher->algorithm_auth;
+ const int using_ecc = (alg_k & SSL_kECDHE) || (alg_a & SSL_aECDSA);
+
+ if (!using_ecc) {
+ return 1;
+ }
+
+ return ext_ec_point_add_extension(hs, out);
+}
+
+
+/* Pre Shared Key
+ *
+ * https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.6 */
+
+static size_t ext_pre_shared_key_clienthello_length(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ uint16_t min_version, max_version;
+ if (!ssl_get_version_range(ssl, &min_version, &max_version)) {
+ return 0;
+ }
+
+ uint16_t session_version;
+ if (max_version < TLS1_3_VERSION || ssl->session == NULL ||
+ !ssl->method->version_from_wire(&session_version,
+ ssl->session->ssl_version) ||
+ session_version < TLS1_3_VERSION) {
+ return 0;
+ }
+
+ const EVP_MD *digest = SSL_SESSION_get_digest(ssl->session, ssl);
+ if (digest == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ size_t binder_len = EVP_MD_size(digest);
+ return 15 + ssl->session->tlsext_ticklen + binder_len;
+}
+
+static int ext_pre_shared_key_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
+ SSL *const ssl = hs->ssl;
+ uint16_t min_version, max_version;
+ if (!ssl_get_version_range(ssl, &min_version, &max_version)) {
+ return 0;
+ }
+
+ uint16_t session_version;
+ if (max_version < TLS1_3_VERSION || ssl->session == NULL ||
+ !ssl->method->version_from_wire(&session_version,
+ ssl->session->ssl_version) ||
+ session_version < TLS1_3_VERSION) {
+ return 1;
+ }
+
+ struct OPENSSL_timeval now;
+ ssl_get_current_time(ssl, &now);
+ uint32_t ticket_age = 1000 * (now.tv_sec - ssl->session->time);
+ uint32_t obfuscated_ticket_age = ticket_age + ssl->session->ticket_age_add;
+
+ /* Fill in a placeholder zero binder of the appropriate length. It will be
+ * computed and filled in later after length prefixes are computed. */
+ uint8_t zero_binder[EVP_MAX_MD_SIZE] = {0};
+
+ const EVP_MD *digest = SSL_SESSION_get_digest(ssl->session, ssl);
+ if (digest == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ size_t binder_len = EVP_MD_size(digest);
+
+ CBB contents, identity, ticket, binders, binder;
+ if (!CBB_add_u16(out, TLSEXT_TYPE_pre_shared_key) ||
+ !CBB_add_u16_length_prefixed(out, &contents) ||
+ !CBB_add_u16_length_prefixed(&contents, &identity) ||
+ !CBB_add_u16_length_prefixed(&identity, &ticket) ||
+ !CBB_add_bytes(&ticket, ssl->session->tlsext_tick,
+ ssl->session->tlsext_ticklen) ||
+ !CBB_add_u32(&identity, obfuscated_ticket_age) ||
+ !CBB_add_u16_length_prefixed(&contents, &binders) ||
+ !CBB_add_u8_length_prefixed(&binders, &binder) ||
+ !CBB_add_bytes(&binder, zero_binder, binder_len)) {
+ return 0;
+ }
+
+ hs->needs_psk_binder = 1;
+ return CBB_flush(out);
+}
+
+int ssl_ext_pre_shared_key_parse_serverhello(SSL_HANDSHAKE *hs,
+ uint8_t *out_alert,
+ CBS *contents) {
+ uint16_t psk_id;
+ if (!CBS_get_u16(contents, &psk_id) ||
+ CBS_len(contents) != 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ /* We only advertise one PSK identity, so the only legal index is zero. */
+ if (psk_id != 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_PSK_IDENTITY_NOT_FOUND);
+ *out_alert = SSL_AD_UNKNOWN_PSK_IDENTITY;
+ return 0;
+ }
+
+ return 1;
+}
+
+int ssl_ext_pre_shared_key_parse_clienthello(
+ SSL_HANDSHAKE *hs, CBS *out_ticket, CBS *out_binders,
+ uint32_t *out_obfuscated_ticket_age, uint8_t *out_alert, CBS *contents) {
+ /* We only process the first PSK identity since we don't support pure PSK. */
+ CBS identities, binders;
+ if (!CBS_get_u16_length_prefixed(contents, &identities) ||
+ !CBS_get_u16_length_prefixed(&identities, out_ticket) ||
+ !CBS_get_u32(&identities, out_obfuscated_ticket_age) ||
+ !CBS_get_u16_length_prefixed(contents, &binders) ||
+ CBS_len(&binders) == 0 ||
+ CBS_len(contents) != 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ *out_binders = binders;
+
+ /* Check the syntax of the remaining identities, but do not process them. */
+ size_t num_identities = 1;
+ while (CBS_len(&identities) != 0) {
+ CBS unused_ticket;
+ uint32_t unused_obfuscated_ticket_age;
+ if (!CBS_get_u16_length_prefixed(&identities, &unused_ticket) ||
+ !CBS_get_u32(&identities, &unused_obfuscated_ticket_age)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ num_identities++;
+ }
+
+ /* Check the syntax of the binders. The value will be checked later if
+ * resuming. */
+ size_t num_binders = 0;
+ while (CBS_len(&binders) != 0) {
+ CBS binder;
+ if (!CBS_get_u8_length_prefixed(&binders, &binder)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ num_binders++;
+ }
+
+ if (num_identities != num_binders) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_PSK_IDENTITY_BINDER_COUNT_MISMATCH);
+ *out_alert = SSL_AD_ILLEGAL_PARAMETER;
+ return 0;
+ }
+
+ return 1;
+}
+
+int ssl_ext_pre_shared_key_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) {
+ if (!hs->ssl->s3->session_reused) {
+ return 1;
+ }
+
+ CBB contents;
+ if (!CBB_add_u16(out, TLSEXT_TYPE_pre_shared_key) ||
+ !CBB_add_u16_length_prefixed(out, &contents) ||
+ /* We only consider the first identity for resumption */
+ !CBB_add_u16(&contents, 0) ||
+ !CBB_flush(out)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/* Pre-Shared Key Exchange Modes
+ *
+ * https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.7 */
+
+static int ext_psk_key_exchange_modes_add_clienthello(SSL_HANDSHAKE *hs,
+ CBB *out) {
+ SSL *const ssl = hs->ssl;
+ uint16_t min_version, max_version;
+ if (!ssl_get_version_range(ssl, &min_version, &max_version)) {
+ return 0;
+ }
+
+ if (max_version < TLS1_3_VERSION) {
+ return 1;
+ }
+
+ CBB contents, ke_modes;
+ if (!CBB_add_u16(out, TLSEXT_TYPE_psk_key_exchange_modes) ||
+ !CBB_add_u16_length_prefixed(out, &contents) ||
+ !CBB_add_u8_length_prefixed(&contents, &ke_modes) ||
+ !CBB_add_u8(&ke_modes, SSL_PSK_DHE_KE)) {
+ return 0;
+ }
+
+ return CBB_flush(out);
+}
+
+static int ext_psk_key_exchange_modes_parse_clienthello(SSL_HANDSHAKE *hs,
+ uint8_t *out_alert,
+ CBS *contents) {
+ if (contents == NULL) {
+ return 1;
+ }
+
+ CBS ke_modes;
+ if (!CBS_get_u8_length_prefixed(contents, &ke_modes) ||
+ CBS_len(&ke_modes) == 0 ||
+ CBS_len(contents) != 0) {
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ /* We only support tickets with PSK_DHE_KE. */
+ hs->accept_psk_mode = OPENSSL_memchr(CBS_data(&ke_modes), SSL_PSK_DHE_KE,
+ CBS_len(&ke_modes)) != NULL;
+
+ return 1;
+}
+
+
+/* Early Data Indication
+ *
+ * https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.8 */
+
+static int ext_early_data_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
+ /* TODO(svaldez): Support 0RTT. */
+ return 1;
+}
+
+static int ext_early_data_parse_clienthello(SSL_HANDSHAKE *hs,
+ uint8_t *out_alert, CBS *contents) {
+ SSL *const ssl = hs->ssl;
+ if (contents == NULL) {
+ return 1;
+ }
+
+ if (CBS_len(contents) != 0) {
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ /* Since we don't currently accept 0-RTT, we have to skip past any early data
+ * the client might have sent. */
+ if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) {
+ ssl->s3->skip_early_data = 1;
+ }
+ return 1;
+}
+
+
+/* Key Share
+ *
+ * https://tools.ietf.org/html/draft-ietf-tls-tls13-16#section-4.2.5 */
+
+static int ext_key_share_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
+ SSL *const ssl = hs->ssl;
+ uint16_t min_version, max_version;
+ if (!ssl_get_version_range(ssl, &min_version, &max_version)) {
+ return 0;
+ }
+
+ if (max_version < TLS1_3_VERSION) {
+ return 1;
+ }
+
+ CBB contents, kse_bytes;
+ if (!CBB_add_u16(out, TLSEXT_TYPE_key_share) ||
+ !CBB_add_u16_length_prefixed(out, &contents) ||
+ !CBB_add_u16_length_prefixed(&contents, &kse_bytes)) {
+ return 0;
+ }
+
+ uint16_t group_id = hs->retry_group;
+ if (hs->received_hello_retry_request) {
+ /* We received a HelloRetryRequest without a new curve, so there is no new
+ * share to append. Leave |ecdh_ctx| as-is. */
+ if (group_id == 0 &&
+ !CBB_add_bytes(&kse_bytes, hs->key_share_bytes,
+ hs->key_share_bytes_len)) {
+ return 0;
+ }
+ OPENSSL_free(hs->key_share_bytes);
+ hs->key_share_bytes = NULL;
+ hs->key_share_bytes_len = 0;
+ if (group_id == 0) {
+ return CBB_flush(out);
+ }
+ } else {
+ /* Add a fake group. See draft-davidben-tls-grease-01. */
+ if (ssl->ctx->grease_enabled &&
+ (!CBB_add_u16(&kse_bytes,
+ ssl_get_grease_value(ssl, ssl_grease_group)) ||
+ !CBB_add_u16(&kse_bytes, 1 /* length */) ||
+ !CBB_add_u8(&kse_bytes, 0 /* one byte key share */))) {
+ return 0;
+ }
+
+ /* Predict the most preferred group. */
+ const uint16_t *groups;
+ size_t groups_len;
+ tls1_get_grouplist(ssl, &groups, &groups_len);
+ if (groups_len == 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_GROUPS_SPECIFIED);
+ return 0;
+ }
+
+ group_id = groups[0];
+ }
+
+ CBB key_exchange;
+ if (!CBB_add_u16(&kse_bytes, group_id) ||
+ !CBB_add_u16_length_prefixed(&kse_bytes, &key_exchange) ||
+ !SSL_ECDH_CTX_init(&hs->ecdh_ctx, group_id) ||
+ !SSL_ECDH_CTX_offer(&hs->ecdh_ctx, &key_exchange) ||
+ !CBB_flush(&kse_bytes)) {
+ return 0;
+ }
+
+ if (!hs->received_hello_retry_request) {
+ /* Save the contents of the extension to repeat it in the second
+ * ClientHello. */
+ hs->key_share_bytes_len = CBB_len(&kse_bytes);
+ hs->key_share_bytes = BUF_memdup(CBB_data(&kse_bytes), CBB_len(&kse_bytes));
+ if (hs->key_share_bytes == NULL) {
+ return 0;
+ }
+ }
+
+ return CBB_flush(out);
+}
+
+int ssl_ext_key_share_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t **out_secret,
+ size_t *out_secret_len,
+ uint8_t *out_alert, CBS *contents) {
+ CBS peer_key;
+ uint16_t group_id;
+ if (!CBS_get_u16(contents, &group_id) ||
+ !CBS_get_u16_length_prefixed(contents, &peer_key) ||
+ CBS_len(contents) != 0) {
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ if (SSL_ECDH_CTX_get_id(&hs->ecdh_ctx) != group_id) {
+ *out_alert = SSL_AD_ILLEGAL_PARAMETER;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE);
+ return 0;
+ }
+
+ if (!SSL_ECDH_CTX_finish(&hs->ecdh_ctx, out_secret, out_secret_len, out_alert,
+ CBS_data(&peer_key), CBS_len(&peer_key))) {
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ return 0;
+ }
+
+ hs->new_session->group_id = group_id;
+ SSL_ECDH_CTX_cleanup(&hs->ecdh_ctx);
+ return 1;
+}
+
+int ssl_ext_key_share_parse_clienthello(SSL_HANDSHAKE *hs, int *out_found,
+ uint8_t **out_secret,
+ size_t *out_secret_len,
+ uint8_t *out_alert, CBS *contents) {
+ uint16_t group_id;
+ CBS key_shares;
+ if (!tls1_get_shared_group(hs, &group_id)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_SHARED_GROUP);
+ *out_alert = SSL_AD_HANDSHAKE_FAILURE;
+ return 0;
+ }
+
+ if (!CBS_get_u16_length_prefixed(contents, &key_shares) ||
+ CBS_len(contents) != 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ return 0;
+ }
+
+ /* Find the corresponding key share. */
+ int found = 0;
+ CBS peer_key;
+ while (CBS_len(&key_shares) > 0) {
+ uint16_t id;
+ CBS peer_key_tmp;
+ if (!CBS_get_u16(&key_shares, &id) ||
+ !CBS_get_u16_length_prefixed(&key_shares, &peer_key_tmp)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ return 0;
+ }
+
+ if (id == group_id) {
+ if (found) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DUPLICATE_KEY_SHARE);
+ *out_alert = SSL_AD_ILLEGAL_PARAMETER;
+ return 0;
+ }
+
+ found = 1;
+ peer_key = peer_key_tmp;
+ /* Continue parsing the structure to keep peers honest. */
+ }
+ }
+
+ if (!found) {
+ *out_found = 0;
+ *out_secret = NULL;
+ *out_secret_len = 0;
+ return 1;
+ }
+
+ /* Compute the DH secret. */
+ uint8_t *secret = NULL;
+ size_t secret_len;
+ SSL_ECDH_CTX group;
+ OPENSSL_memset(&group, 0, sizeof(SSL_ECDH_CTX));
+ CBB public_key;
+ if (!CBB_init(&public_key, 32) ||
+ !SSL_ECDH_CTX_init(&group, group_id) ||
+ !SSL_ECDH_CTX_accept(&group, &public_key, &secret, &secret_len, out_alert,
+ CBS_data(&peer_key), CBS_len(&peer_key)) ||
+ !CBB_finish(&public_key, &hs->public_key, &hs->public_key_len)) {
+ OPENSSL_free(secret);
+ SSL_ECDH_CTX_cleanup(&group);
+ CBB_cleanup(&public_key);
+ *out_alert = SSL_AD_ILLEGAL_PARAMETER;
+ return 0;
+ }
+
+ SSL_ECDH_CTX_cleanup(&group);
+
+ *out_secret = secret;
+ *out_secret_len = secret_len;
+ *out_found = 1;
+ return 1;
+}
+
+int ssl_ext_key_share_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) {
+ uint16_t group_id;
+ CBB kse_bytes, public_key;
+ if (!tls1_get_shared_group(hs, &group_id) ||
+ !CBB_add_u16(out, TLSEXT_TYPE_key_share) ||
+ !CBB_add_u16_length_prefixed(out, &kse_bytes) ||
+ !CBB_add_u16(&kse_bytes, group_id) ||
+ !CBB_add_u16_length_prefixed(&kse_bytes, &public_key) ||
+ !CBB_add_bytes(&public_key, hs->public_key, hs->public_key_len) ||
+ !CBB_flush(out)) {
+ return 0;
+ }
+
+ OPENSSL_free(hs->public_key);
+ hs->public_key = NULL;
+ hs->public_key_len = 0;
+
+ hs->new_session->group_id = group_id;
+ return 1;
+}
+
+
+/* Supported Versions
+ *
+ * https://tools.ietf.org/html/draft-ietf-tls-tls13-16#section-4.2.1 */
+
+static int ext_supported_versions_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
+ SSL *const ssl = hs->ssl;
+ uint16_t min_version, max_version;
+ if (!ssl_get_version_range(ssl, &min_version, &max_version)) {
+ return 0;
+ }
+
+ if (max_version <= TLS1_2_VERSION) {
+ return 1;
+ }
+
+ CBB contents, versions;
+ if (!CBB_add_u16(out, TLSEXT_TYPE_supported_versions) ||
+ !CBB_add_u16_length_prefixed(out, &contents) ||
+ !CBB_add_u8_length_prefixed(&contents, &versions)) {
+ return 0;
+ }
+
+ /* Add a fake version. See draft-davidben-tls-grease-01. */
+ if (ssl->ctx->grease_enabled &&
+ !CBB_add_u16(&versions, ssl_get_grease_value(ssl, ssl_grease_version))) {
+ return 0;
+ }
+
+ for (uint16_t version = max_version; version >= min_version; version--) {
+ if (!CBB_add_u16(&versions, ssl->method->version_to_wire(version))) {
+ return 0;
+ }
+ }
+
+ if (!CBB_flush(out)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/* Cookie
+ *
+ * https://tools.ietf.org/html/draft-ietf-tls-tls13-16#section-4.2.2 */
+
+static int ext_cookie_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
+ if (hs->cookie == NULL) {
+ return 1;
+ }
+
+ CBB contents, cookie;
+ if (!CBB_add_u16(out, TLSEXT_TYPE_cookie) ||
+ !CBB_add_u16_length_prefixed(out, &contents) ||
+ !CBB_add_u16_length_prefixed(&contents, &cookie) ||
+ !CBB_add_bytes(&cookie, hs->cookie, hs->cookie_len) ||
+ !CBB_flush(out)) {
+ return 0;
+ }
+
+ /* The cookie is no longer needed in memory. */
+ OPENSSL_free(hs->cookie);
+ hs->cookie = NULL;
+ hs->cookie_len = 0;
+ return 1;
+}
+
+
+/* Negotiated Groups
+ *
+ * https://tools.ietf.org/html/rfc4492#section-5.1.2
+ * https://tools.ietf.org/html/draft-ietf-tls-tls13-16#section-4.2.4 */
+
+static int ext_supported_groups_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
+ SSL *const ssl = hs->ssl;
+ CBB contents, groups_bytes;
+ if (!CBB_add_u16(out, TLSEXT_TYPE_supported_groups) ||
+ !CBB_add_u16_length_prefixed(out, &contents) ||
+ !CBB_add_u16_length_prefixed(&contents, &groups_bytes)) {
+ return 0;
+ }
+
+ /* Add a fake group. See draft-davidben-tls-grease-01. */
+ if (ssl->ctx->grease_enabled &&
+ !CBB_add_u16(&groups_bytes,
+ ssl_get_grease_value(ssl, ssl_grease_group))) {
+ return 0;
+ }
+
+ const uint16_t *groups;
+ size_t groups_len;
+ tls1_get_grouplist(ssl, &groups, &groups_len);
+
+ for (size_t i = 0; i < groups_len; i++) {
+ if (!CBB_add_u16(&groups_bytes, groups[i])) {
+ return 0;
+ }
+ }
+
+ return CBB_flush(out);
+}
+
+static int ext_supported_groups_parse_serverhello(SSL_HANDSHAKE *hs,
+ uint8_t *out_alert,
+ CBS *contents) {
+ /* This extension is not expected to be echoed by servers in TLS 1.2, but some
+ * BigIP servers send it nonetheless, so do not enforce this. */
+ return 1;
+}
+
+static int ext_supported_groups_parse_clienthello(SSL_HANDSHAKE *hs,
+ uint8_t *out_alert,
+ CBS *contents) {
+ if (contents == NULL) {
+ return 1;
+ }
+
+ CBS supported_group_list;
+ if (!CBS_get_u16_length_prefixed(contents, &supported_group_list) ||
+ CBS_len(&supported_group_list) == 0 ||
+ (CBS_len(&supported_group_list) & 1) != 0 ||
+ CBS_len(contents) != 0) {
+ return 0;
+ }
+
+ hs->peer_supported_group_list =
+ OPENSSL_malloc(CBS_len(&supported_group_list));
+ if (hs->peer_supported_group_list == NULL) {
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ return 0;
+ }
+
+ const size_t num_groups = CBS_len(&supported_group_list) / 2;
+ for (size_t i = 0; i < num_groups; i++) {
+ if (!CBS_get_u16(&supported_group_list,
+ &hs->peer_supported_group_list[i])) {
+ goto err;
+ }
+ }
+
+ assert(CBS_len(&supported_group_list) == 0);
+ hs->peer_supported_group_list_len = num_groups;
+
+ return 1;
+
+err:
+ OPENSSL_free(hs->peer_supported_group_list);
+ hs->peer_supported_group_list = NULL;
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ return 0;
+}
+
+static int ext_supported_groups_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) {
+ /* Servers don't echo this extension. */
+ return 1;
+}
+
+
+/* kExtensions contains all the supported extensions. */
+static const struct tls_extension kExtensions[] = {
+ {
+ TLSEXT_TYPE_renegotiate,
+ NULL,
+ ext_ri_add_clienthello,
+ ext_ri_parse_serverhello,
+ ext_ri_parse_clienthello,
+ ext_ri_add_serverhello,
+ },
+ {
+ TLSEXT_TYPE_server_name,
+ NULL,
+ ext_sni_add_clienthello,
+ ext_sni_parse_serverhello,
+ ext_sni_parse_clienthello,
+ ext_sni_add_serverhello,
+ },
+ {
+ TLSEXT_TYPE_extended_master_secret,
+ NULL,
+ ext_ems_add_clienthello,
+ ext_ems_parse_serverhello,
+ ext_ems_parse_clienthello,
+ ext_ems_add_serverhello,
+ },
+ {
+ TLSEXT_TYPE_session_ticket,
+ NULL,
+ ext_ticket_add_clienthello,
+ ext_ticket_parse_serverhello,
+ /* Ticket extension client parsing is handled in ssl_session.c */
+ ignore_parse_clienthello,
+ ext_ticket_add_serverhello,
+ },
+ {
+ TLSEXT_TYPE_signature_algorithms,
+ NULL,
+ ext_sigalgs_add_clienthello,
+ forbid_parse_serverhello,
+ ext_sigalgs_parse_clienthello,
+ dont_add_serverhello,
+ },
+ {
+ TLSEXT_TYPE_status_request,
+ NULL,
+ ext_ocsp_add_clienthello,
+ ext_ocsp_parse_serverhello,
+ ext_ocsp_parse_clienthello,
+ ext_ocsp_add_serverhello,
+ },
+ {
+ TLSEXT_TYPE_next_proto_neg,
+ NULL,
+ ext_npn_add_clienthello,
+ ext_npn_parse_serverhello,
+ ext_npn_parse_clienthello,
+ ext_npn_add_serverhello,
+ },
+ {
+ TLSEXT_TYPE_certificate_timestamp,
+ NULL,
+ ext_sct_add_clienthello,
+ ext_sct_parse_serverhello,
+ ext_sct_parse_clienthello,
+ ext_sct_add_serverhello,
+ },
+ {
+ TLSEXT_TYPE_application_layer_protocol_negotiation,
+ NULL,
+ ext_alpn_add_clienthello,
+ ext_alpn_parse_serverhello,
+ /* ALPN is negotiated late in |ssl_negotiate_alpn|. */
+ ignore_parse_clienthello,
+ ext_alpn_add_serverhello,
+ },
+ {
+ TLSEXT_TYPE_channel_id,
+ ext_channel_id_init,
+ ext_channel_id_add_clienthello,
+ ext_channel_id_parse_serverhello,
+ ext_channel_id_parse_clienthello,
+ ext_channel_id_add_serverhello,
+ },
+ {
+ TLSEXT_TYPE_srtp,
+ ext_srtp_init,
+ ext_srtp_add_clienthello,
+ ext_srtp_parse_serverhello,
+ ext_srtp_parse_clienthello,
+ ext_srtp_add_serverhello,
+ },
+ {
+ TLSEXT_TYPE_ec_point_formats,
+ NULL,
+ ext_ec_point_add_clienthello,
+ ext_ec_point_parse_serverhello,
+ ext_ec_point_parse_clienthello,
+ ext_ec_point_add_serverhello,
+ },
+ {
+ TLSEXT_TYPE_key_share,
+ NULL,
+ ext_key_share_add_clienthello,
+ forbid_parse_serverhello,
+ ignore_parse_clienthello,
+ dont_add_serverhello,
+ },
+ {
+ TLSEXT_TYPE_psk_key_exchange_modes,
+ NULL,
+ ext_psk_key_exchange_modes_add_clienthello,
+ forbid_parse_serverhello,
+ ext_psk_key_exchange_modes_parse_clienthello,
+ dont_add_serverhello,
+ },
+ {
+ TLSEXT_TYPE_early_data,
+ NULL,
+ ext_early_data_add_clienthello,
+ forbid_parse_serverhello,
+ ext_early_data_parse_clienthello,
+ dont_add_serverhello,
+ },
+ {
+ TLSEXT_TYPE_supported_versions,
+ NULL,
+ ext_supported_versions_add_clienthello,
+ forbid_parse_serverhello,
+ ignore_parse_clienthello,
+ dont_add_serverhello,
+ },
+ {
+ TLSEXT_TYPE_cookie,
+ NULL,
+ ext_cookie_add_clienthello,
+ forbid_parse_serverhello,
+ ignore_parse_clienthello,
+ dont_add_serverhello,
+ },
+ /* The final extension must be non-empty. WebSphere Application Server 7.0 is
+ * intolerant to the last extension being zero-length. See
+ * https://crbug.com/363583. */
+ {
+ TLSEXT_TYPE_supported_groups,
+ NULL,
+ ext_supported_groups_add_clienthello,
+ ext_supported_groups_parse_serverhello,
+ ext_supported_groups_parse_clienthello,
+ ext_supported_groups_add_serverhello,
+ },
+};
+
+#define kNumExtensions (sizeof(kExtensions) / sizeof(struct tls_extension))
+
+OPENSSL_COMPILE_ASSERT(kNumExtensions <=
+ sizeof(((SSL_HANDSHAKE *)NULL)->extensions.sent) * 8,
+ too_many_extensions_for_sent_bitset);
+OPENSSL_COMPILE_ASSERT(
+ kNumExtensions <= sizeof(((SSL_HANDSHAKE *)NULL)->extensions.received) * 8,
+ too_many_extensions_for_received_bitset);
+
+static const struct tls_extension *tls_extension_find(uint32_t *out_index,
+ uint16_t value) {
+ unsigned i;
+ for (i = 0; i < kNumExtensions; i++) {
+ if (kExtensions[i].value == value) {
+ *out_index = i;
+ return &kExtensions[i];
+ }
+ }
+
+ return NULL;
+}
+
+int SSL_extension_supported(unsigned extension_value) {
+ uint32_t index;
+ return extension_value == TLSEXT_TYPE_padding ||
+ tls_extension_find(&index, extension_value) != NULL;
+}
+
+int ssl_add_clienthello_tlsext(SSL_HANDSHAKE *hs, CBB *out, size_t header_len) {
+ SSL *const ssl = hs->ssl;
+ /* Don't add extensions for SSLv3 unless doing secure renegotiation. */
+ if (hs->client_version == SSL3_VERSION &&
+ !ssl->s3->send_connection_binding) {
+ return 1;
+ }
+
+ CBB extensions;
+ if (!CBB_add_u16_length_prefixed(out, &extensions)) {
+ goto err;
+ }
+
+ hs->extensions.sent = 0;
+ hs->custom_extensions.sent = 0;
+
+ for (size_t i = 0; i < kNumExtensions; i++) {
+ if (kExtensions[i].init != NULL) {
+ kExtensions[i].init(hs);
+ }
+ }
+
+ uint16_t grease_ext1 = 0;
+ if (ssl->ctx->grease_enabled) {
+ /* Add a fake empty extension. See draft-davidben-tls-grease-01. */
+ grease_ext1 = ssl_get_grease_value(ssl, ssl_grease_extension1);
+ if (!CBB_add_u16(&extensions, grease_ext1) ||
+ !CBB_add_u16(&extensions, 0 /* zero length */)) {
+ goto err;
+ }
+ }
+
+ for (size_t i = 0; i < kNumExtensions; i++) {
+ const size_t len_before = CBB_len(&extensions);
+ if (!kExtensions[i].add_clienthello(hs, &extensions)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_ADDING_EXTENSION);
+ ERR_add_error_dataf("extension %u", (unsigned)kExtensions[i].value);
+ goto err;
+ }
+
+ if (CBB_len(&extensions) != len_before) {
+ hs->extensions.sent |= (1u << i);
+ }
+ }
+
+ if (!custom_ext_add_clienthello(hs, &extensions)) {
+ goto err;
+ }
+
+ if (ssl->ctx->grease_enabled) {
+ /* Add a fake non-empty extension. See draft-davidben-tls-grease-01. */
+ uint16_t grease_ext2 = ssl_get_grease_value(ssl, ssl_grease_extension2);
+
+ /* The two fake extensions must not have the same value. GREASE values are
+ * of the form 0x1a1a, 0x2a2a, 0x3a3a, etc., so XOR to generate a different
+ * one. */
+ if (grease_ext1 == grease_ext2) {
+ grease_ext2 ^= 0x1010;
+ }
+
+ if (!CBB_add_u16(&extensions, grease_ext2) ||
+ !CBB_add_u16(&extensions, 1 /* one byte length */) ||
+ !CBB_add_u8(&extensions, 0 /* single zero byte as contents */)) {
+ goto err;
+ }
+ }
+
+ if (!SSL_is_dtls(ssl)) {
+ size_t psk_extension_len = ext_pre_shared_key_clienthello_length(hs);
+ header_len += 2 + CBB_len(&extensions) + psk_extension_len;
+ if (header_len > 0xff && header_len < 0x200) {
+ /* Add padding to workaround bugs in F5 terminators. See RFC 7685.
+ *
+ * NB: because this code works out the length of all existing extensions
+ * it MUST always appear last. */
+ size_t padding_len = 0x200 - header_len;
+ /* Extensions take at least four bytes to encode. Always include at least
+ * one byte of data if including the extension. WebSphere Application
+ * Server 7.0 is intolerant to the last extension being zero-length. See
+ * https://crbug.com/363583. */
+ if (padding_len >= 4 + 1) {
+ padding_len -= 4;
+ } else {
+ padding_len = 1;
+ }
+
+ uint8_t *padding_bytes;
+ if (!CBB_add_u16(&extensions, TLSEXT_TYPE_padding) ||
+ !CBB_add_u16(&extensions, padding_len) ||
+ !CBB_add_space(&extensions, &padding_bytes, padding_len)) {
+ goto err;
+ }
+
+ OPENSSL_memset(padding_bytes, 0, padding_len);
+ }
+ }
+
+ /* The PSK extension must be last, including after the padding. */
+ if (!ext_pre_shared_key_add_clienthello(hs, &extensions)) {
+ goto err;
+ }
+
+ /* Discard empty extensions blocks. */
+ if (CBB_len(&extensions) == 0) {
+ CBB_discard_child(out);
+ }
+
+ return CBB_flush(out);
+
+err:
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return 0;
+}
+
+int ssl_add_serverhello_tlsext(SSL_HANDSHAKE *hs, CBB *out) {
+ SSL *const ssl = hs->ssl;
+ CBB extensions;
+ if (!CBB_add_u16_length_prefixed(out, &extensions)) {
+ goto err;
+ }
+
+ for (unsigned i = 0; i < kNumExtensions; i++) {
+ if (!(hs->extensions.received & (1u << i))) {
+ /* Don't send extensions that were not received. */
+ continue;
+ }
+
+ if (!kExtensions[i].add_serverhello(hs, &extensions)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_ADDING_EXTENSION);
+ ERR_add_error_dataf("extension %u", (unsigned)kExtensions[i].value);
+ goto err;
+ }
+ }
+
+ if (!custom_ext_add_serverhello(hs, &extensions)) {
+ goto err;
+ }
+
+ /* Discard empty extensions blocks before TLS 1.3. */
+ if (ssl3_protocol_version(ssl) < TLS1_3_VERSION &&
+ CBB_len(&extensions) == 0) {
+ CBB_discard_child(out);
+ }
+
+ return CBB_flush(out);
+
+err:
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return 0;
+}
+
+static int ssl_scan_clienthello_tlsext(SSL_HANDSHAKE *hs,
+ const SSL_CLIENT_HELLO *client_hello,
+ int *out_alert) {
+ SSL *const ssl = hs->ssl;
+ for (size_t i = 0; i < kNumExtensions; i++) {
+ if (kExtensions[i].init != NULL) {
+ kExtensions[i].init(hs);
+ }
+ }
+
+ hs->extensions.received = 0;
+ hs->custom_extensions.received = 0;
+
+ CBS extensions;
+ CBS_init(&extensions, client_hello->extensions, client_hello->extensions_len);
+ while (CBS_len(&extensions) != 0) {
+ uint16_t type;
+ CBS extension;
+
+ /* Decode the next extension. */
+ if (!CBS_get_u16(&extensions, &type) ||
+ !CBS_get_u16_length_prefixed(&extensions, &extension)) {
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ /* RFC 5746 made the existence of extensions in SSL 3.0 somewhat
+ * ambiguous. Ignore all but the renegotiation_info extension. */
+ if (ssl->version == SSL3_VERSION && type != TLSEXT_TYPE_renegotiate) {
+ continue;
+ }
+
+ unsigned ext_index;
+ const struct tls_extension *const ext =
+ tls_extension_find(&ext_index, type);
+
+ if (ext == NULL) {
+ if (!custom_ext_parse_clienthello(hs, out_alert, type, &extension)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_PARSING_EXTENSION);
+ return 0;
+ }
+ continue;
+ }
+
+ hs->extensions.received |= (1u << ext_index);
+ uint8_t alert = SSL_AD_DECODE_ERROR;
+ if (!ext->parse_clienthello(hs, &alert, &extension)) {
+ *out_alert = alert;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_PARSING_EXTENSION);
+ ERR_add_error_dataf("extension %u", (unsigned)type);
+ return 0;
+ }
+ }
+
+ for (size_t i = 0; i < kNumExtensions; i++) {
+ if (hs->extensions.received & (1u << i)) {
+ continue;
+ }
+
+ CBS *contents = NULL, fake_contents;
+ static const uint8_t kFakeRenegotiateExtension[] = {0};
+ if (kExtensions[i].value == TLSEXT_TYPE_renegotiate &&
+ ssl_client_cipher_list_contains_cipher(client_hello,
+ SSL3_CK_SCSV & 0xffff)) {
+ /* The renegotiation SCSV was received so pretend that we received a
+ * renegotiation extension. */
+ CBS_init(&fake_contents, kFakeRenegotiateExtension,
+ sizeof(kFakeRenegotiateExtension));
+ contents = &fake_contents;
+ hs->extensions.received |= (1u << i);
+ }
+
+ /* Extension wasn't observed so call the callback with a NULL
+ * parameter. */
+ uint8_t alert = SSL_AD_DECODE_ERROR;
+ if (!kExtensions[i].parse_clienthello(hs, &alert, contents)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_EXTENSION);
+ ERR_add_error_dataf("extension %u", (unsigned)kExtensions[i].value);
+ *out_alert = alert;
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+int ssl_parse_clienthello_tlsext(SSL_HANDSHAKE *hs,
+ const SSL_CLIENT_HELLO *client_hello) {
+ SSL *const ssl = hs->ssl;
+ int alert = SSL_AD_DECODE_ERROR;
+ if (ssl_scan_clienthello_tlsext(hs, client_hello, &alert) <= 0) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
+ return 0;
+ }
+
+ if (ssl_check_clienthello_tlsext(hs) <= 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CLIENTHELLO_TLSEXT);
+ return 0;
+ }
+
+ return 1;
+}
+
+static int ssl_scan_serverhello_tlsext(SSL_HANDSHAKE *hs, CBS *cbs,
+ int *out_alert) {
+ SSL *const ssl = hs->ssl;
+ /* Before TLS 1.3, ServerHello extensions blocks may be omitted if empty. */
+ if (CBS_len(cbs) == 0 && ssl3_protocol_version(ssl) < TLS1_3_VERSION) {
+ return 1;
+ }
+
+ /* Decode the extensions block and check it is valid. */
+ CBS extensions;
+ if (!CBS_get_u16_length_prefixed(cbs, &extensions) ||
+ !tls1_check_duplicate_extensions(&extensions)) {
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ uint32_t received = 0;
+ while (CBS_len(&extensions) != 0) {
+ uint16_t type;
+ CBS extension;
+
+ /* Decode the next extension. */
+ if (!CBS_get_u16(&extensions, &type) ||
+ !CBS_get_u16_length_prefixed(&extensions, &extension)) {
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ unsigned ext_index;
+ const struct tls_extension *const ext =
+ tls_extension_find(&ext_index, type);
+
+ if (ext == NULL) {
+ if (!custom_ext_parse_serverhello(hs, out_alert, type, &extension)) {
+ return 0;
+ }
+ continue;
+ }
+
+ OPENSSL_COMPILE_ASSERT(kNumExtensions <= sizeof(hs->extensions.sent) * 8,
+ too_many_bits);
+
+ if (!(hs->extensions.sent & (1u << ext_index)) &&
+ type != TLSEXT_TYPE_renegotiate) {
+ /* If the extension was never sent then it is illegal, except for the
+ * renegotiation extension which, in SSL 3.0, is signaled via SCSV. */
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
+ ERR_add_error_dataf("extension :%u", (unsigned)type);
+ *out_alert = SSL_AD_UNSUPPORTED_EXTENSION;
+ return 0;
+ }
+
+ received |= (1u << ext_index);
+
+ uint8_t alert = SSL_AD_DECODE_ERROR;
+ if (!ext->parse_serverhello(hs, &alert, &extension)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_PARSING_EXTENSION);
+ ERR_add_error_dataf("extension %u", (unsigned)type);
+ *out_alert = alert;
+ return 0;
+ }
+ }
+
+ for (size_t i = 0; i < kNumExtensions; i++) {
+ if (!(received & (1u << i))) {
+ /* Extension wasn't observed so call the callback with a NULL
+ * parameter. */
+ uint8_t alert = SSL_AD_DECODE_ERROR;
+ if (!kExtensions[i].parse_serverhello(hs, &alert, NULL)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_EXTENSION);
+ ERR_add_error_dataf("extension %u", (unsigned)kExtensions[i].value);
+ *out_alert = alert;
+ return 0;
+ }
+ }
+ }
+
+ return 1;
+}
+
+static int ssl_check_clienthello_tlsext(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ int ret = SSL_TLSEXT_ERR_NOACK;
+ int al = SSL_AD_UNRECOGNIZED_NAME;
+
+ if (ssl->ctx->tlsext_servername_callback != 0) {
+ ret = ssl->ctx->tlsext_servername_callback(ssl, &al,
+ ssl->ctx->tlsext_servername_arg);
+ } else if (ssl->session_ctx->tlsext_servername_callback != 0) {
+ ret = ssl->session_ctx->tlsext_servername_callback(
+ ssl, &al, ssl->session_ctx->tlsext_servername_arg);
+ }
+
+ switch (ret) {
+ case SSL_TLSEXT_ERR_ALERT_FATAL:
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, al);
+ return -1;
+
+ case SSL_TLSEXT_ERR_NOACK:
+ hs->should_ack_sni = 0;
+ return 1;
+
+ default:
+ return 1;
+ }
+}
+
+int ssl_parse_serverhello_tlsext(SSL_HANDSHAKE *hs, CBS *cbs) {
+ SSL *const ssl = hs->ssl;
+ int alert = SSL_AD_DECODE_ERROR;
+ if (ssl_scan_serverhello_tlsext(hs, cbs, &alert) <= 0) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
+ return 0;
+ }
+
+ return 1;
+}
+
+static enum ssl_ticket_aead_result_t
+ssl_decrypt_ticket_with_cipher_ctx(SSL *ssl, uint8_t **out, size_t *out_len,
+ int *out_renew_ticket, const uint8_t *ticket,
+ size_t ticket_len) {
+ enum ssl_ticket_aead_result_t ret = ssl_ticket_aead_ignore_ticket;
+ const SSL_CTX *const ssl_ctx = ssl->session_ctx;
+ uint8_t *plaintext = NULL;
+
+ HMAC_CTX hmac_ctx;
+ HMAC_CTX_init(&hmac_ctx);
+ EVP_CIPHER_CTX cipher_ctx;
+ EVP_CIPHER_CTX_init(&cipher_ctx);
+
+ /* Ensure there is room for the key name and the largest IV
+ * |tlsext_ticket_key_cb| may try to consume. The real limit may be lower, but
+ * the maximum IV length should be well under the minimum size for the
+ * session material and HMAC. */
+ if (ticket_len < SSL_TICKET_KEY_NAME_LEN + EVP_MAX_IV_LENGTH) {
+ goto out;
+ }
+ const uint8_t *iv = ticket + SSL_TICKET_KEY_NAME_LEN;
+
+ if (ssl_ctx->tlsext_ticket_key_cb != NULL) {
+ int cb_ret = ssl_ctx->tlsext_ticket_key_cb(
+ ssl, (uint8_t *)ticket /* name */, (uint8_t *)iv, &cipher_ctx,
+ &hmac_ctx, 0 /* decrypt */);
+ if (cb_ret < 0) {
+ ret = ssl_ticket_aead_error;
+ goto out;
+ } else if (cb_ret == 0) {
+ goto out;
+ } else if (cb_ret == 2) {
+ *out_renew_ticket = 1;
+ }
+ } else {
+ /* Check the key name matches. */
+ if (OPENSSL_memcmp(ticket, ssl_ctx->tlsext_tick_key_name,
+ SSL_TICKET_KEY_NAME_LEN) != 0) {
+ goto out;
+ }
+ if (!HMAC_Init_ex(&hmac_ctx, ssl_ctx->tlsext_tick_hmac_key,
+ sizeof(ssl_ctx->tlsext_tick_hmac_key), tlsext_tick_md(),
+ NULL) ||
+ !EVP_DecryptInit_ex(&cipher_ctx, EVP_aes_128_cbc(), NULL,
+ ssl_ctx->tlsext_tick_aes_key, iv)) {
+ ret = ssl_ticket_aead_error;
+ goto out;
+ }
+ }
+ size_t iv_len = EVP_CIPHER_CTX_iv_length(&cipher_ctx);
+
+ /* Check the MAC at the end of the ticket. */
+ uint8_t mac[EVP_MAX_MD_SIZE];
+ size_t mac_len = HMAC_size(&hmac_ctx);
+ if (ticket_len < SSL_TICKET_KEY_NAME_LEN + iv_len + 1 + mac_len) {
+ /* The ticket must be large enough for key name, IV, data, and MAC. */
+ goto out;
+ }
+ HMAC_Update(&hmac_ctx, ticket, ticket_len - mac_len);
+ HMAC_Final(&hmac_ctx, mac, NULL);
+ int mac_ok =
+ CRYPTO_memcmp(mac, ticket + (ticket_len - mac_len), mac_len) == 0;
+#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+ mac_ok = 1;
+#endif
+ if (!mac_ok) {
+ goto out;
+ }
+
+ /* Decrypt the session data. */
+ const uint8_t *ciphertext = ticket + SSL_TICKET_KEY_NAME_LEN + iv_len;
+ size_t ciphertext_len = ticket_len - SSL_TICKET_KEY_NAME_LEN - iv_len -
+ mac_len;
+ plaintext = OPENSSL_malloc(ciphertext_len);
+ if (plaintext == NULL) {
+ ret = ssl_ticket_aead_error;
+ goto out;
+ }
+ size_t plaintext_len;
+#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+ OPENSSL_memcpy(plaintext, ciphertext, ciphertext_len);
+ plaintext_len = ciphertext_len;
+#else
+ if (ciphertext_len >= INT_MAX) {
+ goto out;
+ }
+ int len1, len2;
+ if (!EVP_DecryptUpdate(&cipher_ctx, plaintext, &len1, ciphertext,
+ (int)ciphertext_len) ||
+ !EVP_DecryptFinal_ex(&cipher_ctx, plaintext + len1, &len2)) {
+ ERR_clear_error();
+ goto out;
+ }
+ plaintext_len = (size_t)(len1) + len2;
+#endif
+
+ *out = plaintext;
+ plaintext = NULL;
+ *out_len = plaintext_len;
+ ret = ssl_ticket_aead_success;
+
+out:
+ OPENSSL_free(plaintext);
+ HMAC_CTX_cleanup(&hmac_ctx);
+ EVP_CIPHER_CTX_cleanup(&cipher_ctx);
+ return ret;
+}
+
+static enum ssl_ticket_aead_result_t ssl_decrypt_ticket_with_method(
+ SSL *ssl, uint8_t **out, size_t *out_len, int *out_renew_ticket,
+ const uint8_t *ticket, size_t ticket_len) {
+ uint8_t *plaintext = OPENSSL_malloc(ticket_len);
+ if (plaintext == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ return ssl_ticket_aead_error;
+ }
+
+ size_t plaintext_len;
+ const enum ssl_ticket_aead_result_t result =
+ ssl->session_ctx->ticket_aead_method->open(
+ ssl, plaintext, &plaintext_len, ticket_len, ticket, ticket_len);
+
+ if (result == ssl_ticket_aead_success) {
+ *out = plaintext;
+ plaintext = NULL;
+ *out_len = plaintext_len;
+ }
+
+ OPENSSL_free(plaintext);
+ return result;
+}
+
+enum ssl_ticket_aead_result_t ssl_process_ticket(
+ SSL *ssl, 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;
+
+ if ((SSL_get_options(ssl) & SSL_OP_NO_TICKET) ||
+ session_id_len > SSL_MAX_SSL_SESSION_ID_LENGTH) {
+ return ssl_ticket_aead_ignore_ticket;
+ }
+
+ uint8_t *plaintext = NULL;
+ size_t plaintext_len;
+ enum ssl_ticket_aead_result_t result;
+ if (ssl->session_ctx->ticket_aead_method != NULL) {
+ result = ssl_decrypt_ticket_with_method(
+ ssl, &plaintext, &plaintext_len, out_renew_ticket, ticket, ticket_len);
+ } else {
+ result = ssl_decrypt_ticket_with_cipher_ctx(
+ ssl, &plaintext, &plaintext_len, out_renew_ticket, ticket, ticket_len);
+ }
+
+ if (result != ssl_ticket_aead_success) {
+ return result;
+ }
+
+ /* Decode the session. */
+ SSL_SESSION *session =
+ SSL_SESSION_from_bytes(plaintext, plaintext_len, ssl->ctx);
+ OPENSSL_free(plaintext);
+
+ if (session == NULL) {
+ ERR_clear_error(); /* Don't leave an error on the queue. */
+ return ssl_ticket_aead_ignore_ticket;
+ }
+
+ /* Copy the client's session ID into the new session, to denote the ticket has
+ * been accepted. */
+ OPENSSL_memcpy(session->session_id, session_id, session_id_len);
+ session->session_id_length = session_id_len;
+
+ *out_session = session;
+ return ssl_ticket_aead_success;
+}
+
+int tls1_parse_peer_sigalgs(SSL_HANDSHAKE *hs, const CBS *in_sigalgs) {
+ /* Extension ignored for inappropriate versions */
+ if (ssl3_protocol_version(hs->ssl) < TLS1_2_VERSION) {
+ return 1;
+ }
+
+ OPENSSL_free(hs->peer_sigalgs);
+ hs->peer_sigalgs = NULL;
+ hs->num_peer_sigalgs = 0;
+
+ size_t num_sigalgs = CBS_len(in_sigalgs);
+ if (num_sigalgs % 2 != 0) {
+ return 0;
+ }
+ num_sigalgs /= 2;
+
+ /* supported_signature_algorithms in the certificate request is
+ * allowed to be empty. */
+ if (num_sigalgs == 0) {
+ return 1;
+ }
+
+ /* This multiplication doesn't overflow because sizeof(uint16_t) is two
+ * and we just divided |num_sigalgs| by two. */
+ hs->peer_sigalgs = OPENSSL_malloc(num_sigalgs * sizeof(uint16_t));
+ if (hs->peer_sigalgs == NULL) {
+ return 0;
+ }
+ hs->num_peer_sigalgs = num_sigalgs;
+
+ CBS sigalgs;
+ CBS_init(&sigalgs, CBS_data(in_sigalgs), CBS_len(in_sigalgs));
+ for (size_t i = 0; i < num_sigalgs; i++) {
+ if (!CBS_get_u16(&sigalgs, &hs->peer_sigalgs[i])) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+int tls1_choose_signature_algorithm(SSL_HANDSHAKE *hs, uint16_t *out) {
+ SSL *const ssl = hs->ssl;
+ CERT *cert = ssl->cert;
+
+ /* Before TLS 1.2, the signature algorithm isn't negotiated as part of the
+ * handshake. It is fixed at MD5-SHA1 for RSA and SHA1 for ECDSA. */
+ if (ssl3_protocol_version(ssl) < TLS1_2_VERSION) {
+ int type = ssl_private_key_type(ssl);
+ if (type == NID_rsaEncryption) {
+ *out = SSL_SIGN_RSA_PKCS1_MD5_SHA1;
+ return 1;
+ }
+ if (ssl_is_ecdsa_key_type(type)) {
+ *out = SSL_SIGN_ECDSA_SHA1;
+ return 1;
+ }
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_COMMON_SIGNATURE_ALGORITHMS);
+ return 0;
+ }
+
+ const uint16_t *sigalgs = cert->sigalgs;
+ size_t num_sigalgs = cert->num_sigalgs;
+ if (sigalgs == NULL) {
+ sigalgs = kSignSignatureAlgorithms;
+ num_sigalgs = OPENSSL_ARRAY_SIZE(kSignSignatureAlgorithms);
+ }
+
+ const uint16_t *peer_sigalgs = hs->peer_sigalgs;
+ size_t num_peer_sigalgs = hs->num_peer_sigalgs;
+ if (num_peer_sigalgs == 0 && ssl3_protocol_version(ssl) < TLS1_3_VERSION) {
+ /* If the client didn't specify any signature_algorithms extension then
+ * we can assume that it supports SHA1. See
+ * http://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */
+ static const uint16_t kDefaultPeerAlgorithms[] = {SSL_SIGN_RSA_PKCS1_SHA1,
+ SSL_SIGN_ECDSA_SHA1};
+ peer_sigalgs = kDefaultPeerAlgorithms;
+ num_peer_sigalgs = OPENSSL_ARRAY_SIZE(kDefaultPeerAlgorithms);
+ }
+
+ for (size_t i = 0; i < num_sigalgs; i++) {
+ uint16_t sigalg = sigalgs[i];
+ /* SSL_SIGN_RSA_PKCS1_MD5_SHA1 is an internal value and should never be
+ * negotiated. */
+ if (sigalg == SSL_SIGN_RSA_PKCS1_MD5_SHA1 ||
+ !ssl_private_key_supports_signature_algorithm(ssl, sigalgs[i])) {
+ continue;
+ }
+
+ for (size_t j = 0; j < num_peer_sigalgs; j++) {
+ if (sigalg == peer_sigalgs[j]) {
+ *out = sigalg;
+ return 1;
+ }
+ }
+ }
+
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_COMMON_SIGNATURE_ALGORITHMS);
+ return 0;
+}
+
+int tls1_verify_channel_id(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ int ret = 0;
+ uint16_t extension_type;
+ CBS extension, channel_id;
+
+ /* A Channel ID handshake message is structured to contain multiple
+ * extensions, but the only one that can be present is Channel ID. */
+ CBS_init(&channel_id, ssl->init_msg, ssl->init_num);
+ if (!CBS_get_u16(&channel_id, &extension_type) ||
+ !CBS_get_u16_length_prefixed(&channel_id, &extension) ||
+ CBS_len(&channel_id) != 0 ||
+ extension_type != TLSEXT_TYPE_channel_id ||
+ CBS_len(&extension) != TLSEXT_CHANNEL_ID_SIZE) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ return 0;
+ }
+
+ EC_GROUP *p256 = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
+ if (!p256) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_P256_SUPPORT);
+ return 0;
+ }
+
+ EC_KEY *key = NULL;
+ EC_POINT *point = NULL;
+ BIGNUM x, y;
+ ECDSA_SIG sig;
+ BN_init(&x);
+ BN_init(&y);
+ sig.r = BN_new();
+ sig.s = BN_new();
+ if (sig.r == NULL || sig.s == NULL) {
+ goto err;
+ }
+
+ const uint8_t *p = CBS_data(&extension);
+ if (BN_bin2bn(p + 0, 32, &x) == NULL ||
+ BN_bin2bn(p + 32, 32, &y) == NULL ||
+ BN_bin2bn(p + 64, 32, sig.r) == NULL ||
+ BN_bin2bn(p + 96, 32, sig.s) == NULL) {
+ goto err;
+ }
+
+ point = EC_POINT_new(p256);
+ if (point == NULL ||
+ !EC_POINT_set_affine_coordinates_GFp(p256, point, &x, &y, NULL)) {
+ goto err;
+ }
+
+ key = EC_KEY_new();
+ if (key == NULL ||
+ !EC_KEY_set_group(key, p256) ||
+ !EC_KEY_set_public_key(key, point)) {
+ goto err;
+ }
+
+ uint8_t digest[EVP_MAX_MD_SIZE];
+ size_t digest_len;
+ if (!tls1_channel_id_hash(hs, digest, &digest_len)) {
+ goto err;
+ }
+
+ int sig_ok = ECDSA_do_verify(digest, digest_len, &sig, key);
+#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+ sig_ok = 1;
+#endif
+ if (!sig_ok) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CHANNEL_ID_SIGNATURE_INVALID);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECRYPT_ERROR);
+ ssl->s3->tlsext_channel_id_valid = 0;
+ goto err;
+ }
+
+ OPENSSL_memcpy(ssl->s3->tlsext_channel_id, p, 64);
+ ret = 1;
+
+err:
+ BN_free(&x);
+ BN_free(&y);
+ BN_free(sig.r);
+ BN_free(sig.s);
+ EC_KEY_free(key);
+ EC_POINT_free(point);
+ EC_GROUP_free(p256);
+ return ret;
+}
+
+int tls1_write_channel_id(SSL_HANDSHAKE *hs, CBB *cbb) {
+ SSL *const ssl = hs->ssl;
+ uint8_t digest[EVP_MAX_MD_SIZE];
+ size_t digest_len;
+ if (!tls1_channel_id_hash(hs, digest, &digest_len)) {
+ return 0;
+ }
+
+ EC_KEY *ec_key = EVP_PKEY_get0_EC_KEY(ssl->tlsext_channel_id_private);
+ if (ec_key == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ int ret = 0;
+ BIGNUM *x = BN_new();
+ BIGNUM *y = BN_new();
+ ECDSA_SIG *sig = NULL;
+ if (x == NULL || y == NULL ||
+ !EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(ec_key),
+ EC_KEY_get0_public_key(ec_key),
+ x, y, NULL)) {
+ goto err;
+ }
+
+ sig = ECDSA_do_sign(digest, digest_len, ec_key);
+ if (sig == NULL) {
+ goto err;
+ }
+
+ CBB child;
+ if (!CBB_add_u16(cbb, TLSEXT_TYPE_channel_id) ||
+ !CBB_add_u16_length_prefixed(cbb, &child) ||
+ !BN_bn2cbb_padded(&child, 32, x) ||
+ !BN_bn2cbb_padded(&child, 32, y) ||
+ !BN_bn2cbb_padded(&child, 32, sig->r) ||
+ !BN_bn2cbb_padded(&child, 32, sig->s) ||
+ !CBB_flush(cbb)) {
+ goto err;
+ }
+
+ ret = 1;
+
+err:
+ BN_free(x);
+ BN_free(y);
+ ECDSA_SIG_free(sig);
+ return ret;
+}
+
+int tls1_channel_id_hash(SSL_HANDSHAKE *hs, uint8_t *out, size_t *out_len) {
+ SSL *const ssl = hs->ssl;
+ if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) {
+ uint8_t *msg;
+ size_t msg_len;
+ if (!tls13_get_cert_verify_signature_input(hs, &msg, &msg_len,
+ ssl_cert_verify_channel_id)) {
+ return 0;
+ }
+ SHA256(msg, msg_len, out);
+ *out_len = SHA256_DIGEST_LENGTH;
+ OPENSSL_free(msg);
+ return 1;
+ }
+
+ SHA256_CTX ctx;
+
+ SHA256_Init(&ctx);
+ static const char kClientIDMagic[] = "TLS Channel ID signature";
+ SHA256_Update(&ctx, kClientIDMagic, sizeof(kClientIDMagic));
+
+ if (ssl->session != NULL) {
+ static const char kResumptionMagic[] = "Resumption";
+ SHA256_Update(&ctx, kResumptionMagic, sizeof(kResumptionMagic));
+ if (ssl->session->original_handshake_hash_len == 0) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+ SHA256_Update(&ctx, ssl->session->original_handshake_hash,
+ ssl->session->original_handshake_hash_len);
+ }
+
+ uint8_t hs_hash[EVP_MAX_MD_SIZE];
+ size_t hs_hash_len;
+ if (!SSL_TRANSCRIPT_get_hash(&hs->transcript, hs_hash, &hs_hash_len)) {
+ return 0;
+ }
+ SHA256_Update(&ctx, hs_hash, (size_t)hs_hash_len);
+ SHA256_Final(out, &ctx);
+ *out_len = SHA256_DIGEST_LENGTH;
+ return 1;
+}
+
+/* tls1_record_handshake_hashes_for_channel_id records the current handshake
+ * hashes in |hs->new_session| so that Channel ID resumptions can sign that
+ * data. */
+int tls1_record_handshake_hashes_for_channel_id(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ /* This function should never be called for a resumed session because the
+ * handshake hashes that we wish to record are for the original, full
+ * handshake. */
+ if (ssl->session != NULL) {
+ return -1;
+ }
+
+ OPENSSL_COMPILE_ASSERT(
+ sizeof(hs->new_session->original_handshake_hash) == EVP_MAX_MD_SIZE,
+ original_handshake_hash_is_too_small);
+
+ size_t digest_len;
+ if (!SSL_TRANSCRIPT_get_hash(&hs->transcript,
+ hs->new_session->original_handshake_hash,
+ &digest_len)) {
+ return -1;
+ }
+
+ OPENSSL_COMPILE_ASSERT(EVP_MAX_MD_SIZE <= 0xff, max_md_size_is_too_large);
+ hs->new_session->original_handshake_hash_len = (uint8_t)digest_len;
+
+ return 1;
+}
+
+int ssl_do_channel_id_callback(SSL *ssl) {
+ if (ssl->tlsext_channel_id_private != NULL ||
+ ssl->ctx->channel_id_cb == NULL) {
+ return 1;
+ }
+
+ EVP_PKEY *key = NULL;
+ ssl->ctx->channel_id_cb(ssl, &key);
+ if (key == NULL) {
+ /* The caller should try again later. */
+ return 1;
+ }
+
+ int ret = SSL_set1_tls_channel_id(ssl, key);
+ EVP_PKEY_free(key);
+ return ret;
+}
+
+int ssl_is_sct_list_valid(const CBS *contents) {
+ /* Shallow parse the SCT list for sanity. By the RFC
+ * (https://tools.ietf.org/html/rfc6962#section-3.3) neither the list nor any
+ * of the SCTs may be empty. */
+ CBS copy = *contents;
+ CBS sct_list;
+ if (!CBS_get_u16_length_prefixed(&copy, &sct_list) ||
+ CBS_len(&copy) != 0 ||
+ CBS_len(&sct_list) == 0) {
+ return 0;
+ }
+
+ while (CBS_len(&sct_list) > 0) {
+ CBS sct;
+ if (!CBS_get_u16_length_prefixed(&sct_list, &sct) ||
+ CBS_len(&sct) == 0) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/CMakeLists.txt b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/CMakeLists.txt
new file mode 100644
index 000000000..3b0790308
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/CMakeLists.txt
@@ -0,0 +1,14 @@
+include_directories(../../include)
+
+add_executable(
+ bssl_shim
+
+ async_bio.cc
+ bssl_shim.cc
+ packeted_bio.cc
+ test_config.cc
+
+ $<TARGET_OBJECTS:test_support>
+)
+
+target_link_libraries(bssl_shim ssl crypto)
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/PORTING.md b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/PORTING.md
new file mode 100644
index 000000000..86ad24d0d
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/PORTING.md
@@ -0,0 +1,109 @@
+# Porting to Other Implementations
+
+## Introduction
+
+This document provides an overview of the test runner and how to
+integrate it with other stacks. So far we have it working with
+BoringSSL and some incomplete integrations with NSS and OpenSSL.
+
+Note that supporting non-BoringSSL implementations is a work in
+progress and interfaces may change in the future. Consumers should pin
+to a particular revision rather than using BoringSSL’s master branch
+directly. As we gain experience with other implementations, we hope to
+make further improvements to portability, so please contact
+davidben@google.com and ekr@rtfm.com if implementing a new shim.
+
+
+## Integration Architecture
+
+The test runner integrates with the TLS stack under test through a
+“shim”: a command line program which encapsulates the stack. By
+default, the shim points to the BoringSSL shim in the same source
+tree, but any program can be supplied via the `-shim-path` flag. The
+runner opens up a server socket and provides the shim with a `-port`
+argument that points to that socket. The shim always connects to the
+runner as a TCP client even when acting as a TLS server. For DTLS,
+there is a small framing layer that gives packet boundaries over
+TCP. The shim can also pass a variety of command line arguments which
+are used to configure the stack under test. These can be found at
+`test_config.cc`.
+
+
+The shim reports success by exiting with a `0` error code and failure by
+reporting a non-zero error code and generally sending a textual error
+value to stderr. Many of the tests expect specific error string (such
+as `NO_SHARED_CIPHER`) that indicates what went wrong.
+
+
+## Compatibility Issues
+
+There are a number of situations in which the runner might succeed
+with some tests and not others:
+
+* Defects in the stack under test
+* Features which haven’t yet been implemented
+* Failure to implement one or more of the command line flags the runner uses with the shim
+* Disagreement about the right behavior/interpretation of the spec
+
+
+We have implemented several features which allow implementations to ease these compatibility issues.
+
+### Configuration File
+
+The runner can be supplied with a JSON configuration file which is
+intended to allow for a per-stack mapping. This file currently takes
+two directives:
+
+
+* `DisabledTests`: A JSON map consisting of the pattern matching the
+ tests to be disabled as the key and some sort of reason why it was
+ disabled as the value. The key is used as a match against the test
+ name. The value is ignored and is just used for documentation
+ purposes so you can remember why you disabled a
+ test. `-include-disabled` overrides this filter.
+
+* `ErrorMap`: A JSON map from the internal errors the runner expects to
+ the error strings that your implementation spits out. Generally
+ you’ll need to map every error, but if you also provide the
+ ` -loose-errors` flag, then every un-mapped error just gets mapped to
+ the empty string and treated as if it matched every error the runner
+ expects.
+
+
+The `-shim-config` flag is used to provide the config file.
+
+
+### Unimplemented Features
+If the shim encounters some request from the runner that it knows it
+can’t fulfill (e.g., a command line flag that it doesn’t recognize),
+then it can exit with the special code `89`. Shims are recommended to
+use this exit code on unknown command-line arguments.
+
+The test runner interprets this as “unimplemented” and skips the
+test. If run normally, this will cause the test runner to report that
+the entire test suite failed. The `-allow-unimplemented` flag suppresses
+this behavior and causes the test runner to ignore these tests for the
+purpose of evaluating the success or failure of the test suite.
+
+
+### Malloc Tests
+
+The test runner can also be used to stress malloc failure
+codepaths. If passed `-malloc-test=0`, the runner will run each test
+repeatedly with an incrementing `MALLOC_NUMBER_TO_FAIL` environment
+variable. The shim should then replace the malloc implementation with
+one which fails at the specified number of calls. If there are not
+enough calls to reach the number, the shim should fail with exit code
+`88`. This signals to the runner that the test has completed.
+
+See `crypto/test/malloc.cc` for an example malloc implementation.
+
+Note these tests are slow and will hit Go's test timeout. Pass `-timeout 72h` to
+avoid crashing after 10 minutes.
+
+
+## Example: Running Against NSS
+
+```
+DYLD_LIBRARY_PATH=~/dev/nss-dev/nss-sandbox/dist/Darwin15.6.0_64_DBG.OBJ/lib go test -shim-path ~/dev/nss-dev/nss-sandbox/dist/Darwin15.6.0_64_DBG.OBJ/bin/nss_bogo_shim -loose-errors -allow-unimplemented -shim-config ~/dev/nss-dev/nss-sandbox/nss/external_tests/nss_bogo_shim/config.json
+```
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/README.md b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/README.md
new file mode 100644
index 000000000..7da29eb67
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/README.md
@@ -0,0 +1,38 @@
+# BoringSSL SSL Tests
+
+This directory contains BoringSSL's protocol-level test suite.
+
+Testing a TLS implementation can be difficult. We need to produce invalid but
+sufficiently correct handshakes to get our implementation close to its edge
+cases. TLS's cryptographic steps mean we cannot use a transcript and effectively
+need a TLS implementation on the other end. But we do not wish to litter
+BoringSSL with options for bugs to test against.
+
+Instead, we use a fork of the Go `crypto/tls` package, heavily patched with
+configurable bugs. This code, along with a test suite and harness written in Go,
+lives in the `runner` directory. The harness runs BoringSSL via a C/C++ shim
+binary which lives in this directory. All communication with the shim binary
+occurs with command-line flags, sockets, and standard I/O.
+
+This strategy also ensures we always test against a second implementation. All
+features should be implemented twice, once in C for BoringSSL and once in Go for
+testing. If possible, the Go code should be suitable for potentially
+upstreaming. However, sometimes test code has different needs. For example, our
+test DTLS code enforces strict ordering on sequence numbers and has controlled
+packet drop simulation.
+
+To run the tests manually, run `go test` from the `runner` directory. It takes
+command-line flags found at the top of `runner/runner.go`. The `-help` option
+also works after using `go test -c` to make a `runner.test` binary first.
+
+If adding a new test, these files may be a good starting point:
+
+ * `runner/runner.go`: the test harness and all the individual tests.
+ * `runner/common.go`: contains the `Config` and `ProtocolBugs` struct which
+ control the Go TLS implementation's behavior.
+ * `test_config.h`, `test_config.cc`: the command-line flags which control the
+ shim's behavior.
+ * `bssl_shim.cc`: the shim binary itself.
+
+For porting the test suite to a different implementation see
+[PORTING.md](./PORTING.md).
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/async_bio.cc b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/async_bio.cc
new file mode 100644
index 000000000..fd351760b
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/async_bio.cc
@@ -0,0 +1,191 @@
+/* Copyright (c) 2014, 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 "async_bio.h"
+
+#include <errno.h>
+#include <string.h>
+
+#include <openssl/bio.h>
+#include <openssl/mem.h>
+
+#include "../../crypto/internal.h"
+
+
+namespace {
+
+extern const BIO_METHOD g_async_bio_method;
+
+struct AsyncBio {
+ bool datagram;
+ bool enforce_write_quota;
+ size_t read_quota;
+ size_t write_quota;
+};
+
+AsyncBio *GetData(BIO *bio) {
+ if (bio->method != &g_async_bio_method) {
+ return NULL;
+ }
+ return (AsyncBio *)bio->ptr;
+}
+
+static int AsyncWrite(BIO *bio, const char *in, int inl) {
+ AsyncBio *a = GetData(bio);
+ if (a == NULL || bio->next_bio == NULL) {
+ return 0;
+ }
+
+ if (!a->enforce_write_quota) {
+ return BIO_write(bio->next_bio, in, inl);
+ }
+
+ BIO_clear_retry_flags(bio);
+
+ if (a->write_quota == 0) {
+ BIO_set_retry_write(bio);
+ errno = EAGAIN;
+ return -1;
+ }
+
+ if (!a->datagram && (size_t)inl > a->write_quota) {
+ inl = a->write_quota;
+ }
+ int ret = BIO_write(bio->next_bio, in, inl);
+ if (ret <= 0) {
+ BIO_copy_next_retry(bio);
+ } else {
+ a->write_quota -= (a->datagram ? 1 : ret);
+ }
+ return ret;
+}
+
+static int AsyncRead(BIO *bio, char *out, int outl) {
+ AsyncBio *a = GetData(bio);
+ if (a == NULL || bio->next_bio == NULL) {
+ return 0;
+ }
+
+ BIO_clear_retry_flags(bio);
+
+ if (a->read_quota == 0) {
+ BIO_set_retry_read(bio);
+ errno = EAGAIN;
+ return -1;
+ }
+
+ if (!a->datagram && (size_t)outl > a->read_quota) {
+ outl = a->read_quota;
+ }
+ int ret = BIO_read(bio->next_bio, out, outl);
+ if (ret <= 0) {
+ BIO_copy_next_retry(bio);
+ } else {
+ a->read_quota -= (a->datagram ? 1 : ret);
+ }
+ return ret;
+}
+
+static long AsyncCtrl(BIO *bio, int cmd, long num, void *ptr) {
+ if (bio->next_bio == NULL) {
+ return 0;
+ }
+ BIO_clear_retry_flags(bio);
+ int ret = BIO_ctrl(bio->next_bio, cmd, num, ptr);
+ BIO_copy_next_retry(bio);
+ return ret;
+}
+
+static int AsyncNew(BIO *bio) {
+ AsyncBio *a = (AsyncBio *)OPENSSL_malloc(sizeof(*a));
+ if (a == NULL) {
+ return 0;
+ }
+ OPENSSL_memset(a, 0, sizeof(*a));
+ a->enforce_write_quota = true;
+ bio->init = 1;
+ bio->ptr = (char *)a;
+ return 1;
+}
+
+static int AsyncFree(BIO *bio) {
+ if (bio == NULL) {
+ return 0;
+ }
+
+ OPENSSL_free(bio->ptr);
+ bio->ptr = NULL;
+ bio->init = 0;
+ bio->flags = 0;
+ return 1;
+}
+
+static long AsyncCallbackCtrl(BIO *bio, int cmd, bio_info_cb fp) {
+ if (bio->next_bio == NULL) {
+ return 0;
+ }
+ return BIO_callback_ctrl(bio->next_bio, cmd, fp);
+}
+
+const BIO_METHOD g_async_bio_method = {
+ BIO_TYPE_FILTER,
+ "async bio",
+ AsyncWrite,
+ AsyncRead,
+ NULL /* puts */,
+ NULL /* gets */,
+ AsyncCtrl,
+ AsyncNew,
+ AsyncFree,
+ AsyncCallbackCtrl,
+};
+
+} // namespace
+
+bssl::UniquePtr<BIO> AsyncBioCreate() {
+ return bssl::UniquePtr<BIO>(BIO_new(&g_async_bio_method));
+}
+
+bssl::UniquePtr<BIO> AsyncBioCreateDatagram() {
+ bssl::UniquePtr<BIO> ret(BIO_new(&g_async_bio_method));
+ if (!ret) {
+ return nullptr;
+ }
+ GetData(ret.get())->datagram = true;
+ return ret;
+}
+
+void AsyncBioAllowRead(BIO *bio, size_t count) {
+ AsyncBio *a = GetData(bio);
+ if (a == NULL) {
+ return;
+ }
+ a->read_quota += count;
+}
+
+void AsyncBioAllowWrite(BIO *bio, size_t count) {
+ AsyncBio *a = GetData(bio);
+ if (a == NULL) {
+ return;
+ }
+ a->write_quota += count;
+}
+
+void AsyncBioEnforceWriteQuota(BIO *bio, bool enforce) {
+ AsyncBio *a = GetData(bio);
+ if (a == NULL) {
+ return;
+ }
+ a->enforce_write_quota = enforce;
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/async_bio.h b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/async_bio.h
new file mode 100644
index 000000000..9974139d9
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/async_bio.h
@@ -0,0 +1,43 @@
+/* Copyright (c) 2014, 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 HEADER_ASYNC_BIO
+#define HEADER_ASYNC_BIO
+
+#include <openssl/bio.h>
+
+
+// AsyncBioCreate creates a filter BIO for testing asynchronous state
+// machines which consume a stream socket. Reads and writes will fail
+// and return EAGAIN unless explicitly allowed. Each async BIO has a
+// read quota and a write quota. Initially both are zero. As each is
+// incremented, bytes are allowed to flow through the BIO.
+bssl::UniquePtr<BIO> AsyncBioCreate();
+
+// AsyncBioCreateDatagram creates a filter BIO for testing for
+// asynchronous state machines which consume datagram sockets. The read
+// and write quota count in packets rather than bytes.
+bssl::UniquePtr<BIO> AsyncBioCreateDatagram();
+
+// AsyncBioAllowRead increments |bio|'s read quota by |count|.
+void AsyncBioAllowRead(BIO *bio, size_t count);
+
+// AsyncBioAllowWrite increments |bio|'s write quota by |count|.
+void AsyncBioAllowWrite(BIO *bio, size_t count);
+
+// AsyncBioEnforceWriteQuota configures where |bio| enforces its write quota.
+void AsyncBioEnforceWriteQuota(BIO *bio, bool enforce);
+
+
+#endif // HEADER_ASYNC_BIO
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/bssl_shim.cc b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/bssl_shim.cc
new file mode 100644
index 000000000..804cbbb67
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/bssl_shim.cc
@@ -0,0 +1,2137 @@
+/* Copyright (c) 2014, 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. */
+
+#if !defined(__STDC_FORMAT_MACROS)
+#define __STDC_FORMAT_MACROS
+#endif
+
+#include <openssl/base.h>
+
+#if !defined(OPENSSL_WINDOWS)
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <signal.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <unistd.h>
+#else
+#include <io.h>
+OPENSSL_MSVC_PRAGMA(warning(push, 3))
+#include <winsock2.h>
+#include <ws2tcpip.h>
+OPENSSL_MSVC_PRAGMA(warning(pop))
+
+OPENSSL_MSVC_PRAGMA(comment(lib, "Ws2_32.lib"))
+#endif
+
+#include <assert.h>
+#include <inttypes.h>
+#include <string.h>
+
+#include <openssl/aead.h>
+#include <openssl/bio.h>
+#include <openssl/buf.h>
+#include <openssl/bytestring.h>
+#include <openssl/cipher.h>
+#include <openssl/crypto.h>
+#include <openssl/dh.h>
+#include <openssl/digest.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#include <openssl/nid.h>
+#include <openssl/rand.h>
+#include <openssl/ssl.h>
+#include <openssl/x509.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "../../crypto/internal.h"
+#include "async_bio.h"
+#include "packeted_bio.h"
+#include "test_config.h"
+
+
+static CRYPTO_BUFFER_POOL *g_pool = nullptr;
+
+#if !defined(OPENSSL_WINDOWS)
+static int closesocket(int sock) {
+ return close(sock);
+}
+
+static void PrintSocketError(const char *func) {
+ perror(func);
+}
+#else
+static void PrintSocketError(const char *func) {
+ fprintf(stderr, "%s: %d\n", func, WSAGetLastError());
+}
+#endif
+
+static int Usage(const char *program) {
+ fprintf(stderr, "Usage: %s [flags...]\n", program);
+ return 1;
+}
+
+struct TestState {
+ // async_bio is async BIO which pauses reads and writes.
+ BIO *async_bio = nullptr;
+ // packeted_bio is the packeted BIO which simulates read timeouts.
+ BIO *packeted_bio = nullptr;
+ bssl::UniquePtr<EVP_PKEY> channel_id;
+ bool cert_ready = false;
+ bssl::UniquePtr<SSL_SESSION> session;
+ bssl::UniquePtr<SSL_SESSION> pending_session;
+ bool early_callback_called = false;
+ bool handshake_done = false;
+ // private_key is the underlying private key used when testing custom keys.
+ bssl::UniquePtr<EVP_PKEY> private_key;
+ std::vector<uint8_t> private_key_result;
+ // private_key_retries is the number of times an asynchronous private key
+ // operation has been retried.
+ unsigned private_key_retries = 0;
+ bool got_new_session = false;
+ bssl::UniquePtr<SSL_SESSION> new_session;
+ bool ticket_decrypt_done = false;
+ bool alpn_select_done = false;
+ bool early_callback_ready = false;
+};
+
+static void TestStateExFree(void *parent, void *ptr, CRYPTO_EX_DATA *ad,
+ int index, long argl, void *argp) {
+ delete ((TestState *)ptr);
+}
+
+static int g_config_index = 0;
+static int g_state_index = 0;
+
+static bool SetTestConfig(SSL *ssl, const TestConfig *config) {
+ return SSL_set_ex_data(ssl, g_config_index, (void *)config) == 1;
+}
+
+static const TestConfig *GetTestConfig(const SSL *ssl) {
+ return (const TestConfig *)SSL_get_ex_data(ssl, g_config_index);
+}
+
+static bool SetTestState(SSL *ssl, std::unique_ptr<TestState> state) {
+ // |SSL_set_ex_data| takes ownership of |state| only on success.
+ if (SSL_set_ex_data(ssl, g_state_index, state.get()) == 1) {
+ state.release();
+ return true;
+ }
+ return false;
+}
+
+static TestState *GetTestState(const SSL *ssl) {
+ return (TestState *)SSL_get_ex_data(ssl, g_state_index);
+}
+
+static bool LoadCertificate(bssl::UniquePtr<X509> *out_x509,
+ bssl::UniquePtr<STACK_OF(X509)> *out_chain,
+ const std::string &file) {
+ bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_file()));
+ if (!bio || !BIO_read_filename(bio.get(), file.c_str())) {
+ return false;
+ }
+
+ out_x509->reset(PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr));
+ if (!*out_x509) {
+ return false;
+ }
+
+ out_chain->reset(sk_X509_new_null());
+ if (!*out_chain) {
+ return false;
+ }
+
+ // Keep reading the certificate chain.
+ for (;;) {
+ bssl::UniquePtr<X509> cert(
+ PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr));
+ if (!cert) {
+ break;
+ }
+
+ if (!sk_X509_push(out_chain->get(), cert.get())) {
+ return false;
+ }
+ cert.release(); // sk_X509_push takes ownership.
+ }
+
+ uint32_t err = ERR_peek_last_error();
+ if (ERR_GET_LIB(err) != ERR_LIB_PEM ||
+ ERR_GET_REASON(err) != PEM_R_NO_START_LINE) {
+ return false;
+}
+
+ ERR_clear_error();
+ return true;
+}
+
+static bssl::UniquePtr<EVP_PKEY> LoadPrivateKey(const std::string &file) {
+ bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_file()));
+ if (!bio || !BIO_read_filename(bio.get(), file.c_str())) {
+ return nullptr;
+ }
+ return bssl::UniquePtr<EVP_PKEY>(
+ PEM_read_bio_PrivateKey(bio.get(), NULL, NULL, NULL));
+}
+
+static bool FromHexDigit(uint8_t *out, char c) {
+ if ('0' <= c && c <= '9') {
+ *out = c - '0';
+ return true;
+ }
+ if ('a' <= c && c <= 'f') {
+ *out = c - 'a' + 10;
+ return true;
+ }
+ if ('A' <= c && c <= 'F') {
+ *out = c - 'A' + 10;
+ return true;
+ }
+ return false;
+}
+
+static bool HexDecode(std::string *out, const std::string &in) {
+ if ((in.size() & 1) != 0) {
+ return false;
+ }
+
+ std::unique_ptr<uint8_t[]> buf(new uint8_t[in.size() / 2]);
+ for (size_t i = 0; i < in.size() / 2; i++) {
+ uint8_t high, low;
+ if (!FromHexDigit(&high, in[i*2]) ||
+ !FromHexDigit(&low, in[i*2+1])) {
+ return false;
+ }
+ buf[i] = (high << 4) | low;
+ }
+
+ out->assign(reinterpret_cast<const char *>(buf.get()), in.size() / 2);
+ return true;
+}
+
+static std::vector<std::string> SplitParts(const std::string &in,
+ const char delim) {
+ std::vector<std::string> ret;
+ size_t start = 0;
+
+ for (size_t i = 0; i < in.size(); i++) {
+ if (in[i] == delim) {
+ ret.push_back(in.substr(start, i - start));
+ start = i + 1;
+ }
+ }
+
+ ret.push_back(in.substr(start, std::string::npos));
+ return ret;
+}
+
+static std::vector<std::string> DecodeHexStrings(
+ const std::string &hex_strings) {
+ std::vector<std::string> ret;
+ const std::vector<std::string> parts = SplitParts(hex_strings, ',');
+
+ for (const auto &part : parts) {
+ std::string binary;
+ if (!HexDecode(&binary, part)) {
+ fprintf(stderr, "Bad hex string: %s\n", part.c_str());
+ return ret;
+ }
+
+ ret.push_back(binary);
+ }
+
+ return ret;
+}
+
+static bssl::UniquePtr<STACK_OF(X509_NAME)> DecodeHexX509Names(
+ const std::string &hex_names) {
+ const std::vector<std::string> der_names = DecodeHexStrings(hex_names);
+ bssl::UniquePtr<STACK_OF(X509_NAME)> ret(sk_X509_NAME_new_null());
+
+ for (const auto &der_name : der_names) {
+ const uint8_t *const data =
+ reinterpret_cast<const uint8_t *>(der_name.data());
+ const uint8_t *derp = data;
+ bssl::UniquePtr<X509_NAME> name(
+ d2i_X509_NAME(nullptr, &derp, der_name.size()));
+ if (!name || derp != data + der_name.size()) {
+ fprintf(stderr, "Failed to parse X509_NAME.\n");
+ return nullptr;
+ }
+
+ if (!sk_X509_NAME_push(ret.get(), name.get())) {
+ return nullptr;
+ }
+ name.release();
+ }
+
+ return ret;
+}
+
+static int AsyncPrivateKeyType(SSL *ssl) {
+ EVP_PKEY *key = GetTestState(ssl)->private_key.get();
+ switch (EVP_PKEY_id(key)) {
+ case EVP_PKEY_RSA:
+ return NID_rsaEncryption;
+ case EVP_PKEY_EC:
+ return EC_GROUP_get_curve_name(
+ EC_KEY_get0_group(EVP_PKEY_get0_EC_KEY(key)));
+ default:
+ return NID_undef;
+ }
+}
+
+static size_t AsyncPrivateKeyMaxSignatureLen(SSL *ssl) {
+ return EVP_PKEY_size(GetTestState(ssl)->private_key.get());
+}
+
+static ssl_private_key_result_t AsyncPrivateKeySign(
+ SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out,
+ uint16_t signature_algorithm, const uint8_t *in, size_t in_len) {
+ TestState *test_state = GetTestState(ssl);
+ if (!test_state->private_key_result.empty()) {
+ fprintf(stderr, "AsyncPrivateKeySign called with operation pending.\n");
+ abort();
+ }
+
+ // Determine the hash.
+ const EVP_MD *md;
+ switch (signature_algorithm) {
+ case SSL_SIGN_RSA_PKCS1_SHA1:
+ case SSL_SIGN_ECDSA_SHA1:
+ md = EVP_sha1();
+ break;
+ case SSL_SIGN_RSA_PKCS1_SHA256:
+ case SSL_SIGN_ECDSA_SECP256R1_SHA256:
+ case SSL_SIGN_RSA_PSS_SHA256:
+ md = EVP_sha256();
+ break;
+ case SSL_SIGN_RSA_PKCS1_SHA384:
+ case SSL_SIGN_ECDSA_SECP384R1_SHA384:
+ case SSL_SIGN_RSA_PSS_SHA384:
+ md = EVP_sha384();
+ break;
+ case SSL_SIGN_RSA_PKCS1_SHA512:
+ case SSL_SIGN_ECDSA_SECP521R1_SHA512:
+ case SSL_SIGN_RSA_PSS_SHA512:
+ md = EVP_sha512();
+ break;
+ case SSL_SIGN_RSA_PKCS1_MD5_SHA1:
+ md = EVP_md5_sha1();
+ break;
+ default:
+ fprintf(stderr, "Unknown signature algorithm %04x.\n",
+ signature_algorithm);
+ return ssl_private_key_failure;
+ }
+
+ bssl::ScopedEVP_MD_CTX ctx;
+ EVP_PKEY_CTX *pctx;
+ if (!EVP_DigestSignInit(ctx.get(), &pctx, md, nullptr,
+ test_state->private_key.get())) {
+ return ssl_private_key_failure;
+ }
+
+ // Configure additional signature parameters.
+ switch (signature_algorithm) {
+ case SSL_SIGN_RSA_PSS_SHA256:
+ case SSL_SIGN_RSA_PSS_SHA384:
+ case SSL_SIGN_RSA_PSS_SHA512:
+ if (!EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) ||
+ !EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx,
+ -1 /* salt len = hash len */)) {
+ return ssl_private_key_failure;
+ }
+ }
+
+ // Write the signature into |test_state|.
+ size_t len = 0;
+ if (!EVP_DigestSignUpdate(ctx.get(), in, in_len) ||
+ !EVP_DigestSignFinal(ctx.get(), nullptr, &len)) {
+ return ssl_private_key_failure;
+ }
+ test_state->private_key_result.resize(len);
+ if (!EVP_DigestSignFinal(ctx.get(), test_state->private_key_result.data(),
+ &len)) {
+ return ssl_private_key_failure;
+ }
+ test_state->private_key_result.resize(len);
+
+ // The signature will be released asynchronously in |AsyncPrivateKeyComplete|.
+ return ssl_private_key_retry;
+}
+
+static ssl_private_key_result_t AsyncPrivateKeyDecrypt(
+ SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out,
+ const uint8_t *in, size_t in_len) {
+ TestState *test_state = GetTestState(ssl);
+ if (!test_state->private_key_result.empty()) {
+ fprintf(stderr,
+ "AsyncPrivateKeyDecrypt called with operation pending.\n");
+ abort();
+ }
+
+ RSA *rsa = EVP_PKEY_get0_RSA(test_state->private_key.get());
+ if (rsa == NULL) {
+ fprintf(stderr,
+ "AsyncPrivateKeyDecrypt called with incorrect key type.\n");
+ abort();
+ }
+ test_state->private_key_result.resize(RSA_size(rsa));
+ if (!RSA_decrypt(rsa, out_len, test_state->private_key_result.data(),
+ RSA_size(rsa), in, in_len, RSA_NO_PADDING)) {
+ return ssl_private_key_failure;
+ }
+
+ test_state->private_key_result.resize(*out_len);
+
+ // The decryption will be released asynchronously in |AsyncPrivateComplete|.
+ return ssl_private_key_retry;
+}
+
+static ssl_private_key_result_t AsyncPrivateKeyComplete(
+ SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out) {
+ TestState *test_state = GetTestState(ssl);
+ if (test_state->private_key_result.empty()) {
+ fprintf(stderr,
+ "AsyncPrivateKeyComplete called without operation pending.\n");
+ abort();
+ }
+
+ if (test_state->private_key_retries < 2) {
+ // Only return the decryption on the second attempt, to test both incomplete
+ // |decrypt| and |decrypt_complete|.
+ return ssl_private_key_retry;
+ }
+
+ if (max_out < test_state->private_key_result.size()) {
+ fprintf(stderr, "Output buffer too small.\n");
+ return ssl_private_key_failure;
+ }
+ OPENSSL_memcpy(out, test_state->private_key_result.data(),
+ test_state->private_key_result.size());
+ *out_len = test_state->private_key_result.size();
+
+ test_state->private_key_result.clear();
+ test_state->private_key_retries = 0;
+ return ssl_private_key_success;
+}
+
+static const SSL_PRIVATE_KEY_METHOD g_async_private_key_method = {
+ AsyncPrivateKeyType,
+ AsyncPrivateKeyMaxSignatureLen,
+ AsyncPrivateKeySign,
+ nullptr /* sign_digest */,
+ AsyncPrivateKeyDecrypt,
+ AsyncPrivateKeyComplete,
+};
+
+template<typename T>
+struct Free {
+ void operator()(T *buf) {
+ free(buf);
+ }
+};
+
+static bool GetCertificate(SSL *ssl, bssl::UniquePtr<X509> *out_x509,
+ bssl::UniquePtr<STACK_OF(X509)> *out_chain,
+ bssl::UniquePtr<EVP_PKEY> *out_pkey) {
+ const TestConfig *config = GetTestConfig(ssl);
+
+ if (!config->digest_prefs.empty()) {
+ std::unique_ptr<char, Free<char>> digest_prefs(
+ strdup(config->digest_prefs.c_str()));
+ std::vector<int> digest_list;
+
+ for (;;) {
+ char *token =
+ strtok(digest_list.empty() ? digest_prefs.get() : nullptr, ",");
+ if (token == nullptr) {
+ break;
+ }
+
+ digest_list.push_back(EVP_MD_type(EVP_get_digestbyname(token)));
+ }
+
+ if (!SSL_set_private_key_digest_prefs(ssl, digest_list.data(),
+ digest_list.size())) {
+ return false;
+ }
+ }
+
+ if (!config->signing_prefs.empty()) {
+ std::vector<uint16_t> u16s(config->signing_prefs.begin(),
+ config->signing_prefs.end());
+ if (!SSL_set_signing_algorithm_prefs(ssl, u16s.data(), u16s.size())) {
+ return false;
+ }
+ }
+
+ if (!config->key_file.empty()) {
+ *out_pkey = LoadPrivateKey(config->key_file.c_str());
+ if (!*out_pkey) {
+ return false;
+ }
+ }
+ if (!config->cert_file.empty() &&
+ !LoadCertificate(out_x509, out_chain, config->cert_file.c_str())) {
+ return false;
+ }
+ if (!config->ocsp_response.empty() &&
+ !SSL_set_ocsp_response(ssl, (const uint8_t *)config->ocsp_response.data(),
+ config->ocsp_response.size())) {
+ return false;
+ }
+ return true;
+}
+
+static bool InstallCertificate(SSL *ssl) {
+ bssl::UniquePtr<X509> x509;
+ bssl::UniquePtr<STACK_OF(X509)> chain;
+ bssl::UniquePtr<EVP_PKEY> pkey;
+ if (!GetCertificate(ssl, &x509, &chain, &pkey)) {
+ return false;
+ }
+
+ if (pkey) {
+ TestState *test_state = GetTestState(ssl);
+ const TestConfig *config = GetTestConfig(ssl);
+ if (config->async) {
+ test_state->private_key = std::move(pkey);
+ SSL_set_private_key_method(ssl, &g_async_private_key_method);
+ } else if (!SSL_use_PrivateKey(ssl, pkey.get())) {
+ return false;
+ }
+ }
+
+ if (x509 && !SSL_use_certificate(ssl, x509.get())) {
+ return false;
+ }
+
+ if (sk_X509_num(chain.get()) > 0 &&
+ !SSL_set1_chain(ssl, chain.get())) {
+ return false;
+ }
+
+ return true;
+}
+
+static int SelectCertificateCallback(const SSL_CLIENT_HELLO *client_hello) {
+ const TestConfig *config = GetTestConfig(client_hello->ssl);
+ GetTestState(client_hello->ssl)->early_callback_called = true;
+
+ if (!config->expected_server_name.empty()) {
+ const uint8_t *extension_data;
+ size_t extension_len;
+ CBS extension, server_name_list, host_name;
+ uint8_t name_type;
+
+ if (!SSL_early_callback_ctx_extension_get(
+ client_hello, TLSEXT_TYPE_server_name, &extension_data,
+ &extension_len)) {
+ fprintf(stderr, "Could not find server_name extension.\n");
+ return -1;
+ }
+
+ CBS_init(&extension, extension_data, extension_len);
+ if (!CBS_get_u16_length_prefixed(&extension, &server_name_list) ||
+ CBS_len(&extension) != 0 ||
+ !CBS_get_u8(&server_name_list, &name_type) ||
+ name_type != TLSEXT_NAMETYPE_host_name ||
+ !CBS_get_u16_length_prefixed(&server_name_list, &host_name) ||
+ CBS_len(&server_name_list) != 0) {
+ fprintf(stderr, "Could not decode server_name extension.\n");
+ return -1;
+ }
+
+ if (!CBS_mem_equal(&host_name,
+ (const uint8_t*)config->expected_server_name.data(),
+ config->expected_server_name.size())) {
+ fprintf(stderr, "Server name mismatch.\n");
+ }
+ }
+
+ if (config->fail_early_callback) {
+ return -1;
+ }
+
+ // Install the certificate in the early callback.
+ if (config->use_early_callback) {
+ bool early_callback_ready =
+ GetTestState(client_hello->ssl)->early_callback_ready;
+ if (config->async && !early_callback_ready) {
+ // Install the certificate asynchronously.
+ return 0;
+ }
+ if (!InstallCertificate(client_hello->ssl)) {
+ return -1;
+ }
+ }
+ return 1;
+}
+
+static bool CheckCertificateRequest(SSL *ssl) {
+ const TestConfig *config = GetTestConfig(ssl);
+
+ if (!config->expected_certificate_types.empty()) {
+ const uint8_t *certificate_types;
+ size_t certificate_types_len =
+ SSL_get0_certificate_types(ssl, &certificate_types);
+ if (certificate_types_len != config->expected_certificate_types.size() ||
+ OPENSSL_memcmp(certificate_types,
+ config->expected_certificate_types.data(),
+ certificate_types_len) != 0) {
+ fprintf(stderr, "certificate types mismatch\n");
+ return false;
+ }
+ }
+
+ if (!config->expected_client_ca_list.empty()) {
+ bssl::UniquePtr<STACK_OF(X509_NAME)> expected =
+ DecodeHexX509Names(config->expected_client_ca_list);
+ const size_t num_expected = sk_X509_NAME_num(expected.get());
+
+ const STACK_OF(X509_NAME) *received = SSL_get_client_CA_list(ssl);
+ const size_t num_received = sk_X509_NAME_num(received);
+
+ if (num_received != num_expected) {
+ fprintf(stderr, "expected %u names in CertificateRequest but got %u\n",
+ static_cast<unsigned>(num_expected),
+ static_cast<unsigned>(num_received));
+ return false;
+ }
+
+ for (size_t i = 0; i < num_received; i++) {
+ if (X509_NAME_cmp(sk_X509_NAME_value(received, i),
+ sk_X509_NAME_value(expected.get(), i)) != 0) {
+ fprintf(stderr, "names in CertificateRequest differ at index #%d\n",
+ static_cast<unsigned>(i));
+ return false;
+ }
+ }
+
+ STACK_OF(CRYPTO_BUFFER) *buffers = SSL_get0_server_requested_CAs(ssl);
+ if (sk_CRYPTO_BUFFER_num(buffers) != num_received) {
+ fprintf(stderr,
+ "Mismatch between SSL_get_server_requested_CAs and "
+ "SSL_get_client_CA_list.\n");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static int ClientCertCallback(SSL *ssl, X509 **out_x509, EVP_PKEY **out_pkey) {
+ if (!CheckCertificateRequest(ssl)) {
+ return -1;
+ }
+
+ if (GetTestConfig(ssl)->async && !GetTestState(ssl)->cert_ready) {
+ return -1;
+ }
+
+ bssl::UniquePtr<X509> x509;
+ bssl::UniquePtr<STACK_OF(X509)> chain;
+ bssl::UniquePtr<EVP_PKEY> pkey;
+ if (!GetCertificate(ssl, &x509, &chain, &pkey)) {
+ return -1;
+ }
+
+ // Return zero for no certificate.
+ if (!x509) {
+ return 0;
+ }
+
+ // Chains and asynchronous private keys are not supported with client_cert_cb.
+ *out_x509 = x509.release();
+ *out_pkey = pkey.release();
+ return 1;
+}
+
+static int CertCallback(SSL *ssl, void *arg) {
+ const TestConfig *config = GetTestConfig(ssl);
+
+ // Check the CertificateRequest metadata is as expected.
+ if (!SSL_is_server(ssl) && !CheckCertificateRequest(ssl)) {
+ return -1;
+ }
+
+ if (config->fail_cert_callback) {
+ return 0;
+ }
+
+ // The certificate will be installed via other means.
+ if (!config->async || config->use_early_callback) {
+ return 1;
+ }
+
+ if (!GetTestState(ssl)->cert_ready) {
+ return -1;
+ }
+ if (!InstallCertificate(ssl)) {
+ return 0;
+ }
+ return 1;
+}
+
+static int VerifySucceed(X509_STORE_CTX *store_ctx, void *arg) {
+ SSL* ssl = (SSL*)X509_STORE_CTX_get_ex_data(store_ctx,
+ SSL_get_ex_data_X509_STORE_CTX_idx());
+ const TestConfig *config = GetTestConfig(ssl);
+
+ if (!config->expected_ocsp_response.empty()) {
+ const uint8_t *data;
+ size_t len;
+ SSL_get0_ocsp_response(ssl, &data, &len);
+ if (len == 0) {
+ fprintf(stderr, "OCSP response not available in verify callback\n");
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static int VerifyFail(X509_STORE_CTX *store_ctx, void *arg) {
+ store_ctx->error = X509_V_ERR_APPLICATION_VERIFICATION;
+ return 0;
+}
+
+static int NextProtosAdvertisedCallback(SSL *ssl, const uint8_t **out,
+ unsigned int *out_len, void *arg) {
+ const TestConfig *config = GetTestConfig(ssl);
+ if (config->advertise_npn.empty()) {
+ return SSL_TLSEXT_ERR_NOACK;
+ }
+
+ *out = (const uint8_t*)config->advertise_npn.data();
+ *out_len = config->advertise_npn.size();
+ return SSL_TLSEXT_ERR_OK;
+}
+
+static int NextProtoSelectCallback(SSL* ssl, uint8_t** out, uint8_t* outlen,
+ const uint8_t* in, unsigned inlen, void* arg) {
+ const TestConfig *config = GetTestConfig(ssl);
+ if (config->select_next_proto.empty()) {
+ return SSL_TLSEXT_ERR_NOACK;
+ }
+
+ *out = (uint8_t*)config->select_next_proto.data();
+ *outlen = config->select_next_proto.size();
+ return SSL_TLSEXT_ERR_OK;
+}
+
+static int AlpnSelectCallback(SSL* ssl, const uint8_t** out, uint8_t* outlen,
+ const uint8_t* in, unsigned inlen, void* arg) {
+ if (GetTestState(ssl)->alpn_select_done) {
+ fprintf(stderr, "AlpnSelectCallback called after completion.\n");
+ exit(1);
+ }
+
+ GetTestState(ssl)->alpn_select_done = true;
+
+ const TestConfig *config = GetTestConfig(ssl);
+ if (config->decline_alpn) {
+ return SSL_TLSEXT_ERR_NOACK;
+ }
+
+ if (!config->expected_advertised_alpn.empty() &&
+ (config->expected_advertised_alpn.size() != inlen ||
+ OPENSSL_memcmp(config->expected_advertised_alpn.data(), in, inlen) !=
+ 0)) {
+ fprintf(stderr, "bad ALPN select callback inputs\n");
+ exit(1);
+ }
+
+ *out = (const uint8_t*)config->select_alpn.data();
+ *outlen = config->select_alpn.size();
+ return SSL_TLSEXT_ERR_OK;
+}
+
+static unsigned PskClientCallback(SSL *ssl, const char *hint,
+ char *out_identity,
+ unsigned max_identity_len,
+ uint8_t *out_psk, unsigned max_psk_len) {
+ const TestConfig *config = GetTestConfig(ssl);
+
+ if (config->psk_identity.empty()) {
+ if (hint != nullptr) {
+ fprintf(stderr, "Server PSK hint was non-null.\n");
+ return 0;
+ }
+ } else if (hint == nullptr ||
+ strcmp(hint, config->psk_identity.c_str()) != 0) {
+ fprintf(stderr, "Server PSK hint did not match.\n");
+ return 0;
+ }
+
+ // Account for the trailing '\0' for the identity.
+ if (config->psk_identity.size() >= max_identity_len ||
+ config->psk.size() > max_psk_len) {
+ fprintf(stderr, "PSK buffers too small\n");
+ return 0;
+ }
+
+ BUF_strlcpy(out_identity, config->psk_identity.c_str(),
+ max_identity_len);
+ OPENSSL_memcpy(out_psk, config->psk.data(), config->psk.size());
+ return config->psk.size();
+}
+
+static unsigned PskServerCallback(SSL *ssl, const char *identity,
+ uint8_t *out_psk, unsigned max_psk_len) {
+ const TestConfig *config = GetTestConfig(ssl);
+
+ if (strcmp(identity, config->psk_identity.c_str()) != 0) {
+ fprintf(stderr, "Client PSK identity did not match.\n");
+ return 0;
+ }
+
+ if (config->psk.size() > max_psk_len) {
+ fprintf(stderr, "PSK buffers too small\n");
+ return 0;
+ }
+
+ OPENSSL_memcpy(out_psk, config->psk.data(), config->psk.size());
+ return config->psk.size();
+}
+
+static timeval g_clock;
+
+static void CurrentTimeCallback(const SSL *ssl, timeval *out_clock) {
+ *out_clock = g_clock;
+}
+
+static void ChannelIdCallback(SSL *ssl, EVP_PKEY **out_pkey) {
+ *out_pkey = GetTestState(ssl)->channel_id.release();
+}
+
+static SSL_SESSION *GetSessionCallback(SSL *ssl, uint8_t *data, int len,
+ int *copy) {
+ TestState *async_state = GetTestState(ssl);
+ if (async_state->session) {
+ *copy = 0;
+ return async_state->session.release();
+ } else if (async_state->pending_session) {
+ return SSL_magic_pending_session_ptr();
+ } else {
+ return NULL;
+ }
+}
+
+static int DDoSCallback(const SSL_CLIENT_HELLO *client_hello) {
+ const TestConfig *config = GetTestConfig(client_hello->ssl);
+ static int callback_num = 0;
+
+ callback_num++;
+ if (config->fail_ddos_callback ||
+ (config->fail_second_ddos_callback && callback_num == 2)) {
+ return 0;
+ }
+ return 1;
+}
+
+static void InfoCallback(const SSL *ssl, int type, int val) {
+ if (type == SSL_CB_HANDSHAKE_DONE) {
+ if (GetTestConfig(ssl)->handshake_never_done) {
+ fprintf(stderr, "Handshake unexpectedly completed.\n");
+ // Abort before any expected error code is printed, to ensure the overall
+ // test fails.
+ abort();
+ }
+ GetTestState(ssl)->handshake_done = true;
+
+ // Callbacks may be called again on a new handshake.
+ GetTestState(ssl)->ticket_decrypt_done = false;
+ GetTestState(ssl)->alpn_select_done = false;
+ }
+}
+
+static int NewSessionCallback(SSL *ssl, SSL_SESSION *session) {
+ GetTestState(ssl)->got_new_session = true;
+ GetTestState(ssl)->new_session.reset(session);
+ return 1;
+}
+
+static int TicketKeyCallback(SSL *ssl, uint8_t *key_name, uint8_t *iv,
+ EVP_CIPHER_CTX *ctx, HMAC_CTX *hmac_ctx,
+ int encrypt) {
+ if (!encrypt) {
+ if (GetTestState(ssl)->ticket_decrypt_done) {
+ fprintf(stderr, "TicketKeyCallback called after completion.\n");
+ return -1;
+ }
+
+ GetTestState(ssl)->ticket_decrypt_done = true;
+ }
+
+ // This is just test code, so use the all-zeros key.
+ static const uint8_t kZeros[16] = {0};
+
+ if (encrypt) {
+ OPENSSL_memcpy(key_name, kZeros, sizeof(kZeros));
+ RAND_bytes(iv, 16);
+ } else if (OPENSSL_memcmp(key_name, kZeros, 16) != 0) {
+ return 0;
+ }
+
+ if (!HMAC_Init_ex(hmac_ctx, kZeros, sizeof(kZeros), EVP_sha256(), NULL) ||
+ !EVP_CipherInit_ex(ctx, EVP_aes_128_cbc(), NULL, kZeros, iv, encrypt)) {
+ return -1;
+ }
+
+ if (!encrypt) {
+ return GetTestConfig(ssl)->renew_ticket ? 2 : 1;
+ }
+ return 1;
+}
+
+// kCustomExtensionValue is the extension value that the custom extension
+// callbacks will add.
+static const uint16_t kCustomExtensionValue = 1234;
+static void *const kCustomExtensionAddArg =
+ reinterpret_cast<void *>(kCustomExtensionValue);
+static void *const kCustomExtensionParseArg =
+ reinterpret_cast<void *>(kCustomExtensionValue + 1);
+static const char kCustomExtensionContents[] = "custom extension";
+
+static int CustomExtensionAddCallback(SSL *ssl, unsigned extension_value,
+ const uint8_t **out, size_t *out_len,
+ int *out_alert_value, void *add_arg) {
+ if (extension_value != kCustomExtensionValue ||
+ add_arg != kCustomExtensionAddArg) {
+ abort();
+ }
+
+ if (GetTestConfig(ssl)->custom_extension_skip) {
+ return 0;
+ }
+ if (GetTestConfig(ssl)->custom_extension_fail_add) {
+ return -1;
+ }
+
+ *out = reinterpret_cast<const uint8_t*>(kCustomExtensionContents);
+ *out_len = sizeof(kCustomExtensionContents) - 1;
+
+ return 1;
+}
+
+static void CustomExtensionFreeCallback(SSL *ssl, unsigned extension_value,
+ const uint8_t *out, void *add_arg) {
+ if (extension_value != kCustomExtensionValue ||
+ add_arg != kCustomExtensionAddArg ||
+ out != reinterpret_cast<const uint8_t *>(kCustomExtensionContents)) {
+ abort();
+ }
+}
+
+static int CustomExtensionParseCallback(SSL *ssl, unsigned extension_value,
+ const uint8_t *contents,
+ size_t contents_len,
+ int *out_alert_value, void *parse_arg) {
+ if (extension_value != kCustomExtensionValue ||
+ parse_arg != kCustomExtensionParseArg) {
+ abort();
+ }
+
+ if (contents_len != sizeof(kCustomExtensionContents) - 1 ||
+ OPENSSL_memcmp(contents, kCustomExtensionContents, contents_len) != 0) {
+ *out_alert_value = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ return 1;
+}
+
+static int ServerNameCallback(SSL *ssl, int *out_alert, void *arg) {
+ // SNI must be accessible from the SNI callback.
+ const TestConfig *config = GetTestConfig(ssl);
+ const char *server_name = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
+ if (server_name == nullptr ||
+ std::string(server_name) != config->expected_server_name) {
+ fprintf(stderr, "servername mismatch (got %s; want %s)\n", server_name,
+ config->expected_server_name.c_str());
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
+ }
+
+ return SSL_TLSEXT_ERR_OK;
+}
+
+// Connect returns a new socket connected to localhost on |port| or -1 on
+// error.
+static int Connect(uint16_t port) {
+ int sock = socket(AF_INET, SOCK_STREAM, 0);
+ if (sock == -1) {
+ PrintSocketError("socket");
+ return -1;
+ }
+ int nodelay = 1;
+ if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
+ reinterpret_cast<const char*>(&nodelay), sizeof(nodelay)) != 0) {
+ PrintSocketError("setsockopt");
+ closesocket(sock);
+ return -1;
+ }
+ sockaddr_in sin;
+ OPENSSL_memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(port);
+ if (!inet_pton(AF_INET, "127.0.0.1", &sin.sin_addr)) {
+ PrintSocketError("inet_pton");
+ closesocket(sock);
+ return -1;
+ }
+ if (connect(sock, reinterpret_cast<const sockaddr*>(&sin),
+ sizeof(sin)) != 0) {
+ PrintSocketError("connect");
+ closesocket(sock);
+ return -1;
+ }
+ return sock;
+}
+
+class SocketCloser {
+ public:
+ explicit SocketCloser(int sock) : sock_(sock) {}
+ ~SocketCloser() {
+ // Half-close and drain the socket before releasing it. This seems to be
+ // necessary for graceful shutdown on Windows. It will also avoid write
+ // failures in the test runner.
+#if defined(OPENSSL_WINDOWS)
+ shutdown(sock_, SD_SEND);
+#else
+ shutdown(sock_, SHUT_WR);
+#endif
+ while (true) {
+ char buf[1024];
+ if (recv(sock_, buf, sizeof(buf), 0) <= 0) {
+ break;
+ }
+ }
+ closesocket(sock_);
+ }
+
+ private:
+ const int sock_;
+};
+
+static bssl::UniquePtr<SSL_CTX> SetupCtx(const TestConfig *config) {
+ bssl::UniquePtr<SSL_CTX> ssl_ctx(SSL_CTX_new(
+ config->is_dtls ? DTLS_method() : TLS_method()));
+ if (!ssl_ctx) {
+ return nullptr;
+ }
+
+ SSL_CTX_set0_buffer_pool(ssl_ctx.get(), g_pool);
+
+ // Enable TLS 1.3 for tests.
+ if (!config->is_dtls &&
+ !SSL_CTX_set_max_proto_version(ssl_ctx.get(), TLS1_3_VERSION)) {
+ return nullptr;
+ }
+
+ std::string cipher_list = "ALL";
+ if (!config->cipher.empty()) {
+ cipher_list = config->cipher;
+ SSL_CTX_set_options(ssl_ctx.get(), SSL_OP_CIPHER_SERVER_PREFERENCE);
+ }
+ if (!SSL_CTX_set_strict_cipher_list(ssl_ctx.get(), cipher_list.c_str())) {
+ return nullptr;
+ }
+
+ bssl::UniquePtr<DH> dh(DH_get_2048_256(NULL));
+ if (!dh) {
+ return nullptr;
+ }
+
+ if (config->use_sparse_dh_prime) {
+ // This prime number is 2^1024 + 643 – a value just above a power of two.
+ // Because of its form, values modulo it are essentially certain to be one
+ // byte shorter. This is used to test padding of these values.
+ if (BN_hex2bn(
+ &dh->p,
+ "1000000000000000000000000000000000000000000000000000000000000000"
+ "0000000000000000000000000000000000000000000000000000000000000000"
+ "0000000000000000000000000000000000000000000000000000000000000000"
+ "0000000000000000000000000000000000000000000000000000000000000028"
+ "3") == 0 ||
+ !BN_set_word(dh->g, 2)) {
+ return nullptr;
+ }
+ BN_free(dh->q);
+ dh->q = NULL;
+ dh->priv_length = 0;
+ }
+
+ if (!SSL_CTX_set_tmp_dh(ssl_ctx.get(), dh.get())) {
+ return nullptr;
+ }
+
+ if (config->async && config->is_server) {
+ // Disable the internal session cache. To test asynchronous session lookup,
+ // we use an external session cache.
+ SSL_CTX_set_session_cache_mode(
+ ssl_ctx.get(), SSL_SESS_CACHE_BOTH | SSL_SESS_CACHE_NO_INTERNAL);
+ SSL_CTX_sess_set_get_cb(ssl_ctx.get(), GetSessionCallback);
+ } else {
+ SSL_CTX_set_session_cache_mode(ssl_ctx.get(), SSL_SESS_CACHE_BOTH);
+ }
+
+ SSL_CTX_set_select_certificate_cb(ssl_ctx.get(), SelectCertificateCallback);
+
+ if (config->use_old_client_cert_callback) {
+ SSL_CTX_set_client_cert_cb(ssl_ctx.get(), ClientCertCallback);
+ }
+
+ SSL_CTX_set_next_protos_advertised_cb(
+ ssl_ctx.get(), NextProtosAdvertisedCallback, NULL);
+ if (!config->select_next_proto.empty()) {
+ SSL_CTX_set_next_proto_select_cb(ssl_ctx.get(), NextProtoSelectCallback,
+ NULL);
+ }
+
+ if (!config->select_alpn.empty() || config->decline_alpn) {
+ SSL_CTX_set_alpn_select_cb(ssl_ctx.get(), AlpnSelectCallback, NULL);
+ }
+
+ SSL_CTX_set_channel_id_cb(ssl_ctx.get(), ChannelIdCallback);
+
+ SSL_CTX_set_current_time_cb(ssl_ctx.get(), CurrentTimeCallback);
+
+ SSL_CTX_set_info_callback(ssl_ctx.get(), InfoCallback);
+ SSL_CTX_sess_set_new_cb(ssl_ctx.get(), NewSessionCallback);
+
+ if (config->use_ticket_callback) {
+ SSL_CTX_set_tlsext_ticket_key_cb(ssl_ctx.get(), TicketKeyCallback);
+ }
+
+ if (config->enable_client_custom_extension &&
+ !SSL_CTX_add_client_custom_ext(
+ ssl_ctx.get(), kCustomExtensionValue, CustomExtensionAddCallback,
+ CustomExtensionFreeCallback, kCustomExtensionAddArg,
+ CustomExtensionParseCallback, kCustomExtensionParseArg)) {
+ return nullptr;
+ }
+
+ if (config->enable_server_custom_extension &&
+ !SSL_CTX_add_server_custom_ext(
+ ssl_ctx.get(), kCustomExtensionValue, CustomExtensionAddCallback,
+ CustomExtensionFreeCallback, kCustomExtensionAddArg,
+ CustomExtensionParseCallback, kCustomExtensionParseArg)) {
+ return nullptr;
+ }
+
+ if (config->verify_fail) {
+ SSL_CTX_set_cert_verify_callback(ssl_ctx.get(), VerifyFail, NULL);
+ } else {
+ SSL_CTX_set_cert_verify_callback(ssl_ctx.get(), VerifySucceed, NULL);
+ }
+
+ if (!config->signed_cert_timestamps.empty() &&
+ !SSL_CTX_set_signed_cert_timestamp_list(
+ ssl_ctx.get(), (const uint8_t *)config->signed_cert_timestamps.data(),
+ config->signed_cert_timestamps.size())) {
+ return nullptr;
+ }
+
+ if (!config->use_client_ca_list.empty()) {
+ if (config->use_client_ca_list == "<NULL>") {
+ SSL_CTX_set_client_CA_list(ssl_ctx.get(), nullptr);
+ } else {
+ bssl::UniquePtr<STACK_OF(X509_NAME)> names =
+ DecodeHexX509Names(config->use_client_ca_list);
+ SSL_CTX_set_client_CA_list(ssl_ctx.get(), names.release());
+ }
+ }
+
+ if (config->enable_grease) {
+ SSL_CTX_set_grease_enabled(ssl_ctx.get(), 1);
+ }
+
+ if (!config->expected_server_name.empty()) {
+ SSL_CTX_set_tlsext_servername_callback(ssl_ctx.get(), ServerNameCallback);
+ }
+
+ if (!config->ticket_key.empty() &&
+ !SSL_CTX_set_tlsext_ticket_keys(ssl_ctx.get(), config->ticket_key.data(),
+ config->ticket_key.size())) {
+ return nullptr;
+ }
+
+ if (config->enable_early_data) {
+ SSL_CTX_set_early_data_enabled(ssl_ctx.get(), 1);
+ }
+
+ return ssl_ctx;
+}
+
+// RetryAsync is called after a failed operation on |ssl| with return code
+// |ret|. If the operation should be retried, it simulates one asynchronous
+// event and returns true. Otherwise it returns false.
+static bool RetryAsync(SSL *ssl, int ret) {
+ // No error; don't retry.
+ if (ret >= 0) {
+ return false;
+ }
+
+ TestState *test_state = GetTestState(ssl);
+ assert(GetTestConfig(ssl)->async);
+
+ if (test_state->packeted_bio != nullptr &&
+ PacketedBioAdvanceClock(test_state->packeted_bio)) {
+ // The DTLS retransmit logic silently ignores write failures. So the test
+ // may progress, allow writes through synchronously.
+ AsyncBioEnforceWriteQuota(test_state->async_bio, false);
+ int timeout_ret = DTLSv1_handle_timeout(ssl);
+ AsyncBioEnforceWriteQuota(test_state->async_bio, true);
+
+ if (timeout_ret < 0) {
+ fprintf(stderr, "Error retransmitting.\n");
+ return false;
+ }
+ return true;
+ }
+
+ // See if we needed to read or write more. If so, allow one byte through on
+ // the appropriate end to maximally stress the state machine.
+ switch (SSL_get_error(ssl, ret)) {
+ case SSL_ERROR_WANT_READ:
+ AsyncBioAllowRead(test_state->async_bio, 1);
+ return true;
+ case SSL_ERROR_WANT_WRITE:
+ AsyncBioAllowWrite(test_state->async_bio, 1);
+ return true;
+ case SSL_ERROR_WANT_CHANNEL_ID_LOOKUP: {
+ bssl::UniquePtr<EVP_PKEY> pkey =
+ LoadPrivateKey(GetTestConfig(ssl)->send_channel_id);
+ if (!pkey) {
+ return false;
+ }
+ test_state->channel_id = std::move(pkey);
+ return true;
+ }
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ test_state->cert_ready = true;
+ return true;
+ case SSL_ERROR_PENDING_SESSION:
+ test_state->session = std::move(test_state->pending_session);
+ return true;
+ case SSL_ERROR_PENDING_CERTIFICATE:
+ test_state->early_callback_ready = true;
+ return true;
+ case SSL_ERROR_WANT_PRIVATE_KEY_OPERATION:
+ test_state->private_key_retries++;
+ return true;
+ default:
+ return false;
+ }
+}
+
+// DoRead reads from |ssl|, resolving any asynchronous operations. It returns
+// the result value of the final |SSL_read| call.
+static int DoRead(SSL *ssl, uint8_t *out, size_t max_out) {
+ const TestConfig *config = GetTestConfig(ssl);
+ TestState *test_state = GetTestState(ssl);
+ int ret;
+ do {
+ if (config->async) {
+ // The DTLS retransmit logic silently ignores write failures. So the test
+ // may progress, allow writes through synchronously. |SSL_read| may
+ // trigger a retransmit, so disconnect the write quota.
+ AsyncBioEnforceWriteQuota(test_state->async_bio, false);
+ }
+ ret = config->peek_then_read ? SSL_peek(ssl, out, max_out)
+ : SSL_read(ssl, out, max_out);
+ if (config->async) {
+ AsyncBioEnforceWriteQuota(test_state->async_bio, true);
+ }
+
+ // Run the exporter after each read. This is to test that the exporter fails
+ // during a renegotiation.
+ if (config->use_exporter_between_reads) {
+ uint8_t buf;
+ if (!SSL_export_keying_material(ssl, &buf, 1, NULL, 0, NULL, 0, 0)) {
+ fprintf(stderr, "failed to export keying material\n");
+ return -1;
+ }
+ }
+ } while (config->async && RetryAsync(ssl, ret));
+
+ if (config->peek_then_read && ret > 0) {
+ std::unique_ptr<uint8_t[]> buf(new uint8_t[static_cast<size_t>(ret)]);
+
+ // SSL_peek should synchronously return the same data.
+ int ret2 = SSL_peek(ssl, buf.get(), ret);
+ if (ret2 != ret ||
+ OPENSSL_memcmp(buf.get(), out, ret) != 0) {
+ fprintf(stderr, "First and second SSL_peek did not match.\n");
+ return -1;
+ }
+
+ // SSL_read should synchronously return the same data and consume it.
+ ret2 = SSL_read(ssl, buf.get(), ret);
+ if (ret2 != ret ||
+ OPENSSL_memcmp(buf.get(), out, ret) != 0) {
+ fprintf(stderr, "SSL_peek and SSL_read did not match.\n");
+ return -1;
+ }
+ }
+
+ return ret;
+}
+
+// WriteAll writes |in_len| bytes from |in| to |ssl|, resolving any asynchronous
+// operations. It returns the result of the final |SSL_write| call.
+static int WriteAll(SSL *ssl, const uint8_t *in, size_t in_len) {
+ const TestConfig *config = GetTestConfig(ssl);
+ int ret;
+ do {
+ ret = SSL_write(ssl, in, in_len);
+ if (ret > 0) {
+ in += ret;
+ in_len -= ret;
+ }
+ } while ((config->async && RetryAsync(ssl, ret)) || (ret > 0 && in_len > 0));
+ return ret;
+}
+
+// DoShutdown calls |SSL_shutdown|, resolving any asynchronous operations. It
+// returns the result of the final |SSL_shutdown| call.
+static int DoShutdown(SSL *ssl) {
+ const TestConfig *config = GetTestConfig(ssl);
+ int ret;
+ do {
+ ret = SSL_shutdown(ssl);
+ } while (config->async && RetryAsync(ssl, ret));
+ return ret;
+}
+
+// DoSendFatalAlert calls |SSL_send_fatal_alert|, resolving any asynchronous
+// operations. It returns the result of the final |SSL_send_fatal_alert| call.
+static int DoSendFatalAlert(SSL *ssl, uint8_t alert) {
+ const TestConfig *config = GetTestConfig(ssl);
+ int ret;
+ do {
+ ret = SSL_send_fatal_alert(ssl, alert);
+ } while (config->async && RetryAsync(ssl, ret));
+ return ret;
+}
+
+static uint16_t GetProtocolVersion(const SSL *ssl) {
+ uint16_t version = SSL_version(ssl);
+ if (!SSL_is_dtls(ssl)) {
+ return version;
+ }
+ return 0x0201 + ~version;
+}
+
+// CheckHandshakeProperties checks, immediately after |ssl| completes its
+// initial handshake (or False Starts), whether all the properties are
+// consistent with the test configuration and invariants.
+static bool CheckHandshakeProperties(SSL *ssl, bool is_resume) {
+ const TestConfig *config = GetTestConfig(ssl);
+
+ if (SSL_get_current_cipher(ssl) == nullptr) {
+ fprintf(stderr, "null cipher after handshake\n");
+ return false;
+ }
+
+ if (is_resume &&
+ (!!SSL_session_reused(ssl) == config->expect_session_miss)) {
+ fprintf(stderr, "session was%s reused\n",
+ SSL_session_reused(ssl) ? "" : " not");
+ return false;
+ }
+
+ bool expect_handshake_done = is_resume || !config->false_start;
+ if (expect_handshake_done != GetTestState(ssl)->handshake_done) {
+ fprintf(stderr, "handshake was%s completed\n",
+ GetTestState(ssl)->handshake_done ? "" : " not");
+ return false;
+ }
+
+ if (expect_handshake_done && !config->is_server) {
+ bool expect_new_session =
+ !config->expect_no_session &&
+ (!SSL_session_reused(ssl) || config->expect_ticket_renewal) &&
+ // Session tickets are sent post-handshake in TLS 1.3.
+ GetProtocolVersion(ssl) < TLS1_3_VERSION;
+ if (expect_new_session != GetTestState(ssl)->got_new_session) {
+ fprintf(stderr,
+ "new session was%s cached, but we expected the opposite\n",
+ GetTestState(ssl)->got_new_session ? "" : " not");
+ return false;
+ }
+ }
+
+ if (!is_resume) {
+ if (config->expect_session_id && !GetTestState(ssl)->got_new_session) {
+ fprintf(stderr, "session was not cached on the server.\n");
+ return false;
+ }
+ if (config->expect_no_session_id && GetTestState(ssl)->got_new_session) {
+ fprintf(stderr, "session was unexpectedly cached on the server.\n");
+ return false;
+ }
+ }
+
+ if (config->is_server && !GetTestState(ssl)->early_callback_called) {
+ fprintf(stderr, "early callback not called\n");
+ return false;
+ }
+
+ if (!config->expected_server_name.empty()) {
+ const char *server_name =
+ SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
+ if (server_name == nullptr ||
+ server_name != config->expected_server_name) {
+ fprintf(stderr, "servername mismatch (got %s; want %s)\n",
+ server_name, config->expected_server_name.c_str());
+ return false;
+ }
+ }
+
+ if (!config->expected_next_proto.empty()) {
+ const uint8_t *next_proto;
+ unsigned next_proto_len;
+ SSL_get0_next_proto_negotiated(ssl, &next_proto, &next_proto_len);
+ if (next_proto_len != config->expected_next_proto.size() ||
+ OPENSSL_memcmp(next_proto, config->expected_next_proto.data(),
+ next_proto_len) != 0) {
+ fprintf(stderr, "negotiated next proto mismatch\n");
+ return false;
+ }
+ }
+
+ if (!config->expected_alpn.empty()) {
+ const uint8_t *alpn_proto;
+ unsigned alpn_proto_len;
+ SSL_get0_alpn_selected(ssl, &alpn_proto, &alpn_proto_len);
+ if (alpn_proto_len != config->expected_alpn.size() ||
+ OPENSSL_memcmp(alpn_proto, config->expected_alpn.data(),
+ alpn_proto_len) != 0) {
+ fprintf(stderr, "negotiated alpn proto mismatch\n");
+ return false;
+ }
+ }
+
+ if (!config->expected_channel_id.empty()) {
+ uint8_t channel_id[64];
+ if (!SSL_get_tls_channel_id(ssl, channel_id, sizeof(channel_id))) {
+ fprintf(stderr, "no channel id negotiated\n");
+ return false;
+ }
+ if (config->expected_channel_id.size() != 64 ||
+ OPENSSL_memcmp(config->expected_channel_id.data(), channel_id, 64) !=
+ 0) {
+ fprintf(stderr, "channel id mismatch\n");
+ return false;
+ }
+ }
+
+ if (config->expect_extended_master_secret && !SSL_get_extms_support(ssl)) {
+ fprintf(stderr, "No EMS for connection when expected\n");
+ return false;
+ }
+
+ if (config->expect_secure_renegotiation &&
+ !SSL_get_secure_renegotiation_support(ssl)) {
+ fprintf(stderr, "No secure renegotiation for connection when expected\n");
+ return false;
+ }
+
+ if (config->expect_no_secure_renegotiation &&
+ SSL_get_secure_renegotiation_support(ssl)) {
+ fprintf(stderr,
+ "Secure renegotiation unexpectedly negotiated for connection\n");
+ return false;
+ }
+
+ if (!config->expected_ocsp_response.empty()) {
+ const uint8_t *data;
+ size_t len;
+ SSL_get0_ocsp_response(ssl, &data, &len);
+ if (config->expected_ocsp_response.size() != len ||
+ OPENSSL_memcmp(config->expected_ocsp_response.data(), data, len) != 0) {
+ fprintf(stderr, "OCSP response mismatch\n");
+ return false;
+ }
+ }
+
+ if (!config->expected_signed_cert_timestamps.empty()) {
+ const uint8_t *data;
+ size_t len;
+ SSL_get0_signed_cert_timestamp_list(ssl, &data, &len);
+ if (config->expected_signed_cert_timestamps.size() != len ||
+ OPENSSL_memcmp(config->expected_signed_cert_timestamps.data(), data,
+ len) != 0) {
+ fprintf(stderr, "SCT list mismatch\n");
+ return false;
+ }
+ }
+
+ if (config->expect_verify_result) {
+ int expected_verify_result = config->verify_fail ?
+ X509_V_ERR_APPLICATION_VERIFICATION :
+ X509_V_OK;
+
+ if (SSL_get_verify_result(ssl) != expected_verify_result) {
+ fprintf(stderr, "Wrong certificate verification result\n");
+ return false;
+ }
+ }
+
+ if (config->expect_peer_signature_algorithm != 0 &&
+ config->expect_peer_signature_algorithm !=
+ SSL_get_peer_signature_algorithm(ssl)) {
+ fprintf(stderr, "Peer signature algorithm was %04x, wanted %04x.\n",
+ SSL_get_peer_signature_algorithm(ssl),
+ config->expect_peer_signature_algorithm);
+ return false;
+ }
+
+ int expect_curve_id = config->expect_curve_id;
+ if (is_resume && config->expect_resume_curve_id != 0) {
+ expect_curve_id = config->expect_resume_curve_id;
+ }
+ if (expect_curve_id != 0) {
+ uint16_t curve_id = SSL_get_curve_id(ssl);
+ if (static_cast<uint16_t>(expect_curve_id) != curve_id) {
+ fprintf(stderr, "curve_id was %04x, wanted %04x\n", curve_id,
+ static_cast<uint16_t>(expect_curve_id));
+ return false;
+ }
+ }
+
+ uint16_t cipher_id =
+ static_cast<uint16_t>(SSL_CIPHER_get_id(SSL_get_current_cipher(ssl)));
+ if (config->expect_cipher_aes != 0 &&
+ EVP_has_aes_hardware() &&
+ static_cast<uint16_t>(config->expect_cipher_aes) != cipher_id) {
+ fprintf(stderr, "Cipher ID was %04x, wanted %04x (has AES hardware)\n",
+ cipher_id, static_cast<uint16_t>(config->expect_cipher_aes));
+ return false;
+ }
+
+ if (config->expect_cipher_no_aes != 0 &&
+ !EVP_has_aes_hardware() &&
+ static_cast<uint16_t>(config->expect_cipher_no_aes) != cipher_id) {
+ fprintf(stderr, "Cipher ID was %04x, wanted %04x (no AES hardware)\n",
+ cipher_id, static_cast<uint16_t>(config->expect_cipher_no_aes));
+ return false;
+ }
+
+
+ if (!config->psk.empty()) {
+ if (SSL_get_peer_cert_chain(ssl) != nullptr) {
+ fprintf(stderr, "Received peer certificate on a PSK cipher.\n");
+ return false;
+ }
+ } else if (!config->is_server || config->require_any_client_certificate) {
+ if (SSL_get_peer_cert_chain(ssl) == nullptr) {
+ fprintf(stderr, "Received no peer certificate but expected one.\n");
+ return false;
+ }
+ }
+
+ if (!config->expect_peer_cert_file.empty()) {
+ bssl::UniquePtr<X509> expect_leaf;
+ bssl::UniquePtr<STACK_OF(X509)> expect_chain;
+ if (!LoadCertificate(&expect_leaf, &expect_chain,
+ config->expect_peer_cert_file)) {
+ return false;
+ }
+
+ // For historical reasons, clients report a chain with a leaf and servers
+ // without.
+ if (!config->is_server) {
+ if (!sk_X509_insert(expect_chain.get(), expect_leaf.get(), 0)) {
+ return false;
+ }
+ X509_up_ref(expect_leaf.get()); // sk_X509_push takes ownership.
+ }
+
+ bssl::UniquePtr<X509> leaf(SSL_get_peer_certificate(ssl));
+ STACK_OF(X509) *chain = SSL_get_peer_cert_chain(ssl);
+ if (X509_cmp(leaf.get(), expect_leaf.get()) != 0) {
+ fprintf(stderr, "Received a different leaf certificate than expected.\n");
+ return false;
+ }
+
+ if (sk_X509_num(chain) != sk_X509_num(expect_chain.get())) {
+ fprintf(stderr, "Received a chain of length %zu instead of %zu.\n",
+ sk_X509_num(chain), sk_X509_num(expect_chain.get()));
+ return false;
+ }
+
+ for (size_t i = 0; i < sk_X509_num(chain); i++) {
+ if (X509_cmp(sk_X509_value(chain, i),
+ sk_X509_value(expect_chain.get(), i)) != 0) {
+ fprintf(stderr, "Chain certificate %zu did not match.\n",
+ i + 1);
+ return false;
+ }
+ }
+ }
+
+ bool expected_sha256_client_cert = config->expect_sha256_client_cert_initial;
+ if (is_resume) {
+ expected_sha256_client_cert = config->expect_sha256_client_cert_resume;
+ }
+
+ if (SSL_get_session(ssl)->peer_sha256_valid != expected_sha256_client_cert) {
+ fprintf(stderr,
+ "Unexpected SHA-256 client cert state: expected:%d is_resume:%d.\n",
+ expected_sha256_client_cert, is_resume);
+ return false;
+ }
+
+ if (expected_sha256_client_cert &&
+ SSL_get_session(ssl)->certs != nullptr) {
+ fprintf(stderr, "Have both client cert and SHA-256 hash: is_resume:%d.\n",
+ is_resume);
+ return false;
+ }
+
+ if (is_resume && config->expect_ticket_age_skew != 0 &&
+ SSL_get_ticket_age_skew(ssl) != config->expect_ticket_age_skew) {
+ fprintf(stderr, "Ticket age skew was %" PRId32 ", wanted %d\n",
+ SSL_get_ticket_age_skew(ssl), config->expect_ticket_age_skew);
+ return false;
+ }
+
+ return true;
+}
+
+// DoExchange runs a test SSL exchange against the peer. On success, it returns
+// true and sets |*out_session| to the negotiated SSL session. If the test is a
+// resumption attempt, |is_resume| is true and |session| is the session from the
+// previous exchange.
+static bool DoExchange(bssl::UniquePtr<SSL_SESSION> *out_session,
+ SSL_CTX *ssl_ctx, const TestConfig *config,
+ bool is_resume, SSL_SESSION *session) {
+ bssl::UniquePtr<SSL> ssl(SSL_new(ssl_ctx));
+ if (!ssl) {
+ return false;
+ }
+
+ if (!SetTestConfig(ssl.get(), config) ||
+ !SetTestState(ssl.get(), std::unique_ptr<TestState>(new TestState))) {
+ return false;
+ }
+
+ if (config->fallback_scsv &&
+ !SSL_set_mode(ssl.get(), SSL_MODE_SEND_FALLBACK_SCSV)) {
+ return false;
+ }
+ // Install the certificate synchronously if nothing else will handle it.
+ if (!config->use_early_callback &&
+ !config->use_old_client_cert_callback &&
+ !config->async &&
+ !InstallCertificate(ssl.get())) {
+ return false;
+ }
+ if (!config->use_old_client_cert_callback) {
+ SSL_set_cert_cb(ssl.get(), CertCallback, nullptr);
+ }
+ if (config->require_any_client_certificate) {
+ SSL_set_verify(ssl.get(), SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
+ NULL);
+ }
+ if (config->verify_peer) {
+ SSL_set_verify(ssl.get(), SSL_VERIFY_PEER, NULL);
+ }
+ if (config->false_start) {
+ SSL_set_mode(ssl.get(), SSL_MODE_ENABLE_FALSE_START);
+ }
+ if (config->cbc_record_splitting) {
+ SSL_set_mode(ssl.get(), SSL_MODE_CBC_RECORD_SPLITTING);
+ }
+ if (config->partial_write) {
+ SSL_set_mode(ssl.get(), SSL_MODE_ENABLE_PARTIAL_WRITE);
+ }
+ if (config->no_tls13) {
+ SSL_set_options(ssl.get(), SSL_OP_NO_TLSv1_3);
+ }
+ if (config->no_tls12) {
+ SSL_set_options(ssl.get(), SSL_OP_NO_TLSv1_2);
+ }
+ if (config->no_tls11) {
+ SSL_set_options(ssl.get(), SSL_OP_NO_TLSv1_1);
+ }
+ if (config->no_tls1) {
+ SSL_set_options(ssl.get(), SSL_OP_NO_TLSv1);
+ }
+ if (config->no_ssl3) {
+ SSL_set_options(ssl.get(), SSL_OP_NO_SSLv3);
+ }
+ if (!config->expected_channel_id.empty() ||
+ config->enable_channel_id) {
+ SSL_set_tls_channel_id_enabled(ssl.get(), 1);
+ }
+ if (!config->send_channel_id.empty()) {
+ SSL_set_tls_channel_id_enabled(ssl.get(), 1);
+ if (!config->async) {
+ // The async case will be supplied by |ChannelIdCallback|.
+ bssl::UniquePtr<EVP_PKEY> pkey = LoadPrivateKey(config->send_channel_id);
+ if (!pkey || !SSL_set1_tls_channel_id(ssl.get(), pkey.get())) {
+ return false;
+ }
+ }
+ }
+ if (!config->host_name.empty() &&
+ !SSL_set_tlsext_host_name(ssl.get(), config->host_name.c_str())) {
+ return false;
+ }
+ if (!config->advertise_alpn.empty() &&
+ SSL_set_alpn_protos(ssl.get(),
+ (const uint8_t *)config->advertise_alpn.data(),
+ config->advertise_alpn.size()) != 0) {
+ return false;
+ }
+ if (!config->psk.empty()) {
+ SSL_set_psk_client_callback(ssl.get(), PskClientCallback);
+ SSL_set_psk_server_callback(ssl.get(), PskServerCallback);
+ }
+ if (!config->psk_identity.empty() &&
+ !SSL_use_psk_identity_hint(ssl.get(), config->psk_identity.c_str())) {
+ return false;
+ }
+ if (!config->srtp_profiles.empty() &&
+ !SSL_set_srtp_profiles(ssl.get(), config->srtp_profiles.c_str())) {
+ return false;
+ }
+ if (config->enable_ocsp_stapling) {
+ SSL_enable_ocsp_stapling(ssl.get());
+ }
+ if (config->enable_signed_cert_timestamps) {
+ SSL_enable_signed_cert_timestamps(ssl.get());
+ }
+ if (config->min_version != 0 &&
+ !SSL_set_min_proto_version(ssl.get(), (uint16_t)config->min_version)) {
+ return false;
+ }
+ if (config->max_version != 0 &&
+ !SSL_set_max_proto_version(ssl.get(), (uint16_t)config->max_version)) {
+ return false;
+ }
+ if (config->mtu != 0) {
+ SSL_set_options(ssl.get(), SSL_OP_NO_QUERY_MTU);
+ SSL_set_mtu(ssl.get(), config->mtu);
+ }
+ if (config->install_ddos_callback) {
+ SSL_CTX_set_dos_protection_cb(ssl_ctx, DDoSCallback);
+ }
+ if (config->renegotiate_once) {
+ SSL_set_renegotiate_mode(ssl.get(), ssl_renegotiate_once);
+ }
+ if (config->renegotiate_freely) {
+ SSL_set_renegotiate_mode(ssl.get(), ssl_renegotiate_freely);
+ }
+ if (config->renegotiate_ignore) {
+ SSL_set_renegotiate_mode(ssl.get(), ssl_renegotiate_ignore);
+ }
+ if (!config->check_close_notify) {
+ SSL_set_quiet_shutdown(ssl.get(), 1);
+ }
+ if (config->p384_only) {
+ int nid = NID_secp384r1;
+ if (!SSL_set1_curves(ssl.get(), &nid, 1)) {
+ return false;
+ }
+ }
+ if (config->enable_all_curves) {
+ static const int kAllCurves[] = {
+ NID_X9_62_prime256v1, NID_secp384r1, NID_secp521r1, NID_X25519,
+ };
+ if (!SSL_set1_curves(ssl.get(), kAllCurves,
+ OPENSSL_ARRAY_SIZE(kAllCurves))) {
+ return false;
+ }
+ }
+ if (config->initial_timeout_duration_ms > 0) {
+ DTLSv1_set_initial_timeout_duration(ssl.get(),
+ config->initial_timeout_duration_ms);
+ }
+ if (config->max_cert_list > 0) {
+ SSL_set_max_cert_list(ssl.get(), config->max_cert_list);
+ }
+ if (!is_resume && config->retain_only_sha256_client_cert_initial) {
+ SSL_set_retain_only_sha256_of_client_certs(ssl.get(), 1);
+ }
+ if (is_resume && config->retain_only_sha256_client_cert_resume) {
+ SSL_set_retain_only_sha256_of_client_certs(ssl.get(), 1);
+ }
+ if (config->max_send_fragment > 0) {
+ SSL_set_max_send_fragment(ssl.get(), config->max_send_fragment);
+ }
+
+ int sock = Connect(config->port);
+ if (sock == -1) {
+ return false;
+ }
+ SocketCloser closer(sock);
+
+ bssl::UniquePtr<BIO> bio(BIO_new_socket(sock, BIO_NOCLOSE));
+ if (!bio) {
+ return false;
+ }
+ if (config->is_dtls) {
+ bssl::UniquePtr<BIO> packeted = PacketedBioCreate(&g_clock);
+ if (!packeted) {
+ return false;
+ }
+ GetTestState(ssl.get())->packeted_bio = packeted.get();
+ BIO_push(packeted.get(), bio.release());
+ bio = std::move(packeted);
+ }
+ if (config->async) {
+ bssl::UniquePtr<BIO> async_scoped =
+ config->is_dtls ? AsyncBioCreateDatagram() : AsyncBioCreate();
+ if (!async_scoped) {
+ return false;
+ }
+ BIO_push(async_scoped.get(), bio.release());
+ GetTestState(ssl.get())->async_bio = async_scoped.get();
+ bio = std::move(async_scoped);
+ }
+ SSL_set_bio(ssl.get(), bio.get(), bio.get());
+ bio.release(); // SSL_set_bio takes ownership.
+
+ if (session != NULL) {
+ if (!config->is_server) {
+ if (SSL_set_session(ssl.get(), session) != 1) {
+ return false;
+ }
+ } else if (config->async) {
+ // The internal session cache is disabled, so install the session
+ // manually.
+ SSL_SESSION_up_ref(session);
+ GetTestState(ssl.get())->pending_session.reset(session);
+ }
+ }
+
+ if (SSL_get_current_cipher(ssl.get()) != nullptr) {
+ fprintf(stderr, "non-null cipher before handshake\n");
+ return false;
+ }
+
+ int ret;
+ if (config->implicit_handshake) {
+ if (config->is_server) {
+ SSL_set_accept_state(ssl.get());
+ } else {
+ SSL_set_connect_state(ssl.get());
+ }
+ } else {
+ do {
+ if (config->is_server) {
+ ret = SSL_accept(ssl.get());
+ } else {
+ ret = SSL_connect(ssl.get());
+ }
+ } while (config->async && RetryAsync(ssl.get(), ret));
+ if (ret != 1 ||
+ !CheckHandshakeProperties(ssl.get(), is_resume)) {
+ return false;
+ }
+
+ // Reset the state to assert later that the callback isn't called in
+ // renegotations.
+ GetTestState(ssl.get())->got_new_session = false;
+ }
+
+ if (config->export_keying_material > 0) {
+ std::vector<uint8_t> result(
+ static_cast<size_t>(config->export_keying_material));
+ if (!SSL_export_keying_material(
+ ssl.get(), result.data(), result.size(),
+ config->export_label.data(), config->export_label.size(),
+ reinterpret_cast<const uint8_t*>(config->export_context.data()),
+ config->export_context.size(), config->use_export_context)) {
+ fprintf(stderr, "failed to export keying material\n");
+ return false;
+ }
+ if (WriteAll(ssl.get(), result.data(), result.size()) < 0) {
+ return false;
+ }
+ }
+
+ if (config->tls_unique) {
+ uint8_t tls_unique[16];
+ size_t tls_unique_len;
+ if (!SSL_get_tls_unique(ssl.get(), tls_unique, &tls_unique_len,
+ sizeof(tls_unique))) {
+ fprintf(stderr, "failed to get tls-unique\n");
+ return false;
+ }
+
+ if (tls_unique_len != 12) {
+ fprintf(stderr, "expected 12 bytes of tls-unique but got %u",
+ static_cast<unsigned>(tls_unique_len));
+ return false;
+ }
+
+ if (WriteAll(ssl.get(), tls_unique, tls_unique_len) < 0) {
+ return false;
+ }
+ }
+
+ if (config->send_alert) {
+ if (DoSendFatalAlert(ssl.get(), SSL_AD_DECOMPRESSION_FAILURE) < 0) {
+ return false;
+ }
+ return true;
+ }
+
+ if (config->write_different_record_sizes) {
+ if (config->is_dtls) {
+ fprintf(stderr, "write_different_record_sizes not supported for DTLS\n");
+ return false;
+ }
+ // This mode writes a number of different record sizes in an attempt to
+ // trip up the CBC record splitting code.
+ static const size_t kBufLen = 32769;
+ std::unique_ptr<uint8_t[]> buf(new uint8_t[kBufLen]);
+ OPENSSL_memset(buf.get(), 0x42, kBufLen);
+ static const size_t kRecordSizes[] = {
+ 0, 1, 255, 256, 257, 16383, 16384, 16385, 32767, 32768, 32769};
+ for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kRecordSizes); i++) {
+ const size_t len = kRecordSizes[i];
+ if (len > kBufLen) {
+ fprintf(stderr, "Bad kRecordSizes value.\n");
+ return false;
+ }
+ if (WriteAll(ssl.get(), buf.get(), len) < 0) {
+ return false;
+ }
+ }
+ } else {
+ if (config->read_with_unfinished_write) {
+ if (!config->async) {
+ fprintf(stderr, "-read-with-unfinished-write requires -async.\n");
+ return false;
+ }
+
+ int write_ret = SSL_write(ssl.get(),
+ reinterpret_cast<const uint8_t *>("unfinished"), 10);
+ if (SSL_get_error(ssl.get(), write_ret) != SSL_ERROR_WANT_WRITE) {
+ fprintf(stderr, "Failed to leave unfinished write.\n");
+ return false;
+ }
+ }
+ if (config->shim_writes_first) {
+ if (WriteAll(ssl.get(), reinterpret_cast<const uint8_t *>("hello"),
+ 5) < 0) {
+ return false;
+ }
+ }
+ if (!config->shim_shuts_down) {
+ for (;;) {
+ // Read only 512 bytes at a time in TLS to ensure records may be
+ // returned in multiple reads.
+ size_t read_size = config->is_dtls ? 16384 : 512;
+ if (config->read_size > 0) {
+ read_size = config->read_size;
+ }
+ std::unique_ptr<uint8_t[]> buf(new uint8_t[read_size]);
+
+ int n = DoRead(ssl.get(), buf.get(), read_size);
+ int err = SSL_get_error(ssl.get(), n);
+ if (err == SSL_ERROR_ZERO_RETURN ||
+ (n == 0 && err == SSL_ERROR_SYSCALL)) {
+ if (n != 0) {
+ fprintf(stderr, "Invalid SSL_get_error output\n");
+ return false;
+ }
+ // Stop on either clean or unclean shutdown.
+ break;
+ } else if (err != SSL_ERROR_NONE) {
+ if (n > 0) {
+ fprintf(stderr, "Invalid SSL_get_error output\n");
+ return false;
+ }
+ return false;
+ }
+ // Successfully read data.
+ if (n <= 0) {
+ fprintf(stderr, "Invalid SSL_get_error output\n");
+ return false;
+ }
+
+ // After a successful read, with or without False Start, the handshake
+ // must be complete.
+ if (!GetTestState(ssl.get())->handshake_done) {
+ fprintf(stderr, "handshake was not completed after SSL_read\n");
+ return false;
+ }
+
+ for (int i = 0; i < n; i++) {
+ buf[i] ^= 0xff;
+ }
+ if (WriteAll(ssl.get(), buf.get(), n) < 0) {
+ return false;
+ }
+ }
+ }
+ }
+
+ if (!config->is_server && !config->false_start &&
+ !config->implicit_handshake &&
+ // Session tickets are sent post-handshake in TLS 1.3.
+ GetProtocolVersion(ssl.get()) < TLS1_3_VERSION &&
+ GetTestState(ssl.get())->got_new_session) {
+ fprintf(stderr, "new session was established after the handshake\n");
+ return false;
+ }
+
+ if (GetProtocolVersion(ssl.get()) >= TLS1_3_VERSION && !config->is_server) {
+ bool expect_new_session =
+ !config->expect_no_session && !config->shim_shuts_down;
+ if (expect_new_session != GetTestState(ssl.get())->got_new_session) {
+ fprintf(stderr,
+ "new session was%s cached, but we expected the opposite\n",
+ GetTestState(ssl.get())->got_new_session ? "" : " not");
+ return false;
+ }
+
+ if (expect_new_session) {
+ bool got_early_data_info =
+ GetTestState(ssl.get())->new_session->ticket_max_early_data != 0;
+ if (config->expect_early_data_info != got_early_data_info) {
+ fprintf(
+ stderr,
+ "new session did%s include ticket_early_data_info, but we expected "
+ "the opposite\n",
+ got_early_data_info ? "" : " not");
+ return false;
+ }
+ }
+ }
+
+ if (out_session) {
+ *out_session = std::move(GetTestState(ssl.get())->new_session);
+ }
+
+ ret = DoShutdown(ssl.get());
+
+ if (config->shim_shuts_down && config->check_close_notify) {
+ // We initiate shutdown, so |SSL_shutdown| will return in two stages. First
+ // it returns zero when our close_notify is sent, then one when the peer's
+ // is received.
+ if (ret != 0) {
+ fprintf(stderr, "Unexpected SSL_shutdown result: %d != 0\n", ret);
+ return false;
+ }
+ ret = DoShutdown(ssl.get());
+ }
+
+ if (ret != 1) {
+ fprintf(stderr, "Unexpected SSL_shutdown result: %d != 1\n", ret);
+ return false;
+ }
+
+ if (SSL_total_renegotiations(ssl.get()) !=
+ config->expect_total_renegotiations) {
+ fprintf(stderr, "Expected %d renegotiations, got %d\n",
+ config->expect_total_renegotiations,
+ SSL_total_renegotiations(ssl.get()));
+ return false;
+ }
+
+ return true;
+}
+
+class StderrDelimiter {
+ public:
+ ~StderrDelimiter() { fprintf(stderr, "--- DONE ---\n"); }
+};
+
+int main(int argc, char **argv) {
+ // To distinguish ASan's output from ours, add a trailing message to stderr.
+ // Anything following this line will be considered an error.
+ StderrDelimiter delimiter;
+
+#if defined(OPENSSL_WINDOWS)
+ /* Initialize Winsock. */
+ WORD wsa_version = MAKEWORD(2, 2);
+ WSADATA wsa_data;
+ int wsa_err = WSAStartup(wsa_version, &wsa_data);
+ if (wsa_err != 0) {
+ fprintf(stderr, "WSAStartup failed: %d\n", wsa_err);
+ return 1;
+ }
+ if (wsa_data.wVersion != wsa_version) {
+ fprintf(stderr, "Didn't get expected version: %x\n", wsa_data.wVersion);
+ return 1;
+ }
+#else
+ signal(SIGPIPE, SIG_IGN);
+#endif
+
+ CRYPTO_library_init();
+ g_config_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
+ g_state_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, TestStateExFree);
+ if (g_config_index < 0 || g_state_index < 0) {
+ return 1;
+ }
+
+ TestConfig config;
+ if (!ParseConfig(argc - 1, argv + 1, &config)) {
+ return Usage(argv[0]);
+ }
+
+ g_pool = CRYPTO_BUFFER_POOL_new();
+
+ // Some code treats the zero time special, so initialize the clock to a
+ // non-zero time.
+ g_clock.tv_sec = 1234;
+ g_clock.tv_usec = 1234;
+
+ bssl::UniquePtr<SSL_CTX> ssl_ctx = SetupCtx(&config);
+ if (!ssl_ctx) {
+ ERR_print_errors_fp(stderr);
+ return 1;
+ }
+
+ bssl::UniquePtr<SSL_SESSION> session;
+ for (int i = 0; i < config.resume_count + 1; i++) {
+ bool is_resume = i > 0;
+ if (is_resume && !config.is_server && !session) {
+ fprintf(stderr, "No session to offer.\n");
+ return 1;
+ }
+
+ bssl::UniquePtr<SSL_SESSION> offer_session = std::move(session);
+ if (!DoExchange(&session, ssl_ctx.get(), &config, is_resume,
+ offer_session.get())) {
+ fprintf(stderr, "Connection %d failed.\n", i + 1);
+ ERR_print_errors_fp(stderr);
+ return 1;
+ }
+
+ if (config.resumption_delay != 0) {
+ g_clock.tv_sec += config.resumption_delay;
+ }
+ }
+
+ return 0;
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/packeted_bio.cc b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/packeted_bio.cc
new file mode 100644
index 000000000..835dbfb1f
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/packeted_bio.cc
@@ -0,0 +1,265 @@
+/* Copyright (c) 2014, 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 "packeted_bio.h"
+
+#include <assert.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <openssl/mem.h>
+
+#include "../../crypto/internal.h"
+
+
+namespace {
+
+extern const BIO_METHOD g_packeted_bio_method;
+
+const uint8_t kOpcodePacket = 'P';
+const uint8_t kOpcodeTimeout = 'T';
+const uint8_t kOpcodeTimeoutAck = 't';
+
+struct PacketedBio {
+ explicit PacketedBio(timeval *clock_arg)
+ : clock(clock_arg) {
+ OPENSSL_memset(&timeout, 0, sizeof(timeout));
+ }
+
+ bool HasTimeout() const {
+ return timeout.tv_sec != 0 || timeout.tv_usec != 0;
+ }
+
+ timeval timeout;
+ timeval *clock;
+};
+
+PacketedBio *GetData(BIO *bio) {
+ if (bio->method != &g_packeted_bio_method) {
+ return NULL;
+ }
+ return (PacketedBio *)bio->ptr;
+}
+
+// ReadAll reads |len| bytes from |bio| into |out|. It returns 1 on success and
+// 0 or -1 on error.
+static int ReadAll(BIO *bio, uint8_t *out, size_t len) {
+ while (len > 0) {
+ int chunk_len = INT_MAX;
+ if (len <= INT_MAX) {
+ chunk_len = (int)len;
+ }
+ int ret = BIO_read(bio, out, chunk_len);
+ if (ret <= 0) {
+ return ret;
+ }
+ out += ret;
+ len -= ret;
+ }
+ return 1;
+}
+
+static int PacketedWrite(BIO *bio, const char *in, int inl) {
+ if (bio->next_bio == NULL) {
+ return 0;
+ }
+
+ BIO_clear_retry_flags(bio);
+
+ // Write the header.
+ uint8_t header[5];
+ header[0] = kOpcodePacket;
+ header[1] = (inl >> 24) & 0xff;
+ header[2] = (inl >> 16) & 0xff;
+ header[3] = (inl >> 8) & 0xff;
+ header[4] = inl & 0xff;
+ int ret = BIO_write(bio->next_bio, header, sizeof(header));
+ if (ret <= 0) {
+ BIO_copy_next_retry(bio);
+ return ret;
+ }
+
+ // Write the buffer.
+ ret = BIO_write(bio->next_bio, in, inl);
+ if (ret < 0 || (inl > 0 && ret == 0)) {
+ BIO_copy_next_retry(bio);
+ return ret;
+ }
+ assert(ret == inl);
+ return ret;
+}
+
+static int PacketedRead(BIO *bio, char *out, int outl) {
+ PacketedBio *data = GetData(bio);
+ if (bio->next_bio == NULL) {
+ return 0;
+ }
+
+ BIO_clear_retry_flags(bio);
+
+ // Read the opcode.
+ uint8_t opcode;
+ int ret = ReadAll(bio->next_bio, &opcode, sizeof(opcode));
+ if (ret <= 0) {
+ BIO_copy_next_retry(bio);
+ return ret;
+ }
+
+ if (opcode == kOpcodeTimeout) {
+ // The caller is required to advance any pending timeouts before continuing.
+ if (data->HasTimeout()) {
+ fprintf(stderr, "Unprocessed timeout!\n");
+ return -1;
+ }
+
+ // Process the timeout.
+ uint8_t buf[8];
+ ret = ReadAll(bio->next_bio, buf, sizeof(buf));
+ if (ret <= 0) {
+ BIO_copy_next_retry(bio);
+ return ret;
+ }
+ uint64_t timeout = (static_cast<uint64_t>(buf[0]) << 56) |
+ (static_cast<uint64_t>(buf[1]) << 48) |
+ (static_cast<uint64_t>(buf[2]) << 40) |
+ (static_cast<uint64_t>(buf[3]) << 32) |
+ (static_cast<uint64_t>(buf[4]) << 24) |
+ (static_cast<uint64_t>(buf[5]) << 16) |
+ (static_cast<uint64_t>(buf[6]) << 8) |
+ static_cast<uint64_t>(buf[7]);
+ timeout /= 1000; // Convert nanoseconds to microseconds.
+
+ data->timeout.tv_usec = timeout % 1000000;
+ data->timeout.tv_sec = timeout / 1000000;
+
+ // Send an ACK to the peer.
+ ret = BIO_write(bio->next_bio, &kOpcodeTimeoutAck, 1);
+ if (ret <= 0) {
+ return ret;
+ }
+ assert(ret == 1);
+
+ // Signal to the caller to retry the read, after advancing the clock.
+ BIO_set_retry_read(bio);
+ return -1;
+ }
+
+ if (opcode != kOpcodePacket) {
+ fprintf(stderr, "Unknown opcode, %u\n", opcode);
+ return -1;
+ }
+
+ // Read the length prefix.
+ uint8_t len_bytes[4];
+ ret = ReadAll(bio->next_bio, len_bytes, sizeof(len_bytes));
+ if (ret <= 0) {
+ BIO_copy_next_retry(bio);
+ return ret;
+ }
+
+ uint32_t len = (len_bytes[0] << 24) | (len_bytes[1] << 16) |
+ (len_bytes[2] << 8) | len_bytes[3];
+ uint8_t *buf = (uint8_t *)OPENSSL_malloc(len);
+ if (buf == NULL) {
+ return -1;
+ }
+ ret = ReadAll(bio->next_bio, buf, len);
+ if (ret <= 0) {
+ fprintf(stderr, "Packeted BIO was truncated\n");
+ return -1;
+ }
+
+ if (outl > (int)len) {
+ outl = len;
+ }
+ OPENSSL_memcpy(out, buf, outl);
+ OPENSSL_free(buf);
+ return outl;
+}
+
+static long PacketedCtrl(BIO *bio, int cmd, long num, void *ptr) {
+ if (bio->next_bio == NULL) {
+ return 0;
+ }
+
+ BIO_clear_retry_flags(bio);
+ int ret = BIO_ctrl(bio->next_bio, cmd, num, ptr);
+ BIO_copy_next_retry(bio);
+ return ret;
+}
+
+static int PacketedNew(BIO *bio) {
+ bio->init = 1;
+ return 1;
+}
+
+static int PacketedFree(BIO *bio) {
+ if (bio == NULL) {
+ return 0;
+ }
+
+ delete GetData(bio);
+ bio->init = 0;
+ return 1;
+}
+
+static long PacketedCallbackCtrl(BIO *bio, int cmd, bio_info_cb fp) {
+ if (bio->next_bio == NULL) {
+ return 0;
+ }
+ return BIO_callback_ctrl(bio->next_bio, cmd, fp);
+}
+
+const BIO_METHOD g_packeted_bio_method = {
+ BIO_TYPE_FILTER,
+ "packeted bio",
+ PacketedWrite,
+ PacketedRead,
+ NULL /* puts */,
+ NULL /* gets */,
+ PacketedCtrl,
+ PacketedNew,
+ PacketedFree,
+ PacketedCallbackCtrl,
+};
+
+} // namespace
+
+bssl::UniquePtr<BIO> PacketedBioCreate(timeval *clock) {
+ bssl::UniquePtr<BIO> bio(BIO_new(&g_packeted_bio_method));
+ if (!bio) {
+ return nullptr;
+ }
+ bio->ptr = new PacketedBio(clock);
+ return bio;
+}
+
+bool PacketedBioAdvanceClock(BIO *bio) {
+ PacketedBio *data = GetData(bio);
+ if (data == nullptr) {
+ return false;
+ }
+
+ if (!data->HasTimeout()) {
+ return false;
+ }
+
+ data->clock->tv_usec += data->timeout.tv_usec;
+ data->clock->tv_sec += data->clock->tv_usec / 1000000;
+ data->clock->tv_usec %= 1000000;
+ data->clock->tv_sec += data->timeout.tv_sec;
+ OPENSSL_memset(&data->timeout, 0, sizeof(data->timeout));
+ return true;
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/packeted_bio.h b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/packeted_bio.h
new file mode 100644
index 000000000..7f07fcbf0
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/packeted_bio.h
@@ -0,0 +1,43 @@
+/* Copyright (c) 2014, 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 HEADER_PACKETED_BIO
+#define HEADER_PACKETED_BIO
+
+#include <openssl/base.h>
+#include <openssl/bio.h>
+
+#if defined(OPENSSL_WINDOWS)
+OPENSSL_MSVC_PRAGMA(warning(push, 3))
+#include <winsock2.h>
+OPENSSL_MSVC_PRAGMA(warning(pop))
+#else
+#include <sys/time.h>
+#endif
+
+
+// PacketedBioCreate creates a filter BIO which implements a reliable in-order
+// blocking datagram socket. It uses the value of |*clock| as the clock.
+//
+// During a |BIO_read|, the peer may signal the filter BIO to simulate a
+// timeout. The operation will fail immediately. The caller must then call
+// |PacketedBioAdvanceClock| before retrying |BIO_read|.
+bssl::UniquePtr<BIO> PacketedBioCreate(timeval *clock);
+
+// PacketedBioAdvanceClock advances |bio|'s clock and returns true if there is a
+// pending timeout. Otherwise, it returns false.
+bool PacketedBioAdvanceClock(BIO *bio);
+
+
+#endif // HEADER_PACKETED_BIO
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/alert.go b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/alert.go
new file mode 100644
index 000000000..652e9eec7
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/alert.go
@@ -0,0 +1,93 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runner
+
+import "strconv"
+
+type alert uint8
+
+const (
+ // alert level
+ alertLevelWarning = 1
+ alertLevelError = 2
+)
+
+const (
+ alertCloseNotify alert = 0
+ alertEndOfEarlyData alert = 1
+ alertUnexpectedMessage alert = 10
+ alertBadRecordMAC alert = 20
+ alertDecryptionFailed alert = 21
+ alertRecordOverflow alert = 22
+ alertDecompressionFailure alert = 30
+ alertHandshakeFailure alert = 40
+ alertNoCertificate alert = 41
+ alertBadCertificate alert = 42
+ alertUnsupportedCertificate alert = 43
+ alertCertificateRevoked alert = 44
+ alertCertificateExpired alert = 45
+ alertCertificateUnknown alert = 46
+ alertIllegalParameter alert = 47
+ alertUnknownCA alert = 48
+ alertAccessDenied alert = 49
+ alertDecodeError alert = 50
+ alertDecryptError alert = 51
+ alertProtocolVersion alert = 70
+ alertInsufficientSecurity alert = 71
+ alertInternalError alert = 80
+ alertInappropriateFallback alert = 86
+ alertUserCanceled alert = 90
+ alertNoRenegotiation alert = 100
+ alertMissingExtension alert = 109
+ alertUnsupportedExtension alert = 110
+ alertUnrecognizedName alert = 112
+ alertUnknownPSKIdentity alert = 115
+ alertCertificateRequired alert = 116
+)
+
+var alertText = map[alert]string{
+ alertCloseNotify: "close notify",
+ alertEndOfEarlyData: "end of early data",
+ alertUnexpectedMessage: "unexpected message",
+ alertBadRecordMAC: "bad record MAC",
+ alertDecryptionFailed: "decryption failed",
+ alertRecordOverflow: "record overflow",
+ alertDecompressionFailure: "decompression failure",
+ alertHandshakeFailure: "handshake failure",
+ alertNoCertificate: "no certificate",
+ alertBadCertificate: "bad certificate",
+ alertUnsupportedCertificate: "unsupported certificate",
+ alertCertificateRevoked: "revoked certificate",
+ alertCertificateExpired: "expired certificate",
+ alertCertificateUnknown: "unknown certificate",
+ alertIllegalParameter: "illegal parameter",
+ alertUnknownCA: "unknown certificate authority",
+ alertAccessDenied: "access denied",
+ alertDecodeError: "error decoding message",
+ alertDecryptError: "error decrypting message",
+ alertProtocolVersion: "protocol version not supported",
+ alertInsufficientSecurity: "insufficient security level",
+ alertInternalError: "internal error",
+ alertInappropriateFallback: "inappropriate fallback",
+ alertUserCanceled: "user canceled",
+ alertNoRenegotiation: "no renegotiation",
+ alertMissingExtension: "missing extension",
+ alertUnsupportedExtension: "unsupported extension",
+ alertUnrecognizedName: "unrecognized name",
+ alertUnknownPSKIdentity: "unknown PSK identity",
+ alertCertificateRequired: "certificate required",
+}
+
+func (e alert) String() string {
+ s, ok := alertText[e]
+ if ok {
+ return s
+ }
+ return "alert(" + strconv.Itoa(int(e)) + ")"
+}
+
+func (e alert) Error() string {
+ return e.String()
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/cert.pem b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/cert.pem
new file mode 100644
index 000000000..c360dc731
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/cert.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDtTCCAp2gAwIBAgIJALW2IrlaBKUhMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
+BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX
+aWRnaXRzIFB0eSBMdGQwHhcNMTYwNzA5MDQzODA5WhcNMTYwODA4MDQzODA5WjBF
+MQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50
+ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEAugvahBkSAUF1fC49vb1bvlPrcl80kop1iLpiuYoz4Qptwy57+EWssZBc
+HprZ5BkWf6PeGZ7F5AX1PyJbGHZLqvMCvViP6pd4MFox/igESISEHEixoiXCzepB
+rhtp5UQSjHD4D4hKtgdMgVxX+LRtwgW3mnu/vBu7rzpr/DS8io99p3lqZ1Aky+aN
+lcMj6MYy8U+YFEevb/V0lRY9oqwmW7BHnXikm/vi6sjIS350U8zb/mRzYeIs2R65
+LUduTL50+UMgat9ocewI2dv8aO9Dph+8NdGtg8LFYyTTHcUxJoMr1PTOgnmET19W
+JH4PrFwk7ZE1QJQQ1L4iKmPeQistuQIDAQABo4GnMIGkMB0GA1UdDgQWBBT5m6Vv
+zYjVYHG30iBE+j2XDhUE8jB1BgNVHSMEbjBsgBT5m6VvzYjVYHG30iBE+j2XDhUE
+8qFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNV
+BAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJALW2IrlaBKUhMAwGA1UdEwQF
+MAMBAf8wDQYJKoZIhvcNAQELBQADggEBAD7Jg68SArYWlcoHfZAB90Pmyrt5H6D8
+LRi+W2Ri1fBNxREELnezWJ2scjl4UMcsKYp4Pi950gVN+62IgrImcCNvtb5I1Cfy
+/MNNur9ffas6X334D0hYVIQTePyFk3umI+2mJQrtZZyMPIKSY/sYGQHhGGX6wGK+
+GO/og0PQk/Vu6D+GU2XRnDV0YZg1lsAsHd21XryK6fDmNkEMwbIWrts4xc7scRrG
+HWy+iMf6/7p/Ak/SIicM4XSwmlQ8pPxAZPr+E2LoVd9pMpWUwpW2UbtO5wsGTrY5
+sO45tFNN/y+jtUheB1C2ijObG/tXELaiyCdM+S/waeuv0MXtI4xnn1A=
+-----END CERTIFICATE-----
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/chacha20_poly1305.go b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/chacha20_poly1305.go
new file mode 100644
index 000000000..866f72421
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/chacha20_poly1305.go
@@ -0,0 +1,194 @@
+// Copyright (c) 2016, 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 runner
+
+import (
+ "crypto/cipher"
+ "crypto/subtle"
+ "encoding/binary"
+ "errors"
+
+ "./poly1305"
+)
+
+// See RFC 7539.
+
+func leftRotate(a uint32, n uint) uint32 {
+ return (a << n) | (a >> (32 - n))
+}
+
+func chaChaQuarterRound(state *[16]uint32, a, b, c, d int) {
+ state[a] += state[b]
+ state[d] = leftRotate(state[d]^state[a], 16)
+
+ state[c] += state[d]
+ state[b] = leftRotate(state[b]^state[c], 12)
+
+ state[a] += state[b]
+ state[d] = leftRotate(state[d]^state[a], 8)
+
+ state[c] += state[d]
+ state[b] = leftRotate(state[b]^state[c], 7)
+}
+
+func chaCha20Block(state *[16]uint32, out []byte) {
+ var workingState [16]uint32
+ copy(workingState[:], state[:])
+ for i := 0; i < 10; i++ {
+ chaChaQuarterRound(&workingState, 0, 4, 8, 12)
+ chaChaQuarterRound(&workingState, 1, 5, 9, 13)
+ chaChaQuarterRound(&workingState, 2, 6, 10, 14)
+ chaChaQuarterRound(&workingState, 3, 7, 11, 15)
+ chaChaQuarterRound(&workingState, 0, 5, 10, 15)
+ chaChaQuarterRound(&workingState, 1, 6, 11, 12)
+ chaChaQuarterRound(&workingState, 2, 7, 8, 13)
+ chaChaQuarterRound(&workingState, 3, 4, 9, 14)
+ }
+ for i := 0; i < 16; i++ {
+ binary.LittleEndian.PutUint32(out[i*4:i*4+4], workingState[i]+state[i])
+ }
+}
+
+// sliceForAppend takes a slice and a requested number of bytes. It returns a
+// slice with the contents of the given slice followed by that many bytes and a
+// second slice that aliases into it and contains only the extra bytes. If the
+// original slice has sufficient capacity then no allocation is performed.
+func sliceForAppend(in []byte, n int) (head, tail []byte) {
+ if total := len(in) + n; cap(in) >= total {
+ head = in[:total]
+ } else {
+ head = make([]byte, total)
+ copy(head, in)
+ }
+ tail = head[len(in):]
+ return
+}
+
+func chaCha20(out, in, key, nonce []byte, counter uint64) {
+ var state [16]uint32
+ state[0] = 0x61707865
+ state[1] = 0x3320646e
+ state[2] = 0x79622d32
+ state[3] = 0x6b206574
+ for i := 0; i < 8; i++ {
+ state[4+i] = binary.LittleEndian.Uint32(key[i*4 : i*4+4])
+ }
+
+ switch len(nonce) {
+ case 8:
+ state[14] = binary.LittleEndian.Uint32(nonce[0:4])
+ state[15] = binary.LittleEndian.Uint32(nonce[4:8])
+ case 12:
+ state[13] = binary.LittleEndian.Uint32(nonce[0:4])
+ state[14] = binary.LittleEndian.Uint32(nonce[4:8])
+ state[15] = binary.LittleEndian.Uint32(nonce[8:12])
+ default:
+ panic("bad nonce length")
+ }
+
+ for i := 0; i < len(in); i += 64 {
+ state[12] = uint32(counter)
+
+ var tmp [64]byte
+ chaCha20Block(&state, tmp[:])
+ count := 64
+ if len(in)-i < count {
+ count = len(in) - i
+ }
+ for j := 0; j < count; j++ {
+ out[i+j] = in[i+j] ^ tmp[j]
+ }
+
+ counter++
+ }
+}
+
+// chaCha20Poly1305 implements the AEAD from
+// RFC 7539 and draft-agl-tls-chacha20poly1305-04.
+type chaCha20Poly1305 struct {
+ key [32]byte
+}
+
+func newChaCha20Poly1305(key []byte) (cipher.AEAD, error) {
+ if len(key) != 32 {
+ return nil, errors.New("bad key length")
+ }
+ aead := new(chaCha20Poly1305)
+ copy(aead.key[:], key)
+ return aead, nil
+}
+
+func (c *chaCha20Poly1305) NonceSize() int {
+ return 12
+}
+
+func (c *chaCha20Poly1305) Overhead() int { return 16 }
+
+func (c *chaCha20Poly1305) poly1305(tag *[16]byte, nonce, ciphertext, additionalData []byte) {
+ input := make([]byte, 0, len(additionalData)+15+len(ciphertext)+15+8+8)
+ input = append(input, additionalData...)
+ var zeros [15]byte
+ if pad := len(input) % 16; pad != 0 {
+ input = append(input, zeros[:16-pad]...)
+ }
+ input = append(input, ciphertext...)
+ if pad := len(input) % 16; pad != 0 {
+ input = append(input, zeros[:16-pad]...)
+ }
+ input, out := sliceForAppend(input, 8)
+ binary.LittleEndian.PutUint64(out, uint64(len(additionalData)))
+ input, out = sliceForAppend(input, 8)
+ binary.LittleEndian.PutUint64(out, uint64(len(ciphertext)))
+
+ var poly1305Key [32]byte
+ chaCha20(poly1305Key[:], poly1305Key[:], c.key[:], nonce, 0)
+
+ poly1305.Sum(tag, input, &poly1305Key)
+}
+
+func (c *chaCha20Poly1305) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
+ if len(nonce) != c.NonceSize() {
+ panic("Bad nonce length")
+ }
+
+ ret, out := sliceForAppend(dst, len(plaintext)+16)
+ chaCha20(out[:len(plaintext)], plaintext, c.key[:], nonce, 1)
+
+ var tag [16]byte
+ c.poly1305(&tag, nonce, out[:len(plaintext)], additionalData)
+ copy(out[len(plaintext):], tag[:])
+
+ return ret
+}
+
+func (c *chaCha20Poly1305) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
+ if len(nonce) != c.NonceSize() {
+ panic("Bad nonce length")
+ }
+ if len(ciphertext) < 16 {
+ return nil, errors.New("chacha20: message authentication failed")
+ }
+ plaintextLen := len(ciphertext) - 16
+
+ var tag [16]byte
+ c.poly1305(&tag, nonce, ciphertext[:plaintextLen], additionalData)
+ if subtle.ConstantTimeCompare(tag[:], ciphertext[plaintextLen:]) != 1 {
+ return nil, errors.New("chacha20: message authentication failed")
+ }
+
+ ret, out := sliceForAppend(dst, plaintextLen)
+ chaCha20(out, ciphertext[:plaintextLen], c.key[:], nonce, 1)
+ return ret, nil
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/chacha20_poly1305_test.go b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/chacha20_poly1305_test.go
new file mode 100644
index 000000000..38c4b70fb
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/chacha20_poly1305_test.go
@@ -0,0 +1,144 @@
+// Copyright (c) 2016, 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 runner
+
+import (
+ "bytes"
+ "encoding/hex"
+ "testing"
+)
+
+// See RFC 7539, section 2.1.1.
+func TestChaChaQuarterRound(t *testing.T) {
+ state := [16]uint32{0x11111111, 0x01020304, 0x9b8d6f43, 0x01234567}
+ chaChaQuarterRound(&state, 0, 1, 2, 3)
+
+ a, b, c, d := state[0], state[1], state[2], state[3]
+ if a != 0xea2a92f4 || b != 0xcb1cf8ce || c != 0x4581472e || d != 0x5881c4bb {
+ t.Errorf("Incorrect results: %x", state)
+ }
+}
+
+// See RFC 7539, section 2.2.1.
+func TestChaChaQuarterRoundState(t *testing.T) {
+ state := [16]uint32{
+ 0x879531e0, 0xc5ecf37d, 0x516461b1, 0xc9a62f8a,
+ 0x44c20ef3, 0x3390af7f, 0xd9fc690b, 0x2a5f714c,
+ 0x53372767, 0xb00a5631, 0x974c541a, 0x359e9963,
+ 0x5c971061, 0x3d631689, 0x2098d9d6, 0x91dbd320,
+ }
+ chaChaQuarterRound(&state, 2, 7, 8, 13)
+
+ expected := [16]uint32{
+ 0x879531e0, 0xc5ecf37d, 0xbdb886dc, 0xc9a62f8a,
+ 0x44c20ef3, 0x3390af7f, 0xd9fc690b, 0xcfacafd2,
+ 0xe46bea80, 0xb00a5631, 0x974c541a, 0x359e9963,
+ 0x5c971061, 0xccc07c79, 0x2098d9d6, 0x91dbd320,
+ }
+ for i := range state {
+ if state[i] != expected[i] {
+ t.Errorf("Mismatch at %d: %x vs %x", i, state, expected)
+ }
+ }
+}
+
+// See RFC 7539, section 2.3.2.
+func TestChaCha20Block(t *testing.T) {
+ state := [16]uint32{
+ 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574,
+ 0x03020100, 0x07060504, 0x0b0a0908, 0x0f0e0d0c,
+ 0x13121110, 0x17161514, 0x1b1a1918, 0x1f1e1d1c,
+ 0x00000001, 0x09000000, 0x4a000000, 0x00000000,
+ }
+ out := make([]byte, 64)
+ chaCha20Block(&state, out)
+
+ expected := []byte{
+ 0x10, 0xf1, 0xe7, 0xe4, 0xd1, 0x3b, 0x59, 0x15,
+ 0x50, 0x0f, 0xdd, 0x1f, 0xa3, 0x20, 0x71, 0xc4,
+ 0xc7, 0xd1, 0xf4, 0xc7, 0x33, 0xc0, 0x68, 0x03,
+ 0x04, 0x22, 0xaa, 0x9a, 0xc3, 0xd4, 0x6c, 0x4e,
+ 0xd2, 0x82, 0x64, 0x46, 0x07, 0x9f, 0xaa, 0x09,
+ 0x14, 0xc2, 0xd7, 0x05, 0xd9, 0x8b, 0x02, 0xa2,
+ 0xb5, 0x12, 0x9c, 0xd1, 0xde, 0x16, 0x4e, 0xb9,
+ 0xcb, 0xd0, 0x83, 0xe8, 0xa2, 0x50, 0x3c, 0x4e,
+ }
+ if !bytes.Equal(out, expected) {
+ t.Errorf("Got %x, wanted %x", out, expected)
+ }
+}
+
+func decodeHexOrPanic(in string) []byte {
+ out, err := hex.DecodeString(in)
+ if err != nil {
+ panic(err)
+ }
+ return out
+}
+
+var chaCha20Poly1305TestVectors = []struct {
+ key, input, nonce, ad, output string
+}{
+ {
+ // See RFC 7539, section 2.8.2.
+ key: "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f",
+ input: "4c616469657320616e642047656e746c656d656e206f662074686520636c617373206f66202739393a204966204920636f756c64206f6666657220796f75206f6e6c79206f6e652074697020666f7220746865206675747572652c2073756e73637265656e20776f756c642062652069742e",
+ nonce: "070000004041424344454647",
+ ad: "50515253c0c1c2c3c4c5c6c7",
+ output: "d31a8d34648e60db7b86afbc53ef7ec2a4aded51296e08fea9e2b5a736ee62d63dbea45e8ca9671282fafb69da92728b1a71de0a9e060b2905d6a5b67ecd3b3692ddbd7f2d778b8c9803aee328091b58fab324e4fad675945585808b4831d7bc3ff4def08e4b7a9de576d26586cec64b61161ae10b594f09e26a7e902ecbd0600691",
+ },
+ {
+ // See RFC 7539, section A.5.
+ key: "1c9240a5eb55d38af333888604f6b5f0473917c1402b80099dca5cbc207075c0",
+ input: "496e7465726e65742d4472616674732061726520647261667420646f63756d656e74732076616c696420666f722061206d6178696d756d206f6620736978206d6f6e74687320616e64206d617920626520757064617465642c207265706c616365642c206f72206f62736f6c65746564206279206f7468657220646f63756d656e747320617420616e792074696d652e20497420697320696e617070726f70726961746520746f2075736520496e7465726e65742d447261667473206173207265666572656e6365206d6174657269616c206f7220746f2063697465207468656d206f74686572207468616e206173202fe2809c776f726b20696e2070726f67726573732e2fe2809d",
+ nonce: "000000000102030405060708",
+ ad: "f33388860000000000004e91",
+ output: "64a0861575861af460f062c79be643bd5e805cfd345cf389f108670ac76c8cb24c6cfc18755d43eea09ee94e382d26b0bdb7b73c321b0100d4f03b7f355894cf332f830e710b97ce98c8a84abd0b948114ad176e008d33bd60f982b1ff37c8559797a06ef4f0ef61c186324e2b3506383606907b6a7c02b0f9f6157b53c867e4b9166c767b804d46a59b5216cde7a4e99040c5a40433225ee282a1b0a06c523eaf4534d7f83fa1155b0047718cbc546a0d072b04b3564eea1b422273f548271a0bb2316053fa76991955ebd63159434ecebb4e466dae5a1073a6727627097a1049e617d91d361094fa68f0ff77987130305beaba2eda04df997b714d6c6f2c29a6ad5cb4022b02709beead9d67890cbb22392336fea1851f38",
+ },
+}
+
+// See draft-agl-tls-chacha20poly1305-04, section 7.
+func TestChaCha20Poly1305(t *testing.T) {
+ for i, tt := range chaCha20Poly1305TestVectors {
+ key := decodeHexOrPanic(tt.key)
+ input := decodeHexOrPanic(tt.input)
+ nonce := decodeHexOrPanic(tt.nonce)
+ ad := decodeHexOrPanic(tt.ad)
+ output := decodeHexOrPanic(tt.output)
+
+ aead, err := newChaCha20Poly1305(key)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ out, err := aead.Open(nil, nonce, output, ad)
+ if err != nil {
+ t.Errorf("%d. Open failed: %s", i, err)
+ } else if !bytes.Equal(out, input) {
+ t.Errorf("%d. Open gave %x, wanted %x", i, out, input)
+ }
+
+ out = aead.Seal(nil, nonce, input, ad)
+ if !bytes.Equal(out, output) {
+ t.Errorf("%d. Open gave %x, wanted %x", i, out, output)
+ }
+
+ out[0]++
+ _, err = aead.Open(nil, nonce, out, ad)
+ if err == nil {
+ t.Errorf("%d. Open on malformed data unexpectedly succeeded", i)
+ }
+ }
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/channel_id_key.pem b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/channel_id_key.pem
new file mode 100644
index 000000000..604752bcd
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/channel_id_key.pem
@@ -0,0 +1,5 @@
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIPwxu50c7LEhVNRYJFRWBUnoaz7JSos96T5hBp4rjyptoAoGCCqGSM49
+AwEHoUQDQgAEzFSVTE5guxJRQ0VbZ8dicPs5e/DT7xpW7Yc9hq0VOchv7cbXuI/T
+CwadDjGWX/oaz0ftFqrVmfkwZu+C58ioWg==
+-----END EC PRIVATE KEY-----
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/cipher_suites.go b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/cipher_suites.go
new file mode 100644
index 000000000..a2c6fbfcc
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/cipher_suites.go
@@ -0,0 +1,515 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runner
+
+import (
+ "crypto"
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/des"
+ "crypto/hmac"
+ "crypto/md5"
+ "crypto/rc4"
+ "crypto/sha1"
+ "crypto/sha256"
+ "crypto/sha512"
+ "crypto/x509"
+ "hash"
+)
+
+// a keyAgreement implements the client and server side of a TLS key agreement
+// protocol by generating and processing key exchange messages.
+type keyAgreement interface {
+ // On the server side, the first two methods are called in order.
+
+ // In the case that the key agreement protocol doesn't use a
+ // ServerKeyExchange message, generateServerKeyExchange can return nil,
+ // nil.
+ generateServerKeyExchange(*Config, *Certificate, *clientHelloMsg, *serverHelloMsg) (*serverKeyExchangeMsg, error)
+ processClientKeyExchange(*Config, *Certificate, *clientKeyExchangeMsg, uint16) ([]byte, error)
+
+ // On the client side, the next two methods are called in order.
+
+ // This method may not be called if the server doesn't send a
+ // ServerKeyExchange message.
+ processServerKeyExchange(*Config, *clientHelloMsg, *serverHelloMsg, *x509.Certificate, *serverKeyExchangeMsg) error
+ generateClientKeyExchange(*Config, *clientHelloMsg, *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error)
+
+ // peerSignatureAlgorithm returns the signature algorithm used by the
+ // peer, or zero if not applicable.
+ peerSignatureAlgorithm() signatureAlgorithm
+}
+
+const (
+ // suiteECDH indicates that the cipher suite involves elliptic curve
+ // Diffie-Hellman. This means that it should only be selected when the
+ // client indicates that it supports ECC with a curve and point format
+ // that we're happy with.
+ suiteECDHE = 1 << iota
+ // suiteECDSA indicates that the cipher suite involves an ECDSA
+ // signature and therefore may only be selected when the server's
+ // certificate is ECDSA. If this is not set then the cipher suite is
+ // RSA based.
+ suiteECDSA
+ // suiteTLS12 indicates that the cipher suite should only be advertised
+ // and accepted when using TLS 1.2 or greater.
+ suiteTLS12
+ // suiteTLS13 indicates that the cipher suite can be used with TLS 1.3.
+ // Cipher suites lacking this flag may not be used with TLS 1.3.
+ suiteTLS13
+ // suiteSHA384 indicates that the cipher suite uses SHA384 as the
+ // handshake hash.
+ suiteSHA384
+ // suiteNoDTLS indicates that the cipher suite cannot be used
+ // in DTLS.
+ suiteNoDTLS
+ // suitePSK indicates that the cipher suite authenticates with
+ // a pre-shared key rather than a server private key.
+ suitePSK
+)
+
+type tlsAead struct {
+ cipher.AEAD
+ explicitNonce bool
+}
+
+// A cipherSuite is a specific combination of key agreement, cipher and MAC
+// function. All cipher suites currently assume RSA key agreement.
+type cipherSuite struct {
+ id uint16
+ // the lengths, in bytes, of the key material needed for each component.
+ keyLen int
+ macLen int
+ ivLen func(version uint16) int
+ ka func(version uint16) keyAgreement
+ // flags is a bitmask of the suite* values, above.
+ flags int
+ cipher func(key, iv []byte, isRead bool) interface{}
+ mac func(version uint16, macKey []byte) macFunction
+ aead func(version uint16, key, fixedNonce []byte) *tlsAead
+}
+
+func (cs cipherSuite) hash() crypto.Hash {
+ if cs.flags&suiteSHA384 != 0 {
+ return crypto.SHA384
+ }
+ return crypto.SHA256
+}
+
+var cipherSuites = []*cipherSuite{
+ // Ciphersuite order is chosen so that ECDHE comes before plain RSA
+ // and RC4 comes before AES (because of the Lucky13 attack).
+ {TLS_CHACHA20_POLY1305_SHA256, 32, 0, ivLenChaCha20Poly1305, nil, suiteTLS13, nil, nil, aeadCHACHA20POLY1305},
+ {TLS_AES_128_GCM_SHA256, 16, 0, ivLenAESGCM, nil, suiteTLS13, nil, nil, aeadAESGCM},
+ {TLS_AES_256_GCM_SHA384, 32, 0, ivLenAESGCM, nil, suiteTLS13 | suiteSHA384, nil, nil, aeadAESGCM},
+ {TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, 32, 0, ivLenChaCha20Poly1305, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, nil, nil, aeadCHACHA20POLY1305},
+ {TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, 32, 0, ivLenChaCha20Poly1305, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadCHACHA20POLY1305},
+ {TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 16, 0, ivLenAESGCM, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadAESGCM},
+ {TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 16, 0, ivLenAESGCM, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, nil, nil, aeadAESGCM},
+ {TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 32, 0, ivLenAESGCM, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
+ {TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, 32, 0, ivLenAESGCM, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
+ {TLS_ECDHE_RSA_WITH_RC4_128_SHA, 16, 20, noIV, ecdheRSAKA, suiteECDHE | suiteNoDTLS, cipherRC4, macSHA1, nil},
+ {TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, 16, 20, noIV, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteNoDTLS, cipherRC4, macSHA1, nil},
+ {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, 16, 32, ivLenAES, ecdheRSAKA, suiteECDHE | suiteTLS12, cipherAES, macSHA256, nil},
+ {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, 16, 32, ivLenAES, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, cipherAES, macSHA256, nil},
+ {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, 16, 20, ivLenAES, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil},
+ {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, 16, 20, ivLenAES, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil},
+ {TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, 32, 48, ivLenAES, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteSHA384, cipherAES, macSHA384, nil},
+ {TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, 32, 48, ivLenAES, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12 | suiteSHA384, cipherAES, macSHA384, nil},
+ {TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, 32, 20, ivLenAES, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil},
+ {TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, 32, 20, ivLenAES, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil},
+ {TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, 16, 0, ivLenAESGCM, dheRSAKA, suiteTLS12, nil, nil, aeadAESGCM},
+ {TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, 32, 0, ivLenAESGCM, dheRSAKA, suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
+ {TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, 16, 32, ivLenAES, dheRSAKA, suiteTLS12, cipherAES, macSHA256, nil},
+ {TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, 32, 32, ivLenAES, dheRSAKA, suiteTLS12, cipherAES, macSHA256, nil},
+ {TLS_DHE_RSA_WITH_AES_128_CBC_SHA, 16, 20, ivLenAES, dheRSAKA, 0, cipherAES, macSHA1, nil},
+ {TLS_DHE_RSA_WITH_AES_256_CBC_SHA, 32, 20, ivLenAES, dheRSAKA, 0, cipherAES, macSHA1, nil},
+ {TLS_RSA_WITH_AES_128_GCM_SHA256, 16, 0, ivLenAESGCM, rsaKA, suiteTLS12, nil, nil, aeadAESGCM},
+ {TLS_RSA_WITH_AES_256_GCM_SHA384, 32, 0, ivLenAESGCM, rsaKA, suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
+ {TLS_RSA_WITH_RC4_128_SHA, 16, 20, noIV, rsaKA, suiteNoDTLS, cipherRC4, macSHA1, nil},
+ {TLS_RSA_WITH_RC4_128_MD5, 16, 16, noIV, rsaKA, suiteNoDTLS, cipherRC4, macMD5, nil},
+ {TLS_RSA_WITH_AES_128_CBC_SHA256, 16, 32, ivLenAES, rsaKA, suiteTLS12, cipherAES, macSHA256, nil},
+ {TLS_RSA_WITH_AES_256_CBC_SHA256, 32, 32, ivLenAES, rsaKA, suiteTLS12, cipherAES, macSHA256, nil},
+ {TLS_RSA_WITH_AES_128_CBC_SHA, 16, 20, ivLenAES, rsaKA, 0, cipherAES, macSHA1, nil},
+ {TLS_RSA_WITH_AES_256_CBC_SHA, 32, 20, ivLenAES, rsaKA, 0, cipherAES, macSHA1, nil},
+ {TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, ivLen3DES, ecdheRSAKA, suiteECDHE, cipher3DES, macSHA1, nil},
+ {TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, ivLen3DES, dheRSAKA, 0, cipher3DES, macSHA1, nil},
+ {TLS_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, ivLen3DES, rsaKA, 0, cipher3DES, macSHA1, nil},
+ {TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256, 32, 0, ivLenChaCha20Poly1305, ecdhePSKKA, suiteECDHE | suitePSK | suiteTLS12, nil, nil, aeadCHACHA20POLY1305},
+ {TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA, 16, 20, ivLenAES, ecdhePSKKA, suiteECDHE | suitePSK, cipherAES, macSHA1, nil},
+ {TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA, 32, 20, ivLenAES, ecdhePSKKA, suiteECDHE | suitePSK, cipherAES, macSHA1, nil},
+ {TLS_PSK_WITH_RC4_128_SHA, 16, 20, noIV, pskKA, suiteNoDTLS | suitePSK, cipherRC4, macSHA1, nil},
+ {TLS_PSK_WITH_AES_128_CBC_SHA, 16, 20, ivLenAES, pskKA, suitePSK, cipherAES, macSHA1, nil},
+ {TLS_PSK_WITH_AES_256_CBC_SHA, 32, 20, ivLenAES, pskKA, suitePSK, cipherAES, macSHA1, nil},
+ {TLS_RSA_WITH_NULL_SHA, 0, 20, noIV, rsaKA, suiteNoDTLS, cipherNull, macSHA1, nil},
+}
+
+func noIV(vers uint16) int {
+ return 0
+}
+
+func ivLenChaCha20Poly1305(vers uint16) int {
+ return 12
+}
+
+func ivLenAESGCM(vers uint16) int {
+ if vers >= VersionTLS13 {
+ return 12
+ }
+ return 4
+}
+
+func ivLenAES(vers uint16) int {
+ return 16
+}
+
+func ivLen3DES(vers uint16) int {
+ return 8
+}
+
+type nullCipher struct{}
+
+func cipherNull(key, iv []byte, isRead bool) interface{} {
+ return nullCipher{}
+}
+
+func cipherRC4(key, iv []byte, isRead bool) interface{} {
+ cipher, _ := rc4.NewCipher(key)
+ return cipher
+}
+
+func cipher3DES(key, iv []byte, isRead bool) interface{} {
+ block, _ := des.NewTripleDESCipher(key)
+ if isRead {
+ return cipher.NewCBCDecrypter(block, iv)
+ }
+ return cipher.NewCBCEncrypter(block, iv)
+}
+
+func cipherAES(key, iv []byte, isRead bool) interface{} {
+ block, _ := aes.NewCipher(key)
+ if isRead {
+ return cipher.NewCBCDecrypter(block, iv)
+ }
+ return cipher.NewCBCEncrypter(block, iv)
+}
+
+// macSHA1 returns a macFunction for the given protocol version.
+func macSHA1(version uint16, key []byte) macFunction {
+ if version == VersionSSL30 {
+ mac := ssl30MAC{
+ h: sha1.New(),
+ key: make([]byte, len(key)),
+ }
+ copy(mac.key, key)
+ return mac
+ }
+ return tls10MAC{hmac.New(sha1.New, key)}
+}
+
+func macMD5(version uint16, key []byte) macFunction {
+ if version == VersionSSL30 {
+ mac := ssl30MAC{
+ h: md5.New(),
+ key: make([]byte, len(key)),
+ }
+ copy(mac.key, key)
+ return mac
+ }
+ return tls10MAC{hmac.New(md5.New, key)}
+}
+
+func macSHA256(version uint16, key []byte) macFunction {
+ if version == VersionSSL30 {
+ mac := ssl30MAC{
+ h: sha256.New(),
+ key: make([]byte, len(key)),
+ }
+ copy(mac.key, key)
+ return mac
+ }
+ return tls10MAC{hmac.New(sha256.New, key)}
+}
+
+func macSHA384(version uint16, key []byte) macFunction {
+ if version == VersionSSL30 {
+ mac := ssl30MAC{
+ h: sha512.New384(),
+ key: make([]byte, len(key)),
+ }
+ copy(mac.key, key)
+ return mac
+ }
+ return tls10MAC{hmac.New(sha512.New384, key)}
+}
+
+type macFunction interface {
+ Size() int
+ MAC(digestBuf, seq, header, length, data []byte) []byte
+}
+
+// fixedNonceAEAD wraps an AEAD and prefixes a fixed portion of the nonce to
+// each call.
+type fixedNonceAEAD struct {
+ // sealNonce and openNonce are buffers where the larger nonce will be
+ // constructed. Since a seal and open operation may be running
+ // concurrently, there is a separate buffer for each.
+ sealNonce, openNonce []byte
+ aead cipher.AEAD
+}
+
+func (f *fixedNonceAEAD) NonceSize() int { return 8 }
+func (f *fixedNonceAEAD) Overhead() int { return f.aead.Overhead() }
+
+func (f *fixedNonceAEAD) Seal(out, nonce, plaintext, additionalData []byte) []byte {
+ copy(f.sealNonce[len(f.sealNonce)-8:], nonce)
+ return f.aead.Seal(out, f.sealNonce, plaintext, additionalData)
+}
+
+func (f *fixedNonceAEAD) Open(out, nonce, plaintext, additionalData []byte) ([]byte, error) {
+ copy(f.openNonce[len(f.openNonce)-8:], nonce)
+ return f.aead.Open(out, f.openNonce, plaintext, additionalData)
+}
+
+func aeadAESGCM(version uint16, key, fixedNonce []byte) *tlsAead {
+ aes, err := aes.NewCipher(key)
+ if err != nil {
+ panic(err)
+ }
+ aead, err := cipher.NewGCM(aes)
+ if err != nil {
+ panic(err)
+ }
+
+ nonce1, nonce2 := make([]byte, 12), make([]byte, 12)
+ copy(nonce1, fixedNonce)
+ copy(nonce2, fixedNonce)
+
+ if version >= VersionTLS13 {
+ return &tlsAead{&xorNonceAEAD{nonce1, nonce2, aead}, false}
+ }
+
+ return &tlsAead{&fixedNonceAEAD{nonce1, nonce2, aead}, true}
+}
+
+func xorSlice(out, in []byte) {
+ for i := range out {
+ out[i] ^= in[i]
+ }
+}
+
+// xorNonceAEAD wraps an AEAD and XORs a fixed portion of the nonce, left-padded
+// if necessary, each call.
+type xorNonceAEAD struct {
+ // sealNonce and openNonce are buffers where the larger nonce will be
+ // constructed. Since a seal and open operation may be running
+ // concurrently, there is a separate buffer for each.
+ sealNonce, openNonce []byte
+ aead cipher.AEAD
+}
+
+func (x *xorNonceAEAD) NonceSize() int { return 8 }
+func (x *xorNonceAEAD) Overhead() int { return x.aead.Overhead() }
+
+func (x *xorNonceAEAD) Seal(out, nonce, plaintext, additionalData []byte) []byte {
+ xorSlice(x.sealNonce[len(x.sealNonce)-len(nonce):], nonce)
+ ret := x.aead.Seal(out, x.sealNonce, plaintext, additionalData)
+ xorSlice(x.sealNonce[len(x.sealNonce)-len(nonce):], nonce)
+ return ret
+}
+
+func (x *xorNonceAEAD) Open(out, nonce, plaintext, additionalData []byte) ([]byte, error) {
+ xorSlice(x.openNonce[len(x.openNonce)-len(nonce):], nonce)
+ ret, err := x.aead.Open(out, x.openNonce, plaintext, additionalData)
+ xorSlice(x.openNonce[len(x.openNonce)-len(nonce):], nonce)
+ return ret, err
+}
+
+func aeadCHACHA20POLY1305(version uint16, key, fixedNonce []byte) *tlsAead {
+ aead, err := newChaCha20Poly1305(key)
+ if err != nil {
+ panic(err)
+ }
+
+ nonce1, nonce2 := make([]byte, len(fixedNonce)), make([]byte, len(fixedNonce))
+ copy(nonce1, fixedNonce)
+ copy(nonce2, fixedNonce)
+
+ return &tlsAead{&xorNonceAEAD{nonce1, nonce2, aead}, false}
+}
+
+// ssl30MAC implements the SSLv3 MAC function, as defined in
+// www.mozilla.org/projects/security/pki/nss/ssl/draft302.txt section 5.2.3.1
+type ssl30MAC struct {
+ h hash.Hash
+ key []byte
+}
+
+func (s ssl30MAC) Size() int {
+ return s.h.Size()
+}
+
+var ssl30Pad1 = [48]byte{0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36}
+
+var ssl30Pad2 = [48]byte{0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c}
+
+func (s ssl30MAC) MAC(digestBuf, seq, header, length, data []byte) []byte {
+ padLength := 48
+ if s.h.Size() == 20 {
+ padLength = 40
+ }
+
+ s.h.Reset()
+ s.h.Write(s.key)
+ s.h.Write(ssl30Pad1[:padLength])
+ s.h.Write(seq)
+ s.h.Write(header[:1])
+ s.h.Write(length)
+ s.h.Write(data)
+ digestBuf = s.h.Sum(digestBuf[:0])
+
+ s.h.Reset()
+ s.h.Write(s.key)
+ s.h.Write(ssl30Pad2[:padLength])
+ s.h.Write(digestBuf)
+ return s.h.Sum(digestBuf[:0])
+}
+
+// tls10MAC implements the TLS 1.0 MAC function. RFC 2246, section 6.2.3.
+type tls10MAC struct {
+ h hash.Hash
+}
+
+func (s tls10MAC) Size() int {
+ return s.h.Size()
+}
+
+func (s tls10MAC) MAC(digestBuf, seq, header, length, data []byte) []byte {
+ s.h.Reset()
+ s.h.Write(seq)
+ s.h.Write(header)
+ s.h.Write(length)
+ s.h.Write(data)
+ return s.h.Sum(digestBuf[:0])
+}
+
+func rsaKA(version uint16) keyAgreement {
+ return &rsaKeyAgreement{version: version}
+}
+
+func ecdheECDSAKA(version uint16) keyAgreement {
+ return &ecdheKeyAgreement{
+ auth: &signedKeyAgreement{
+ keyType: keyTypeECDSA,
+ version: version,
+ },
+ }
+}
+
+func ecdheRSAKA(version uint16) keyAgreement {
+ return &ecdheKeyAgreement{
+ auth: &signedKeyAgreement{
+ keyType: keyTypeRSA,
+ version: version,
+ },
+ }
+}
+
+func dheRSAKA(version uint16) keyAgreement {
+ return &dheKeyAgreement{
+ auth: &signedKeyAgreement{
+ keyType: keyTypeRSA,
+ version: version,
+ },
+ }
+}
+
+func pskKA(version uint16) keyAgreement {
+ return &pskKeyAgreement{
+ base: &nilKeyAgreement{},
+ }
+}
+
+func ecdhePSKKA(version uint16) keyAgreement {
+ return &pskKeyAgreement{
+ base: &ecdheKeyAgreement{
+ auth: &nilKeyAgreementAuthentication{},
+ },
+ }
+}
+
+// mutualCipherSuite returns a cipherSuite given a list of supported
+// ciphersuites and the id requested by the peer.
+func mutualCipherSuite(have []uint16, want uint16) *cipherSuite {
+ for _, id := range have {
+ if id == want {
+ return cipherSuiteFromID(id)
+ }
+ }
+ return nil
+}
+
+func cipherSuiteFromID(id uint16) *cipherSuite {
+ for _, suite := range cipherSuites {
+ if suite.id == id {
+ return suite
+ }
+ }
+ return nil
+}
+
+// A list of the possible cipher suite ids. Taken from
+// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml
+const (
+ TLS_RSA_WITH_NULL_SHA uint16 = 0x0002
+ TLS_RSA_WITH_RC4_128_MD5 uint16 = 0x0004
+ TLS_RSA_WITH_RC4_128_SHA uint16 = 0x0005
+ TLS_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0x000a
+ TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0x0016
+ TLS_RSA_WITH_AES_128_CBC_SHA uint16 = 0x002f
+ TLS_DHE_RSA_WITH_AES_128_CBC_SHA uint16 = 0x0033
+ TLS_RSA_WITH_AES_256_CBC_SHA uint16 = 0x0035
+ TLS_DHE_RSA_WITH_AES_256_CBC_SHA uint16 = 0x0039
+ TLS_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0x003c
+ TLS_RSA_WITH_AES_256_CBC_SHA256 uint16 = 0x003d
+ TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0x0067
+ TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 uint16 = 0x006b
+ TLS_PSK_WITH_RC4_128_SHA uint16 = 0x008a
+ TLS_PSK_WITH_AES_128_CBC_SHA uint16 = 0x008c
+ TLS_PSK_WITH_AES_256_CBC_SHA uint16 = 0x008d
+ TLS_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0x009c
+ TLS_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0x009d
+ TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0x009e
+ TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0x009f
+ TLS_ECDHE_ECDSA_WITH_RC4_128_SHA uint16 = 0xc007
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA uint16 = 0xc009
+ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA uint16 = 0xc00a
+ TLS_ECDHE_RSA_WITH_RC4_128_SHA uint16 = 0xc011
+ TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0xc012
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA uint16 = 0xc013
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA uint16 = 0xc014
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 uint16 = 0xc023
+ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 uint16 = 0xc024
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0xc027
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 uint16 = 0xc028
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 uint16 = 0xc02b
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 uint16 = 0xc02c
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0xc02f
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0xc030
+ TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA uint16 = 0xc035
+ TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA uint16 = 0xc036
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xcca8
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xcca9
+ TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xccac
+ renegotiationSCSV uint16 = 0x00ff
+ fallbackSCSV uint16 = 0x5600
+)
+
+// Additional cipher suite IDs, not IANA-assigned.
+const (
+ TLS_AES_128_GCM_SHA256 uint16 = 0x1301
+ TLS_AES_256_GCM_SHA384 uint16 = 0x1302
+ TLS_CHACHA20_POLY1305_SHA256 uint16 = 0x1303
+)
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/common.go b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/common.go
new file mode 100644
index 000000000..167e872b0
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/common.go
@@ -0,0 +1,1681 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runner
+
+import (
+ "container/list"
+ "crypto"
+ "crypto/ecdsa"
+ "crypto/rand"
+ "crypto/x509"
+ "fmt"
+ "io"
+ "math/big"
+ "strings"
+ "sync"
+ "time"
+)
+
+const (
+ VersionSSL30 = 0x0300
+ VersionTLS10 = 0x0301
+ VersionTLS11 = 0x0302
+ VersionTLS12 = 0x0303
+ VersionTLS13 = 0x0304
+)
+
+// A draft version of TLS 1.3 that is sent over the wire for the current draft.
+const tls13DraftVersion = 0x7f12
+
+const (
+ maxPlaintext = 16384 // maximum plaintext payload length
+ maxCiphertext = 16384 + 2048 // maximum ciphertext payload length
+ tlsRecordHeaderLen = 5 // record header length
+ dtlsRecordHeaderLen = 13
+ maxHandshake = 65536 // maximum handshake we support (protocol max is 16 MB)
+
+ minVersion = VersionSSL30
+ maxVersion = VersionTLS13
+)
+
+// TLS record types.
+type recordType uint8
+
+const (
+ recordTypeChangeCipherSpec recordType = 20
+ recordTypeAlert recordType = 21
+ recordTypeHandshake recordType = 22
+ recordTypeApplicationData recordType = 23
+)
+
+// TLS handshake message types.
+const (
+ typeHelloRequest uint8 = 0
+ typeClientHello uint8 = 1
+ typeServerHello uint8 = 2
+ typeHelloVerifyRequest uint8 = 3
+ typeNewSessionTicket uint8 = 4
+ typeHelloRetryRequest uint8 = 6 // draft-ietf-tls-tls13-16
+ typeEncryptedExtensions uint8 = 8 // draft-ietf-tls-tls13-16
+ typeCertificate uint8 = 11
+ typeServerKeyExchange uint8 = 12
+ typeCertificateRequest uint8 = 13
+ typeServerHelloDone uint8 = 14
+ typeCertificateVerify uint8 = 15
+ typeClientKeyExchange uint8 = 16
+ typeFinished uint8 = 20
+ typeCertificateStatus uint8 = 22
+ typeKeyUpdate uint8 = 24 // draft-ietf-tls-tls13-16
+ typeNextProtocol uint8 = 67 // Not IANA assigned
+ typeChannelID uint8 = 203 // Not IANA assigned
+)
+
+// TLS compression types.
+const (
+ compressionNone uint8 = 0
+)
+
+// TLS extension numbers
+const (
+ extensionServerName uint16 = 0
+ extensionStatusRequest uint16 = 5
+ extensionSupportedCurves uint16 = 10
+ extensionSupportedPoints uint16 = 11
+ extensionSignatureAlgorithms uint16 = 13
+ extensionUseSRTP uint16 = 14
+ extensionALPN uint16 = 16
+ extensionSignedCertificateTimestamp uint16 = 18
+ extensionExtendedMasterSecret uint16 = 23
+ extensionSessionTicket uint16 = 35
+ extensionKeyShare uint16 = 40 // draft-ietf-tls-tls13-16
+ extensionPreSharedKey uint16 = 41 // draft-ietf-tls-tls13-16
+ extensionEarlyData uint16 = 42 // draft-ietf-tls-tls13-16
+ extensionSupportedVersions uint16 = 43 // draft-ietf-tls-tls13-16
+ extensionCookie uint16 = 44 // draft-ietf-tls-tls13-16
+ extensionPSKKeyExchangeModes uint16 = 45 // draft-ietf-tls-tls13-18
+ extensionTicketEarlyDataInfo uint16 = 46 // draft-ietf-tls-tls13-18
+ extensionCustom uint16 = 1234 // not IANA assigned
+ extensionNextProtoNeg uint16 = 13172 // not IANA assigned
+ extensionRenegotiationInfo uint16 = 0xff01
+ extensionChannelID uint16 = 30032 // not IANA assigned
+)
+
+// TLS signaling cipher suite values
+const (
+ scsvRenegotiation uint16 = 0x00ff
+)
+
+// CurveID is the type of a TLS identifier for an elliptic curve. See
+// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-8
+type CurveID uint16
+
+const (
+ CurveP224 CurveID = 21
+ CurveP256 CurveID = 23
+ CurveP384 CurveID = 24
+ CurveP521 CurveID = 25
+ CurveX25519 CurveID = 29
+)
+
+// TLS Elliptic Curve Point Formats
+// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-9
+const (
+ pointFormatUncompressed uint8 = 0
+ pointFormatCompressedPrime uint8 = 1
+)
+
+// TLS CertificateStatusType (RFC 3546)
+const (
+ statusTypeOCSP uint8 = 1
+)
+
+// Certificate types (for certificateRequestMsg)
+const (
+ CertTypeRSASign = 1 // A certificate containing an RSA key
+ CertTypeDSSSign = 2 // A certificate containing a DSA key
+ CertTypeRSAFixedDH = 3 // A certificate containing a static DH key
+ CertTypeDSSFixedDH = 4 // A certificate containing a static DH key
+
+ // See RFC4492 sections 3 and 5.5.
+ CertTypeECDSASign = 64 // A certificate containing an ECDSA-capable public key, signed with ECDSA.
+ CertTypeRSAFixedECDH = 65 // A certificate containing an ECDH-capable public key, signed with RSA.
+ CertTypeECDSAFixedECDH = 66 // A certificate containing an ECDH-capable public key, signed with ECDSA.
+
+ // Rest of these are reserved by the TLS spec
+)
+
+// signatureAlgorithm corresponds to a SignatureScheme value from TLS 1.3. Note
+// that TLS 1.3 names the production 'SignatureScheme' to avoid colliding with
+// TLS 1.2's SignatureAlgorithm but otherwise refers to them as 'signature
+// algorithms' throughout. We match the latter.
+type signatureAlgorithm uint16
+
+const (
+ // RSASSA-PKCS1-v1_5 algorithms
+ signatureRSAPKCS1WithMD5 signatureAlgorithm = 0x0101
+ signatureRSAPKCS1WithSHA1 signatureAlgorithm = 0x0201
+ signatureRSAPKCS1WithSHA256 signatureAlgorithm = 0x0401
+ signatureRSAPKCS1WithSHA384 signatureAlgorithm = 0x0501
+ signatureRSAPKCS1WithSHA512 signatureAlgorithm = 0x0601
+
+ // ECDSA algorithms
+ signatureECDSAWithSHA1 signatureAlgorithm = 0x0203
+ signatureECDSAWithP256AndSHA256 signatureAlgorithm = 0x0403
+ signatureECDSAWithP384AndSHA384 signatureAlgorithm = 0x0503
+ signatureECDSAWithP521AndSHA512 signatureAlgorithm = 0x0603
+
+ // RSASSA-PSS algorithms
+ signatureRSAPSSWithSHA256 signatureAlgorithm = 0x0804
+ signatureRSAPSSWithSHA384 signatureAlgorithm = 0x0805
+ signatureRSAPSSWithSHA512 signatureAlgorithm = 0x0806
+
+ // EdDSA algorithms
+ signatureEd25519 signatureAlgorithm = 0x0807
+ signatureEd448 signatureAlgorithm = 0x0808
+)
+
+// supportedSignatureAlgorithms contains the default supported signature
+// algorithms.
+var supportedSignatureAlgorithms = []signatureAlgorithm{
+ signatureRSAPSSWithSHA256,
+ signatureRSAPKCS1WithSHA256,
+ signatureECDSAWithP256AndSHA256,
+ signatureRSAPKCS1WithSHA1,
+ signatureECDSAWithSHA1,
+}
+
+// SRTP protection profiles (See RFC 5764, section 4.1.2)
+const (
+ SRTP_AES128_CM_HMAC_SHA1_80 uint16 = 0x0001
+ SRTP_AES128_CM_HMAC_SHA1_32 = 0x0002
+)
+
+// PskKeyExchangeMode values (see draft-ietf-tls-tls13-16)
+const (
+ pskKEMode = 0
+ pskDHEKEMode = 1
+)
+
+// KeyUpdateRequest values (see draft-ietf-tls-tls13-16, section 4.5.3)
+const (
+ keyUpdateNotRequested = 0
+ keyUpdateRequested = 1
+)
+
+// ConnectionState records basic TLS details about the connection.
+type ConnectionState struct {
+ Version uint16 // TLS version used by the connection (e.g. VersionTLS12)
+ HandshakeComplete bool // TLS handshake is complete
+ DidResume bool // connection resumes a previous TLS connection
+ CipherSuite uint16 // cipher suite in use (TLS_RSA_WITH_RC4_128_SHA, ...)
+ NegotiatedProtocol string // negotiated next protocol (from Config.NextProtos)
+ NegotiatedProtocolIsMutual bool // negotiated protocol was advertised by server
+ NegotiatedProtocolFromALPN bool // protocol negotiated with ALPN
+ ServerName string // server name requested by client, if any (server side only)
+ PeerCertificates []*x509.Certificate // certificate chain presented by remote peer
+ VerifiedChains [][]*x509.Certificate // verified chains built from PeerCertificates
+ ChannelID *ecdsa.PublicKey // the channel ID for this connection
+ SRTPProtectionProfile uint16 // the negotiated DTLS-SRTP protection profile
+ TLSUnique []byte // the tls-unique channel binding
+ SCTList []byte // signed certificate timestamp list
+ PeerSignatureAlgorithm signatureAlgorithm // algorithm used by the peer in the handshake
+ CurveID CurveID // the curve used in ECDHE
+}
+
+// ClientAuthType declares the policy the server will follow for
+// TLS Client Authentication.
+type ClientAuthType int
+
+const (
+ NoClientCert ClientAuthType = iota
+ RequestClientCert
+ RequireAnyClientCert
+ VerifyClientCertIfGiven
+ RequireAndVerifyClientCert
+)
+
+// ClientSessionState contains the state needed by clients to resume TLS
+// sessions.
+type ClientSessionState struct {
+ sessionId []uint8 // Session ID supplied by the server. nil if the session has a ticket.
+ sessionTicket []uint8 // Encrypted ticket used for session resumption with server
+ vers uint16 // SSL/TLS version negotiated for the session
+ cipherSuite uint16 // Ciphersuite negotiated for the session
+ masterSecret []byte // MasterSecret generated by client on a full handshake
+ handshakeHash []byte // Handshake hash for Channel ID purposes.
+ serverCertificates []*x509.Certificate // Certificate chain presented by the server
+ extendedMasterSecret bool // Whether an extended master secret was used to generate the session
+ sctList []byte
+ ocspResponse []byte
+ ticketCreationTime time.Time
+ ticketExpiration time.Time
+ ticketAgeAdd uint32
+ maxEarlyDataSize uint32
+}
+
+// ClientSessionCache is a cache of ClientSessionState objects that can be used
+// by a client to resume a TLS session with a given server. ClientSessionCache
+// implementations should expect to be called concurrently from different
+// goroutines.
+type ClientSessionCache interface {
+ // Get searches for a ClientSessionState associated with the given key.
+ // On return, ok is true if one was found.
+ Get(sessionKey string) (session *ClientSessionState, ok bool)
+
+ // Put adds the ClientSessionState to the cache with the given key.
+ Put(sessionKey string, cs *ClientSessionState)
+}
+
+// ServerSessionCache is a cache of sessionState objects that can be used by a
+// client to resume a TLS session with a given server. ServerSessionCache
+// implementations should expect to be called concurrently from different
+// goroutines.
+type ServerSessionCache interface {
+ // Get searches for a sessionState associated with the given session
+ // ID. On return, ok is true if one was found.
+ Get(sessionId string) (session *sessionState, ok bool)
+
+ // Put adds the sessionState to the cache with the given session ID.
+ Put(sessionId string, session *sessionState)
+}
+
+// A Config structure is used to configure a TLS client or server.
+// After one has been passed to a TLS function it must not be
+// modified. A Config may be reused; the tls package will also not
+// modify it.
+type Config struct {
+ // Rand provides the source of entropy for nonces and RSA blinding.
+ // If Rand is nil, TLS uses the cryptographic random reader in package
+ // crypto/rand.
+ // The Reader must be safe for use by multiple goroutines.
+ Rand io.Reader
+
+ // Time returns the current time as the number of seconds since the epoch.
+ // If Time is nil, TLS uses time.Now.
+ Time func() time.Time
+
+ // Certificates contains one or more certificate chains
+ // to present to the other side of the connection.
+ // Server configurations must include at least one certificate.
+ Certificates []Certificate
+
+ // NameToCertificate maps from a certificate name to an element of
+ // Certificates. Note that a certificate name can be of the form
+ // '*.example.com' and so doesn't have to be a domain name as such.
+ // See Config.BuildNameToCertificate
+ // The nil value causes the first element of Certificates to be used
+ // for all connections.
+ NameToCertificate map[string]*Certificate
+
+ // RootCAs defines the set of root certificate authorities
+ // that clients use when verifying server certificates.
+ // If RootCAs is nil, TLS uses the host's root CA set.
+ RootCAs *x509.CertPool
+
+ // NextProtos is a list of supported, application level protocols.
+ NextProtos []string
+
+ // ServerName is used to verify the hostname on the returned
+ // certificates unless InsecureSkipVerify is given. It is also included
+ // in the client's handshake to support virtual hosting.
+ ServerName string
+
+ // ClientAuth determines the server's policy for
+ // TLS Client Authentication. The default is NoClientCert.
+ ClientAuth ClientAuthType
+
+ // ClientCAs defines the set of root certificate authorities
+ // that servers use if required to verify a client certificate
+ // by the policy in ClientAuth.
+ ClientCAs *x509.CertPool
+
+ // ClientCertificateTypes defines the set of allowed client certificate
+ // types. The default is CertTypeRSASign and CertTypeECDSASign.
+ ClientCertificateTypes []byte
+
+ // InsecureSkipVerify controls whether a client verifies the
+ // server's certificate chain and host name.
+ // If InsecureSkipVerify is true, TLS accepts any certificate
+ // presented by the server and any host name in that certificate.
+ // In this mode, TLS is susceptible to man-in-the-middle attacks.
+ // This should be used only for testing.
+ InsecureSkipVerify bool
+
+ // CipherSuites is a list of supported cipher suites. If CipherSuites
+ // is nil, TLS uses a list of suites supported by the implementation.
+ CipherSuites []uint16
+
+ // PreferServerCipherSuites controls whether the server selects the
+ // client's most preferred ciphersuite, or the server's most preferred
+ // ciphersuite. If true then the server's preference, as expressed in
+ // the order of elements in CipherSuites, is used.
+ PreferServerCipherSuites bool
+
+ // SessionTicketsDisabled may be set to true to disable session ticket
+ // (resumption) support.
+ SessionTicketsDisabled bool
+
+ // SessionTicketKey is used by TLS servers to provide session
+ // resumption. See RFC 5077. If zero, it will be filled with
+ // random data before the first server handshake.
+ //
+ // If multiple servers are terminating connections for the same host
+ // they should all have the same SessionTicketKey. If the
+ // SessionTicketKey leaks, previously recorded and future TLS
+ // connections using that key are compromised.
+ SessionTicketKey [32]byte
+
+ // ClientSessionCache is a cache of ClientSessionState entries
+ // for TLS session resumption.
+ ClientSessionCache ClientSessionCache
+
+ // ServerSessionCache is a cache of sessionState entries for TLS session
+ // resumption.
+ ServerSessionCache ServerSessionCache
+
+ // MinVersion contains the minimum SSL/TLS version that is acceptable.
+ // If zero, then SSLv3 is taken as the minimum.
+ MinVersion uint16
+
+ // MaxVersion contains the maximum SSL/TLS version that is acceptable.
+ // If zero, then the maximum version supported by this package is used,
+ // which is currently TLS 1.2.
+ MaxVersion uint16
+
+ // CurvePreferences contains the elliptic curves that will be used in
+ // an ECDHE handshake, in preference order. If empty, the default will
+ // be used.
+ CurvePreferences []CurveID
+
+ // DefaultCurves contains the elliptic curves for which public values will
+ // be sent in the ClientHello's KeyShare extension. If this value is nil,
+ // all supported curves will have public values sent. This field is ignored
+ // on servers.
+ DefaultCurves []CurveID
+
+ // ChannelID contains the ECDSA key for the client to use as
+ // its TLS Channel ID.
+ ChannelID *ecdsa.PrivateKey
+
+ // RequestChannelID controls whether the server requests a TLS
+ // Channel ID. If negotiated, the client's public key is
+ // returned in the ConnectionState.
+ RequestChannelID bool
+
+ // PreSharedKey, if not nil, is the pre-shared key to use with
+ // the PSK cipher suites.
+ PreSharedKey []byte
+
+ // PreSharedKeyIdentity, if not empty, is the identity to use
+ // with the PSK cipher suites.
+ PreSharedKeyIdentity string
+
+ // MaxEarlyDataSize controls the maximum number of bytes that the
+ // server will accept in early data and advertise in a
+ // NewSessionTicketMsg. If 0, no early data will be accepted and
+ // the TicketEarlyDataInfo extension in the NewSessionTicketMsg
+ // will be omitted.
+ MaxEarlyDataSize uint32
+
+ // SRTPProtectionProfiles, if not nil, is the list of SRTP
+ // protection profiles to offer in DTLS-SRTP.
+ SRTPProtectionProfiles []uint16
+
+ // SignSignatureAlgorithms, if not nil, overrides the default set of
+ // supported signature algorithms to sign with.
+ SignSignatureAlgorithms []signatureAlgorithm
+
+ // VerifySignatureAlgorithms, if not nil, overrides the default set of
+ // supported signature algorithms that are accepted.
+ VerifySignatureAlgorithms []signatureAlgorithm
+
+ // Bugs specifies optional misbehaviour to be used for testing other
+ // implementations.
+ Bugs ProtocolBugs
+
+ serverInitOnce sync.Once // guards calling (*Config).serverInit
+}
+
+type BadValue int
+
+const (
+ BadValueNone BadValue = iota
+ BadValueNegative
+ BadValueZero
+ BadValueLimit
+ BadValueLarge
+ NumBadValues
+)
+
+type RSABadValue int
+
+const (
+ RSABadValueNone RSABadValue = iota
+ RSABadValueCorrupt
+ RSABadValueTooLong
+ RSABadValueTooShort
+ RSABadValueWrongVersion
+ NumRSABadValues
+)
+
+type ProtocolBugs struct {
+ // InvalidSignature specifies that the signature in a ServerKeyExchange
+ // or CertificateVerify message should be invalid.
+ InvalidSignature bool
+
+ // SendCurve, if non-zero, causes the server to send the specified curve
+ // ID in ServerKeyExchange (TLS 1.2) or ServerHello (TLS 1.3) rather
+ // than the negotiated one.
+ SendCurve CurveID
+
+ // InvalidECDHPoint, if true, causes the ECC points in
+ // ServerKeyExchange or ClientKeyExchange messages to be invalid.
+ InvalidECDHPoint bool
+
+ // BadECDSAR controls ways in which the 'r' value of an ECDSA signature
+ // can be invalid.
+ BadECDSAR BadValue
+ BadECDSAS BadValue
+
+ // MaxPadding causes CBC records to have the maximum possible padding.
+ MaxPadding bool
+ // PaddingFirstByteBad causes the first byte of the padding to be
+ // incorrect.
+ PaddingFirstByteBad bool
+ // PaddingFirstByteBadIf255 causes the first byte of padding to be
+ // incorrect if there's a maximum amount of padding (i.e. 255 bytes).
+ PaddingFirstByteBadIf255 bool
+
+ // FailIfNotFallbackSCSV causes a server handshake to fail if the
+ // client doesn't send the fallback SCSV value.
+ FailIfNotFallbackSCSV bool
+
+ // DuplicateExtension causes an extra empty extension of bogus type to
+ // be emitted in either the ClientHello or the ServerHello.
+ DuplicateExtension bool
+
+ // UnauthenticatedECDH causes the server to pretend ECDHE_RSA
+ // and ECDHE_ECDSA cipher suites are actually ECDH_anon. No
+ // Certificate message is sent and no signature is added to
+ // ServerKeyExchange.
+ UnauthenticatedECDH bool
+
+ // SkipHelloVerifyRequest causes a DTLS server to skip the
+ // HelloVerifyRequest message.
+ SkipHelloVerifyRequest bool
+
+ // SkipCertificateStatus, if true, causes the server to skip the
+ // CertificateStatus message. This is legal because CertificateStatus is
+ // optional, even with a status_request in ServerHello.
+ SkipCertificateStatus bool
+
+ // SkipServerKeyExchange causes the server to skip sending
+ // ServerKeyExchange messages.
+ SkipServerKeyExchange bool
+
+ // SkipNewSessionTicket causes the server to skip sending the
+ // NewSessionTicket message despite promising to in ServerHello.
+ SkipNewSessionTicket bool
+
+ // SkipClientCertificate causes the client to skip the Certificate
+ // message.
+ SkipClientCertificate bool
+
+ // SkipChangeCipherSpec causes the implementation to skip
+ // sending the ChangeCipherSpec message (and adjusting cipher
+ // state accordingly for the Finished message).
+ SkipChangeCipherSpec bool
+
+ // SkipFinished causes the implementation to skip sending the Finished
+ // message.
+ SkipFinished bool
+
+ // EarlyChangeCipherSpec causes the client to send an early
+ // ChangeCipherSpec message before the ClientKeyExchange. A value of
+ // zero disables this behavior. One and two configure variants for 0.9.8
+ // and 1.0.1 modes, respectively.
+ EarlyChangeCipherSpec int
+
+ // StrayChangeCipherSpec causes every pre-ChangeCipherSpec handshake
+ // message in DTLS to be prefaced by stray ChangeCipherSpec record. This
+ // may be used to test DTLS's handling of reordered ChangeCipherSpec.
+ StrayChangeCipherSpec bool
+
+ // FragmentAcrossChangeCipherSpec causes the implementation to fragment
+ // the Finished (or NextProto) message around the ChangeCipherSpec
+ // messages.
+ FragmentAcrossChangeCipherSpec bool
+
+ // SendUnencryptedFinished, if true, causes the Finished message to be
+ // send unencrypted before ChangeCipherSpec rather than after it.
+ SendUnencryptedFinished bool
+
+ // PartialEncryptedExtensionsWithServerHello, if true, causes the TLS
+ // 1.3 server to send part of EncryptedExtensions unencrypted
+ // in the same record as ServerHello.
+ PartialEncryptedExtensionsWithServerHello bool
+
+ // PartialClientFinishedWithClientHello, if true, causes the TLS 1.3
+ // client to send part of Finished unencrypted in the same record as
+ // ClientHello.
+ PartialClientFinishedWithClientHello bool
+
+ // SendV2ClientHello causes the client to send a V2ClientHello
+ // instead of a normal ClientHello.
+ SendV2ClientHello bool
+
+ // SendFallbackSCSV causes the client to include
+ // TLS_FALLBACK_SCSV in the ClientHello.
+ SendFallbackSCSV bool
+
+ // SendRenegotiationSCSV causes the client to include the renegotiation
+ // SCSV in the ClientHello.
+ SendRenegotiationSCSV bool
+
+ // MaxHandshakeRecordLength, if non-zero, is the maximum size of a
+ // handshake record. Handshake messages will be split into multiple
+ // records at the specified size, except that the client_version will
+ // never be fragmented. For DTLS, it is the maximum handshake fragment
+ // size, not record size; DTLS allows multiple handshake fragments in a
+ // single handshake record. See |PackHandshakeFragments|.
+ MaxHandshakeRecordLength int
+
+ // FragmentClientVersion will allow MaxHandshakeRecordLength to apply to
+ // the first 6 bytes of the ClientHello.
+ FragmentClientVersion bool
+
+ // FragmentAlert will cause all alerts to be fragmented across
+ // two records.
+ FragmentAlert bool
+
+ // DoubleAlert will cause all alerts to be sent as two copies packed
+ // within one record.
+ DoubleAlert bool
+
+ // SendSpuriousAlert, if non-zero, will cause an spurious, unwanted
+ // alert to be sent.
+ SendSpuriousAlert alert
+
+ // BadRSAClientKeyExchange causes the client to send a corrupted RSA
+ // ClientKeyExchange which would not pass padding checks.
+ BadRSAClientKeyExchange RSABadValue
+
+ // RenewTicketOnResume causes the server to renew the session ticket and
+ // send a NewSessionTicket message during an abbreviated handshake.
+ RenewTicketOnResume bool
+
+ // SendClientVersion, if non-zero, causes the client to send the
+ // specified value in the ClientHello version field.
+ SendClientVersion uint16
+
+ // OmitSupportedVersions, if true, causes the client to omit the
+ // supported versions extension.
+ OmitSupportedVersions bool
+
+ // SendSupportedVersions, if non-empty, causes the client to send a
+ // supported versions extension with the values from array.
+ SendSupportedVersions []uint16
+
+ // NegotiateVersion, if non-zero, causes the server to negotiate the
+ // specifed TLS version rather than the version supported by either
+ // peer.
+ NegotiateVersion uint16
+
+ // NegotiateVersionOnRenego, if non-zero, causes the server to negotiate
+ // the specified TLS version on renegotiation rather than retaining it.
+ NegotiateVersionOnRenego uint16
+
+ // ExpectFalseStart causes the server to, on full handshakes,
+ // expect the peer to False Start; the server Finished message
+ // isn't sent until we receive an application data record
+ // from the peer.
+ ExpectFalseStart bool
+
+ // AlertBeforeFalseStartTest, if non-zero, causes the server to, on full
+ // handshakes, send an alert just before reading the application data
+ // record to test False Start. This can be used in a negative False
+ // Start test to determine whether the peer processed the alert (and
+ // closed the connection) before or after sending app data.
+ AlertBeforeFalseStartTest alert
+
+ // ExpectServerName, if not empty, is the hostname the client
+ // must specify in the server_name extension.
+ ExpectServerName string
+
+ // SwapNPNAndALPN switches the relative order between NPN and ALPN in
+ // both ClientHello and ServerHello.
+ SwapNPNAndALPN bool
+
+ // ALPNProtocol, if not nil, sets the ALPN protocol that a server will
+ // return.
+ ALPNProtocol *string
+
+ // AcceptAnySession causes the server to resume sessions regardless of
+ // the version associated with the session or cipher suite. It also
+ // causes the server to look in both TLS 1.2 and 1.3 extensions to
+ // process a ticket.
+ AcceptAnySession bool
+
+ // SendBothTickets, if true, causes the client to send tickets in both
+ // TLS 1.2 and 1.3 extensions.
+ SendBothTickets bool
+
+ // FilterTicket, if not nil, causes the client to modify a session
+ // ticket before sending it in a resume handshake.
+ FilterTicket func([]byte) ([]byte, error)
+
+ // TicketSessionIDLength, if non-zero, is the length of the session ID
+ // to send with a ticket resumption offer.
+ TicketSessionIDLength int
+
+ // EmptyTicketSessionID, if true, causes the client to send an empty
+ // session ID with a ticket resumption offer. For simplicity, this will
+ // also cause the client to interpret a ServerHello with empty session
+ // ID as a resumption. (A client which sends empty session ID is
+ // normally expected to look ahead for ChangeCipherSpec.)
+ EmptyTicketSessionID bool
+
+ // ExpectNoTLS12Session, if true, causes the server to fail the
+ // connection if either a session ID or TLS 1.2 ticket is offered.
+ ExpectNoTLS12Session bool
+
+ // ExpectNoTLS13PSK, if true, causes the server to fail the connection
+ // if a TLS 1.3 PSK is offered.
+ ExpectNoTLS13PSK bool
+
+ // RequireExtendedMasterSecret, if true, requires that the peer support
+ // the extended master secret option.
+ RequireExtendedMasterSecret bool
+
+ // NoExtendedMasterSecret causes the client and server to behave as if
+ // they didn't support an extended master secret in the initial
+ // handshake.
+ NoExtendedMasterSecret bool
+
+ // NoExtendedMasterSecretOnRenegotiation causes the client and server to
+ // behave as if they didn't support an extended master secret in
+ // renegotiation handshakes.
+ NoExtendedMasterSecretOnRenegotiation bool
+
+ // EmptyRenegotiationInfo causes the renegotiation extension to be
+ // empty in a renegotiation handshake.
+ EmptyRenegotiationInfo bool
+
+ // BadRenegotiationInfo causes the renegotiation extension value in a
+ // renegotiation handshake to be incorrect.
+ BadRenegotiationInfo bool
+
+ // NoRenegotiationInfo disables renegotiation info support in all
+ // handshakes.
+ NoRenegotiationInfo bool
+
+ // NoRenegotiationInfoInInitial disables renegotiation info support in
+ // the initial handshake.
+ NoRenegotiationInfoInInitial bool
+
+ // NoRenegotiationInfoAfterInitial disables renegotiation info support
+ // in renegotiation handshakes.
+ NoRenegotiationInfoAfterInitial bool
+
+ // RequireRenegotiationInfo, if true, causes the client to return an
+ // error if the server doesn't reply with the renegotiation extension.
+ RequireRenegotiationInfo bool
+
+ // SequenceNumberMapping, if non-nil, is the mapping function to apply
+ // to the sequence number of outgoing packets. For both TLS and DTLS,
+ // the two most-significant bytes in the resulting sequence number are
+ // ignored so that the DTLS epoch cannot be changed.
+ SequenceNumberMapping func(uint64) uint64
+
+ // RSAEphemeralKey, if true, causes the server to send a
+ // ServerKeyExchange message containing an ephemeral key (as in
+ // RSA_EXPORT) in the plain RSA key exchange.
+ RSAEphemeralKey bool
+
+ // SRTPMasterKeyIdentifer, if not empty, is the SRTP MKI value that the
+ // client offers when negotiating SRTP. MKI support is still missing so
+ // the peer must still send none.
+ SRTPMasterKeyIdentifer string
+
+ // SendSRTPProtectionProfile, if non-zero, is the SRTP profile that the
+ // server sends in the ServerHello instead of the negotiated one.
+ SendSRTPProtectionProfile uint16
+
+ // NoSignatureAlgorithms, if true, causes the client to omit the
+ // signature and hashes extension.
+ //
+ // For a server, it will cause an empty list to be sent in the
+ // CertificateRequest message. None the less, the configured set will
+ // still be enforced.
+ NoSignatureAlgorithms bool
+
+ // NoSupportedCurves, if true, causes the client to omit the
+ // supported_curves extension.
+ NoSupportedCurves bool
+
+ // RequireSameRenegoClientVersion, if true, causes the server
+ // to require that all ClientHellos match in offered version
+ // across a renego.
+ RequireSameRenegoClientVersion bool
+
+ // ExpectInitialRecordVersion, if non-zero, is the expected value of
+ // record-layer version field before the protocol version is determined.
+ ExpectInitialRecordVersion uint16
+
+ // SendRecordVersion, if non-zero, is the value to send as the
+ // record-layer version.
+ SendRecordVersion uint16
+
+ // SendInitialRecordVersion, if non-zero, is the value to send as the
+ // record-layer version before the protocol version is determined.
+ SendInitialRecordVersion uint16
+
+ // MaxPacketLength, if non-zero, is the maximum acceptable size for a
+ // packet.
+ MaxPacketLength int
+
+ // SendCipherSuite, if non-zero, is the cipher suite value that the
+ // server will send in the ServerHello. This does not affect the cipher
+ // the server believes it has actually negotiated.
+ SendCipherSuite uint16
+
+ // SendCipherSuites, if not nil, is the cipher suite list that the
+ // client will send in the ClientHello. This does not affect the cipher
+ // the client believes it has actually offered.
+ SendCipherSuites []uint16
+
+ // AppDataBeforeHandshake, if not nil, causes application data to be
+ // sent immediately before the first handshake message.
+ AppDataBeforeHandshake []byte
+
+ // AppDataAfterChangeCipherSpec, if not nil, causes application data to
+ // be sent immediately after ChangeCipherSpec.
+ AppDataAfterChangeCipherSpec []byte
+
+ // AlertAfterChangeCipherSpec, if non-zero, causes an alert to be sent
+ // immediately after ChangeCipherSpec.
+ AlertAfterChangeCipherSpec alert
+
+ // TimeoutSchedule is the schedule of packet drops and simulated
+ // timeouts for before each handshake leg from the peer.
+ TimeoutSchedule []time.Duration
+
+ // PacketAdaptor is the packetAdaptor to use to simulate timeouts.
+ PacketAdaptor *packetAdaptor
+
+ // ReorderHandshakeFragments, if true, causes handshake fragments in
+ // DTLS to overlap and be sent in the wrong order. It also causes
+ // pre-CCS flights to be sent twice. (Post-CCS flights consist of
+ // Finished and will trigger a spurious retransmit.)
+ ReorderHandshakeFragments bool
+
+ // ReverseHandshakeFragments, if true, causes handshake fragments in
+ // DTLS to be reversed within a flight.
+ ReverseHandshakeFragments bool
+
+ // MixCompleteMessageWithFragments, if true, causes handshake
+ // messages in DTLS to redundantly both fragment the message
+ // and include a copy of the full one.
+ MixCompleteMessageWithFragments bool
+
+ // SendInvalidRecordType, if true, causes a record with an invalid
+ // content type to be sent immediately following the handshake.
+ SendInvalidRecordType bool
+
+ // SendWrongMessageType, if non-zero, causes messages of the specified
+ // type to be sent with the wrong value.
+ SendWrongMessageType byte
+
+ // SendTrailingMessageData, if non-zero, causes messages of the
+ // specified type to be sent with trailing data.
+ SendTrailingMessageData byte
+
+ // FragmentMessageTypeMismatch, if true, causes all non-initial
+ // handshake fragments in DTLS to have the wrong message type.
+ FragmentMessageTypeMismatch bool
+
+ // FragmentMessageLengthMismatch, if true, causes all non-initial
+ // handshake fragments in DTLS to have the wrong message length.
+ FragmentMessageLengthMismatch bool
+
+ // SplitFragments, if non-zero, causes the handshake fragments in DTLS
+ // to be split across two records. The value of |SplitFragments| is the
+ // number of bytes in the first fragment.
+ SplitFragments int
+
+ // SendEmptyFragments, if true, causes handshakes to include empty
+ // fragments in DTLS.
+ SendEmptyFragments bool
+
+ // SendSplitAlert, if true, causes an alert to be sent with the header
+ // and record body split across multiple packets. The peer should
+ // discard these packets rather than process it.
+ SendSplitAlert bool
+
+ // FailIfResumeOnRenego, if true, causes renegotiations to fail if the
+ // client offers a resumption or the server accepts one.
+ FailIfResumeOnRenego bool
+
+ // IgnorePeerCipherPreferences, if true, causes the peer's cipher
+ // preferences to be ignored.
+ IgnorePeerCipherPreferences bool
+
+ // IgnorePeerSignatureAlgorithmPreferences, if true, causes the peer's
+ // signature algorithm preferences to be ignored.
+ IgnorePeerSignatureAlgorithmPreferences bool
+
+ // IgnorePeerCurvePreferences, if true, causes the peer's curve
+ // preferences to be ignored.
+ IgnorePeerCurvePreferences bool
+
+ // BadFinished, if true, causes the Finished hash to be broken.
+ BadFinished bool
+
+ // DHGroupPrime, if not nil, is used to define the (finite field)
+ // Diffie-Hellman group. The generator used is always two.
+ DHGroupPrime *big.Int
+
+ // PackHandshakeFragments, if true, causes handshake fragments in DTLS
+ // to be packed into individual handshake records, up to the specified
+ // record size.
+ PackHandshakeFragments int
+
+ // PackHandshakeRecords, if true, causes handshake records in DTLS to be
+ // packed into individual packets, up to the specified packet size.
+ PackHandshakeRecords int
+
+ // PackHandshakeFlight, if true, causes each handshake flight in TLS to
+ // be packed into records, up to the largest size record available.
+ PackHandshakeFlight bool
+
+ // AdvertiseAllConfiguredCiphers, if true, causes the client to
+ // advertise all configured cipher suite values.
+ AdvertiseAllConfiguredCiphers bool
+
+ // EmptyCertificateList, if true, causes the server to send an empty
+ // certificate list in the Certificate message.
+ EmptyCertificateList bool
+
+ // ExpectNewTicket, if true, causes the client to abort if it does not
+ // receive a new ticket.
+ ExpectNewTicket bool
+
+ // RequireClientHelloSize, if not zero, is the required length in bytes
+ // of the ClientHello /record/. This is checked by the server.
+ RequireClientHelloSize int
+
+ // CustomExtension, if not empty, contains the contents of an extension
+ // that will be added to client/server hellos.
+ CustomExtension string
+
+ // CustomUnencryptedExtension, if not empty, contains the contents of
+ // an extension that will be added to ServerHello in TLS 1.3.
+ CustomUnencryptedExtension string
+
+ // ExpectedCustomExtension, if not nil, contains the expected contents
+ // of a custom extension.
+ ExpectedCustomExtension *string
+
+ // CustomTicketExtension, if not empty, contains the contents of an
+ // extension what will be added to NewSessionTicket in TLS 1.3.
+ CustomTicketExtension string
+
+ // CustomTicketExtension, if not empty, contains the contents of an
+ // extension what will be added to HelloRetryRequest in TLS 1.3.
+ CustomHelloRetryRequestExtension string
+
+ // NoCloseNotify, if true, causes the close_notify alert to be skipped
+ // on connection shutdown.
+ NoCloseNotify bool
+
+ // SendAlertOnShutdown, if non-zero, is the alert to send instead of
+ // close_notify on shutdown.
+ SendAlertOnShutdown alert
+
+ // ExpectCloseNotify, if true, requires a close_notify from the peer on
+ // shutdown. Records from the peer received after close_notify is sent
+ // are not discard.
+ ExpectCloseNotify bool
+
+ // SendLargeRecords, if true, allows outgoing records to be sent
+ // arbitrarily large.
+ SendLargeRecords bool
+
+ // NegotiateALPNAndNPN, if true, causes the server to negotiate both
+ // ALPN and NPN in the same connetion.
+ NegotiateALPNAndNPN bool
+
+ // SendALPN, if non-empty, causes the server to send the specified
+ // string in the ALPN extension regardless of the content or presence of
+ // the client offer.
+ SendALPN string
+
+ // SendUnencryptedALPN, if non-empty, causes the server to send the
+ // specified string in a ServerHello ALPN extension in TLS 1.3.
+ SendUnencryptedALPN string
+
+ // SendEmptySessionTicket, if true, causes the server to send an empty
+ // session ticket.
+ SendEmptySessionTicket bool
+
+ // SendPSKKeyExchangeModes, if present, determines the PSK key exchange modes
+ // to send.
+ SendPSKKeyExchangeModes []byte
+
+ // ExpectNoNewSessionTicket, if present, means that the client will fail upon
+ // receipt of a NewSessionTicket message.
+ ExpectNoNewSessionTicket bool
+
+ // DuplicateTicketEarlyDataInfo causes an extra empty extension of
+ // ticket_early_data_info to be sent in NewSessionTicket.
+ DuplicateTicketEarlyDataInfo bool
+
+ // ExpectTicketEarlyDataInfo, if true, means that the client will fail upon
+ // absence of the ticket_early_data_info extension.
+ ExpectTicketEarlyDataInfo bool
+
+ // ExpectTicketAge, if non-zero, is the expected age of the ticket that the
+ // server receives from the client.
+ ExpectTicketAge time.Duration
+
+ // SendTicketAge, if non-zero, is the ticket age to be sent by the
+ // client.
+ SendTicketAge time.Duration
+
+ // FailIfSessionOffered, if true, causes the server to fail any
+ // connections where the client offers a non-empty session ID or session
+ // ticket.
+ FailIfSessionOffered bool
+
+ // SendHelloRequestBeforeEveryAppDataRecord, if true, causes a
+ // HelloRequest handshake message to be sent before each application
+ // data record. This only makes sense for a server.
+ SendHelloRequestBeforeEveryAppDataRecord bool
+
+ // SendHelloRequestBeforeEveryHandshakeMessage, if true, causes a
+ // HelloRequest handshake message to be sent before each handshake
+ // message. This only makes sense for a server.
+ SendHelloRequestBeforeEveryHandshakeMessage bool
+
+ // RequireDHPublicValueLen causes a fatal error if the length (in
+ // bytes) of the server's Diffie-Hellman public value is not equal to
+ // this.
+ RequireDHPublicValueLen int
+
+ // BadChangeCipherSpec, if not nil, is the body to be sent in
+ // ChangeCipherSpec records instead of {1}.
+ BadChangeCipherSpec []byte
+
+ // BadHelloRequest, if not nil, is what to send instead of a
+ // HelloRequest.
+ BadHelloRequest []byte
+
+ // RequireSessionTickets, if true, causes the client to require new
+ // sessions use session tickets instead of session IDs.
+ RequireSessionTickets bool
+
+ // NullAllCiphers, if true, causes every cipher to behave like the null
+ // cipher.
+ NullAllCiphers bool
+
+ // SendSCTListOnResume, if not nil, causes the server to send the
+ // supplied SCT list in resumption handshakes.
+ SendSCTListOnResume []byte
+
+ // SendOCSPResponseOnResume, if not nil, causes the server to advertise
+ // OCSP stapling in resumption handshakes and, if applicable, send the
+ // supplied stapled response.
+ SendOCSPResponseOnResume []byte
+
+ // SendExtensionOnCertificate, if not nil, causes the runner to send the
+ // supplied bytes in the extensions on the Certificate message.
+ SendExtensionOnCertificate []byte
+
+ // SendOCSPOnIntermediates, if not nil, causes the server to send the
+ // supplied OCSP on intermediate certificates in the Certificate message.
+ SendOCSPOnIntermediates []byte
+
+ // SendSCTOnIntermediates, if not nil, causes the server to send the
+ // supplied SCT on intermediate certificates in the Certificate message.
+ SendSCTOnIntermediates []byte
+
+ // SendDuplicateCertExtensions, if true, causes the server to send an extra
+ // copy of the OCSP/SCT extensions in the Certificate message.
+ SendDuplicateCertExtensions bool
+
+ // ExpectNoExtensionsOnIntermediate, if true, causes the client to
+ // reject extensions on intermediate certificates.
+ ExpectNoExtensionsOnIntermediate bool
+
+ // RecordPadding is the number of bytes of padding to add to each
+ // encrypted record in TLS 1.3.
+ RecordPadding int
+
+ // OmitRecordContents, if true, causes encrypted records in TLS 1.3 to
+ // be missing their body and content type. Padding, if configured, is
+ // still added.
+ OmitRecordContents bool
+
+ // OuterRecordType, if non-zero, is the outer record type to use instead
+ // of application data.
+ OuterRecordType recordType
+
+ // SendSignatureAlgorithm, if non-zero, causes all signatures to be sent
+ // with the given signature algorithm rather than the one negotiated.
+ SendSignatureAlgorithm signatureAlgorithm
+
+ // SkipECDSACurveCheck, if true, causes all ECDSA curve checks to be
+ // skipped.
+ SkipECDSACurveCheck bool
+
+ // IgnoreSignatureVersionChecks, if true, causes all signature
+ // algorithms to be enabled at all TLS versions.
+ IgnoreSignatureVersionChecks bool
+
+ // NegotiateRenegotiationInfoAtAllVersions, if true, causes
+ // Renegotiation Info to be negotiated at all versions.
+ NegotiateRenegotiationInfoAtAllVersions bool
+
+ // NegotiateNPNAtAllVersions, if true, causes NPN to be negotiated at
+ // all versions.
+ NegotiateNPNAtAllVersions bool
+
+ // NegotiateEMSAtAllVersions, if true, causes EMS to be negotiated at
+ // all versions.
+ NegotiateEMSAtAllVersions bool
+
+ // AdvertiseTicketExtension, if true, causes the ticket extension to be
+ // advertised in server extensions
+ AdvertiseTicketExtension bool
+
+ // NegotiatePSKResumption, if true, causes the server to attempt pure PSK
+ // resumption.
+ NegotiatePSKResumption bool
+
+ // AlwaysSelectPSKIdentity, if true, causes the server in TLS 1.3 to
+ // always acknowledge a session, regardless of one was offered.
+ AlwaysSelectPSKIdentity bool
+
+ // SelectPSKIdentityOnResume, if non-zero, causes the server to select
+ // the specified PSK identity index rather than the actual value.
+ SelectPSKIdentityOnResume uint16
+
+ // ExtraPSKIdentity, if true, causes the client to send an extra PSK
+ // identity.
+ ExtraPSKIdentity bool
+
+ // MissingKeyShare, if true, causes the TLS 1.3 implementation to skip
+ // sending a key_share extension and use the zero ECDHE secret
+ // instead.
+ MissingKeyShare bool
+
+ // SecondClientHelloMissingKeyShare, if true, causes the second TLS 1.3
+ // ClientHello to skip sending a key_share extension and use the zero
+ // ECDHE secret instead.
+ SecondClientHelloMissingKeyShare bool
+
+ // MisinterpretHelloRetryRequestCurve, if non-zero, causes the TLS 1.3
+ // client to pretend the server requested a HelloRetryRequest with the
+ // given curve rather than the actual one.
+ MisinterpretHelloRetryRequestCurve CurveID
+
+ // DuplicateKeyShares, if true, causes the TLS 1.3 client to send two
+ // copies of each KeyShareEntry.
+ DuplicateKeyShares bool
+
+ // SendEarlyAlert, if true, sends a fatal alert after the ClientHello.
+ SendEarlyAlert bool
+
+ // SendFakeEarlyDataLength, if non-zero, is the amount of early data to
+ // send after the ClientHello.
+ SendFakeEarlyDataLength int
+
+ // OmitEarlyDataExtension, if true, causes the early data extension to
+ // be omitted in the ClientHello.
+ OmitEarlyDataExtension bool
+
+ // SendEarlyDataOnSecondClientHello, if true, causes the TLS 1.3 client to
+ // send early data after the second ClientHello.
+ SendEarlyDataOnSecondClientHello bool
+
+ // InterleaveEarlyData, if true, causes the TLS 1.3 client to send early
+ // data interleaved with the second ClientHello and the client Finished.
+ InterleaveEarlyData bool
+
+ // SendEarlyData causes a TLS 1.3 client to send the provided data
+ // in application data records immediately after the ClientHello,
+ // provided that the client has a PSK that is appropriate for sending
+ // early data and includes that PSK in its ClientHello.
+ SendEarlyData [][]byte
+
+ // ExpectEarlyData causes a TLS 1.3 server to read application
+ // data after the ClientHello (assuming the server is able to
+ // derive the key under which the data is encrypted) before it
+ // sends a ServerHello. It checks that the application data it
+ // reads matches what is provided in ExpectEarlyData and errors if
+ // the number of records or their content do not match.
+ ExpectEarlyData [][]byte
+
+ // SendHalfRTTData causes a TLS 1.3 server to send the provided
+ // data in application data records before reading the client's
+ // Finished message.
+ SendHalfRTTData [][]byte
+
+ // ExpectHalfRTTData causes a TLS 1.3 client to read application
+ // data after reading the server's Finished message and before
+ // sending any other handshake messages. It checks that the
+ // application data it reads matches what is provided in
+ // ExpectHalfRTTData and errors if the number of records or their
+ // content do not match.
+ ExpectHalfRTTData [][]byte
+
+ // EmptyEncryptedExtensions, if true, causes the TLS 1.3 server to
+ // emit an empty EncryptedExtensions block.
+ EmptyEncryptedExtensions bool
+
+ // EncryptedExtensionsWithKeyShare, if true, causes the TLS 1.3 server to
+ // include the KeyShare extension in the EncryptedExtensions block.
+ EncryptedExtensionsWithKeyShare bool
+
+ // AlwaysSendHelloRetryRequest, if true, causes a HelloRetryRequest to
+ // be sent by the server, even if empty.
+ AlwaysSendHelloRetryRequest bool
+
+ // SecondHelloRetryRequest, if true, causes the TLS 1.3 server to send
+ // two HelloRetryRequests instead of one.
+ SecondHelloRetryRequest bool
+
+ // SendHelloRetryRequestCurve, if non-zero, causes the server to send
+ // the specified curve in a HelloRetryRequest.
+ SendHelloRetryRequestCurve CurveID
+
+ // SendHelloRetryRequestCookie, if not nil, contains a cookie to be
+ // sent by the server in HelloRetryRequest.
+ SendHelloRetryRequestCookie []byte
+
+ // DuplicateHelloRetryRequestExtensions, if true, causes all
+ // HelloRetryRequest extensions to be sent twice.
+ DuplicateHelloRetryRequestExtensions bool
+
+ // SendServerHelloVersion, if non-zero, causes the server to send the
+ // specified value in ServerHello version field.
+ SendServerHelloVersion uint16
+
+ // SkipHelloRetryRequest, if true, causes the TLS 1.3 server to not send
+ // HelloRetryRequest.
+ SkipHelloRetryRequest bool
+
+ // PackHelloRequestWithFinished, if true, causes the TLS server to send
+ // HelloRequest in the same record as Finished.
+ PackHelloRequestWithFinished bool
+
+ // ExpectMissingKeyShare, if true, causes the TLS server to fail the
+ // connection if the selected curve appears in the client's initial
+ // ClientHello. That is, it requires that a HelloRetryRequest be sent.
+ ExpectMissingKeyShare bool
+
+ // SendExtraFinished, if true, causes an extra Finished message to be
+ // sent.
+ SendExtraFinished bool
+
+ // SendRequestContext, if not empty, is the request context to send in
+ // a TLS 1.3 CertificateRequest.
+ SendRequestContext []byte
+
+ // SendSNIWarningAlert, if true, causes the server to send an
+ // unrecognized_name alert before the ServerHello.
+ SendSNIWarningAlert bool
+
+ // SendCompressionMethods, if not nil, is the compression method list to
+ // send in the ClientHello.
+ SendCompressionMethods []byte
+
+ // AlwaysSendPreSharedKeyIdentityHint, if true, causes the server to
+ // always send a ServerKeyExchange for PSK ciphers, even if the identity
+ // hint is empty.
+ AlwaysSendPreSharedKeyIdentityHint bool
+
+ // TrailingKeyShareData, if true, causes the client key share list to
+ // include a trailing byte.
+ TrailingKeyShareData bool
+
+ // InvalidChannelIDSignature, if true, causes the client to generate an
+ // invalid Channel ID signature.
+ InvalidChannelIDSignature bool
+
+ // ExpectGREASE, if true, causes messages without GREASE values to be
+ // rejected. See draft-davidben-tls-grease-01.
+ ExpectGREASE bool
+
+ // SendShortPSKBinder, if true, causes the client to send a PSK binder
+ // that is one byte shorter than it should be.
+ SendShortPSKBinder bool
+
+ // SendInvalidPSKBinder, if true, causes the client to send an invalid
+ // PSK binder.
+ SendInvalidPSKBinder bool
+
+ // SendNoPSKBinder, if true, causes the client to send no PSK binders.
+ SendNoPSKBinder bool
+
+ // SendExtraPSKBinder, if true, causes the client to send an extra PSK
+ // binder.
+ SendExtraPSKBinder bool
+
+ // PSKBinderFirst, if true, causes the client to send the PSK Binder
+ // extension as the first extension instead of the last extension.
+ PSKBinderFirst bool
+
+ // NoOCSPStapling, if true, causes the client to not request OCSP
+ // stapling.
+ NoOCSPStapling bool
+
+ // NoSignedCertificateTimestamps, if true, causes the client to not
+ // request signed certificate timestamps.
+ NoSignedCertificateTimestamps bool
+
+ // SendSupportedPointFormats, if not nil, is the list of supported point
+ // formats to send in ClientHello or ServerHello. If set to a non-nil
+ // empty slice, no extension will be sent.
+ SendSupportedPointFormats []byte
+
+ // MaxReceivePlaintext, if non-zero, is the maximum plaintext record
+ // length accepted from the peer.
+ MaxReceivePlaintext int
+
+ // SendTicketLifetime, if non-zero, is the ticket lifetime to send in
+ // NewSessionTicket messages.
+ SendTicketLifetime time.Duration
+
+ // SendServerNameAck, if true, causes the server to acknowledge the SNI
+ // extension.
+ SendServerNameAck bool
+
+ // ExpectCertificateReqNames, if not nil, contains the list of X.509
+ // names that must be sent in a CertificateRequest from the server.
+ ExpectCertificateReqNames [][]byte
+
+ // RenegotiationCertificate, if not nil, is the certificate to use on
+ // renegotiation handshakes.
+ RenegotiationCertificate *Certificate
+}
+
+func (c *Config) serverInit() {
+ if c.SessionTicketsDisabled {
+ return
+ }
+
+ // If the key has already been set then we have nothing to do.
+ for _, b := range c.SessionTicketKey {
+ if b != 0 {
+ return
+ }
+ }
+
+ if _, err := io.ReadFull(c.rand(), c.SessionTicketKey[:]); err != nil {
+ c.SessionTicketsDisabled = true
+ }
+}
+
+func (c *Config) rand() io.Reader {
+ r := c.Rand
+ if r == nil {
+ return rand.Reader
+ }
+ return r
+}
+
+func (c *Config) time() time.Time {
+ t := c.Time
+ if t == nil {
+ t = time.Now
+ }
+ return t()
+}
+
+func (c *Config) cipherSuites() []uint16 {
+ s := c.CipherSuites
+ if s == nil {
+ s = defaultCipherSuites()
+ }
+ return s
+}
+
+func (c *Config) minVersion(isDTLS bool) uint16 {
+ ret := uint16(minVersion)
+ if c != nil && c.MinVersion != 0 {
+ ret = c.MinVersion
+ }
+ if isDTLS {
+ // The lowest version of DTLS is 1.0. There is no DSSL 3.0.
+ if ret < VersionTLS10 {
+ return VersionTLS10
+ }
+ // There is no such thing as DTLS 1.1.
+ if ret == VersionTLS11 {
+ return VersionTLS12
+ }
+ }
+ return ret
+}
+
+func (c *Config) maxVersion(isDTLS bool) uint16 {
+ ret := uint16(maxVersion)
+ if c != nil && c.MaxVersion != 0 {
+ ret = c.MaxVersion
+ }
+ if isDTLS {
+ // We only implement up to DTLS 1.2.
+ if ret > VersionTLS12 {
+ return VersionTLS12
+ }
+ // There is no such thing as DTLS 1.1.
+ if ret == VersionTLS11 {
+ return VersionTLS10
+ }
+ }
+ return ret
+}
+
+var defaultCurvePreferences = []CurveID{CurveX25519, CurveP256, CurveP384, CurveP521}
+
+func (c *Config) curvePreferences() []CurveID {
+ if c == nil || len(c.CurvePreferences) == 0 {
+ return defaultCurvePreferences
+ }
+ return c.CurvePreferences
+}
+
+func (c *Config) defaultCurves() map[CurveID]bool {
+ defaultCurves := make(map[CurveID]bool)
+ curves := c.DefaultCurves
+ if c == nil || c.DefaultCurves == nil {
+ curves = c.curvePreferences()
+ }
+ for _, curveID := range curves {
+ defaultCurves[curveID] = true
+ }
+ return defaultCurves
+}
+
+// isSupportedVersion returns true if the specified protocol version is
+// acceptable.
+func (c *Config) isSupportedVersion(vers uint16, isDTLS bool) bool {
+ return c.minVersion(isDTLS) <= vers && vers <= c.maxVersion(isDTLS)
+}
+
+// getCertificateForName returns the best certificate for the given name,
+// defaulting to the first element of c.Certificates if there are no good
+// options.
+func (c *Config) getCertificateForName(name string) *Certificate {
+ if len(c.Certificates) == 1 || c.NameToCertificate == nil {
+ // There's only one choice, so no point doing any work.
+ return &c.Certificates[0]
+ }
+
+ name = strings.ToLower(name)
+ for len(name) > 0 && name[len(name)-1] == '.' {
+ name = name[:len(name)-1]
+ }
+
+ if cert, ok := c.NameToCertificate[name]; ok {
+ return cert
+ }
+
+ // try replacing labels in the name with wildcards until we get a
+ // match.
+ labels := strings.Split(name, ".")
+ for i := range labels {
+ labels[i] = "*"
+ candidate := strings.Join(labels, ".")
+ if cert, ok := c.NameToCertificate[candidate]; ok {
+ return cert
+ }
+ }
+
+ // If nothing matches, return the first certificate.
+ return &c.Certificates[0]
+}
+
+func (c *Config) signSignatureAlgorithms() []signatureAlgorithm {
+ if c != nil && c.SignSignatureAlgorithms != nil {
+ return c.SignSignatureAlgorithms
+ }
+ return supportedSignatureAlgorithms
+}
+
+func (c *Config) verifySignatureAlgorithms() []signatureAlgorithm {
+ if c != nil && c.VerifySignatureAlgorithms != nil {
+ return c.VerifySignatureAlgorithms
+ }
+ return supportedSignatureAlgorithms
+}
+
+// BuildNameToCertificate parses c.Certificates and builds c.NameToCertificate
+// from the CommonName and SubjectAlternateName fields of each of the leaf
+// certificates.
+func (c *Config) BuildNameToCertificate() {
+ c.NameToCertificate = make(map[string]*Certificate)
+ for i := range c.Certificates {
+ cert := &c.Certificates[i]
+ x509Cert, err := x509.ParseCertificate(cert.Certificate[0])
+ if err != nil {
+ continue
+ }
+ if len(x509Cert.Subject.CommonName) > 0 {
+ c.NameToCertificate[x509Cert.Subject.CommonName] = cert
+ }
+ for _, san := range x509Cert.DNSNames {
+ c.NameToCertificate[san] = cert
+ }
+ }
+}
+
+// A Certificate is a chain of one or more certificates, leaf first.
+type Certificate struct {
+ Certificate [][]byte
+ PrivateKey crypto.PrivateKey // supported types: *rsa.PrivateKey, *ecdsa.PrivateKey
+ // OCSPStaple contains an optional OCSP response which will be served
+ // to clients that request it.
+ OCSPStaple []byte
+ // SignedCertificateTimestampList contains an optional encoded
+ // SignedCertificateTimestampList structure which will be
+ // served to clients that request it.
+ SignedCertificateTimestampList []byte
+ // Leaf is the parsed form of the leaf certificate, which may be
+ // initialized using x509.ParseCertificate to reduce per-handshake
+ // processing for TLS clients doing client authentication. If nil, the
+ // leaf certificate will be parsed as needed.
+ Leaf *x509.Certificate
+}
+
+// A TLS record.
+type record struct {
+ contentType recordType
+ major, minor uint8
+ payload []byte
+}
+
+type handshakeMessage interface {
+ marshal() []byte
+ unmarshal([]byte) bool
+}
+
+// lruSessionCache is a client or server session cache implementation
+// that uses an LRU caching strategy.
+type lruSessionCache struct {
+ sync.Mutex
+
+ m map[string]*list.Element
+ q *list.List
+ capacity int
+}
+
+type lruSessionCacheEntry struct {
+ sessionKey string
+ state interface{}
+}
+
+// Put adds the provided (sessionKey, cs) pair to the cache.
+func (c *lruSessionCache) Put(sessionKey string, cs interface{}) {
+ c.Lock()
+ defer c.Unlock()
+
+ if elem, ok := c.m[sessionKey]; ok {
+ entry := elem.Value.(*lruSessionCacheEntry)
+ entry.state = cs
+ c.q.MoveToFront(elem)
+ return
+ }
+
+ if c.q.Len() < c.capacity {
+ entry := &lruSessionCacheEntry{sessionKey, cs}
+ c.m[sessionKey] = c.q.PushFront(entry)
+ return
+ }
+
+ elem := c.q.Back()
+ entry := elem.Value.(*lruSessionCacheEntry)
+ delete(c.m, entry.sessionKey)
+ entry.sessionKey = sessionKey
+ entry.state = cs
+ c.q.MoveToFront(elem)
+ c.m[sessionKey] = elem
+}
+
+// Get returns the value associated with a given key. It returns (nil,
+// false) if no value is found.
+func (c *lruSessionCache) Get(sessionKey string) (interface{}, bool) {
+ c.Lock()
+ defer c.Unlock()
+
+ if elem, ok := c.m[sessionKey]; ok {
+ c.q.MoveToFront(elem)
+ return elem.Value.(*lruSessionCacheEntry).state, true
+ }
+ return nil, false
+}
+
+// lruClientSessionCache is a ClientSessionCache implementation that
+// uses an LRU caching strategy.
+type lruClientSessionCache struct {
+ lruSessionCache
+}
+
+func (c *lruClientSessionCache) Put(sessionKey string, cs *ClientSessionState) {
+ c.lruSessionCache.Put(sessionKey, cs)
+}
+
+func (c *lruClientSessionCache) Get(sessionKey string) (*ClientSessionState, bool) {
+ cs, ok := c.lruSessionCache.Get(sessionKey)
+ if !ok {
+ return nil, false
+ }
+ return cs.(*ClientSessionState), true
+}
+
+// lruServerSessionCache is a ServerSessionCache implementation that
+// uses an LRU caching strategy.
+type lruServerSessionCache struct {
+ lruSessionCache
+}
+
+func (c *lruServerSessionCache) Put(sessionId string, session *sessionState) {
+ c.lruSessionCache.Put(sessionId, session)
+}
+
+func (c *lruServerSessionCache) Get(sessionId string) (*sessionState, bool) {
+ cs, ok := c.lruSessionCache.Get(sessionId)
+ if !ok {
+ return nil, false
+ }
+ return cs.(*sessionState), true
+}
+
+// NewLRUClientSessionCache returns a ClientSessionCache with the given
+// capacity that uses an LRU strategy. If capacity is < 1, a default capacity
+// is used instead.
+func NewLRUClientSessionCache(capacity int) ClientSessionCache {
+ const defaultSessionCacheCapacity = 64
+
+ if capacity < 1 {
+ capacity = defaultSessionCacheCapacity
+ }
+ return &lruClientSessionCache{
+ lruSessionCache{
+ m: make(map[string]*list.Element),
+ q: list.New(),
+ capacity: capacity,
+ },
+ }
+}
+
+// NewLRUServerSessionCache returns a ServerSessionCache with the given
+// capacity that uses an LRU strategy. If capacity is < 1, a default capacity
+// is used instead.
+func NewLRUServerSessionCache(capacity int) ServerSessionCache {
+ const defaultSessionCacheCapacity = 64
+
+ if capacity < 1 {
+ capacity = defaultSessionCacheCapacity
+ }
+ return &lruServerSessionCache{
+ lruSessionCache{
+ m: make(map[string]*list.Element),
+ q: list.New(),
+ capacity: capacity,
+ },
+ }
+}
+
+// TODO(jsing): Make these available to both crypto/x509 and crypto/tls.
+type dsaSignature struct {
+ R, S *big.Int
+}
+
+type ecdsaSignature dsaSignature
+
+var emptyConfig Config
+
+func defaultConfig() *Config {
+ return &emptyConfig
+}
+
+var (
+ once sync.Once
+ varDefaultCipherSuites []uint16
+)
+
+func defaultCipherSuites() []uint16 {
+ once.Do(initDefaultCipherSuites)
+ return varDefaultCipherSuites
+}
+
+func initDefaultCipherSuites() {
+ for _, suite := range cipherSuites {
+ if suite.flags&suitePSK == 0 {
+ varDefaultCipherSuites = append(varDefaultCipherSuites, suite.id)
+ }
+ }
+}
+
+func unexpectedMessageError(wanted, got interface{}) error {
+ return fmt.Errorf("tls: received unexpected handshake message of type %T when waiting for %T", got, wanted)
+}
+
+func isSupportedSignatureAlgorithm(sigAlg signatureAlgorithm, sigAlgs []signatureAlgorithm) bool {
+ for _, s := range sigAlgs {
+ if s == sigAlg {
+ return true
+ }
+ }
+ return false
+}
+
+var (
+ // See draft-ietf-tls-tls13-16, section 6.3.1.2.
+ downgradeTLS13 = []byte{0x44, 0x4f, 0x57, 0x4e, 0x47, 0x52, 0x44, 0x01}
+ downgradeTLS12 = []byte{0x44, 0x4f, 0x57, 0x4e, 0x47, 0x52, 0x44, 0x00}
+)
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/conn.go b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/conn.go
new file mode 100644
index 000000000..1bdca84de
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/conn.go
@@ -0,0 +1,1843 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// TLS low level connection and record layer
+
+package runner
+
+import (
+ "bytes"
+ "crypto/cipher"
+ "crypto/ecdsa"
+ "crypto/subtle"
+ "crypto/x509"
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "io"
+ "net"
+ "sync"
+ "time"
+)
+
+var errNoCertificateAlert = errors.New("tls: no certificate alert")
+var errEndOfEarlyDataAlert = errors.New("tls: end of early data alert")
+
+// A Conn represents a secured connection.
+// It implements the net.Conn interface.
+type Conn struct {
+ // constant
+ conn net.Conn
+ isDTLS bool
+ isClient bool
+
+ // constant after handshake; protected by handshakeMutex
+ handshakeMutex sync.Mutex // handshakeMutex < in.Mutex, out.Mutex, errMutex
+ handshakeErr error // error resulting from handshake
+ vers uint16 // TLS version
+ haveVers bool // version has been negotiated
+ config *Config // configuration passed to constructor
+ handshakeComplete bool
+ skipEarlyData bool // On a server, indicates that the client is sending early data that must be skipped over.
+ didResume bool // whether this connection was a session resumption
+ extendedMasterSecret bool // whether this session used an extended master secret
+ cipherSuite *cipherSuite
+ ocspResponse []byte // stapled OCSP response
+ sctList []byte // signed certificate timestamp list
+ peerCertificates []*x509.Certificate
+ // verifiedChains contains the certificate chains that we built, as
+ // opposed to the ones presented by the server.
+ verifiedChains [][]*x509.Certificate
+ // serverName contains the server name indicated by the client, if any.
+ serverName string
+ // firstFinished contains the first Finished hash sent during the
+ // handshake. This is the "tls-unique" channel binding value.
+ firstFinished [12]byte
+ // peerSignatureAlgorithm contains the signature algorithm that was used
+ // by the peer in the handshake, or zero if not applicable.
+ peerSignatureAlgorithm signatureAlgorithm
+ // curveID contains the curve that was used in the handshake, or zero if
+ // not applicable.
+ curveID CurveID
+
+ clientRandom, serverRandom [32]byte
+ exporterSecret []byte
+ resumptionSecret []byte
+
+ clientProtocol string
+ clientProtocolFallback bool
+ usedALPN bool
+
+ // verify_data values for the renegotiation extension.
+ clientVerify []byte
+ serverVerify []byte
+
+ channelID *ecdsa.PublicKey
+
+ srtpProtectionProfile uint16
+
+ clientVersion uint16
+
+ // input/output
+ in, out halfConn // in.Mutex < out.Mutex
+ rawInput *block // raw input, right off the wire
+ input *block // application record waiting to be read
+ hand bytes.Buffer // handshake record waiting to be read
+
+ // pendingFlight, if PackHandshakeFlight is enabled, is the buffer of
+ // handshake data to be split into records at the end of the flight.
+ pendingFlight bytes.Buffer
+
+ // DTLS state
+ sendHandshakeSeq uint16
+ recvHandshakeSeq uint16
+ handMsg []byte // pending assembled handshake message
+ handMsgLen int // handshake message length, not including the header
+ pendingFragments [][]byte // pending outgoing handshake fragments.
+
+ keyUpdateRequested bool
+
+ tmp [16]byte
+}
+
+func (c *Conn) init() {
+ c.in.isDTLS = c.isDTLS
+ c.out.isDTLS = c.isDTLS
+ c.in.config = c.config
+ c.out.config = c.config
+
+ c.out.updateOutSeq()
+}
+
+// Access to net.Conn methods.
+// Cannot just embed net.Conn because that would
+// export the struct field too.
+
+// LocalAddr returns the local network address.
+func (c *Conn) LocalAddr() net.Addr {
+ return c.conn.LocalAddr()
+}
+
+// RemoteAddr returns the remote network address.
+func (c *Conn) RemoteAddr() net.Addr {
+ return c.conn.RemoteAddr()
+}
+
+// SetDeadline sets the read and write deadlines associated with the connection.
+// A zero value for t means Read and Write will not time out.
+// After a Write has timed out, the TLS state is corrupt and all future writes will return the same error.
+func (c *Conn) SetDeadline(t time.Time) error {
+ return c.conn.SetDeadline(t)
+}
+
+// SetReadDeadline sets the read deadline on the underlying connection.
+// A zero value for t means Read will not time out.
+func (c *Conn) SetReadDeadline(t time.Time) error {
+ return c.conn.SetReadDeadline(t)
+}
+
+// SetWriteDeadline sets the write deadline on the underlying conneciton.
+// A zero value for t means Write will not time out.
+// After a Write has timed out, the TLS state is corrupt and all future writes will return the same error.
+func (c *Conn) SetWriteDeadline(t time.Time) error {
+ return c.conn.SetWriteDeadline(t)
+}
+
+// A halfConn represents one direction of the record layer
+// connection, either sending or receiving.
+type halfConn struct {
+ sync.Mutex
+
+ err error // first permanent error
+ version uint16 // protocol version
+ isDTLS bool
+ cipher interface{} // cipher algorithm
+ mac macFunction
+ seq [8]byte // 64-bit sequence number
+ outSeq [8]byte // Mapped sequence number
+ bfree *block // list of free blocks
+
+ nextCipher interface{} // next encryption state
+ nextMac macFunction // next MAC algorithm
+ nextSeq [6]byte // next epoch's starting sequence number in DTLS
+
+ // used to save allocating a new buffer for each MAC.
+ inDigestBuf, outDigestBuf []byte
+
+ trafficSecret []byte
+
+ config *Config
+}
+
+func (hc *halfConn) setErrorLocked(err error) error {
+ hc.err = err
+ return err
+}
+
+func (hc *halfConn) error() error {
+ // This should be locked, but I've removed it for the renegotiation
+ // tests since we don't concurrently read and write the same tls.Conn
+ // in any case during testing.
+ err := hc.err
+ return err
+}
+
+// prepareCipherSpec sets the encryption and MAC states
+// that a subsequent changeCipherSpec will use.
+func (hc *halfConn) prepareCipherSpec(version uint16, cipher interface{}, mac macFunction) {
+ hc.version = version
+ hc.nextCipher = cipher
+ hc.nextMac = mac
+}
+
+// changeCipherSpec changes the encryption and MAC states
+// to the ones previously passed to prepareCipherSpec.
+func (hc *halfConn) changeCipherSpec(config *Config) error {
+ if hc.nextCipher == nil {
+ return alertInternalError
+ }
+ hc.cipher = hc.nextCipher
+ hc.mac = hc.nextMac
+ hc.nextCipher = nil
+ hc.nextMac = nil
+ hc.config = config
+ hc.incEpoch()
+
+ if config.Bugs.NullAllCiphers {
+ hc.cipher = nullCipher{}
+ hc.mac = nil
+ }
+ return nil
+}
+
+// useTrafficSecret sets the current cipher state for TLS 1.3.
+func (hc *halfConn) useTrafficSecret(version uint16, suite *cipherSuite, secret []byte, side trafficDirection) {
+ hc.version = version
+ hc.cipher = deriveTrafficAEAD(version, suite, secret, side)
+ if hc.config.Bugs.NullAllCiphers {
+ hc.cipher = nullCipher{}
+ }
+ hc.trafficSecret = secret
+ hc.incEpoch()
+}
+
+// resetCipher changes the cipher state back to no encryption to be able
+// to send an unencrypted ClientHello in response to HelloRetryRequest
+// after 0-RTT data was rejected.
+func (hc *halfConn) resetCipher() {
+ hc.cipher = nil
+ hc.incEpoch()
+}
+
+func (hc *halfConn) doKeyUpdate(c *Conn, isOutgoing bool) {
+ side := serverWrite
+ if c.isClient == isOutgoing {
+ side = clientWrite
+ }
+ hc.useTrafficSecret(hc.version, c.cipherSuite, updateTrafficSecret(c.cipherSuite.hash(), hc.trafficSecret), side)
+}
+
+// incSeq increments the sequence number.
+func (hc *halfConn) incSeq(isOutgoing bool) {
+ limit := 0
+ increment := uint64(1)
+ if hc.isDTLS {
+ // Increment up to the epoch in DTLS.
+ limit = 2
+ }
+ for i := 7; i >= limit; i-- {
+ increment += uint64(hc.seq[i])
+ hc.seq[i] = byte(increment)
+ increment >>= 8
+ }
+
+ // Not allowed to let sequence number wrap.
+ // Instead, must renegotiate before it does.
+ // Not likely enough to bother.
+ if increment != 0 {
+ panic("TLS: sequence number wraparound")
+ }
+
+ hc.updateOutSeq()
+}
+
+// incNextSeq increments the starting sequence number for the next epoch.
+func (hc *halfConn) incNextSeq() {
+ for i := len(hc.nextSeq) - 1; i >= 0; i-- {
+ hc.nextSeq[i]++
+ if hc.nextSeq[i] != 0 {
+ return
+ }
+ }
+ panic("TLS: sequence number wraparound")
+}
+
+// incEpoch resets the sequence number. In DTLS, it also increments the epoch
+// half of the sequence number.
+func (hc *halfConn) incEpoch() {
+ if hc.isDTLS {
+ for i := 1; i >= 0; i-- {
+ hc.seq[i]++
+ if hc.seq[i] != 0 {
+ break
+ }
+ if i == 0 {
+ panic("TLS: epoch number wraparound")
+ }
+ }
+ copy(hc.seq[2:], hc.nextSeq[:])
+ for i := range hc.nextSeq {
+ hc.nextSeq[i] = 0
+ }
+ } else {
+ for i := range hc.seq {
+ hc.seq[i] = 0
+ }
+ }
+
+ hc.updateOutSeq()
+}
+
+func (hc *halfConn) updateOutSeq() {
+ if hc.config.Bugs.SequenceNumberMapping != nil {
+ seqU64 := binary.BigEndian.Uint64(hc.seq[:])
+ seqU64 = hc.config.Bugs.SequenceNumberMapping(seqU64)
+ binary.BigEndian.PutUint64(hc.outSeq[:], seqU64)
+
+ // The DTLS epoch cannot be changed.
+ copy(hc.outSeq[:2], hc.seq[:2])
+ return
+ }
+
+ copy(hc.outSeq[:], hc.seq[:])
+}
+
+func (hc *halfConn) recordHeaderLen() int {
+ if hc.isDTLS {
+ return dtlsRecordHeaderLen
+ }
+ return tlsRecordHeaderLen
+}
+
+// removePadding returns an unpadded slice, in constant time, which is a prefix
+// of the input. It also returns a byte which is equal to 255 if the padding
+// was valid and 0 otherwise. See RFC 2246, section 6.2.3.2
+func removePadding(payload []byte) ([]byte, byte) {
+ if len(payload) < 1 {
+ return payload, 0
+ }
+
+ paddingLen := payload[len(payload)-1]
+ t := uint(len(payload)-1) - uint(paddingLen)
+ // if len(payload) >= (paddingLen - 1) then the MSB of t is zero
+ good := byte(int32(^t) >> 31)
+
+ toCheck := 255 // the maximum possible padding length
+ // The length of the padded data is public, so we can use an if here
+ if toCheck+1 > len(payload) {
+ toCheck = len(payload) - 1
+ }
+
+ for i := 0; i < toCheck; i++ {
+ t := uint(paddingLen) - uint(i)
+ // if i <= paddingLen then the MSB of t is zero
+ mask := byte(int32(^t) >> 31)
+ b := payload[len(payload)-1-i]
+ good &^= mask&paddingLen ^ mask&b
+ }
+
+ // We AND together the bits of good and replicate the result across
+ // all the bits.
+ good &= good << 4
+ good &= good << 2
+ good &= good << 1
+ good = uint8(int8(good) >> 7)
+
+ toRemove := good&paddingLen + 1
+ return payload[:len(payload)-int(toRemove)], good
+}
+
+// removePaddingSSL30 is a replacement for removePadding in the case that the
+// protocol version is SSLv3. In this version, the contents of the padding
+// are random and cannot be checked.
+func removePaddingSSL30(payload []byte) ([]byte, byte) {
+ if len(payload) < 1 {
+ return payload, 0
+ }
+
+ paddingLen := int(payload[len(payload)-1]) + 1
+ if paddingLen > len(payload) {
+ return payload, 0
+ }
+
+ return payload[:len(payload)-paddingLen], 255
+}
+
+func roundUp(a, b int) int {
+ return a + (b-a%b)%b
+}
+
+// cbcMode is an interface for block ciphers using cipher block chaining.
+type cbcMode interface {
+ cipher.BlockMode
+ SetIV([]byte)
+}
+
+// decrypt checks and strips the mac and decrypts the data in b. Returns a
+// success boolean, the number of bytes to skip from the start of the record in
+// order to get the application payload, the encrypted record type (or 0
+// if there is none), and an optional alert value.
+func (hc *halfConn) decrypt(b *block) (ok bool, prefixLen int, contentType recordType, alertValue alert) {
+ recordHeaderLen := hc.recordHeaderLen()
+
+ // pull out payload
+ payload := b.data[recordHeaderLen:]
+
+ macSize := 0
+ if hc.mac != nil {
+ macSize = hc.mac.Size()
+ }
+
+ paddingGood := byte(255)
+ explicitIVLen := 0
+
+ seq := hc.seq[:]
+ if hc.isDTLS {
+ // DTLS sequence numbers are explicit.
+ seq = b.data[3:11]
+ }
+
+ // decrypt
+ if hc.cipher != nil {
+ switch c := hc.cipher.(type) {
+ case cipher.Stream:
+ c.XORKeyStream(payload, payload)
+ case *tlsAead:
+ nonce := seq
+ if c.explicitNonce {
+ explicitIVLen = 8
+ if len(payload) < explicitIVLen {
+ return false, 0, 0, alertBadRecordMAC
+ }
+ nonce = payload[:8]
+ payload = payload[8:]
+ }
+
+ var additionalData []byte
+ if hc.version < VersionTLS13 {
+ additionalData = make([]byte, 13)
+ copy(additionalData, seq)
+ copy(additionalData[8:], b.data[:3])
+ n := len(payload) - c.Overhead()
+ additionalData[11] = byte(n >> 8)
+ additionalData[12] = byte(n)
+ }
+ var err error
+ payload, err = c.Open(payload[:0], nonce, payload, additionalData)
+ if err != nil {
+ return false, 0, 0, alertBadRecordMAC
+ }
+ b.resize(recordHeaderLen + explicitIVLen + len(payload))
+ case cbcMode:
+ blockSize := c.BlockSize()
+ if hc.version >= VersionTLS11 || hc.isDTLS {
+ explicitIVLen = blockSize
+ }
+
+ if len(payload)%blockSize != 0 || len(payload) < roundUp(explicitIVLen+macSize+1, blockSize) {
+ return false, 0, 0, alertBadRecordMAC
+ }
+
+ if explicitIVLen > 0 {
+ c.SetIV(payload[:explicitIVLen])
+ payload = payload[explicitIVLen:]
+ }
+ c.CryptBlocks(payload, payload)
+ if hc.version == VersionSSL30 {
+ payload, paddingGood = removePaddingSSL30(payload)
+ } else {
+ payload, paddingGood = removePadding(payload)
+ }
+ b.resize(recordHeaderLen + explicitIVLen + len(payload))
+
+ // note that we still have a timing side-channel in the
+ // MAC check, below. An attacker can align the record
+ // so that a correct padding will cause one less hash
+ // block to be calculated. Then they can iteratively
+ // decrypt a record by breaking each byte. See
+ // "Password Interception in a SSL/TLS Channel", Brice
+ // Canvel et al.
+ //
+ // However, our behavior matches OpenSSL, so we leak
+ // only as much as they do.
+ case nullCipher:
+ break
+ default:
+ panic("unknown cipher type")
+ }
+
+ if hc.version >= VersionTLS13 {
+ i := len(payload)
+ for i > 0 && payload[i-1] == 0 {
+ i--
+ }
+ payload = payload[:i]
+ if len(payload) == 0 {
+ return false, 0, 0, alertUnexpectedMessage
+ }
+ contentType = recordType(payload[len(payload)-1])
+ payload = payload[:len(payload)-1]
+ b.resize(recordHeaderLen + len(payload))
+ }
+ }
+
+ // check, strip mac
+ if hc.mac != nil {
+ if len(payload) < macSize {
+ return false, 0, 0, alertBadRecordMAC
+ }
+
+ // strip mac off payload, b.data
+ n := len(payload) - macSize
+ b.data[recordHeaderLen-2] = byte(n >> 8)
+ b.data[recordHeaderLen-1] = byte(n)
+ b.resize(recordHeaderLen + explicitIVLen + n)
+ remoteMAC := payload[n:]
+ localMAC := hc.mac.MAC(hc.inDigestBuf, seq, b.data[:3], b.data[recordHeaderLen-2:recordHeaderLen], payload[:n])
+
+ if subtle.ConstantTimeCompare(localMAC, remoteMAC) != 1 || paddingGood != 255 {
+ return false, 0, 0, alertBadRecordMAC
+ }
+ hc.inDigestBuf = localMAC
+ }
+ hc.incSeq(false)
+
+ return true, recordHeaderLen + explicitIVLen, contentType, 0
+}
+
+// padToBlockSize calculates the needed padding block, if any, for a payload.
+// On exit, prefix aliases payload and extends to the end of the last full
+// block of payload. finalBlock is a fresh slice which contains the contents of
+// any suffix of payload as well as the needed padding to make finalBlock a
+// full block.
+func padToBlockSize(payload []byte, blockSize int, config *Config) (prefix, finalBlock []byte) {
+ overrun := len(payload) % blockSize
+ prefix = payload[:len(payload)-overrun]
+
+ paddingLen := blockSize - overrun
+ finalSize := blockSize
+ if config.Bugs.MaxPadding {
+ for paddingLen+blockSize <= 256 {
+ paddingLen += blockSize
+ }
+ finalSize = 256
+ }
+ finalBlock = make([]byte, finalSize)
+ for i := range finalBlock {
+ finalBlock[i] = byte(paddingLen - 1)
+ }
+ if config.Bugs.PaddingFirstByteBad || config.Bugs.PaddingFirstByteBadIf255 && paddingLen == 256 {
+ finalBlock[overrun] ^= 0xff
+ }
+ copy(finalBlock, payload[len(payload)-overrun:])
+ return
+}
+
+// encrypt encrypts and macs the data in b.
+func (hc *halfConn) encrypt(b *block, explicitIVLen int, typ recordType) (bool, alert) {
+ recordHeaderLen := hc.recordHeaderLen()
+
+ // mac
+ if hc.mac != nil {
+ mac := hc.mac.MAC(hc.outDigestBuf, hc.outSeq[0:], b.data[:3], b.data[recordHeaderLen-2:recordHeaderLen], b.data[recordHeaderLen+explicitIVLen:])
+
+ n := len(b.data)
+ b.resize(n + len(mac))
+ copy(b.data[n:], mac)
+ hc.outDigestBuf = mac
+ }
+
+ payload := b.data[recordHeaderLen:]
+
+ // encrypt
+ if hc.cipher != nil {
+ // Add TLS 1.3 padding.
+ if hc.version >= VersionTLS13 {
+ paddingLen := hc.config.Bugs.RecordPadding
+ if hc.config.Bugs.OmitRecordContents {
+ b.resize(recordHeaderLen + paddingLen)
+ } else {
+ b.resize(len(b.data) + 1 + paddingLen)
+ b.data[len(b.data)-paddingLen-1] = byte(typ)
+ }
+ for i := 0; i < paddingLen; i++ {
+ b.data[len(b.data)-paddingLen+i] = 0
+ }
+ }
+
+ switch c := hc.cipher.(type) {
+ case cipher.Stream:
+ c.XORKeyStream(payload, payload)
+ case *tlsAead:
+ payloadLen := len(b.data) - recordHeaderLen - explicitIVLen
+ b.resize(len(b.data) + c.Overhead())
+ nonce := hc.outSeq[:]
+ if c.explicitNonce {
+ nonce = b.data[recordHeaderLen : recordHeaderLen+explicitIVLen]
+ }
+ payload := b.data[recordHeaderLen+explicitIVLen:]
+ payload = payload[:payloadLen]
+
+ var additionalData []byte
+ if hc.version < VersionTLS13 {
+ additionalData = make([]byte, 13)
+ copy(additionalData, hc.outSeq[:])
+ copy(additionalData[8:], b.data[:3])
+ additionalData[11] = byte(payloadLen >> 8)
+ additionalData[12] = byte(payloadLen)
+ }
+
+ c.Seal(payload[:0], nonce, payload, additionalData)
+ case cbcMode:
+ blockSize := c.BlockSize()
+ if explicitIVLen > 0 {
+ c.SetIV(payload[:explicitIVLen])
+ payload = payload[explicitIVLen:]
+ }
+ prefix, finalBlock := padToBlockSize(payload, blockSize, hc.config)
+ b.resize(recordHeaderLen + explicitIVLen + len(prefix) + len(finalBlock))
+ c.CryptBlocks(b.data[recordHeaderLen+explicitIVLen:], prefix)
+ c.CryptBlocks(b.data[recordHeaderLen+explicitIVLen+len(prefix):], finalBlock)
+ case nullCipher:
+ break
+ default:
+ panic("unknown cipher type")
+ }
+ }
+
+ // update length to include MAC and any block padding needed.
+ n := len(b.data) - recordHeaderLen
+ b.data[recordHeaderLen-2] = byte(n >> 8)
+ b.data[recordHeaderLen-1] = byte(n)
+ hc.incSeq(true)
+
+ return true, 0
+}
+
+// A block is a simple data buffer.
+type block struct {
+ data []byte
+ off int // index for Read
+ link *block
+}
+
+// resize resizes block to be n bytes, growing if necessary.
+func (b *block) resize(n int) {
+ if n > cap(b.data) {
+ b.reserve(n)
+ }
+ b.data = b.data[0:n]
+}
+
+// reserve makes sure that block contains a capacity of at least n bytes.
+func (b *block) reserve(n int) {
+ if cap(b.data) >= n {
+ return
+ }
+ m := cap(b.data)
+ if m == 0 {
+ m = 1024
+ }
+ for m < n {
+ m *= 2
+ }
+ data := make([]byte, len(b.data), m)
+ copy(data, b.data)
+ b.data = data
+}
+
+// readFromUntil reads from r into b until b contains at least n bytes
+// or else returns an error.
+func (b *block) readFromUntil(r io.Reader, n int) error {
+ // quick case
+ if len(b.data) >= n {
+ return nil
+ }
+
+ // read until have enough.
+ b.reserve(n)
+ for {
+ m, err := r.Read(b.data[len(b.data):cap(b.data)])
+ b.data = b.data[0 : len(b.data)+m]
+ if len(b.data) >= n {
+ // TODO(bradfitz,agl): slightly suspicious
+ // that we're throwing away r.Read's err here.
+ break
+ }
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (b *block) Read(p []byte) (n int, err error) {
+ n = copy(p, b.data[b.off:])
+ b.off += n
+ return
+}
+
+// newBlock allocates a new block, from hc's free list if possible.
+func (hc *halfConn) newBlock() *block {
+ b := hc.bfree
+ if b == nil {
+ return new(block)
+ }
+ hc.bfree = b.link
+ b.link = nil
+ b.resize(0)
+ return b
+}
+
+// freeBlock returns a block to hc's free list.
+// The protocol is such that each side only has a block or two on
+// its free list at a time, so there's no need to worry about
+// trimming the list, etc.
+func (hc *halfConn) freeBlock(b *block) {
+ b.link = hc.bfree
+ hc.bfree = b
+}
+
+// splitBlock splits a block after the first n bytes,
+// returning a block with those n bytes and a
+// block with the remainder. the latter may be nil.
+func (hc *halfConn) splitBlock(b *block, n int) (*block, *block) {
+ if len(b.data) <= n {
+ return b, nil
+ }
+ bb := hc.newBlock()
+ bb.resize(len(b.data) - n)
+ copy(bb.data, b.data[n:])
+ b.data = b.data[0:n]
+ return b, bb
+}
+
+func (c *Conn) doReadRecord(want recordType) (recordType, *block, error) {
+RestartReadRecord:
+ if c.isDTLS {
+ return c.dtlsDoReadRecord(want)
+ }
+
+ recordHeaderLen := c.in.recordHeaderLen()
+
+ if c.rawInput == nil {
+ c.rawInput = c.in.newBlock()
+ }
+ b := c.rawInput
+
+ // Read header, payload.
+ if err := b.readFromUntil(c.conn, recordHeaderLen); err != nil {
+ // RFC suggests that EOF without an alertCloseNotify is
+ // an error, but popular web sites seem to do this,
+ // so we can't make it an error, outside of tests.
+ if err == io.EOF && c.config.Bugs.ExpectCloseNotify {
+ err = io.ErrUnexpectedEOF
+ }
+ if e, ok := err.(net.Error); !ok || !e.Temporary() {
+ c.in.setErrorLocked(err)
+ }
+ return 0, nil, err
+ }
+
+ typ := recordType(b.data[0])
+
+ // No valid TLS record has a type of 0x80, however SSLv2 handshakes
+ // start with a uint16 length where the MSB is set and the first record
+ // is always < 256 bytes long. Therefore typ == 0x80 strongly suggests
+ // an SSLv2 client.
+ if want == recordTypeHandshake && typ == 0x80 {
+ c.sendAlert(alertProtocolVersion)
+ return 0, nil, c.in.setErrorLocked(errors.New("tls: unsupported SSLv2 handshake received"))
+ }
+
+ vers := uint16(b.data[1])<<8 | uint16(b.data[2])
+ n := int(b.data[3])<<8 | int(b.data[4])
+
+ // Alerts sent near version negotiation do not have a well-defined
+ // record-layer version prior to TLS 1.3. (In TLS 1.3, the record-layer
+ // version is irrelevant.)
+ if typ != recordTypeAlert {
+ var expect uint16
+ if c.haveVers {
+ expect = c.vers
+ if c.vers >= VersionTLS13 {
+ expect = VersionTLS10
+ }
+ } else {
+ expect = c.config.Bugs.ExpectInitialRecordVersion
+ }
+ if expect != 0 && vers != expect {
+ c.sendAlert(alertProtocolVersion)
+ return 0, nil, c.in.setErrorLocked(fmt.Errorf("tls: received record with version %x when expecting version %x", vers, expect))
+ }
+ }
+ if n > maxCiphertext {
+ c.sendAlert(alertRecordOverflow)
+ return 0, nil, c.in.setErrorLocked(fmt.Errorf("tls: oversized record received with length %d", n))
+ }
+ if !c.haveVers {
+ // First message, be extra suspicious:
+ // this might not be a TLS client.
+ // Bail out before reading a full 'body', if possible.
+ // The current max version is 3.1.
+ // If the version is >= 16.0, it's probably not real.
+ // Similarly, a clientHello message encodes in
+ // well under a kilobyte. If the length is >= 12 kB,
+ // it's probably not real.
+ if (typ != recordTypeAlert && typ != want) || vers >= 0x1000 || n >= 0x3000 {
+ c.sendAlert(alertUnexpectedMessage)
+ return 0, nil, c.in.setErrorLocked(fmt.Errorf("tls: first record does not look like a TLS handshake"))
+ }
+ }
+ if err := b.readFromUntil(c.conn, recordHeaderLen+n); err != nil {
+ if err == io.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ if e, ok := err.(net.Error); !ok || !e.Temporary() {
+ c.in.setErrorLocked(err)
+ }
+ return 0, nil, err
+ }
+
+ // Process message.
+ b, c.rawInput = c.in.splitBlock(b, recordHeaderLen+n)
+ ok, off, encTyp, alertValue := c.in.decrypt(b)
+
+ // Handle skipping over early data.
+ if !ok && c.skipEarlyData {
+ goto RestartReadRecord
+ }
+
+ // If the server is expecting a second ClientHello (in response to
+ // a HelloRetryRequest) and the client sends early data, there
+ // won't be a decryption failure but it still needs to be skipped.
+ if c.in.cipher == nil && typ == recordTypeApplicationData && c.skipEarlyData {
+ goto RestartReadRecord
+ }
+
+ if !ok {
+ return 0, nil, c.in.setErrorLocked(c.sendAlert(alertValue))
+ }
+ b.off = off
+ c.skipEarlyData = false
+
+ if c.vers >= VersionTLS13 && c.in.cipher != nil {
+ if typ != recordTypeApplicationData {
+ return 0, nil, c.in.setErrorLocked(fmt.Errorf("tls: outer record type is not application data"))
+ }
+ typ = encTyp
+ }
+ return typ, b, nil
+}
+
+// readRecord reads the next TLS record from the connection
+// and updates the record layer state.
+// c.in.Mutex <= L; c.input == nil.
+func (c *Conn) readRecord(want recordType) error {
+ // Caller must be in sync with connection:
+ // handshake data if handshake not yet completed,
+ // else application data.
+ switch want {
+ default:
+ c.sendAlert(alertInternalError)
+ return c.in.setErrorLocked(errors.New("tls: unknown record type requested"))
+ case recordTypeHandshake, recordTypeChangeCipherSpec:
+ if c.handshakeComplete {
+ c.sendAlert(alertInternalError)
+ return c.in.setErrorLocked(errors.New("tls: handshake or ChangeCipherSpec requested after handshake complete"))
+ }
+ case recordTypeApplicationData:
+ if !c.handshakeComplete && !c.config.Bugs.ExpectFalseStart && len(c.config.Bugs.ExpectHalfRTTData) == 0 && len(c.config.Bugs.ExpectEarlyData) == 0 {
+ c.sendAlert(alertInternalError)
+ return c.in.setErrorLocked(errors.New("tls: application data record requested before handshake complete"))
+ }
+ case recordTypeAlert:
+ // Looking for a close_notify. Note: unlike a real
+ // implementation, this is not tolerant of additional records.
+ // See the documentation for ExpectCloseNotify.
+ }
+
+Again:
+ typ, b, err := c.doReadRecord(want)
+ if err != nil {
+ return err
+ }
+ data := b.data[b.off:]
+ max := maxPlaintext
+ if c.config.Bugs.MaxReceivePlaintext != 0 {
+ max = c.config.Bugs.MaxReceivePlaintext
+ }
+ if len(data) > max {
+ err := c.sendAlert(alertRecordOverflow)
+ c.in.freeBlock(b)
+ return c.in.setErrorLocked(err)
+ }
+
+ switch typ {
+ default:
+ c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+
+ case recordTypeAlert:
+ if len(data) != 2 {
+ c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+ break
+ }
+ if alert(data[1]) == alertCloseNotify {
+ c.in.setErrorLocked(io.EOF)
+ break
+ }
+ switch data[0] {
+ case alertLevelWarning:
+ if alert(data[1]) == alertNoCertificate {
+ c.in.freeBlock(b)
+ return errNoCertificateAlert
+ }
+ if alert(data[1]) == alertEndOfEarlyData {
+ c.in.freeBlock(b)
+ return errEndOfEarlyDataAlert
+ }
+
+ // drop on the floor
+ c.in.freeBlock(b)
+ goto Again
+ case alertLevelError:
+ c.in.setErrorLocked(&net.OpError{Op: "remote error", Err: alert(data[1])})
+ default:
+ c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+ }
+
+ case recordTypeChangeCipherSpec:
+ if typ != want || len(data) != 1 || data[0] != 1 {
+ c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+ break
+ }
+ err := c.in.changeCipherSpec(c.config)
+ if err != nil {
+ c.in.setErrorLocked(c.sendAlert(err.(alert)))
+ }
+
+ case recordTypeApplicationData:
+ if typ != want {
+ c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+ break
+ }
+ c.input = b
+ b = nil
+
+ case recordTypeHandshake:
+ // Allow handshake data while reading application data to
+ // trigger post-handshake messages.
+ // TODO(rsc): Should at least pick off connection close.
+ if typ != want && want != recordTypeApplicationData {
+ return c.in.setErrorLocked(c.sendAlert(alertNoRenegotiation))
+ }
+ c.hand.Write(data)
+ }
+
+ if b != nil {
+ c.in.freeBlock(b)
+ }
+ return c.in.err
+}
+
+// sendAlert sends a TLS alert message.
+// c.out.Mutex <= L.
+func (c *Conn) sendAlertLocked(level byte, err alert) error {
+ c.tmp[0] = level
+ c.tmp[1] = byte(err)
+ if c.config.Bugs.FragmentAlert {
+ c.writeRecord(recordTypeAlert, c.tmp[0:1])
+ c.writeRecord(recordTypeAlert, c.tmp[1:2])
+ } else if c.config.Bugs.DoubleAlert {
+ copy(c.tmp[2:4], c.tmp[0:2])
+ c.writeRecord(recordTypeAlert, c.tmp[0:4])
+ } else {
+ c.writeRecord(recordTypeAlert, c.tmp[0:2])
+ }
+ // Error alerts are fatal to the connection.
+ if level == alertLevelError {
+ return c.out.setErrorLocked(&net.OpError{Op: "local error", Err: err})
+ }
+ return nil
+}
+
+// sendAlert sends a TLS alert message.
+// L < c.out.Mutex.
+func (c *Conn) sendAlert(err alert) error {
+ level := byte(alertLevelError)
+ if err == alertNoRenegotiation || err == alertCloseNotify || err == alertNoCertificate || err == alertEndOfEarlyData {
+ level = alertLevelWarning
+ }
+ return c.SendAlert(level, err)
+}
+
+func (c *Conn) SendAlert(level byte, err alert) error {
+ c.out.Lock()
+ defer c.out.Unlock()
+ return c.sendAlertLocked(level, err)
+}
+
+// writeV2Record writes a record for a V2ClientHello.
+func (c *Conn) writeV2Record(data []byte) (n int, err error) {
+ record := make([]byte, 2+len(data))
+ record[0] = uint8(len(data)>>8) | 0x80
+ record[1] = uint8(len(data))
+ copy(record[2:], data)
+ return c.conn.Write(record)
+}
+
+// writeRecord writes a TLS record with the given type and payload
+// to the connection and updates the record layer state.
+// c.out.Mutex <= L.
+func (c *Conn) writeRecord(typ recordType, data []byte) (n int, err error) {
+ if msgType := c.config.Bugs.SendWrongMessageType; msgType != 0 {
+ if typ == recordTypeHandshake && data[0] == msgType {
+ newData := make([]byte, len(data))
+ copy(newData, data)
+ newData[0] += 42
+ data = newData
+ }
+ }
+
+ if msgType := c.config.Bugs.SendTrailingMessageData; msgType != 0 {
+ if typ == recordTypeHandshake && data[0] == msgType {
+ newData := make([]byte, len(data))
+ copy(newData, data)
+
+ // Add a 0 to the body.
+ newData = append(newData, 0)
+ // Fix the header.
+ newLen := len(newData) - 4
+ newData[1] = byte(newLen >> 16)
+ newData[2] = byte(newLen >> 8)
+ newData[3] = byte(newLen)
+
+ data = newData
+ }
+ }
+
+ if c.isDTLS {
+ return c.dtlsWriteRecord(typ, data)
+ }
+
+ if typ == recordTypeHandshake {
+ if c.config.Bugs.SendHelloRequestBeforeEveryHandshakeMessage {
+ newData := make([]byte, 0, 4+len(data))
+ newData = append(newData, typeHelloRequest, 0, 0, 0)
+ newData = append(newData, data...)
+ data = newData
+ }
+
+ if c.config.Bugs.PackHandshakeFlight {
+ c.pendingFlight.Write(data)
+ return len(data), nil
+ }
+ }
+
+ return c.doWriteRecord(typ, data)
+}
+
+func (c *Conn) doWriteRecord(typ recordType, data []byte) (n int, err error) {
+ recordHeaderLen := c.out.recordHeaderLen()
+ b := c.out.newBlock()
+ first := true
+ isClientHello := typ == recordTypeHandshake && len(data) > 0 && data[0] == typeClientHello
+ for len(data) > 0 || first {
+ m := len(data)
+ if m > maxPlaintext && !c.config.Bugs.SendLargeRecords {
+ m = maxPlaintext
+ }
+ if typ == recordTypeHandshake && c.config.Bugs.MaxHandshakeRecordLength > 0 && m > c.config.Bugs.MaxHandshakeRecordLength {
+ m = c.config.Bugs.MaxHandshakeRecordLength
+ // By default, do not fragment the client_version or
+ // server_version, which are located in the first 6
+ // bytes.
+ if first && isClientHello && !c.config.Bugs.FragmentClientVersion && m < 6 {
+ m = 6
+ }
+ }
+ explicitIVLen := 0
+ explicitIVIsSeq := false
+ first = false
+
+ var cbc cbcMode
+ if c.out.version >= VersionTLS11 {
+ var ok bool
+ if cbc, ok = c.out.cipher.(cbcMode); ok {
+ explicitIVLen = cbc.BlockSize()
+ }
+ }
+ if explicitIVLen == 0 {
+ if aead, ok := c.out.cipher.(*tlsAead); ok && aead.explicitNonce {
+ explicitIVLen = 8
+ // The AES-GCM construction in TLS has an
+ // explicit nonce so that the nonce can be
+ // random. However, the nonce is only 8 bytes
+ // which is too small for a secure, random
+ // nonce. Therefore we use the sequence number
+ // as the nonce.
+ explicitIVIsSeq = true
+ }
+ }
+ b.resize(recordHeaderLen + explicitIVLen + m)
+ b.data[0] = byte(typ)
+ if c.vers >= VersionTLS13 && c.out.cipher != nil {
+ b.data[0] = byte(recordTypeApplicationData)
+ if outerType := c.config.Bugs.OuterRecordType; outerType != 0 {
+ b.data[0] = byte(outerType)
+ }
+ }
+ vers := c.vers
+ if vers == 0 || vers >= VersionTLS13 {
+ // Some TLS servers fail if the record version is
+ // greater than TLS 1.0 for the initial ClientHello.
+ //
+ // TLS 1.3 fixes the version number in the record
+ // layer to {3, 1}.
+ vers = VersionTLS10
+ }
+ if c.config.Bugs.SendRecordVersion != 0 {
+ vers = c.config.Bugs.SendRecordVersion
+ }
+ if c.vers == 0 && c.config.Bugs.SendInitialRecordVersion != 0 {
+ vers = c.config.Bugs.SendInitialRecordVersion
+ }
+ b.data[1] = byte(vers >> 8)
+ b.data[2] = byte(vers)
+ b.data[3] = byte(m >> 8)
+ b.data[4] = byte(m)
+ if explicitIVLen > 0 {
+ explicitIV := b.data[recordHeaderLen : recordHeaderLen+explicitIVLen]
+ if explicitIVIsSeq {
+ copy(explicitIV, c.out.seq[:])
+ } else {
+ if _, err = io.ReadFull(c.config.rand(), explicitIV); err != nil {
+ break
+ }
+ }
+ }
+ copy(b.data[recordHeaderLen+explicitIVLen:], data)
+ c.out.encrypt(b, explicitIVLen, typ)
+ _, err = c.conn.Write(b.data)
+ if err != nil {
+ break
+ }
+ n += m
+ data = data[m:]
+ }
+ c.out.freeBlock(b)
+
+ if typ == recordTypeChangeCipherSpec {
+ err = c.out.changeCipherSpec(c.config)
+ if err != nil {
+ // Cannot call sendAlert directly,
+ // because we already hold c.out.Mutex.
+ c.tmp[0] = alertLevelError
+ c.tmp[1] = byte(err.(alert))
+ c.writeRecord(recordTypeAlert, c.tmp[0:2])
+ return n, c.out.setErrorLocked(&net.OpError{Op: "local error", Err: err})
+ }
+ }
+ return
+}
+
+func (c *Conn) flushHandshake() error {
+ if c.isDTLS {
+ return c.dtlsFlushHandshake()
+ }
+
+ for c.pendingFlight.Len() > 0 {
+ var buf [maxPlaintext]byte
+ n, _ := c.pendingFlight.Read(buf[:])
+ if _, err := c.doWriteRecord(recordTypeHandshake, buf[:n]); err != nil {
+ return err
+ }
+ }
+
+ c.pendingFlight.Reset()
+ return nil
+}
+
+func (c *Conn) doReadHandshake() ([]byte, error) {
+ if c.isDTLS {
+ return c.dtlsDoReadHandshake()
+ }
+
+ for c.hand.Len() < 4 {
+ if err := c.in.err; err != nil {
+ return nil, err
+ }
+ if err := c.readRecord(recordTypeHandshake); err != nil {
+ return nil, err
+ }
+ }
+
+ data := c.hand.Bytes()
+ n := int(data[1])<<16 | int(data[2])<<8 | int(data[3])
+ if n > maxHandshake {
+ return nil, c.in.setErrorLocked(c.sendAlert(alertInternalError))
+ }
+ for c.hand.Len() < 4+n {
+ if err := c.in.err; err != nil {
+ return nil, err
+ }
+ if err := c.readRecord(recordTypeHandshake); err != nil {
+ return nil, err
+ }
+ }
+ return c.hand.Next(4 + n), nil
+}
+
+// readHandshake reads the next handshake message from
+// the record layer.
+// c.in.Mutex < L; c.out.Mutex < L.
+func (c *Conn) readHandshake() (interface{}, error) {
+ data, err := c.doReadHandshake()
+ if err == errNoCertificateAlert {
+ if c.hand.Len() != 0 {
+ // The warning alert may not interleave with a handshake message.
+ return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+ }
+ return new(ssl3NoCertificateMsg), nil
+ }
+ if err != nil {
+ return nil, err
+ }
+
+ var m handshakeMessage
+ switch data[0] {
+ case typeHelloRequest:
+ m = new(helloRequestMsg)
+ case typeClientHello:
+ m = &clientHelloMsg{
+ isDTLS: c.isDTLS,
+ }
+ case typeServerHello:
+ m = &serverHelloMsg{
+ isDTLS: c.isDTLS,
+ }
+ case typeHelloRetryRequest:
+ m = new(helloRetryRequestMsg)
+ case typeNewSessionTicket:
+ m = &newSessionTicketMsg{
+ version: c.vers,
+ }
+ case typeEncryptedExtensions:
+ m = new(encryptedExtensionsMsg)
+ case typeCertificate:
+ m = &certificateMsg{
+ hasRequestContext: c.vers >= VersionTLS13,
+ }
+ case typeCertificateRequest:
+ m = &certificateRequestMsg{
+ hasSignatureAlgorithm: c.vers >= VersionTLS12,
+ hasRequestContext: c.vers >= VersionTLS13,
+ }
+ case typeCertificateStatus:
+ m = new(certificateStatusMsg)
+ case typeServerKeyExchange:
+ m = new(serverKeyExchangeMsg)
+ case typeServerHelloDone:
+ m = new(serverHelloDoneMsg)
+ case typeClientKeyExchange:
+ m = new(clientKeyExchangeMsg)
+ case typeCertificateVerify:
+ m = &certificateVerifyMsg{
+ hasSignatureAlgorithm: c.vers >= VersionTLS12,
+ }
+ case typeNextProtocol:
+ m = new(nextProtoMsg)
+ case typeFinished:
+ m = new(finishedMsg)
+ case typeHelloVerifyRequest:
+ m = new(helloVerifyRequestMsg)
+ case typeChannelID:
+ m = new(channelIDMsg)
+ case typeKeyUpdate:
+ m = new(keyUpdateMsg)
+ default:
+ return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+ }
+
+ // The handshake message unmarshallers
+ // expect to be able to keep references to data,
+ // so pass in a fresh copy that won't be overwritten.
+ data = append([]byte(nil), data...)
+
+ if !m.unmarshal(data) {
+ return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+ }
+ return m, nil
+}
+
+// skipPacket processes all the DTLS records in packet. It updates
+// sequence number expectations but otherwise ignores them.
+func (c *Conn) skipPacket(packet []byte) error {
+ for len(packet) > 0 {
+ if len(packet) < 13 {
+ return errors.New("tls: bad packet")
+ }
+ // Dropped packets are completely ignored save to update
+ // expected sequence numbers for this and the next epoch. (We
+ // don't assert on the contents of the packets both for
+ // simplicity and because a previous test with one shorter
+ // timeout schedule would have done so.)
+ epoch := packet[3:5]
+ seq := packet[5:11]
+ length := uint16(packet[11])<<8 | uint16(packet[12])
+ if bytes.Equal(c.in.seq[:2], epoch) {
+ if bytes.Compare(seq, c.in.seq[2:]) < 0 {
+ return errors.New("tls: sequence mismatch")
+ }
+ copy(c.in.seq[2:], seq)
+ c.in.incSeq(false)
+ } else {
+ if bytes.Compare(seq, c.in.nextSeq[:]) < 0 {
+ return errors.New("tls: sequence mismatch")
+ }
+ copy(c.in.nextSeq[:], seq)
+ c.in.incNextSeq()
+ }
+ if len(packet) < 13+int(length) {
+ return errors.New("tls: bad packet")
+ }
+ packet = packet[13+length:]
+ }
+ return nil
+}
+
+// simulatePacketLoss simulates the loss of a handshake leg from the
+// peer based on the schedule in c.config.Bugs. If resendFunc is
+// non-nil, it is called after each simulated timeout to retransmit
+// handshake messages from the local end. This is used in cases where
+// the peer retransmits on a stale Finished rather than a timeout.
+func (c *Conn) simulatePacketLoss(resendFunc func()) error {
+ if len(c.config.Bugs.TimeoutSchedule) == 0 {
+ return nil
+ }
+ if !c.isDTLS {
+ return errors.New("tls: TimeoutSchedule may only be set in DTLS")
+ }
+ if c.config.Bugs.PacketAdaptor == nil {
+ return errors.New("tls: TimeoutSchedule set without PacketAdapter")
+ }
+ for _, timeout := range c.config.Bugs.TimeoutSchedule {
+ // Simulate a timeout.
+ packets, err := c.config.Bugs.PacketAdaptor.SendReadTimeout(timeout)
+ if err != nil {
+ return err
+ }
+ for _, packet := range packets {
+ if err := c.skipPacket(packet); err != nil {
+ return err
+ }
+ }
+ if resendFunc != nil {
+ resendFunc()
+ }
+ }
+ return nil
+}
+
+func (c *Conn) SendHalfHelloRequest() error {
+ if err := c.Handshake(); err != nil {
+ return err
+ }
+
+ c.out.Lock()
+ defer c.out.Unlock()
+
+ if _, err := c.writeRecord(recordTypeHandshake, []byte{typeHelloRequest, 0}); err != nil {
+ return err
+ }
+ return c.flushHandshake()
+}
+
+// Write writes data to the connection.
+func (c *Conn) Write(b []byte) (int, error) {
+ if err := c.Handshake(); err != nil {
+ return 0, err
+ }
+
+ c.out.Lock()
+ defer c.out.Unlock()
+
+ // Flush any pending handshake data. PackHelloRequestWithFinished may
+ // have been set and the handshake not followed by Renegotiate.
+ c.flushHandshake()
+
+ if err := c.out.err; err != nil {
+ return 0, err
+ }
+
+ if !c.handshakeComplete {
+ return 0, alertInternalError
+ }
+
+ if c.keyUpdateRequested {
+ if err := c.sendKeyUpdateLocked(keyUpdateNotRequested); err != nil {
+ return 0, err
+ }
+ c.keyUpdateRequested = false
+ }
+
+ if c.config.Bugs.SendSpuriousAlert != 0 {
+ c.sendAlertLocked(alertLevelError, c.config.Bugs.SendSpuriousAlert)
+ }
+
+ if c.config.Bugs.SendHelloRequestBeforeEveryAppDataRecord {
+ c.writeRecord(recordTypeHandshake, []byte{typeHelloRequest, 0, 0, 0})
+ c.flushHandshake()
+ }
+
+ // SSL 3.0 and TLS 1.0 are susceptible to a chosen-plaintext
+ // attack when using block mode ciphers due to predictable IVs.
+ // This can be prevented by splitting each Application Data
+ // record into two records, effectively randomizing the IV.
+ //
+ // http://www.openssl.org/~bodo/tls-cbc.txt
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=665814
+ // http://www.imperialviolet.org/2012/01/15/beastfollowup.html
+
+ var m int
+ if len(b) > 1 && c.vers <= VersionTLS10 && !c.isDTLS {
+ if _, ok := c.out.cipher.(cipher.BlockMode); ok {
+ n, err := c.writeRecord(recordTypeApplicationData, b[:1])
+ if err != nil {
+ return n, c.out.setErrorLocked(err)
+ }
+ m, b = 1, b[1:]
+ }
+ }
+
+ n, err := c.writeRecord(recordTypeApplicationData, b)
+ return n + m, c.out.setErrorLocked(err)
+}
+
+func (c *Conn) handlePostHandshakeMessage() error {
+ msg, err := c.readHandshake()
+ if err != nil {
+ return err
+ }
+
+ if c.vers < VersionTLS13 {
+ if !c.isClient {
+ c.sendAlert(alertUnexpectedMessage)
+ return errors.New("tls: unexpected post-handshake message")
+ }
+
+ _, ok := msg.(*helloRequestMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return alertUnexpectedMessage
+ }
+
+ c.handshakeComplete = false
+ return c.Handshake()
+ }
+
+ if c.isClient {
+ if newSessionTicket, ok := msg.(*newSessionTicketMsg); ok {
+ if c.config.Bugs.ExpectGREASE && !newSessionTicket.hasGREASEExtension {
+ return errors.New("tls: no GREASE ticket extension found")
+ }
+
+ if c.config.Bugs.ExpectTicketEarlyDataInfo && newSessionTicket.maxEarlyDataSize == 0 {
+ return errors.New("tls: no ticket_early_data_info extension found")
+ }
+
+ if c.config.Bugs.ExpectNoNewSessionTicket {
+ return errors.New("tls: received unexpected NewSessionTicket")
+ }
+
+ if c.config.ClientSessionCache == nil || newSessionTicket.ticketLifetime == 0 {
+ return nil
+ }
+
+ session := &ClientSessionState{
+ sessionTicket: newSessionTicket.ticket,
+ vers: c.vers,
+ cipherSuite: c.cipherSuite.id,
+ masterSecret: c.resumptionSecret,
+ serverCertificates: c.peerCertificates,
+ sctList: c.sctList,
+ ocspResponse: c.ocspResponse,
+ ticketCreationTime: c.config.time(),
+ ticketExpiration: c.config.time().Add(time.Duration(newSessionTicket.ticketLifetime) * time.Second),
+ ticketAgeAdd: newSessionTicket.ticketAgeAdd,
+ maxEarlyDataSize: newSessionTicket.maxEarlyDataSize,
+ }
+
+ cacheKey := clientSessionCacheKey(c.conn.RemoteAddr(), c.config)
+ c.config.ClientSessionCache.Put(cacheKey, session)
+ return nil
+ }
+ }
+
+ if keyUpdate, ok := msg.(*keyUpdateMsg); ok {
+ c.in.doKeyUpdate(c, false)
+ if keyUpdate.keyUpdateRequest == keyUpdateRequested {
+ c.keyUpdateRequested = true
+ }
+ return nil
+ }
+
+ // TODO(davidben): Add support for KeyUpdate.
+ c.sendAlert(alertUnexpectedMessage)
+ return alertUnexpectedMessage
+}
+
+func (c *Conn) Renegotiate() error {
+ if !c.isClient {
+ helloReq := new(helloRequestMsg).marshal()
+ if c.config.Bugs.BadHelloRequest != nil {
+ helloReq = c.config.Bugs.BadHelloRequest
+ }
+ c.writeRecord(recordTypeHandshake, helloReq)
+ c.flushHandshake()
+ }
+
+ c.handshakeComplete = false
+ return c.Handshake()
+}
+
+// Read can be made to time out and return a net.Error with Timeout() == true
+// after a fixed time limit; see SetDeadline and SetReadDeadline.
+func (c *Conn) Read(b []byte) (n int, err error) {
+ if err = c.Handshake(); err != nil {
+ return
+ }
+
+ c.in.Lock()
+ defer c.in.Unlock()
+
+ // Some OpenSSL servers send empty records in order to randomize the
+ // CBC IV. So this loop ignores a limited number of empty records.
+ const maxConsecutiveEmptyRecords = 100
+ for emptyRecordCount := 0; emptyRecordCount <= maxConsecutiveEmptyRecords; emptyRecordCount++ {
+ for c.input == nil && c.in.err == nil {
+ if err := c.readRecord(recordTypeApplicationData); err != nil {
+ // Soft error, like EAGAIN
+ return 0, err
+ }
+ if c.hand.Len() > 0 {
+ // We received handshake bytes, indicating a
+ // post-handshake message.
+ if err := c.handlePostHandshakeMessage(); err != nil {
+ return 0, err
+ }
+ continue
+ }
+ }
+ if err := c.in.err; err != nil {
+ return 0, err
+ }
+
+ n, err = c.input.Read(b)
+ if c.input.off >= len(c.input.data) || c.isDTLS {
+ c.in.freeBlock(c.input)
+ c.input = nil
+ }
+
+ // If a close-notify alert is waiting, read it so that
+ // we can return (n, EOF) instead of (n, nil), to signal
+ // to the HTTP response reading goroutine that the
+ // connection is now closed. This eliminates a race
+ // where the HTTP response reading goroutine would
+ // otherwise not observe the EOF until its next read,
+ // by which time a client goroutine might have already
+ // tried to reuse the HTTP connection for a new
+ // request.
+ // See https://codereview.appspot.com/76400046
+ // and http://golang.org/issue/3514
+ if ri := c.rawInput; ri != nil &&
+ n != 0 && err == nil &&
+ c.input == nil && len(ri.data) > 0 && recordType(ri.data[0]) == recordTypeAlert {
+ if recErr := c.readRecord(recordTypeApplicationData); recErr != nil {
+ err = recErr // will be io.EOF on closeNotify
+ }
+ }
+
+ if n != 0 || err != nil {
+ return n, err
+ }
+ }
+
+ return 0, io.ErrNoProgress
+}
+
+// Close closes the connection.
+func (c *Conn) Close() error {
+ var alertErr error
+
+ c.handshakeMutex.Lock()
+ defer c.handshakeMutex.Unlock()
+ if c.handshakeComplete && !c.config.Bugs.NoCloseNotify {
+ alert := alertCloseNotify
+ if c.config.Bugs.SendAlertOnShutdown != 0 {
+ alert = c.config.Bugs.SendAlertOnShutdown
+ }
+ alertErr = c.sendAlert(alert)
+ // Clear local alerts when sending alerts so we continue to wait
+ // for the peer rather than closing the socket early.
+ if opErr, ok := alertErr.(*net.OpError); ok && opErr.Op == "local error" {
+ alertErr = nil
+ }
+ }
+
+ // Consume a close_notify from the peer if one hasn't been received
+ // already. This avoids the peer from failing |SSL_shutdown| due to a
+ // write failing.
+ if c.handshakeComplete && alertErr == nil && c.config.Bugs.ExpectCloseNotify {
+ for c.in.error() == nil {
+ c.readRecord(recordTypeAlert)
+ }
+ if c.in.error() != io.EOF {
+ alertErr = c.in.error()
+ }
+ }
+
+ if err := c.conn.Close(); err != nil {
+ return err
+ }
+ return alertErr
+}
+
+// Handshake runs the client or server handshake
+// protocol if it has not yet been run.
+// Most uses of this package need not call Handshake
+// explicitly: the first Read or Write will call it automatically.
+func (c *Conn) Handshake() error {
+ c.handshakeMutex.Lock()
+ defer c.handshakeMutex.Unlock()
+ if err := c.handshakeErr; err != nil {
+ return err
+ }
+ if c.handshakeComplete {
+ return nil
+ }
+
+ if c.isDTLS && c.config.Bugs.SendSplitAlert {
+ c.conn.Write([]byte{
+ byte(recordTypeAlert), // type
+ 0xfe, 0xff, // version
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // sequence
+ 0x0, 0x2, // length
+ })
+ c.conn.Write([]byte{alertLevelError, byte(alertInternalError)})
+ }
+ if data := c.config.Bugs.AppDataBeforeHandshake; data != nil {
+ c.writeRecord(recordTypeApplicationData, data)
+ }
+ if c.isClient {
+ c.handshakeErr = c.clientHandshake()
+ } else {
+ c.handshakeErr = c.serverHandshake()
+ }
+ if c.handshakeErr == nil && c.config.Bugs.SendInvalidRecordType {
+ c.writeRecord(recordType(42), []byte("invalid record"))
+ }
+ return c.handshakeErr
+}
+
+// ConnectionState returns basic TLS details about the connection.
+func (c *Conn) ConnectionState() ConnectionState {
+ c.handshakeMutex.Lock()
+ defer c.handshakeMutex.Unlock()
+
+ var state ConnectionState
+ state.HandshakeComplete = c.handshakeComplete
+ if c.handshakeComplete {
+ state.Version = c.vers
+ state.NegotiatedProtocol = c.clientProtocol
+ state.DidResume = c.didResume
+ state.NegotiatedProtocolIsMutual = !c.clientProtocolFallback
+ state.NegotiatedProtocolFromALPN = c.usedALPN
+ state.CipherSuite = c.cipherSuite.id
+ state.PeerCertificates = c.peerCertificates
+ state.VerifiedChains = c.verifiedChains
+ state.ServerName = c.serverName
+ state.ChannelID = c.channelID
+ state.SRTPProtectionProfile = c.srtpProtectionProfile
+ state.TLSUnique = c.firstFinished[:]
+ state.SCTList = c.sctList
+ state.PeerSignatureAlgorithm = c.peerSignatureAlgorithm
+ state.CurveID = c.curveID
+ }
+
+ return state
+}
+
+// OCSPResponse returns the stapled OCSP response from the TLS server, if
+// any. (Only valid for client connections.)
+func (c *Conn) OCSPResponse() []byte {
+ c.handshakeMutex.Lock()
+ defer c.handshakeMutex.Unlock()
+
+ return c.ocspResponse
+}
+
+// VerifyHostname checks that the peer certificate chain is valid for
+// connecting to host. If so, it returns nil; if not, it returns an error
+// describing the problem.
+func (c *Conn) VerifyHostname(host string) error {
+ c.handshakeMutex.Lock()
+ defer c.handshakeMutex.Unlock()
+ if !c.isClient {
+ return errors.New("tls: VerifyHostname called on TLS server connection")
+ }
+ if !c.handshakeComplete {
+ return errors.New("tls: handshake has not yet been performed")
+ }
+ return c.peerCertificates[0].VerifyHostname(host)
+}
+
+// ExportKeyingMaterial exports keying material from the current connection
+// state, as per RFC 5705.
+func (c *Conn) ExportKeyingMaterial(length int, label, context []byte, useContext bool) ([]byte, error) {
+ c.handshakeMutex.Lock()
+ defer c.handshakeMutex.Unlock()
+ if !c.handshakeComplete {
+ return nil, errors.New("tls: handshake has not yet been performed")
+ }
+
+ if c.vers >= VersionTLS13 {
+ // TODO(davidben): What should we do with useContext? See
+ // https://github.com/tlswg/tls13-spec/issues/546
+ return hkdfExpandLabel(c.cipherSuite.hash(), c.exporterSecret, label, context, length), nil
+ }
+
+ seedLen := len(c.clientRandom) + len(c.serverRandom)
+ if useContext {
+ seedLen += 2 + len(context)
+ }
+ seed := make([]byte, 0, seedLen)
+ seed = append(seed, c.clientRandom[:]...)
+ seed = append(seed, c.serverRandom[:]...)
+ if useContext {
+ seed = append(seed, byte(len(context)>>8), byte(len(context)))
+ seed = append(seed, context...)
+ }
+ result := make([]byte, length)
+ prfForVersion(c.vers, c.cipherSuite)(result, c.exporterSecret, label, seed)
+ return result, nil
+}
+
+// noRenegotiationInfo returns true if the renegotiation info extension
+// should be supported in the current handshake.
+func (c *Conn) noRenegotiationInfo() bool {
+ if c.config.Bugs.NoRenegotiationInfo {
+ return true
+ }
+ if c.cipherSuite == nil && c.config.Bugs.NoRenegotiationInfoInInitial {
+ return true
+ }
+ if c.cipherSuite != nil && c.config.Bugs.NoRenegotiationInfoAfterInitial {
+ return true
+ }
+ return false
+}
+
+func (c *Conn) SendNewSessionTicket() error {
+ if c.isClient || c.vers < VersionTLS13 {
+ return errors.New("tls: cannot send post-handshake NewSessionTicket")
+ }
+
+ var peerCertificatesRaw [][]byte
+ for _, cert := range c.peerCertificates {
+ peerCertificatesRaw = append(peerCertificatesRaw, cert.Raw)
+ }
+
+ addBuffer := make([]byte, 4)
+ _, err := io.ReadFull(c.config.rand(), addBuffer)
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return errors.New("tls: short read from Rand: " + err.Error())
+ }
+ ticketAgeAdd := uint32(addBuffer[3])<<24 | uint32(addBuffer[2])<<16 | uint32(addBuffer[1])<<8 | uint32(addBuffer[0])
+
+ // TODO(davidben): Allow configuring these values.
+ m := &newSessionTicketMsg{
+ version: c.vers,
+ ticketLifetime: uint32(24 * time.Hour / time.Second),
+ duplicateEarlyDataInfo: c.config.Bugs.DuplicateTicketEarlyDataInfo,
+ customExtension: c.config.Bugs.CustomTicketExtension,
+ ticketAgeAdd: ticketAgeAdd,
+ maxEarlyDataSize: c.config.MaxEarlyDataSize,
+ }
+
+ if c.config.Bugs.SendTicketLifetime != 0 {
+ m.ticketLifetime = uint32(c.config.Bugs.SendTicketLifetime / time.Second)
+ }
+
+ state := sessionState{
+ vers: c.vers,
+ cipherSuite: c.cipherSuite.id,
+ masterSecret: c.resumptionSecret,
+ certificates: peerCertificatesRaw,
+ ticketCreationTime: c.config.time(),
+ ticketExpiration: c.config.time().Add(time.Duration(m.ticketLifetime) * time.Second),
+ ticketAgeAdd: uint32(addBuffer[3])<<24 | uint32(addBuffer[2])<<16 | uint32(addBuffer[1])<<8 | uint32(addBuffer[0]),
+ }
+
+ if !c.config.Bugs.SendEmptySessionTicket {
+ var err error
+ m.ticket, err = c.encryptTicket(&state)
+ if err != nil {
+ return err
+ }
+ }
+
+ c.out.Lock()
+ defer c.out.Unlock()
+ _, err = c.writeRecord(recordTypeHandshake, m.marshal())
+ return err
+}
+
+func (c *Conn) SendKeyUpdate(keyUpdateRequest byte) error {
+ c.out.Lock()
+ defer c.out.Unlock()
+ return c.sendKeyUpdateLocked(keyUpdateRequest)
+}
+
+func (c *Conn) sendKeyUpdateLocked(keyUpdateRequest byte) error {
+ if c.vers < VersionTLS13 {
+ return errors.New("tls: attempted to send KeyUpdate before TLS 1.3")
+ }
+
+ m := keyUpdateMsg{
+ keyUpdateRequest: keyUpdateRequest,
+ }
+ if _, err := c.writeRecord(recordTypeHandshake, m.marshal()); err != nil {
+ return err
+ }
+ if err := c.flushHandshake(); err != nil {
+ return err
+ }
+ c.out.doKeyUpdate(c, true)
+ return nil
+}
+
+func (c *Conn) sendFakeEarlyData(len int) error {
+ // Assemble a fake early data record. This does not use writeRecord
+ // because the record layer may be using different keys at this point.
+ payload := make([]byte, 5+len)
+ payload[0] = byte(recordTypeApplicationData)
+ payload[1] = 3
+ payload[2] = 1
+ payload[3] = byte(len >> 8)
+ payload[4] = byte(len)
+ _, err := c.conn.Write(payload)
+ return err
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/curve25519/curve25519.go b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/curve25519/curve25519.go
new file mode 100644
index 000000000..6918c47fc
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/curve25519/curve25519.go
@@ -0,0 +1,841 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// We have a implementation in amd64 assembly so this code is only run on
+// non-amd64 platforms. The amd64 assembly does not support gccgo.
+// +build !amd64 gccgo appengine
+
+package curve25519
+
+// This code is a port of the public domain, "ref10" implementation of
+// curve25519 from SUPERCOP 20130419 by D. J. Bernstein.
+
+// fieldElement represents an element of the field GF(2^255 - 19). An element
+// t, entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77
+// t[3]+2^102 t[4]+...+2^230 t[9]. Bounds on each t[i] vary depending on
+// context.
+type fieldElement [10]int32
+
+func feZero(fe *fieldElement) {
+ for i := range fe {
+ fe[i] = 0
+ }
+}
+
+func feOne(fe *fieldElement) {
+ feZero(fe)
+ fe[0] = 1
+}
+
+func feAdd(dst, a, b *fieldElement) {
+ for i := range dst {
+ dst[i] = a[i] + b[i]
+ }
+}
+
+func feSub(dst, a, b *fieldElement) {
+ for i := range dst {
+ dst[i] = a[i] - b[i]
+ }
+}
+
+func feCopy(dst, src *fieldElement) {
+ for i := range dst {
+ dst[i] = src[i]
+ }
+}
+
+// feCSwap replaces (f,g) with (g,f) if b == 1; replaces (f,g) with (f,g) if b == 0.
+//
+// Preconditions: b in {0,1}.
+func feCSwap(f, g *fieldElement, b int32) {
+ var x fieldElement
+ b = -b
+ for i := range x {
+ x[i] = b & (f[i] ^ g[i])
+ }
+
+ for i := range f {
+ f[i] ^= x[i]
+ }
+ for i := range g {
+ g[i] ^= x[i]
+ }
+}
+
+// load3 reads a 24-bit, little-endian value from in.
+func load3(in []byte) int64 {
+ var r int64
+ r = int64(in[0])
+ r |= int64(in[1]) << 8
+ r |= int64(in[2]) << 16
+ return r
+}
+
+// load4 reads a 32-bit, little-endian value from in.
+func load4(in []byte) int64 {
+ var r int64
+ r = int64(in[0])
+ r |= int64(in[1]) << 8
+ r |= int64(in[2]) << 16
+ r |= int64(in[3]) << 24
+ return r
+}
+
+func feFromBytes(dst *fieldElement, src *[32]byte) {
+ h0 := load4(src[:])
+ h1 := load3(src[4:]) << 6
+ h2 := load3(src[7:]) << 5
+ h3 := load3(src[10:]) << 3
+ h4 := load3(src[13:]) << 2
+ h5 := load4(src[16:])
+ h6 := load3(src[20:]) << 7
+ h7 := load3(src[23:]) << 5
+ h8 := load3(src[26:]) << 4
+ h9 := load3(src[29:]) << 2
+
+ var carry [10]int64
+ carry[9] = (h9 + 1<<24) >> 25
+ h0 += carry[9] * 19
+ h9 -= carry[9] << 25
+ carry[1] = (h1 + 1<<24) >> 25
+ h2 += carry[1]
+ h1 -= carry[1] << 25
+ carry[3] = (h3 + 1<<24) >> 25
+ h4 += carry[3]
+ h3 -= carry[3] << 25
+ carry[5] = (h5 + 1<<24) >> 25
+ h6 += carry[5]
+ h5 -= carry[5] << 25
+ carry[7] = (h7 + 1<<24) >> 25
+ h8 += carry[7]
+ h7 -= carry[7] << 25
+
+ carry[0] = (h0 + 1<<25) >> 26
+ h1 += carry[0]
+ h0 -= carry[0] << 26
+ carry[2] = (h2 + 1<<25) >> 26
+ h3 += carry[2]
+ h2 -= carry[2] << 26
+ carry[4] = (h4 + 1<<25) >> 26
+ h5 += carry[4]
+ h4 -= carry[4] << 26
+ carry[6] = (h6 + 1<<25) >> 26
+ h7 += carry[6]
+ h6 -= carry[6] << 26
+ carry[8] = (h8 + 1<<25) >> 26
+ h9 += carry[8]
+ h8 -= carry[8] << 26
+
+ dst[0] = int32(h0)
+ dst[1] = int32(h1)
+ dst[2] = int32(h2)
+ dst[3] = int32(h3)
+ dst[4] = int32(h4)
+ dst[5] = int32(h5)
+ dst[6] = int32(h6)
+ dst[7] = int32(h7)
+ dst[8] = int32(h8)
+ dst[9] = int32(h9)
+}
+
+// feToBytes marshals h to s.
+// Preconditions:
+// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+//
+// Write p=2^255-19; q=floor(h/p).
+// Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))).
+//
+// Proof:
+// Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4.
+// Also have |h-2^230 h9|<2^230 so |19 2^(-255)(h-2^230 h9)|<1/4.
+//
+// Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9).
+// Then 0<y<1.
+//
+// Write r=h-pq.
+// Have 0<=r<=p-1=2^255-20.
+// Thus 0<=r+19(2^-255)r<r+19(2^-255)2^255<=2^255-1.
+//
+// Write x=r+19(2^-255)r+y.
+// Then 0<x<2^255 so floor(2^(-255)x) = 0 so floor(q+2^(-255)x) = q.
+//
+// Have q+2^(-255)x = 2^(-255)(h + 19 2^(-25) h9 + 2^(-1))
+// so floor(2^(-255)(h + 19 2^(-25) h9 + 2^(-1))) = q.
+func feToBytes(s *[32]byte, h *fieldElement) {
+ var carry [10]int32
+
+ q := (19*h[9] + (1 << 24)) >> 25
+ q = (h[0] + q) >> 26
+ q = (h[1] + q) >> 25
+ q = (h[2] + q) >> 26
+ q = (h[3] + q) >> 25
+ q = (h[4] + q) >> 26
+ q = (h[5] + q) >> 25
+ q = (h[6] + q) >> 26
+ q = (h[7] + q) >> 25
+ q = (h[8] + q) >> 26
+ q = (h[9] + q) >> 25
+
+ // Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20.
+ h[0] += 19 * q
+ // Goal: Output h-2^255 q, which is between 0 and 2^255-20.
+
+ carry[0] = h[0] >> 26
+ h[1] += carry[0]
+ h[0] -= carry[0] << 26
+ carry[1] = h[1] >> 25
+ h[2] += carry[1]
+ h[1] -= carry[1] << 25
+ carry[2] = h[2] >> 26
+ h[3] += carry[2]
+ h[2] -= carry[2] << 26
+ carry[3] = h[3] >> 25
+ h[4] += carry[3]
+ h[3] -= carry[3] << 25
+ carry[4] = h[4] >> 26
+ h[5] += carry[4]
+ h[4] -= carry[4] << 26
+ carry[5] = h[5] >> 25
+ h[6] += carry[5]
+ h[5] -= carry[5] << 25
+ carry[6] = h[6] >> 26
+ h[7] += carry[6]
+ h[6] -= carry[6] << 26
+ carry[7] = h[7] >> 25
+ h[8] += carry[7]
+ h[7] -= carry[7] << 25
+ carry[8] = h[8] >> 26
+ h[9] += carry[8]
+ h[8] -= carry[8] << 26
+ carry[9] = h[9] >> 25
+ h[9] -= carry[9] << 25
+ // h10 = carry9
+
+ // Goal: Output h[0]+...+2^255 h10-2^255 q, which is between 0 and 2^255-20.
+ // Have h[0]+...+2^230 h[9] between 0 and 2^255-1;
+ // evidently 2^255 h10-2^255 q = 0.
+ // Goal: Output h[0]+...+2^230 h[9].
+
+ s[0] = byte(h[0] >> 0)
+ s[1] = byte(h[0] >> 8)
+ s[2] = byte(h[0] >> 16)
+ s[3] = byte((h[0] >> 24) | (h[1] << 2))
+ s[4] = byte(h[1] >> 6)
+ s[5] = byte(h[1] >> 14)
+ s[6] = byte((h[1] >> 22) | (h[2] << 3))
+ s[7] = byte(h[2] >> 5)
+ s[8] = byte(h[2] >> 13)
+ s[9] = byte((h[2] >> 21) | (h[3] << 5))
+ s[10] = byte(h[3] >> 3)
+ s[11] = byte(h[3] >> 11)
+ s[12] = byte((h[3] >> 19) | (h[4] << 6))
+ s[13] = byte(h[4] >> 2)
+ s[14] = byte(h[4] >> 10)
+ s[15] = byte(h[4] >> 18)
+ s[16] = byte(h[5] >> 0)
+ s[17] = byte(h[5] >> 8)
+ s[18] = byte(h[5] >> 16)
+ s[19] = byte((h[5] >> 24) | (h[6] << 1))
+ s[20] = byte(h[6] >> 7)
+ s[21] = byte(h[6] >> 15)
+ s[22] = byte((h[6] >> 23) | (h[7] << 3))
+ s[23] = byte(h[7] >> 5)
+ s[24] = byte(h[7] >> 13)
+ s[25] = byte((h[7] >> 21) | (h[8] << 4))
+ s[26] = byte(h[8] >> 4)
+ s[27] = byte(h[8] >> 12)
+ s[28] = byte((h[8] >> 20) | (h[9] << 6))
+ s[29] = byte(h[9] >> 2)
+ s[30] = byte(h[9] >> 10)
+ s[31] = byte(h[9] >> 18)
+}
+
+// feMul calculates h = f * g
+// Can overlap h with f or g.
+//
+// Preconditions:
+// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+// |g| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+//
+// Postconditions:
+// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+//
+// Notes on implementation strategy:
+//
+// Using schoolbook multiplication.
+// Karatsuba would save a little in some cost models.
+//
+// Most multiplications by 2 and 19 are 32-bit precomputations;
+// cheaper than 64-bit postcomputations.
+//
+// There is one remaining multiplication by 19 in the carry chain;
+// one *19 precomputation can be merged into this,
+// but the resulting data flow is considerably less clean.
+//
+// There are 12 carries below.
+// 10 of them are 2-way parallelizable and vectorizable.
+// Can get away with 11 carries, but then data flow is much deeper.
+//
+// With tighter constraints on inputs can squeeze carries into int32.
+func feMul(h, f, g *fieldElement) {
+ f0 := f[0]
+ f1 := f[1]
+ f2 := f[2]
+ f3 := f[3]
+ f4 := f[4]
+ f5 := f[5]
+ f6 := f[6]
+ f7 := f[7]
+ f8 := f[8]
+ f9 := f[9]
+ g0 := g[0]
+ g1 := g[1]
+ g2 := g[2]
+ g3 := g[3]
+ g4 := g[4]
+ g5 := g[5]
+ g6 := g[6]
+ g7 := g[7]
+ g8 := g[8]
+ g9 := g[9]
+ g1_19 := 19 * g1 // 1.4*2^29
+ g2_19 := 19 * g2 // 1.4*2^30; still ok
+ g3_19 := 19 * g3
+ g4_19 := 19 * g4
+ g5_19 := 19 * g5
+ g6_19 := 19 * g6
+ g7_19 := 19 * g7
+ g8_19 := 19 * g8
+ g9_19 := 19 * g9
+ f1_2 := 2 * f1
+ f3_2 := 2 * f3
+ f5_2 := 2 * f5
+ f7_2 := 2 * f7
+ f9_2 := 2 * f9
+ f0g0 := int64(f0) * int64(g0)
+ f0g1 := int64(f0) * int64(g1)
+ f0g2 := int64(f0) * int64(g2)
+ f0g3 := int64(f0) * int64(g3)
+ f0g4 := int64(f0) * int64(g4)
+ f0g5 := int64(f0) * int64(g5)
+ f0g6 := int64(f0) * int64(g6)
+ f0g7 := int64(f0) * int64(g7)
+ f0g8 := int64(f0) * int64(g8)
+ f0g9 := int64(f0) * int64(g9)
+ f1g0 := int64(f1) * int64(g0)
+ f1g1_2 := int64(f1_2) * int64(g1)
+ f1g2 := int64(f1) * int64(g2)
+ f1g3_2 := int64(f1_2) * int64(g3)
+ f1g4 := int64(f1) * int64(g4)
+ f1g5_2 := int64(f1_2) * int64(g5)
+ f1g6 := int64(f1) * int64(g6)
+ f1g7_2 := int64(f1_2) * int64(g7)
+ f1g8 := int64(f1) * int64(g8)
+ f1g9_38 := int64(f1_2) * int64(g9_19)
+ f2g0 := int64(f2) * int64(g0)
+ f2g1 := int64(f2) * int64(g1)
+ f2g2 := int64(f2) * int64(g2)
+ f2g3 := int64(f2) * int64(g3)
+ f2g4 := int64(f2) * int64(g4)
+ f2g5 := int64(f2) * int64(g5)
+ f2g6 := int64(f2) * int64(g6)
+ f2g7 := int64(f2) * int64(g7)
+ f2g8_19 := int64(f2) * int64(g8_19)
+ f2g9_19 := int64(f2) * int64(g9_19)
+ f3g0 := int64(f3) * int64(g0)
+ f3g1_2 := int64(f3_2) * int64(g1)
+ f3g2 := int64(f3) * int64(g2)
+ f3g3_2 := int64(f3_2) * int64(g3)
+ f3g4 := int64(f3) * int64(g4)
+ f3g5_2 := int64(f3_2) * int64(g5)
+ f3g6 := int64(f3) * int64(g6)
+ f3g7_38 := int64(f3_2) * int64(g7_19)
+ f3g8_19 := int64(f3) * int64(g8_19)
+ f3g9_38 := int64(f3_2) * int64(g9_19)
+ f4g0 := int64(f4) * int64(g0)
+ f4g1 := int64(f4) * int64(g1)
+ f4g2 := int64(f4) * int64(g2)
+ f4g3 := int64(f4) * int64(g3)
+ f4g4 := int64(f4) * int64(g4)
+ f4g5 := int64(f4) * int64(g5)
+ f4g6_19 := int64(f4) * int64(g6_19)
+ f4g7_19 := int64(f4) * int64(g7_19)
+ f4g8_19 := int64(f4) * int64(g8_19)
+ f4g9_19 := int64(f4) * int64(g9_19)
+ f5g0 := int64(f5) * int64(g0)
+ f5g1_2 := int64(f5_2) * int64(g1)
+ f5g2 := int64(f5) * int64(g2)
+ f5g3_2 := int64(f5_2) * int64(g3)
+ f5g4 := int64(f5) * int64(g4)
+ f5g5_38 := int64(f5_2) * int64(g5_19)
+ f5g6_19 := int64(f5) * int64(g6_19)
+ f5g7_38 := int64(f5_2) * int64(g7_19)
+ f5g8_19 := int64(f5) * int64(g8_19)
+ f5g9_38 := int64(f5_2) * int64(g9_19)
+ f6g0 := int64(f6) * int64(g0)
+ f6g1 := int64(f6) * int64(g1)
+ f6g2 := int64(f6) * int64(g2)
+ f6g3 := int64(f6) * int64(g3)
+ f6g4_19 := int64(f6) * int64(g4_19)
+ f6g5_19 := int64(f6) * int64(g5_19)
+ f6g6_19 := int64(f6) * int64(g6_19)
+ f6g7_19 := int64(f6) * int64(g7_19)
+ f6g8_19 := int64(f6) * int64(g8_19)
+ f6g9_19 := int64(f6) * int64(g9_19)
+ f7g0 := int64(f7) * int64(g0)
+ f7g1_2 := int64(f7_2) * int64(g1)
+ f7g2 := int64(f7) * int64(g2)
+ f7g3_38 := int64(f7_2) * int64(g3_19)
+ f7g4_19 := int64(f7) * int64(g4_19)
+ f7g5_38 := int64(f7_2) * int64(g5_19)
+ f7g6_19 := int64(f7) * int64(g6_19)
+ f7g7_38 := int64(f7_2) * int64(g7_19)
+ f7g8_19 := int64(f7) * int64(g8_19)
+ f7g9_38 := int64(f7_2) * int64(g9_19)
+ f8g0 := int64(f8) * int64(g0)
+ f8g1 := int64(f8) * int64(g1)
+ f8g2_19 := int64(f8) * int64(g2_19)
+ f8g3_19 := int64(f8) * int64(g3_19)
+ f8g4_19 := int64(f8) * int64(g4_19)
+ f8g5_19 := int64(f8) * int64(g5_19)
+ f8g6_19 := int64(f8) * int64(g6_19)
+ f8g7_19 := int64(f8) * int64(g7_19)
+ f8g8_19 := int64(f8) * int64(g8_19)
+ f8g9_19 := int64(f8) * int64(g9_19)
+ f9g0 := int64(f9) * int64(g0)
+ f9g1_38 := int64(f9_2) * int64(g1_19)
+ f9g2_19 := int64(f9) * int64(g2_19)
+ f9g3_38 := int64(f9_2) * int64(g3_19)
+ f9g4_19 := int64(f9) * int64(g4_19)
+ f9g5_38 := int64(f9_2) * int64(g5_19)
+ f9g6_19 := int64(f9) * int64(g6_19)
+ f9g7_38 := int64(f9_2) * int64(g7_19)
+ f9g8_19 := int64(f9) * int64(g8_19)
+ f9g9_38 := int64(f9_2) * int64(g9_19)
+ h0 := f0g0 + f1g9_38 + f2g8_19 + f3g7_38 + f4g6_19 + f5g5_38 + f6g4_19 + f7g3_38 + f8g2_19 + f9g1_38
+ h1 := f0g1 + f1g0 + f2g9_19 + f3g8_19 + f4g7_19 + f5g6_19 + f6g5_19 + f7g4_19 + f8g3_19 + f9g2_19
+ h2 := f0g2 + f1g1_2 + f2g0 + f3g9_38 + f4g8_19 + f5g7_38 + f6g6_19 + f7g5_38 + f8g4_19 + f9g3_38
+ h3 := f0g3 + f1g2 + f2g1 + f3g0 + f4g9_19 + f5g8_19 + f6g7_19 + f7g6_19 + f8g5_19 + f9g4_19
+ h4 := f0g4 + f1g3_2 + f2g2 + f3g1_2 + f4g0 + f5g9_38 + f6g8_19 + f7g7_38 + f8g6_19 + f9g5_38
+ h5 := f0g5 + f1g4 + f2g3 + f3g2 + f4g1 + f5g0 + f6g9_19 + f7g8_19 + f8g7_19 + f9g6_19
+ h6 := f0g6 + f1g5_2 + f2g4 + f3g3_2 + f4g2 + f5g1_2 + f6g0 + f7g9_38 + f8g8_19 + f9g7_38
+ h7 := f0g7 + f1g6 + f2g5 + f3g4 + f4g3 + f5g2 + f6g1 + f7g0 + f8g9_19 + f9g8_19
+ h8 := f0g8 + f1g7_2 + f2g6 + f3g5_2 + f4g4 + f5g3_2 + f6g2 + f7g1_2 + f8g0 + f9g9_38
+ h9 := f0g9 + f1g8 + f2g7 + f3g6 + f4g5 + f5g4 + f6g3 + f7g2 + f8g1 + f9g0
+ var carry [10]int64
+
+ // |h0| <= (1.1*1.1*2^52*(1+19+19+19+19)+1.1*1.1*2^50*(38+38+38+38+38))
+ // i.e. |h0| <= 1.2*2^59; narrower ranges for h2, h4, h6, h8
+ // |h1| <= (1.1*1.1*2^51*(1+1+19+19+19+19+19+19+19+19))
+ // i.e. |h1| <= 1.5*2^58; narrower ranges for h3, h5, h7, h9
+
+ carry[0] = (h0 + (1 << 25)) >> 26
+ h1 += carry[0]
+ h0 -= carry[0] << 26
+ carry[4] = (h4 + (1 << 25)) >> 26
+ h5 += carry[4]
+ h4 -= carry[4] << 26
+ // |h0| <= 2^25
+ // |h4| <= 2^25
+ // |h1| <= 1.51*2^58
+ // |h5| <= 1.51*2^58
+
+ carry[1] = (h1 + (1 << 24)) >> 25
+ h2 += carry[1]
+ h1 -= carry[1] << 25
+ carry[5] = (h5 + (1 << 24)) >> 25
+ h6 += carry[5]
+ h5 -= carry[5] << 25
+ // |h1| <= 2^24; from now on fits into int32
+ // |h5| <= 2^24; from now on fits into int32
+ // |h2| <= 1.21*2^59
+ // |h6| <= 1.21*2^59
+
+ carry[2] = (h2 + (1 << 25)) >> 26
+ h3 += carry[2]
+ h2 -= carry[2] << 26
+ carry[6] = (h6 + (1 << 25)) >> 26
+ h7 += carry[6]
+ h6 -= carry[6] << 26
+ // |h2| <= 2^25; from now on fits into int32 unchanged
+ // |h6| <= 2^25; from now on fits into int32 unchanged
+ // |h3| <= 1.51*2^58
+ // |h7| <= 1.51*2^58
+
+ carry[3] = (h3 + (1 << 24)) >> 25
+ h4 += carry[3]
+ h3 -= carry[3] << 25
+ carry[7] = (h7 + (1 << 24)) >> 25
+ h8 += carry[7]
+ h7 -= carry[7] << 25
+ // |h3| <= 2^24; from now on fits into int32 unchanged
+ // |h7| <= 2^24; from now on fits into int32 unchanged
+ // |h4| <= 1.52*2^33
+ // |h8| <= 1.52*2^33
+
+ carry[4] = (h4 + (1 << 25)) >> 26
+ h5 += carry[4]
+ h4 -= carry[4] << 26
+ carry[8] = (h8 + (1 << 25)) >> 26
+ h9 += carry[8]
+ h8 -= carry[8] << 26
+ // |h4| <= 2^25; from now on fits into int32 unchanged
+ // |h8| <= 2^25; from now on fits into int32 unchanged
+ // |h5| <= 1.01*2^24
+ // |h9| <= 1.51*2^58
+
+ carry[9] = (h9 + (1 << 24)) >> 25
+ h0 += carry[9] * 19
+ h9 -= carry[9] << 25
+ // |h9| <= 2^24; from now on fits into int32 unchanged
+ // |h0| <= 1.8*2^37
+
+ carry[0] = (h0 + (1 << 25)) >> 26
+ h1 += carry[0]
+ h0 -= carry[0] << 26
+ // |h0| <= 2^25; from now on fits into int32 unchanged
+ // |h1| <= 1.01*2^24
+
+ h[0] = int32(h0)
+ h[1] = int32(h1)
+ h[2] = int32(h2)
+ h[3] = int32(h3)
+ h[4] = int32(h4)
+ h[5] = int32(h5)
+ h[6] = int32(h6)
+ h[7] = int32(h7)
+ h[8] = int32(h8)
+ h[9] = int32(h9)
+}
+
+// feSquare calculates h = f*f. Can overlap h with f.
+//
+// Preconditions:
+// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+//
+// Postconditions:
+// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+func feSquare(h, f *fieldElement) {
+ f0 := f[0]
+ f1 := f[1]
+ f2 := f[2]
+ f3 := f[3]
+ f4 := f[4]
+ f5 := f[5]
+ f6 := f[6]
+ f7 := f[7]
+ f8 := f[8]
+ f9 := f[9]
+ f0_2 := 2 * f0
+ f1_2 := 2 * f1
+ f2_2 := 2 * f2
+ f3_2 := 2 * f3
+ f4_2 := 2 * f4
+ f5_2 := 2 * f5
+ f6_2 := 2 * f6
+ f7_2 := 2 * f7
+ f5_38 := 38 * f5 // 1.31*2^30
+ f6_19 := 19 * f6 // 1.31*2^30
+ f7_38 := 38 * f7 // 1.31*2^30
+ f8_19 := 19 * f8 // 1.31*2^30
+ f9_38 := 38 * f9 // 1.31*2^30
+ f0f0 := int64(f0) * int64(f0)
+ f0f1_2 := int64(f0_2) * int64(f1)
+ f0f2_2 := int64(f0_2) * int64(f2)
+ f0f3_2 := int64(f0_2) * int64(f3)
+ f0f4_2 := int64(f0_2) * int64(f4)
+ f0f5_2 := int64(f0_2) * int64(f5)
+ f0f6_2 := int64(f0_2) * int64(f6)
+ f0f7_2 := int64(f0_2) * int64(f7)
+ f0f8_2 := int64(f0_2) * int64(f8)
+ f0f9_2 := int64(f0_2) * int64(f9)
+ f1f1_2 := int64(f1_2) * int64(f1)
+ f1f2_2 := int64(f1_2) * int64(f2)
+ f1f3_4 := int64(f1_2) * int64(f3_2)
+ f1f4_2 := int64(f1_2) * int64(f4)
+ f1f5_4 := int64(f1_2) * int64(f5_2)
+ f1f6_2 := int64(f1_2) * int64(f6)
+ f1f7_4 := int64(f1_2) * int64(f7_2)
+ f1f8_2 := int64(f1_2) * int64(f8)
+ f1f9_76 := int64(f1_2) * int64(f9_38)
+ f2f2 := int64(f2) * int64(f2)
+ f2f3_2 := int64(f2_2) * int64(f3)
+ f2f4_2 := int64(f2_2) * int64(f4)
+ f2f5_2 := int64(f2_2) * int64(f5)
+ f2f6_2 := int64(f2_2) * int64(f6)
+ f2f7_2 := int64(f2_2) * int64(f7)
+ f2f8_38 := int64(f2_2) * int64(f8_19)
+ f2f9_38 := int64(f2) * int64(f9_38)
+ f3f3_2 := int64(f3_2) * int64(f3)
+ f3f4_2 := int64(f3_2) * int64(f4)
+ f3f5_4 := int64(f3_2) * int64(f5_2)
+ f3f6_2 := int64(f3_2) * int64(f6)
+ f3f7_76 := int64(f3_2) * int64(f7_38)
+ f3f8_38 := int64(f3_2) * int64(f8_19)
+ f3f9_76 := int64(f3_2) * int64(f9_38)
+ f4f4 := int64(f4) * int64(f4)
+ f4f5_2 := int64(f4_2) * int64(f5)
+ f4f6_38 := int64(f4_2) * int64(f6_19)
+ f4f7_38 := int64(f4) * int64(f7_38)
+ f4f8_38 := int64(f4_2) * int64(f8_19)
+ f4f9_38 := int64(f4) * int64(f9_38)
+ f5f5_38 := int64(f5) * int64(f5_38)
+ f5f6_38 := int64(f5_2) * int64(f6_19)
+ f5f7_76 := int64(f5_2) * int64(f7_38)
+ f5f8_38 := int64(f5_2) * int64(f8_19)
+ f5f9_76 := int64(f5_2) * int64(f9_38)
+ f6f6_19 := int64(f6) * int64(f6_19)
+ f6f7_38 := int64(f6) * int64(f7_38)
+ f6f8_38 := int64(f6_2) * int64(f8_19)
+ f6f9_38 := int64(f6) * int64(f9_38)
+ f7f7_38 := int64(f7) * int64(f7_38)
+ f7f8_38 := int64(f7_2) * int64(f8_19)
+ f7f9_76 := int64(f7_2) * int64(f9_38)
+ f8f8_19 := int64(f8) * int64(f8_19)
+ f8f9_38 := int64(f8) * int64(f9_38)
+ f9f9_38 := int64(f9) * int64(f9_38)
+ h0 := f0f0 + f1f9_76 + f2f8_38 + f3f7_76 + f4f6_38 + f5f5_38
+ h1 := f0f1_2 + f2f9_38 + f3f8_38 + f4f7_38 + f5f6_38
+ h2 := f0f2_2 + f1f1_2 + f3f9_76 + f4f8_38 + f5f7_76 + f6f6_19
+ h3 := f0f3_2 + f1f2_2 + f4f9_38 + f5f8_38 + f6f7_38
+ h4 := f0f4_2 + f1f3_4 + f2f2 + f5f9_76 + f6f8_38 + f7f7_38
+ h5 := f0f5_2 + f1f4_2 + f2f3_2 + f6f9_38 + f7f8_38
+ h6 := f0f6_2 + f1f5_4 + f2f4_2 + f3f3_2 + f7f9_76 + f8f8_19
+ h7 := f0f7_2 + f1f6_2 + f2f5_2 + f3f4_2 + f8f9_38
+ h8 := f0f8_2 + f1f7_4 + f2f6_2 + f3f5_4 + f4f4 + f9f9_38
+ h9 := f0f9_2 + f1f8_2 + f2f7_2 + f3f6_2 + f4f5_2
+ var carry [10]int64
+
+ carry[0] = (h0 + (1 << 25)) >> 26
+ h1 += carry[0]
+ h0 -= carry[0] << 26
+ carry[4] = (h4 + (1 << 25)) >> 26
+ h5 += carry[4]
+ h4 -= carry[4] << 26
+
+ carry[1] = (h1 + (1 << 24)) >> 25
+ h2 += carry[1]
+ h1 -= carry[1] << 25
+ carry[5] = (h5 + (1 << 24)) >> 25
+ h6 += carry[5]
+ h5 -= carry[5] << 25
+
+ carry[2] = (h2 + (1 << 25)) >> 26
+ h3 += carry[2]
+ h2 -= carry[2] << 26
+ carry[6] = (h6 + (1 << 25)) >> 26
+ h7 += carry[6]
+ h6 -= carry[6] << 26
+
+ carry[3] = (h3 + (1 << 24)) >> 25
+ h4 += carry[3]
+ h3 -= carry[3] << 25
+ carry[7] = (h7 + (1 << 24)) >> 25
+ h8 += carry[7]
+ h7 -= carry[7] << 25
+
+ carry[4] = (h4 + (1 << 25)) >> 26
+ h5 += carry[4]
+ h4 -= carry[4] << 26
+ carry[8] = (h8 + (1 << 25)) >> 26
+ h9 += carry[8]
+ h8 -= carry[8] << 26
+
+ carry[9] = (h9 + (1 << 24)) >> 25
+ h0 += carry[9] * 19
+ h9 -= carry[9] << 25
+
+ carry[0] = (h0 + (1 << 25)) >> 26
+ h1 += carry[0]
+ h0 -= carry[0] << 26
+
+ h[0] = int32(h0)
+ h[1] = int32(h1)
+ h[2] = int32(h2)
+ h[3] = int32(h3)
+ h[4] = int32(h4)
+ h[5] = int32(h5)
+ h[6] = int32(h6)
+ h[7] = int32(h7)
+ h[8] = int32(h8)
+ h[9] = int32(h9)
+}
+
+// feMul121666 calculates h = f * 121666. Can overlap h with f.
+//
+// Preconditions:
+// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+//
+// Postconditions:
+// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+func feMul121666(h, f *fieldElement) {
+ h0 := int64(f[0]) * 121666
+ h1 := int64(f[1]) * 121666
+ h2 := int64(f[2]) * 121666
+ h3 := int64(f[3]) * 121666
+ h4 := int64(f[4]) * 121666
+ h5 := int64(f[5]) * 121666
+ h6 := int64(f[6]) * 121666
+ h7 := int64(f[7]) * 121666
+ h8 := int64(f[8]) * 121666
+ h9 := int64(f[9]) * 121666
+ var carry [10]int64
+
+ carry[9] = (h9 + (1 << 24)) >> 25
+ h0 += carry[9] * 19
+ h9 -= carry[9] << 25
+ carry[1] = (h1 + (1 << 24)) >> 25
+ h2 += carry[1]
+ h1 -= carry[1] << 25
+ carry[3] = (h3 + (1 << 24)) >> 25
+ h4 += carry[3]
+ h3 -= carry[3] << 25
+ carry[5] = (h5 + (1 << 24)) >> 25
+ h6 += carry[5]
+ h5 -= carry[5] << 25
+ carry[7] = (h7 + (1 << 24)) >> 25
+ h8 += carry[7]
+ h7 -= carry[7] << 25
+
+ carry[0] = (h0 + (1 << 25)) >> 26
+ h1 += carry[0]
+ h0 -= carry[0] << 26
+ carry[2] = (h2 + (1 << 25)) >> 26
+ h3 += carry[2]
+ h2 -= carry[2] << 26
+ carry[4] = (h4 + (1 << 25)) >> 26
+ h5 += carry[4]
+ h4 -= carry[4] << 26
+ carry[6] = (h6 + (1 << 25)) >> 26
+ h7 += carry[6]
+ h6 -= carry[6] << 26
+ carry[8] = (h8 + (1 << 25)) >> 26
+ h9 += carry[8]
+ h8 -= carry[8] << 26
+
+ h[0] = int32(h0)
+ h[1] = int32(h1)
+ h[2] = int32(h2)
+ h[3] = int32(h3)
+ h[4] = int32(h4)
+ h[5] = int32(h5)
+ h[6] = int32(h6)
+ h[7] = int32(h7)
+ h[8] = int32(h8)
+ h[9] = int32(h9)
+}
+
+// feInvert sets out = z^-1.
+func feInvert(out, z *fieldElement) {
+ var t0, t1, t2, t3 fieldElement
+ var i int
+
+ feSquare(&t0, z)
+ for i = 1; i < 1; i++ {
+ feSquare(&t0, &t0)
+ }
+ feSquare(&t1, &t0)
+ for i = 1; i < 2; i++ {
+ feSquare(&t1, &t1)
+ }
+ feMul(&t1, z, &t1)
+ feMul(&t0, &t0, &t1)
+ feSquare(&t2, &t0)
+ for i = 1; i < 1; i++ {
+ feSquare(&t2, &t2)
+ }
+ feMul(&t1, &t1, &t2)
+ feSquare(&t2, &t1)
+ for i = 1; i < 5; i++ {
+ feSquare(&t2, &t2)
+ }
+ feMul(&t1, &t2, &t1)
+ feSquare(&t2, &t1)
+ for i = 1; i < 10; i++ {
+ feSquare(&t2, &t2)
+ }
+ feMul(&t2, &t2, &t1)
+ feSquare(&t3, &t2)
+ for i = 1; i < 20; i++ {
+ feSquare(&t3, &t3)
+ }
+ feMul(&t2, &t3, &t2)
+ feSquare(&t2, &t2)
+ for i = 1; i < 10; i++ {
+ feSquare(&t2, &t2)
+ }
+ feMul(&t1, &t2, &t1)
+ feSquare(&t2, &t1)
+ for i = 1; i < 50; i++ {
+ feSquare(&t2, &t2)
+ }
+ feMul(&t2, &t2, &t1)
+ feSquare(&t3, &t2)
+ for i = 1; i < 100; i++ {
+ feSquare(&t3, &t3)
+ }
+ feMul(&t2, &t3, &t2)
+ feSquare(&t2, &t2)
+ for i = 1; i < 50; i++ {
+ feSquare(&t2, &t2)
+ }
+ feMul(&t1, &t2, &t1)
+ feSquare(&t1, &t1)
+ for i = 1; i < 5; i++ {
+ feSquare(&t1, &t1)
+ }
+ feMul(out, &t1, &t0)
+}
+
+func scalarMult(out, in, base *[32]byte) {
+ var e [32]byte
+
+ copy(e[:], in[:])
+ e[0] &= 248
+ e[31] &= 127
+ e[31] |= 64
+
+ var x1, x2, z2, x3, z3, tmp0, tmp1 fieldElement
+ feFromBytes(&x1, base)
+ feOne(&x2)
+ feCopy(&x3, &x1)
+ feOne(&z3)
+
+ swap := int32(0)
+ for pos := 254; pos >= 0; pos-- {
+ b := e[pos/8] >> uint(pos&7)
+ b &= 1
+ swap ^= int32(b)
+ feCSwap(&x2, &x3, swap)
+ feCSwap(&z2, &z3, swap)
+ swap = int32(b)
+
+ feSub(&tmp0, &x3, &z3)
+ feSub(&tmp1, &x2, &z2)
+ feAdd(&x2, &x2, &z2)
+ feAdd(&z2, &x3, &z3)
+ feMul(&z3, &tmp0, &x2)
+ feMul(&z2, &z2, &tmp1)
+ feSquare(&tmp0, &tmp1)
+ feSquare(&tmp1, &x2)
+ feAdd(&x3, &z3, &z2)
+ feSub(&z2, &z3, &z2)
+ feMul(&x2, &tmp1, &tmp0)
+ feSub(&tmp1, &tmp1, &tmp0)
+ feSquare(&z2, &z2)
+ feMul121666(&z3, &tmp1)
+ feSquare(&x3, &x3)
+ feAdd(&tmp0, &tmp0, &z3)
+ feMul(&z3, &x1, &z2)
+ feMul(&z2, &tmp1, &tmp0)
+ }
+
+ feCSwap(&x2, &x3, swap)
+ feCSwap(&z2, &z3, swap)
+
+ feInvert(&z2, &z2)
+ feMul(&x2, &x2, &z2)
+ feToBytes(out, &x2)
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/curve25519/curve25519_test.go b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/curve25519/curve25519_test.go
new file mode 100644
index 000000000..14b0ee87c
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/curve25519/curve25519_test.go
@@ -0,0 +1,29 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package curve25519
+
+import (
+ "fmt"
+ "testing"
+)
+
+const expectedHex = "89161fde887b2b53de549af483940106ecc114d6982daa98256de23bdf77661a"
+
+func TestBaseScalarMult(t *testing.T) {
+ var a, b [32]byte
+ in := &a
+ out := &b
+ a[0] = 1
+
+ for i := 0; i < 200; i++ {
+ ScalarBaseMult(out, in)
+ in, out = out, in
+ }
+
+ result := fmt.Sprintf("%x", in[:])
+ if result != expectedHex {
+ t.Errorf("incorrect result: got %s, want %s", result, expectedHex)
+ }
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/curve25519/doc.go b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/curve25519/doc.go
new file mode 100644
index 000000000..ebeea3c2d
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/curve25519/doc.go
@@ -0,0 +1,23 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package curve25519 provides an implementation of scalar multiplication on
+// the elliptic curve known as curve25519. See http://cr.yp.to/ecdh.html
+package curve25519 // import "golang.org/x/crypto/curve25519"
+
+// basePoint is the x coordinate of the generator of the curve.
+var basePoint = [32]byte{9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+
+// ScalarMult sets dst to the product in*base where dst and base are the x
+// coordinates of group points and all values are in little-endian form.
+func ScalarMult(dst, in, base *[32]byte) {
+ scalarMult(dst, in, base)
+}
+
+// ScalarBaseMult sets dst to the product in*base where dst and base are the x
+// coordinates of group points, base is the standard generator and all values
+// are in little-endian form.
+func ScalarBaseMult(dst, in *[32]byte) {
+ ScalarMult(dst, in, &basePoint)
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/curve25519/mont25519_amd64.go b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/curve25519/mont25519_amd64.go
new file mode 100644
index 000000000..5822bd533
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/curve25519/mont25519_amd64.go
@@ -0,0 +1,240 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build amd64,!gccgo,!appengine
+
+package curve25519
+
+// These functions are implemented in the .s files. The names of the functions
+// in the rest of the file are also taken from the SUPERCOP sources to help
+// people following along.
+
+//go:noescape
+
+func cswap(inout *[5]uint64, v uint64)
+
+//go:noescape
+
+func ladderstep(inout *[5][5]uint64)
+
+//go:noescape
+
+func freeze(inout *[5]uint64)
+
+//go:noescape
+
+func mul(dest, a, b *[5]uint64)
+
+//go:noescape
+
+func square(out, in *[5]uint64)
+
+// mladder uses a Montgomery ladder to calculate (xr/zr) *= s.
+func mladder(xr, zr *[5]uint64, s *[32]byte) {
+ var work [5][5]uint64
+
+ work[0] = *xr
+ setint(&work[1], 1)
+ setint(&work[2], 0)
+ work[3] = *xr
+ setint(&work[4], 1)
+
+ j := uint(6)
+ var prevbit byte
+
+ for i := 31; i >= 0; i-- {
+ for j < 8 {
+ bit := ((*s)[i] >> j) & 1
+ swap := bit ^ prevbit
+ prevbit = bit
+ cswap(&work[1], uint64(swap))
+ ladderstep(&work)
+ j--
+ }
+ j = 7
+ }
+
+ *xr = work[1]
+ *zr = work[2]
+}
+
+func scalarMult(out, in, base *[32]byte) {
+ var e [32]byte
+ copy(e[:], (*in)[:])
+ e[0] &= 248
+ e[31] &= 127
+ e[31] |= 64
+
+ var t, z [5]uint64
+ unpack(&t, base)
+ mladder(&t, &z, &e)
+ invert(&z, &z)
+ mul(&t, &t, &z)
+ pack(out, &t)
+}
+
+func setint(r *[5]uint64, v uint64) {
+ r[0] = v
+ r[1] = 0
+ r[2] = 0
+ r[3] = 0
+ r[4] = 0
+}
+
+// unpack sets r = x where r consists of 5, 51-bit limbs in little-endian
+// order.
+func unpack(r *[5]uint64, x *[32]byte) {
+ r[0] = uint64(x[0]) |
+ uint64(x[1])<<8 |
+ uint64(x[2])<<16 |
+ uint64(x[3])<<24 |
+ uint64(x[4])<<32 |
+ uint64(x[5])<<40 |
+ uint64(x[6]&7)<<48
+
+ r[1] = uint64(x[6])>>3 |
+ uint64(x[7])<<5 |
+ uint64(x[8])<<13 |
+ uint64(x[9])<<21 |
+ uint64(x[10])<<29 |
+ uint64(x[11])<<37 |
+ uint64(x[12]&63)<<45
+
+ r[2] = uint64(x[12])>>6 |
+ uint64(x[13])<<2 |
+ uint64(x[14])<<10 |
+ uint64(x[15])<<18 |
+ uint64(x[16])<<26 |
+ uint64(x[17])<<34 |
+ uint64(x[18])<<42 |
+ uint64(x[19]&1)<<50
+
+ r[3] = uint64(x[19])>>1 |
+ uint64(x[20])<<7 |
+ uint64(x[21])<<15 |
+ uint64(x[22])<<23 |
+ uint64(x[23])<<31 |
+ uint64(x[24])<<39 |
+ uint64(x[25]&15)<<47
+
+ r[4] = uint64(x[25])>>4 |
+ uint64(x[26])<<4 |
+ uint64(x[27])<<12 |
+ uint64(x[28])<<20 |
+ uint64(x[29])<<28 |
+ uint64(x[30])<<36 |
+ uint64(x[31]&127)<<44
+}
+
+// pack sets out = x where out is the usual, little-endian form of the 5,
+// 51-bit limbs in x.
+func pack(out *[32]byte, x *[5]uint64) {
+ t := *x
+ freeze(&t)
+
+ out[0] = byte(t[0])
+ out[1] = byte(t[0] >> 8)
+ out[2] = byte(t[0] >> 16)
+ out[3] = byte(t[0] >> 24)
+ out[4] = byte(t[0] >> 32)
+ out[5] = byte(t[0] >> 40)
+ out[6] = byte(t[0] >> 48)
+
+ out[6] ^= byte(t[1]<<3) & 0xf8
+ out[7] = byte(t[1] >> 5)
+ out[8] = byte(t[1] >> 13)
+ out[9] = byte(t[1] >> 21)
+ out[10] = byte(t[1] >> 29)
+ out[11] = byte(t[1] >> 37)
+ out[12] = byte(t[1] >> 45)
+
+ out[12] ^= byte(t[2]<<6) & 0xc0
+ out[13] = byte(t[2] >> 2)
+ out[14] = byte(t[2] >> 10)
+ out[15] = byte(t[2] >> 18)
+ out[16] = byte(t[2] >> 26)
+ out[17] = byte(t[2] >> 34)
+ out[18] = byte(t[2] >> 42)
+ out[19] = byte(t[2] >> 50)
+
+ out[19] ^= byte(t[3]<<1) & 0xfe
+ out[20] = byte(t[3] >> 7)
+ out[21] = byte(t[3] >> 15)
+ out[22] = byte(t[3] >> 23)
+ out[23] = byte(t[3] >> 31)
+ out[24] = byte(t[3] >> 39)
+ out[25] = byte(t[3] >> 47)
+
+ out[25] ^= byte(t[4]<<4) & 0xf0
+ out[26] = byte(t[4] >> 4)
+ out[27] = byte(t[4] >> 12)
+ out[28] = byte(t[4] >> 20)
+ out[29] = byte(t[4] >> 28)
+ out[30] = byte(t[4] >> 36)
+ out[31] = byte(t[4] >> 44)
+}
+
+// invert calculates r = x^-1 mod p using Fermat's little theorem.
+func invert(r *[5]uint64, x *[5]uint64) {
+ var z2, z9, z11, z2_5_0, z2_10_0, z2_20_0, z2_50_0, z2_100_0, t [5]uint64
+
+ square(&z2, x) /* 2 */
+ square(&t, &z2) /* 4 */
+ square(&t, &t) /* 8 */
+ mul(&z9, &t, x) /* 9 */
+ mul(&z11, &z9, &z2) /* 11 */
+ square(&t, &z11) /* 22 */
+ mul(&z2_5_0, &t, &z9) /* 2^5 - 2^0 = 31 */
+
+ square(&t, &z2_5_0) /* 2^6 - 2^1 */
+ for i := 1; i < 5; i++ { /* 2^20 - 2^10 */
+ square(&t, &t)
+ }
+ mul(&z2_10_0, &t, &z2_5_0) /* 2^10 - 2^0 */
+
+ square(&t, &z2_10_0) /* 2^11 - 2^1 */
+ for i := 1; i < 10; i++ { /* 2^20 - 2^10 */
+ square(&t, &t)
+ }
+ mul(&z2_20_0, &t, &z2_10_0) /* 2^20 - 2^0 */
+
+ square(&t, &z2_20_0) /* 2^21 - 2^1 */
+ for i := 1; i < 20; i++ { /* 2^40 - 2^20 */
+ square(&t, &t)
+ }
+ mul(&t, &t, &z2_20_0) /* 2^40 - 2^0 */
+
+ square(&t, &t) /* 2^41 - 2^1 */
+ for i := 1; i < 10; i++ { /* 2^50 - 2^10 */
+ square(&t, &t)
+ }
+ mul(&z2_50_0, &t, &z2_10_0) /* 2^50 - 2^0 */
+
+ square(&t, &z2_50_0) /* 2^51 - 2^1 */
+ for i := 1; i < 50; i++ { /* 2^100 - 2^50 */
+ square(&t, &t)
+ }
+ mul(&z2_100_0, &t, &z2_50_0) /* 2^100 - 2^0 */
+
+ square(&t, &z2_100_0) /* 2^101 - 2^1 */
+ for i := 1; i < 100; i++ { /* 2^200 - 2^100 */
+ square(&t, &t)
+ }
+ mul(&t, &t, &z2_100_0) /* 2^200 - 2^0 */
+
+ square(&t, &t) /* 2^201 - 2^1 */
+ for i := 1; i < 50; i++ { /* 2^250 - 2^50 */
+ square(&t, &t)
+ }
+ mul(&t, &t, &z2_50_0) /* 2^250 - 2^0 */
+
+ square(&t, &t) /* 2^251 - 2^1 */
+ square(&t, &t) /* 2^252 - 2^2 */
+ square(&t, &t) /* 2^253 - 2^3 */
+
+ square(&t, &t) /* 2^254 - 2^4 */
+
+ square(&t, &t) /* 2^255 - 2^5 */
+ mul(r, &t, &z11) /* 2^255 - 21 */
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/deterministic.go b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/deterministic.go
new file mode 100644
index 000000000..2b71076b1
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/deterministic.go
@@ -0,0 +1,37 @@
+// Copyright (c) 2016, 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 runner
+
+import (
+ "encoding/binary"
+)
+
+// Use a different key from crypto/rand/deterministic.c.
+var deterministicRandKey = []byte("runner deterministic key 0123456")
+
+type deterministicRand struct {
+ numCalls uint64
+}
+
+func (d *deterministicRand) Read(buf []byte) (int, error) {
+ for i := range buf {
+ buf[i] = 0
+ }
+ var nonce [12]byte
+ binary.LittleEndian.PutUint64(nonce[:8], d.numCalls)
+ chaCha20(buf, buf, deterministicRandKey, nonce[:], 0)
+ d.numCalls++
+ return len(buf), nil
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/dtls.go b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/dtls.go
new file mode 100644
index 000000000..e273bc796
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/dtls.go
@@ -0,0 +1,499 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// DTLS implementation.
+//
+// NOTE: This is a not even a remotely production-quality DTLS
+// implementation. It is the bare minimum necessary to be able to
+// achieve coverage on BoringSSL's implementation. Of note is that
+// this implementation assumes the underlying net.PacketConn is not
+// only reliable but also ordered. BoringSSL will be expected to deal
+// with simulated loss, but there is no point in forcing the test
+// driver to.
+
+package runner
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "io"
+ "math/rand"
+ "net"
+)
+
+func versionToWire(vers uint16, isDTLS bool) uint16 {
+ if isDTLS {
+ switch vers {
+ case VersionTLS12:
+ return 0xfefd
+ case VersionTLS10:
+ return 0xfeff
+ }
+ } else {
+ switch vers {
+ case VersionSSL30, VersionTLS10, VersionTLS11, VersionTLS12:
+ return vers
+ case VersionTLS13:
+ return tls13DraftVersion
+ }
+ }
+
+ panic("unknown version")
+}
+
+func wireToVersion(vers uint16, isDTLS bool) (uint16, bool) {
+ if isDTLS {
+ switch vers {
+ case 0xfefd:
+ return VersionTLS12, true
+ case 0xfeff:
+ return VersionTLS10, true
+ }
+ } else {
+ switch vers {
+ case VersionSSL30, VersionTLS10, VersionTLS11, VersionTLS12:
+ return vers, true
+ case tls13DraftVersion:
+ return VersionTLS13, true
+ }
+ }
+
+ return 0, false
+}
+
+func (c *Conn) dtlsDoReadRecord(want recordType) (recordType, *block, error) {
+ recordHeaderLen := dtlsRecordHeaderLen
+
+ if c.rawInput == nil {
+ c.rawInput = c.in.newBlock()
+ }
+ b := c.rawInput
+
+ // Read a new packet only if the current one is empty.
+ var newPacket bool
+ if len(b.data) == 0 {
+ // Pick some absurdly large buffer size.
+ b.resize(maxCiphertext + recordHeaderLen)
+ n, err := c.conn.Read(c.rawInput.data)
+ if err != nil {
+ return 0, nil, err
+ }
+ if c.config.Bugs.MaxPacketLength != 0 && n > c.config.Bugs.MaxPacketLength {
+ return 0, nil, fmt.Errorf("dtls: exceeded maximum packet length")
+ }
+ c.rawInput.resize(n)
+ newPacket = true
+ }
+
+ // Read out one record.
+ //
+ // A real DTLS implementation should be tolerant of errors,
+ // but this is test code. We should not be tolerant of our
+ // peer sending garbage.
+ if len(b.data) < recordHeaderLen {
+ return 0, nil, errors.New("dtls: failed to read record header")
+ }
+ typ := recordType(b.data[0])
+ vers := uint16(b.data[1])<<8 | uint16(b.data[2])
+ // Alerts sent near version negotiation do not have a well-defined
+ // record-layer version prior to TLS 1.3. (In TLS 1.3, the record-layer
+ // version is irrelevant.)
+ if typ != recordTypeAlert {
+ if c.haveVers {
+ if wireVers := versionToWire(c.vers, c.isDTLS); vers != wireVers {
+ c.sendAlert(alertProtocolVersion)
+ return 0, nil, c.in.setErrorLocked(fmt.Errorf("dtls: received record with version %x when expecting version %x", vers, wireVers))
+ }
+ } else {
+ // Pre-version-negotiation alerts may be sent with any version.
+ if expect := c.config.Bugs.ExpectInitialRecordVersion; expect != 0 && vers != expect {
+ c.sendAlert(alertProtocolVersion)
+ return 0, nil, c.in.setErrorLocked(fmt.Errorf("dtls: received record with version %x when expecting version %x", vers, expect))
+ }
+ }
+ }
+ epoch := b.data[3:5]
+ seq := b.data[5:11]
+ // For test purposes, require the sequence number be monotonically
+ // increasing, so c.in includes the minimum next sequence number. Gaps
+ // may occur if packets failed to be sent out. A real implementation
+ // would maintain a replay window and such.
+ if !bytes.Equal(epoch, c.in.seq[:2]) {
+ c.sendAlert(alertIllegalParameter)
+ return 0, nil, c.in.setErrorLocked(fmt.Errorf("dtls: bad epoch"))
+ }
+ if bytes.Compare(seq, c.in.seq[2:]) < 0 {
+ c.sendAlert(alertIllegalParameter)
+ return 0, nil, c.in.setErrorLocked(fmt.Errorf("dtls: bad sequence number"))
+ }
+ copy(c.in.seq[2:], seq)
+ n := int(b.data[11])<<8 | int(b.data[12])
+ if n > maxCiphertext || len(b.data) < recordHeaderLen+n {
+ c.sendAlert(alertRecordOverflow)
+ return 0, nil, c.in.setErrorLocked(fmt.Errorf("dtls: oversized record received with length %d", n))
+ }
+
+ // Process message.
+ b, c.rawInput = c.in.splitBlock(b, recordHeaderLen+n)
+ ok, off, _, alertValue := c.in.decrypt(b)
+ if !ok {
+ // A real DTLS implementation would silently ignore bad records,
+ // but we want to notice errors from the implementation under
+ // test.
+ return 0, nil, c.in.setErrorLocked(c.sendAlert(alertValue))
+ }
+ b.off = off
+
+ // TODO(nharper): Once DTLS 1.3 is defined, handle the extra
+ // parameter from decrypt.
+
+ // Require that ChangeCipherSpec always share a packet with either the
+ // previous or next handshake message.
+ if newPacket && typ == recordTypeChangeCipherSpec && c.rawInput == nil {
+ return 0, nil, c.in.setErrorLocked(fmt.Errorf("dtls: ChangeCipherSpec not packed together with Finished"))
+ }
+
+ return typ, b, nil
+}
+
+func (c *Conn) makeFragment(header, data []byte, fragOffset, fragLen int) []byte {
+ fragment := make([]byte, 0, 12+fragLen)
+ fragment = append(fragment, header...)
+ fragment = append(fragment, byte(c.sendHandshakeSeq>>8), byte(c.sendHandshakeSeq))
+ fragment = append(fragment, byte(fragOffset>>16), byte(fragOffset>>8), byte(fragOffset))
+ fragment = append(fragment, byte(fragLen>>16), byte(fragLen>>8), byte(fragLen))
+ fragment = append(fragment, data[fragOffset:fragOffset+fragLen]...)
+ return fragment
+}
+
+func (c *Conn) dtlsWriteRecord(typ recordType, data []byte) (n int, err error) {
+ if typ != recordTypeHandshake {
+ // Only handshake messages are fragmented.
+ n, err = c.dtlsWriteRawRecord(typ, data)
+ if err != nil {
+ return
+ }
+
+ if typ == recordTypeChangeCipherSpec {
+ err = c.out.changeCipherSpec(c.config)
+ if err != nil {
+ // Cannot call sendAlert directly,
+ // because we already hold c.out.Mutex.
+ c.tmp[0] = alertLevelError
+ c.tmp[1] = byte(err.(alert))
+ c.writeRecord(recordTypeAlert, c.tmp[0:2])
+ return n, c.out.setErrorLocked(&net.OpError{Op: "local error", Err: err})
+ }
+ }
+ return
+ }
+
+ if c.out.cipher == nil && c.config.Bugs.StrayChangeCipherSpec {
+ _, err = c.dtlsWriteRawRecord(recordTypeChangeCipherSpec, []byte{1})
+ if err != nil {
+ return
+ }
+ }
+
+ maxLen := c.config.Bugs.MaxHandshakeRecordLength
+ if maxLen <= 0 {
+ maxLen = 1024
+ }
+
+ // Handshake messages have to be modified to include fragment
+ // offset and length and with the header replicated. Save the
+ // TLS header here.
+ //
+ // TODO(davidben): This assumes that data contains exactly one
+ // handshake message. This is incompatible with
+ // FragmentAcrossChangeCipherSpec. (Which is unfortunate
+ // because OpenSSL's DTLS implementation will probably accept
+ // such fragmentation and could do with a fix + tests.)
+ header := data[:4]
+ data = data[4:]
+
+ isFinished := header[0] == typeFinished
+
+ if c.config.Bugs.SendEmptyFragments {
+ fragment := c.makeFragment(header, data, 0, 0)
+ c.pendingFragments = append(c.pendingFragments, fragment)
+ }
+
+ firstRun := true
+ fragOffset := 0
+ for firstRun || fragOffset < len(data) {
+ firstRun = false
+ fragLen := len(data) - fragOffset
+ if fragLen > maxLen {
+ fragLen = maxLen
+ }
+
+ fragment := c.makeFragment(header, data, fragOffset, fragLen)
+ if c.config.Bugs.FragmentMessageTypeMismatch && fragOffset > 0 {
+ fragment[0]++
+ }
+ if c.config.Bugs.FragmentMessageLengthMismatch && fragOffset > 0 {
+ fragment[3]++
+ }
+
+ // Buffer the fragment for later. They will be sent (and
+ // reordered) on flush.
+ c.pendingFragments = append(c.pendingFragments, fragment)
+ if c.config.Bugs.ReorderHandshakeFragments {
+ // Don't duplicate Finished to avoid the peer
+ // interpreting it as a retransmit request.
+ if !isFinished {
+ c.pendingFragments = append(c.pendingFragments, fragment)
+ }
+
+ if fragLen > (maxLen+1)/2 {
+ // Overlap each fragment by half.
+ fragLen = (maxLen + 1) / 2
+ }
+ }
+ fragOffset += fragLen
+ n += fragLen
+ }
+ if !isFinished && c.config.Bugs.MixCompleteMessageWithFragments {
+ fragment := c.makeFragment(header, data, 0, len(data))
+ c.pendingFragments = append(c.pendingFragments, fragment)
+ }
+
+ // Increment the handshake sequence number for the next
+ // handshake message.
+ c.sendHandshakeSeq++
+ return
+}
+
+func (c *Conn) dtlsFlushHandshake() error {
+ // This is a test-only DTLS implementation, so there is no need to
+ // retain |c.pendingFragments| for a future retransmit.
+ var fragments [][]byte
+ fragments, c.pendingFragments = c.pendingFragments, fragments
+
+ if c.config.Bugs.ReorderHandshakeFragments {
+ perm := rand.New(rand.NewSource(0)).Perm(len(fragments))
+ tmp := make([][]byte, len(fragments))
+ for i := range tmp {
+ tmp[i] = fragments[perm[i]]
+ }
+ fragments = tmp
+ } else if c.config.Bugs.ReverseHandshakeFragments {
+ tmp := make([][]byte, len(fragments))
+ for i := range tmp {
+ tmp[i] = fragments[len(fragments)-i-1]
+ }
+ fragments = tmp
+ }
+
+ maxRecordLen := c.config.Bugs.PackHandshakeFragments
+ maxPacketLen := c.config.Bugs.PackHandshakeRecords
+
+ // Pack handshake fragments into records.
+ var records [][]byte
+ for _, fragment := range fragments {
+ if n := c.config.Bugs.SplitFragments; n > 0 {
+ if len(fragment) > n {
+ records = append(records, fragment[:n])
+ records = append(records, fragment[n:])
+ } else {
+ records = append(records, fragment)
+ }
+ } else if i := len(records) - 1; len(records) > 0 && len(records[i])+len(fragment) <= maxRecordLen {
+ records[i] = append(records[i], fragment...)
+ } else {
+ // The fragment will be appended to, so copy it.
+ records = append(records, append([]byte{}, fragment...))
+ }
+ }
+
+ // Format them into packets.
+ var packets [][]byte
+ for _, record := range records {
+ b, err := c.dtlsSealRecord(recordTypeHandshake, record)
+ if err != nil {
+ return err
+ }
+
+ if i := len(packets) - 1; len(packets) > 0 && len(packets[i])+len(b.data) <= maxPacketLen {
+ packets[i] = append(packets[i], b.data...)
+ } else {
+ // The sealed record will be appended to and reused by
+ // |c.out|, so copy it.
+ packets = append(packets, append([]byte{}, b.data...))
+ }
+ c.out.freeBlock(b)
+ }
+
+ // Send all the packets.
+ for _, packet := range packets {
+ if _, err := c.conn.Write(packet); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// dtlsSealRecord seals a record into a block from |c.out|'s pool.
+func (c *Conn) dtlsSealRecord(typ recordType, data []byte) (b *block, err error) {
+ recordHeaderLen := dtlsRecordHeaderLen
+ maxLen := c.config.Bugs.MaxHandshakeRecordLength
+ if maxLen <= 0 {
+ maxLen = 1024
+ }
+
+ b = c.out.newBlock()
+
+ explicitIVLen := 0
+ explicitIVIsSeq := false
+
+ if cbc, ok := c.out.cipher.(cbcMode); ok {
+ // Block cipher modes have an explicit IV.
+ explicitIVLen = cbc.BlockSize()
+ } else if aead, ok := c.out.cipher.(*tlsAead); ok {
+ if aead.explicitNonce {
+ explicitIVLen = 8
+ // The AES-GCM construction in TLS has an explicit nonce so that
+ // the nonce can be random. However, the nonce is only 8 bytes
+ // which is too small for a secure, random nonce. Therefore we
+ // use the sequence number as the nonce.
+ explicitIVIsSeq = true
+ }
+ } else if _, ok := c.out.cipher.(nullCipher); !ok && c.out.cipher != nil {
+ panic("Unknown cipher")
+ }
+ b.resize(recordHeaderLen + explicitIVLen + len(data))
+ // TODO(nharper): DTLS 1.3 will likely need to set this to
+ // recordTypeApplicationData if c.out.cipher != nil.
+ b.data[0] = byte(typ)
+ vers := c.vers
+ if vers == 0 {
+ // Some TLS servers fail if the record version is greater than
+ // TLS 1.0 for the initial ClientHello.
+ vers = VersionTLS10
+ }
+ vers = versionToWire(vers, c.isDTLS)
+ b.data[1] = byte(vers >> 8)
+ b.data[2] = byte(vers)
+ // DTLS records include an explicit sequence number.
+ copy(b.data[3:11], c.out.outSeq[0:])
+ b.data[11] = byte(len(data) >> 8)
+ b.data[12] = byte(len(data))
+ if explicitIVLen > 0 {
+ explicitIV := b.data[recordHeaderLen : recordHeaderLen+explicitIVLen]
+ if explicitIVIsSeq {
+ copy(explicitIV, c.out.outSeq[:])
+ } else {
+ if _, err = io.ReadFull(c.config.rand(), explicitIV); err != nil {
+ return
+ }
+ }
+ }
+ copy(b.data[recordHeaderLen+explicitIVLen:], data)
+ c.out.encrypt(b, explicitIVLen, typ)
+ return
+}
+
+func (c *Conn) dtlsWriteRawRecord(typ recordType, data []byte) (n int, err error) {
+ b, err := c.dtlsSealRecord(typ, data)
+ if err != nil {
+ return
+ }
+
+ _, err = c.conn.Write(b.data)
+ if err != nil {
+ return
+ }
+ n = len(data)
+
+ c.out.freeBlock(b)
+ return
+}
+
+func (c *Conn) dtlsDoReadHandshake() ([]byte, error) {
+ // Assemble a full handshake message. For test purposes, this
+ // implementation assumes fragments arrive in order. It may
+ // need to be cleverer if we ever test BoringSSL's retransmit
+ // behavior.
+ for len(c.handMsg) < 4+c.handMsgLen {
+ // Get a new handshake record if the previous has been
+ // exhausted.
+ if c.hand.Len() == 0 {
+ if err := c.in.err; err != nil {
+ return nil, err
+ }
+ if err := c.readRecord(recordTypeHandshake); err != nil {
+ return nil, err
+ }
+ }
+
+ // Read the next fragment. It must fit entirely within
+ // the record.
+ if c.hand.Len() < 12 {
+ return nil, errors.New("dtls: bad handshake record")
+ }
+ header := c.hand.Next(12)
+ fragN := int(header[1])<<16 | int(header[2])<<8 | int(header[3])
+ fragSeq := uint16(header[4])<<8 | uint16(header[5])
+ fragOff := int(header[6])<<16 | int(header[7])<<8 | int(header[8])
+ fragLen := int(header[9])<<16 | int(header[10])<<8 | int(header[11])
+
+ if c.hand.Len() < fragLen {
+ return nil, errors.New("dtls: fragment length too long")
+ }
+ fragment := c.hand.Next(fragLen)
+
+ // Check it's a fragment for the right message.
+ if fragSeq != c.recvHandshakeSeq {
+ return nil, errors.New("dtls: bad handshake sequence number")
+ }
+
+ // Check that the length is consistent.
+ if c.handMsg == nil {
+ c.handMsgLen = fragN
+ if c.handMsgLen > maxHandshake {
+ return nil, c.in.setErrorLocked(c.sendAlert(alertInternalError))
+ }
+ // Start with the TLS handshake header,
+ // without the DTLS bits.
+ c.handMsg = append([]byte{}, header[:4]...)
+ } else if fragN != c.handMsgLen {
+ return nil, errors.New("dtls: bad handshake length")
+ }
+
+ // Add the fragment to the pending message.
+ if 4+fragOff != len(c.handMsg) {
+ return nil, errors.New("dtls: bad fragment offset")
+ }
+ if fragOff+fragLen > c.handMsgLen {
+ return nil, errors.New("dtls: bad fragment length")
+ }
+ c.handMsg = append(c.handMsg, fragment...)
+ }
+ c.recvHandshakeSeq++
+ ret := c.handMsg
+ c.handMsg, c.handMsgLen = nil, 0
+ return ret, nil
+}
+
+// DTLSServer returns a new DTLS server side connection
+// using conn as the underlying transport.
+// The configuration config must be non-nil and must have
+// at least one certificate.
+func DTLSServer(conn net.Conn, config *Config) *Conn {
+ c := &Conn{config: config, isDTLS: true, conn: conn}
+ c.init()
+ return c
+}
+
+// DTLSClient returns a new DTLS client side connection
+// using conn as the underlying transport.
+// The config cannot be nil: users must set either ServerHostname or
+// InsecureSkipVerify in the config.
+func DTLSClient(conn net.Conn, config *Config) *Conn {
+ c := &Conn{config: config, isClient: true, isDTLS: true, conn: conn}
+ c.init()
+ return c
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/ecdsa_p224_cert.pem b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/ecdsa_p224_cert.pem
new file mode 100644
index 000000000..29246a2ea
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/ecdsa_p224_cert.pem
@@ -0,0 +1,12 @@
+-----BEGIN CERTIFICATE-----
+MIIBvjCCAWygAwIBAgIJAPlkrPTq4HgnMAoGCCqGSM49BAMCMEUxCzAJBgNVBAYT
+AkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRn
+aXRzIFB0eSBMdGQwHhcNMTcwMjI3MjAxOTIzWhcNMTkwMjI3MjAxOTIzWjBFMQsw
+CQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJu
+ZXQgV2lkZ2l0cyBQdHkgTHRkME4wEAYHKoZIzj0CAQYFK4EEACEDOgAE6dul6dL0
++CyooFiKK4V+EYNYPbMZoLTxRcjRgrw3db6QzBAviDSxKADTVuyRmaVC74Mf6boB
+HDmjUDBOMB0GA1UdDgQWBBSMtlkUJ7SCZ4zRqkjXMWvOebSgpTAfBgNVHSMEGDAW
+gBSMtlkUJ7SCZ4zRqkjXMWvOebSgpTAMBgNVHRMEBTADAQH/MAoGCCqGSM49BAMC
+A0AAMD0CHHolWPktSLbVMy9ukQUb2E7+Jb3hcNFqAXh47pYCHQC+jv2EE6oOEZ9F
+tLkFLtap71+83P0NUEJX4Etu
+-----END CERTIFICATE-----
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/ecdsa_p224_key.pem b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/ecdsa_p224_key.pem
new file mode 100644
index 000000000..cfe411b45
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/ecdsa_p224_key.pem
@@ -0,0 +1,5 @@
+-----BEGIN EC PRIVATE KEY-----
+MGgCAQEEHGi+rNLi+gHJqmRRtdlLBOw1WYv7H/VnlYGAZ0+gBwYFK4EEACGhPAM6
+AATp26Xp0vT4LKigWIorhX4Rg1g9sxmgtPFFyNGCvDd1vpDMEC+INLEoANNW7JGZ
+pULvgx/pugEcOQ==
+-----END EC PRIVATE KEY-----
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/ecdsa_p256_cert.pem b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/ecdsa_p256_cert.pem
new file mode 100644
index 000000000..50bcbf5bf
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/ecdsa_p256_cert.pem
@@ -0,0 +1,12 @@
+-----BEGIN CERTIFICATE-----
+MIIBzzCCAXagAwIBAgIJANlMBNpJfb/rMAkGByqGSM49BAEwRTELMAkGA1UEBhMC
+QVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdp
+dHMgUHR5IEx0ZDAeFw0xNDA0MjMyMzIxNTdaFw0xNDA1MjMyMzIxNTdaMEUxCzAJ
+BgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5l
+dCBXaWRnaXRzIFB0eSBMdGQwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATmK2ni
+v2Wfl74vHg2UikzVl2u3qR4NRvvdqakendy6WgHn1peoChj5w8SjHlbifINI2xYa
+HPUdfvGULUvPciLBo1AwTjAdBgNVHQ4EFgQUq4TSrKuV8IJOFngHVVdf5CaNgtEw
+HwYDVR0jBBgwFoAUq4TSrKuV8IJOFngHVVdf5CaNgtEwDAYDVR0TBAUwAwEB/zAJ
+BgcqhkjOPQQBA0gAMEUCIQDyoDVeUTo2w4J5m+4nUIWOcAZ0lVfSKXQA9L4Vh13E
+BwIgfB55FGohg/B6dGh5XxSZmmi08cueFV7mHzJSYV51yRQ=
+-----END CERTIFICATE-----
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/ecdsa_p256_key.pem b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/ecdsa_p256_key.pem
new file mode 100644
index 000000000..bce6a1e15
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/ecdsa_p256_key.pem
@@ -0,0 +1,5 @@
+-----BEGIN PRIVATE KEY-----
+MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgBw8IcnrUoEqc3VnJ
+TYlodwi1b8ldMHcO6NHJzgqLtGqhRANCAATmK2niv2Wfl74vHg2UikzVl2u3qR4N
+Rvvdqakendy6WgHn1peoChj5w8SjHlbifINI2xYaHPUdfvGULUvPciLB
+-----END PRIVATE KEY-----
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/ecdsa_p384_cert.pem b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/ecdsa_p384_cert.pem
new file mode 100644
index 000000000..1fd3fec63
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/ecdsa_p384_cert.pem
@@ -0,0 +1,15 @@
+-----BEGIN CERTIFICATE-----
+MIICZTCCAeugAwIBAgIJAN+/LubpDwxNMAkGByqGSM49BAEwRTELMAkGA1UEBhMC
+QVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdp
+dHMgUHR5IEx0ZDAeFw0xNjA3MDkwMDAxMzJaFw0xNjA4MDgwMDAxMzJaMEUxCzAJ
+BgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5l
+dCBXaWRnaXRzIFB0eSBMdGQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQOdTJNqxiZ
++B68tCZV4GEJwDJ18jK9gFzvefcEAQluBijjrMjflL+RZAT64ExWzedRMp9PD9CW
+Tz9hG/Kz4q/l952YsIhy7LTGXzwy7549WUOi+N3aW8psDjtwzWNZXqWjgacwgaQw
+HQYDVR0OBBYEFKmYPjADcOlogOMU6D9wlftIWMj6MHUGA1UdIwRuMGyAFKmYPjAD
+cOlogOMU6D9wlftIWMj6oUmkRzBFMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29t
+ZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkggkA378u
+5ukPDE0wDAYDVR0TBAUwAwEB/zAJBgcqhkjOPQQBA2kAMGYCMQDTfL0OkRGnS5Ze
+tsxagAuZqM2Zyv5a2g7u6eFLCx2rpTuQndWOtEnmVo3wjTDtkDcCMQCg+05XSqEF
+cqxdXMZJMhqj2jS+tWucdgDstp/1KzJkbsupSjBzIycjVBKLdRwtNg8=
+-----END CERTIFICATE-----
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/ecdsa_p384_key.pem b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/ecdsa_p384_key.pem
new file mode 100644
index 000000000..d72e10451
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/ecdsa_p384_key.pem
@@ -0,0 +1,6 @@
+-----BEGIN PRIVATE KEY-----
+MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDCVFIFNZ6y5EijVMUuD
+W+WJsQRAVxsZ+6ge1Nez2IoOr3+APs6+fj130OJinFATXa2hZANiAAQOdTJNqxiZ
++B68tCZV4GEJwDJ18jK9gFzvefcEAQluBijjrMjflL+RZAT64ExWzedRMp9PD9CW
+Tz9hG/Kz4q/l952YsIhy7LTGXzwy7549WUOi+N3aW8psDjtwzWNZXqU=
+-----END PRIVATE KEY-----
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/ecdsa_p521_cert.pem b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/ecdsa_p521_cert.pem
new file mode 100644
index 000000000..8b9a1e838
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/ecdsa_p521_cert.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICrzCCAhGgAwIBAgIJAMZT7oSqTg/lMAkGByqGSM49BAEwRTELMAkGA1UEBhMC
+QVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdp
+dHMgUHR5IEx0ZDAeFw0xNjA3MDkwMDAwNTBaFw0xNjA4MDgwMDAwNTBaMEUxCzAJ
+BgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5l
+dCBXaWRnaXRzIFB0eSBMdGQwgZswEAYHKoZIzj0CAQYFK4EEACMDgYYABAFD0TiZ
+InCoCYDI66FvoaZ0tniUhaNk2YnjEPikfmYHDwstbqkTEqnGAq3pKF2y/MHTBXFd
+E0KcFOPs5Ju8EgIcqwGvCkwHPmZtvvOrf+nJNHdm1gZfBUy09f3fVe/mHwfM2++H
+dz54nHKxtQqvdafhmMV77R/rBuI24MLKbMihxRgQKaOBpzCBpDAdBgNVHQ4EFgQU
+mLWm6ZtGfvih6iFx0+duYfHjGsYwdQYDVR0jBG4wbIAUmLWm6ZtGfvih6iFx0+du
+YfHjGsahSaRHMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEw
+HwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGSCCQDGU+6Eqk4P5TAMBgNV
+HRMEBTADAQH/MAkGByqGSM49BAEDgYwAMIGIAkIBL/oEXMMQH9fefVd8onvgQbWI
+/CJXYE+kLO15gO8satasGutVpXtYGeP8gZeuHrq+jWxzj7dGM7YzkW0pAu+wOAkC
+QgFJSvKFcmbreLIjuwYik5aXeaUnTCvTQumG07cF0hZRgCf/kTxxmu2ffRoGCDTz
+XoPqlxwaO7K+gaAS//CvR0E3lw==
+-----END CERTIFICATE-----
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/ecdsa_p521_key.pem b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/ecdsa_p521_key.pem
new file mode 100644
index 000000000..a8b1006c1
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/ecdsa_p521_key.pem
@@ -0,0 +1,7 @@
+-----BEGIN PRIVATE KEY-----
+MIHtAgEAMBAGByqGSM49AgEGBSuBBAAjBIHVMIHSAgEBBEFqpd7S4UQqO2MJSylA
+8Ufq/qbUuebEJY6t1Oz76JZ0u0k+NdmmujWjULcP4thAhX+xitUap+r86ud8FQCv
+dawUnKGBiQOBhgAEAUPROJkicKgJgMjroW+hpnS2eJSFo2TZieMQ+KR+ZgcPCy1u
+qRMSqcYCrekoXbL8wdMFcV0TQpwU4+zkm7wSAhyrAa8KTAc+Zm2+86t/6ck0d2bW
+Bl8FTLT1/d9V7+YfB8zb74d3PniccrG1Cq91p+GYxXvtH+sG4jbgwspsyKHFGBAp
+-----END PRIVATE KEY-----
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/fuzzer_mode.json b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/fuzzer_mode.json
new file mode 100644
index 000000000..80a9bf1de
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/fuzzer_mode.json
@@ -0,0 +1,39 @@
+{
+ "DisabledTests": {
+ "BadCBCPadding*": "Fuzzer mode has no CBC padding.",
+
+ "BadFinished-*": "Fuzzer mode ignores Finished checks.",
+ "FalseStart-BadFinished": "Fuzzer mode ignores Finished checks.",
+ "TrailingMessageData-*Finished*": "Fuzzer mode ignores Finished checks.",
+
+ "DTLSIgnoreBadPackets*": "Fuzzer mode has no bad packets.",
+ "TLSFatalBadPackets": "Fuzzer mode has no bad packets.",
+ "*-BadRecord": "Fuzzer mode has no bad packets.",
+
+ "BadRSAClientKeyExchange*": "Fuzzer mode does not notice a bad premaster secret.",
+
+ "TrailingMessageData-TLS13-ServerHello": "Fuzzer mode will not read the peer's alert as a MAC error",
+ "UnexpectedUnencryptedExtension-Client-TLS13": "Fuzzer mode will not read the peer's alert as a MAC error",
+ "UnknownUnencryptedExtension-Client-TLS13": "Fuzzer mode will not read the peer's alert as a MAC error",
+ "WrongMessageType-TLS13-ServerHello": "Fuzzer mode will not read the peer's alert as a MAC error",
+
+ "BadECDSA-*": "Fuzzer mode always accepts a signature.",
+ "*-InvalidSignature-*": "Fuzzer mode always accepts a signature.",
+ "*Auth-Verify-RSA-PKCS1-*-TLS13": "Fuzzer mode always accepts a signature.",
+ "*Auth-Verify-ECDSA-SHA1-TLS13": "Fuzzer mode always accepts a signature.",
+ "Verify-*Auth-SignatureType*": "Fuzzer mode always accepts a signature.",
+ "ECDSACurveMismatch-Verify-TLS13": "Fuzzer mode always accepts a signature.",
+ "InvalidChannelIDSignature-*": "Fuzzer mode always accepts a signature.",
+
+ "Resume-Server-CipherNotPreferred*": "Fuzzer mode does not encrypt tickets.",
+ "Resume-Server-DeclineBadCipher*": "Fuzzer mode does not encrypt tickets.",
+ "Resume-Server-DeclineCrossVersion*": "Fuzzer mode does not encrypt tickets.",
+ "TicketCallback-SingleCall-*": "Fuzzer mode does not encrypt tickets.",
+ "CorruptTicket-*": "Fuzzer mode does not encrypt tickets.",
+ "ShimTicketRewritable": "Fuzzer mode does not encrypt tickets.",
+
+ "Resume-Server-*Binder*": "Fuzzer mode does not check binders.",
+
+ "SkipEarlyData*": "Trial decryption does not work with the NULL cipher."
+ }
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/handshake_client.go b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/handshake_client.go
new file mode 100644
index 000000000..bf38c1a78
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/handshake_client.go
@@ -0,0 +1,1758 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runner
+
+import (
+ "bytes"
+ "crypto"
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "crypto/rsa"
+ "crypto/subtle"
+ "crypto/x509"
+ "errors"
+ "fmt"
+ "io"
+ "math/big"
+ "net"
+ "strconv"
+ "time"
+)
+
+type clientHandshakeState struct {
+ c *Conn
+ serverHello *serverHelloMsg
+ hello *clientHelloMsg
+ suite *cipherSuite
+ finishedHash finishedHash
+ keyShares map[CurveID]ecdhCurve
+ masterSecret []byte
+ session *ClientSessionState
+ finishedBytes []byte
+}
+
+func (c *Conn) clientHandshake() error {
+ if c.config == nil {
+ c.config = defaultConfig()
+ }
+
+ if len(c.config.ServerName) == 0 && !c.config.InsecureSkipVerify {
+ return errors.New("tls: either ServerName or InsecureSkipVerify must be specified in the tls.Config")
+ }
+
+ c.sendHandshakeSeq = 0
+ c.recvHandshakeSeq = 0
+
+ nextProtosLength := 0
+ for _, proto := range c.config.NextProtos {
+ if l := len(proto); l > 255 {
+ return errors.New("tls: invalid NextProtos value")
+ } else {
+ nextProtosLength += 1 + l
+ }
+ }
+ if nextProtosLength > 0xffff {
+ return errors.New("tls: NextProtos values too large")
+ }
+
+ minVersion := c.config.minVersion(c.isDTLS)
+ maxVersion := c.config.maxVersion(c.isDTLS)
+ hello := &clientHelloMsg{
+ isDTLS: c.isDTLS,
+ vers: versionToWire(maxVersion, c.isDTLS),
+ compressionMethods: []uint8{compressionNone},
+ random: make([]byte, 32),
+ ocspStapling: !c.config.Bugs.NoOCSPStapling,
+ sctListSupported: !c.config.Bugs.NoSignedCertificateTimestamps,
+ serverName: c.config.ServerName,
+ supportedCurves: c.config.curvePreferences(),
+ pskKEModes: []byte{pskDHEKEMode},
+ supportedPoints: []uint8{pointFormatUncompressed},
+ nextProtoNeg: len(c.config.NextProtos) > 0,
+ secureRenegotiation: []byte{},
+ alpnProtocols: c.config.NextProtos,
+ duplicateExtension: c.config.Bugs.DuplicateExtension,
+ channelIDSupported: c.config.ChannelID != nil,
+ npnAfterAlpn: c.config.Bugs.SwapNPNAndALPN,
+ extendedMasterSecret: maxVersion >= VersionTLS10,
+ srtpProtectionProfiles: c.config.SRTPProtectionProfiles,
+ srtpMasterKeyIdentifier: c.config.Bugs.SRTPMasterKeyIdentifer,
+ customExtension: c.config.Bugs.CustomExtension,
+ pskBinderFirst: c.config.Bugs.PSKBinderFirst,
+ }
+
+ disableEMS := c.config.Bugs.NoExtendedMasterSecret
+ if c.cipherSuite != nil {
+ disableEMS = c.config.Bugs.NoExtendedMasterSecretOnRenegotiation
+ }
+
+ if disableEMS {
+ hello.extendedMasterSecret = false
+ }
+
+ if c.config.Bugs.NoSupportedCurves {
+ hello.supportedCurves = nil
+ }
+
+ if len(c.config.Bugs.SendPSKKeyExchangeModes) != 0 {
+ hello.pskKEModes = c.config.Bugs.SendPSKKeyExchangeModes
+ }
+
+ if c.config.Bugs.SendCompressionMethods != nil {
+ hello.compressionMethods = c.config.Bugs.SendCompressionMethods
+ }
+
+ if c.config.Bugs.SendSupportedPointFormats != nil {
+ hello.supportedPoints = c.config.Bugs.SendSupportedPointFormats
+ }
+
+ if len(c.clientVerify) > 0 && !c.config.Bugs.EmptyRenegotiationInfo {
+ if c.config.Bugs.BadRenegotiationInfo {
+ hello.secureRenegotiation = append(hello.secureRenegotiation, c.clientVerify...)
+ hello.secureRenegotiation[0] ^= 0x80
+ } else {
+ hello.secureRenegotiation = c.clientVerify
+ }
+ }
+
+ if c.noRenegotiationInfo() {
+ hello.secureRenegotiation = nil
+ }
+
+ var keyShares map[CurveID]ecdhCurve
+ if maxVersion >= VersionTLS13 {
+ keyShares = make(map[CurveID]ecdhCurve)
+ hello.hasKeyShares = true
+ hello.trailingKeyShareData = c.config.Bugs.TrailingKeyShareData
+ curvesToSend := c.config.defaultCurves()
+ for _, curveID := range hello.supportedCurves {
+ if !curvesToSend[curveID] {
+ continue
+ }
+ curve, ok := curveForCurveID(curveID)
+ if !ok {
+ continue
+ }
+ publicKey, err := curve.offer(c.config.rand())
+ if err != nil {
+ return err
+ }
+
+ if c.config.Bugs.SendCurve != 0 {
+ curveID = c.config.Bugs.SendCurve
+ }
+ if c.config.Bugs.InvalidECDHPoint {
+ publicKey[0] ^= 0xff
+ }
+
+ hello.keyShares = append(hello.keyShares, keyShareEntry{
+ group: curveID,
+ keyExchange: publicKey,
+ })
+ keyShares[curveID] = curve
+
+ if c.config.Bugs.DuplicateKeyShares {
+ hello.keyShares = append(hello.keyShares, hello.keyShares[len(hello.keyShares)-1])
+ }
+ }
+
+ if c.config.Bugs.MissingKeyShare {
+ hello.hasKeyShares = false
+ }
+ }
+
+ possibleCipherSuites := c.config.cipherSuites()
+ hello.cipherSuites = make([]uint16, 0, len(possibleCipherSuites))
+
+NextCipherSuite:
+ for _, suiteId := range possibleCipherSuites {
+ for _, suite := range cipherSuites {
+ if suite.id != suiteId {
+ continue
+ }
+ // Don't advertise TLS 1.2-only cipher suites unless
+ // we're attempting TLS 1.2.
+ if maxVersion < VersionTLS12 && suite.flags&suiteTLS12 != 0 {
+ continue
+ }
+ // Don't advertise non-DTLS cipher suites in DTLS.
+ if c.isDTLS && suite.flags&suiteNoDTLS != 0 {
+ continue
+ }
+ hello.cipherSuites = append(hello.cipherSuites, suiteId)
+ continue NextCipherSuite
+ }
+ }
+
+ if c.config.Bugs.AdvertiseAllConfiguredCiphers {
+ hello.cipherSuites = possibleCipherSuites
+ }
+
+ if c.config.Bugs.SendRenegotiationSCSV {
+ hello.cipherSuites = append(hello.cipherSuites, renegotiationSCSV)
+ }
+
+ if c.config.Bugs.SendFallbackSCSV {
+ hello.cipherSuites = append(hello.cipherSuites, fallbackSCSV)
+ }
+
+ _, err := io.ReadFull(c.config.rand(), hello.random)
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return errors.New("tls: short read from Rand: " + err.Error())
+ }
+
+ if maxVersion >= VersionTLS12 && !c.config.Bugs.NoSignatureAlgorithms {
+ hello.signatureAlgorithms = c.config.verifySignatureAlgorithms()
+ }
+
+ var session *ClientSessionState
+ var cacheKey string
+ sessionCache := c.config.ClientSessionCache
+
+ if sessionCache != nil {
+ hello.ticketSupported = !c.config.SessionTicketsDisabled
+
+ // Try to resume a previously negotiated TLS session, if
+ // available.
+ cacheKey = clientSessionCacheKey(c.conn.RemoteAddr(), c.config)
+ // TODO(nharper): Support storing more than one session
+ // ticket for TLS 1.3.
+ candidateSession, ok := sessionCache.Get(cacheKey)
+ if ok {
+ ticketOk := !c.config.SessionTicketsDisabled || candidateSession.sessionTicket == nil
+
+ // Check that the ciphersuite/version used for the
+ // previous session are still valid.
+ cipherSuiteOk := false
+ if candidateSession.vers <= VersionTLS12 {
+ for _, id := range hello.cipherSuites {
+ if id == candidateSession.cipherSuite {
+ cipherSuiteOk = true
+ break
+ }
+ }
+ } else {
+ // TLS 1.3 allows the cipher to change on
+ // resumption.
+ cipherSuiteOk = true
+ }
+
+ versOk := candidateSession.vers >= minVersion &&
+ candidateSession.vers <= maxVersion
+ if ticketOk && versOk && cipherSuiteOk {
+ session = candidateSession
+ }
+ }
+ }
+
+ var pskCipherSuite *cipherSuite
+ if session != nil && c.config.time().Before(session.ticketExpiration) {
+ ticket := session.sessionTicket
+ if c.config.Bugs.FilterTicket != nil && len(ticket) > 0 {
+ // Copy the ticket so FilterTicket may act in-place.
+ ticket = make([]byte, len(session.sessionTicket))
+ copy(ticket, session.sessionTicket)
+
+ ticket, err = c.config.Bugs.FilterTicket(ticket)
+ if err != nil {
+ return err
+ }
+ }
+
+ if session.vers >= VersionTLS13 || c.config.Bugs.SendBothTickets {
+ pskCipherSuite = cipherSuiteFromID(session.cipherSuite)
+ if pskCipherSuite == nil {
+ return errors.New("tls: client session cache has invalid cipher suite")
+ }
+ // TODO(nharper): Support sending more
+ // than one PSK identity.
+ ticketAge := uint32(c.config.time().Sub(session.ticketCreationTime) / time.Millisecond)
+ if c.config.Bugs.SendTicketAge != 0 {
+ ticketAge = uint32(c.config.Bugs.SendTicketAge / time.Millisecond)
+ }
+ psk := pskIdentity{
+ ticket: ticket,
+ obfuscatedTicketAge: session.ticketAgeAdd + ticketAge,
+ }
+ hello.pskIdentities = []pskIdentity{psk}
+
+ if c.config.Bugs.ExtraPSKIdentity {
+ hello.pskIdentities = append(hello.pskIdentities, psk)
+ }
+ }
+
+ if session.vers < VersionTLS13 || c.config.Bugs.SendBothTickets {
+ if ticket != nil {
+ hello.sessionTicket = ticket
+ // A random session ID is used to detect when the
+ // server accepted the ticket and is resuming a session
+ // (see RFC 5077).
+ sessionIdLen := 16
+ if c.config.Bugs.TicketSessionIDLength != 0 {
+ sessionIdLen = c.config.Bugs.TicketSessionIDLength
+ }
+ if c.config.Bugs.EmptyTicketSessionID {
+ sessionIdLen = 0
+ }
+ hello.sessionId = make([]byte, sessionIdLen)
+ if _, err := io.ReadFull(c.config.rand(), hello.sessionId); err != nil {
+ c.sendAlert(alertInternalError)
+ return errors.New("tls: short read from Rand: " + err.Error())
+ }
+ } else {
+ hello.sessionId = session.sessionId
+ }
+ }
+ }
+
+ if maxVersion == VersionTLS13 && !c.config.Bugs.OmitSupportedVersions {
+ if hello.vers >= VersionTLS13 {
+ hello.vers = VersionTLS12
+ }
+ for version := maxVersion; version >= minVersion; version-- {
+ hello.supportedVersions = append(hello.supportedVersions, versionToWire(version, c.isDTLS))
+ }
+ }
+
+ if len(c.config.Bugs.SendSupportedVersions) > 0 {
+ hello.supportedVersions = c.config.Bugs.SendSupportedVersions
+ }
+
+ if c.config.Bugs.SendClientVersion != 0 {
+ hello.vers = c.config.Bugs.SendClientVersion
+ }
+
+ if c.config.Bugs.SendCipherSuites != nil {
+ hello.cipherSuites = c.config.Bugs.SendCipherSuites
+ }
+
+ var sendEarlyData bool
+ if len(hello.pskIdentities) > 0 && session.maxEarlyDataSize > 0 && c.config.Bugs.SendEarlyData != nil {
+ hello.hasEarlyData = true
+ sendEarlyData = true
+ }
+ if c.config.Bugs.SendFakeEarlyDataLength > 0 {
+ hello.hasEarlyData = true
+ }
+ if c.config.Bugs.OmitEarlyDataExtension {
+ hello.hasEarlyData = false
+ }
+
+ var helloBytes []byte
+ if c.config.Bugs.SendV2ClientHello {
+ // Test that the peer left-pads random.
+ hello.random[0] = 0
+ v2Hello := &v2ClientHelloMsg{
+ vers: hello.vers,
+ cipherSuites: hello.cipherSuites,
+ // No session resumption for V2ClientHello.
+ sessionId: nil,
+ challenge: hello.random[1:],
+ }
+ helloBytes = v2Hello.marshal()
+ c.writeV2Record(helloBytes)
+ } else {
+ if len(hello.pskIdentities) > 0 {
+ generatePSKBinders(hello, pskCipherSuite, session.masterSecret, []byte{}, c.config)
+ }
+ helloBytes = hello.marshal()
+
+ if c.config.Bugs.PartialClientFinishedWithClientHello {
+ // Include one byte of Finished. We can compute it
+ // without completing the handshake. This assumes we
+ // negotiate TLS 1.3 with no HelloRetryRequest or
+ // CertificateRequest.
+ toWrite := make([]byte, 0, len(helloBytes)+1)
+ toWrite = append(toWrite, helloBytes...)
+ toWrite = append(toWrite, typeFinished)
+ c.writeRecord(recordTypeHandshake, toWrite)
+ } else {
+ c.writeRecord(recordTypeHandshake, helloBytes)
+ }
+ }
+ c.flushHandshake()
+
+ if err := c.simulatePacketLoss(nil); err != nil {
+ return err
+ }
+ if c.config.Bugs.SendEarlyAlert {
+ c.sendAlert(alertHandshakeFailure)
+ }
+ if c.config.Bugs.SendFakeEarlyDataLength > 0 {
+ c.sendFakeEarlyData(c.config.Bugs.SendFakeEarlyDataLength)
+ }
+
+ // Derive early write keys and set Conn state to allow early writes.
+ if sendEarlyData {
+ finishedHash := newFinishedHash(session.vers, pskCipherSuite)
+ finishedHash.addEntropy(session.masterSecret)
+ finishedHash.Write(helloBytes)
+ earlyTrafficSecret := finishedHash.deriveSecret(earlyTrafficLabel)
+ c.out.useTrafficSecret(session.vers, pskCipherSuite, earlyTrafficSecret, clientWrite)
+
+ for _, earlyData := range c.config.Bugs.SendEarlyData {
+ if _, err := c.writeRecord(recordTypeApplicationData, earlyData); err != nil {
+ return err
+ }
+ }
+ }
+
+ msg, err := c.readHandshake()
+ if err != nil {
+ return err
+ }
+
+ if c.isDTLS {
+ helloVerifyRequest, ok := msg.(*helloVerifyRequestMsg)
+ if ok {
+ if helloVerifyRequest.vers != versionToWire(VersionTLS10, c.isDTLS) {
+ // Per RFC 6347, the version field in
+ // HelloVerifyRequest SHOULD be always DTLS
+ // 1.0. Enforce this for testing purposes.
+ return errors.New("dtls: bad HelloVerifyRequest version")
+ }
+
+ hello.raw = nil
+ hello.cookie = helloVerifyRequest.cookie
+ helloBytes = hello.marshal()
+ c.writeRecord(recordTypeHandshake, helloBytes)
+ c.flushHandshake()
+
+ if err := c.simulatePacketLoss(nil); err != nil {
+ return err
+ }
+ msg, err = c.readHandshake()
+ if err != nil {
+ return err
+ }
+ }
+ }
+
+ var serverWireVersion uint16
+ switch m := msg.(type) {
+ case *helloRetryRequestMsg:
+ serverWireVersion = m.vers
+ case *serverHelloMsg:
+ serverWireVersion = m.vers
+ default:
+ c.sendAlert(alertUnexpectedMessage)
+ return fmt.Errorf("tls: received unexpected message of type %T when waiting for HelloRetryRequest or ServerHello", msg)
+ }
+
+ serverVersion, ok := wireToVersion(serverWireVersion, c.isDTLS)
+ if ok {
+ ok = c.config.isSupportedVersion(serverVersion, c.isDTLS)
+ }
+ if !ok {
+ c.sendAlert(alertProtocolVersion)
+ return fmt.Errorf("tls: server selected unsupported protocol version %x", c.vers)
+ }
+ c.vers = serverVersion
+ c.haveVers = true
+
+ helloRetryRequest, haveHelloRetryRequest := msg.(*helloRetryRequestMsg)
+ var secondHelloBytes []byte
+ if haveHelloRetryRequest {
+ c.out.resetCipher()
+ if len(helloRetryRequest.cookie) > 0 {
+ hello.tls13Cookie = helloRetryRequest.cookie
+ }
+
+ if c.config.Bugs.MisinterpretHelloRetryRequestCurve != 0 {
+ helloRetryRequest.hasSelectedGroup = true
+ helloRetryRequest.selectedGroup = c.config.Bugs.MisinterpretHelloRetryRequestCurve
+ }
+ if helloRetryRequest.hasSelectedGroup {
+ var hrrCurveFound bool
+ group := helloRetryRequest.selectedGroup
+ for _, curveID := range hello.supportedCurves {
+ if group == curveID {
+ hrrCurveFound = true
+ break
+ }
+ }
+ if !hrrCurveFound || keyShares[group] != nil {
+ c.sendAlert(alertHandshakeFailure)
+ return errors.New("tls: received invalid HelloRetryRequest")
+ }
+ curve, ok := curveForCurveID(group)
+ if !ok {
+ return errors.New("tls: Unable to get curve requested in HelloRetryRequest")
+ }
+ publicKey, err := curve.offer(c.config.rand())
+ if err != nil {
+ return err
+ }
+ keyShares[group] = curve
+ hello.keyShares = []keyShareEntry{{
+ group: group,
+ keyExchange: publicKey,
+ }}
+ }
+
+ if c.config.Bugs.SecondClientHelloMissingKeyShare {
+ hello.hasKeyShares = false
+ }
+
+ hello.hasEarlyData = c.config.Bugs.SendEarlyDataOnSecondClientHello
+ hello.raw = nil
+
+ if len(hello.pskIdentities) > 0 {
+ generatePSKBinders(hello, pskCipherSuite, session.masterSecret, append(helloBytes, helloRetryRequest.marshal()...), c.config)
+ }
+ secondHelloBytes = hello.marshal()
+
+ if c.config.Bugs.InterleaveEarlyData {
+ c.sendFakeEarlyData(4)
+ c.writeRecord(recordTypeHandshake, secondHelloBytes[:16])
+ c.sendFakeEarlyData(4)
+ c.writeRecord(recordTypeHandshake, secondHelloBytes[16:])
+ } else {
+ c.writeRecord(recordTypeHandshake, secondHelloBytes)
+ }
+ c.flushHandshake()
+
+ if c.config.Bugs.SendEarlyDataOnSecondClientHello {
+ c.sendFakeEarlyData(4)
+ }
+
+ msg, err = c.readHandshake()
+ if err != nil {
+ return err
+ }
+ }
+
+ serverHello, ok := msg.(*serverHelloMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(serverHello, msg)
+ }
+
+ if serverWireVersion != serverHello.vers {
+ c.sendAlert(alertProtocolVersion)
+ return fmt.Errorf("tls: server sent non-matching version %x vs %x", serverWireVersion, serverHello.vers)
+ }
+
+ // Check for downgrade signals in the server random, per
+ // draft-ietf-tls-tls13-16, section 4.1.3.
+ if c.vers <= VersionTLS12 && c.config.maxVersion(c.isDTLS) >= VersionTLS13 {
+ if bytes.Equal(serverHello.random[len(serverHello.random)-8:], downgradeTLS13) {
+ c.sendAlert(alertProtocolVersion)
+ return errors.New("tls: downgrade from TLS 1.3 detected")
+ }
+ }
+ if c.vers <= VersionTLS11 && c.config.maxVersion(c.isDTLS) >= VersionTLS12 {
+ if bytes.Equal(serverHello.random[len(serverHello.random)-8:], downgradeTLS12) {
+ c.sendAlert(alertProtocolVersion)
+ return errors.New("tls: downgrade from TLS 1.2 detected")
+ }
+ }
+
+ suite := mutualCipherSuite(hello.cipherSuites, serverHello.cipherSuite)
+ if suite == nil {
+ c.sendAlert(alertHandshakeFailure)
+ return fmt.Errorf("tls: server selected an unsupported cipher suite")
+ }
+
+ if haveHelloRetryRequest && helloRetryRequest.hasSelectedGroup && helloRetryRequest.selectedGroup != serverHello.keyShare.group {
+ c.sendAlert(alertHandshakeFailure)
+ return errors.New("tls: ServerHello parameters did not match HelloRetryRequest")
+ }
+
+ hs := &clientHandshakeState{
+ c: c,
+ serverHello: serverHello,
+ hello: hello,
+ suite: suite,
+ finishedHash: newFinishedHash(c.vers, suite),
+ keyShares: keyShares,
+ session: session,
+ }
+
+ hs.writeHash(helloBytes, hs.c.sendHandshakeSeq-1)
+ if haveHelloRetryRequest {
+ hs.writeServerHash(helloRetryRequest.marshal())
+ hs.writeClientHash(secondHelloBytes)
+ }
+ hs.writeServerHash(hs.serverHello.marshal())
+
+ if c.vers >= VersionTLS13 {
+ if err := hs.doTLS13Handshake(); err != nil {
+ return err
+ }
+ } else {
+ if c.config.Bugs.EarlyChangeCipherSpec > 0 {
+ hs.establishKeys()
+ c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
+ }
+
+ if hs.serverHello.compressionMethod != compressionNone {
+ c.sendAlert(alertUnexpectedMessage)
+ return errors.New("tls: server selected unsupported compression format")
+ }
+
+ err = hs.processServerExtensions(&serverHello.extensions)
+ if err != nil {
+ return err
+ }
+
+ isResume, err := hs.processServerHello()
+ if err != nil {
+ return err
+ }
+
+ if isResume {
+ if c.config.Bugs.EarlyChangeCipherSpec == 0 {
+ if err := hs.establishKeys(); err != nil {
+ return err
+ }
+ }
+ if err := hs.readSessionTicket(); err != nil {
+ return err
+ }
+ if err := hs.readFinished(c.firstFinished[:]); err != nil {
+ return err
+ }
+ if err := hs.sendFinished(nil, isResume); err != nil {
+ return err
+ }
+ } else {
+ if err := hs.doFullHandshake(); err != nil {
+ return err
+ }
+ if err := hs.establishKeys(); err != nil {
+ return err
+ }
+ if err := hs.sendFinished(c.firstFinished[:], isResume); err != nil {
+ return err
+ }
+ // Most retransmits are triggered by a timeout, but the final
+ // leg of the handshake is retransmited upon re-receiving a
+ // Finished.
+ if err := c.simulatePacketLoss(func() {
+ c.sendHandshakeSeq--
+ c.writeRecord(recordTypeHandshake, hs.finishedBytes)
+ c.flushHandshake()
+ }); err != nil {
+ return err
+ }
+ if err := hs.readSessionTicket(); err != nil {
+ return err
+ }
+ if err := hs.readFinished(nil); err != nil {
+ return err
+ }
+ }
+
+ if sessionCache != nil && hs.session != nil && session != hs.session {
+ if c.config.Bugs.RequireSessionTickets && len(hs.session.sessionTicket) == 0 {
+ return errors.New("tls: new session used session IDs instead of tickets")
+ }
+ sessionCache.Put(cacheKey, hs.session)
+ }
+
+ c.didResume = isResume
+ c.exporterSecret = hs.masterSecret
+ }
+
+ c.handshakeComplete = true
+ c.cipherSuite = suite
+ copy(c.clientRandom[:], hs.hello.random)
+ copy(c.serverRandom[:], hs.serverHello.random)
+
+ return nil
+}
+
+func (hs *clientHandshakeState) doTLS13Handshake() error {
+ c := hs.c
+
+ // Once the PRF hash is known, TLS 1.3 does not require a handshake
+ // buffer.
+ hs.finishedHash.discardHandshakeBuffer()
+
+ zeroSecret := hs.finishedHash.zeroSecret()
+
+ // Resolve PSK and compute the early secret.
+ //
+ // TODO(davidben): This will need to be handled slightly earlier once
+ // 0-RTT is implemented.
+ if hs.serverHello.hasPSKIdentity {
+ // We send at most one PSK identity.
+ if hs.session == nil || hs.serverHello.pskIdentity != 0 {
+ c.sendAlert(alertUnknownPSKIdentity)
+ return errors.New("tls: server sent unknown PSK identity")
+ }
+ sessionCipher := cipherSuiteFromID(hs.session.cipherSuite)
+ if sessionCipher == nil || sessionCipher.hash() != hs.suite.hash() {
+ c.sendAlert(alertHandshakeFailure)
+ return errors.New("tls: server resumed an invalid session for the cipher suite")
+ }
+ hs.finishedHash.addEntropy(hs.session.masterSecret)
+ c.didResume = true
+ } else {
+ hs.finishedHash.addEntropy(zeroSecret)
+ }
+
+ if !hs.serverHello.hasKeyShare {
+ c.sendAlert(alertUnsupportedExtension)
+ return errors.New("tls: server omitted KeyShare on resumption.")
+ }
+
+ // Resolve ECDHE and compute the handshake secret.
+ if !c.config.Bugs.MissingKeyShare && !c.config.Bugs.SecondClientHelloMissingKeyShare {
+ curve, ok := hs.keyShares[hs.serverHello.keyShare.group]
+ if !ok {
+ c.sendAlert(alertHandshakeFailure)
+ return errors.New("tls: server selected an unsupported group")
+ }
+ c.curveID = hs.serverHello.keyShare.group
+
+ ecdheSecret, err := curve.finish(hs.serverHello.keyShare.keyExchange)
+ if err != nil {
+ return err
+ }
+ hs.finishedHash.addEntropy(ecdheSecret)
+ } else {
+ hs.finishedHash.addEntropy(zeroSecret)
+ }
+
+ // Derive handshake traffic keys and switch read key to handshake
+ // traffic key.
+ clientHandshakeTrafficSecret := hs.finishedHash.deriveSecret(clientHandshakeTrafficLabel)
+ serverHandshakeTrafficSecret := hs.finishedHash.deriveSecret(serverHandshakeTrafficLabel)
+ c.in.useTrafficSecret(c.vers, hs.suite, serverHandshakeTrafficSecret, serverWrite)
+
+ msg, err := c.readHandshake()
+ if err != nil {
+ return err
+ }
+
+ encryptedExtensions, ok := msg.(*encryptedExtensionsMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(encryptedExtensions, msg)
+ }
+ hs.writeServerHash(encryptedExtensions.marshal())
+
+ err = hs.processServerExtensions(&encryptedExtensions.extensions)
+ if err != nil {
+ return err
+ }
+
+ var chainToSend *Certificate
+ var certReq *certificateRequestMsg
+ if c.didResume {
+ // Copy over authentication from the session.
+ c.peerCertificates = hs.session.serverCertificates
+ c.sctList = hs.session.sctList
+ c.ocspResponse = hs.session.ocspResponse
+ } else {
+ msg, err := c.readHandshake()
+ if err != nil {
+ return err
+ }
+
+ var ok bool
+ certReq, ok = msg.(*certificateRequestMsg)
+ if ok {
+ if len(certReq.requestContext) != 0 {
+ return errors.New("tls: non-empty certificate request context sent in handshake")
+ }
+
+ if c.config.Bugs.IgnorePeerSignatureAlgorithmPreferences {
+ certReq.signatureAlgorithms = c.config.signSignatureAlgorithms()
+ }
+
+ hs.writeServerHash(certReq.marshal())
+
+ chainToSend, err = selectClientCertificate(c, certReq)
+ if err != nil {
+ return err
+ }
+
+ msg, err = c.readHandshake()
+ if err != nil {
+ return err
+ }
+ }
+
+ certMsg, ok := msg.(*certificateMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(certMsg, msg)
+ }
+ hs.writeServerHash(certMsg.marshal())
+
+ // Check for unsolicited extensions.
+ for i, cert := range certMsg.certificates {
+ if c.config.Bugs.NoOCSPStapling && cert.ocspResponse != nil {
+ c.sendAlert(alertUnsupportedExtension)
+ return errors.New("tls: unexpected OCSP response in the server certificate")
+ }
+ if c.config.Bugs.NoSignedCertificateTimestamps && cert.sctList != nil {
+ c.sendAlert(alertUnsupportedExtension)
+ return errors.New("tls: unexpected SCT list in the server certificate")
+ }
+ if i > 0 && c.config.Bugs.ExpectNoExtensionsOnIntermediate && (cert.ocspResponse != nil || cert.sctList != nil) {
+ c.sendAlert(alertUnsupportedExtension)
+ return errors.New("tls: unexpected extensions in the server certificate")
+ }
+ }
+
+ if err := hs.verifyCertificates(certMsg); err != nil {
+ return err
+ }
+ leaf := c.peerCertificates[0]
+ c.ocspResponse = certMsg.certificates[0].ocspResponse
+ c.sctList = certMsg.certificates[0].sctList
+
+ msg, err = c.readHandshake()
+ if err != nil {
+ return err
+ }
+ certVerifyMsg, ok := msg.(*certificateVerifyMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(certVerifyMsg, msg)
+ }
+
+ c.peerSignatureAlgorithm = certVerifyMsg.signatureAlgorithm
+ input := hs.finishedHash.certificateVerifyInput(serverCertificateVerifyContextTLS13)
+ err = verifyMessage(c.vers, leaf.PublicKey, c.config, certVerifyMsg.signatureAlgorithm, input, certVerifyMsg.signature)
+ if err != nil {
+ return err
+ }
+
+ hs.writeServerHash(certVerifyMsg.marshal())
+ }
+
+ msg, err = c.readHandshake()
+ if err != nil {
+ return err
+ }
+ serverFinished, ok := msg.(*finishedMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(serverFinished, msg)
+ }
+
+ verify := hs.finishedHash.serverSum(serverHandshakeTrafficSecret)
+ if len(verify) != len(serverFinished.verifyData) ||
+ subtle.ConstantTimeCompare(verify, serverFinished.verifyData) != 1 {
+ c.sendAlert(alertHandshakeFailure)
+ return errors.New("tls: server's Finished message was incorrect")
+ }
+
+ hs.writeServerHash(serverFinished.marshal())
+
+ // The various secrets do not incorporate the client's final leg, so
+ // derive them now before updating the handshake context.
+ hs.finishedHash.addEntropy(zeroSecret)
+ clientTrafficSecret := hs.finishedHash.deriveSecret(clientApplicationTrafficLabel)
+ serverTrafficSecret := hs.finishedHash.deriveSecret(serverApplicationTrafficLabel)
+ c.exporterSecret = hs.finishedHash.deriveSecret(exporterLabel)
+
+ // Switch to application data keys on read. In particular, any alerts
+ // from the client certificate are read over these keys.
+ c.in.useTrafficSecret(c.vers, hs.suite, serverTrafficSecret, serverWrite)
+
+ // If we're expecting 0.5-RTT messages from the server, read them
+ // now.
+ for _, expectedMsg := range c.config.Bugs.ExpectHalfRTTData {
+ if err := c.readRecord(recordTypeApplicationData); err != nil {
+ return err
+ }
+ if !bytes.Equal(c.input.data[c.input.off:], expectedMsg) {
+ return errors.New("ExpectHalfRTTData: did not get expected message")
+ }
+ c.in.freeBlock(c.input)
+ c.input = nil
+ }
+
+ // Send EndOfEarlyData and then switch write key to handshake
+ // traffic key.
+ if c.out.cipher != nil {
+ c.sendAlert(alertEndOfEarlyData)
+ }
+ c.out.useTrafficSecret(c.vers, hs.suite, clientHandshakeTrafficSecret, clientWrite)
+
+ if certReq != nil && !c.config.Bugs.SkipClientCertificate {
+ certMsg := &certificateMsg{
+ hasRequestContext: true,
+ requestContext: certReq.requestContext,
+ }
+ if chainToSend != nil {
+ for _, certData := range chainToSend.Certificate {
+ certMsg.certificates = append(certMsg.certificates, certificateEntry{
+ data: certData,
+ extraExtension: c.config.Bugs.SendExtensionOnCertificate,
+ })
+ }
+ }
+ hs.writeClientHash(certMsg.marshal())
+ c.writeRecord(recordTypeHandshake, certMsg.marshal())
+
+ if chainToSend != nil {
+ certVerify := &certificateVerifyMsg{
+ hasSignatureAlgorithm: true,
+ }
+
+ // Determine the hash to sign.
+ privKey := chainToSend.PrivateKey
+
+ var err error
+ certVerify.signatureAlgorithm, err = selectSignatureAlgorithm(c.vers, privKey, c.config, certReq.signatureAlgorithms)
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
+
+ input := hs.finishedHash.certificateVerifyInput(clientCertificateVerifyContextTLS13)
+ certVerify.signature, err = signMessage(c.vers, privKey, c.config, certVerify.signatureAlgorithm, input)
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
+ if c.config.Bugs.SendSignatureAlgorithm != 0 {
+ certVerify.signatureAlgorithm = c.config.Bugs.SendSignatureAlgorithm
+ }
+
+ hs.writeClientHash(certVerify.marshal())
+ c.writeRecord(recordTypeHandshake, certVerify.marshal())
+ }
+ }
+
+ if encryptedExtensions.extensions.channelIDRequested {
+ channelIDHash := crypto.SHA256.New()
+ channelIDHash.Write(hs.finishedHash.certificateVerifyInput(channelIDContextTLS13))
+ channelIDMsgBytes, err := hs.writeChannelIDMessage(channelIDHash.Sum(nil))
+ if err != nil {
+ return err
+ }
+ hs.writeClientHash(channelIDMsgBytes)
+ c.writeRecord(recordTypeHandshake, channelIDMsgBytes)
+ }
+
+ // Send a client Finished message.
+ finished := new(finishedMsg)
+ finished.verifyData = hs.finishedHash.clientSum(clientHandshakeTrafficSecret)
+ if c.config.Bugs.BadFinished {
+ finished.verifyData[0]++
+ }
+ hs.writeClientHash(finished.marshal())
+ if c.config.Bugs.PartialClientFinishedWithClientHello {
+ // The first byte has already been sent.
+ c.writeRecord(recordTypeHandshake, finished.marshal()[1:])
+ } else if c.config.Bugs.InterleaveEarlyData {
+ finishedBytes := finished.marshal()
+ c.sendFakeEarlyData(4)
+ c.writeRecord(recordTypeHandshake, finishedBytes[:1])
+ c.sendFakeEarlyData(4)
+ c.writeRecord(recordTypeHandshake, finishedBytes[1:])
+ } else {
+ c.writeRecord(recordTypeHandshake, finished.marshal())
+ }
+ if c.config.Bugs.SendExtraFinished {
+ c.writeRecord(recordTypeHandshake, finished.marshal())
+ }
+ c.flushHandshake()
+
+ // Switch to application data keys.
+ c.out.useTrafficSecret(c.vers, hs.suite, clientTrafficSecret, clientWrite)
+
+ c.resumptionSecret = hs.finishedHash.deriveSecret(resumptionLabel)
+ return nil
+}
+
+func (hs *clientHandshakeState) doFullHandshake() error {
+ c := hs.c
+
+ var leaf *x509.Certificate
+ if hs.suite.flags&suitePSK == 0 {
+ msg, err := c.readHandshake()
+ if err != nil {
+ return err
+ }
+
+ certMsg, ok := msg.(*certificateMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(certMsg, msg)
+ }
+ hs.writeServerHash(certMsg.marshal())
+
+ if err := hs.verifyCertificates(certMsg); err != nil {
+ return err
+ }
+ leaf = c.peerCertificates[0]
+ }
+
+ if hs.serverHello.extensions.ocspStapling {
+ msg, err := c.readHandshake()
+ if err != nil {
+ return err
+ }
+ cs, ok := msg.(*certificateStatusMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(cs, msg)
+ }
+ hs.writeServerHash(cs.marshal())
+
+ if cs.statusType == statusTypeOCSP {
+ c.ocspResponse = cs.response
+ }
+ }
+
+ msg, err := c.readHandshake()
+ if err != nil {
+ return err
+ }
+
+ keyAgreement := hs.suite.ka(c.vers)
+
+ skx, ok := msg.(*serverKeyExchangeMsg)
+ if ok {
+ hs.writeServerHash(skx.marshal())
+ err = keyAgreement.processServerKeyExchange(c.config, hs.hello, hs.serverHello, leaf, skx)
+ if err != nil {
+ c.sendAlert(alertUnexpectedMessage)
+ return err
+ }
+ if ecdhe, ok := keyAgreement.(*ecdheKeyAgreement); ok {
+ c.curveID = ecdhe.curveID
+ }
+
+ c.peerSignatureAlgorithm = keyAgreement.peerSignatureAlgorithm()
+
+ msg, err = c.readHandshake()
+ if err != nil {
+ return err
+ }
+ }
+
+ var chainToSend *Certificate
+ var certRequested bool
+ certReq, ok := msg.(*certificateRequestMsg)
+ if ok {
+ certRequested = true
+ if c.config.Bugs.IgnorePeerSignatureAlgorithmPreferences {
+ certReq.signatureAlgorithms = c.config.signSignatureAlgorithms()
+ }
+
+ hs.writeServerHash(certReq.marshal())
+
+ chainToSend, err = selectClientCertificate(c, certReq)
+ if err != nil {
+ return err
+ }
+
+ msg, err = c.readHandshake()
+ if err != nil {
+ return err
+ }
+ }
+
+ shd, ok := msg.(*serverHelloDoneMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(shd, msg)
+ }
+ hs.writeServerHash(shd.marshal())
+
+ // If the server requested a certificate then we have to send a
+ // Certificate message in TLS, even if it's empty because we don't have
+ // a certificate to send. In SSL 3.0, skip the message and send a
+ // no_certificate warning alert.
+ if certRequested {
+ if c.vers == VersionSSL30 && chainToSend == nil {
+ c.sendAlert(alertNoCertificate)
+ } else if !c.config.Bugs.SkipClientCertificate {
+ certMsg := new(certificateMsg)
+ if chainToSend != nil {
+ for _, certData := range chainToSend.Certificate {
+ certMsg.certificates = append(certMsg.certificates, certificateEntry{
+ data: certData,
+ })
+ }
+ }
+ hs.writeClientHash(certMsg.marshal())
+ c.writeRecord(recordTypeHandshake, certMsg.marshal())
+ }
+ }
+
+ preMasterSecret, ckx, err := keyAgreement.generateClientKeyExchange(c.config, hs.hello, leaf)
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
+ if ckx != nil {
+ if c.config.Bugs.EarlyChangeCipherSpec < 2 {
+ hs.writeClientHash(ckx.marshal())
+ }
+ c.writeRecord(recordTypeHandshake, ckx.marshal())
+ }
+
+ if hs.serverHello.extensions.extendedMasterSecret && c.vers >= VersionTLS10 {
+ hs.masterSecret = extendedMasterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.finishedHash)
+ c.extendedMasterSecret = true
+ } else {
+ if c.config.Bugs.RequireExtendedMasterSecret {
+ return errors.New("tls: extended master secret required but not supported by peer")
+ }
+ hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.hello.random, hs.serverHello.random)
+ }
+
+ if chainToSend != nil {
+ certVerify := &certificateVerifyMsg{
+ hasSignatureAlgorithm: c.vers >= VersionTLS12,
+ }
+
+ // Determine the hash to sign.
+ privKey := c.config.Certificates[0].PrivateKey
+
+ if certVerify.hasSignatureAlgorithm {
+ certVerify.signatureAlgorithm, err = selectSignatureAlgorithm(c.vers, privKey, c.config, certReq.signatureAlgorithms)
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
+ }
+
+ if c.vers > VersionSSL30 {
+ certVerify.signature, err = signMessage(c.vers, privKey, c.config, certVerify.signatureAlgorithm, hs.finishedHash.buffer)
+ if err == nil && c.config.Bugs.SendSignatureAlgorithm != 0 {
+ certVerify.signatureAlgorithm = c.config.Bugs.SendSignatureAlgorithm
+ }
+ } else {
+ // SSL 3.0's client certificate construction is
+ // incompatible with signatureAlgorithm.
+ rsaKey, ok := privKey.(*rsa.PrivateKey)
+ if !ok {
+ err = errors.New("unsupported signature type for client certificate")
+ } else {
+ digest := hs.finishedHash.hashForClientCertificateSSL3(hs.masterSecret)
+ if c.config.Bugs.InvalidSignature {
+ digest[0] ^= 0x80
+ }
+ certVerify.signature, err = rsa.SignPKCS1v15(c.config.rand(), rsaKey, crypto.MD5SHA1, digest)
+ }
+ }
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return errors.New("tls: failed to sign handshake with client certificate: " + err.Error())
+ }
+
+ hs.writeClientHash(certVerify.marshal())
+ c.writeRecord(recordTypeHandshake, certVerify.marshal())
+ }
+ // flushHandshake will be called in sendFinished.
+
+ hs.finishedHash.discardHandshakeBuffer()
+
+ return nil
+}
+
+func (hs *clientHandshakeState) verifyCertificates(certMsg *certificateMsg) error {
+ c := hs.c
+
+ if len(certMsg.certificates) == 0 {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: no certificates sent")
+ }
+
+ certs := make([]*x509.Certificate, len(certMsg.certificates))
+ for i, certEntry := range certMsg.certificates {
+ cert, err := x509.ParseCertificate(certEntry.data)
+ if err != nil {
+ c.sendAlert(alertBadCertificate)
+ return errors.New("tls: failed to parse certificate from server: " + err.Error())
+ }
+ certs[i] = cert
+ }
+
+ if !c.config.InsecureSkipVerify {
+ opts := x509.VerifyOptions{
+ Roots: c.config.RootCAs,
+ CurrentTime: c.config.time(),
+ DNSName: c.config.ServerName,
+ Intermediates: x509.NewCertPool(),
+ }
+
+ for i, cert := range certs {
+ if i == 0 {
+ continue
+ }
+ opts.Intermediates.AddCert(cert)
+ }
+ var err error
+ c.verifiedChains, err = certs[0].Verify(opts)
+ if err != nil {
+ c.sendAlert(alertBadCertificate)
+ return err
+ }
+ }
+
+ switch certs[0].PublicKey.(type) {
+ case *rsa.PublicKey, *ecdsa.PublicKey:
+ break
+ default:
+ c.sendAlert(alertUnsupportedCertificate)
+ return fmt.Errorf("tls: server's certificate contains an unsupported type of public key: %T", certs[0].PublicKey)
+ }
+
+ c.peerCertificates = certs
+ return nil
+}
+
+func (hs *clientHandshakeState) establishKeys() error {
+ c := hs.c
+
+ clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
+ keysFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.hello.random, hs.serverHello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen(c.vers))
+ var clientCipher, serverCipher interface{}
+ var clientHash, serverHash macFunction
+ if hs.suite.cipher != nil {
+ clientCipher = hs.suite.cipher(clientKey, clientIV, false /* not for reading */)
+ clientHash = hs.suite.mac(c.vers, clientMAC)
+ serverCipher = hs.suite.cipher(serverKey, serverIV, true /* for reading */)
+ serverHash = hs.suite.mac(c.vers, serverMAC)
+ } else {
+ clientCipher = hs.suite.aead(c.vers, clientKey, clientIV)
+ serverCipher = hs.suite.aead(c.vers, serverKey, serverIV)
+ }
+
+ c.in.prepareCipherSpec(c.vers, serverCipher, serverHash)
+ c.out.prepareCipherSpec(c.vers, clientCipher, clientHash)
+ return nil
+}
+
+func (hs *clientHandshakeState) processServerExtensions(serverExtensions *serverExtensions) error {
+ c := hs.c
+
+ if c.vers < VersionTLS13 {
+ if c.config.Bugs.RequireRenegotiationInfo && serverExtensions.secureRenegotiation == nil {
+ return errors.New("tls: renegotiation extension missing")
+ }
+
+ if len(c.clientVerify) > 0 && !c.noRenegotiationInfo() {
+ var expectedRenegInfo []byte
+ expectedRenegInfo = append(expectedRenegInfo, c.clientVerify...)
+ expectedRenegInfo = append(expectedRenegInfo, c.serverVerify...)
+ if !bytes.Equal(serverExtensions.secureRenegotiation, expectedRenegInfo) {
+ c.sendAlert(alertHandshakeFailure)
+ return fmt.Errorf("tls: renegotiation mismatch")
+ }
+ }
+ } else if serverExtensions.secureRenegotiation != nil {
+ return errors.New("tls: renegotiation info sent in TLS 1.3")
+ }
+
+ if expected := c.config.Bugs.ExpectedCustomExtension; expected != nil {
+ if serverExtensions.customExtension != *expected {
+ return fmt.Errorf("tls: bad custom extension contents %q", serverExtensions.customExtension)
+ }
+ }
+
+ clientDidNPN := hs.hello.nextProtoNeg
+ clientDidALPN := len(hs.hello.alpnProtocols) > 0
+ serverHasNPN := serverExtensions.nextProtoNeg
+ serverHasALPN := len(serverExtensions.alpnProtocol) > 0
+
+ if !clientDidNPN && serverHasNPN {
+ c.sendAlert(alertHandshakeFailure)
+ return errors.New("server advertised unrequested NPN extension")
+ }
+
+ if !clientDidALPN && serverHasALPN {
+ c.sendAlert(alertHandshakeFailure)
+ return errors.New("server advertised unrequested ALPN extension")
+ }
+
+ if serverHasNPN && serverHasALPN {
+ c.sendAlert(alertHandshakeFailure)
+ return errors.New("server advertised both NPN and ALPN extensions")
+ }
+
+ if serverHasALPN {
+ c.clientProtocol = serverExtensions.alpnProtocol
+ c.clientProtocolFallback = false
+ c.usedALPN = true
+ }
+
+ if serverHasNPN && c.vers >= VersionTLS13 {
+ c.sendAlert(alertHandshakeFailure)
+ return errors.New("server advertised NPN over TLS 1.3")
+ }
+
+ if !hs.hello.channelIDSupported && serverExtensions.channelIDRequested {
+ c.sendAlert(alertHandshakeFailure)
+ return errors.New("server advertised unrequested Channel ID extension")
+ }
+
+ if serverExtensions.extendedMasterSecret && c.vers >= VersionTLS13 {
+ return errors.New("tls: server advertised extended master secret over TLS 1.3")
+ }
+
+ if serverExtensions.ticketSupported && c.vers >= VersionTLS13 {
+ return errors.New("tls: server advertised ticket extension over TLS 1.3")
+ }
+
+ if serverExtensions.ocspStapling && c.vers >= VersionTLS13 {
+ return errors.New("tls: server advertised OCSP in ServerHello over TLS 1.3")
+ }
+
+ if serverExtensions.ocspStapling && c.config.Bugs.NoOCSPStapling {
+ return errors.New("tls: server advertised unrequested OCSP extension")
+ }
+
+ if len(serverExtensions.sctList) > 0 && c.vers >= VersionTLS13 {
+ return errors.New("tls: server advertised SCTs in ServerHello over TLS 1.3")
+ }
+
+ if len(serverExtensions.sctList) > 0 && c.config.Bugs.NoSignedCertificateTimestamps {
+ return errors.New("tls: server advertised unrequested SCTs")
+ }
+
+ if serverExtensions.srtpProtectionProfile != 0 {
+ if serverExtensions.srtpMasterKeyIdentifier != "" {
+ return errors.New("tls: server selected SRTP MKI value")
+ }
+
+ found := false
+ for _, p := range c.config.SRTPProtectionProfiles {
+ if p == serverExtensions.srtpProtectionProfile {
+ found = true
+ break
+ }
+ }
+ if !found {
+ return errors.New("tls: server advertised unsupported SRTP profile")
+ }
+
+ c.srtpProtectionProfile = serverExtensions.srtpProtectionProfile
+ }
+
+ return nil
+}
+
+func (hs *clientHandshakeState) serverResumedSession() bool {
+ // If the server responded with the same sessionId then it means the
+ // sessionTicket is being used to resume a TLS session.
+ //
+ // Note that, if hs.hello.sessionId is a non-nil empty array, this will
+ // accept an empty session ID from the server as resumption. See
+ // EmptyTicketSessionID.
+ return hs.session != nil && hs.hello.sessionId != nil &&
+ bytes.Equal(hs.serverHello.sessionId, hs.hello.sessionId)
+}
+
+func (hs *clientHandshakeState) processServerHello() (bool, error) {
+ c := hs.c
+
+ if hs.serverResumedSession() {
+ // For test purposes, assert that the server never accepts the
+ // resumption offer on renegotiation.
+ if c.cipherSuite != nil && c.config.Bugs.FailIfResumeOnRenego {
+ return false, errors.New("tls: server resumed session on renegotiation")
+ }
+
+ if hs.serverHello.extensions.sctList != nil {
+ return false, errors.New("tls: server sent SCT extension on session resumption")
+ }
+
+ if hs.serverHello.extensions.ocspStapling {
+ return false, errors.New("tls: server sent OCSP extension on session resumption")
+ }
+
+ // Restore masterSecret and peerCerts from previous state
+ hs.masterSecret = hs.session.masterSecret
+ c.peerCertificates = hs.session.serverCertificates
+ c.extendedMasterSecret = hs.session.extendedMasterSecret
+ c.sctList = hs.session.sctList
+ c.ocspResponse = hs.session.ocspResponse
+ hs.finishedHash.discardHandshakeBuffer()
+ return true, nil
+ }
+
+ if hs.serverHello.extensions.sctList != nil {
+ c.sctList = hs.serverHello.extensions.sctList
+ }
+
+ return false, nil
+}
+
+func (hs *clientHandshakeState) readFinished(out []byte) error {
+ c := hs.c
+
+ c.readRecord(recordTypeChangeCipherSpec)
+ if err := c.in.error(); err != nil {
+ return err
+ }
+
+ msg, err := c.readHandshake()
+ if err != nil {
+ return err
+ }
+ serverFinished, ok := msg.(*finishedMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(serverFinished, msg)
+ }
+
+ if c.config.Bugs.EarlyChangeCipherSpec == 0 {
+ verify := hs.finishedHash.serverSum(hs.masterSecret)
+ if len(verify) != len(serverFinished.verifyData) ||
+ subtle.ConstantTimeCompare(verify, serverFinished.verifyData) != 1 {
+ c.sendAlert(alertHandshakeFailure)
+ return errors.New("tls: server's Finished message was incorrect")
+ }
+ }
+ c.serverVerify = append(c.serverVerify[:0], serverFinished.verifyData...)
+ copy(out, serverFinished.verifyData)
+ hs.writeServerHash(serverFinished.marshal())
+ return nil
+}
+
+func (hs *clientHandshakeState) readSessionTicket() error {
+ c := hs.c
+
+ // Create a session with no server identifier. Either a
+ // session ID or session ticket will be attached.
+ session := &ClientSessionState{
+ vers: c.vers,
+ cipherSuite: hs.suite.id,
+ masterSecret: hs.masterSecret,
+ handshakeHash: hs.finishedHash.Sum(),
+ serverCertificates: c.peerCertificates,
+ sctList: c.sctList,
+ ocspResponse: c.ocspResponse,
+ ticketExpiration: c.config.time().Add(time.Duration(7 * 24 * time.Hour)),
+ }
+
+ if !hs.serverHello.extensions.ticketSupported {
+ if c.config.Bugs.ExpectNewTicket {
+ return errors.New("tls: expected new ticket")
+ }
+ if hs.session == nil && len(hs.serverHello.sessionId) > 0 {
+ session.sessionId = hs.serverHello.sessionId
+ hs.session = session
+ }
+ return nil
+ }
+
+ if c.vers == VersionSSL30 {
+ return errors.New("tls: negotiated session tickets in SSL 3.0")
+ }
+
+ msg, err := c.readHandshake()
+ if err != nil {
+ return err
+ }
+ sessionTicketMsg, ok := msg.(*newSessionTicketMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(sessionTicketMsg, msg)
+ }
+
+ session.sessionTicket = sessionTicketMsg.ticket
+ hs.session = session
+
+ hs.writeServerHash(sessionTicketMsg.marshal())
+
+ return nil
+}
+
+func (hs *clientHandshakeState) sendFinished(out []byte, isResume bool) error {
+ c := hs.c
+
+ var postCCSMsgs [][]byte
+ seqno := hs.c.sendHandshakeSeq
+ if hs.serverHello.extensions.nextProtoNeg {
+ nextProto := new(nextProtoMsg)
+ proto, fallback := mutualProtocol(c.config.NextProtos, hs.serverHello.extensions.nextProtos)
+ nextProto.proto = proto
+ c.clientProtocol = proto
+ c.clientProtocolFallback = fallback
+
+ nextProtoBytes := nextProto.marshal()
+ hs.writeHash(nextProtoBytes, seqno)
+ seqno++
+ postCCSMsgs = append(postCCSMsgs, nextProtoBytes)
+ }
+
+ if hs.serverHello.extensions.channelIDRequested {
+ var resumeHash []byte
+ if isResume {
+ resumeHash = hs.session.handshakeHash
+ }
+ channelIDMsgBytes, err := hs.writeChannelIDMessage(hs.finishedHash.hashForChannelID(resumeHash))
+ if err != nil {
+ return err
+ }
+ hs.writeHash(channelIDMsgBytes, seqno)
+ seqno++
+ postCCSMsgs = append(postCCSMsgs, channelIDMsgBytes)
+ }
+
+ finished := new(finishedMsg)
+ if c.config.Bugs.EarlyChangeCipherSpec == 2 {
+ finished.verifyData = hs.finishedHash.clientSum(nil)
+ } else {
+ finished.verifyData = hs.finishedHash.clientSum(hs.masterSecret)
+ }
+ copy(out, finished.verifyData)
+ if c.config.Bugs.BadFinished {
+ finished.verifyData[0]++
+ }
+ c.clientVerify = append(c.clientVerify[:0], finished.verifyData...)
+ hs.finishedBytes = finished.marshal()
+ hs.writeHash(hs.finishedBytes, seqno)
+ postCCSMsgs = append(postCCSMsgs, hs.finishedBytes)
+
+ if c.config.Bugs.FragmentAcrossChangeCipherSpec {
+ c.writeRecord(recordTypeHandshake, postCCSMsgs[0][:5])
+ postCCSMsgs[0] = postCCSMsgs[0][5:]
+ } else if c.config.Bugs.SendUnencryptedFinished {
+ c.writeRecord(recordTypeHandshake, postCCSMsgs[0])
+ postCCSMsgs = postCCSMsgs[1:]
+ }
+ c.flushHandshake()
+
+ if !c.config.Bugs.SkipChangeCipherSpec &&
+ c.config.Bugs.EarlyChangeCipherSpec == 0 {
+ ccs := []byte{1}
+ if c.config.Bugs.BadChangeCipherSpec != nil {
+ ccs = c.config.Bugs.BadChangeCipherSpec
+ }
+ c.writeRecord(recordTypeChangeCipherSpec, ccs)
+ }
+
+ if c.config.Bugs.AppDataAfterChangeCipherSpec != nil {
+ c.writeRecord(recordTypeApplicationData, c.config.Bugs.AppDataAfterChangeCipherSpec)
+ }
+ if c.config.Bugs.AlertAfterChangeCipherSpec != 0 {
+ c.sendAlert(c.config.Bugs.AlertAfterChangeCipherSpec)
+ return errors.New("tls: simulating post-CCS alert")
+ }
+
+ if !c.config.Bugs.SkipFinished {
+ for _, msg := range postCCSMsgs {
+ c.writeRecord(recordTypeHandshake, msg)
+ }
+
+ if c.config.Bugs.SendExtraFinished {
+ c.writeRecord(recordTypeHandshake, finished.marshal())
+ }
+
+ c.flushHandshake()
+ }
+ return nil
+}
+
+func (hs *clientHandshakeState) writeChannelIDMessage(channelIDHash []byte) ([]byte, error) {
+ c := hs.c
+ channelIDMsg := new(channelIDMsg)
+ if c.config.ChannelID.Curve != elliptic.P256() {
+ return nil, fmt.Errorf("tls: Channel ID is not on P-256.")
+ }
+ r, s, err := ecdsa.Sign(c.config.rand(), c.config.ChannelID, channelIDHash)
+ if err != nil {
+ return nil, err
+ }
+ channelID := make([]byte, 128)
+ writeIntPadded(channelID[0:32], c.config.ChannelID.X)
+ writeIntPadded(channelID[32:64], c.config.ChannelID.Y)
+ writeIntPadded(channelID[64:96], r)
+ writeIntPadded(channelID[96:128], s)
+ if c.config.Bugs.InvalidChannelIDSignature {
+ channelID[64] ^= 1
+ }
+ channelIDMsg.channelID = channelID
+
+ c.channelID = &c.config.ChannelID.PublicKey
+
+ return channelIDMsg.marshal(), nil
+}
+
+func (hs *clientHandshakeState) writeClientHash(msg []byte) {
+ // writeClientHash is called before writeRecord.
+ hs.writeHash(msg, hs.c.sendHandshakeSeq)
+}
+
+func (hs *clientHandshakeState) writeServerHash(msg []byte) {
+ // writeServerHash is called after readHandshake.
+ hs.writeHash(msg, hs.c.recvHandshakeSeq-1)
+}
+
+func (hs *clientHandshakeState) writeHash(msg []byte, seqno uint16) {
+ if hs.c.isDTLS {
+ // This is somewhat hacky. DTLS hashes a slightly different format.
+ // First, the TLS header.
+ hs.finishedHash.Write(msg[:4])
+ // Then the sequence number and reassembled fragment offset (always 0).
+ hs.finishedHash.Write([]byte{byte(seqno >> 8), byte(seqno), 0, 0, 0})
+ // Then the reassembled fragment (always equal to the message length).
+ hs.finishedHash.Write(msg[1:4])
+ // And then the message body.
+ hs.finishedHash.Write(msg[4:])
+ } else {
+ hs.finishedHash.Write(msg)
+ }
+}
+
+// selectClientCertificate selects a certificate for use with the given
+// certificate, or none if none match. It may return a particular certificate or
+// nil on success, or an error on internal error.
+func selectClientCertificate(c *Conn, certReq *certificateRequestMsg) (*Certificate, error) {
+ // RFC 4346 on the certificateAuthorities field:
+ // A list of the distinguished names of acceptable certificate
+ // authorities. These distinguished names may specify a desired
+ // distinguished name for a root CA or for a subordinate CA; thus, this
+ // message can be used to describe both known roots and a desired
+ // authorization space. If the certificate_authorities list is empty
+ // then the client MAY send any certificate of the appropriate
+ // ClientCertificateType, unless there is some external arrangement to
+ // the contrary.
+
+ var rsaAvail, ecdsaAvail bool
+ if !certReq.hasRequestContext {
+ for _, certType := range certReq.certificateTypes {
+ switch certType {
+ case CertTypeRSASign:
+ rsaAvail = true
+ case CertTypeECDSASign:
+ ecdsaAvail = true
+ }
+ }
+ }
+
+ // We need to search our list of client certs for one
+ // where SignatureAlgorithm is RSA and the Issuer is in
+ // certReq.certificateAuthorities
+findCert:
+ for i, chain := range c.config.Certificates {
+ if !certReq.hasRequestContext && !rsaAvail && !ecdsaAvail {
+ continue
+ }
+
+ // Ensure the private key supports one of the advertised
+ // signature algorithms.
+ if certReq.hasSignatureAlgorithm {
+ if _, err := selectSignatureAlgorithm(c.vers, chain.PrivateKey, c.config, certReq.signatureAlgorithms); err != nil {
+ continue
+ }
+ }
+
+ for j, cert := range chain.Certificate {
+ x509Cert := chain.Leaf
+ // parse the certificate if this isn't the leaf
+ // node, or if chain.Leaf was nil
+ if j != 0 || x509Cert == nil {
+ var err error
+ if x509Cert, err = x509.ParseCertificate(cert); err != nil {
+ c.sendAlert(alertInternalError)
+ return nil, errors.New("tls: failed to parse client certificate #" + strconv.Itoa(i) + ": " + err.Error())
+ }
+ }
+
+ if !certReq.hasRequestContext {
+ switch {
+ case rsaAvail && x509Cert.PublicKeyAlgorithm == x509.RSA:
+ case ecdsaAvail && x509Cert.PublicKeyAlgorithm == x509.ECDSA:
+ default:
+ continue findCert
+ }
+ }
+
+ if expected := c.config.Bugs.ExpectCertificateReqNames; expected != nil {
+ if !eqByteSlices(expected, certReq.certificateAuthorities) {
+ return nil, fmt.Errorf("tls: CertificateRequest names differed, got %#v but expected %#v", certReq.certificateAuthorities, expected)
+ }
+ }
+
+ return &chain, nil
+ }
+ }
+
+ return nil, nil
+}
+
+// clientSessionCacheKey returns a key used to cache sessionTickets that could
+// be used to resume previously negotiated TLS sessions with a server.
+func clientSessionCacheKey(serverAddr net.Addr, config *Config) string {
+ if len(config.ServerName) > 0 {
+ return config.ServerName
+ }
+ return serverAddr.String()
+}
+
+// mutualProtocol finds the mutual Next Protocol Negotiation or ALPN protocol
+// given list of possible protocols and a list of the preference order. The
+// first list must not be empty. It returns the resulting protocol and flag
+// indicating if the fallback case was reached.
+func mutualProtocol(protos, preferenceProtos []string) (string, bool) {
+ for _, s := range preferenceProtos {
+ for _, c := range protos {
+ if s == c {
+ return s, false
+ }
+ }
+ }
+
+ return protos[0], true
+}
+
+// writeIntPadded writes x into b, padded up with leading zeros as
+// needed.
+func writeIntPadded(b []byte, x *big.Int) {
+ for i := range b {
+ b[i] = 0
+ }
+ xb := x.Bytes()
+ copy(b[len(b)-len(xb):], xb)
+}
+
+func generatePSKBinders(hello *clientHelloMsg, pskCipherSuite *cipherSuite, psk, transcript []byte, config *Config) {
+ if config.Bugs.SendNoPSKBinder {
+ return
+ }
+
+ binderLen := pskCipherSuite.hash().Size()
+ if config.Bugs.SendShortPSKBinder {
+ binderLen--
+ }
+
+ numBinders := 1
+ if config.Bugs.SendExtraPSKBinder {
+ numBinders++
+ }
+
+ // Fill hello.pskBinders with appropriate length arrays of zeros so the
+ // length prefixes are correct when computing the binder over the truncated
+ // ClientHello message.
+ hello.pskBinders = make([][]byte, numBinders)
+ for i := range hello.pskBinders {
+ hello.pskBinders[i] = make([]byte, binderLen)
+ }
+
+ helloBytes := hello.marshal()
+ binderSize := len(hello.pskBinders)*(binderLen+1) + 2
+ truncatedHello := helloBytes[:len(helloBytes)-binderSize]
+ binder := computePSKBinder(psk, resumptionPSKBinderLabel, pskCipherSuite, transcript, truncatedHello)
+ if config.Bugs.SendShortPSKBinder {
+ binder = binder[:binderLen]
+ }
+ if config.Bugs.SendInvalidPSKBinder {
+ binder[0] ^= 1
+ }
+
+ for i := range hello.pskBinders {
+ hello.pskBinders[i] = binder
+ }
+
+ hello.raw = nil
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/handshake_messages.go b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/handshake_messages.go
new file mode 100644
index 000000000..86e2821d5
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/handshake_messages.go
@@ -0,0 +1,2369 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runner
+
+import (
+ "bytes"
+ "encoding/binary"
+)
+
+func writeLen(buf []byte, v, size int) {
+ for i := 0; i < size; i++ {
+ buf[size-i-1] = byte(v)
+ v >>= 8
+ }
+ if v != 0 {
+ panic("length is too long")
+ }
+}
+
+type byteBuilder struct {
+ buf *[]byte
+ start int
+ prefixLen int
+ child *byteBuilder
+}
+
+func newByteBuilder() *byteBuilder {
+ buf := make([]byte, 0, 32)
+ return &byteBuilder{buf: &buf}
+}
+
+func (bb *byteBuilder) len() int {
+ return len(*bb.buf) - bb.start - bb.prefixLen
+}
+
+func (bb *byteBuilder) flush() {
+ if bb.child == nil {
+ return
+ }
+ bb.child.flush()
+ writeLen((*bb.buf)[bb.child.start:], bb.child.len(), bb.child.prefixLen)
+ bb.child = nil
+ return
+}
+
+func (bb *byteBuilder) finish() []byte {
+ bb.flush()
+ return *bb.buf
+}
+
+func (bb *byteBuilder) addU8(u uint8) {
+ bb.flush()
+ *bb.buf = append(*bb.buf, u)
+}
+
+func (bb *byteBuilder) addU16(u uint16) {
+ bb.flush()
+ *bb.buf = append(*bb.buf, byte(u>>8), byte(u))
+}
+
+func (bb *byteBuilder) addU24(u int) {
+ bb.flush()
+ *bb.buf = append(*bb.buf, byte(u>>16), byte(u>>8), byte(u))
+}
+
+func (bb *byteBuilder) addU32(u uint32) {
+ bb.flush()
+ *bb.buf = append(*bb.buf, byte(u>>24), byte(u>>16), byte(u>>8), byte(u))
+}
+
+func (bb *byteBuilder) addU64(u uint64) {
+ bb.flush()
+ var b [8]byte
+ binary.BigEndian.PutUint64(b[:], u)
+ *bb.buf = append(*bb.buf, b[:]...)
+}
+
+func (bb *byteBuilder) addU8LengthPrefixed() *byteBuilder {
+ return bb.createChild(1)
+}
+
+func (bb *byteBuilder) addU16LengthPrefixed() *byteBuilder {
+ return bb.createChild(2)
+}
+
+func (bb *byteBuilder) addU24LengthPrefixed() *byteBuilder {
+ return bb.createChild(3)
+}
+
+func (bb *byteBuilder) addU32LengthPrefixed() *byteBuilder {
+ return bb.createChild(4)
+}
+
+func (bb *byteBuilder) addBytes(b []byte) {
+ bb.flush()
+ *bb.buf = append(*bb.buf, b...)
+}
+
+func (bb *byteBuilder) createChild(lengthPrefixSize int) *byteBuilder {
+ bb.flush()
+ bb.child = &byteBuilder{
+ buf: bb.buf,
+ start: len(*bb.buf),
+ prefixLen: lengthPrefixSize,
+ }
+ for i := 0; i < lengthPrefixSize; i++ {
+ *bb.buf = append(*bb.buf, 0)
+ }
+ return bb.child
+}
+
+func (bb *byteBuilder) discardChild() {
+ if bb.child != nil {
+ return
+ }
+ bb.child = nil
+ *bb.buf = (*bb.buf)[:bb.start]
+}
+
+type keyShareEntry struct {
+ group CurveID
+ keyExchange []byte
+}
+
+type pskIdentity struct {
+ ticket []uint8
+ obfuscatedTicketAge uint32
+}
+
+type clientHelloMsg struct {
+ raw []byte
+ isDTLS bool
+ vers uint16
+ random []byte
+ sessionId []byte
+ cookie []byte
+ cipherSuites []uint16
+ compressionMethods []uint8
+ nextProtoNeg bool
+ serverName string
+ ocspStapling bool
+ supportedCurves []CurveID
+ supportedPoints []uint8
+ hasKeyShares bool
+ keyShares []keyShareEntry
+ trailingKeyShareData bool
+ pskIdentities []pskIdentity
+ pskKEModes []byte
+ pskBinders [][]uint8
+ hasEarlyData bool
+ tls13Cookie []byte
+ ticketSupported bool
+ sessionTicket []uint8
+ signatureAlgorithms []signatureAlgorithm
+ supportedVersions []uint16
+ secureRenegotiation []byte
+ alpnProtocols []string
+ duplicateExtension bool
+ channelIDSupported bool
+ npnAfterAlpn bool
+ extendedMasterSecret bool
+ srtpProtectionProfiles []uint16
+ srtpMasterKeyIdentifier string
+ sctListSupported bool
+ customExtension string
+ hasGREASEExtension bool
+ pskBinderFirst bool
+}
+
+func (m *clientHelloMsg) equal(i interface{}) bool {
+ m1, ok := i.(*clientHelloMsg)
+ if !ok {
+ return false
+ }
+
+ return bytes.Equal(m.raw, m1.raw) &&
+ m.isDTLS == m1.isDTLS &&
+ m.vers == m1.vers &&
+ bytes.Equal(m.random, m1.random) &&
+ bytes.Equal(m.sessionId, m1.sessionId) &&
+ bytes.Equal(m.cookie, m1.cookie) &&
+ eqUint16s(m.cipherSuites, m1.cipherSuites) &&
+ bytes.Equal(m.compressionMethods, m1.compressionMethods) &&
+ m.nextProtoNeg == m1.nextProtoNeg &&
+ m.serverName == m1.serverName &&
+ m.ocspStapling == m1.ocspStapling &&
+ eqCurveIDs(m.supportedCurves, m1.supportedCurves) &&
+ bytes.Equal(m.supportedPoints, m1.supportedPoints) &&
+ m.hasKeyShares == m1.hasKeyShares &&
+ eqKeyShareEntryLists(m.keyShares, m1.keyShares) &&
+ m.trailingKeyShareData == m1.trailingKeyShareData &&
+ eqPSKIdentityLists(m.pskIdentities, m1.pskIdentities) &&
+ bytes.Equal(m.pskKEModes, m1.pskKEModes) &&
+ eqByteSlices(m.pskBinders, m1.pskBinders) &&
+ m.hasEarlyData == m1.hasEarlyData &&
+ bytes.Equal(m.tls13Cookie, m1.tls13Cookie) &&
+ m.ticketSupported == m1.ticketSupported &&
+ bytes.Equal(m.sessionTicket, m1.sessionTicket) &&
+ eqSignatureAlgorithms(m.signatureAlgorithms, m1.signatureAlgorithms) &&
+ eqUint16s(m.supportedVersions, m1.supportedVersions) &&
+ bytes.Equal(m.secureRenegotiation, m1.secureRenegotiation) &&
+ (m.secureRenegotiation == nil) == (m1.secureRenegotiation == nil) &&
+ eqStrings(m.alpnProtocols, m1.alpnProtocols) &&
+ m.duplicateExtension == m1.duplicateExtension &&
+ m.channelIDSupported == m1.channelIDSupported &&
+ m.npnAfterAlpn == m1.npnAfterAlpn &&
+ m.extendedMasterSecret == m1.extendedMasterSecret &&
+ eqUint16s(m.srtpProtectionProfiles, m1.srtpProtectionProfiles) &&
+ m.srtpMasterKeyIdentifier == m1.srtpMasterKeyIdentifier &&
+ m.sctListSupported == m1.sctListSupported &&
+ m.customExtension == m1.customExtension &&
+ m.hasGREASEExtension == m1.hasGREASEExtension &&
+ m.pskBinderFirst == m1.pskBinderFirst
+}
+
+func (m *clientHelloMsg) marshal() []byte {
+ if m.raw != nil {
+ return m.raw
+ }
+
+ handshakeMsg := newByteBuilder()
+ handshakeMsg.addU8(typeClientHello)
+ hello := handshakeMsg.addU24LengthPrefixed()
+ hello.addU16(m.vers)
+ hello.addBytes(m.random)
+ sessionId := hello.addU8LengthPrefixed()
+ sessionId.addBytes(m.sessionId)
+ if m.isDTLS {
+ cookie := hello.addU8LengthPrefixed()
+ cookie.addBytes(m.cookie)
+ }
+ cipherSuites := hello.addU16LengthPrefixed()
+ for _, suite := range m.cipherSuites {
+ cipherSuites.addU16(suite)
+ }
+ compressionMethods := hello.addU8LengthPrefixed()
+ compressionMethods.addBytes(m.compressionMethods)
+
+ extensions := hello.addU16LengthPrefixed()
+ if len(m.pskIdentities) > 0 && m.pskBinderFirst {
+ extensions.addU16(extensionPreSharedKey)
+ pskExtension := extensions.addU16LengthPrefixed()
+
+ pskIdentities := pskExtension.addU16LengthPrefixed()
+ for _, psk := range m.pskIdentities {
+ pskIdentities.addU16LengthPrefixed().addBytes(psk.ticket)
+ pskIdentities.addU32(psk.obfuscatedTicketAge)
+ }
+ pskBinders := pskExtension.addU16LengthPrefixed()
+ for _, binder := range m.pskBinders {
+ pskBinders.addU8LengthPrefixed().addBytes(binder)
+ }
+ }
+ if m.duplicateExtension {
+ // Add a duplicate bogus extension at the beginning and end.
+ extensions.addU16(0xffff)
+ extensions.addU16(0) // 0-length for empty extension
+ }
+ if m.nextProtoNeg && !m.npnAfterAlpn {
+ extensions.addU16(extensionNextProtoNeg)
+ extensions.addU16(0) // The length is always 0
+ }
+ if len(m.serverName) > 0 {
+ extensions.addU16(extensionServerName)
+ serverNameList := extensions.addU16LengthPrefixed()
+
+ // RFC 3546, section 3.1
+ //
+ // struct {
+ // NameType name_type;
+ // select (name_type) {
+ // case host_name: HostName;
+ // } name;
+ // } ServerName;
+ //
+ // enum {
+ // host_name(0), (255)
+ // } NameType;
+ //
+ // opaque HostName<1..2^16-1>;
+ //
+ // struct {
+ // ServerName server_name_list<1..2^16-1>
+ // } ServerNameList;
+
+ serverName := serverNameList.addU16LengthPrefixed()
+ serverName.addU8(0) // NameType host_name(0)
+ hostName := serverName.addU16LengthPrefixed()
+ hostName.addBytes([]byte(m.serverName))
+ }
+ if m.ocspStapling {
+ extensions.addU16(extensionStatusRequest)
+ certificateStatusRequest := extensions.addU16LengthPrefixed()
+
+ // RFC 4366, section 3.6
+ certificateStatusRequest.addU8(1) // OCSP type
+ // Two zero valued uint16s for the two lengths.
+ certificateStatusRequest.addU16(0) // ResponderID length
+ certificateStatusRequest.addU16(0) // Extensions length
+ }
+ if len(m.supportedCurves) > 0 {
+ // http://tools.ietf.org/html/rfc4492#section-5.1.1
+ extensions.addU16(extensionSupportedCurves)
+ supportedCurvesList := extensions.addU16LengthPrefixed()
+ supportedCurves := supportedCurvesList.addU16LengthPrefixed()
+ for _, curve := range m.supportedCurves {
+ supportedCurves.addU16(uint16(curve))
+ }
+ }
+ if len(m.supportedPoints) > 0 {
+ // http://tools.ietf.org/html/rfc4492#section-5.1.2
+ extensions.addU16(extensionSupportedPoints)
+ supportedPointsList := extensions.addU16LengthPrefixed()
+ supportedPoints := supportedPointsList.addU8LengthPrefixed()
+ supportedPoints.addBytes(m.supportedPoints)
+ }
+ if m.hasKeyShares {
+ extensions.addU16(extensionKeyShare)
+ keyShareList := extensions.addU16LengthPrefixed()
+
+ keyShares := keyShareList.addU16LengthPrefixed()
+ for _, keyShare := range m.keyShares {
+ keyShares.addU16(uint16(keyShare.group))
+ keyExchange := keyShares.addU16LengthPrefixed()
+ keyExchange.addBytes(keyShare.keyExchange)
+ }
+
+ if m.trailingKeyShareData {
+ keyShares.addU8(0)
+ }
+ }
+ if len(m.pskKEModes) > 0 {
+ extensions.addU16(extensionPSKKeyExchangeModes)
+ pskModesExtension := extensions.addU16LengthPrefixed()
+ pskModesExtension.addU8LengthPrefixed().addBytes(m.pskKEModes)
+ }
+ if m.hasEarlyData {
+ extensions.addU16(extensionEarlyData)
+ extensions.addU16(0) // The length is zero.
+ }
+ if len(m.tls13Cookie) > 0 {
+ extensions.addU16(extensionCookie)
+ body := extensions.addU16LengthPrefixed()
+ body.addU16LengthPrefixed().addBytes(m.tls13Cookie)
+ }
+ if m.ticketSupported {
+ // http://tools.ietf.org/html/rfc5077#section-3.2
+ extensions.addU16(extensionSessionTicket)
+ sessionTicketExtension := extensions.addU16LengthPrefixed()
+ sessionTicketExtension.addBytes(m.sessionTicket)
+ }
+ if len(m.signatureAlgorithms) > 0 {
+ // https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
+ extensions.addU16(extensionSignatureAlgorithms)
+ signatureAlgorithmsExtension := extensions.addU16LengthPrefixed()
+ signatureAlgorithms := signatureAlgorithmsExtension.addU16LengthPrefixed()
+ for _, sigAlg := range m.signatureAlgorithms {
+ signatureAlgorithms.addU16(uint16(sigAlg))
+ }
+ }
+ if len(m.supportedVersions) > 0 {
+ extensions.addU16(extensionSupportedVersions)
+ supportedVersionsExtension := extensions.addU16LengthPrefixed()
+ supportedVersions := supportedVersionsExtension.addU8LengthPrefixed()
+ for _, version := range m.supportedVersions {
+ supportedVersions.addU16(uint16(version))
+ }
+ }
+ if m.secureRenegotiation != nil {
+ extensions.addU16(extensionRenegotiationInfo)
+ secureRenegoExt := extensions.addU16LengthPrefixed()
+ secureRenego := secureRenegoExt.addU8LengthPrefixed()
+ secureRenego.addBytes(m.secureRenegotiation)
+ }
+ if len(m.alpnProtocols) > 0 {
+ // https://tools.ietf.org/html/rfc7301#section-3.1
+ extensions.addU16(extensionALPN)
+ alpnExtension := extensions.addU16LengthPrefixed()
+
+ protocolNameList := alpnExtension.addU16LengthPrefixed()
+ for _, s := range m.alpnProtocols {
+ protocolName := protocolNameList.addU8LengthPrefixed()
+ protocolName.addBytes([]byte(s))
+ }
+ }
+ if m.channelIDSupported {
+ extensions.addU16(extensionChannelID)
+ extensions.addU16(0) // Length is always 0
+ }
+ if m.nextProtoNeg && m.npnAfterAlpn {
+ extensions.addU16(extensionNextProtoNeg)
+ extensions.addU16(0) // Length is always 0
+ }
+ if m.duplicateExtension {
+ // Add a duplicate bogus extension at the beginning and end.
+ extensions.addU16(0xffff)
+ extensions.addU16(0)
+ }
+ if m.extendedMasterSecret {
+ // https://tools.ietf.org/html/rfc7627
+ extensions.addU16(extensionExtendedMasterSecret)
+ extensions.addU16(0) // Length is always 0
+ }
+ if len(m.srtpProtectionProfiles) > 0 {
+ // https://tools.ietf.org/html/rfc5764#section-4.1.1
+ extensions.addU16(extensionUseSRTP)
+ useSrtpExt := extensions.addU16LengthPrefixed()
+
+ srtpProtectionProfiles := useSrtpExt.addU16LengthPrefixed()
+ for _, p := range m.srtpProtectionProfiles {
+ // An SRTPProtectionProfile is defined as uint8[2],
+ // not uint16. For some reason, we're storing it
+ // as a uint16.
+ srtpProtectionProfiles.addU8(byte(p >> 8))
+ srtpProtectionProfiles.addU8(byte(p))
+ }
+ srtpMki := useSrtpExt.addU8LengthPrefixed()
+ srtpMki.addBytes([]byte(m.srtpMasterKeyIdentifier))
+ }
+ if m.sctListSupported {
+ extensions.addU16(extensionSignedCertificateTimestamp)
+ extensions.addU16(0) // Length is always 0
+ }
+ if l := len(m.customExtension); l > 0 {
+ extensions.addU16(extensionCustom)
+ customExt := extensions.addU16LengthPrefixed()
+ customExt.addBytes([]byte(m.customExtension))
+ }
+ // The PSK extension must be last (draft-ietf-tls-tls13-18 section 4.2.6).
+ if len(m.pskIdentities) > 0 && !m.pskBinderFirst {
+ extensions.addU16(extensionPreSharedKey)
+ pskExtension := extensions.addU16LengthPrefixed()
+
+ pskIdentities := pskExtension.addU16LengthPrefixed()
+ for _, psk := range m.pskIdentities {
+ pskIdentities.addU16LengthPrefixed().addBytes(psk.ticket)
+ pskIdentities.addU32(psk.obfuscatedTicketAge)
+ }
+ pskBinders := pskExtension.addU16LengthPrefixed()
+ for _, binder := range m.pskBinders {
+ pskBinders.addU8LengthPrefixed().addBytes(binder)
+ }
+ }
+
+ if extensions.len() == 0 {
+ hello.discardChild()
+ }
+
+ m.raw = handshakeMsg.finish()
+ return m.raw
+}
+
+func (m *clientHelloMsg) unmarshal(data []byte) bool {
+ if len(data) < 42 {
+ return false
+ }
+ m.raw = data
+ m.vers = uint16(data[4])<<8 | uint16(data[5])
+ m.random = data[6:38]
+ sessionIdLen := int(data[38])
+ if sessionIdLen > 32 || len(data) < 39+sessionIdLen {
+ return false
+ }
+ m.sessionId = data[39 : 39+sessionIdLen]
+ data = data[39+sessionIdLen:]
+ if m.isDTLS {
+ if len(data) < 1 {
+ return false
+ }
+ cookieLen := int(data[0])
+ if cookieLen > 32 || len(data) < 1+cookieLen {
+ return false
+ }
+ m.cookie = data[1 : 1+cookieLen]
+ data = data[1+cookieLen:]
+ }
+ if len(data) < 2 {
+ return false
+ }
+ // cipherSuiteLen is the number of bytes of cipher suite numbers. Since
+ // they are uint16s, the number must be even.
+ cipherSuiteLen := int(data[0])<<8 | int(data[1])
+ if cipherSuiteLen%2 == 1 || len(data) < 2+cipherSuiteLen {
+ return false
+ }
+ numCipherSuites := cipherSuiteLen / 2
+ m.cipherSuites = make([]uint16, numCipherSuites)
+ for i := 0; i < numCipherSuites; i++ {
+ m.cipherSuites[i] = uint16(data[2+2*i])<<8 | uint16(data[3+2*i])
+ if m.cipherSuites[i] == scsvRenegotiation {
+ m.secureRenegotiation = []byte{}
+ }
+ }
+ data = data[2+cipherSuiteLen:]
+ if len(data) < 1 {
+ return false
+ }
+ compressionMethodsLen := int(data[0])
+ if len(data) < 1+compressionMethodsLen {
+ return false
+ }
+ m.compressionMethods = data[1 : 1+compressionMethodsLen]
+
+ data = data[1+compressionMethodsLen:]
+
+ m.nextProtoNeg = false
+ m.serverName = ""
+ m.ocspStapling = false
+ m.keyShares = nil
+ m.pskIdentities = nil
+ m.hasEarlyData = false
+ m.ticketSupported = false
+ m.sessionTicket = nil
+ m.signatureAlgorithms = nil
+ m.supportedVersions = nil
+ m.alpnProtocols = nil
+ m.extendedMasterSecret = false
+ m.customExtension = ""
+
+ if len(data) == 0 {
+ // ClientHello is optionally followed by extension data
+ return true
+ }
+ if len(data) < 2 {
+ return false
+ }
+
+ extensionsLength := int(data[0])<<8 | int(data[1])
+ data = data[2:]
+ if extensionsLength != len(data) {
+ return false
+ }
+
+ for len(data) != 0 {
+ if len(data) < 4 {
+ return false
+ }
+ extension := uint16(data[0])<<8 | uint16(data[1])
+ length := int(data[2])<<8 | int(data[3])
+ data = data[4:]
+ if len(data) < length {
+ return false
+ }
+
+ switch extension {
+ case extensionServerName:
+ if length < 2 {
+ return false
+ }
+ numNames := int(data[0])<<8 | int(data[1])
+ d := data[2:]
+ for i := 0; i < numNames; i++ {
+ if len(d) < 3 {
+ return false
+ }
+ nameType := d[0]
+ nameLen := int(d[1])<<8 | int(d[2])
+ d = d[3:]
+ if len(d) < nameLen {
+ return false
+ }
+ if nameType == 0 {
+ m.serverName = string(d[0:nameLen])
+ break
+ }
+ d = d[nameLen:]
+ }
+ case extensionNextProtoNeg:
+ if length > 0 {
+ return false
+ }
+ m.nextProtoNeg = true
+ case extensionStatusRequest:
+ m.ocspStapling = length > 0 && data[0] == statusTypeOCSP
+ case extensionSupportedCurves:
+ // http://tools.ietf.org/html/rfc4492#section-5.5.1
+ if length < 2 {
+ return false
+ }
+ l := int(data[0])<<8 | int(data[1])
+ if l%2 == 1 || length != l+2 {
+ return false
+ }
+ numCurves := l / 2
+ m.supportedCurves = make([]CurveID, numCurves)
+ d := data[2:]
+ for i := 0; i < numCurves; i++ {
+ m.supportedCurves[i] = CurveID(d[0])<<8 | CurveID(d[1])
+ d = d[2:]
+ }
+ case extensionSupportedPoints:
+ // http://tools.ietf.org/html/rfc4492#section-5.5.2
+ if length < 1 {
+ return false
+ }
+ l := int(data[0])
+ if length != l+1 {
+ return false
+ }
+ m.supportedPoints = data[1 : 1+l]
+ case extensionSessionTicket:
+ // http://tools.ietf.org/html/rfc5077#section-3.2
+ m.ticketSupported = true
+ m.sessionTicket = data[:length]
+ case extensionKeyShare:
+ // draft-ietf-tls-tls13 section 6.3.2.3
+ if length < 2 {
+ return false
+ }
+ l := int(data[0])<<8 | int(data[1])
+ if l != length-2 {
+ return false
+ }
+ d := data[2:length]
+ m.hasKeyShares = true
+ for len(d) > 0 {
+ // The next KeyShareEntry contains a NamedGroup (2 bytes) and a
+ // key_exchange (2-byte length prefix with at least 1 byte of content).
+ if len(d) < 5 {
+ return false
+ }
+ entry := keyShareEntry{}
+ entry.group = CurveID(d[0])<<8 | CurveID(d[1])
+ keyExchLen := int(d[2])<<8 | int(d[3])
+ d = d[4:]
+ if len(d) < keyExchLen {
+ return false
+ }
+ entry.keyExchange = d[:keyExchLen]
+ d = d[keyExchLen:]
+ m.keyShares = append(m.keyShares, entry)
+ }
+ case extensionPreSharedKey:
+ // draft-ietf-tls-tls13-18 section 4.2.6
+ if length < 2 {
+ return false
+ }
+ l := int(data[0])<<8 | int(data[1])
+ d := data[2 : l+2]
+ // Parse PSK identities.
+ for len(d) > 0 {
+ if len(d) < 2 {
+ return false
+ }
+ pskLen := int(d[0])<<8 | int(d[1])
+ d = d[2:]
+
+ if len(d) < pskLen+4 {
+ return false
+ }
+ ticket := d[:pskLen]
+ obfuscatedTicketAge := uint32(d[pskLen])<<24 | uint32(d[pskLen+1])<<16 | uint32(d[pskLen+2])<<8 | uint32(d[pskLen+3])
+ psk := pskIdentity{
+ ticket: ticket,
+ obfuscatedTicketAge: obfuscatedTicketAge,
+ }
+ m.pskIdentities = append(m.pskIdentities, psk)
+ d = d[pskLen+4:]
+ }
+ d = data[l+2:]
+ if len(d) < 2 {
+ return false
+ }
+ l = int(d[0])<<8 | int(d[1])
+ d = d[2:]
+ if l != len(d) {
+ return false
+ }
+ // Parse PSK binders.
+ for len(d) > 0 {
+ if len(d) < 1 {
+ return false
+ }
+ binderLen := int(d[0])
+ d = d[1:]
+ if binderLen > len(d) {
+ return false
+ }
+ m.pskBinders = append(m.pskBinders, d[:binderLen])
+ d = d[binderLen:]
+ }
+
+ // There must be the same number of identities as binders.
+ if len(m.pskIdentities) != len(m.pskBinders) {
+ return false
+ }
+ case extensionPSKKeyExchangeModes:
+ // draft-ietf-tls-tls13-18 section 4.2.7
+ if length < 1 {
+ return false
+ }
+ l := int(data[0])
+ if l != length-1 {
+ return false
+ }
+ m.pskKEModes = data[1:length]
+ case extensionEarlyData:
+ // draft-ietf-tls-tls13 section 6.3.2.5
+ if length != 0 {
+ return false
+ }
+ m.hasEarlyData = true
+ case extensionCookie:
+ if length < 2 {
+ return false
+ }
+ l := int(data[0])<<8 | int(data[1])
+ if l != length-2 || l == 0 {
+ return false
+ }
+ m.tls13Cookie = data[2 : 2+l]
+ case extensionSignatureAlgorithms:
+ // https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
+ if length < 2 || length&1 != 0 {
+ return false
+ }
+ l := int(data[0])<<8 | int(data[1])
+ if l != length-2 {
+ return false
+ }
+ n := l / 2
+ d := data[2:]
+ m.signatureAlgorithms = make([]signatureAlgorithm, n)
+ for i := range m.signatureAlgorithms {
+ m.signatureAlgorithms[i] = signatureAlgorithm(d[0])<<8 | signatureAlgorithm(d[1])
+ d = d[2:]
+ }
+ case extensionSupportedVersions:
+ if length < 1+2 {
+ return false
+ }
+ l := int(data[0])
+ if l != length-1 || l%2 == 1 || l < 2 {
+ return false
+ }
+ n := l / 2
+ d := data[1:]
+ m.supportedVersions = make([]uint16, n)
+ for i := range m.supportedVersions {
+ m.supportedVersions[i] = uint16(d[0])<<8 | uint16(d[1])
+ d = d[2:]
+ }
+ case extensionRenegotiationInfo:
+ if length < 1 || length != int(data[0])+1 {
+ return false
+ }
+ m.secureRenegotiation = data[1:length]
+ case extensionALPN:
+ if length < 2 {
+ return false
+ }
+ l := int(data[0])<<8 | int(data[1])
+ if l != length-2 {
+ return false
+ }
+ d := data[2:length]
+ for len(d) != 0 {
+ stringLen := int(d[0])
+ d = d[1:]
+ if stringLen == 0 || stringLen > len(d) {
+ return false
+ }
+ m.alpnProtocols = append(m.alpnProtocols, string(d[:stringLen]))
+ d = d[stringLen:]
+ }
+ case extensionChannelID:
+ if length > 0 {
+ return false
+ }
+ m.channelIDSupported = true
+ case extensionExtendedMasterSecret:
+ if length != 0 {
+ return false
+ }
+ m.extendedMasterSecret = true
+ case extensionUseSRTP:
+ if length < 2 {
+ return false
+ }
+ l := int(data[0])<<8 | int(data[1])
+ if l > length-2 || l%2 != 0 {
+ return false
+ }
+ n := l / 2
+ m.srtpProtectionProfiles = make([]uint16, n)
+ d := data[2:length]
+ for i := 0; i < n; i++ {
+ m.srtpProtectionProfiles[i] = uint16(d[0])<<8 | uint16(d[1])
+ d = d[2:]
+ }
+ if len(d) < 1 || int(d[0]) != len(d)-1 {
+ return false
+ }
+ m.srtpMasterKeyIdentifier = string(d[1:])
+ case extensionSignedCertificateTimestamp:
+ if length != 0 {
+ return false
+ }
+ m.sctListSupported = true
+ case extensionCustom:
+ m.customExtension = string(data[:length])
+ }
+ data = data[length:]
+
+ if isGREASEValue(extension) {
+ m.hasGREASEExtension = true
+ }
+ }
+
+ return true
+}
+
+type serverHelloMsg struct {
+ raw []byte
+ isDTLS bool
+ vers uint16
+ versOverride uint16
+ random []byte
+ sessionId []byte
+ cipherSuite uint16
+ hasKeyShare bool
+ keyShare keyShareEntry
+ hasPSKIdentity bool
+ pskIdentity uint16
+ compressionMethod uint8
+ customExtension string
+ unencryptedALPN string
+ extensions serverExtensions
+}
+
+func (m *serverHelloMsg) marshal() []byte {
+ if m.raw != nil {
+ return m.raw
+ }
+
+ handshakeMsg := newByteBuilder()
+ handshakeMsg.addU8(typeServerHello)
+ hello := handshakeMsg.addU24LengthPrefixed()
+
+ // m.vers is used both to determine the format of the rest of the
+ // ServerHello and to override the value, so include a second version
+ // field.
+ vers, ok := wireToVersion(m.vers, m.isDTLS)
+ if !ok {
+ panic("unknown version")
+ }
+ if m.versOverride != 0 {
+ hello.addU16(m.versOverride)
+ } else {
+ hello.addU16(m.vers)
+ }
+
+ hello.addBytes(m.random)
+ if vers < VersionTLS13 {
+ sessionId := hello.addU8LengthPrefixed()
+ sessionId.addBytes(m.sessionId)
+ }
+ hello.addU16(m.cipherSuite)
+ if vers < VersionTLS13 {
+ hello.addU8(m.compressionMethod)
+ }
+
+ extensions := hello.addU16LengthPrefixed()
+
+ if vers >= VersionTLS13 {
+ if m.hasKeyShare {
+ extensions.addU16(extensionKeyShare)
+ keyShare := extensions.addU16LengthPrefixed()
+ keyShare.addU16(uint16(m.keyShare.group))
+ keyExchange := keyShare.addU16LengthPrefixed()
+ keyExchange.addBytes(m.keyShare.keyExchange)
+ }
+ if m.hasPSKIdentity {
+ extensions.addU16(extensionPreSharedKey)
+ extensions.addU16(2) // Length
+ extensions.addU16(m.pskIdentity)
+ }
+ if len(m.customExtension) > 0 {
+ extensions.addU16(extensionCustom)
+ customExt := extensions.addU16LengthPrefixed()
+ customExt.addBytes([]byte(m.customExtension))
+ }
+ if len(m.unencryptedALPN) > 0 {
+ extensions.addU16(extensionALPN)
+ extension := extensions.addU16LengthPrefixed()
+
+ protocolNameList := extension.addU16LengthPrefixed()
+ protocolName := protocolNameList.addU8LengthPrefixed()
+ protocolName.addBytes([]byte(m.unencryptedALPN))
+ }
+ } else {
+ m.extensions.marshal(extensions)
+ if extensions.len() == 0 {
+ hello.discardChild()
+ }
+ }
+
+ m.raw = handshakeMsg.finish()
+ return m.raw
+}
+
+func (m *serverHelloMsg) unmarshal(data []byte) bool {
+ if len(data) < 42 {
+ return false
+ }
+ m.raw = data
+ m.vers = uint16(data[4])<<8 | uint16(data[5])
+ vers, ok := wireToVersion(m.vers, m.isDTLS)
+ if !ok {
+ return false
+ }
+ m.random = data[6:38]
+ data = data[38:]
+ if vers < VersionTLS13 {
+ sessionIdLen := int(data[0])
+ if sessionIdLen > 32 || len(data) < 1+sessionIdLen {
+ return false
+ }
+ m.sessionId = data[1 : 1+sessionIdLen]
+ data = data[1+sessionIdLen:]
+ }
+ if len(data) < 2 {
+ return false
+ }
+ m.cipherSuite = uint16(data[0])<<8 | uint16(data[1])
+ data = data[2:]
+ if vers < VersionTLS13 {
+ if len(data) < 1 {
+ return false
+ }
+ m.compressionMethod = data[0]
+ data = data[1:]
+ }
+
+ if len(data) == 0 && m.vers < VersionTLS13 {
+ // Extension data is optional before TLS 1.3.
+ m.extensions = serverExtensions{}
+ return true
+ }
+ if len(data) < 2 {
+ return false
+ }
+
+ extensionsLength := int(data[0])<<8 | int(data[1])
+ data = data[2:]
+ if len(data) != extensionsLength {
+ return false
+ }
+
+ if vers >= VersionTLS13 {
+ for len(data) != 0 {
+ if len(data) < 4 {
+ return false
+ }
+ extension := uint16(data[0])<<8 | uint16(data[1])
+ length := int(data[2])<<8 | int(data[3])
+ data = data[4:]
+
+ if len(data) < length {
+ return false
+ }
+ d := data[:length]
+ data = data[length:]
+
+ switch extension {
+ case extensionKeyShare:
+ m.hasKeyShare = true
+ if len(d) < 4 {
+ return false
+ }
+ m.keyShare.group = CurveID(uint16(d[0])<<8 | uint16(d[1]))
+ keyExchLen := int(d[2])<<8 | int(d[3])
+ if keyExchLen != len(d)-4 {
+ return false
+ }
+ m.keyShare.keyExchange = make([]byte, keyExchLen)
+ copy(m.keyShare.keyExchange, d[4:])
+ case extensionPreSharedKey:
+ if len(d) != 2 {
+ return false
+ }
+ m.pskIdentity = uint16(d[0])<<8 | uint16(d[1])
+ m.hasPSKIdentity = true
+ default:
+ // Only allow the 3 extensions that are sent in
+ // the clear in TLS 1.3.
+ return false
+ }
+ }
+ } else if !m.extensions.unmarshal(data, vers) {
+ return false
+ }
+
+ return true
+}
+
+type encryptedExtensionsMsg struct {
+ raw []byte
+ extensions serverExtensions
+ empty bool
+}
+
+func (m *encryptedExtensionsMsg) marshal() []byte {
+ if m.raw != nil {
+ return m.raw
+ }
+
+ encryptedExtensionsMsg := newByteBuilder()
+ encryptedExtensionsMsg.addU8(typeEncryptedExtensions)
+ encryptedExtensions := encryptedExtensionsMsg.addU24LengthPrefixed()
+ if !m.empty {
+ extensions := encryptedExtensions.addU16LengthPrefixed()
+ m.extensions.marshal(extensions)
+ }
+
+ m.raw = encryptedExtensionsMsg.finish()
+ return m.raw
+}
+
+func (m *encryptedExtensionsMsg) unmarshal(data []byte) bool {
+ m.raw = data
+ if len(data) < 6 {
+ return false
+ }
+ if data[0] != typeEncryptedExtensions {
+ return false
+ }
+ msgLen := int(data[1])<<16 | int(data[2])<<8 | int(data[3])
+ data = data[4:]
+ if len(data) != msgLen {
+ return false
+ }
+ extLen := int(data[0])<<8 | int(data[1])
+ data = data[2:]
+ if extLen != len(data) {
+ return false
+ }
+ return m.extensions.unmarshal(data, VersionTLS13)
+}
+
+type serverExtensions struct {
+ nextProtoNeg bool
+ nextProtos []string
+ ocspStapling bool
+ ticketSupported bool
+ secureRenegotiation []byte
+ alpnProtocol string
+ alpnProtocolEmpty bool
+ duplicateExtension bool
+ channelIDRequested bool
+ extendedMasterSecret bool
+ srtpProtectionProfile uint16
+ srtpMasterKeyIdentifier string
+ sctList []byte
+ customExtension string
+ npnAfterAlpn bool
+ hasKeyShare bool
+ hasEarlyData bool
+ keyShare keyShareEntry
+ supportedPoints []uint8
+ serverNameAck bool
+}
+
+func (m *serverExtensions) marshal(extensions *byteBuilder) {
+ if m.duplicateExtension {
+ // Add a duplicate bogus extension at the beginning and end.
+ extensions.addU16(0xffff)
+ extensions.addU16(0) // length = 0 for empty extension
+ }
+ if m.nextProtoNeg && !m.npnAfterAlpn {
+ extensions.addU16(extensionNextProtoNeg)
+ extension := extensions.addU16LengthPrefixed()
+
+ for _, v := range m.nextProtos {
+ if len(v) > 255 {
+ v = v[:255]
+ }
+ npn := extension.addU8LengthPrefixed()
+ npn.addBytes([]byte(v))
+ }
+ }
+ if m.ocspStapling {
+ extensions.addU16(extensionStatusRequest)
+ extensions.addU16(0)
+ }
+ if m.ticketSupported {
+ extensions.addU16(extensionSessionTicket)
+ extensions.addU16(0)
+ }
+ if m.secureRenegotiation != nil {
+ extensions.addU16(extensionRenegotiationInfo)
+ extension := extensions.addU16LengthPrefixed()
+ secureRenego := extension.addU8LengthPrefixed()
+ secureRenego.addBytes(m.secureRenegotiation)
+ }
+ if len(m.alpnProtocol) > 0 || m.alpnProtocolEmpty {
+ extensions.addU16(extensionALPN)
+ extension := extensions.addU16LengthPrefixed()
+
+ protocolNameList := extension.addU16LengthPrefixed()
+ protocolName := protocolNameList.addU8LengthPrefixed()
+ protocolName.addBytes([]byte(m.alpnProtocol))
+ }
+ if m.channelIDRequested {
+ extensions.addU16(extensionChannelID)
+ extensions.addU16(0)
+ }
+ if m.duplicateExtension {
+ // Add a duplicate bogus extension at the beginning and end.
+ extensions.addU16(0xffff)
+ extensions.addU16(0)
+ }
+ if m.extendedMasterSecret {
+ extensions.addU16(extensionExtendedMasterSecret)
+ extensions.addU16(0)
+ }
+ if m.srtpProtectionProfile != 0 {
+ extensions.addU16(extensionUseSRTP)
+ extension := extensions.addU16LengthPrefixed()
+
+ srtpProtectionProfiles := extension.addU16LengthPrefixed()
+ srtpProtectionProfiles.addU8(byte(m.srtpProtectionProfile >> 8))
+ srtpProtectionProfiles.addU8(byte(m.srtpProtectionProfile))
+ srtpMki := extension.addU8LengthPrefixed()
+ srtpMki.addBytes([]byte(m.srtpMasterKeyIdentifier))
+ }
+ if m.sctList != nil {
+ extensions.addU16(extensionSignedCertificateTimestamp)
+ extension := extensions.addU16LengthPrefixed()
+ extension.addBytes(m.sctList)
+ }
+ if l := len(m.customExtension); l > 0 {
+ extensions.addU16(extensionCustom)
+ customExt := extensions.addU16LengthPrefixed()
+ customExt.addBytes([]byte(m.customExtension))
+ }
+ if m.nextProtoNeg && m.npnAfterAlpn {
+ extensions.addU16(extensionNextProtoNeg)
+ extension := extensions.addU16LengthPrefixed()
+
+ for _, v := range m.nextProtos {
+ if len(v) > 255 {
+ v = v[0:255]
+ }
+ npn := extension.addU8LengthPrefixed()
+ npn.addBytes([]byte(v))
+ }
+ }
+ if m.hasKeyShare {
+ extensions.addU16(extensionKeyShare)
+ keyShare := extensions.addU16LengthPrefixed()
+ keyShare.addU16(uint16(m.keyShare.group))
+ keyExchange := keyShare.addU16LengthPrefixed()
+ keyExchange.addBytes(m.keyShare.keyExchange)
+ }
+ if len(m.supportedPoints) > 0 {
+ // http://tools.ietf.org/html/rfc4492#section-5.1.2
+ extensions.addU16(extensionSupportedPoints)
+ supportedPointsList := extensions.addU16LengthPrefixed()
+ supportedPoints := supportedPointsList.addU8LengthPrefixed()
+ supportedPoints.addBytes(m.supportedPoints)
+ }
+ if m.hasEarlyData {
+ extensions.addU16(extensionEarlyData)
+ extensions.addBytes([]byte{0, 0})
+ }
+ if m.serverNameAck {
+ extensions.addU16(extensionServerName)
+ extensions.addU16(0) // zero length
+ }
+}
+
+func (m *serverExtensions) unmarshal(data []byte, version uint16) bool {
+ // Reset all fields.
+ *m = serverExtensions{}
+
+ for len(data) != 0 {
+ if len(data) < 4 {
+ return false
+ }
+ extension := uint16(data[0])<<8 | uint16(data[1])
+ length := int(data[2])<<8 | int(data[3])
+ data = data[4:]
+ if len(data) < length {
+ return false
+ }
+
+ switch extension {
+ case extensionNextProtoNeg:
+ m.nextProtoNeg = true
+ d := data[:length]
+ for len(d) > 0 {
+ l := int(d[0])
+ d = d[1:]
+ if l == 0 || l > len(d) {
+ return false
+ }
+ m.nextProtos = append(m.nextProtos, string(d[:l]))
+ d = d[l:]
+ }
+ case extensionStatusRequest:
+ if length > 0 {
+ return false
+ }
+ m.ocspStapling = true
+ case extensionSessionTicket:
+ if length > 0 {
+ return false
+ }
+ m.ticketSupported = true
+ case extensionRenegotiationInfo:
+ if length < 1 || length != int(data[0])+1 {
+ return false
+ }
+ m.secureRenegotiation = data[1:length]
+ case extensionALPN:
+ d := data[:length]
+ if len(d) < 3 {
+ return false
+ }
+ l := int(d[0])<<8 | int(d[1])
+ if l != len(d)-2 {
+ return false
+ }
+ d = d[2:]
+ l = int(d[0])
+ if l != len(d)-1 {
+ return false
+ }
+ d = d[1:]
+ m.alpnProtocol = string(d)
+ m.alpnProtocolEmpty = len(d) == 0
+ case extensionChannelID:
+ if length > 0 {
+ return false
+ }
+ m.channelIDRequested = true
+ case extensionExtendedMasterSecret:
+ if length != 0 {
+ return false
+ }
+ m.extendedMasterSecret = true
+ case extensionUseSRTP:
+ if length < 2+2+1 {
+ return false
+ }
+ if data[0] != 0 || data[1] != 2 {
+ return false
+ }
+ m.srtpProtectionProfile = uint16(data[2])<<8 | uint16(data[3])
+ d := data[4:length]
+ l := int(d[0])
+ if l != len(d)-1 {
+ return false
+ }
+ m.srtpMasterKeyIdentifier = string(d[1:])
+ case extensionSignedCertificateTimestamp:
+ m.sctList = data[:length]
+ case extensionCustom:
+ m.customExtension = string(data[:length])
+ case extensionServerName:
+ if length != 0 {
+ return false
+ }
+ m.serverNameAck = true
+ case extensionSupportedPoints:
+ // supported_points is illegal in TLS 1.3.
+ if version >= VersionTLS13 {
+ return false
+ }
+ // http://tools.ietf.org/html/rfc4492#section-5.5.2
+ if length < 1 {
+ return false
+ }
+ l := int(data[0])
+ if length != l+1 {
+ return false
+ }
+ m.supportedPoints = data[1 : 1+l]
+ case extensionSupportedCurves:
+ // The server can only send supported_curves in TLS 1.3.
+ if version < VersionTLS13 {
+ return false
+ }
+ case extensionEarlyData:
+ if version < VersionTLS13 || length != 0 {
+ return false
+ }
+ m.hasEarlyData = true
+ default:
+ // Unknown extensions are illegal from the server.
+ return false
+ }
+ data = data[length:]
+ }
+
+ return true
+}
+
+type helloRetryRequestMsg struct {
+ raw []byte
+ vers uint16
+ hasSelectedGroup bool
+ selectedGroup CurveID
+ cookie []byte
+ customExtension string
+ duplicateExtensions bool
+}
+
+func (m *helloRetryRequestMsg) marshal() []byte {
+ if m.raw != nil {
+ return m.raw
+ }
+
+ retryRequestMsg := newByteBuilder()
+ retryRequestMsg.addU8(typeHelloRetryRequest)
+ retryRequest := retryRequestMsg.addU24LengthPrefixed()
+ retryRequest.addU16(m.vers)
+ extensions := retryRequest.addU16LengthPrefixed()
+
+ count := 1
+ if m.duplicateExtensions {
+ count = 2
+ }
+
+ for i := 0; i < count; i++ {
+ if m.hasSelectedGroup {
+ extensions.addU16(extensionKeyShare)
+ extensions.addU16(2) // length
+ extensions.addU16(uint16(m.selectedGroup))
+ }
+ if len(m.cookie) > 0 {
+ extensions.addU16(extensionCookie)
+ body := extensions.addU16LengthPrefixed()
+ body.addU16LengthPrefixed().addBytes(m.cookie)
+ }
+ if len(m.customExtension) > 0 {
+ extensions.addU16(extensionCustom)
+ extensions.addU16LengthPrefixed().addBytes([]byte(m.customExtension))
+ }
+ }
+
+ m.raw = retryRequestMsg.finish()
+ return m.raw
+}
+
+func (m *helloRetryRequestMsg) unmarshal(data []byte) bool {
+ m.raw = data
+ if len(data) < 8 {
+ return false
+ }
+ m.vers = uint16(data[4])<<8 | uint16(data[5])
+ extLen := int(data[6])<<8 | int(data[7])
+ data = data[8:]
+ if len(data) != extLen || len(data) == 0 {
+ return false
+ }
+ for len(data) > 0 {
+ if len(data) < 4 {
+ return false
+ }
+ extension := uint16(data[0])<<8 | uint16(data[1])
+ length := int(data[2])<<8 | int(data[3])
+ data = data[4:]
+ if len(data) < length {
+ return false
+ }
+
+ switch extension {
+ case extensionKeyShare:
+ if length != 2 {
+ return false
+ }
+ m.hasSelectedGroup = true
+ m.selectedGroup = CurveID(data[0])<<8 | CurveID(data[1])
+ case extensionCookie:
+ if length < 2 {
+ return false
+ }
+ cookieLen := int(data[0])<<8 | int(data[1])
+ if 2+cookieLen != length {
+ return false
+ }
+ m.cookie = data[2 : 2+cookieLen]
+ default:
+ // Unknown extensions are illegal from the server.
+ return false
+ }
+ data = data[length:]
+ }
+ return true
+}
+
+type certificateEntry struct {
+ data []byte
+ ocspResponse []byte
+ sctList []byte
+ duplicateExtensions bool
+ extraExtension []byte
+}
+
+type certificateMsg struct {
+ raw []byte
+ hasRequestContext bool
+ requestContext []byte
+ certificates []certificateEntry
+}
+
+func (m *certificateMsg) marshal() (x []byte) {
+ if m.raw != nil {
+ return m.raw
+ }
+
+ certMsg := newByteBuilder()
+ certMsg.addU8(typeCertificate)
+ certificate := certMsg.addU24LengthPrefixed()
+ if m.hasRequestContext {
+ context := certificate.addU8LengthPrefixed()
+ context.addBytes(m.requestContext)
+ }
+ certificateList := certificate.addU24LengthPrefixed()
+ for _, cert := range m.certificates {
+ certEntry := certificateList.addU24LengthPrefixed()
+ certEntry.addBytes(cert.data)
+ if m.hasRequestContext {
+ extensions := certificateList.addU16LengthPrefixed()
+ count := 1
+ if cert.duplicateExtensions {
+ count = 2
+ }
+
+ for i := 0; i < count; i++ {
+ if cert.ocspResponse != nil {
+ extensions.addU16(extensionStatusRequest)
+ body := extensions.addU16LengthPrefixed()
+ body.addU8(statusTypeOCSP)
+ response := body.addU24LengthPrefixed()
+ response.addBytes(cert.ocspResponse)
+ }
+
+ if cert.sctList != nil {
+ extensions.addU16(extensionSignedCertificateTimestamp)
+ extension := extensions.addU16LengthPrefixed()
+ extension.addBytes(cert.sctList)
+ }
+ }
+ if cert.extraExtension != nil {
+ extensions.addBytes(cert.extraExtension)
+ }
+ }
+ }
+
+ m.raw = certMsg.finish()
+ return m.raw
+}
+
+func (m *certificateMsg) unmarshal(data []byte) bool {
+ if len(data) < 4 {
+ return false
+ }
+
+ m.raw = data
+ data = data[4:]
+
+ if m.hasRequestContext {
+ if len(data) == 0 {
+ return false
+ }
+ contextLen := int(data[0])
+ if len(data) < 1+contextLen {
+ return false
+ }
+ m.requestContext = make([]byte, contextLen)
+ copy(m.requestContext, data[1:])
+ data = data[1+contextLen:]
+ }
+
+ if len(data) < 3 {
+ return false
+ }
+ certsLen := int(data[0])<<16 | int(data[1])<<8 | int(data[2])
+ data = data[3:]
+ if len(data) != certsLen {
+ return false
+ }
+
+ m.certificates = nil
+ for len(data) != 0 {
+ if len(data) < 3 {
+ return false
+ }
+ certLen := int(data[0])<<16 | int(data[1])<<8 | int(data[2])
+ if len(data) < 3+certLen {
+ return false
+ }
+ cert := certificateEntry{
+ data: data[3 : 3+certLen],
+ }
+ data = data[3+certLen:]
+ if m.hasRequestContext {
+ if len(data) < 2 {
+ return false
+ }
+ extensionsLen := int(data[0])<<8 | int(data[1])
+ if len(data) < 2+extensionsLen {
+ return false
+ }
+ extensions := data[2 : 2+extensionsLen]
+ data = data[2+extensionsLen:]
+ for len(extensions) != 0 {
+ if len(extensions) < 4 {
+ return false
+ }
+ extension := uint16(extensions[0])<<8 | uint16(extensions[1])
+ length := int(extensions[2])<<8 | int(extensions[3])
+ if len(extensions) < 4+length {
+ return false
+ }
+ contents := extensions[4 : 4+length]
+ extensions = extensions[4+length:]
+
+ switch extension {
+ case extensionStatusRequest:
+ if length < 4 {
+ return false
+ }
+ if contents[0] != statusTypeOCSP {
+ return false
+ }
+ respLen := int(contents[1])<<16 | int(contents[2])<<8 | int(contents[3])
+ if respLen+4 != len(contents) || respLen == 0 {
+ return false
+ }
+ cert.ocspResponse = contents[4:]
+ case extensionSignedCertificateTimestamp:
+ cert.sctList = contents
+ default:
+ return false
+ }
+ }
+ }
+ m.certificates = append(m.certificates, cert)
+ }
+
+ return true
+}
+
+type serverKeyExchangeMsg struct {
+ raw []byte
+ key []byte
+}
+
+func (m *serverKeyExchangeMsg) marshal() []byte {
+ if m.raw != nil {
+ return m.raw
+ }
+ length := len(m.key)
+ x := make([]byte, length+4)
+ x[0] = typeServerKeyExchange
+ x[1] = uint8(length >> 16)
+ x[2] = uint8(length >> 8)
+ x[3] = uint8(length)
+ copy(x[4:], m.key)
+
+ m.raw = x
+ return x
+}
+
+func (m *serverKeyExchangeMsg) unmarshal(data []byte) bool {
+ m.raw = data
+ if len(data) < 4 {
+ return false
+ }
+ m.key = data[4:]
+ return true
+}
+
+type certificateStatusMsg struct {
+ raw []byte
+ statusType uint8
+ response []byte
+}
+
+func (m *certificateStatusMsg) marshal() []byte {
+ if m.raw != nil {
+ return m.raw
+ }
+
+ var x []byte
+ if m.statusType == statusTypeOCSP {
+ x = make([]byte, 4+4+len(m.response))
+ x[0] = typeCertificateStatus
+ l := len(m.response) + 4
+ x[1] = byte(l >> 16)
+ x[2] = byte(l >> 8)
+ x[3] = byte(l)
+ x[4] = statusTypeOCSP
+
+ l -= 4
+ x[5] = byte(l >> 16)
+ x[6] = byte(l >> 8)
+ x[7] = byte(l)
+ copy(x[8:], m.response)
+ } else {
+ x = []byte{typeCertificateStatus, 0, 0, 1, m.statusType}
+ }
+
+ m.raw = x
+ return x
+}
+
+func (m *certificateStatusMsg) unmarshal(data []byte) bool {
+ m.raw = data
+ if len(data) < 5 {
+ return false
+ }
+ m.statusType = data[4]
+
+ m.response = nil
+ if m.statusType == statusTypeOCSP {
+ if len(data) < 8 {
+ return false
+ }
+ respLen := uint32(data[5])<<16 | uint32(data[6])<<8 | uint32(data[7])
+ if uint32(len(data)) != 4+4+respLen {
+ return false
+ }
+ m.response = data[8:]
+ }
+ return true
+}
+
+type serverHelloDoneMsg struct{}
+
+func (m *serverHelloDoneMsg) marshal() []byte {
+ x := make([]byte, 4)
+ x[0] = typeServerHelloDone
+ return x
+}
+
+func (m *serverHelloDoneMsg) unmarshal(data []byte) bool {
+ return len(data) == 4
+}
+
+type clientKeyExchangeMsg struct {
+ raw []byte
+ ciphertext []byte
+}
+
+func (m *clientKeyExchangeMsg) marshal() []byte {
+ if m.raw != nil {
+ return m.raw
+ }
+ length := len(m.ciphertext)
+ x := make([]byte, length+4)
+ x[0] = typeClientKeyExchange
+ x[1] = uint8(length >> 16)
+ x[2] = uint8(length >> 8)
+ x[3] = uint8(length)
+ copy(x[4:], m.ciphertext)
+
+ m.raw = x
+ return x
+}
+
+func (m *clientKeyExchangeMsg) unmarshal(data []byte) bool {
+ m.raw = data
+ if len(data) < 4 {
+ return false
+ }
+ l := int(data[1])<<16 | int(data[2])<<8 | int(data[3])
+ if l != len(data)-4 {
+ return false
+ }
+ m.ciphertext = data[4:]
+ return true
+}
+
+type finishedMsg struct {
+ raw []byte
+ verifyData []byte
+}
+
+func (m *finishedMsg) marshal() (x []byte) {
+ if m.raw != nil {
+ return m.raw
+ }
+
+ x = make([]byte, 4+len(m.verifyData))
+ x[0] = typeFinished
+ x[3] = byte(len(m.verifyData))
+ copy(x[4:], m.verifyData)
+ m.raw = x
+ return
+}
+
+func (m *finishedMsg) unmarshal(data []byte) bool {
+ m.raw = data
+ if len(data) < 4 {
+ return false
+ }
+ m.verifyData = data[4:]
+ return true
+}
+
+type nextProtoMsg struct {
+ raw []byte
+ proto string
+}
+
+func (m *nextProtoMsg) marshal() []byte {
+ if m.raw != nil {
+ return m.raw
+ }
+ l := len(m.proto)
+ if l > 255 {
+ l = 255
+ }
+
+ padding := 32 - (l+2)%32
+ length := l + padding + 2
+ x := make([]byte, length+4)
+ x[0] = typeNextProtocol
+ x[1] = uint8(length >> 16)
+ x[2] = uint8(length >> 8)
+ x[3] = uint8(length)
+
+ y := x[4:]
+ y[0] = byte(l)
+ copy(y[1:], []byte(m.proto[0:l]))
+ y = y[1+l:]
+ y[0] = byte(padding)
+
+ m.raw = x
+
+ return x
+}
+
+func (m *nextProtoMsg) unmarshal(data []byte) bool {
+ m.raw = data
+
+ if len(data) < 5 {
+ return false
+ }
+ data = data[4:]
+ protoLen := int(data[0])
+ data = data[1:]
+ if len(data) < protoLen {
+ return false
+ }
+ m.proto = string(data[0:protoLen])
+ data = data[protoLen:]
+
+ if len(data) < 1 {
+ return false
+ }
+ paddingLen := int(data[0])
+ data = data[1:]
+ if len(data) != paddingLen {
+ return false
+ }
+
+ return true
+}
+
+type certificateRequestMsg struct {
+ raw []byte
+ // hasSignatureAlgorithm indicates whether this message includes a list
+ // of signature and hash functions. This change was introduced with TLS
+ // 1.2.
+ hasSignatureAlgorithm bool
+ // hasRequestContext indicates whether this message includes a context
+ // field instead of certificateTypes. This change was introduced with
+ // TLS 1.3.
+ hasRequestContext bool
+
+ certificateTypes []byte
+ requestContext []byte
+ signatureAlgorithms []signatureAlgorithm
+ certificateAuthorities [][]byte
+}
+
+func (m *certificateRequestMsg) marshal() []byte {
+ if m.raw != nil {
+ return m.raw
+ }
+
+ // See http://tools.ietf.org/html/rfc4346#section-7.4.4
+ builder := newByteBuilder()
+ builder.addU8(typeCertificateRequest)
+ body := builder.addU24LengthPrefixed()
+
+ if m.hasRequestContext {
+ requestContext := body.addU8LengthPrefixed()
+ requestContext.addBytes(m.requestContext)
+ } else {
+ certificateTypes := body.addU8LengthPrefixed()
+ certificateTypes.addBytes(m.certificateTypes)
+ }
+
+ if m.hasSignatureAlgorithm {
+ signatureAlgorithms := body.addU16LengthPrefixed()
+ for _, sigAlg := range m.signatureAlgorithms {
+ signatureAlgorithms.addU16(uint16(sigAlg))
+ }
+ }
+
+ certificateAuthorities := body.addU16LengthPrefixed()
+ for _, ca := range m.certificateAuthorities {
+ caEntry := certificateAuthorities.addU16LengthPrefixed()
+ caEntry.addBytes(ca)
+ }
+
+ if m.hasRequestContext {
+ // Emit no certificate extensions.
+ body.addU16(0)
+ }
+
+ m.raw = builder.finish()
+ return m.raw
+}
+
+func (m *certificateRequestMsg) unmarshal(data []byte) bool {
+ m.raw = data
+
+ if len(data) < 5 {
+ return false
+ }
+ data = data[4:]
+
+ if m.hasRequestContext {
+ contextLen := int(data[0])
+ if len(data) < 1+contextLen {
+ return false
+ }
+ m.requestContext = make([]byte, contextLen)
+ copy(m.requestContext, data[1:])
+ data = data[1+contextLen:]
+ } else {
+ numCertTypes := int(data[0])
+ if len(data) < 1+numCertTypes {
+ return false
+ }
+ m.certificateTypes = make([]byte, numCertTypes)
+ copy(m.certificateTypes, data[1:])
+ data = data[1+numCertTypes:]
+ }
+
+ if m.hasSignatureAlgorithm {
+ if len(data) < 2 {
+ return false
+ }
+ sigAlgsLen := uint16(data[0])<<8 | uint16(data[1])
+ data = data[2:]
+ if sigAlgsLen&1 != 0 {
+ return false
+ }
+ if len(data) < int(sigAlgsLen) {
+ return false
+ }
+ numSigAlgs := sigAlgsLen / 2
+ m.signatureAlgorithms = make([]signatureAlgorithm, numSigAlgs)
+ for i := range m.signatureAlgorithms {
+ m.signatureAlgorithms[i] = signatureAlgorithm(data[0])<<8 | signatureAlgorithm(data[1])
+ data = data[2:]
+ }
+ }
+
+ if len(data) < 2 {
+ return false
+ }
+ casLength := uint16(data[0])<<8 | uint16(data[1])
+ data = data[2:]
+ if len(data) < int(casLength) {
+ return false
+ }
+ cas := make([]byte, casLength)
+ copy(cas, data)
+ data = data[casLength:]
+
+ m.certificateAuthorities = nil
+ for len(cas) > 0 {
+ if len(cas) < 2 {
+ return false
+ }
+ caLen := uint16(cas[0])<<8 | uint16(cas[1])
+ cas = cas[2:]
+
+ if len(cas) < int(caLen) {
+ return false
+ }
+
+ m.certificateAuthorities = append(m.certificateAuthorities, cas[:caLen])
+ cas = cas[caLen:]
+ }
+
+ if m.hasRequestContext {
+ // Ignore certificate extensions.
+ if len(data) < 2 {
+ return false
+ }
+ extsLength := int(data[0])<<8 | int(data[1])
+ if len(data) < 2+extsLength {
+ return false
+ }
+ data = data[2+extsLength:]
+ }
+
+ if len(data) > 0 {
+ return false
+ }
+
+ return true
+}
+
+type certificateVerifyMsg struct {
+ raw []byte
+ hasSignatureAlgorithm bool
+ signatureAlgorithm signatureAlgorithm
+ signature []byte
+}
+
+func (m *certificateVerifyMsg) marshal() (x []byte) {
+ if m.raw != nil {
+ return m.raw
+ }
+
+ // See http://tools.ietf.org/html/rfc4346#section-7.4.8
+ siglength := len(m.signature)
+ length := 2 + siglength
+ if m.hasSignatureAlgorithm {
+ length += 2
+ }
+ x = make([]byte, 4+length)
+ x[0] = typeCertificateVerify
+ x[1] = uint8(length >> 16)
+ x[2] = uint8(length >> 8)
+ x[3] = uint8(length)
+ y := x[4:]
+ if m.hasSignatureAlgorithm {
+ y[0] = byte(m.signatureAlgorithm >> 8)
+ y[1] = byte(m.signatureAlgorithm)
+ y = y[2:]
+ }
+ y[0] = uint8(siglength >> 8)
+ y[1] = uint8(siglength)
+ copy(y[2:], m.signature)
+
+ m.raw = x
+
+ return
+}
+
+func (m *certificateVerifyMsg) unmarshal(data []byte) bool {
+ m.raw = data
+
+ if len(data) < 6 {
+ return false
+ }
+
+ length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
+ if uint32(len(data))-4 != length {
+ return false
+ }
+
+ data = data[4:]
+ if m.hasSignatureAlgorithm {
+ m.signatureAlgorithm = signatureAlgorithm(data[0])<<8 | signatureAlgorithm(data[1])
+ data = data[2:]
+ }
+
+ if len(data) < 2 {
+ return false
+ }
+ siglength := int(data[0])<<8 + int(data[1])
+ data = data[2:]
+ if len(data) != siglength {
+ return false
+ }
+
+ m.signature = data
+
+ return true
+}
+
+type newSessionTicketMsg struct {
+ raw []byte
+ version uint16
+ ticketLifetime uint32
+ ticketAgeAdd uint32
+ ticket []byte
+ maxEarlyDataSize uint32
+ customExtension string
+ duplicateEarlyDataInfo bool
+ hasGREASEExtension bool
+}
+
+func (m *newSessionTicketMsg) marshal() []byte {
+ if m.raw != nil {
+ return m.raw
+ }
+
+ // See http://tools.ietf.org/html/rfc5077#section-3.3
+ ticketMsg := newByteBuilder()
+ ticketMsg.addU8(typeNewSessionTicket)
+ body := ticketMsg.addU24LengthPrefixed()
+ body.addU32(m.ticketLifetime)
+ if m.version >= VersionTLS13 {
+ body.addU32(m.ticketAgeAdd)
+ }
+
+ ticket := body.addU16LengthPrefixed()
+ ticket.addBytes(m.ticket)
+
+ if m.version >= VersionTLS13 {
+ extensions := body.addU16LengthPrefixed()
+ if m.maxEarlyDataSize > 0 {
+ extensions.addU16(extensionTicketEarlyDataInfo)
+ extensions.addU16LengthPrefixed().addU32(m.maxEarlyDataSize)
+ if m.duplicateEarlyDataInfo {
+ extensions.addU16(extensionTicketEarlyDataInfo)
+ extensions.addU16LengthPrefixed().addU32(m.maxEarlyDataSize)
+ }
+ }
+ if len(m.customExtension) > 0 {
+ extensions.addU16(extensionCustom)
+ extensions.addU16LengthPrefixed().addBytes([]byte(m.customExtension))
+ }
+ }
+
+ m.raw = ticketMsg.finish()
+ return m.raw
+}
+
+func (m *newSessionTicketMsg) unmarshal(data []byte) bool {
+ m.raw = data
+
+ if len(data) < 8 {
+ return false
+ }
+ m.ticketLifetime = uint32(data[4])<<24 | uint32(data[5])<<16 | uint32(data[6])<<8 | uint32(data[7])
+ data = data[8:]
+
+ if m.version >= VersionTLS13 {
+ if len(data) < 4 {
+ return false
+ }
+ m.ticketAgeAdd = uint32(data[0])<<24 | uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
+ data = data[4:]
+ }
+
+ if len(data) < 2 {
+ return false
+ }
+ ticketLen := int(data[0])<<8 + int(data[1])
+ data = data[2:]
+ if len(data) < ticketLen {
+ return false
+ }
+
+ if m.version >= VersionTLS13 && ticketLen == 0 {
+ return false
+ }
+
+ m.ticket = data[:ticketLen]
+ data = data[ticketLen:]
+
+ if m.version >= VersionTLS13 {
+ if len(data) < 2 {
+ return false
+ }
+
+ extensionsLength := int(data[0])<<8 | int(data[1])
+ data = data[2:]
+ if extensionsLength != len(data) {
+ return false
+ }
+
+ for len(data) != 0 {
+ if len(data) < 4 {
+ return false
+ }
+ extension := uint16(data[0])<<8 | uint16(data[1])
+ length := int(data[2])<<8 | int(data[3])
+ data = data[4:]
+ if len(data) < length {
+ return false
+ }
+
+ switch extension {
+ case extensionTicketEarlyDataInfo:
+ if length != 4 {
+ return false
+ }
+ m.maxEarlyDataSize = uint32(data[0])<<24 | uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
+ default:
+ if isGREASEValue(extension) {
+ m.hasGREASEExtension = true
+ }
+ }
+
+ data = data[length:]
+ }
+ }
+
+ if len(data) > 0 {
+ return false
+ }
+
+ return true
+}
+
+type v2ClientHelloMsg struct {
+ raw []byte
+ vers uint16
+ cipherSuites []uint16
+ sessionId []byte
+ challenge []byte
+}
+
+func (m *v2ClientHelloMsg) marshal() []byte {
+ if m.raw != nil {
+ return m.raw
+ }
+
+ length := 1 + 2 + 2 + 2 + 2 + len(m.cipherSuites)*3 + len(m.sessionId) + len(m.challenge)
+
+ x := make([]byte, length)
+ x[0] = 1
+ x[1] = uint8(m.vers >> 8)
+ x[2] = uint8(m.vers)
+ x[3] = uint8((len(m.cipherSuites) * 3) >> 8)
+ x[4] = uint8(len(m.cipherSuites) * 3)
+ x[5] = uint8(len(m.sessionId) >> 8)
+ x[6] = uint8(len(m.sessionId))
+ x[7] = uint8(len(m.challenge) >> 8)
+ x[8] = uint8(len(m.challenge))
+ y := x[9:]
+ for i, spec := range m.cipherSuites {
+ y[i*3] = 0
+ y[i*3+1] = uint8(spec >> 8)
+ y[i*3+2] = uint8(spec)
+ }
+ y = y[len(m.cipherSuites)*3:]
+ copy(y, m.sessionId)
+ y = y[len(m.sessionId):]
+ copy(y, m.challenge)
+
+ m.raw = x
+
+ return x
+}
+
+type helloVerifyRequestMsg struct {
+ raw []byte
+ vers uint16
+ cookie []byte
+}
+
+func (m *helloVerifyRequestMsg) marshal() []byte {
+ if m.raw != nil {
+ return m.raw
+ }
+
+ length := 2 + 1 + len(m.cookie)
+
+ x := make([]byte, 4+length)
+ x[0] = typeHelloVerifyRequest
+ x[1] = uint8(length >> 16)
+ x[2] = uint8(length >> 8)
+ x[3] = uint8(length)
+ vers := m.vers
+ x[4] = uint8(vers >> 8)
+ x[5] = uint8(vers)
+ x[6] = uint8(len(m.cookie))
+ copy(x[7:7+len(m.cookie)], m.cookie)
+
+ return x
+}
+
+func (m *helloVerifyRequestMsg) unmarshal(data []byte) bool {
+ if len(data) < 4+2+1 {
+ return false
+ }
+ m.raw = data
+ m.vers = uint16(data[4])<<8 | uint16(data[5])
+ cookieLen := int(data[6])
+ if cookieLen > 32 || len(data) != 7+cookieLen {
+ return false
+ }
+ m.cookie = data[7 : 7+cookieLen]
+
+ return true
+}
+
+type channelIDMsg struct {
+ raw []byte
+ channelID []byte
+}
+
+func (m *channelIDMsg) marshal() []byte {
+ if m.raw != nil {
+ return m.raw
+ }
+
+ length := 2 + 2 + len(m.channelID)
+
+ x := make([]byte, 4+length)
+ x[0] = typeChannelID
+ x[1] = uint8(length >> 16)
+ x[2] = uint8(length >> 8)
+ x[3] = uint8(length)
+ x[4] = uint8(extensionChannelID >> 8)
+ x[5] = uint8(extensionChannelID & 0xff)
+ x[6] = uint8(len(m.channelID) >> 8)
+ x[7] = uint8(len(m.channelID) & 0xff)
+ copy(x[8:], m.channelID)
+
+ return x
+}
+
+func (m *channelIDMsg) unmarshal(data []byte) bool {
+ if len(data) != 4+2+2+128 {
+ return false
+ }
+ m.raw = data
+ if (uint16(data[4])<<8)|uint16(data[5]) != extensionChannelID {
+ return false
+ }
+ if int(data[6])<<8|int(data[7]) != 128 {
+ return false
+ }
+ m.channelID = data[4+2+2:]
+
+ return true
+}
+
+type helloRequestMsg struct {
+}
+
+func (*helloRequestMsg) marshal() []byte {
+ return []byte{typeHelloRequest, 0, 0, 0}
+}
+
+func (*helloRequestMsg) unmarshal(data []byte) bool {
+ return len(data) == 4
+}
+
+type keyUpdateMsg struct {
+ raw []byte
+ keyUpdateRequest byte
+}
+
+func (m *keyUpdateMsg) marshal() []byte {
+ if m.raw != nil {
+ return m.raw
+ }
+
+ return []byte{typeKeyUpdate, 0, 0, 1, m.keyUpdateRequest}
+}
+
+func (m *keyUpdateMsg) unmarshal(data []byte) bool {
+ m.raw = data
+
+ if len(data) != 5 {
+ return false
+ }
+
+ length := int(data[1])<<16 | int(data[2])<<8 | int(data[3])
+ if len(data)-4 != length {
+ return false
+ }
+
+ m.keyUpdateRequest = data[4]
+ return m.keyUpdateRequest == keyUpdateNotRequested || m.keyUpdateRequest == keyUpdateRequested
+}
+
+// ssl3NoCertificateMsg is a dummy message to handle SSL 3.0 using a warning
+// alert in the handshake.
+type ssl3NoCertificateMsg struct{}
+
+func eqUint16s(x, y []uint16) bool {
+ if len(x) != len(y) {
+ return false
+ }
+ for i, v := range x {
+ if y[i] != v {
+ return false
+ }
+ }
+ return true
+}
+
+func eqCurveIDs(x, y []CurveID) bool {
+ if len(x) != len(y) {
+ return false
+ }
+ for i, v := range x {
+ if y[i] != v {
+ return false
+ }
+ }
+ return true
+}
+
+func eqStrings(x, y []string) bool {
+ if len(x) != len(y) {
+ return false
+ }
+ for i, v := range x {
+ if y[i] != v {
+ return false
+ }
+ }
+ return true
+}
+
+func eqByteSlices(x, y [][]byte) bool {
+ if len(x) != len(y) {
+ return false
+ }
+ for i, v := range x {
+ if !bytes.Equal(v, y[i]) {
+ return false
+ }
+ }
+ return true
+}
+
+func eqSignatureAlgorithms(x, y []signatureAlgorithm) bool {
+ if len(x) != len(y) {
+ return false
+ }
+ for i, v := range x {
+ v2 := y[i]
+ if v != v2 {
+ return false
+ }
+ }
+ return true
+}
+
+func eqKeyShareEntryLists(x, y []keyShareEntry) bool {
+ if len(x) != len(y) {
+ return false
+ }
+ for i, v := range x {
+ if y[i].group != v.group || !bytes.Equal(y[i].keyExchange, v.keyExchange) {
+ return false
+ }
+ }
+ return true
+
+}
+
+func eqPSKIdentityLists(x, y []pskIdentity) bool {
+ if len(x) != len(y) {
+ return false
+ }
+ for i, v := range x {
+ if !bytes.Equal(y[i].ticket, v.ticket) || y[i].obfuscatedTicketAge != v.obfuscatedTicketAge {
+ return false
+ }
+ }
+ return true
+
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/handshake_server.go b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/handshake_server.go
new file mode 100644
index 000000000..64edd0163
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/handshake_server.go
@@ -0,0 +1,1975 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runner
+
+import (
+ "bytes"
+ "crypto"
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "crypto/rsa"
+ "crypto/subtle"
+ "crypto/x509"
+ "errors"
+ "fmt"
+ "io"
+ "math/big"
+ "time"
+)
+
+// serverHandshakeState contains details of a server handshake in progress.
+// It's discarded once the handshake has completed.
+type serverHandshakeState struct {
+ c *Conn
+ clientHello *clientHelloMsg
+ hello *serverHelloMsg
+ suite *cipherSuite
+ ellipticOk bool
+ ecdsaOk bool
+ sessionState *sessionState
+ finishedHash finishedHash
+ masterSecret []byte
+ certsFromClient [][]byte
+ cert *Certificate
+ finishedBytes []byte
+}
+
+// serverHandshake performs a TLS handshake as a server.
+func (c *Conn) serverHandshake() error {
+ config := c.config
+
+ // If this is the first server handshake, we generate a random key to
+ // encrypt the tickets with.
+ config.serverInitOnce.Do(config.serverInit)
+
+ c.sendHandshakeSeq = 0
+ c.recvHandshakeSeq = 0
+
+ hs := serverHandshakeState{
+ c: c,
+ }
+ if err := hs.readClientHello(); err != nil {
+ return err
+ }
+
+ if c.vers >= VersionTLS13 {
+ if err := hs.doTLS13Handshake(); err != nil {
+ return err
+ }
+ } else {
+ isResume, err := hs.processClientHello()
+ if err != nil {
+ return err
+ }
+
+ // For an overview of TLS handshaking, see https://tools.ietf.org/html/rfc5246#section-7.3
+ if isResume {
+ // The client has included a session ticket and so we do an abbreviated handshake.
+ if err := hs.doResumeHandshake(); err != nil {
+ return err
+ }
+ if err := hs.establishKeys(); err != nil {
+ return err
+ }
+ if c.config.Bugs.RenewTicketOnResume {
+ if err := hs.sendSessionTicket(); err != nil {
+ return err
+ }
+ }
+ if err := hs.sendFinished(c.firstFinished[:]); err != nil {
+ return err
+ }
+ // Most retransmits are triggered by a timeout, but the final
+ // leg of the handshake is retransmited upon re-receiving a
+ // Finished.
+ if err := c.simulatePacketLoss(func() {
+ c.sendHandshakeSeq--
+ c.writeRecord(recordTypeHandshake, hs.finishedBytes)
+ c.flushHandshake()
+ }); err != nil {
+ return err
+ }
+ if err := hs.readFinished(nil, isResume); err != nil {
+ return err
+ }
+ c.didResume = true
+ } else {
+ // The client didn't include a session ticket, or it wasn't
+ // valid so we do a full handshake.
+ if err := hs.doFullHandshake(); err != nil {
+ return err
+ }
+ if err := hs.establishKeys(); err != nil {
+ return err
+ }
+ if err := hs.readFinished(c.firstFinished[:], isResume); err != nil {
+ return err
+ }
+ if c.config.Bugs.AlertBeforeFalseStartTest != 0 {
+ c.sendAlert(c.config.Bugs.AlertBeforeFalseStartTest)
+ }
+ if c.config.Bugs.ExpectFalseStart {
+ if err := c.readRecord(recordTypeApplicationData); err != nil {
+ return fmt.Errorf("tls: peer did not false start: %s", err)
+ }
+ }
+ if err := hs.sendSessionTicket(); err != nil {
+ return err
+ }
+ if err := hs.sendFinished(nil); err != nil {
+ return err
+ }
+ }
+
+ c.exporterSecret = hs.masterSecret
+ }
+ c.handshakeComplete = true
+ copy(c.clientRandom[:], hs.clientHello.random)
+ copy(c.serverRandom[:], hs.hello.random)
+
+ return nil
+}
+
+// readClientHello reads a ClientHello message from the client and determines
+// the protocol version.
+func (hs *serverHandshakeState) readClientHello() error {
+ config := hs.c.config
+ c := hs.c
+
+ if err := c.simulatePacketLoss(nil); err != nil {
+ return err
+ }
+ msg, err := c.readHandshake()
+ if err != nil {
+ return err
+ }
+ var ok bool
+ hs.clientHello, ok = msg.(*clientHelloMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(hs.clientHello, msg)
+ }
+ if size := config.Bugs.RequireClientHelloSize; size != 0 && len(hs.clientHello.raw) != size {
+ return fmt.Errorf("tls: ClientHello record size is %d, but expected %d", len(hs.clientHello.raw), size)
+ }
+
+ if c.isDTLS && !config.Bugs.SkipHelloVerifyRequest {
+ // Per RFC 6347, the version field in HelloVerifyRequest SHOULD
+ // be always DTLS 1.0
+ helloVerifyRequest := &helloVerifyRequestMsg{
+ vers: versionToWire(VersionTLS10, c.isDTLS),
+ cookie: make([]byte, 32),
+ }
+ if _, err := io.ReadFull(c.config.rand(), helloVerifyRequest.cookie); err != nil {
+ c.sendAlert(alertInternalError)
+ return errors.New("dtls: short read from Rand: " + err.Error())
+ }
+ c.writeRecord(recordTypeHandshake, helloVerifyRequest.marshal())
+ c.flushHandshake()
+
+ if err := c.simulatePacketLoss(nil); err != nil {
+ return err
+ }
+ msg, err := c.readHandshake()
+ if err != nil {
+ return err
+ }
+ newClientHello, ok := msg.(*clientHelloMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(hs.clientHello, msg)
+ }
+ if !bytes.Equal(newClientHello.cookie, helloVerifyRequest.cookie) {
+ return errors.New("dtls: invalid cookie")
+ }
+
+ // Apart from the cookie, the two ClientHellos must
+ // match. Note that clientHello.equal compares the
+ // serialization, so we make a copy.
+ oldClientHelloCopy := *hs.clientHello
+ oldClientHelloCopy.raw = nil
+ oldClientHelloCopy.cookie = nil
+ newClientHelloCopy := *newClientHello
+ newClientHelloCopy.raw = nil
+ newClientHelloCopy.cookie = nil
+ if !oldClientHelloCopy.equal(&newClientHelloCopy) {
+ return errors.New("dtls: retransmitted ClientHello does not match")
+ }
+ hs.clientHello = newClientHello
+ }
+
+ if config.Bugs.RequireSameRenegoClientVersion && c.clientVersion != 0 {
+ if c.clientVersion != hs.clientHello.vers {
+ return fmt.Errorf("tls: client offered different version on renego")
+ }
+ }
+
+ c.clientVersion = hs.clientHello.vers
+
+ // Convert the ClientHello wire version to a protocol version.
+ var clientVersion uint16
+ if c.isDTLS {
+ if hs.clientHello.vers <= 0xfefd {
+ clientVersion = VersionTLS12
+ } else if hs.clientHello.vers <= 0xfeff {
+ clientVersion = VersionTLS10
+ }
+ } else {
+ if hs.clientHello.vers >= VersionTLS12 {
+ clientVersion = VersionTLS12
+ } else if hs.clientHello.vers >= VersionTLS11 {
+ clientVersion = VersionTLS11
+ } else if hs.clientHello.vers >= VersionTLS10 {
+ clientVersion = VersionTLS10
+ } else if hs.clientHello.vers >= VersionSSL30 {
+ clientVersion = VersionSSL30
+ }
+ }
+
+ if config.Bugs.NegotiateVersion != 0 {
+ c.vers = config.Bugs.NegotiateVersion
+ } else if c.haveVers && config.Bugs.NegotiateVersionOnRenego != 0 {
+ c.vers = config.Bugs.NegotiateVersionOnRenego
+ } else if len(hs.clientHello.supportedVersions) > 0 {
+ // Use the versions extension if supplied.
+ var foundVersion, foundGREASE bool
+ for _, extVersion := range hs.clientHello.supportedVersions {
+ if isGREASEValue(extVersion) {
+ foundGREASE = true
+ }
+ extVersion, ok = wireToVersion(extVersion, c.isDTLS)
+ if !ok {
+ continue
+ }
+ if config.isSupportedVersion(extVersion, c.isDTLS) && !foundVersion {
+ c.vers = extVersion
+ foundVersion = true
+ break
+ }
+ }
+ if !foundVersion {
+ c.sendAlert(alertProtocolVersion)
+ return errors.New("tls: client did not offer any supported protocol versions")
+ }
+ if config.Bugs.ExpectGREASE && !foundGREASE {
+ return errors.New("tls: no GREASE version value found")
+ }
+ } else {
+ // Otherwise, use the legacy ClientHello version.
+ version := clientVersion
+ if maxVersion := config.maxVersion(c.isDTLS); version > maxVersion {
+ version = maxVersion
+ }
+ if version == 0 || !config.isSupportedVersion(version, c.isDTLS) {
+ return fmt.Errorf("tls: client offered an unsupported, maximum protocol version of %x", hs.clientHello.vers)
+ }
+ c.vers = version
+ }
+ c.haveVers = true
+
+ // Reject < 1.2 ClientHellos with signature_algorithms.
+ if clientVersion < VersionTLS12 && len(hs.clientHello.signatureAlgorithms) > 0 {
+ return fmt.Errorf("tls: client included signature_algorithms before TLS 1.2")
+ }
+
+ // Check the client cipher list is consistent with the version.
+ if clientVersion < VersionTLS12 {
+ for _, id := range hs.clientHello.cipherSuites {
+ if isTLS12Cipher(id) {
+ return fmt.Errorf("tls: client offered TLS 1.2 cipher before TLS 1.2")
+ }
+ }
+ }
+
+ if config.Bugs.ExpectNoTLS12Session {
+ if len(hs.clientHello.sessionId) > 0 {
+ return fmt.Errorf("tls: client offered an unexpected session ID")
+ }
+ if len(hs.clientHello.sessionTicket) > 0 {
+ return fmt.Errorf("tls: client offered an unexpected session ticket")
+ }
+ }
+
+ if config.Bugs.ExpectNoTLS13PSK && len(hs.clientHello.pskIdentities) > 0 {
+ return fmt.Errorf("tls: client offered unexpected PSK identities")
+ }
+
+ var scsvFound, greaseFound bool
+ for _, cipherSuite := range hs.clientHello.cipherSuites {
+ if cipherSuite == fallbackSCSV {
+ scsvFound = true
+ }
+ if isGREASEValue(cipherSuite) {
+ greaseFound = true
+ }
+ }
+
+ if !scsvFound && config.Bugs.FailIfNotFallbackSCSV {
+ return errors.New("tls: no fallback SCSV found when expected")
+ } else if scsvFound && !config.Bugs.FailIfNotFallbackSCSV {
+ return errors.New("tls: fallback SCSV found when not expected")
+ }
+
+ if !greaseFound && config.Bugs.ExpectGREASE {
+ return errors.New("tls: no GREASE cipher suite value found")
+ }
+
+ greaseFound = false
+ for _, curve := range hs.clientHello.supportedCurves {
+ if isGREASEValue(uint16(curve)) {
+ greaseFound = true
+ break
+ }
+ }
+
+ if !greaseFound && config.Bugs.ExpectGREASE {
+ return errors.New("tls: no GREASE curve value found")
+ }
+
+ if len(hs.clientHello.keyShares) > 0 {
+ greaseFound = false
+ for _, keyShare := range hs.clientHello.keyShares {
+ if isGREASEValue(uint16(keyShare.group)) {
+ greaseFound = true
+ break
+ }
+ }
+
+ if !greaseFound && config.Bugs.ExpectGREASE {
+ return errors.New("tls: no GREASE curve value found")
+ }
+ }
+
+ applyBugsToClientHello(hs.clientHello, config)
+
+ return nil
+}
+
+func applyBugsToClientHello(clientHello *clientHelloMsg, config *Config) {
+ if config.Bugs.IgnorePeerSignatureAlgorithmPreferences {
+ clientHello.signatureAlgorithms = config.signSignatureAlgorithms()
+ }
+ if config.Bugs.IgnorePeerCurvePreferences {
+ clientHello.supportedCurves = config.curvePreferences()
+ }
+ if config.Bugs.IgnorePeerCipherPreferences {
+ clientHello.cipherSuites = config.cipherSuites()
+ }
+}
+
+func (hs *serverHandshakeState) doTLS13Handshake() error {
+ c := hs.c
+ config := c.config
+
+ hs.hello = &serverHelloMsg{
+ isDTLS: c.isDTLS,
+ vers: versionToWire(c.vers, c.isDTLS),
+ versOverride: config.Bugs.SendServerHelloVersion,
+ customExtension: config.Bugs.CustomUnencryptedExtension,
+ unencryptedALPN: config.Bugs.SendUnencryptedALPN,
+ }
+
+ hs.hello.random = make([]byte, 32)
+ if _, err := io.ReadFull(config.rand(), hs.hello.random); err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
+
+ // TLS 1.3 forbids clients from advertising any non-null compression.
+ if len(hs.clientHello.compressionMethods) != 1 || hs.clientHello.compressionMethods[0] != compressionNone {
+ return errors.New("tls: client sent compression method other than null for TLS 1.3")
+ }
+
+ // Prepare an EncryptedExtensions message, but do not send it yet.
+ encryptedExtensions := new(encryptedExtensionsMsg)
+ encryptedExtensions.empty = config.Bugs.EmptyEncryptedExtensions
+ if err := hs.processClientExtensions(&encryptedExtensions.extensions); err != nil {
+ return err
+ }
+
+ // Select the cipher suite.
+ var preferenceList, supportedList []uint16
+ if config.PreferServerCipherSuites {
+ preferenceList = config.cipherSuites()
+ supportedList = hs.clientHello.cipherSuites
+ } else {
+ preferenceList = hs.clientHello.cipherSuites
+ supportedList = config.cipherSuites()
+ }
+
+ for _, id := range preferenceList {
+ if hs.suite = c.tryCipherSuite(id, supportedList, c.vers, true, true); hs.suite != nil {
+ break
+ }
+ }
+
+ if hs.suite == nil {
+ c.sendAlert(alertHandshakeFailure)
+ return errors.New("tls: no cipher suite supported by both client and server")
+ }
+
+ hs.hello.cipherSuite = hs.suite.id
+ if c.config.Bugs.SendCipherSuite != 0 {
+ hs.hello.cipherSuite = c.config.Bugs.SendCipherSuite
+ }
+
+ hs.finishedHash = newFinishedHash(c.vers, hs.suite)
+ hs.finishedHash.discardHandshakeBuffer()
+ hs.writeClientHash(hs.clientHello.marshal())
+
+ supportedCurve := false
+ var selectedCurve CurveID
+ preferredCurves := config.curvePreferences()
+Curves:
+ for _, curve := range hs.clientHello.supportedCurves {
+ for _, supported := range preferredCurves {
+ if supported == curve {
+ supportedCurve = true
+ selectedCurve = curve
+ break Curves
+ }
+ }
+ }
+
+ if !supportedCurve {
+ c.sendAlert(alertHandshakeFailure)
+ return errors.New("tls: no curve supported by both client and server")
+ }
+
+ pskIdentities := hs.clientHello.pskIdentities
+ pskKEModes := hs.clientHello.pskKEModes
+
+ if len(pskIdentities) == 0 && len(hs.clientHello.sessionTicket) > 0 && c.config.Bugs.AcceptAnySession {
+ psk := pskIdentity{
+ ticket: hs.clientHello.sessionTicket,
+ }
+ pskIdentities = []pskIdentity{psk}
+ pskKEModes = []byte{pskDHEKEMode}
+ }
+
+ var pskIndex int
+ foundKEMode := bytes.IndexByte(pskKEModes, pskDHEKEMode) >= 0
+ if foundKEMode {
+ for i, pskIdentity := range pskIdentities {
+ // TODO(svaldez): Check the obfuscatedTicketAge before accepting 0-RTT.
+ sessionState, ok := c.decryptTicket(pskIdentity.ticket)
+ if !ok {
+ continue
+ }
+
+ if !config.Bugs.AcceptAnySession {
+ if sessionState.vers != c.vers {
+ continue
+ }
+ if sessionState.ticketExpiration.Before(c.config.time()) {
+ continue
+ }
+ sessionCipher := cipherSuiteFromID(sessionState.cipherSuite)
+ if sessionCipher == nil || sessionCipher.hash() != hs.suite.hash() {
+ continue
+ }
+ }
+
+ clientTicketAge := time.Duration(uint32(pskIdentity.obfuscatedTicketAge-sessionState.ticketAgeAdd)) * time.Millisecond
+ if config.Bugs.ExpectTicketAge != 0 && clientTicketAge != config.Bugs.ExpectTicketAge {
+ c.sendAlert(alertHandshakeFailure)
+ return errors.New("tls: invalid ticket age")
+ }
+
+ hs.sessionState = sessionState
+ hs.hello.hasPSKIdentity = true
+ hs.hello.pskIdentity = uint16(i)
+ pskIndex = i
+ if config.Bugs.SelectPSKIdentityOnResume != 0 {
+ hs.hello.pskIdentity = config.Bugs.SelectPSKIdentityOnResume
+ }
+ c.didResume = true
+ break
+ }
+ }
+
+ if config.Bugs.AlwaysSelectPSKIdentity {
+ hs.hello.hasPSKIdentity = true
+ hs.hello.pskIdentity = 0
+ }
+
+ // Verify the PSK binder. Note there may not be a PSK binder if
+ // AcceptAnyBinder is set. See https://crbug.com/boringssl/115.
+ if hs.sessionState != nil && !config.Bugs.AcceptAnySession {
+ binderToVerify := hs.clientHello.pskBinders[pskIndex]
+ if err := verifyPSKBinder(hs.clientHello, hs.sessionState, binderToVerify, []byte{}); err != nil {
+ return err
+ }
+ }
+
+ // Resolve PSK and compute the early secret.
+ if hs.sessionState != nil {
+ hs.finishedHash.addEntropy(hs.sessionState.masterSecret)
+ } else {
+ hs.finishedHash.addEntropy(hs.finishedHash.zeroSecret())
+ }
+
+ hs.hello.hasKeyShare = true
+ if hs.sessionState != nil && config.Bugs.NegotiatePSKResumption {
+ hs.hello.hasKeyShare = false
+ }
+ if config.Bugs.MissingKeyShare {
+ hs.hello.hasKeyShare = false
+ }
+
+ firstHelloRetryRequest := true
+
+ResendHelloRetryRequest:
+ var sendHelloRetryRequest bool
+ helloRetryRequest := &helloRetryRequestMsg{
+ vers: versionToWire(c.vers, c.isDTLS),
+ duplicateExtensions: config.Bugs.DuplicateHelloRetryRequestExtensions,
+ }
+
+ if config.Bugs.AlwaysSendHelloRetryRequest {
+ sendHelloRetryRequest = true
+ }
+
+ if config.Bugs.SendHelloRetryRequestCookie != nil {
+ sendHelloRetryRequest = true
+ helloRetryRequest.cookie = config.Bugs.SendHelloRetryRequestCookie
+ }
+
+ if len(config.Bugs.CustomHelloRetryRequestExtension) > 0 {
+ sendHelloRetryRequest = true
+ helloRetryRequest.customExtension = config.Bugs.CustomHelloRetryRequestExtension
+ }
+
+ var selectedKeyShare *keyShareEntry
+ if hs.hello.hasKeyShare {
+ // Look for the key share corresponding to our selected curve.
+ for i := range hs.clientHello.keyShares {
+ if hs.clientHello.keyShares[i].group == selectedCurve {
+ selectedKeyShare = &hs.clientHello.keyShares[i]
+ break
+ }
+ }
+
+ if config.Bugs.ExpectMissingKeyShare && selectedKeyShare != nil {
+ return errors.New("tls: expected missing key share")
+ }
+
+ if selectedKeyShare == nil {
+ helloRetryRequest.hasSelectedGroup = true
+ helloRetryRequest.selectedGroup = selectedCurve
+ sendHelloRetryRequest = true
+ }
+ }
+
+ if config.Bugs.SendHelloRetryRequestCurve != 0 {
+ helloRetryRequest.hasSelectedGroup = true
+ helloRetryRequest.selectedGroup = config.Bugs.SendHelloRetryRequestCurve
+ sendHelloRetryRequest = true
+ }
+
+ if config.Bugs.SkipHelloRetryRequest {
+ sendHelloRetryRequest = false
+ }
+
+ if sendHelloRetryRequest {
+ oldClientHelloBytes := hs.clientHello.marshal()
+ hs.writeServerHash(helloRetryRequest.marshal())
+ c.writeRecord(recordTypeHandshake, helloRetryRequest.marshal())
+ c.flushHandshake()
+
+ // Read new ClientHello.
+ newMsg, err := c.readHandshake()
+ if err != nil {
+ return err
+ }
+ newClientHello, ok := newMsg.(*clientHelloMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(newClientHello, newMsg)
+ }
+ hs.writeClientHash(newClientHello.marshal())
+
+ applyBugsToClientHello(newClientHello, config)
+
+ // Check that the new ClientHello matches the old ClientHello,
+ // except for relevant modifications.
+ //
+ // TODO(davidben): Make this check more precise.
+ oldClientHelloCopy := *hs.clientHello
+ oldClientHelloCopy.raw = nil
+ oldClientHelloCopy.hasEarlyData = false
+ newClientHelloCopy := *newClientHello
+ newClientHelloCopy.raw = nil
+
+ if helloRetryRequest.hasSelectedGroup {
+ newKeyShares := newClientHelloCopy.keyShares
+ if len(newKeyShares) != 1 || newKeyShares[0].group != helloRetryRequest.selectedGroup {
+ return errors.New("tls: KeyShare from HelloRetryRequest not in new ClientHello")
+ }
+ selectedKeyShare = &newKeyShares[0]
+ newClientHelloCopy.keyShares = oldClientHelloCopy.keyShares
+ }
+
+ if len(helloRetryRequest.cookie) > 0 {
+ if !bytes.Equal(newClientHelloCopy.tls13Cookie, helloRetryRequest.cookie) {
+ return errors.New("tls: cookie from HelloRetryRequest not present in new ClientHello")
+ }
+ newClientHelloCopy.tls13Cookie = nil
+ }
+
+ // PSK binders and obfuscated ticket age are both updated in the
+ // second ClientHello.
+ if len(oldClientHelloCopy.pskIdentities) != len(newClientHelloCopy.pskIdentities) {
+ return errors.New("tls: PSK identity count from old and new ClientHello do not match")
+ }
+ for i, identity := range oldClientHelloCopy.pskIdentities {
+ newClientHelloCopy.pskIdentities[i].obfuscatedTicketAge = identity.obfuscatedTicketAge
+ }
+ newClientHelloCopy.pskBinders = oldClientHelloCopy.pskBinders
+
+ if !oldClientHelloCopy.equal(&newClientHelloCopy) {
+ return errors.New("tls: new ClientHello does not match")
+ }
+
+ if firstHelloRetryRequest && config.Bugs.SecondHelloRetryRequest {
+ firstHelloRetryRequest = false
+ goto ResendHelloRetryRequest
+ }
+
+ // Verify the PSK binder. Note there may not be a PSK binder if
+ // AcceptAnyBinder is set. See https://crbug.com/115.
+ if hs.sessionState != nil && !config.Bugs.AcceptAnySession {
+ binderToVerify := newClientHello.pskBinders[pskIndex]
+ err := verifyPSKBinder(newClientHello, hs.sessionState, binderToVerify, append(oldClientHelloBytes, helloRetryRequest.marshal()...))
+ if err != nil {
+ return err
+ }
+ }
+ }
+
+ // Decide whether or not to accept early data.
+ // TODO(nharper): This does not check that ALPN or SNI matches.
+ if hs.clientHello.hasEarlyData {
+ if !sendHelloRetryRequest && hs.sessionState != nil {
+ encryptedExtensions.extensions.hasEarlyData = true
+ earlyTrafficSecret := hs.finishedHash.deriveSecret(earlyTrafficLabel)
+ c.in.useTrafficSecret(c.vers, hs.suite, earlyTrafficSecret, clientWrite)
+
+ for _, expectedMsg := range config.Bugs.ExpectEarlyData {
+ if err := c.readRecord(recordTypeApplicationData); err != nil {
+ return err
+ }
+ if !bytes.Equal(c.input.data[c.input.off:], expectedMsg) {
+ return errors.New("ExpectEarlyData: did not get expected message")
+ }
+ c.in.freeBlock(c.input)
+ c.input = nil
+
+ }
+ } else {
+ c.skipEarlyData = true
+ }
+ }
+
+ // Resolve ECDHE and compute the handshake secret.
+ if hs.hello.hasKeyShare {
+ // Once a curve has been selected and a key share identified,
+ // the server needs to generate a public value and send it in
+ // the ServerHello.
+ curve, ok := curveForCurveID(selectedCurve)
+ if !ok {
+ panic("tls: server failed to look up curve ID")
+ }
+ c.curveID = selectedCurve
+
+ var peerKey []byte
+ if config.Bugs.SkipHelloRetryRequest {
+ // If skipping HelloRetryRequest, use a random key to
+ // avoid crashing.
+ curve2, _ := curveForCurveID(selectedCurve)
+ var err error
+ peerKey, err = curve2.offer(config.rand())
+ if err != nil {
+ return err
+ }
+ } else {
+ peerKey = selectedKeyShare.keyExchange
+ }
+
+ publicKey, ecdheSecret, err := curve.accept(config.rand(), peerKey)
+ if err != nil {
+ c.sendAlert(alertHandshakeFailure)
+ return err
+ }
+ hs.finishedHash.addEntropy(ecdheSecret)
+ hs.hello.hasKeyShare = true
+
+ curveID := selectedCurve
+ if c.config.Bugs.SendCurve != 0 {
+ curveID = config.Bugs.SendCurve
+ }
+ if c.config.Bugs.InvalidECDHPoint {
+ publicKey[0] ^= 0xff
+ }
+
+ hs.hello.keyShare = keyShareEntry{
+ group: curveID,
+ keyExchange: publicKey,
+ }
+
+ if config.Bugs.EncryptedExtensionsWithKeyShare {
+ encryptedExtensions.extensions.hasKeyShare = true
+ encryptedExtensions.extensions.keyShare = keyShareEntry{
+ group: curveID,
+ keyExchange: publicKey,
+ }
+ }
+ } else {
+ hs.finishedHash.addEntropy(hs.finishedHash.zeroSecret())
+ }
+
+ // Send unencrypted ServerHello.
+ hs.writeServerHash(hs.hello.marshal())
+ if config.Bugs.PartialEncryptedExtensionsWithServerHello {
+ helloBytes := hs.hello.marshal()
+ toWrite := make([]byte, 0, len(helloBytes)+1)
+ toWrite = append(toWrite, helloBytes...)
+ toWrite = append(toWrite, typeEncryptedExtensions)
+ c.writeRecord(recordTypeHandshake, toWrite)
+ } else {
+ c.writeRecord(recordTypeHandshake, hs.hello.marshal())
+ }
+ c.flushHandshake()
+
+ // Switch to handshake traffic keys.
+ serverHandshakeTrafficSecret := hs.finishedHash.deriveSecret(serverHandshakeTrafficLabel)
+ c.out.useTrafficSecret(c.vers, hs.suite, serverHandshakeTrafficSecret, serverWrite)
+ // Derive handshake traffic read key, but don't switch yet.
+ clientHandshakeTrafficSecret := hs.finishedHash.deriveSecret(clientHandshakeTrafficLabel)
+
+ // Send EncryptedExtensions.
+ hs.writeServerHash(encryptedExtensions.marshal())
+ if config.Bugs.PartialEncryptedExtensionsWithServerHello {
+ // The first byte has already been sent.
+ c.writeRecord(recordTypeHandshake, encryptedExtensions.marshal()[1:])
+ } else {
+ c.writeRecord(recordTypeHandshake, encryptedExtensions.marshal())
+ }
+
+ if hs.sessionState == nil {
+ if config.ClientAuth >= RequestClientCert {
+ // Request a client certificate
+ certReq := &certificateRequestMsg{
+ hasSignatureAlgorithm: true,
+ hasRequestContext: true,
+ requestContext: config.Bugs.SendRequestContext,
+ }
+ if !config.Bugs.NoSignatureAlgorithms {
+ certReq.signatureAlgorithms = config.verifySignatureAlgorithms()
+ }
+
+ // An empty list of certificateAuthorities signals to
+ // the client that it may send any certificate in response
+ // to our request. When we know the CAs we trust, then
+ // we can send them down, so that the client can choose
+ // an appropriate certificate to give to us.
+ if config.ClientCAs != nil {
+ certReq.certificateAuthorities = config.ClientCAs.Subjects()
+ }
+ hs.writeServerHash(certReq.marshal())
+ c.writeRecord(recordTypeHandshake, certReq.marshal())
+ }
+
+ certMsg := &certificateMsg{
+ hasRequestContext: true,
+ }
+ if !config.Bugs.EmptyCertificateList {
+ for i, certData := range hs.cert.Certificate {
+ cert := certificateEntry{
+ data: certData,
+ }
+ if i == 0 {
+ if hs.clientHello.ocspStapling {
+ cert.ocspResponse = hs.cert.OCSPStaple
+ }
+ if hs.clientHello.sctListSupported {
+ cert.sctList = hs.cert.SignedCertificateTimestampList
+ }
+ cert.duplicateExtensions = config.Bugs.SendDuplicateCertExtensions
+ cert.extraExtension = config.Bugs.SendExtensionOnCertificate
+ } else {
+ if config.Bugs.SendOCSPOnIntermediates != nil {
+ cert.ocspResponse = config.Bugs.SendOCSPOnIntermediates
+ }
+ if config.Bugs.SendSCTOnIntermediates != nil {
+ cert.sctList = config.Bugs.SendSCTOnIntermediates
+ }
+ }
+ certMsg.certificates = append(certMsg.certificates, cert)
+ }
+ }
+ certMsgBytes := certMsg.marshal()
+ hs.writeServerHash(certMsgBytes)
+ c.writeRecord(recordTypeHandshake, certMsgBytes)
+
+ certVerify := &certificateVerifyMsg{
+ hasSignatureAlgorithm: true,
+ }
+
+ // Determine the hash to sign.
+ privKey := hs.cert.PrivateKey
+
+ var err error
+ certVerify.signatureAlgorithm, err = selectSignatureAlgorithm(c.vers, privKey, config, hs.clientHello.signatureAlgorithms)
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
+
+ input := hs.finishedHash.certificateVerifyInput(serverCertificateVerifyContextTLS13)
+ certVerify.signature, err = signMessage(c.vers, privKey, c.config, certVerify.signatureAlgorithm, input)
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
+
+ if config.Bugs.SendSignatureAlgorithm != 0 {
+ certVerify.signatureAlgorithm = config.Bugs.SendSignatureAlgorithm
+ }
+
+ hs.writeServerHash(certVerify.marshal())
+ c.writeRecord(recordTypeHandshake, certVerify.marshal())
+ } else if hs.sessionState != nil {
+ // Pick up certificates from the session instead.
+ if len(hs.sessionState.certificates) > 0 {
+ if _, err := hs.processCertsFromClient(hs.sessionState.certificates); err != nil {
+ return err
+ }
+ }
+ }
+
+ finished := new(finishedMsg)
+ finished.verifyData = hs.finishedHash.serverSum(serverHandshakeTrafficSecret)
+ if config.Bugs.BadFinished {
+ finished.verifyData[0]++
+ }
+ hs.writeServerHash(finished.marshal())
+ c.writeRecord(recordTypeHandshake, finished.marshal())
+ if c.config.Bugs.SendExtraFinished {
+ c.writeRecord(recordTypeHandshake, finished.marshal())
+ }
+ c.flushHandshake()
+
+ // The various secrets do not incorporate the client's final leg, so
+ // derive them now before updating the handshake context.
+ hs.finishedHash.addEntropy(hs.finishedHash.zeroSecret())
+ clientTrafficSecret := hs.finishedHash.deriveSecret(clientApplicationTrafficLabel)
+ serverTrafficSecret := hs.finishedHash.deriveSecret(serverApplicationTrafficLabel)
+ c.exporterSecret = hs.finishedHash.deriveSecret(exporterLabel)
+
+ // Switch to application data keys on write. In particular, any alerts
+ // from the client certificate are sent over these keys.
+ c.out.useTrafficSecret(c.vers, hs.suite, serverTrafficSecret, serverWrite)
+
+ // Send 0.5-RTT messages.
+ for _, halfRTTMsg := range config.Bugs.SendHalfRTTData {
+ if _, err := c.writeRecord(recordTypeApplicationData, halfRTTMsg); err != nil {
+ return err
+ }
+ }
+
+ // Read end_of_early_data alert.
+ if encryptedExtensions.extensions.hasEarlyData {
+ if err := c.readRecord(recordTypeAlert); err != errEndOfEarlyDataAlert {
+ if err == nil {
+ panic("readRecord(recordTypeAlert) returned nil")
+ }
+ return err
+ }
+ }
+
+ // Switch input stream to handshake traffic keys.
+ c.in.useTrafficSecret(c.vers, hs.suite, clientHandshakeTrafficSecret, clientWrite)
+
+ // If we requested a client certificate, then the client must send a
+ // certificate message, even if it's empty.
+ if config.ClientAuth >= RequestClientCert {
+ msg, err := c.readHandshake()
+ if err != nil {
+ return err
+ }
+
+ certMsg, ok := msg.(*certificateMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(certMsg, msg)
+ }
+ hs.writeClientHash(certMsg.marshal())
+
+ if len(certMsg.certificates) == 0 {
+ // The client didn't actually send a certificate
+ switch config.ClientAuth {
+ case RequireAnyClientCert, RequireAndVerifyClientCert:
+ c.sendAlert(alertCertificateRequired)
+ return errors.New("tls: client didn't provide a certificate")
+ }
+ }
+
+ var certs [][]byte
+ for _, cert := range certMsg.certificates {
+ certs = append(certs, cert.data)
+ // OCSP responses and SCT lists are not negotiated in
+ // client certificates.
+ if cert.ocspResponse != nil || cert.sctList != nil {
+ c.sendAlert(alertUnsupportedExtension)
+ return errors.New("tls: unexpected extensions in the client certificate")
+ }
+ }
+ pub, err := hs.processCertsFromClient(certs)
+ if err != nil {
+ return err
+ }
+
+ if len(c.peerCertificates) > 0 {
+ msg, err = c.readHandshake()
+ if err != nil {
+ return err
+ }
+
+ certVerify, ok := msg.(*certificateVerifyMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(certVerify, msg)
+ }
+
+ c.peerSignatureAlgorithm = certVerify.signatureAlgorithm
+ input := hs.finishedHash.certificateVerifyInput(clientCertificateVerifyContextTLS13)
+ if err := verifyMessage(c.vers, pub, config, certVerify.signatureAlgorithm, input, certVerify.signature); err != nil {
+ c.sendAlert(alertBadCertificate)
+ return err
+ }
+ hs.writeClientHash(certVerify.marshal())
+ }
+ }
+
+ if encryptedExtensions.extensions.channelIDRequested {
+ msg, err := c.readHandshake()
+ if err != nil {
+ return err
+ }
+ channelIDMsg, ok := msg.(*channelIDMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(channelIDMsg, msg)
+ }
+ channelIDHash := crypto.SHA256.New()
+ channelIDHash.Write(hs.finishedHash.certificateVerifyInput(channelIDContextTLS13))
+ channelID, err := verifyChannelIDMessage(channelIDMsg, channelIDHash.Sum(nil))
+ if err != nil {
+ return err
+ }
+ c.channelID = channelID
+
+ hs.writeClientHash(channelIDMsg.marshal())
+ }
+
+ // Read the client Finished message.
+ msg, err := c.readHandshake()
+ if err != nil {
+ return err
+ }
+ clientFinished, ok := msg.(*finishedMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(clientFinished, msg)
+ }
+
+ verify := hs.finishedHash.clientSum(clientHandshakeTrafficSecret)
+ if len(verify) != len(clientFinished.verifyData) ||
+ subtle.ConstantTimeCompare(verify, clientFinished.verifyData) != 1 {
+ c.sendAlert(alertHandshakeFailure)
+ return errors.New("tls: client's Finished message was incorrect")
+ }
+ hs.writeClientHash(clientFinished.marshal())
+
+ // Switch to application data keys on read.
+ c.in.useTrafficSecret(c.vers, hs.suite, clientTrafficSecret, clientWrite)
+
+ c.cipherSuite = hs.suite
+ c.resumptionSecret = hs.finishedHash.deriveSecret(resumptionLabel)
+
+ // TODO(davidben): Allow configuring the number of tickets sent for
+ // testing.
+ if !c.config.SessionTicketsDisabled && foundKEMode {
+ ticketCount := 2
+ for i := 0; i < ticketCount; i++ {
+ c.SendNewSessionTicket()
+ }
+ }
+ return nil
+}
+
+// processClientHello processes the ClientHello message from the client and
+// decides whether we will perform session resumption.
+func (hs *serverHandshakeState) processClientHello() (isResume bool, err error) {
+ config := hs.c.config
+ c := hs.c
+
+ hs.hello = &serverHelloMsg{
+ isDTLS: c.isDTLS,
+ vers: versionToWire(c.vers, c.isDTLS),
+ versOverride: config.Bugs.SendServerHelloVersion,
+ compressionMethod: compressionNone,
+ }
+
+ hs.hello.random = make([]byte, 32)
+ _, err = io.ReadFull(config.rand(), hs.hello.random)
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return false, err
+ }
+ // Signal downgrades in the server random, per draft-ietf-tls-tls13-16,
+ // section 4.1.3.
+ if c.vers <= VersionTLS12 && config.maxVersion(c.isDTLS) >= VersionTLS13 {
+ copy(hs.hello.random[len(hs.hello.random)-8:], downgradeTLS13)
+ }
+ if c.vers <= VersionTLS11 && config.maxVersion(c.isDTLS) == VersionTLS12 {
+ copy(hs.hello.random[len(hs.hello.random)-8:], downgradeTLS12)
+ }
+
+ foundCompression := false
+ // We only support null compression, so check that the client offered it.
+ for _, compression := range hs.clientHello.compressionMethods {
+ if compression == compressionNone {
+ foundCompression = true
+ break
+ }
+ }
+
+ if !foundCompression {
+ c.sendAlert(alertHandshakeFailure)
+ return false, errors.New("tls: client does not support uncompressed connections")
+ }
+
+ if err := hs.processClientExtensions(&hs.hello.extensions); err != nil {
+ return false, err
+ }
+
+ supportedCurve := false
+ preferredCurves := config.curvePreferences()
+Curves:
+ for _, curve := range hs.clientHello.supportedCurves {
+ for _, supported := range preferredCurves {
+ if supported == curve {
+ supportedCurve = true
+ break Curves
+ }
+ }
+ }
+
+ supportedPointFormat := false
+ for _, pointFormat := range hs.clientHello.supportedPoints {
+ if pointFormat == pointFormatUncompressed {
+ supportedPointFormat = true
+ break
+ }
+ }
+ hs.ellipticOk = supportedCurve && supportedPointFormat
+
+ _, hs.ecdsaOk = hs.cert.PrivateKey.(*ecdsa.PrivateKey)
+
+ // For test purposes, check that the peer never offers a session when
+ // renegotiating.
+ if c.cipherSuite != nil && len(hs.clientHello.sessionId) > 0 && c.config.Bugs.FailIfResumeOnRenego {
+ return false, errors.New("tls: offered resumption on renegotiation")
+ }
+
+ if c.config.Bugs.FailIfSessionOffered && (len(hs.clientHello.sessionTicket) > 0 || len(hs.clientHello.sessionId) > 0) {
+ return false, errors.New("tls: client offered a session ticket or ID")
+ }
+
+ if hs.checkForResumption() {
+ return true, nil
+ }
+
+ var preferenceList, supportedList []uint16
+ if c.config.PreferServerCipherSuites {
+ preferenceList = c.config.cipherSuites()
+ supportedList = hs.clientHello.cipherSuites
+ } else {
+ preferenceList = hs.clientHello.cipherSuites
+ supportedList = c.config.cipherSuites()
+ }
+
+ for _, id := range preferenceList {
+ if hs.suite = c.tryCipherSuite(id, supportedList, c.vers, hs.ellipticOk, hs.ecdsaOk); hs.suite != nil {
+ break
+ }
+ }
+
+ if hs.suite == nil {
+ c.sendAlert(alertHandshakeFailure)
+ return false, errors.New("tls: no cipher suite supported by both client and server")
+ }
+
+ return false, nil
+}
+
+// processClientExtensions processes all ClientHello extensions not directly
+// related to cipher suite negotiation and writes responses in serverExtensions.
+func (hs *serverHandshakeState) processClientExtensions(serverExtensions *serverExtensions) error {
+ config := hs.c.config
+ c := hs.c
+
+ if c.vers < VersionTLS13 || config.Bugs.NegotiateRenegotiationInfoAtAllVersions {
+ if !bytes.Equal(c.clientVerify, hs.clientHello.secureRenegotiation) {
+ c.sendAlert(alertHandshakeFailure)
+ return errors.New("tls: renegotiation mismatch")
+ }
+
+ if len(c.clientVerify) > 0 && !c.config.Bugs.EmptyRenegotiationInfo {
+ serverExtensions.secureRenegotiation = append(serverExtensions.secureRenegotiation, c.clientVerify...)
+ serverExtensions.secureRenegotiation = append(serverExtensions.secureRenegotiation, c.serverVerify...)
+ if c.config.Bugs.BadRenegotiationInfo {
+ serverExtensions.secureRenegotiation[0] ^= 0x80
+ }
+ } else {
+ serverExtensions.secureRenegotiation = hs.clientHello.secureRenegotiation
+ }
+
+ if c.noRenegotiationInfo() {
+ serverExtensions.secureRenegotiation = nil
+ }
+ }
+
+ serverExtensions.duplicateExtension = c.config.Bugs.DuplicateExtension
+
+ if len(hs.clientHello.serverName) > 0 {
+ c.serverName = hs.clientHello.serverName
+ }
+ if len(config.Certificates) == 0 {
+ c.sendAlert(alertInternalError)
+ return errors.New("tls: no certificates configured")
+ }
+ hs.cert = &config.Certificates[0]
+ if len(hs.clientHello.serverName) > 0 {
+ hs.cert = config.getCertificateForName(hs.clientHello.serverName)
+ }
+ if expected := c.config.Bugs.ExpectServerName; expected != "" && expected != hs.clientHello.serverName {
+ return errors.New("tls: unexpected server name")
+ }
+
+ if cert := config.Bugs.RenegotiationCertificate; c.cipherSuite != nil && cert != nil {
+ hs.cert = cert
+ }
+
+ if len(hs.clientHello.alpnProtocols) > 0 {
+ if proto := c.config.Bugs.ALPNProtocol; proto != nil {
+ serverExtensions.alpnProtocol = *proto
+ serverExtensions.alpnProtocolEmpty = len(*proto) == 0
+ c.clientProtocol = *proto
+ c.usedALPN = true
+ } else if selectedProto, fallback := mutualProtocol(hs.clientHello.alpnProtocols, c.config.NextProtos); !fallback {
+ serverExtensions.alpnProtocol = selectedProto
+ c.clientProtocol = selectedProto
+ c.usedALPN = true
+ }
+ }
+
+ if len(c.config.Bugs.SendALPN) > 0 {
+ serverExtensions.alpnProtocol = c.config.Bugs.SendALPN
+ }
+
+ if c.vers < VersionTLS13 || config.Bugs.NegotiateNPNAtAllVersions {
+ if len(hs.clientHello.alpnProtocols) == 0 || c.config.Bugs.NegotiateALPNAndNPN {
+ // Although sending an empty NPN extension is reasonable, Firefox has
+ // had a bug around this. Best to send nothing at all if
+ // config.NextProtos is empty. See
+ // https://code.google.com/p/go/issues/detail?id=5445.
+ if hs.clientHello.nextProtoNeg && len(config.NextProtos) > 0 {
+ serverExtensions.nextProtoNeg = true
+ serverExtensions.nextProtos = config.NextProtos
+ serverExtensions.npnAfterAlpn = config.Bugs.SwapNPNAndALPN
+ }
+ }
+ }
+
+ if c.vers < VersionTLS13 || config.Bugs.NegotiateEMSAtAllVersions {
+ disableEMS := config.Bugs.NoExtendedMasterSecret
+ if c.cipherSuite != nil {
+ disableEMS = config.Bugs.NoExtendedMasterSecretOnRenegotiation
+ }
+ serverExtensions.extendedMasterSecret = c.vers >= VersionTLS10 && hs.clientHello.extendedMasterSecret && !disableEMS
+ }
+
+ if hs.clientHello.channelIDSupported && config.RequestChannelID {
+ serverExtensions.channelIDRequested = true
+ }
+
+ if hs.clientHello.srtpProtectionProfiles != nil {
+ SRTPLoop:
+ for _, p1 := range c.config.SRTPProtectionProfiles {
+ for _, p2 := range hs.clientHello.srtpProtectionProfiles {
+ if p1 == p2 {
+ serverExtensions.srtpProtectionProfile = p1
+ c.srtpProtectionProfile = p1
+ break SRTPLoop
+ }
+ }
+ }
+ }
+
+ if c.config.Bugs.SendSRTPProtectionProfile != 0 {
+ serverExtensions.srtpProtectionProfile = c.config.Bugs.SendSRTPProtectionProfile
+ }
+
+ if expected := c.config.Bugs.ExpectedCustomExtension; expected != nil {
+ if hs.clientHello.customExtension != *expected {
+ return fmt.Errorf("tls: bad custom extension contents %q", hs.clientHello.customExtension)
+ }
+ }
+ serverExtensions.customExtension = config.Bugs.CustomExtension
+
+ if c.config.Bugs.AdvertiseTicketExtension {
+ serverExtensions.ticketSupported = true
+ }
+
+ if c.config.Bugs.SendSupportedPointFormats != nil {
+ serverExtensions.supportedPoints = c.config.Bugs.SendSupportedPointFormats
+ }
+
+ if !hs.clientHello.hasGREASEExtension && config.Bugs.ExpectGREASE {
+ return errors.New("tls: no GREASE extension found")
+ }
+
+ serverExtensions.serverNameAck = c.config.Bugs.SendServerNameAck
+
+ return nil
+}
+
+// checkForResumption returns true if we should perform resumption on this connection.
+func (hs *serverHandshakeState) checkForResumption() bool {
+ c := hs.c
+
+ ticket := hs.clientHello.sessionTicket
+ if len(ticket) == 0 && len(hs.clientHello.pskIdentities) > 0 && c.config.Bugs.AcceptAnySession {
+ ticket = hs.clientHello.pskIdentities[0].ticket
+ }
+ if len(ticket) > 0 {
+ if c.config.SessionTicketsDisabled {
+ return false
+ }
+
+ var ok bool
+ if hs.sessionState, ok = c.decryptTicket(ticket); !ok {
+ return false
+ }
+ } else {
+ if c.config.ServerSessionCache == nil {
+ return false
+ }
+
+ var ok bool
+ sessionId := string(hs.clientHello.sessionId)
+ if hs.sessionState, ok = c.config.ServerSessionCache.Get(sessionId); !ok {
+ return false
+ }
+ }
+
+ if c.config.Bugs.AcceptAnySession {
+ // Replace the cipher suite with one known to work, to test
+ // cross-version resumption attempts.
+ hs.sessionState.cipherSuite = TLS_RSA_WITH_AES_128_CBC_SHA
+ } else {
+ // Never resume a session for a different SSL version.
+ if c.vers != hs.sessionState.vers {
+ return false
+ }
+
+ cipherSuiteOk := false
+ // Check that the client is still offering the ciphersuite in the session.
+ for _, id := range hs.clientHello.cipherSuites {
+ if id == hs.sessionState.cipherSuite {
+ cipherSuiteOk = true
+ break
+ }
+ }
+ if !cipherSuiteOk {
+ return false
+ }
+ }
+
+ // Check that we also support the ciphersuite from the session.
+ hs.suite = c.tryCipherSuite(hs.sessionState.cipherSuite, c.config.cipherSuites(), c.vers, hs.ellipticOk, hs.ecdsaOk)
+
+ if hs.suite == nil {
+ return false
+ }
+
+ sessionHasClientCerts := len(hs.sessionState.certificates) != 0
+ needClientCerts := c.config.ClientAuth == RequireAnyClientCert || c.config.ClientAuth == RequireAndVerifyClientCert
+ if needClientCerts && !sessionHasClientCerts {
+ return false
+ }
+ if sessionHasClientCerts && c.config.ClientAuth == NoClientCert {
+ return false
+ }
+
+ return true
+}
+
+func (hs *serverHandshakeState) doResumeHandshake() error {
+ c := hs.c
+
+ hs.hello.cipherSuite = hs.suite.id
+ if c.config.Bugs.SendCipherSuite != 0 {
+ hs.hello.cipherSuite = c.config.Bugs.SendCipherSuite
+ }
+ // We echo the client's session ID in the ServerHello to let it know
+ // that we're doing a resumption.
+ hs.hello.sessionId = hs.clientHello.sessionId
+ hs.hello.extensions.ticketSupported = c.config.Bugs.RenewTicketOnResume
+
+ if c.config.Bugs.SendSCTListOnResume != nil {
+ hs.hello.extensions.sctList = c.config.Bugs.SendSCTListOnResume
+ }
+
+ if c.config.Bugs.SendOCSPResponseOnResume != nil {
+ // There is no way, syntactically, to send an OCSP response on a
+ // resumption handshake.
+ hs.hello.extensions.ocspStapling = true
+ }
+
+ hs.finishedHash = newFinishedHash(c.vers, hs.suite)
+ hs.finishedHash.discardHandshakeBuffer()
+ hs.writeClientHash(hs.clientHello.marshal())
+ hs.writeServerHash(hs.hello.marshal())
+
+ c.writeRecord(recordTypeHandshake, hs.hello.marshal())
+
+ if len(hs.sessionState.certificates) > 0 {
+ if _, err := hs.processCertsFromClient(hs.sessionState.certificates); err != nil {
+ return err
+ }
+ }
+
+ hs.masterSecret = hs.sessionState.masterSecret
+ c.extendedMasterSecret = hs.sessionState.extendedMasterSecret
+
+ return nil
+}
+
+func (hs *serverHandshakeState) doFullHandshake() error {
+ config := hs.c.config
+ c := hs.c
+
+ isPSK := hs.suite.flags&suitePSK != 0
+ if !isPSK && hs.clientHello.ocspStapling && len(hs.cert.OCSPStaple) > 0 {
+ hs.hello.extensions.ocspStapling = true
+ }
+
+ if hs.clientHello.sctListSupported && len(hs.cert.SignedCertificateTimestampList) > 0 {
+ hs.hello.extensions.sctList = hs.cert.SignedCertificateTimestampList
+ }
+
+ hs.hello.extensions.ticketSupported = hs.clientHello.ticketSupported && !config.SessionTicketsDisabled && c.vers > VersionSSL30
+ hs.hello.cipherSuite = hs.suite.id
+ if config.Bugs.SendCipherSuite != 0 {
+ hs.hello.cipherSuite = config.Bugs.SendCipherSuite
+ }
+ c.extendedMasterSecret = hs.hello.extensions.extendedMasterSecret
+
+ // Generate a session ID if we're to save the session.
+ if !hs.hello.extensions.ticketSupported && config.ServerSessionCache != nil {
+ hs.hello.sessionId = make([]byte, 32)
+ if _, err := io.ReadFull(config.rand(), hs.hello.sessionId); err != nil {
+ c.sendAlert(alertInternalError)
+ return errors.New("tls: short read from Rand: " + err.Error())
+ }
+ }
+
+ hs.finishedHash = newFinishedHash(c.vers, hs.suite)
+ hs.writeClientHash(hs.clientHello.marshal())
+ hs.writeServerHash(hs.hello.marshal())
+
+ if config.Bugs.SendSNIWarningAlert {
+ c.SendAlert(alertLevelWarning, alertUnrecognizedName)
+ }
+
+ c.writeRecord(recordTypeHandshake, hs.hello.marshal())
+
+ if !isPSK {
+ certMsg := new(certificateMsg)
+ if !config.Bugs.EmptyCertificateList {
+ for _, certData := range hs.cert.Certificate {
+ certMsg.certificates = append(certMsg.certificates, certificateEntry{
+ data: certData,
+ })
+ }
+ }
+ if !config.Bugs.UnauthenticatedECDH {
+ certMsgBytes := certMsg.marshal()
+ hs.writeServerHash(certMsgBytes)
+ c.writeRecord(recordTypeHandshake, certMsgBytes)
+ }
+ }
+
+ if hs.hello.extensions.ocspStapling && !c.config.Bugs.SkipCertificateStatus {
+ certStatus := new(certificateStatusMsg)
+ certStatus.statusType = statusTypeOCSP
+ certStatus.response = hs.cert.OCSPStaple
+ hs.writeServerHash(certStatus.marshal())
+ c.writeRecord(recordTypeHandshake, certStatus.marshal())
+ }
+
+ keyAgreement := hs.suite.ka(c.vers)
+ skx, err := keyAgreement.generateServerKeyExchange(config, hs.cert, hs.clientHello, hs.hello)
+ if err != nil {
+ c.sendAlert(alertHandshakeFailure)
+ return err
+ }
+ if ecdhe, ok := keyAgreement.(*ecdheKeyAgreement); ok {
+ c.curveID = ecdhe.curveID
+ }
+ if skx != nil && !config.Bugs.SkipServerKeyExchange {
+ hs.writeServerHash(skx.marshal())
+ c.writeRecord(recordTypeHandshake, skx.marshal())
+ }
+
+ if config.ClientAuth >= RequestClientCert {
+ // Request a client certificate
+ certReq := &certificateRequestMsg{
+ certificateTypes: config.ClientCertificateTypes,
+ }
+ if certReq.certificateTypes == nil {
+ certReq.certificateTypes = []byte{
+ byte(CertTypeRSASign),
+ byte(CertTypeECDSASign),
+ }
+ }
+ if c.vers >= VersionTLS12 {
+ certReq.hasSignatureAlgorithm = true
+ if !config.Bugs.NoSignatureAlgorithms {
+ certReq.signatureAlgorithms = config.verifySignatureAlgorithms()
+ }
+ }
+
+ // An empty list of certificateAuthorities signals to
+ // the client that it may send any certificate in response
+ // to our request. When we know the CAs we trust, then
+ // we can send them down, so that the client can choose
+ // an appropriate certificate to give to us.
+ if config.ClientCAs != nil {
+ certReq.certificateAuthorities = config.ClientCAs.Subjects()
+ }
+ hs.writeServerHash(certReq.marshal())
+ c.writeRecord(recordTypeHandshake, certReq.marshal())
+ }
+
+ helloDone := new(serverHelloDoneMsg)
+ hs.writeServerHash(helloDone.marshal())
+ c.writeRecord(recordTypeHandshake, helloDone.marshal())
+ c.flushHandshake()
+
+ var pub crypto.PublicKey // public key for client auth, if any
+
+ if err := c.simulatePacketLoss(nil); err != nil {
+ return err
+ }
+ msg, err := c.readHandshake()
+ if err != nil {
+ return err
+ }
+
+ var ok bool
+ // If we requested a client certificate, then the client must send a
+ // certificate message, even if it's empty.
+ if config.ClientAuth >= RequestClientCert {
+ var certMsg *certificateMsg
+ var certificates [][]byte
+ if certMsg, ok = msg.(*certificateMsg); ok {
+ if c.vers == VersionSSL30 && len(certMsg.certificates) == 0 {
+ return errors.New("tls: empty certificate message in SSL 3.0")
+ }
+
+ hs.writeClientHash(certMsg.marshal())
+ for _, cert := range certMsg.certificates {
+ certificates = append(certificates, cert.data)
+ }
+ } else if c.vers == VersionSSL30 {
+ // In SSL 3.0, no certificate is signaled by a warning
+ // alert which we translate to ssl3NoCertificateMsg.
+ if _, ok := msg.(*ssl3NoCertificateMsg); !ok {
+ return errors.New("tls: client provided neither a certificate nor no_certificate warning alert")
+ }
+ } else {
+ // In TLS, the Certificate message is required. In SSL
+ // 3.0, the peer skips it when sending no certificates.
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(certMsg, msg)
+ }
+
+ if len(certificates) == 0 {
+ // The client didn't actually send a certificate
+ switch config.ClientAuth {
+ case RequireAnyClientCert, RequireAndVerifyClientCert:
+ c.sendAlert(alertBadCertificate)
+ return errors.New("tls: client didn't provide a certificate")
+ }
+ }
+
+ pub, err = hs.processCertsFromClient(certificates)
+ if err != nil {
+ return err
+ }
+
+ msg, err = c.readHandshake()
+ if err != nil {
+ return err
+ }
+ }
+
+ // Get client key exchange
+ ckx, ok := msg.(*clientKeyExchangeMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(ckx, msg)
+ }
+ hs.writeClientHash(ckx.marshal())
+
+ preMasterSecret, err := keyAgreement.processClientKeyExchange(config, hs.cert, ckx, c.vers)
+ if err != nil {
+ c.sendAlert(alertHandshakeFailure)
+ return err
+ }
+ if c.extendedMasterSecret {
+ hs.masterSecret = extendedMasterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.finishedHash)
+ } else {
+ if c.config.Bugs.RequireExtendedMasterSecret {
+ return errors.New("tls: extended master secret required but not supported by peer")
+ }
+ hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.clientHello.random, hs.hello.random)
+ }
+
+ // If we received a client cert in response to our certificate request message,
+ // the client will send us a certificateVerifyMsg immediately after the
+ // clientKeyExchangeMsg. This message is a digest of all preceding
+ // handshake-layer messages that is signed using the private key corresponding
+ // to the client's certificate. This allows us to verify that the client is in
+ // possession of the private key of the certificate.
+ if len(c.peerCertificates) > 0 {
+ msg, err = c.readHandshake()
+ if err != nil {
+ return err
+ }
+ certVerify, ok := msg.(*certificateVerifyMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(certVerify, msg)
+ }
+
+ // Determine the signature type.
+ var sigAlg signatureAlgorithm
+ if certVerify.hasSignatureAlgorithm {
+ sigAlg = certVerify.signatureAlgorithm
+ c.peerSignatureAlgorithm = sigAlg
+ }
+
+ if c.vers > VersionSSL30 {
+ err = verifyMessage(c.vers, pub, c.config, sigAlg, hs.finishedHash.buffer, certVerify.signature)
+ } else {
+ // SSL 3.0's client certificate construction is
+ // incompatible with signatureAlgorithm.
+ rsaPub, ok := pub.(*rsa.PublicKey)
+ if !ok {
+ err = errors.New("unsupported key type for client certificate")
+ } else {
+ digest := hs.finishedHash.hashForClientCertificateSSL3(hs.masterSecret)
+ err = rsa.VerifyPKCS1v15(rsaPub, crypto.MD5SHA1, digest, certVerify.signature)
+ }
+ }
+ if err != nil {
+ c.sendAlert(alertBadCertificate)
+ return errors.New("could not validate signature of connection nonces: " + err.Error())
+ }
+
+ hs.writeClientHash(certVerify.marshal())
+ }
+
+ hs.finishedHash.discardHandshakeBuffer()
+
+ return nil
+}
+
+func (hs *serverHandshakeState) establishKeys() error {
+ c := hs.c
+
+ clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
+ keysFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.clientHello.random, hs.hello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen(c.vers))
+
+ var clientCipher, serverCipher interface{}
+ var clientHash, serverHash macFunction
+
+ if hs.suite.aead == nil {
+ clientCipher = hs.suite.cipher(clientKey, clientIV, true /* for reading */)
+ clientHash = hs.suite.mac(c.vers, clientMAC)
+ serverCipher = hs.suite.cipher(serverKey, serverIV, false /* not for reading */)
+ serverHash = hs.suite.mac(c.vers, serverMAC)
+ } else {
+ clientCipher = hs.suite.aead(c.vers, clientKey, clientIV)
+ serverCipher = hs.suite.aead(c.vers, serverKey, serverIV)
+ }
+
+ c.in.prepareCipherSpec(c.vers, clientCipher, clientHash)
+ c.out.prepareCipherSpec(c.vers, serverCipher, serverHash)
+
+ return nil
+}
+
+func (hs *serverHandshakeState) readFinished(out []byte, isResume bool) error {
+ c := hs.c
+
+ c.readRecord(recordTypeChangeCipherSpec)
+ if err := c.in.error(); err != nil {
+ return err
+ }
+
+ if hs.hello.extensions.nextProtoNeg {
+ msg, err := c.readHandshake()
+ if err != nil {
+ return err
+ }
+ nextProto, ok := msg.(*nextProtoMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(nextProto, msg)
+ }
+ hs.writeClientHash(nextProto.marshal())
+ c.clientProtocol = nextProto.proto
+ }
+
+ if hs.hello.extensions.channelIDRequested {
+ msg, err := c.readHandshake()
+ if err != nil {
+ return err
+ }
+ channelIDMsg, ok := msg.(*channelIDMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(channelIDMsg, msg)
+ }
+ var resumeHash []byte
+ if isResume {
+ resumeHash = hs.sessionState.handshakeHash
+ }
+ channelID, err := verifyChannelIDMessage(channelIDMsg, hs.finishedHash.hashForChannelID(resumeHash))
+ if err != nil {
+ return err
+ }
+ c.channelID = channelID
+
+ hs.writeClientHash(channelIDMsg.marshal())
+ }
+
+ msg, err := c.readHandshake()
+ if err != nil {
+ return err
+ }
+ clientFinished, ok := msg.(*finishedMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(clientFinished, msg)
+ }
+
+ verify := hs.finishedHash.clientSum(hs.masterSecret)
+ if len(verify) != len(clientFinished.verifyData) ||
+ subtle.ConstantTimeCompare(verify, clientFinished.verifyData) != 1 {
+ c.sendAlert(alertHandshakeFailure)
+ return errors.New("tls: client's Finished message is incorrect")
+ }
+ c.clientVerify = append(c.clientVerify[:0], clientFinished.verifyData...)
+ copy(out, clientFinished.verifyData)
+
+ hs.writeClientHash(clientFinished.marshal())
+ return nil
+}
+
+func (hs *serverHandshakeState) sendSessionTicket() error {
+ c := hs.c
+ state := sessionState{
+ vers: c.vers,
+ cipherSuite: hs.suite.id,
+ masterSecret: hs.masterSecret,
+ certificates: hs.certsFromClient,
+ handshakeHash: hs.finishedHash.Sum(),
+ }
+
+ if !hs.hello.extensions.ticketSupported || hs.c.config.Bugs.SkipNewSessionTicket {
+ if c.config.ServerSessionCache != nil && len(hs.hello.sessionId) != 0 {
+ c.config.ServerSessionCache.Put(string(hs.hello.sessionId), &state)
+ }
+ return nil
+ }
+
+ m := new(newSessionTicketMsg)
+ if c.config.Bugs.SendTicketLifetime != 0 {
+ m.ticketLifetime = uint32(c.config.Bugs.SendTicketLifetime / time.Second)
+ }
+
+ if !c.config.Bugs.SendEmptySessionTicket {
+ var err error
+ m.ticket, err = c.encryptTicket(&state)
+ if err != nil {
+ return err
+ }
+ }
+
+ hs.writeServerHash(m.marshal())
+ c.writeRecord(recordTypeHandshake, m.marshal())
+
+ return nil
+}
+
+func (hs *serverHandshakeState) sendFinished(out []byte) error {
+ c := hs.c
+
+ finished := new(finishedMsg)
+ finished.verifyData = hs.finishedHash.serverSum(hs.masterSecret)
+ copy(out, finished.verifyData)
+ if c.config.Bugs.BadFinished {
+ finished.verifyData[0]++
+ }
+ c.serverVerify = append(c.serverVerify[:0], finished.verifyData...)
+ hs.finishedBytes = finished.marshal()
+ hs.writeServerHash(hs.finishedBytes)
+ postCCSBytes := hs.finishedBytes
+
+ if c.config.Bugs.FragmentAcrossChangeCipherSpec {
+ c.writeRecord(recordTypeHandshake, postCCSBytes[:5])
+ postCCSBytes = postCCSBytes[5:]
+ } else if c.config.Bugs.SendUnencryptedFinished {
+ c.writeRecord(recordTypeHandshake, postCCSBytes)
+ postCCSBytes = nil
+ }
+ c.flushHandshake()
+
+ if !c.config.Bugs.SkipChangeCipherSpec {
+ ccs := []byte{1}
+ if c.config.Bugs.BadChangeCipherSpec != nil {
+ ccs = c.config.Bugs.BadChangeCipherSpec
+ }
+ c.writeRecord(recordTypeChangeCipherSpec, ccs)
+ }
+
+ if c.config.Bugs.AppDataAfterChangeCipherSpec != nil {
+ c.writeRecord(recordTypeApplicationData, c.config.Bugs.AppDataAfterChangeCipherSpec)
+ }
+ if c.config.Bugs.AlertAfterChangeCipherSpec != 0 {
+ c.sendAlert(c.config.Bugs.AlertAfterChangeCipherSpec)
+ return errors.New("tls: simulating post-CCS alert")
+ }
+
+ if !c.config.Bugs.SkipFinished && len(postCCSBytes) > 0 {
+ c.writeRecord(recordTypeHandshake, postCCSBytes)
+ if c.config.Bugs.SendExtraFinished {
+ c.writeRecord(recordTypeHandshake, finished.marshal())
+ }
+
+ if !c.config.Bugs.PackHelloRequestWithFinished {
+ // Defer flushing until renegotiation.
+ c.flushHandshake()
+ }
+ }
+
+ c.cipherSuite = hs.suite
+
+ return nil
+}
+
+// processCertsFromClient takes a chain of client certificates either from a
+// Certificates message or from a sessionState and verifies them. It returns
+// the public key of the leaf certificate.
+func (hs *serverHandshakeState) processCertsFromClient(certificates [][]byte) (crypto.PublicKey, error) {
+ c := hs.c
+
+ hs.certsFromClient = certificates
+ certs := make([]*x509.Certificate, len(certificates))
+ var err error
+ for i, asn1Data := range certificates {
+ if certs[i], err = x509.ParseCertificate(asn1Data); err != nil {
+ c.sendAlert(alertBadCertificate)
+ return nil, errors.New("tls: failed to parse client certificate: " + err.Error())
+ }
+ }
+
+ if c.config.ClientAuth >= VerifyClientCertIfGiven && len(certs) > 0 {
+ opts := x509.VerifyOptions{
+ Roots: c.config.ClientCAs,
+ CurrentTime: c.config.time(),
+ Intermediates: x509.NewCertPool(),
+ KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
+ }
+
+ for _, cert := range certs[1:] {
+ opts.Intermediates.AddCert(cert)
+ }
+
+ chains, err := certs[0].Verify(opts)
+ if err != nil {
+ c.sendAlert(alertBadCertificate)
+ return nil, errors.New("tls: failed to verify client's certificate: " + err.Error())
+ }
+
+ ok := false
+ for _, ku := range certs[0].ExtKeyUsage {
+ if ku == x509.ExtKeyUsageClientAuth {
+ ok = true
+ break
+ }
+ }
+ if !ok {
+ c.sendAlert(alertHandshakeFailure)
+ return nil, errors.New("tls: client's certificate's extended key usage doesn't permit it to be used for client authentication")
+ }
+
+ c.verifiedChains = chains
+ }
+
+ if len(certs) > 0 {
+ var pub crypto.PublicKey
+ switch key := certs[0].PublicKey.(type) {
+ case *ecdsa.PublicKey, *rsa.PublicKey:
+ pub = key
+ default:
+ c.sendAlert(alertUnsupportedCertificate)
+ return nil, fmt.Errorf("tls: client's certificate contains an unsupported public key of type %T", certs[0].PublicKey)
+ }
+ c.peerCertificates = certs
+ return pub, nil
+ }
+
+ return nil, nil
+}
+
+func verifyChannelIDMessage(channelIDMsg *channelIDMsg, channelIDHash []byte) (*ecdsa.PublicKey, error) {
+ x := new(big.Int).SetBytes(channelIDMsg.channelID[0:32])
+ y := new(big.Int).SetBytes(channelIDMsg.channelID[32:64])
+ r := new(big.Int).SetBytes(channelIDMsg.channelID[64:96])
+ s := new(big.Int).SetBytes(channelIDMsg.channelID[96:128])
+ if !elliptic.P256().IsOnCurve(x, y) {
+ return nil, errors.New("tls: invalid channel ID public key")
+ }
+ channelID := &ecdsa.PublicKey{elliptic.P256(), x, y}
+ if !ecdsa.Verify(channelID, channelIDHash, r, s) {
+ return nil, errors.New("tls: invalid channel ID signature")
+ }
+ return channelID, nil
+}
+
+func (hs *serverHandshakeState) writeServerHash(msg []byte) {
+ // writeServerHash is called before writeRecord.
+ hs.writeHash(msg, hs.c.sendHandshakeSeq)
+}
+
+func (hs *serverHandshakeState) writeClientHash(msg []byte) {
+ // writeClientHash is called after readHandshake.
+ hs.writeHash(msg, hs.c.recvHandshakeSeq-1)
+}
+
+func (hs *serverHandshakeState) writeHash(msg []byte, seqno uint16) {
+ if hs.c.isDTLS {
+ // This is somewhat hacky. DTLS hashes a slightly different format.
+ // First, the TLS header.
+ hs.finishedHash.Write(msg[:4])
+ // Then the sequence number and reassembled fragment offset (always 0).
+ hs.finishedHash.Write([]byte{byte(seqno >> 8), byte(seqno), 0, 0, 0})
+ // Then the reassembled fragment (always equal to the message length).
+ hs.finishedHash.Write(msg[1:4])
+ // And then the message body.
+ hs.finishedHash.Write(msg[4:])
+ } else {
+ hs.finishedHash.Write(msg)
+ }
+}
+
+// tryCipherSuite returns a cipherSuite with the given id if that cipher suite
+// is acceptable to use.
+func (c *Conn) tryCipherSuite(id uint16, supportedCipherSuites []uint16, version uint16, ellipticOk, ecdsaOk bool) *cipherSuite {
+ for _, supported := range supportedCipherSuites {
+ if id == supported {
+ var candidate *cipherSuite
+
+ for _, s := range cipherSuites {
+ if s.id == id {
+ candidate = s
+ break
+ }
+ }
+ if candidate == nil {
+ continue
+ }
+
+ // Don't select a ciphersuite which we can't
+ // support for this client.
+ if version >= VersionTLS13 || candidate.flags&suiteTLS13 != 0 {
+ if version < VersionTLS13 || candidate.flags&suiteTLS13 == 0 {
+ continue
+ }
+ return candidate
+ }
+ if (candidate.flags&suiteECDHE != 0) && !ellipticOk {
+ continue
+ }
+ if (candidate.flags&suiteECDSA != 0) != ecdsaOk {
+ continue
+ }
+ if version < VersionTLS12 && candidate.flags&suiteTLS12 != 0 {
+ continue
+ }
+ if c.isDTLS && candidate.flags&suiteNoDTLS != 0 {
+ continue
+ }
+ return candidate
+ }
+ }
+
+ return nil
+}
+
+func isTLS12Cipher(id uint16) bool {
+ for _, cipher := range cipherSuites {
+ if cipher.id != id {
+ continue
+ }
+ return cipher.flags&suiteTLS12 != 0
+ }
+ // Unknown cipher.
+ return false
+}
+
+func isGREASEValue(val uint16) bool {
+ return val&0x0f0f == 0x0a0a && val&0xff == val>>8
+}
+
+func verifyPSKBinder(clientHello *clientHelloMsg, sessionState *sessionState, binderToVerify, transcript []byte) error {
+ binderLen := 2
+ for _, binder := range clientHello.pskBinders {
+ binderLen += 1 + len(binder)
+ }
+
+ truncatedHello := clientHello.marshal()
+ truncatedHello = truncatedHello[:len(truncatedHello)-binderLen]
+ pskCipherSuite := cipherSuiteFromID(sessionState.cipherSuite)
+ if pskCipherSuite == nil {
+ return errors.New("tls: Unknown cipher suite for PSK in session")
+ }
+
+ binder := computePSKBinder(sessionState.masterSecret, resumptionPSKBinderLabel, pskCipherSuite, transcript, truncatedHello)
+ if !bytes.Equal(binder, binderToVerify) {
+ return errors.New("tls: PSK binder does not verify")
+ }
+
+ return nil
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/hkdf.go b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/hkdf.go
new file mode 100644
index 000000000..c60e4ccf9
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/hkdf.go
@@ -0,0 +1,57 @@
+// Copyright (c) 2016, 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 runner
+
+import (
+ "crypto/hmac"
+ "hash"
+)
+
+// hkdfExtract implements HKDF-Extract from RFC 5869.
+func hkdfExtract(hash func() hash.Hash, salt, ikm []byte) []byte {
+ if salt == nil {
+ salt = make([]byte, hash().Size())
+ }
+ hmac := hmac.New(hash, salt)
+ hmac.Write(ikm)
+ return hmac.Sum(nil)
+}
+
+// hkdfExpand implements HKDF-Expand from RFC 5869.
+func hkdfExpand(hash func() hash.Hash, prk, info []byte, length int) []byte {
+ hashSize := hash().Size()
+ if length > 255*hashSize {
+ panic("hkdfExpand: length too long")
+ }
+ if len(prk) < hashSize {
+ panic("hkdfExpand: prk too short")
+ }
+ var lastBlock []byte
+ counter := byte(0)
+ okm := make([]byte, length)
+ hmac := hmac.New(hash, prk)
+ for length > 0 {
+ hmac.Reset()
+ counter++
+ hmac.Write(lastBlock)
+ hmac.Write(info)
+ hmac.Write([]byte{counter})
+ block := hmac.Sum(nil)
+ lastBlock = block
+ copy(okm[(int(counter)-1)*hashSize:], block)
+ length -= hashSize
+ }
+ return okm
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/hkdf_test.go b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/hkdf_test.go
new file mode 100644
index 000000000..4e6958ea9
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/hkdf_test.go
@@ -0,0 +1,101 @@
+// Copyright (c) 2016, 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 runner
+
+import (
+ "bytes"
+ "crypto"
+ _ "crypto/sha1"
+ _ "crypto/sha256"
+ "testing"
+)
+
+var hkdfTests = []struct {
+ hash crypto.Hash
+ ikm, salt, info, prk, okm []byte
+}{
+ {
+ crypto.SHA256,
+ []byte{0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b},
+ []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c},
+ []byte{0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9},
+ []byte{0x07, 0x77, 0x09, 0x36, 0x2c, 0x2e, 0x32, 0xdf, 0x0d, 0xdc, 0x3f, 0x0d, 0xc4, 0x7b, 0xba, 0x63, 0x90, 0xb6, 0xc7, 0x3b, 0xb5, 0x0f, 0x9c, 0x31, 0x22, 0xec, 0x84, 0x4a, 0xd7, 0xc2, 0xb3, 0xe5},
+ []byte{0x3c, 0xb2, 0x5f, 0x25, 0xfa, 0xac, 0xd5, 0x7a, 0x90, 0x43, 0x4f, 0x64, 0xd0, 0x36, 0x2f, 0x2a, 0x2d, 0x2d, 0x0a, 0x90, 0xcf, 0x1a, 0x5a, 0x4c, 0x5d, 0xb0, 0x2d, 0x56, 0xec, 0xc4, 0xc5, 0xbf, 0x34, 0x00, 0x72, 0x08, 0xd5, 0xb8, 0x87, 0x18, 0x58, 0x65},
+ },
+ {
+ crypto.SHA256,
+ []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f},
+ []byte{0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf},
+ []byte{0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff},
+ []byte{0x06, 0xa6, 0xb8, 0x8c, 0x58, 0x53, 0x36, 0x1a, 0x06, 0x10, 0x4c, 0x9c, 0xeb, 0x35, 0xb4, 0x5c, 0xef, 0x76, 0x00, 0x14, 0x90, 0x46, 0x71, 0x01, 0x4a, 0x19, 0x3f, 0x40, 0xc1, 0x5f, 0xc2, 0x44},
+ []byte{0xb1, 0x1e, 0x39, 0x8d, 0xc8, 0x03, 0x27, 0xa1, 0xc8, 0xe7, 0xf7, 0x8c, 0x59, 0x6a, 0x49, 0x34, 0x4f, 0x01, 0x2e, 0xda, 0x2d, 0x4e, 0xfa, 0xd8, 0xa0, 0x50, 0xcc, 0x4c, 0x19, 0xaf, 0xa9, 0x7c, 0x59, 0x04, 0x5a, 0x99, 0xca, 0xc7, 0x82, 0x72, 0x71, 0xcb, 0x41, 0xc6, 0x5e, 0x59, 0x0e, 0x09, 0xda, 0x32, 0x75, 0x60, 0x0c, 0x2f, 0x09, 0xb8, 0x36, 0x77, 0x93, 0xa9, 0xac, 0xa3, 0xdb, 0x71, 0xcc, 0x30, 0xc5, 0x81, 0x79, 0xec, 0x3e, 0x87, 0xc1, 0x4c, 0x01, 0xd5, 0xc1, 0xf3, 0x43, 0x4f, 0x1d, 0x87},
+ },
+ {
+ crypto.SHA256,
+ []byte{
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b},
+ []byte{},
+ []byte{},
+ []byte{0x19, 0xef, 0x24, 0xa3, 0x2c, 0x71, 0x7b, 0x16, 0x7f, 0x33, 0xa9, 0x1d, 0x6f, 0x64, 0x8b, 0xdf, 0x96, 0x59, 0x67, 0x76, 0xaf, 0xdb, 0x63, 0x77, 0xac, 0x43, 0x4c, 0x1c, 0x29, 0x3c, 0xcb, 0x04},
+ []byte{0x8d, 0xa4, 0xe7, 0x75, 0xa5, 0x63, 0xc1, 0x8f, 0x71, 0x5f, 0x80, 0x2a, 0x06, 0x3c, 0x5a, 0x31, 0xb8, 0xa1, 0x1f, 0x5c, 0x5e, 0xe1, 0x87, 0x9e, 0xc3, 0x45, 0x4e, 0x5f, 0x3c, 0x73, 0x8d, 0x2d, 0x9d, 0x20, 0x13, 0x95, 0xfa, 0xa4, 0xb6, 0x1a, 0x96, 0xc8},
+ },
+ {
+ crypto.SHA1,
+ []byte{0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b},
+ []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c},
+ []byte{0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9},
+ []byte{0x9b, 0x6c, 0x18, 0xc4, 0x32, 0xa7, 0xbf, 0x8f, 0x0e, 0x71, 0xc8, 0xeb, 0x88, 0xf4, 0xb3, 0x0b, 0xaa, 0x2b, 0xa2, 0x43},
+ []byte{0x08, 0x5a, 0x01, 0xea, 0x1b, 0x10, 0xf3, 0x69, 0x33, 0x06, 0x8b, 0x56, 0xef, 0xa5, 0xad, 0x81, 0xa4, 0xf1, 0x4b, 0x82, 0x2f, 0x5b, 0x09, 0x15, 0x68, 0xa9, 0xcd, 0xd4, 0xf1, 0x55, 0xfd, 0xa2, 0xc2, 0x2e, 0x42, 0x24, 0x78, 0xd3, 0x05, 0xf3, 0xf8, 0x96},
+ },
+ {
+ crypto.SHA1,
+ []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f},
+ []byte{0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf},
+ []byte{0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff},
+ []byte{0x8a, 0xda, 0xe0, 0x9a, 0x2a, 0x30, 0x70, 0x59, 0x47, 0x8d, 0x30, 0x9b, 0x26, 0xc4, 0x11, 0x5a, 0x22, 0x4c, 0xfa, 0xf6},
+ []byte{0x0b, 0xd7, 0x70, 0xa7, 0x4d, 0x11, 0x60, 0xf7, 0xc9, 0xf1, 0x2c, 0xd5, 0x91, 0x2a, 0x06, 0xeb, 0xff, 0x6a, 0xdc, 0xae, 0x89, 0x9d, 0x92, 0x19, 0x1f, 0xe4, 0x30, 0x56, 0x73, 0xba, 0x2f, 0xfe, 0x8f, 0xa3, 0xf1, 0xa4, 0xe5, 0xad, 0x79, 0xf3, 0xf3, 0x34, 0xb3, 0xb2, 0x02, 0xb2, 0x17, 0x3c, 0x48, 0x6e, 0xa3, 0x7c, 0xe3, 0xd3, 0x97, 0xed, 0x03, 0x4c, 0x7f, 0x9d, 0xfe, 0xb1, 0x5c, 0x5e, 0x92, 0x73, 0x36, 0xd0, 0x44, 0x1f, 0x4c, 0x43, 0x00, 0xe2, 0xcf, 0xf0, 0xd0, 0x90, 0x0b, 0x52, 0xd3, 0xb4},
+ },
+ {
+ crypto.SHA1,
+ []byte{0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b},
+ []byte{},
+ []byte{},
+ []byte{0xda, 0x8c, 0x8a, 0x73, 0xc7, 0xfa, 0x77, 0x28, 0x8e, 0xc6, 0xf5, 0xe7, 0xc2, 0x97, 0x78, 0x6a, 0xa0, 0xd3, 0x2d, 0x01},
+ []byte{0x0a, 0xc1, 0xaf, 0x70, 0x02, 0xb3, 0xd7, 0x61, 0xd1, 0xe5, 0x52, 0x98, 0xda, 0x9d, 0x05, 0x06, 0xb9, 0xae, 0x52, 0x05, 0x72, 0x20, 0xa3, 0x06, 0xe0, 0x7b, 0x6b, 0x87, 0xe8, 0xdf, 0x21, 0xd0, 0xea, 0x00, 0x03, 0x3d, 0xe0, 0x39, 0x84, 0xd3, 0x49, 0x18},
+ },
+ {
+ crypto.SHA1,
+ []byte{0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c},
+ []byte{},
+ []byte{},
+ []byte{0x2a, 0xdc, 0xca, 0xda, 0x18, 0x77, 0x9e, 0x7c, 0x20, 0x77, 0xad, 0x2e, 0xb1, 0x9d, 0x3f, 0x3e, 0x73, 0x13, 0x85, 0xdd},
+ []byte{0x2c, 0x91, 0x11, 0x72, 0x04, 0xd7, 0x45, 0xf3, 0x50, 0x0d, 0x63, 0x6a, 0x62, 0xf6, 0x4f, 0x0a, 0xb3, 0xba, 0xe5, 0x48, 0xaa, 0x53, 0xd4, 0x23, 0xb0, 0xd1, 0xf2, 0x7e, 0xbb, 0xa6, 0xf5, 0xe5, 0x67, 0x3a, 0x08, 0x1d, 0x70, 0xcc, 0xe7, 0xac, 0xfc, 0x48},
+ },
+}
+
+func TestHKDF(t *testing.T) {
+ for i, tt := range hkdfTests {
+ prk := hkdfExtract(tt.hash.New, tt.salt, tt.ikm)
+ if !bytes.Equal(prk, tt.prk) {
+ t.Errorf("%d. got hkdfExtract(%x, %x) = %x; wanted %x", i+1, tt.salt, tt.ikm, prk, tt.prk)
+ }
+
+ okm := hkdfExpand(tt.hash.New, tt.prk, tt.info, len(tt.okm))
+ if !bytes.Equal(okm, tt.okm) {
+ t.Errorf("%d. got hkdfExpand(%x, %x, %d) = %x; wanted %x", i+1, tt.prk, tt.info, len(tt.okm), okm, tt.okm)
+ }
+ }
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/key.pem b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/key.pem
new file mode 100644
index 000000000..aeba1865d
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC6C9qEGRIBQXV8
+Lj29vVu+U+tyXzSSinWIumK5ijPhCm3DLnv4RayxkFwemtnkGRZ/o94ZnsXkBfU/
+IlsYdkuq8wK9WI/ql3gwWjH+KARIhIQcSLGiJcLN6kGuG2nlRBKMcPgPiEq2B0yB
+XFf4tG3CBbeae7+8G7uvOmv8NLyKj32neWpnUCTL5o2VwyPoxjLxT5gUR69v9XSV
+Fj2irCZbsEedeKSb++LqyMhLfnRTzNv+ZHNh4izZHrktR25MvnT5QyBq32hx7AjZ
+2/xo70OmH7w10a2DwsVjJNMdxTEmgyvU9M6CeYRPX1Ykfg+sXCTtkTVAlBDUviIq
+Y95CKy25AgMBAAECggEAHPvvxRiqx2tNRFVn5QF1I4erbJwMcrADc5OmAcXYIz0e
+sIOzaJBiQR9+Wn5BZ9nIuYXr+g3UQpvzAyz1CDCVxUIqsRj1AtUqMk4675+IW0vZ
+0RY6Jkq/uJjANsGqk78xLJQE8VaIXSdx8c1THznsx4dgfT6+Ni4T5U6yuA33OZaw
+4NdYZYtEkqNiqK6VYe4mAxxVh5qscihVVMGkBVqJNiiEotctm1lph8ow+7o8ggXO
+W9xm+RHHPcH7Epx7hjkb/helANcYOK950W5/R+2zWV9R6kxo6R+/hfGFFmCvl4k5
++i8Y0IlEv3fze1E0Lwyf379i3C/cKcuaE5gwR54BAQKBgQDxlsNy9M37HgguglHt
+8W+cuPNtxNjFCWIjNR9dSvdr1Oi28Z1AY+BBPSv6UBKnT5PpOFjqxfMY/j/zoKdI
+aYX1phgeQHXcHrB1pS8yoaF/pTJSN2Yb8v9kl/Ch1yeYXaNVGmeBLkH9H6wIcUxD
+Mas1i8VUzshzhcluCNGoJj9wUQKBgQDFJOoWncssfWCrsuDWEoeU71Zh3+bD96GF
+s29CdIbHpcbxhWYjA9RM8yxbGPopexzoGcV1HX6j8E1s0xfYZJV23rxoM9Zj9l5D
+mZAJQPxYXIdu3h4PslhZLd3p+DEHjbsLC/avk3M4iZim1FMPBJMswKSL23ysqXoY
+/ynor+W06QKBgHYeu6M6NHgCYAe1ai+Hq4WaHFNgOohkJRqHv7USkVSkvb+s9LDl
+5GChcx4pBmXNj8ko5rirXkerEEOjGgdaqMfJlOM9qyKb0rVCtYfw5RCPCcKPGZqy
+vdJGQ74tf0uNBO34QgE0R8lmMevS0XHNGCPPGgV0MSfikvD82N15De1xAoGAbsZM
+RsMJfAlDPZc4oPEuf/BwMHTYPTsy5map2MSTSzGKdQHJH1myfD6TqOiDALXtyzlX
+63PUShfn2YNPvcbe+Tk00rR1/htcYk2yUpDSenAbpZ9ncth6rjmInURZgG4SMKXb
+SlLnBljCjtN1jFW8wQPKMc/14SslsVAHY3ka8KkCgYB58QNT1YfH3jS62+mT2pXq
+qLjLqvsD742VYnFoHR+HBOnN8ry0dda4lgwM106L5FgSg9DOZvASZ+QGFk+QVQv+
+c77ASWpuhmBmamZCrwZXrq9Xc92RDPkKFqnP9MVv06hYKNp0moSdM8dIaM6uSows
+/r/aDs4oudubz26o5GDKmA==
+-----END PRIVATE KEY-----
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/key_agreement.go b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/key_agreement.go
new file mode 100644
index 000000000..8aa91186d
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/key_agreement.go
@@ -0,0 +1,853 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runner
+
+import (
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "crypto/rand"
+ "crypto/rsa"
+ "crypto/subtle"
+ "crypto/x509"
+ "errors"
+ "fmt"
+ "io"
+ "math/big"
+
+ "./curve25519"
+)
+
+type keyType int
+
+const (
+ keyTypeRSA keyType = iota + 1
+ keyTypeECDSA
+)
+
+var errClientKeyExchange = errors.New("tls: invalid ClientKeyExchange message")
+var errServerKeyExchange = errors.New("tls: invalid ServerKeyExchange message")
+
+// rsaKeyAgreement implements the standard TLS key agreement where the client
+// encrypts the pre-master secret to the server's public key.
+type rsaKeyAgreement struct {
+ version uint16
+ clientVersion uint16
+ exportKey *rsa.PrivateKey
+}
+
+func (ka *rsaKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) {
+ // Save the client version for comparison later.
+ ka.clientVersion = clientHello.vers
+
+ if !config.Bugs.RSAEphemeralKey {
+ return nil, nil
+ }
+
+ // Generate an ephemeral RSA key to use instead of the real
+ // one, as in RSA_EXPORT.
+ key, err := rsa.GenerateKey(config.rand(), 512)
+ if err != nil {
+ return nil, err
+ }
+ ka.exportKey = key
+
+ modulus := key.N.Bytes()
+ exponent := big.NewInt(int64(key.E)).Bytes()
+ serverRSAParams := make([]byte, 0, 2+len(modulus)+2+len(exponent))
+ serverRSAParams = append(serverRSAParams, byte(len(modulus)>>8), byte(len(modulus)))
+ serverRSAParams = append(serverRSAParams, modulus...)
+ serverRSAParams = append(serverRSAParams, byte(len(exponent)>>8), byte(len(exponent)))
+ serverRSAParams = append(serverRSAParams, exponent...)
+
+ var sigAlg signatureAlgorithm
+ if ka.version >= VersionTLS12 {
+ sigAlg, err = selectSignatureAlgorithm(ka.version, cert.PrivateKey, config, clientHello.signatureAlgorithms)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ sig, err := signMessage(ka.version, cert.PrivateKey, config, sigAlg, serverRSAParams)
+ if err != nil {
+ return nil, errors.New("failed to sign RSA parameters: " + err.Error())
+ }
+
+ skx := new(serverKeyExchangeMsg)
+ sigAlgsLen := 0
+ if ka.version >= VersionTLS12 {
+ sigAlgsLen = 2
+ }
+ skx.key = make([]byte, len(serverRSAParams)+sigAlgsLen+2+len(sig))
+ copy(skx.key, serverRSAParams)
+ k := skx.key[len(serverRSAParams):]
+ if ka.version >= VersionTLS12 {
+ k[0] = byte(sigAlg >> 8)
+ k[1] = byte(sigAlg)
+ k = k[2:]
+ }
+ k[0] = byte(len(sig) >> 8)
+ k[1] = byte(len(sig))
+ copy(k[2:], sig)
+
+ return skx, nil
+}
+
+func (ka *rsaKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
+ preMasterSecret := make([]byte, 48)
+ _, err := io.ReadFull(config.rand(), preMasterSecret[2:])
+ if err != nil {
+ return nil, err
+ }
+
+ if len(ckx.ciphertext) < 2 {
+ return nil, errClientKeyExchange
+ }
+
+ ciphertext := ckx.ciphertext
+ if version != VersionSSL30 {
+ ciphertextLen := int(ckx.ciphertext[0])<<8 | int(ckx.ciphertext[1])
+ if ciphertextLen != len(ckx.ciphertext)-2 {
+ return nil, errClientKeyExchange
+ }
+ ciphertext = ckx.ciphertext[2:]
+ }
+
+ key := cert.PrivateKey.(*rsa.PrivateKey)
+ if ka.exportKey != nil {
+ key = ka.exportKey
+ }
+ err = rsa.DecryptPKCS1v15SessionKey(config.rand(), key, ciphertext, preMasterSecret)
+ if err != nil {
+ return nil, err
+ }
+ // This check should be done in constant-time, but this is a testing
+ // implementation. See the discussion at the end of section 7.4.7.1 of
+ // RFC 4346.
+ vers := uint16(preMasterSecret[0])<<8 | uint16(preMasterSecret[1])
+ if ka.clientVersion != vers {
+ return nil, fmt.Errorf("tls: invalid version in RSA premaster (got %04x, wanted %04x)", vers, ka.clientVersion)
+ }
+ return preMasterSecret, nil
+}
+
+func (ka *rsaKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error {
+ return errors.New("tls: unexpected ServerKeyExchange")
+}
+
+func (ka *rsaKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) {
+ bad := config.Bugs.BadRSAClientKeyExchange
+ preMasterSecret := make([]byte, 48)
+ vers := clientHello.vers
+ if bad == RSABadValueWrongVersion {
+ vers ^= 1
+ }
+ preMasterSecret[0] = byte(vers >> 8)
+ preMasterSecret[1] = byte(vers)
+ _, err := io.ReadFull(config.rand(), preMasterSecret[2:])
+ if err != nil {
+ return nil, nil, err
+ }
+
+ sentPreMasterSecret := preMasterSecret
+ if bad == RSABadValueTooLong {
+ sentPreMasterSecret = make([]byte, len(sentPreMasterSecret)+1)
+ copy(sentPreMasterSecret, preMasterSecret)
+ } else if bad == RSABadValueTooShort {
+ sentPreMasterSecret = sentPreMasterSecret[:len(sentPreMasterSecret)-1]
+ }
+
+ encrypted, err := rsa.EncryptPKCS1v15(config.rand(), cert.PublicKey.(*rsa.PublicKey), sentPreMasterSecret)
+ if err != nil {
+ return nil, nil, err
+ }
+ if bad == RSABadValueCorrupt {
+ encrypted[len(encrypted)-1] ^= 1
+ // Clear the high byte to ensure |encrypted| is still below the RSA modulus.
+ encrypted[0] = 0
+ }
+ ckx := new(clientKeyExchangeMsg)
+ if clientHello.vers != VersionSSL30 {
+ ckx.ciphertext = make([]byte, len(encrypted)+2)
+ ckx.ciphertext[0] = byte(len(encrypted) >> 8)
+ ckx.ciphertext[1] = byte(len(encrypted))
+ copy(ckx.ciphertext[2:], encrypted)
+ } else {
+ ckx.ciphertext = encrypted
+ }
+ return preMasterSecret, ckx, nil
+}
+
+func (ka *rsaKeyAgreement) peerSignatureAlgorithm() signatureAlgorithm {
+ return 0
+}
+
+// A ecdhCurve is an instance of ECDH-style key agreement for TLS.
+type ecdhCurve interface {
+ // offer generates a keypair using rand. It returns the encoded |publicKey|.
+ offer(rand io.Reader) (publicKey []byte, err error)
+
+ // accept responds to the |peerKey| generated by |offer| with the acceptor's
+ // |publicKey|, and returns agreed-upon |preMasterSecret| to the acceptor.
+ accept(rand io.Reader, peerKey []byte) (publicKey []byte, preMasterSecret []byte, err error)
+
+ // finish returns the computed |preMasterSecret|, given the |peerKey|
+ // generated by |accept|.
+ finish(peerKey []byte) (preMasterSecret []byte, err error)
+}
+
+// ellipticECDHCurve implements ecdhCurve with an elliptic.Curve.
+type ellipticECDHCurve struct {
+ curve elliptic.Curve
+ privateKey []byte
+}
+
+func (e *ellipticECDHCurve) offer(rand io.Reader) (publicKey []byte, err error) {
+ var x, y *big.Int
+ e.privateKey, x, y, err = elliptic.GenerateKey(e.curve, rand)
+ if err != nil {
+ return nil, err
+ }
+ return elliptic.Marshal(e.curve, x, y), nil
+}
+
+func (e *ellipticECDHCurve) accept(rand io.Reader, peerKey []byte) (publicKey []byte, preMasterSecret []byte, err error) {
+ publicKey, err = e.offer(rand)
+ if err != nil {
+ return nil, nil, err
+ }
+ preMasterSecret, err = e.finish(peerKey)
+ if err != nil {
+ return nil, nil, err
+ }
+ return
+}
+
+func (e *ellipticECDHCurve) finish(peerKey []byte) (preMasterSecret []byte, err error) {
+ x, y := elliptic.Unmarshal(e.curve, peerKey)
+ if x == nil {
+ return nil, errors.New("tls: invalid peer key")
+ }
+ x, _ = e.curve.ScalarMult(x, y, e.privateKey)
+ preMasterSecret = make([]byte, (e.curve.Params().BitSize+7)>>3)
+ xBytes := x.Bytes()
+ copy(preMasterSecret[len(preMasterSecret)-len(xBytes):], xBytes)
+
+ return preMasterSecret, nil
+}
+
+// x25519ECDHCurve implements ecdhCurve with X25519.
+type x25519ECDHCurve struct {
+ privateKey [32]byte
+}
+
+func (e *x25519ECDHCurve) offer(rand io.Reader) (publicKey []byte, err error) {
+ _, err = io.ReadFull(rand, e.privateKey[:])
+ if err != nil {
+ return
+ }
+ var out [32]byte
+ curve25519.ScalarBaseMult(&out, &e.privateKey)
+ return out[:], nil
+}
+
+func (e *x25519ECDHCurve) accept(rand io.Reader, peerKey []byte) (publicKey []byte, preMasterSecret []byte, err error) {
+ publicKey, err = e.offer(rand)
+ if err != nil {
+ return nil, nil, err
+ }
+ preMasterSecret, err = e.finish(peerKey)
+ if err != nil {
+ return nil, nil, err
+ }
+ return
+}
+
+func (e *x25519ECDHCurve) finish(peerKey []byte) (preMasterSecret []byte, err error) {
+ if len(peerKey) != 32 {
+ return nil, errors.New("tls: invalid peer key")
+ }
+ var out, peerKeyCopy [32]byte
+ copy(peerKeyCopy[:], peerKey)
+ curve25519.ScalarMult(&out, &e.privateKey, &peerKeyCopy)
+
+ // Per RFC 7748, reject the all-zero value in constant time.
+ var zeros [32]byte
+ if subtle.ConstantTimeCompare(zeros[:], out[:]) == 1 {
+ return nil, errors.New("tls: X25519 value with wrong order")
+ }
+
+ return out[:], nil
+}
+
+func curveForCurveID(id CurveID) (ecdhCurve, bool) {
+ switch id {
+ case CurveP224:
+ return &ellipticECDHCurve{curve: elliptic.P224()}, true
+ case CurveP256:
+ return &ellipticECDHCurve{curve: elliptic.P256()}, true
+ case CurveP384:
+ return &ellipticECDHCurve{curve: elliptic.P384()}, true
+ case CurveP521:
+ return &ellipticECDHCurve{curve: elliptic.P521()}, true
+ case CurveX25519:
+ return &x25519ECDHCurve{}, true
+ default:
+ return nil, false
+ }
+
+}
+
+// keyAgreementAuthentication is a helper interface that specifies how
+// to authenticate the ServerKeyExchange parameters.
+type keyAgreementAuthentication interface {
+ signParameters(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg, params []byte) (*serverKeyExchangeMsg, error)
+ verifyParameters(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, params []byte, sig []byte) error
+}
+
+// nilKeyAgreementAuthentication does not authenticate the key
+// agreement parameters.
+type nilKeyAgreementAuthentication struct{}
+
+func (ka *nilKeyAgreementAuthentication) signParameters(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg, params []byte) (*serverKeyExchangeMsg, error) {
+ skx := new(serverKeyExchangeMsg)
+ skx.key = params
+ return skx, nil
+}
+
+func (ka *nilKeyAgreementAuthentication) verifyParameters(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, params []byte, sig []byte) error {
+ return nil
+}
+
+// signedKeyAgreement signs the ServerKeyExchange parameters with the
+// server's private key.
+type signedKeyAgreement struct {
+ keyType keyType
+ version uint16
+ peerSignatureAlgorithm signatureAlgorithm
+}
+
+func (ka *signedKeyAgreement) signParameters(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg, params []byte) (*serverKeyExchangeMsg, error) {
+ // The message to be signed is prepended by the randoms.
+ var msg []byte
+ msg = append(msg, clientHello.random...)
+ msg = append(msg, hello.random...)
+ msg = append(msg, params...)
+
+ var sigAlg signatureAlgorithm
+ var err error
+ if ka.version >= VersionTLS12 {
+ sigAlg, err = selectSignatureAlgorithm(ka.version, cert.PrivateKey, config, clientHello.signatureAlgorithms)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ sig, err := signMessage(ka.version, cert.PrivateKey, config, sigAlg, msg)
+ if err != nil {
+ return nil, err
+ }
+ if config.Bugs.SendSignatureAlgorithm != 0 {
+ sigAlg = config.Bugs.SendSignatureAlgorithm
+ }
+
+ skx := new(serverKeyExchangeMsg)
+ if config.Bugs.UnauthenticatedECDH {
+ skx.key = params
+ } else {
+ sigAlgsLen := 0
+ if ka.version >= VersionTLS12 {
+ sigAlgsLen = 2
+ }
+ skx.key = make([]byte, len(params)+sigAlgsLen+2+len(sig))
+ copy(skx.key, params)
+ k := skx.key[len(params):]
+ if ka.version >= VersionTLS12 {
+ k[0] = byte(sigAlg >> 8)
+ k[1] = byte(sigAlg)
+ k = k[2:]
+ }
+ k[0] = byte(len(sig) >> 8)
+ k[1] = byte(len(sig))
+ copy(k[2:], sig)
+ }
+
+ return skx, nil
+}
+
+func (ka *signedKeyAgreement) verifyParameters(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, params []byte, sig []byte) error {
+ // The peer's key must match the cipher type.
+ switch ka.keyType {
+ case keyTypeECDSA:
+ _, ok := cert.PublicKey.(*ecdsa.PublicKey)
+ if !ok {
+ return errors.New("tls: ECDHE ECDSA requires a ECDSA server public key")
+ }
+ case keyTypeRSA:
+ _, ok := cert.PublicKey.(*rsa.PublicKey)
+ if !ok {
+ return errors.New("tls: ECDHE RSA requires a RSA server public key")
+ }
+ default:
+ return errors.New("tls: unknown key type")
+ }
+
+ // The message to be signed is prepended by the randoms.
+ var msg []byte
+ msg = append(msg, clientHello.random...)
+ msg = append(msg, serverHello.random...)
+ msg = append(msg, params...)
+
+ var sigAlg signatureAlgorithm
+ if ka.version >= VersionTLS12 {
+ if len(sig) < 2 {
+ return errServerKeyExchange
+ }
+ sigAlg = signatureAlgorithm(sig[0])<<8 | signatureAlgorithm(sig[1])
+ sig = sig[2:]
+ // Stash the signature algorithm to be extracted by the handshake.
+ ka.peerSignatureAlgorithm = sigAlg
+ }
+
+ if len(sig) < 2 {
+ return errServerKeyExchange
+ }
+ sigLen := int(sig[0])<<8 | int(sig[1])
+ if sigLen+2 != len(sig) {
+ return errServerKeyExchange
+ }
+ sig = sig[2:]
+
+ return verifyMessage(ka.version, cert.PublicKey, config, sigAlg, msg, sig)
+}
+
+// ecdheKeyAgreement implements a TLS key agreement where the server
+// generates a ephemeral EC public/private key pair and signs it. The
+// pre-master secret is then calculated using ECDH. The signature may
+// either be ECDSA or RSA.
+type ecdheKeyAgreement struct {
+ auth keyAgreementAuthentication
+ curve ecdhCurve
+ curveID CurveID
+ peerKey []byte
+}
+
+func (ka *ecdheKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) {
+ var curveid CurveID
+ preferredCurves := config.curvePreferences()
+
+NextCandidate:
+ for _, candidate := range preferredCurves {
+ for _, c := range clientHello.supportedCurves {
+ if candidate == c {
+ curveid = c
+ break NextCandidate
+ }
+ }
+ }
+
+ if curveid == 0 {
+ return nil, errors.New("tls: no supported elliptic curves offered")
+ }
+
+ var ok bool
+ if ka.curve, ok = curveForCurveID(curveid); !ok {
+ return nil, errors.New("tls: preferredCurves includes unsupported curve")
+ }
+ ka.curveID = curveid
+
+ publicKey, err := ka.curve.offer(config.rand())
+ if err != nil {
+ return nil, err
+ }
+
+ // http://tools.ietf.org/html/rfc4492#section-5.4
+ serverECDHParams := make([]byte, 1+2+1+len(publicKey))
+ serverECDHParams[0] = 3 // named curve
+ if config.Bugs.SendCurve != 0 {
+ curveid = config.Bugs.SendCurve
+ }
+ serverECDHParams[1] = byte(curveid >> 8)
+ serverECDHParams[2] = byte(curveid)
+ serverECDHParams[3] = byte(len(publicKey))
+ copy(serverECDHParams[4:], publicKey)
+ if config.Bugs.InvalidECDHPoint {
+ serverECDHParams[4] ^= 0xff
+ }
+
+ return ka.auth.signParameters(config, cert, clientHello, hello, serverECDHParams)
+}
+
+func (ka *ecdheKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
+ if len(ckx.ciphertext) == 0 || int(ckx.ciphertext[0]) != len(ckx.ciphertext)-1 {
+ return nil, errClientKeyExchange
+ }
+ return ka.curve.finish(ckx.ciphertext[1:])
+}
+
+func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error {
+ if len(skx.key) < 4 {
+ return errServerKeyExchange
+ }
+ if skx.key[0] != 3 { // named curve
+ return errors.New("tls: server selected unsupported curve")
+ }
+ curveid := CurveID(skx.key[1])<<8 | CurveID(skx.key[2])
+ ka.curveID = curveid
+
+ var ok bool
+ if ka.curve, ok = curveForCurveID(curveid); !ok {
+ return errors.New("tls: server selected unsupported curve")
+ }
+
+ publicLen := int(skx.key[3])
+ if publicLen+4 > len(skx.key) {
+ return errServerKeyExchange
+ }
+ // Save the peer key for later.
+ ka.peerKey = skx.key[4 : 4+publicLen]
+
+ // Check the signature.
+ serverECDHParams := skx.key[:4+publicLen]
+ sig := skx.key[4+publicLen:]
+ return ka.auth.verifyParameters(config, clientHello, serverHello, cert, serverECDHParams, sig)
+}
+
+func (ka *ecdheKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) {
+ if ka.curve == nil {
+ return nil, nil, errors.New("missing ServerKeyExchange message")
+ }
+
+ publicKey, preMasterSecret, err := ka.curve.accept(config.rand(), ka.peerKey)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ ckx := new(clientKeyExchangeMsg)
+ ckx.ciphertext = make([]byte, 1+len(publicKey))
+ ckx.ciphertext[0] = byte(len(publicKey))
+ copy(ckx.ciphertext[1:], publicKey)
+ if config.Bugs.InvalidECDHPoint {
+ ckx.ciphertext[1] ^= 0xff
+ }
+
+ return preMasterSecret, ckx, nil
+}
+
+func (ka *ecdheKeyAgreement) peerSignatureAlgorithm() signatureAlgorithm {
+ if auth, ok := ka.auth.(*signedKeyAgreement); ok {
+ return auth.peerSignatureAlgorithm
+ }
+ return 0
+}
+
+// dheRSAKeyAgreement implements a TLS key agreement where the server generates
+// an ephemeral Diffie-Hellman public/private key pair and signs it. The
+// pre-master secret is then calculated using Diffie-Hellman.
+type dheKeyAgreement struct {
+ auth keyAgreementAuthentication
+ p, g *big.Int
+ yTheirs *big.Int
+ xOurs *big.Int
+}
+
+func (ka *dheKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) {
+ var q *big.Int
+ if p := config.Bugs.DHGroupPrime; p != nil {
+ ka.p = p
+ ka.g = big.NewInt(2)
+ q = p
+ } else {
+ // 2048-bit MODP Group with 256-bit Prime Order Subgroup (RFC
+ // 5114, Section 2.3)
+ ka.p, _ = new(big.Int).SetString("87A8E61DB4B6663CFFBBD19C651959998CEEF608660DD0F25D2CEED4435E3B00E00DF8F1D61957D4FAF7DF4561B2AA3016C3D91134096FAA3BF4296D830E9A7C209E0C6497517ABD5A8A9D306BCF67ED91F9E6725B4758C022E0B1EF4275BF7B6C5BFC11D45F9088B941F54EB1E59BB8BC39A0BF12307F5C4FDB70C581B23F76B63ACAE1CAA6B7902D52526735488A0EF13C6D9A51BFA4AB3AD8347796524D8EF6A167B5A41825D967E144E5140564251CCACB83E6B486F6B3CA3F7971506026C0B857F689962856DED4010ABD0BE621C3A3960A54E710C375F26375D7014103A4B54330C198AF126116D2276E11715F693877FAD7EF09CADB094AE91E1A1597", 16)
+ ka.g, _ = new(big.Int).SetString("3FB32C9B73134D0B2E77506660EDBD484CA7B18F21EF205407F4793A1A0BA12510DBC15077BE463FFF4FED4AAC0BB555BE3A6C1B0C6B47B1BC3773BF7E8C6F62901228F8C28CBB18A55AE31341000A650196F931C77A57F2DDF463E5E9EC144B777DE62AAAB8A8628AC376D282D6ED3864E67982428EBC831D14348F6F2F9193B5045AF2767164E1DFC967C1FB3F2E55A4BD1BFFE83B9C80D052B985D182EA0ADB2A3B7313D3FE14C8484B1E052588B9B7D2BBD2DF016199ECD06E1557CD0915B3353BBB64E0EC377FD028370DF92B52C7891428CDC67EB6184B523D1DB246C32F63078490F00EF8D647D148D47954515E2327CFEF98C582664B4C0F6CC41659", 16)
+ q, _ = new(big.Int).SetString("8CF83642A709A097B447997640129DA299B1A47D1EB3750BA308B0FE64F5FBD3", 16)
+ }
+
+ var err error
+ ka.xOurs, err = rand.Int(config.rand(), q)
+ if err != nil {
+ return nil, err
+ }
+ yOurs := new(big.Int).Exp(ka.g, ka.xOurs, ka.p)
+
+ // http://tools.ietf.org/html/rfc5246#section-7.4.3
+ pBytes := ka.p.Bytes()
+ gBytes := ka.g.Bytes()
+ yBytes := yOurs.Bytes()
+ serverDHParams := make([]byte, 0, 2+len(pBytes)+2+len(gBytes)+2+len(yBytes))
+ serverDHParams = append(serverDHParams, byte(len(pBytes)>>8), byte(len(pBytes)))
+ serverDHParams = append(serverDHParams, pBytes...)
+ serverDHParams = append(serverDHParams, byte(len(gBytes)>>8), byte(len(gBytes)))
+ serverDHParams = append(serverDHParams, gBytes...)
+ serverDHParams = append(serverDHParams, byte(len(yBytes)>>8), byte(len(yBytes)))
+ serverDHParams = append(serverDHParams, yBytes...)
+
+ return ka.auth.signParameters(config, cert, clientHello, hello, serverDHParams)
+}
+
+func (ka *dheKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
+ if len(ckx.ciphertext) < 2 {
+ return nil, errClientKeyExchange
+ }
+ yLen := (int(ckx.ciphertext[0]) << 8) | int(ckx.ciphertext[1])
+ if yLen != len(ckx.ciphertext)-2 {
+ return nil, errClientKeyExchange
+ }
+ yTheirs := new(big.Int).SetBytes(ckx.ciphertext[2:])
+ if yTheirs.Sign() <= 0 || yTheirs.Cmp(ka.p) >= 0 {
+ return nil, errClientKeyExchange
+ }
+ return new(big.Int).Exp(yTheirs, ka.xOurs, ka.p).Bytes(), nil
+}
+
+func (ka *dheKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error {
+ // Read dh_p
+ k := skx.key
+ if len(k) < 2 {
+ return errServerKeyExchange
+ }
+ pLen := (int(k[0]) << 8) | int(k[1])
+ k = k[2:]
+ if len(k) < pLen {
+ return errServerKeyExchange
+ }
+ ka.p = new(big.Int).SetBytes(k[:pLen])
+ k = k[pLen:]
+
+ // Read dh_g
+ if len(k) < 2 {
+ return errServerKeyExchange
+ }
+ gLen := (int(k[0]) << 8) | int(k[1])
+ k = k[2:]
+ if len(k) < gLen {
+ return errServerKeyExchange
+ }
+ ka.g = new(big.Int).SetBytes(k[:gLen])
+ k = k[gLen:]
+
+ // Read dh_Ys
+ if len(k) < 2 {
+ return errServerKeyExchange
+ }
+ yLen := (int(k[0]) << 8) | int(k[1])
+ k = k[2:]
+ if len(k) < yLen {
+ return errServerKeyExchange
+ }
+ ka.yTheirs = new(big.Int).SetBytes(k[:yLen])
+ k = k[yLen:]
+ if ka.yTheirs.Sign() <= 0 || ka.yTheirs.Cmp(ka.p) >= 0 {
+ return errServerKeyExchange
+ }
+
+ if l := config.Bugs.RequireDHPublicValueLen; l != 0 && l != yLen {
+ return fmt.Errorf("RequireDHPublicValueLen set to %d, but server's public value was %d bytes on the wire and %d bytes if minimal", l, yLen, (ka.yTheirs.BitLen()+7)/8)
+ }
+
+ sig := k
+ serverDHParams := skx.key[:len(skx.key)-len(sig)]
+
+ return ka.auth.verifyParameters(config, clientHello, serverHello, cert, serverDHParams, sig)
+}
+
+func (ka *dheKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) {
+ if ka.p == nil || ka.g == nil || ka.yTheirs == nil {
+ return nil, nil, errors.New("missing ServerKeyExchange message")
+ }
+
+ xOurs, err := rand.Int(config.rand(), ka.p)
+ if err != nil {
+ return nil, nil, err
+ }
+ preMasterSecret := new(big.Int).Exp(ka.yTheirs, xOurs, ka.p).Bytes()
+
+ yOurs := new(big.Int).Exp(ka.g, xOurs, ka.p)
+ yBytes := yOurs.Bytes()
+ ckx := new(clientKeyExchangeMsg)
+ ckx.ciphertext = make([]byte, 2+len(yBytes))
+ ckx.ciphertext[0] = byte(len(yBytes) >> 8)
+ ckx.ciphertext[1] = byte(len(yBytes))
+ copy(ckx.ciphertext[2:], yBytes)
+
+ return preMasterSecret, ckx, nil
+}
+
+func (ka *dheKeyAgreement) peerSignatureAlgorithm() signatureAlgorithm {
+ if auth, ok := ka.auth.(*signedKeyAgreement); ok {
+ return auth.peerSignatureAlgorithm
+ }
+ return 0
+}
+
+// nilKeyAgreement is a fake key agreement used to implement the plain PSK key
+// exchange.
+type nilKeyAgreement struct{}
+
+func (ka *nilKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) {
+ return nil, nil
+}
+
+func (ka *nilKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
+ if len(ckx.ciphertext) != 0 {
+ return nil, errClientKeyExchange
+ }
+
+ // Although in plain PSK, otherSecret is all zeros, the base key
+ // agreement does not access to the length of the pre-shared
+ // key. pskKeyAgreement instead interprets nil to mean to use all zeros
+ // of the appropriate length.
+ return nil, nil
+}
+
+func (ka *nilKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error {
+ if len(skx.key) != 0 {
+ return errServerKeyExchange
+ }
+ return nil
+}
+
+func (ka *nilKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) {
+ // Although in plain PSK, otherSecret is all zeros, the base key
+ // agreement does not access to the length of the pre-shared
+ // key. pskKeyAgreement instead interprets nil to mean to use all zeros
+ // of the appropriate length.
+ return nil, &clientKeyExchangeMsg{}, nil
+}
+
+func (ka *nilKeyAgreement) peerSignatureAlgorithm() signatureAlgorithm {
+ return 0
+}
+
+// makePSKPremaster formats a PSK pre-master secret based on otherSecret from
+// the base key exchange and psk.
+func makePSKPremaster(otherSecret, psk []byte) []byte {
+ out := make([]byte, 0, 2+len(otherSecret)+2+len(psk))
+ out = append(out, byte(len(otherSecret)>>8), byte(len(otherSecret)))
+ out = append(out, otherSecret...)
+ out = append(out, byte(len(psk)>>8), byte(len(psk)))
+ out = append(out, psk...)
+ return out
+}
+
+// pskKeyAgreement implements the PSK key agreement.
+type pskKeyAgreement struct {
+ base keyAgreement
+ identityHint string
+}
+
+func (ka *pskKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) {
+ // Assemble the identity hint.
+ bytes := make([]byte, 2+len(config.PreSharedKeyIdentity))
+ bytes[0] = byte(len(config.PreSharedKeyIdentity) >> 8)
+ bytes[1] = byte(len(config.PreSharedKeyIdentity))
+ copy(bytes[2:], []byte(config.PreSharedKeyIdentity))
+
+ // If there is one, append the base key agreement's
+ // ServerKeyExchange.
+ baseSkx, err := ka.base.generateServerKeyExchange(config, cert, clientHello, hello)
+ if err != nil {
+ return nil, err
+ }
+
+ if baseSkx != nil {
+ bytes = append(bytes, baseSkx.key...)
+ } else if config.PreSharedKeyIdentity == "" && !config.Bugs.AlwaysSendPreSharedKeyIdentityHint {
+ // ServerKeyExchange is optional if the identity hint is empty
+ // and there would otherwise be no ServerKeyExchange.
+ return nil, nil
+ }
+
+ skx := new(serverKeyExchangeMsg)
+ skx.key = bytes
+ return skx, nil
+}
+
+func (ka *pskKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
+ // First, process the PSK identity.
+ if len(ckx.ciphertext) < 2 {
+ return nil, errClientKeyExchange
+ }
+ identityLen := (int(ckx.ciphertext[0]) << 8) | int(ckx.ciphertext[1])
+ if 2+identityLen > len(ckx.ciphertext) {
+ return nil, errClientKeyExchange
+ }
+ identity := string(ckx.ciphertext[2 : 2+identityLen])
+
+ if identity != config.PreSharedKeyIdentity {
+ return nil, errors.New("tls: unexpected identity")
+ }
+
+ if config.PreSharedKey == nil {
+ return nil, errors.New("tls: pre-shared key not configured")
+ }
+
+ // Process the remainder of the ClientKeyExchange to compute the base
+ // pre-master secret.
+ newCkx := new(clientKeyExchangeMsg)
+ newCkx.ciphertext = ckx.ciphertext[2+identityLen:]
+ otherSecret, err := ka.base.processClientKeyExchange(config, cert, newCkx, version)
+ if err != nil {
+ return nil, err
+ }
+
+ if otherSecret == nil {
+ // Special-case for the plain PSK key exchanges.
+ otherSecret = make([]byte, len(config.PreSharedKey))
+ }
+ return makePSKPremaster(otherSecret, config.PreSharedKey), nil
+}
+
+func (ka *pskKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error {
+ if len(skx.key) < 2 {
+ return errServerKeyExchange
+ }
+ identityLen := (int(skx.key[0]) << 8) | int(skx.key[1])
+ if 2+identityLen > len(skx.key) {
+ return errServerKeyExchange
+ }
+ ka.identityHint = string(skx.key[2 : 2+identityLen])
+
+ // Process the remainder of the ServerKeyExchange.
+ newSkx := new(serverKeyExchangeMsg)
+ newSkx.key = skx.key[2+identityLen:]
+ return ka.base.processServerKeyExchange(config, clientHello, serverHello, cert, newSkx)
+}
+
+func (ka *pskKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) {
+ // The server only sends an identity hint but, for purposes of
+ // test code, the server always sends the hint and it is
+ // required to match.
+ if ka.identityHint != config.PreSharedKeyIdentity {
+ return nil, nil, errors.New("tls: unexpected identity")
+ }
+
+ // Serialize the identity.
+ bytes := make([]byte, 2+len(config.PreSharedKeyIdentity))
+ bytes[0] = byte(len(config.PreSharedKeyIdentity) >> 8)
+ bytes[1] = byte(len(config.PreSharedKeyIdentity))
+ copy(bytes[2:], []byte(config.PreSharedKeyIdentity))
+
+ // Append the base key exchange's ClientKeyExchange.
+ otherSecret, baseCkx, err := ka.base.generateClientKeyExchange(config, clientHello, cert)
+ if err != nil {
+ return nil, nil, err
+ }
+ ckx := new(clientKeyExchangeMsg)
+ ckx.ciphertext = append(bytes, baseCkx.ciphertext...)
+
+ if config.PreSharedKey == nil {
+ return nil, nil, errors.New("tls: pre-shared key not configured")
+ }
+ if otherSecret == nil {
+ otherSecret = make([]byte, len(config.PreSharedKey))
+ }
+ return makePSKPremaster(otherSecret, config.PreSharedKey), ckx, nil
+}
+
+func (ka *pskKeyAgreement) peerSignatureAlgorithm() signatureAlgorithm {
+ return 0
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/packet_adapter.go b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/packet_adapter.go
new file mode 100644
index 000000000..a8da311bb
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/packet_adapter.go
@@ -0,0 +1,179 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runner
+
+import (
+ "encoding/binary"
+ "fmt"
+ "io"
+ "net"
+ "time"
+)
+
+// opcodePacket signals a packet, encoded with a 32-bit length prefix, followed
+// by the payload.
+const opcodePacket = byte('P')
+
+// opcodeTimeout signals a read timeout, encoded by a 64-bit number of
+// nanoseconds. On receipt, the peer should reply with
+// opcodeTimeoutAck. opcodeTimeout may only be sent by the Go side.
+const opcodeTimeout = byte('T')
+
+// opcodeTimeoutAck acknowledges a read timeout. This opcode has no payload and
+// may only be sent by the C side. Timeout ACKs act as a synchronization point
+// at the timeout, to bracket one flight of messages from C.
+const opcodeTimeoutAck = byte('t')
+
+type packetAdaptor struct {
+ net.Conn
+ debug *recordingConn
+}
+
+// newPacketAdaptor wraps a reliable streaming net.Conn into a reliable
+// packet-based net.Conn. The stream contains packets and control commands,
+// distinguished by a one byte opcode.
+func newPacketAdaptor(conn net.Conn) *packetAdaptor {
+ return &packetAdaptor{conn, nil}
+}
+
+func (p *packetAdaptor) log(message string, data []byte) {
+ if p.debug == nil {
+ return
+ }
+
+ p.debug.LogSpecial(message, data)
+}
+
+func (p *packetAdaptor) readOpcode() (byte, error) {
+ out := make([]byte, 1)
+ if _, err := io.ReadFull(p.Conn, out); err != nil {
+ return 0, err
+ }
+ return out[0], nil
+}
+
+func (p *packetAdaptor) readPacketBody() ([]byte, error) {
+ var length uint32
+ if err := binary.Read(p.Conn, binary.BigEndian, &length); err != nil {
+ return nil, err
+ }
+ out := make([]byte, length)
+ if _, err := io.ReadFull(p.Conn, out); err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (p *packetAdaptor) Read(b []byte) (int, error) {
+ opcode, err := p.readOpcode()
+ if err != nil {
+ return 0, err
+ }
+ if opcode != opcodePacket {
+ return 0, fmt.Errorf("unexpected opcode '%d'", opcode)
+ }
+ out, err := p.readPacketBody()
+ if err != nil {
+ return 0, err
+ }
+ return copy(b, out), nil
+}
+
+func (p *packetAdaptor) Write(b []byte) (int, error) {
+ payload := make([]byte, 1+4+len(b))
+ payload[0] = opcodePacket
+ binary.BigEndian.PutUint32(payload[1:5], uint32(len(b)))
+ copy(payload[5:], b)
+ if _, err := p.Conn.Write(payload); err != nil {
+ return 0, err
+ }
+ return len(b), nil
+}
+
+// SendReadTimeout instructs the peer to simulate a read timeout. It then waits
+// for acknowledgement of the timeout, buffering any packets received since
+// then. The packets are then returned.
+func (p *packetAdaptor) SendReadTimeout(d time.Duration) ([][]byte, error) {
+ p.log("Simulating read timeout: "+d.String(), nil)
+
+ payload := make([]byte, 1+8)
+ payload[0] = opcodeTimeout
+ binary.BigEndian.PutUint64(payload[1:], uint64(d.Nanoseconds()))
+ if _, err := p.Conn.Write(payload); err != nil {
+ return nil, err
+ }
+
+ var packets [][]byte
+ for {
+ opcode, err := p.readOpcode()
+ if err != nil {
+ return nil, err
+ }
+ switch opcode {
+ case opcodeTimeoutAck:
+ p.log("Received timeout ACK", nil)
+ // Done! Return the packets buffered and continue.
+ return packets, nil
+ case opcodePacket:
+ // Buffer the packet for the caller to process.
+ packet, err := p.readPacketBody()
+ if err != nil {
+ return nil, err
+ }
+ p.log("Simulating dropped packet", packet)
+ packets = append(packets, packet)
+ default:
+ return nil, fmt.Errorf("unexpected opcode '%d'", opcode)
+ }
+ }
+}
+
+type replayAdaptor struct {
+ net.Conn
+ prevWrite []byte
+}
+
+// newReplayAdaptor wraps a packeted net.Conn. It transforms it into
+// one which, after writing a packet, always replays the previous
+// write.
+func newReplayAdaptor(conn net.Conn) net.Conn {
+ return &replayAdaptor{Conn: conn}
+}
+
+func (r *replayAdaptor) Write(b []byte) (int, error) {
+ n, err := r.Conn.Write(b)
+
+ // Replay the previous packet and save the current one to
+ // replay next.
+ if r.prevWrite != nil {
+ r.Conn.Write(r.prevWrite)
+ }
+ r.prevWrite = append(r.prevWrite[:0], b...)
+
+ return n, err
+}
+
+type damageAdaptor struct {
+ net.Conn
+ damage bool
+}
+
+// newDamageAdaptor wraps a packeted net.Conn. It transforms it into one which
+// optionally damages the final byte of every Write() call.
+func newDamageAdaptor(conn net.Conn) *damageAdaptor {
+ return &damageAdaptor{Conn: conn}
+}
+
+func (d *damageAdaptor) setDamage(damage bool) {
+ d.damage = damage
+}
+
+func (d *damageAdaptor) Write(b []byte) (int, error) {
+ if d.damage && len(b) > 0 {
+ b = append([]byte{}, b...)
+ b[len(b)-1]++
+ }
+ return d.Conn.Write(b)
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/poly1305/poly1305.go b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/poly1305/poly1305.go
new file mode 100644
index 000000000..4a5f826f7
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/poly1305/poly1305.go
@@ -0,0 +1,32 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Package poly1305 implements Poly1305 one-time message authentication code as specified in http://cr.yp.to/mac/poly1305-20050329.pdf.
+
+Poly1305 is a fast, one-time authentication function. It is infeasible for an
+attacker to generate an authenticator for a message without the key. However, a
+key must only be used for a single message. Authenticating two different
+messages with the same key allows an attacker to forge authenticators for other
+messages with the same key.
+
+Poly1305 was originally coupled with AES in order to make Poly1305-AES. AES was
+used with a fixed key in order to generate one-time keys from an nonce.
+However, in this package AES isn't used and the one-time key is specified
+directly.
+*/
+package poly1305 // import "golang.org/x/crypto/poly1305"
+
+import "crypto/subtle"
+
+// TagSize is the size, in bytes, of a poly1305 authenticator.
+const TagSize = 16
+
+// Verify returns true if mac is a valid authenticator for m with the given
+// key.
+func Verify(mac *[16]byte, m []byte, key *[32]byte) bool {
+ var tmp [16]byte
+ Sum(&tmp, m, key)
+ return subtle.ConstantTimeCompare(tmp[:], mac[:]) == 1
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/poly1305/poly1305_test.go b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/poly1305/poly1305_test.go
new file mode 100644
index 000000000..b3e92310b
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/poly1305/poly1305_test.go
@@ -0,0 +1,86 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package poly1305
+
+import (
+ "bytes"
+ "testing"
+ "unsafe"
+)
+
+var testData = []struct {
+ in, k, correct []byte
+}{
+ {
+ []byte("Hello world!"),
+ []byte("this is 32-byte key for Poly1305"),
+ []byte{0xa6, 0xf7, 0x45, 0x00, 0x8f, 0x81, 0xc9, 0x16, 0xa2, 0x0d, 0xcc, 0x74, 0xee, 0xf2, 0xb2, 0xf0},
+ },
+ {
+ make([]byte, 32),
+ []byte("this is 32-byte key for Poly1305"),
+ []byte{0x49, 0xec, 0x78, 0x09, 0x0e, 0x48, 0x1e, 0xc6, 0xc2, 0x6b, 0x33, 0xb9, 0x1c, 0xcc, 0x03, 0x07},
+ },
+ {
+ make([]byte, 2007),
+ []byte("this is 32-byte key for Poly1305"),
+ []byte{0xda, 0x84, 0xbc, 0xab, 0x02, 0x67, 0x6c, 0x38, 0xcd, 0xb0, 0x15, 0x60, 0x42, 0x74, 0xc2, 0xaa},
+ },
+ {
+ make([]byte, 2007),
+ make([]byte, 32),
+ make([]byte, 16),
+ },
+}
+
+func testSum(t *testing.T, unaligned bool) {
+ var out [16]byte
+ var key [32]byte
+
+ for i, v := range testData {
+ in := v.in
+ if unaligned {
+ in = unalignBytes(in)
+ }
+ copy(key[:], v.k)
+ Sum(&out, in, &key)
+ if !bytes.Equal(out[:], v.correct) {
+ t.Errorf("%d: expected %x, got %x", i, v.correct, out[:])
+ }
+ }
+}
+
+func TestSum(t *testing.T) { testSum(t, false) }
+func TestSumUnaligned(t *testing.T) { testSum(t, true) }
+
+func benchmark(b *testing.B, size int, unaligned bool) {
+ var out [16]byte
+ var key [32]byte
+ in := make([]byte, size)
+ if unaligned {
+ in = unalignBytes(in)
+ }
+ b.SetBytes(int64(len(in)))
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ Sum(&out, in, &key)
+ }
+}
+
+func Benchmark64(b *testing.B) { benchmark(b, 64, false) }
+func Benchmark1K(b *testing.B) { benchmark(b, 1024, false) }
+func Benchmark64Unaligned(b *testing.B) { benchmark(b, 64, true) }
+func Benchmark1KUnaligned(b *testing.B) { benchmark(b, 1024, true) }
+
+func unalignBytes(in []byte) []byte {
+ out := make([]byte, len(in)+1)
+ if uintptr(unsafe.Pointer(&out[0]))&(unsafe.Alignof(uint32(0))-1) == 0 {
+ out = out[1:]
+ } else {
+ out = out[:len(in)]
+ }
+ copy(out, in)
+ return out
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/poly1305/sum_amd64.go b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/poly1305/sum_amd64.go
new file mode 100644
index 000000000..6775c703f
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/poly1305/sum_amd64.go
@@ -0,0 +1,24 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build amd64,!gccgo,!appengine
+
+package poly1305
+
+// This function is implemented in poly1305_amd64.s
+
+//go:noescape
+
+func poly1305(out *[16]byte, m *byte, mlen uint64, key *[32]byte)
+
+// Sum generates an authenticator for m using a one-time key and puts the
+// 16-byte result into out. Authenticating two different messages with the same
+// key allows an attacker to forge messages at will.
+func Sum(out *[16]byte, m []byte, key *[32]byte) {
+ var mPtr *byte
+ if len(m) > 0 {
+ mPtr = &m[0]
+ }
+ poly1305(out, mPtr, uint64(len(m)), key)
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/poly1305/sum_arm.go b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/poly1305/sum_arm.go
new file mode 100644
index 000000000..50b979c24
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/poly1305/sum_arm.go
@@ -0,0 +1,24 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build arm,!gccgo,!appengine
+
+package poly1305
+
+// This function is implemented in poly1305_arm.s
+
+//go:noescape
+
+func poly1305_auth_armv6(out *[16]byte, m *byte, mlen uint32, key *[32]byte)
+
+// Sum generates an authenticator for m using a one-time key and puts the
+// 16-byte result into out. Authenticating two different messages with the same
+// key allows an attacker to forge messages at will.
+func Sum(out *[16]byte, m []byte, key *[32]byte) {
+ var mPtr *byte
+ if len(m) > 0 {
+ mPtr = &m[0]
+ }
+ poly1305_auth_armv6(out, mPtr, uint32(len(m)), key)
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/poly1305/sum_ref.go b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/poly1305/sum_ref.go
new file mode 100644
index 000000000..0b24fc78b
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/poly1305/sum_ref.go
@@ -0,0 +1,1531 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !amd64,!arm gccgo appengine
+
+package poly1305
+
+// Based on original, public domain implementation from NaCl by D. J.
+// Bernstein.
+
+import "math"
+
+const (
+ alpham80 = 0.00000000558793544769287109375
+ alpham48 = 24.0
+ alpham16 = 103079215104.0
+ alpha0 = 6755399441055744.0
+ alpha18 = 1770887431076116955136.0
+ alpha32 = 29014219670751100192948224.0
+ alpha50 = 7605903601369376408980219232256.0
+ alpha64 = 124615124604835863084731911901282304.0
+ alpha82 = 32667107224410092492483962313449748299776.0
+ alpha96 = 535217884764734955396857238543560676143529984.0
+ alpha112 = 35076039295941670036888435985190792471742381031424.0
+ alpha130 = 9194973245195333150150082162901855101712434733101613056.0
+ scale = 0.0000000000000000000000000000000000000036734198463196484624023016788195177431833298649127735047148490821200539357960224151611328125
+ offset0 = 6755408030990331.0
+ offset1 = 29014256564239239022116864.0
+ offset2 = 124615283061160854719918951570079744.0
+ offset3 = 535219245894202480694386063513315216128475136.0
+)
+
+// Sum generates an authenticator for m using a one-time key and puts the
+// 16-byte result into out. Authenticating two different messages with the same
+// key allows an attacker to forge messages at will.
+func Sum(out *[16]byte, m []byte, key *[32]byte) {
+ r := key
+ s := key[16:]
+ var (
+ y7 float64
+ y6 float64
+ y1 float64
+ y0 float64
+ y5 float64
+ y4 float64
+ x7 float64
+ x6 float64
+ x1 float64
+ x0 float64
+ y3 float64
+ y2 float64
+ x5 float64
+ r3lowx0 float64
+ x4 float64
+ r0lowx6 float64
+ x3 float64
+ r3highx0 float64
+ x2 float64
+ r0highx6 float64
+ r0lowx0 float64
+ sr1lowx6 float64
+ r0highx0 float64
+ sr1highx6 float64
+ sr3low float64
+ r1lowx0 float64
+ sr2lowx6 float64
+ r1highx0 float64
+ sr2highx6 float64
+ r2lowx0 float64
+ sr3lowx6 float64
+ r2highx0 float64
+ sr3highx6 float64
+ r1highx4 float64
+ r1lowx4 float64
+ r0highx4 float64
+ r0lowx4 float64
+ sr3highx4 float64
+ sr3lowx4 float64
+ sr2highx4 float64
+ sr2lowx4 float64
+ r0lowx2 float64
+ r0highx2 float64
+ r1lowx2 float64
+ r1highx2 float64
+ r2lowx2 float64
+ r2highx2 float64
+ sr3lowx2 float64
+ sr3highx2 float64
+ z0 float64
+ z1 float64
+ z2 float64
+ z3 float64
+ m0 int64
+ m1 int64
+ m2 int64
+ m3 int64
+ m00 uint32
+ m01 uint32
+ m02 uint32
+ m03 uint32
+ m10 uint32
+ m11 uint32
+ m12 uint32
+ m13 uint32
+ m20 uint32
+ m21 uint32
+ m22 uint32
+ m23 uint32
+ m30 uint32
+ m31 uint32
+ m32 uint32
+ m33 uint64
+ lbelow2 int32
+ lbelow3 int32
+ lbelow4 int32
+ lbelow5 int32
+ lbelow6 int32
+ lbelow7 int32
+ lbelow8 int32
+ lbelow9 int32
+ lbelow10 int32
+ lbelow11 int32
+ lbelow12 int32
+ lbelow13 int32
+ lbelow14 int32
+ lbelow15 int32
+ s00 uint32
+ s01 uint32
+ s02 uint32
+ s03 uint32
+ s10 uint32
+ s11 uint32
+ s12 uint32
+ s13 uint32
+ s20 uint32
+ s21 uint32
+ s22 uint32
+ s23 uint32
+ s30 uint32
+ s31 uint32
+ s32 uint32
+ s33 uint32
+ bits32 uint64
+ f uint64
+ f0 uint64
+ f1 uint64
+ f2 uint64
+ f3 uint64
+ f4 uint64
+ g uint64
+ g0 uint64
+ g1 uint64
+ g2 uint64
+ g3 uint64
+ g4 uint64
+ )
+
+ var p int32
+
+ l := int32(len(m))
+
+ r00 := uint32(r[0])
+
+ r01 := uint32(r[1])
+
+ r02 := uint32(r[2])
+ r0 := int64(2151)
+
+ r03 := uint32(r[3])
+ r03 &= 15
+ r0 <<= 51
+
+ r10 := uint32(r[4])
+ r10 &= 252
+ r01 <<= 8
+ r0 += int64(r00)
+
+ r11 := uint32(r[5])
+ r02 <<= 16
+ r0 += int64(r01)
+
+ r12 := uint32(r[6])
+ r03 <<= 24
+ r0 += int64(r02)
+
+ r13 := uint32(r[7])
+ r13 &= 15
+ r1 := int64(2215)
+ r0 += int64(r03)
+
+ d0 := r0
+ r1 <<= 51
+ r2 := int64(2279)
+
+ r20 := uint32(r[8])
+ r20 &= 252
+ r11 <<= 8
+ r1 += int64(r10)
+
+ r21 := uint32(r[9])
+ r12 <<= 16
+ r1 += int64(r11)
+
+ r22 := uint32(r[10])
+ r13 <<= 24
+ r1 += int64(r12)
+
+ r23 := uint32(r[11])
+ r23 &= 15
+ r2 <<= 51
+ r1 += int64(r13)
+
+ d1 := r1
+ r21 <<= 8
+ r2 += int64(r20)
+
+ r30 := uint32(r[12])
+ r30 &= 252
+ r22 <<= 16
+ r2 += int64(r21)
+
+ r31 := uint32(r[13])
+ r23 <<= 24
+ r2 += int64(r22)
+
+ r32 := uint32(r[14])
+ r2 += int64(r23)
+ r3 := int64(2343)
+
+ d2 := r2
+ r3 <<= 51
+
+ r33 := uint32(r[15])
+ r33 &= 15
+ r31 <<= 8
+ r3 += int64(r30)
+
+ r32 <<= 16
+ r3 += int64(r31)
+
+ r33 <<= 24
+ r3 += int64(r32)
+
+ r3 += int64(r33)
+ h0 := alpha32 - alpha32
+
+ d3 := r3
+ h1 := alpha32 - alpha32
+
+ h2 := alpha32 - alpha32
+
+ h3 := alpha32 - alpha32
+
+ h4 := alpha32 - alpha32
+
+ r0low := math.Float64frombits(uint64(d0))
+ h5 := alpha32 - alpha32
+
+ r1low := math.Float64frombits(uint64(d1))
+ h6 := alpha32 - alpha32
+
+ r2low := math.Float64frombits(uint64(d2))
+ h7 := alpha32 - alpha32
+
+ r0low -= alpha0
+
+ r1low -= alpha32
+
+ r2low -= alpha64
+
+ r0high := r0low + alpha18
+
+ r3low := math.Float64frombits(uint64(d3))
+
+ r1high := r1low + alpha50
+ sr1low := scale * r1low
+
+ r2high := r2low + alpha82
+ sr2low := scale * r2low
+
+ r0high -= alpha18
+ r0high_stack := r0high
+
+ r3low -= alpha96
+
+ r1high -= alpha50
+ r1high_stack := r1high
+
+ sr1high := sr1low + alpham80
+
+ r0low -= r0high
+
+ r2high -= alpha82
+ sr3low = scale * r3low
+
+ sr2high := sr2low + alpham48
+
+ r1low -= r1high
+ r1low_stack := r1low
+
+ sr1high -= alpham80
+ sr1high_stack := sr1high
+
+ r2low -= r2high
+ r2low_stack := r2low
+
+ sr2high -= alpham48
+ sr2high_stack := sr2high
+
+ r3high := r3low + alpha112
+ r0low_stack := r0low
+
+ sr1low -= sr1high
+ sr1low_stack := sr1low
+
+ sr3high := sr3low + alpham16
+ r2high_stack := r2high
+
+ sr2low -= sr2high
+ sr2low_stack := sr2low
+
+ r3high -= alpha112
+ r3high_stack := r3high
+
+ sr3high -= alpham16
+ sr3high_stack := sr3high
+
+ r3low -= r3high
+ r3low_stack := r3low
+
+ sr3low -= sr3high
+ sr3low_stack := sr3low
+
+ if l < 16 {
+ goto addatmost15bytes
+ }
+
+ m00 = uint32(m[p+0])
+ m0 = 2151
+
+ m0 <<= 51
+ m1 = 2215
+ m01 = uint32(m[p+1])
+
+ m1 <<= 51
+ m2 = 2279
+ m02 = uint32(m[p+2])
+
+ m2 <<= 51
+ m3 = 2343
+ m03 = uint32(m[p+3])
+
+ m10 = uint32(m[p+4])
+ m01 <<= 8
+ m0 += int64(m00)
+
+ m11 = uint32(m[p+5])
+ m02 <<= 16
+ m0 += int64(m01)
+
+ m12 = uint32(m[p+6])
+ m03 <<= 24
+ m0 += int64(m02)
+
+ m13 = uint32(m[p+7])
+ m3 <<= 51
+ m0 += int64(m03)
+
+ m20 = uint32(m[p+8])
+ m11 <<= 8
+ m1 += int64(m10)
+
+ m21 = uint32(m[p+9])
+ m12 <<= 16
+ m1 += int64(m11)
+
+ m22 = uint32(m[p+10])
+ m13 <<= 24
+ m1 += int64(m12)
+
+ m23 = uint32(m[p+11])
+ m1 += int64(m13)
+
+ m30 = uint32(m[p+12])
+ m21 <<= 8
+ m2 += int64(m20)
+
+ m31 = uint32(m[p+13])
+ m22 <<= 16
+ m2 += int64(m21)
+
+ m32 = uint32(m[p+14])
+ m23 <<= 24
+ m2 += int64(m22)
+
+ m33 = uint64(m[p+15])
+ m2 += int64(m23)
+
+ d0 = m0
+ m31 <<= 8
+ m3 += int64(m30)
+
+ d1 = m1
+ m32 <<= 16
+ m3 += int64(m31)
+
+ d2 = m2
+ m33 += 256
+
+ m33 <<= 24
+ m3 += int64(m32)
+
+ m3 += int64(m33)
+ d3 = m3
+
+ p += 16
+ l -= 16
+
+ z0 = math.Float64frombits(uint64(d0))
+
+ z1 = math.Float64frombits(uint64(d1))
+
+ z2 = math.Float64frombits(uint64(d2))
+
+ z3 = math.Float64frombits(uint64(d3))
+
+ z0 -= alpha0
+
+ z1 -= alpha32
+
+ z2 -= alpha64
+
+ z3 -= alpha96
+
+ h0 += z0
+
+ h1 += z1
+
+ h3 += z2
+
+ h5 += z3
+
+ if l < 16 {
+ goto multiplyaddatmost15bytes
+ }
+
+multiplyaddatleast16bytes:
+
+ m2 = 2279
+ m20 = uint32(m[p+8])
+ y7 = h7 + alpha130
+
+ m2 <<= 51
+ m3 = 2343
+ m21 = uint32(m[p+9])
+ y6 = h6 + alpha130
+
+ m3 <<= 51
+ m0 = 2151
+ m22 = uint32(m[p+10])
+ y1 = h1 + alpha32
+
+ m0 <<= 51
+ m1 = 2215
+ m23 = uint32(m[p+11])
+ y0 = h0 + alpha32
+
+ m1 <<= 51
+ m30 = uint32(m[p+12])
+ y7 -= alpha130
+
+ m21 <<= 8
+ m2 += int64(m20)
+ m31 = uint32(m[p+13])
+ y6 -= alpha130
+
+ m22 <<= 16
+ m2 += int64(m21)
+ m32 = uint32(m[p+14])
+ y1 -= alpha32
+
+ m23 <<= 24
+ m2 += int64(m22)
+ m33 = uint64(m[p+15])
+ y0 -= alpha32
+
+ m2 += int64(m23)
+ m00 = uint32(m[p+0])
+ y5 = h5 + alpha96
+
+ m31 <<= 8
+ m3 += int64(m30)
+ m01 = uint32(m[p+1])
+ y4 = h4 + alpha96
+
+ m32 <<= 16
+ m02 = uint32(m[p+2])
+ x7 = h7 - y7
+ y7 *= scale
+
+ m33 += 256
+ m03 = uint32(m[p+3])
+ x6 = h6 - y6
+ y6 *= scale
+
+ m33 <<= 24
+ m3 += int64(m31)
+ m10 = uint32(m[p+4])
+ x1 = h1 - y1
+
+ m01 <<= 8
+ m3 += int64(m32)
+ m11 = uint32(m[p+5])
+ x0 = h0 - y0
+
+ m3 += int64(m33)
+ m0 += int64(m00)
+ m12 = uint32(m[p+6])
+ y5 -= alpha96
+
+ m02 <<= 16
+ m0 += int64(m01)
+ m13 = uint32(m[p+7])
+ y4 -= alpha96
+
+ m03 <<= 24
+ m0 += int64(m02)
+ d2 = m2
+ x1 += y7
+
+ m0 += int64(m03)
+ d3 = m3
+ x0 += y6
+
+ m11 <<= 8
+ m1 += int64(m10)
+ d0 = m0
+ x7 += y5
+
+ m12 <<= 16
+ m1 += int64(m11)
+ x6 += y4
+
+ m13 <<= 24
+ m1 += int64(m12)
+ y3 = h3 + alpha64
+
+ m1 += int64(m13)
+ d1 = m1
+ y2 = h2 + alpha64
+
+ x0 += x1
+
+ x6 += x7
+
+ y3 -= alpha64
+ r3low = r3low_stack
+
+ y2 -= alpha64
+ r0low = r0low_stack
+
+ x5 = h5 - y5
+ r3lowx0 = r3low * x0
+ r3high = r3high_stack
+
+ x4 = h4 - y4
+ r0lowx6 = r0low * x6
+ r0high = r0high_stack
+
+ x3 = h3 - y3
+ r3highx0 = r3high * x0
+ sr1low = sr1low_stack
+
+ x2 = h2 - y2
+ r0highx6 = r0high * x6
+ sr1high = sr1high_stack
+
+ x5 += y3
+ r0lowx0 = r0low * x0
+ r1low = r1low_stack
+
+ h6 = r3lowx0 + r0lowx6
+ sr1lowx6 = sr1low * x6
+ r1high = r1high_stack
+
+ x4 += y2
+ r0highx0 = r0high * x0
+ sr2low = sr2low_stack
+
+ h7 = r3highx0 + r0highx6
+ sr1highx6 = sr1high * x6
+ sr2high = sr2high_stack
+
+ x3 += y1
+ r1lowx0 = r1low * x0
+ r2low = r2low_stack
+
+ h0 = r0lowx0 + sr1lowx6
+ sr2lowx6 = sr2low * x6
+ r2high = r2high_stack
+
+ x2 += y0
+ r1highx0 = r1high * x0
+ sr3low = sr3low_stack
+
+ h1 = r0highx0 + sr1highx6
+ sr2highx6 = sr2high * x6
+ sr3high = sr3high_stack
+
+ x4 += x5
+ r2lowx0 = r2low * x0
+ z2 = math.Float64frombits(uint64(d2))
+
+ h2 = r1lowx0 + sr2lowx6
+ sr3lowx6 = sr3low * x6
+
+ x2 += x3
+ r2highx0 = r2high * x0
+ z3 = math.Float64frombits(uint64(d3))
+
+ h3 = r1highx0 + sr2highx6
+ sr3highx6 = sr3high * x6
+
+ r1highx4 = r1high * x4
+ z2 -= alpha64
+
+ h4 = r2lowx0 + sr3lowx6
+ r1lowx4 = r1low * x4
+
+ r0highx4 = r0high * x4
+ z3 -= alpha96
+
+ h5 = r2highx0 + sr3highx6
+ r0lowx4 = r0low * x4
+
+ h7 += r1highx4
+ sr3highx4 = sr3high * x4
+
+ h6 += r1lowx4
+ sr3lowx4 = sr3low * x4
+
+ h5 += r0highx4
+ sr2highx4 = sr2high * x4
+
+ h4 += r0lowx4
+ sr2lowx4 = sr2low * x4
+
+ h3 += sr3highx4
+ r0lowx2 = r0low * x2
+
+ h2 += sr3lowx4
+ r0highx2 = r0high * x2
+
+ h1 += sr2highx4
+ r1lowx2 = r1low * x2
+
+ h0 += sr2lowx4
+ r1highx2 = r1high * x2
+
+ h2 += r0lowx2
+ r2lowx2 = r2low * x2
+
+ h3 += r0highx2
+ r2highx2 = r2high * x2
+
+ h4 += r1lowx2
+ sr3lowx2 = sr3low * x2
+
+ h5 += r1highx2
+ sr3highx2 = sr3high * x2
+
+ p += 16
+ l -= 16
+ h6 += r2lowx2
+
+ h7 += r2highx2
+
+ z1 = math.Float64frombits(uint64(d1))
+ h0 += sr3lowx2
+
+ z0 = math.Float64frombits(uint64(d0))
+ h1 += sr3highx2
+
+ z1 -= alpha32
+
+ z0 -= alpha0
+
+ h5 += z3
+
+ h3 += z2
+
+ h1 += z1
+
+ h0 += z0
+
+ if l >= 16 {
+ goto multiplyaddatleast16bytes
+ }
+
+multiplyaddatmost15bytes:
+
+ y7 = h7 + alpha130
+
+ y6 = h6 + alpha130
+
+ y1 = h1 + alpha32
+
+ y0 = h0 + alpha32
+
+ y7 -= alpha130
+
+ y6 -= alpha130
+
+ y1 -= alpha32
+
+ y0 -= alpha32
+
+ y5 = h5 + alpha96
+
+ y4 = h4 + alpha96
+
+ x7 = h7 - y7
+ y7 *= scale
+
+ x6 = h6 - y6
+ y6 *= scale
+
+ x1 = h1 - y1
+
+ x0 = h0 - y0
+
+ y5 -= alpha96
+
+ y4 -= alpha96
+
+ x1 += y7
+
+ x0 += y6
+
+ x7 += y5
+
+ x6 += y4
+
+ y3 = h3 + alpha64
+
+ y2 = h2 + alpha64
+
+ x0 += x1
+
+ x6 += x7
+
+ y3 -= alpha64
+ r3low = r3low_stack
+
+ y2 -= alpha64
+ r0low = r0low_stack
+
+ x5 = h5 - y5
+ r3lowx0 = r3low * x0
+ r3high = r3high_stack
+
+ x4 = h4 - y4
+ r0lowx6 = r0low * x6
+ r0high = r0high_stack
+
+ x3 = h3 - y3
+ r3highx0 = r3high * x0
+ sr1low = sr1low_stack
+
+ x2 = h2 - y2
+ r0highx6 = r0high * x6
+ sr1high = sr1high_stack
+
+ x5 += y3
+ r0lowx0 = r0low * x0
+ r1low = r1low_stack
+
+ h6 = r3lowx0 + r0lowx6
+ sr1lowx6 = sr1low * x6
+ r1high = r1high_stack
+
+ x4 += y2
+ r0highx0 = r0high * x0
+ sr2low = sr2low_stack
+
+ h7 = r3highx0 + r0highx6
+ sr1highx6 = sr1high * x6
+ sr2high = sr2high_stack
+
+ x3 += y1
+ r1lowx0 = r1low * x0
+ r2low = r2low_stack
+
+ h0 = r0lowx0 + sr1lowx6
+ sr2lowx6 = sr2low * x6
+ r2high = r2high_stack
+
+ x2 += y0
+ r1highx0 = r1high * x0
+ sr3low = sr3low_stack
+
+ h1 = r0highx0 + sr1highx6
+ sr2highx6 = sr2high * x6
+ sr3high = sr3high_stack
+
+ x4 += x5
+ r2lowx0 = r2low * x0
+
+ h2 = r1lowx0 + sr2lowx6
+ sr3lowx6 = sr3low * x6
+
+ x2 += x3
+ r2highx0 = r2high * x0
+
+ h3 = r1highx0 + sr2highx6
+ sr3highx6 = sr3high * x6
+
+ r1highx4 = r1high * x4
+
+ h4 = r2lowx0 + sr3lowx6
+ r1lowx4 = r1low * x4
+
+ r0highx4 = r0high * x4
+
+ h5 = r2highx0 + sr3highx6
+ r0lowx4 = r0low * x4
+
+ h7 += r1highx4
+ sr3highx4 = sr3high * x4
+
+ h6 += r1lowx4
+ sr3lowx4 = sr3low * x4
+
+ h5 += r0highx4
+ sr2highx4 = sr2high * x4
+
+ h4 += r0lowx4
+ sr2lowx4 = sr2low * x4
+
+ h3 += sr3highx4
+ r0lowx2 = r0low * x2
+
+ h2 += sr3lowx4
+ r0highx2 = r0high * x2
+
+ h1 += sr2highx4
+ r1lowx2 = r1low * x2
+
+ h0 += sr2lowx4
+ r1highx2 = r1high * x2
+
+ h2 += r0lowx2
+ r2lowx2 = r2low * x2
+
+ h3 += r0highx2
+ r2highx2 = r2high * x2
+
+ h4 += r1lowx2
+ sr3lowx2 = sr3low * x2
+
+ h5 += r1highx2
+ sr3highx2 = sr3high * x2
+
+ h6 += r2lowx2
+
+ h7 += r2highx2
+
+ h0 += sr3lowx2
+
+ h1 += sr3highx2
+
+addatmost15bytes:
+
+ if l == 0 {
+ goto nomorebytes
+ }
+
+ lbelow2 = l - 2
+
+ lbelow3 = l - 3
+
+ lbelow2 >>= 31
+ lbelow4 = l - 4
+
+ m00 = uint32(m[p+0])
+ lbelow3 >>= 31
+ p += lbelow2
+
+ m01 = uint32(m[p+1])
+ lbelow4 >>= 31
+ p += lbelow3
+
+ m02 = uint32(m[p+2])
+ p += lbelow4
+ m0 = 2151
+
+ m03 = uint32(m[p+3])
+ m0 <<= 51
+ m1 = 2215
+
+ m0 += int64(m00)
+ m01 &^= uint32(lbelow2)
+
+ m02 &^= uint32(lbelow3)
+ m01 -= uint32(lbelow2)
+
+ m01 <<= 8
+ m03 &^= uint32(lbelow4)
+
+ m0 += int64(m01)
+ lbelow2 -= lbelow3
+
+ m02 += uint32(lbelow2)
+ lbelow3 -= lbelow4
+
+ m02 <<= 16
+ m03 += uint32(lbelow3)
+
+ m03 <<= 24
+ m0 += int64(m02)
+
+ m0 += int64(m03)
+ lbelow5 = l - 5
+
+ lbelow6 = l - 6
+ lbelow7 = l - 7
+
+ lbelow5 >>= 31
+ lbelow8 = l - 8
+
+ lbelow6 >>= 31
+ p += lbelow5
+
+ m10 = uint32(m[p+4])
+ lbelow7 >>= 31
+ p += lbelow6
+
+ m11 = uint32(m[p+5])
+ lbelow8 >>= 31
+ p += lbelow7
+
+ m12 = uint32(m[p+6])
+ m1 <<= 51
+ p += lbelow8
+
+ m13 = uint32(m[p+7])
+ m10 &^= uint32(lbelow5)
+ lbelow4 -= lbelow5
+
+ m10 += uint32(lbelow4)
+ lbelow5 -= lbelow6
+
+ m11 &^= uint32(lbelow6)
+ m11 += uint32(lbelow5)
+
+ m11 <<= 8
+ m1 += int64(m10)
+
+ m1 += int64(m11)
+ m12 &^= uint32(lbelow7)
+
+ lbelow6 -= lbelow7
+ m13 &^= uint32(lbelow8)
+
+ m12 += uint32(lbelow6)
+ lbelow7 -= lbelow8
+
+ m12 <<= 16
+ m13 += uint32(lbelow7)
+
+ m13 <<= 24
+ m1 += int64(m12)
+
+ m1 += int64(m13)
+ m2 = 2279
+
+ lbelow9 = l - 9
+ m3 = 2343
+
+ lbelow10 = l - 10
+ lbelow11 = l - 11
+
+ lbelow9 >>= 31
+ lbelow12 = l - 12
+
+ lbelow10 >>= 31
+ p += lbelow9
+
+ m20 = uint32(m[p+8])
+ lbelow11 >>= 31
+ p += lbelow10
+
+ m21 = uint32(m[p+9])
+ lbelow12 >>= 31
+ p += lbelow11
+
+ m22 = uint32(m[p+10])
+ m2 <<= 51
+ p += lbelow12
+
+ m23 = uint32(m[p+11])
+ m20 &^= uint32(lbelow9)
+ lbelow8 -= lbelow9
+
+ m20 += uint32(lbelow8)
+ lbelow9 -= lbelow10
+
+ m21 &^= uint32(lbelow10)
+ m21 += uint32(lbelow9)
+
+ m21 <<= 8
+ m2 += int64(m20)
+
+ m2 += int64(m21)
+ m22 &^= uint32(lbelow11)
+
+ lbelow10 -= lbelow11
+ m23 &^= uint32(lbelow12)
+
+ m22 += uint32(lbelow10)
+ lbelow11 -= lbelow12
+
+ m22 <<= 16
+ m23 += uint32(lbelow11)
+
+ m23 <<= 24
+ m2 += int64(m22)
+
+ m3 <<= 51
+ lbelow13 = l - 13
+
+ lbelow13 >>= 31
+ lbelow14 = l - 14
+
+ lbelow14 >>= 31
+ p += lbelow13
+ lbelow15 = l - 15
+
+ m30 = uint32(m[p+12])
+ lbelow15 >>= 31
+ p += lbelow14
+
+ m31 = uint32(m[p+13])
+ p += lbelow15
+ m2 += int64(m23)
+
+ m32 = uint32(m[p+14])
+ m30 &^= uint32(lbelow13)
+ lbelow12 -= lbelow13
+
+ m30 += uint32(lbelow12)
+ lbelow13 -= lbelow14
+
+ m3 += int64(m30)
+ m31 &^= uint32(lbelow14)
+
+ m31 += uint32(lbelow13)
+ m32 &^= uint32(lbelow15)
+
+ m31 <<= 8
+ lbelow14 -= lbelow15
+
+ m3 += int64(m31)
+ m32 += uint32(lbelow14)
+ d0 = m0
+
+ m32 <<= 16
+ m33 = uint64(lbelow15 + 1)
+ d1 = m1
+
+ m33 <<= 24
+ m3 += int64(m32)
+ d2 = m2
+
+ m3 += int64(m33)
+ d3 = m3
+
+ z3 = math.Float64frombits(uint64(d3))
+
+ z2 = math.Float64frombits(uint64(d2))
+
+ z1 = math.Float64frombits(uint64(d1))
+
+ z0 = math.Float64frombits(uint64(d0))
+
+ z3 -= alpha96
+
+ z2 -= alpha64
+
+ z1 -= alpha32
+
+ z0 -= alpha0
+
+ h5 += z3
+
+ h3 += z2
+
+ h1 += z1
+
+ h0 += z0
+
+ y7 = h7 + alpha130
+
+ y6 = h6 + alpha130
+
+ y1 = h1 + alpha32
+
+ y0 = h0 + alpha32
+
+ y7 -= alpha130
+
+ y6 -= alpha130
+
+ y1 -= alpha32
+
+ y0 -= alpha32
+
+ y5 = h5 + alpha96
+
+ y4 = h4 + alpha96
+
+ x7 = h7 - y7
+ y7 *= scale
+
+ x6 = h6 - y6
+ y6 *= scale
+
+ x1 = h1 - y1
+
+ x0 = h0 - y0
+
+ y5 -= alpha96
+
+ y4 -= alpha96
+
+ x1 += y7
+
+ x0 += y6
+
+ x7 += y5
+
+ x6 += y4
+
+ y3 = h3 + alpha64
+
+ y2 = h2 + alpha64
+
+ x0 += x1
+
+ x6 += x7
+
+ y3 -= alpha64
+ r3low = r3low_stack
+
+ y2 -= alpha64
+ r0low = r0low_stack
+
+ x5 = h5 - y5
+ r3lowx0 = r3low * x0
+ r3high = r3high_stack
+
+ x4 = h4 - y4
+ r0lowx6 = r0low * x6
+ r0high = r0high_stack
+
+ x3 = h3 - y3
+ r3highx0 = r3high * x0
+ sr1low = sr1low_stack
+
+ x2 = h2 - y2
+ r0highx6 = r0high * x6
+ sr1high = sr1high_stack
+
+ x5 += y3
+ r0lowx0 = r0low * x0
+ r1low = r1low_stack
+
+ h6 = r3lowx0 + r0lowx6
+ sr1lowx6 = sr1low * x6
+ r1high = r1high_stack
+
+ x4 += y2
+ r0highx0 = r0high * x0
+ sr2low = sr2low_stack
+
+ h7 = r3highx0 + r0highx6
+ sr1highx6 = sr1high * x6
+ sr2high = sr2high_stack
+
+ x3 += y1
+ r1lowx0 = r1low * x0
+ r2low = r2low_stack
+
+ h0 = r0lowx0 + sr1lowx6
+ sr2lowx6 = sr2low * x6
+ r2high = r2high_stack
+
+ x2 += y0
+ r1highx0 = r1high * x0
+ sr3low = sr3low_stack
+
+ h1 = r0highx0 + sr1highx6
+ sr2highx6 = sr2high * x6
+ sr3high = sr3high_stack
+
+ x4 += x5
+ r2lowx0 = r2low * x0
+
+ h2 = r1lowx0 + sr2lowx6
+ sr3lowx6 = sr3low * x6
+
+ x2 += x3
+ r2highx0 = r2high * x0
+
+ h3 = r1highx0 + sr2highx6
+ sr3highx6 = sr3high * x6
+
+ r1highx4 = r1high * x4
+
+ h4 = r2lowx0 + sr3lowx6
+ r1lowx4 = r1low * x4
+
+ r0highx4 = r0high * x4
+
+ h5 = r2highx0 + sr3highx6
+ r0lowx4 = r0low * x4
+
+ h7 += r1highx4
+ sr3highx4 = sr3high * x4
+
+ h6 += r1lowx4
+ sr3lowx4 = sr3low * x4
+
+ h5 += r0highx4
+ sr2highx4 = sr2high * x4
+
+ h4 += r0lowx4
+ sr2lowx4 = sr2low * x4
+
+ h3 += sr3highx4
+ r0lowx2 = r0low * x2
+
+ h2 += sr3lowx4
+ r0highx2 = r0high * x2
+
+ h1 += sr2highx4
+ r1lowx2 = r1low * x2
+
+ h0 += sr2lowx4
+ r1highx2 = r1high * x2
+
+ h2 += r0lowx2
+ r2lowx2 = r2low * x2
+
+ h3 += r0highx2
+ r2highx2 = r2high * x2
+
+ h4 += r1lowx2
+ sr3lowx2 = sr3low * x2
+
+ h5 += r1highx2
+ sr3highx2 = sr3high * x2
+
+ h6 += r2lowx2
+
+ h7 += r2highx2
+
+ h0 += sr3lowx2
+
+ h1 += sr3highx2
+
+nomorebytes:
+
+ y7 = h7 + alpha130
+
+ y0 = h0 + alpha32
+
+ y1 = h1 + alpha32
+
+ y2 = h2 + alpha64
+
+ y7 -= alpha130
+
+ y3 = h3 + alpha64
+
+ y4 = h4 + alpha96
+
+ y5 = h5 + alpha96
+
+ x7 = h7 - y7
+ y7 *= scale
+
+ y0 -= alpha32
+
+ y1 -= alpha32
+
+ y2 -= alpha64
+
+ h6 += x7
+
+ y3 -= alpha64
+
+ y4 -= alpha96
+
+ y5 -= alpha96
+
+ y6 = h6 + alpha130
+
+ x0 = h0 - y0
+
+ x1 = h1 - y1
+
+ x2 = h2 - y2
+
+ y6 -= alpha130
+
+ x0 += y7
+
+ x3 = h3 - y3
+
+ x4 = h4 - y4
+
+ x5 = h5 - y5
+
+ x6 = h6 - y6
+
+ y6 *= scale
+
+ x2 += y0
+
+ x3 += y1
+
+ x4 += y2
+
+ x0 += y6
+
+ x5 += y3
+
+ x6 += y4
+
+ x2 += x3
+
+ x0 += x1
+
+ x4 += x5
+
+ x6 += y5
+
+ x2 += offset1
+ d1 = int64(math.Float64bits(x2))
+
+ x0 += offset0
+ d0 = int64(math.Float64bits(x0))
+
+ x4 += offset2
+ d2 = int64(math.Float64bits(x4))
+
+ x6 += offset3
+ d3 = int64(math.Float64bits(x6))
+
+ f0 = uint64(d0)
+
+ f1 = uint64(d1)
+ bits32 = math.MaxUint64
+
+ f2 = uint64(d2)
+ bits32 >>= 32
+
+ f3 = uint64(d3)
+ f = f0 >> 32
+
+ f0 &= bits32
+ f &= 255
+
+ f1 += f
+ g0 = f0 + 5
+
+ g = g0 >> 32
+ g0 &= bits32
+
+ f = f1 >> 32
+ f1 &= bits32
+
+ f &= 255
+ g1 = f1 + g
+
+ g = g1 >> 32
+ f2 += f
+
+ f = f2 >> 32
+ g1 &= bits32
+
+ f2 &= bits32
+ f &= 255
+
+ f3 += f
+ g2 = f2 + g
+
+ g = g2 >> 32
+ g2 &= bits32
+
+ f4 = f3 >> 32
+ f3 &= bits32
+
+ f4 &= 255
+ g3 = f3 + g
+
+ g = g3 >> 32
+ g3 &= bits32
+
+ g4 = f4 + g
+
+ g4 = g4 - 4
+ s00 = uint32(s[0])
+
+ f = uint64(int64(g4) >> 63)
+ s01 = uint32(s[1])
+
+ f0 &= f
+ g0 &^= f
+ s02 = uint32(s[2])
+
+ f1 &= f
+ f0 |= g0
+ s03 = uint32(s[3])
+
+ g1 &^= f
+ f2 &= f
+ s10 = uint32(s[4])
+
+ f3 &= f
+ g2 &^= f
+ s11 = uint32(s[5])
+
+ g3 &^= f
+ f1 |= g1
+ s12 = uint32(s[6])
+
+ f2 |= g2
+ f3 |= g3
+ s13 = uint32(s[7])
+
+ s01 <<= 8
+ f0 += uint64(s00)
+ s20 = uint32(s[8])
+
+ s02 <<= 16
+ f0 += uint64(s01)
+ s21 = uint32(s[9])
+
+ s03 <<= 24
+ f0 += uint64(s02)
+ s22 = uint32(s[10])
+
+ s11 <<= 8
+ f1 += uint64(s10)
+ s23 = uint32(s[11])
+
+ s12 <<= 16
+ f1 += uint64(s11)
+ s30 = uint32(s[12])
+
+ s13 <<= 24
+ f1 += uint64(s12)
+ s31 = uint32(s[13])
+
+ f0 += uint64(s03)
+ f1 += uint64(s13)
+ s32 = uint32(s[14])
+
+ s21 <<= 8
+ f2 += uint64(s20)
+ s33 = uint32(s[15])
+
+ s22 <<= 16
+ f2 += uint64(s21)
+
+ s23 <<= 24
+ f2 += uint64(s22)
+
+ s31 <<= 8
+ f3 += uint64(s30)
+
+ s32 <<= 16
+ f3 += uint64(s31)
+
+ s33 <<= 24
+ f3 += uint64(s32)
+
+ f2 += uint64(s23)
+ f3 += uint64(s33)
+
+ out[0] = byte(f0)
+ f0 >>= 8
+ out[1] = byte(f0)
+ f0 >>= 8
+ out[2] = byte(f0)
+ f0 >>= 8
+ out[3] = byte(f0)
+ f0 >>= 8
+ f1 += f0
+
+ out[4] = byte(f1)
+ f1 >>= 8
+ out[5] = byte(f1)
+ f1 >>= 8
+ out[6] = byte(f1)
+ f1 >>= 8
+ out[7] = byte(f1)
+ f1 >>= 8
+ f2 += f1
+
+ out[8] = byte(f2)
+ f2 >>= 8
+ out[9] = byte(f2)
+ f2 >>= 8
+ out[10] = byte(f2)
+ f2 >>= 8
+ out[11] = byte(f2)
+ f2 >>= 8
+ f3 += f2
+
+ out[12] = byte(f3)
+ f3 >>= 8
+ out[13] = byte(f3)
+ f3 >>= 8
+ out[14] = byte(f3)
+ f3 >>= 8
+ out[15] = byte(f3)
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/prf.go b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/prf.go
new file mode 100644
index 000000000..cfc383dc5
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/prf.go
@@ -0,0 +1,478 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runner
+
+import (
+ "crypto"
+ "crypto/hmac"
+ "crypto/md5"
+ "crypto/sha1"
+ "crypto/sha256"
+ "hash"
+)
+
+// Split a premaster secret in two as specified in RFC 4346, section 5.
+func splitPreMasterSecret(secret []byte) (s1, s2 []byte) {
+ s1 = secret[0 : (len(secret)+1)/2]
+ s2 = secret[len(secret)/2:]
+ return
+}
+
+// pHash implements the P_hash function, as defined in RFC 4346, section 5.
+func pHash(result, secret, seed []byte, hash func() hash.Hash) {
+ h := hmac.New(hash, secret)
+ h.Write(seed)
+ a := h.Sum(nil)
+
+ j := 0
+ for j < len(result) {
+ h.Reset()
+ h.Write(a)
+ h.Write(seed)
+ b := h.Sum(nil)
+ todo := len(b)
+ if j+todo > len(result) {
+ todo = len(result) - j
+ }
+ copy(result[j:j+todo], b)
+ j += todo
+
+ h.Reset()
+ h.Write(a)
+ a = h.Sum(nil)
+ }
+}
+
+// prf10 implements the TLS 1.0 pseudo-random function, as defined in RFC 2246, section 5.
+func prf10(result, secret, label, seed []byte) {
+ hashSHA1 := sha1.New
+ hashMD5 := md5.New
+
+ labelAndSeed := make([]byte, len(label)+len(seed))
+ copy(labelAndSeed, label)
+ copy(labelAndSeed[len(label):], seed)
+
+ s1, s2 := splitPreMasterSecret(secret)
+ pHash(result, s1, labelAndSeed, hashMD5)
+ result2 := make([]byte, len(result))
+ pHash(result2, s2, labelAndSeed, hashSHA1)
+
+ for i, b := range result2 {
+ result[i] ^= b
+ }
+}
+
+// prf12 implements the TLS 1.2 pseudo-random function, as defined in RFC 5246, section 5.
+func prf12(hashFunc func() hash.Hash) func(result, secret, label, seed []byte) {
+ return func(result, secret, label, seed []byte) {
+ labelAndSeed := make([]byte, len(label)+len(seed))
+ copy(labelAndSeed, label)
+ copy(labelAndSeed[len(label):], seed)
+
+ pHash(result, secret, labelAndSeed, hashFunc)
+ }
+}
+
+// prf30 implements the SSL 3.0 pseudo-random function, as defined in
+// www.mozilla.org/projects/security/pki/nss/ssl/draft302.txt section 6.
+func prf30(result, secret, label, seed []byte) {
+ hashSHA1 := sha1.New()
+ hashMD5 := md5.New()
+
+ done := 0
+ i := 0
+ // RFC5246 section 6.3 says that the largest PRF output needed is 128
+ // bytes. Since no more ciphersuites will be added to SSLv3, this will
+ // remain true. Each iteration gives us 16 bytes so 10 iterations will
+ // be sufficient.
+ var b [11]byte
+ for done < len(result) {
+ for j := 0; j <= i; j++ {
+ b[j] = 'A' + byte(i)
+ }
+
+ hashSHA1.Reset()
+ hashSHA1.Write(b[:i+1])
+ hashSHA1.Write(secret)
+ hashSHA1.Write(seed)
+ digest := hashSHA1.Sum(nil)
+
+ hashMD5.Reset()
+ hashMD5.Write(secret)
+ hashMD5.Write(digest)
+
+ done += copy(result[done:], hashMD5.Sum(nil))
+ i++
+ }
+}
+
+const (
+ tlsRandomLength = 32 // Length of a random nonce in TLS 1.1.
+ masterSecretLength = 48 // Length of a master secret in TLS 1.1.
+ finishedVerifyLength = 12 // Length of verify_data in a Finished message.
+)
+
+var masterSecretLabel = []byte("master secret")
+var extendedMasterSecretLabel = []byte("extended master secret")
+var keyExpansionLabel = []byte("key expansion")
+var clientFinishedLabel = []byte("client finished")
+var serverFinishedLabel = []byte("server finished")
+var finishedLabel = []byte("finished")
+var channelIDLabel = []byte("TLS Channel ID signature\x00")
+var channelIDResumeLabel = []byte("Resumption\x00")
+
+func prfForVersion(version uint16, suite *cipherSuite) func(result, secret, label, seed []byte) {
+ switch version {
+ case VersionSSL30:
+ return prf30
+ case VersionTLS10, VersionTLS11:
+ return prf10
+ case VersionTLS12:
+ return prf12(suite.hash().New)
+ }
+ panic("unknown version")
+}
+
+// masterFromPreMasterSecret generates the master secret from the pre-master
+// secret. See http://tools.ietf.org/html/rfc5246#section-8.1
+func masterFromPreMasterSecret(version uint16, suite *cipherSuite, preMasterSecret, clientRandom, serverRandom []byte) []byte {
+ var seed [tlsRandomLength * 2]byte
+ copy(seed[0:len(clientRandom)], clientRandom)
+ copy(seed[len(clientRandom):], serverRandom)
+ masterSecret := make([]byte, masterSecretLength)
+ prfForVersion(version, suite)(masterSecret, preMasterSecret, masterSecretLabel, seed[0:])
+ return masterSecret
+}
+
+// extendedMasterFromPreMasterSecret generates the master secret from the
+// pre-master secret when the Triple Handshake fix is in effect. See
+// https://tools.ietf.org/html/rfc7627
+func extendedMasterFromPreMasterSecret(version uint16, suite *cipherSuite, preMasterSecret []byte, h finishedHash) []byte {
+ masterSecret := make([]byte, masterSecretLength)
+ prfForVersion(version, suite)(masterSecret, preMasterSecret, extendedMasterSecretLabel, h.Sum())
+ return masterSecret
+}
+
+// keysFromMasterSecret generates the connection keys from the master
+// secret, given the lengths of the MAC key, cipher key and IV, as defined in
+// RFC 2246, section 6.3.
+func keysFromMasterSecret(version uint16, suite *cipherSuite, masterSecret, clientRandom, serverRandom []byte, macLen, keyLen, ivLen int) (clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV []byte) {
+ var seed [tlsRandomLength * 2]byte
+ copy(seed[0:len(clientRandom)], serverRandom)
+ copy(seed[len(serverRandom):], clientRandom)
+
+ n := 2*macLen + 2*keyLen + 2*ivLen
+ keyMaterial := make([]byte, n)
+ prfForVersion(version, suite)(keyMaterial, masterSecret, keyExpansionLabel, seed[0:])
+ clientMAC = keyMaterial[:macLen]
+ keyMaterial = keyMaterial[macLen:]
+ serverMAC = keyMaterial[:macLen]
+ keyMaterial = keyMaterial[macLen:]
+ clientKey = keyMaterial[:keyLen]
+ keyMaterial = keyMaterial[keyLen:]
+ serverKey = keyMaterial[:keyLen]
+ keyMaterial = keyMaterial[keyLen:]
+ clientIV = keyMaterial[:ivLen]
+ keyMaterial = keyMaterial[ivLen:]
+ serverIV = keyMaterial[:ivLen]
+ return
+}
+
+func newFinishedHash(version uint16, cipherSuite *cipherSuite) finishedHash {
+ var ret finishedHash
+
+ if version >= VersionTLS12 {
+ ret.hash = cipherSuite.hash()
+
+ ret.client = ret.hash.New()
+ ret.server = ret.hash.New()
+
+ if version == VersionTLS12 {
+ ret.prf = prf12(ret.hash.New)
+ } else {
+ ret.secret = make([]byte, ret.hash.Size())
+ }
+ } else {
+ ret.hash = crypto.MD5SHA1
+
+ ret.client = sha1.New()
+ ret.server = sha1.New()
+ ret.clientMD5 = md5.New()
+ ret.serverMD5 = md5.New()
+
+ ret.prf = prf10
+ }
+
+ ret.buffer = []byte{}
+ ret.version = version
+ return ret
+}
+
+// A finishedHash calculates the hash of a set of handshake messages suitable
+// for including in a Finished message.
+type finishedHash struct {
+ hash crypto.Hash
+
+ client hash.Hash
+ server hash.Hash
+
+ // Prior to TLS 1.2, an additional MD5 hash is required.
+ clientMD5 hash.Hash
+ serverMD5 hash.Hash
+
+ // In TLS 1.2 (and SSL 3 for implementation convenience), a
+ // full buffer is required.
+ buffer []byte
+
+ version uint16
+ prf func(result, secret, label, seed []byte)
+
+ // secret, in TLS 1.3, is the running input secret.
+ secret []byte
+}
+
+func (h *finishedHash) Write(msg []byte) (n int, err error) {
+ h.client.Write(msg)
+ h.server.Write(msg)
+
+ if h.version < VersionTLS12 {
+ h.clientMD5.Write(msg)
+ h.serverMD5.Write(msg)
+ }
+
+ if h.buffer != nil {
+ h.buffer = append(h.buffer, msg...)
+ }
+
+ return len(msg), nil
+}
+
+func (h finishedHash) Sum() []byte {
+ if h.version >= VersionTLS12 {
+ return h.client.Sum(nil)
+ }
+
+ out := make([]byte, 0, md5.Size+sha1.Size)
+ out = h.clientMD5.Sum(out)
+ return h.client.Sum(out)
+}
+
+// finishedSum30 calculates the contents of the verify_data member of a SSLv3
+// Finished message given the MD5 and SHA1 hashes of a set of handshake
+// messages.
+func finishedSum30(md5, sha1 hash.Hash, masterSecret []byte, magic []byte) []byte {
+ md5.Write(magic)
+ md5.Write(masterSecret)
+ md5.Write(ssl30Pad1[:])
+ md5Digest := md5.Sum(nil)
+
+ md5.Reset()
+ md5.Write(masterSecret)
+ md5.Write(ssl30Pad2[:])
+ md5.Write(md5Digest)
+ md5Digest = md5.Sum(nil)
+
+ sha1.Write(magic)
+ sha1.Write(masterSecret)
+ sha1.Write(ssl30Pad1[:40])
+ sha1Digest := sha1.Sum(nil)
+
+ sha1.Reset()
+ sha1.Write(masterSecret)
+ sha1.Write(ssl30Pad2[:40])
+ sha1.Write(sha1Digest)
+ sha1Digest = sha1.Sum(nil)
+
+ ret := make([]byte, len(md5Digest)+len(sha1Digest))
+ copy(ret, md5Digest)
+ copy(ret[len(md5Digest):], sha1Digest)
+ return ret
+}
+
+var ssl3ClientFinishedMagic = [4]byte{0x43, 0x4c, 0x4e, 0x54}
+var ssl3ServerFinishedMagic = [4]byte{0x53, 0x52, 0x56, 0x52}
+
+// clientSum returns the contents of the verify_data member of a client's
+// Finished message.
+func (h finishedHash) clientSum(baseKey []byte) []byte {
+ if h.version == VersionSSL30 {
+ return finishedSum30(h.clientMD5, h.client, baseKey, ssl3ClientFinishedMagic[:])
+ }
+
+ if h.version < VersionTLS13 {
+ out := make([]byte, finishedVerifyLength)
+ h.prf(out, baseKey, clientFinishedLabel, h.Sum())
+ return out
+ }
+
+ clientFinishedKey := hkdfExpandLabel(h.hash, baseKey, finishedLabel, nil, h.hash.Size())
+ finishedHMAC := hmac.New(h.hash.New, clientFinishedKey)
+ finishedHMAC.Write(h.appendContextHashes(nil))
+ return finishedHMAC.Sum(nil)
+}
+
+// serverSum returns the contents of the verify_data member of a server's
+// Finished message.
+func (h finishedHash) serverSum(baseKey []byte) []byte {
+ if h.version == VersionSSL30 {
+ return finishedSum30(h.serverMD5, h.server, baseKey, ssl3ServerFinishedMagic[:])
+ }
+
+ if h.version < VersionTLS13 {
+ out := make([]byte, finishedVerifyLength)
+ h.prf(out, baseKey, serverFinishedLabel, h.Sum())
+ return out
+ }
+
+ serverFinishedKey := hkdfExpandLabel(h.hash, baseKey, finishedLabel, nil, h.hash.Size())
+ finishedHMAC := hmac.New(h.hash.New, serverFinishedKey)
+ finishedHMAC.Write(h.appendContextHashes(nil))
+ return finishedHMAC.Sum(nil)
+}
+
+// hashForClientCertificateSSL3 returns the hash to be signed for client
+// certificates in SSL 3.0.
+func (h finishedHash) hashForClientCertificateSSL3(masterSecret []byte) []byte {
+ md5Hash := md5.New()
+ md5Hash.Write(h.buffer)
+ sha1Hash := sha1.New()
+ sha1Hash.Write(h.buffer)
+ return finishedSum30(md5Hash, sha1Hash, masterSecret, nil)
+}
+
+// hashForChannelID returns the hash to be signed for TLS Channel
+// ID. If a resumption, resumeHash has the previous handshake
+// hash. Otherwise, it is nil.
+func (h finishedHash) hashForChannelID(resumeHash []byte) []byte {
+ hash := sha256.New()
+ hash.Write(channelIDLabel)
+ if resumeHash != nil {
+ hash.Write(channelIDResumeLabel)
+ hash.Write(resumeHash)
+ }
+ hash.Write(h.Sum())
+ return hash.Sum(nil)
+}
+
+// discardHandshakeBuffer is called when there is no more need to
+// buffer the entirety of the handshake messages.
+func (h *finishedHash) discardHandshakeBuffer() {
+ h.buffer = nil
+}
+
+// zeroSecretTLS13 returns the default all zeros secret for TLS 1.3, used when a
+// given secret is not available in the handshake. See draft-ietf-tls-tls13-16,
+// section 7.1.
+func (h *finishedHash) zeroSecret() []byte {
+ return make([]byte, h.hash.Size())
+}
+
+// addEntropy incorporates ikm into the running TLS 1.3 secret with HKDF-Expand.
+func (h *finishedHash) addEntropy(ikm []byte) {
+ h.secret = hkdfExtract(h.hash.New, h.secret, ikm)
+}
+
+// hkdfExpandLabel implements TLS 1.3's HKDF-Expand-Label function, as defined
+// in section 7.1 of draft-ietf-tls-tls13-16.
+func hkdfExpandLabel(hash crypto.Hash, secret, label, hashValue []byte, length int) []byte {
+ if len(label) > 255 || len(hashValue) > 255 {
+ panic("hkdfExpandLabel: label or hashValue too long")
+ }
+ hkdfLabel := make([]byte, 3+9+len(label)+1+len(hashValue))
+ x := hkdfLabel
+ x[0] = byte(length >> 8)
+ x[1] = byte(length)
+ x[2] = byte(9 + len(label))
+ x = x[3:]
+ copy(x, []byte("TLS 1.3, "))
+ x = x[9:]
+ copy(x, label)
+ x = x[len(label):]
+ x[0] = byte(len(hashValue))
+ copy(x[1:], hashValue)
+ return hkdfExpand(hash.New, secret, hkdfLabel, length)
+}
+
+// appendContextHashes returns the concatenation of the handshake hash and the
+// resumption context hash, as used in TLS 1.3.
+func (h *finishedHash) appendContextHashes(b []byte) []byte {
+ b = h.client.Sum(b)
+ return b
+}
+
+// The following are labels for traffic secret derivation in TLS 1.3.
+var (
+ externalPSKBinderLabel = []byte("external psk binder key")
+ resumptionPSKBinderLabel = []byte("resumption psk binder key")
+ earlyTrafficLabel = []byte("client early traffic secret")
+ clientHandshakeTrafficLabel = []byte("client handshake traffic secret")
+ serverHandshakeTrafficLabel = []byte("server handshake traffic secret")
+ clientApplicationTrafficLabel = []byte("client application traffic secret")
+ serverApplicationTrafficLabel = []byte("server application traffic secret")
+ applicationTrafficLabel = []byte("application traffic secret")
+ exporterLabel = []byte("exporter master secret")
+ resumptionLabel = []byte("resumption master secret")
+)
+
+// deriveSecret implements TLS 1.3's Derive-Secret function, as defined in
+// section 7.1 of draft ietf-tls-tls13-16.
+func (h *finishedHash) deriveSecret(label []byte) []byte {
+ return hkdfExpandLabel(h.hash, h.secret, label, h.appendContextHashes(nil), h.hash.Size())
+}
+
+// The following are context strings for CertificateVerify in TLS 1.3.
+var (
+ clientCertificateVerifyContextTLS13 = []byte("TLS 1.3, client CertificateVerify")
+ serverCertificateVerifyContextTLS13 = []byte("TLS 1.3, server CertificateVerify")
+ channelIDContextTLS13 = []byte("TLS 1.3, Channel ID")
+)
+
+// certificateVerifyMessage returns the input to be signed for CertificateVerify
+// in TLS 1.3.
+func (h *finishedHash) certificateVerifyInput(context []byte) []byte {
+ const paddingLen = 64
+ b := make([]byte, paddingLen, paddingLen+len(context)+1+2*h.hash.Size())
+ for i := 0; i < paddingLen; i++ {
+ b[i] = 32
+ }
+ b = append(b, context...)
+ b = append(b, 0)
+ b = h.appendContextHashes(b)
+ return b
+}
+
+type trafficDirection int
+
+const (
+ clientWrite trafficDirection = iota
+ serverWrite
+)
+
+var (
+ keyTLS13 = []byte("key")
+ ivTLS13 = []byte("iv")
+)
+
+// deriveTrafficAEAD derives traffic keys and constructs an AEAD given a traffic
+// secret.
+func deriveTrafficAEAD(version uint16, suite *cipherSuite, secret []byte, side trafficDirection) interface{} {
+ key := hkdfExpandLabel(suite.hash(), secret, keyTLS13, nil, suite.keyLen)
+ iv := hkdfExpandLabel(suite.hash(), secret, ivTLS13, nil, suite.ivLen(version))
+
+ return suite.aead(version, key, iv)
+}
+
+func updateTrafficSecret(hash crypto.Hash, secret []byte) []byte {
+ return hkdfExpandLabel(hash, secret, applicationTrafficLabel, nil, hash.Size())
+}
+
+func computePSKBinder(psk, label []byte, cipherSuite *cipherSuite, transcript, truncatedHello []byte) []byte {
+ finishedHash := newFinishedHash(VersionTLS13, cipherSuite)
+ finishedHash.addEntropy(psk)
+ binderKey := finishedHash.deriveSecret(label)
+ finishedHash.Write(transcript)
+ finishedHash.Write(truncatedHello)
+ return finishedHash.clientSum(binderKey)
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/recordingconn.go b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/recordingconn.go
new file mode 100644
index 000000000..4dae43575
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/recordingconn.go
@@ -0,0 +1,167 @@
+// Copyright (c) 2016, 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 runner
+
+import (
+ "bufio"
+ "encoding/hex"
+ "errors"
+ "fmt"
+ "io"
+ "net"
+ "strconv"
+ "strings"
+ "sync"
+)
+
+type flowType int
+
+const (
+ readFlow flowType = iota
+ writeFlow
+ specialFlow
+)
+
+type flow struct {
+ flowType flowType
+ message string
+ data []byte
+}
+
+// recordingConn is a net.Conn that records the traffic that passes through it.
+// WriteTo can be used to produce output that can be later be loaded with
+// ParseTestData.
+type recordingConn struct {
+ net.Conn
+ sync.Mutex
+ flows []flow
+ isDatagram bool
+ local, peer string
+}
+
+func (r *recordingConn) appendFlow(flowType flowType, message string, data []byte) {
+ r.Lock()
+ defer r.Unlock()
+
+ if l := len(r.flows); flowType == specialFlow || r.isDatagram || l == 0 || r.flows[l-1].flowType != flowType {
+ buf := make([]byte, len(data))
+ copy(buf, data)
+ r.flows = append(r.flows, flow{flowType, message, buf})
+ } else {
+ r.flows[l-1].data = append(r.flows[l-1].data, data...)
+ }
+}
+
+func (r *recordingConn) Read(b []byte) (n int, err error) {
+ if n, err = r.Conn.Read(b); n == 0 {
+ return
+ }
+ r.appendFlow(readFlow, "", b[:n])
+ return
+}
+
+func (r *recordingConn) Write(b []byte) (n int, err error) {
+ if n, err = r.Conn.Write(b); n == 0 {
+ return
+ }
+ r.appendFlow(writeFlow, "", b[:n])
+ return
+}
+
+// LogSpecial appends an entry to the record of type 'special'.
+func (r *recordingConn) LogSpecial(message string, data []byte) {
+ r.appendFlow(specialFlow, message, data)
+}
+
+// WriteTo writes hex dumps to w that contains the recorded traffic.
+func (r *recordingConn) WriteTo(w io.Writer) {
+ fmt.Fprintf(w, ">>> runner is %s, shim is %s\n", r.local, r.peer)
+ for i, flow := range r.flows {
+ switch flow.flowType {
+ case readFlow:
+ fmt.Fprintf(w, ">>> Flow %d (%s to %s)\n", i+1, r.peer, r.local)
+ case writeFlow:
+ fmt.Fprintf(w, ">>> Flow %d (%s to %s)\n", i+1, r.local, r.peer)
+ case specialFlow:
+ fmt.Fprintf(w, ">>> Flow %d %q\n", i+1, flow.message)
+ }
+
+ if flow.data != nil {
+ dumper := hex.Dumper(w)
+ dumper.Write(flow.data)
+ dumper.Close()
+ }
+ }
+}
+
+func (r *recordingConn) Transcript() []byte {
+ var ret []byte
+ for _, flow := range r.flows {
+ if flow.flowType != writeFlow {
+ continue
+ }
+ ret = append(ret, flow.data...)
+ }
+ return ret
+}
+
+func parseTestData(r io.Reader) (flows [][]byte, err error) {
+ var currentFlow []byte
+
+ scanner := bufio.NewScanner(r)
+ for scanner.Scan() {
+ line := scanner.Text()
+ // If the line starts with ">>> " then it marks the beginning
+ // of a new flow.
+ if strings.HasPrefix(line, ">>> ") {
+ if len(currentFlow) > 0 || len(flows) > 0 {
+ flows = append(flows, currentFlow)
+ currentFlow = nil
+ }
+ continue
+ }
+
+ // Otherwise the line is a line of hex dump that looks like:
+ // 00000170 fc f5 06 bf (...) |.....X{&?......!|
+ // (Some bytes have been omitted from the middle section.)
+
+ if i := strings.IndexByte(line, ' '); i >= 0 {
+ line = line[i:]
+ } else {
+ return nil, errors.New("invalid test data")
+ }
+
+ if i := strings.IndexByte(line, '|'); i >= 0 {
+ line = line[:i]
+ } else {
+ return nil, errors.New("invalid test data")
+ }
+
+ hexBytes := strings.Fields(line)
+ for _, hexByte := range hexBytes {
+ val, err := strconv.ParseUint(hexByte, 16, 8)
+ if err != nil {
+ return nil, errors.New("invalid hex byte in test data: " + err.Error())
+ }
+ currentFlow = append(currentFlow, byte(val))
+ }
+ }
+
+ if len(currentFlow) > 0 {
+ flows = append(flows, currentFlow)
+ }
+
+ return flows, nil
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/rsa_1024_cert.pem b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/rsa_1024_cert.pem
new file mode 100644
index 000000000..4de4f49a3
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/rsa_1024_cert.pem
@@ -0,0 +1,15 @@
+-----BEGIN CERTIFICATE-----
+MIICWDCCAcGgAwIBAgIJAPuwTC6rEJsMMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV
+BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
+aWRnaXRzIFB0eSBMdGQwHhcNMTQwNDIzMjA1MDQwWhcNMTcwNDIyMjA1MDQwWjBF
+MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
+ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB
+gQDYK8imMuRi/03z0K1Zi0WnvfFHvwlYeyK9Na6XJYaUoIDAtB92kWdGMdAQhLci
+HnAjkXLI6W15OoV3gA/ElRZ1xUpxTMhjP6PyY5wqT5r6y8FxbiiFKKAnHmUcrgfV
+W28tQ+0rkLGMryRtrukXOgXBv7gcrmU7G1jC2a7WqmeI8QIDAQABo1AwTjAdBgNV
+HQ4EFgQUi3XVrMsIvg4fZbf6Vr5sp3Xaha8wHwYDVR0jBBgwFoAUi3XVrMsIvg4f
+Zbf6Vr5sp3Xaha8wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQA76Hht
+ldY9avcTGSwbwoiuIqv0jTL1fHFnzy3RHMLDh+Lpvolc5DSrSJHCP5WuK0eeJXhr
+T5oQpHL9z/cCDLAKCKRa4uV0fhEdOWBqyR9p8y5jJtye72t6CuFUV5iqcpF4BH4f
+j2VNHwsSrJwkD4QUGlUtH7vwnQmyCFxZMmWAJg==
+-----END CERTIFICATE-----
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/rsa_1024_key.pem b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/rsa_1024_key.pem
new file mode 100644
index 000000000..2a3b9dedc
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/rsa_1024_key.pem
@@ -0,0 +1,16 @@
+-----BEGIN PRIVATE KEY-----
+MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBANgryKYy5GL/TfPQ
+rVmLRae98Ue/CVh7Ir01rpclhpSggMC0H3aRZ0Yx0BCEtyIecCORcsjpbXk6hXeA
+D8SVFnXFSnFMyGM/o/JjnCpPmvrLwXFuKIUooCceZRyuB9Vbby1D7SuQsYyvJG2u
+6Rc6BcG/uByuZTsbWMLZrtaqZ4jxAgMBAAECgYEAgHLT0V3gM6r8iOnwd4q4IwpM
+epNbXEYeyEtDqPBVXa9Zkif1oiCYOy+SMJ6Lqyxm+duNVzDNKgHKGM3xkJ/+LXkc
+QJYMUWHqC3Q/nPQycKHDNma9q1X8VcJPSP5aYY0H+CR6EqMZcstyNNvp1FhUlIJm
+FW44stxtYhXXSCCAlAECQQDxLywZ7h7PLJmbh72v3mDqzjeQ+q2Pmt7BOxTG37af
+h5Wh0P5lSUJQtZU0AUuRhFMEIBKVKub1eGNCmZYAclSRAkEA5XNB0VRp7Au104mg
+8K2lihjXN3bZ5p7xNASakY5HXUvqRvEtCyRoyXL8M6c5prza2oAZN2oMRmBI2YJ4
+oqSeYQJAC+mdjwZQ5UC5sZHpz5b3SIG5AuMu0Wn/2KF3bD8+gPCsdlqhRhVxPhVJ
+8lCiD+TuSMTgxhdhYvx4QqDdZNZA0QJBAOTXThaL3VSZ3U/MXSKN3aNc4RElTXAQ
+p7pcuRhg0dZAB7mXgngxaP053EVcDEi65H+18PBuqS1rjFy7Hrv/+SECQQC+9Fcs
+dNprpUXNNqKI7xJoWwdXeVDJc60ysGkHmN2ahlaCMe8HZb0KSfuwOqw8H5Ta3JfS
+OgN1ATK6IwQINjyh
+-----END PRIVATE KEY-----
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/rsa_chain_cert.pem b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/rsa_chain_cert.pem
new file mode 100644
index 000000000..8eb6e60ed
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/rsa_chain_cert.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIC0jCCAbqgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwDzENMAsGA1UEAwwEQiBD
+QTAeFw0xNjAyMjgyMDI3MDNaFw0yNjAyMjUyMDI3MDNaMBgxFjAUBgNVBAMMDUNs
+aWVudCBDZXJ0IEEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDRvaz8
+CC/cshpCafJo4jLkHEoBqDLhdgFelJoAiQUyIqyWl2O7YHPnpJH+TgR7oelzNzt/
+kLRcH89M/TszB6zqyLTC4aqmvzKL0peD/jL2LWBucR0WXIvjA3zoRuF/x86+rYH3
+tHb+xs2PSs8EGL/Ev+ss+qTzTGEn26fuGNHkNw6tOwPpc+o8+wUtzf/kAthamo+c
+IDs2rQ+lP7+aLZTLeU/q4gcLutlzcK5imex5xy2jPkweq48kijK0kIzl1cPlA5d1
+z7C8jU50Pj9X9sQDJTN32j7UYRisJeeYQF8GaaN8SbrDI6zHgKzrRLyxDt/KQa9V
+iLeXANgZi+Xx9KgfAgMBAAGjLzAtMAwGA1UdEwEB/wQCMAAwHQYDVR0lBBYwFAYI
+KwYBBQUHAwEGCCsGAQUFBwMCMA0GCSqGSIb3DQEBCwUAA4IBAQBFEVbmYl+2RtNw
+rDftRDF1v2QUbcN2ouSnQDHxeDQdSgasLzT3ui8iYu0Rw2WWcZ0DV5e0ztGPhWq7
+AO0B120aFRMOY+4+bzu9Q2FFkQqc7/fKTvTDzIJI5wrMnFvUfzzvxh3OHWMYSs/w
+giq33hTKeHEq6Jyk3btCny0Ycecyc3yGXH10sizUfiHlhviCkDuESk8mFDwDDzqW
+ZF0IipzFbEDHoIxLlm3GQxpiLoEV4k8KYJp3R5KBLFyxM6UGPz8h72mIPCJp2RuK
+MYgF91UDvVzvnYm6TfseM2+ewKirC00GOrZ7rEcFvtxnKSqYf4ckqfNdSU1Y+RRC
+1ngWZ7Ih
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICwjCCAaqgAwIBAgICEAEwDQYJKoZIhvcNAQELBQAwFDESMBAGA1UEAwwJQyBS
+b290IENBMB4XDTE2MDIyODIwMjcwM1oXDTI2MDIyNTIwMjcwM1owDzENMAsGA1UE
+AwwEQiBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALsSCYmDip2D
+GkjFxw7ykz26JSjELkl6ArlYjFJ3aT/SCh8qbS4gln7RH8CPBd78oFdfhIKQrwtZ
+3/q21ykD9BAS3qHe2YdcJfm8/kWAy5DvXk6NXU4qX334KofBAEpgdA/igEFq1P1l
+HAuIfZCpMRfT+i5WohVsGi8f/NgpRvVaMONLNfgw57mz1lbtFeBEISmX0kbsuJxF
+Qj/Bwhi5/0HAEXG8e7zN4cEx0yPRvmOATRdVb/8dW2pwOHRJq9R5M0NUkIsTSnL7
+6N/z8hRAHMsV3IudC5Yd7GXW1AGu9a+iKU+Q4xcZCoj0DC99tL4VKujrV1kAeqsM
+cz5/dKzi6+cCAwEAAaMjMCEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
+AQYwDQYJKoZIhvcNAQELBQADggEBAIIeZiEeNhWWQ8Y4D+AGDwqUUeG8NjCbKrXQ
+BlHg5wZ8xftFaiP1Dp/UAezmx2LNazdmuwrYB8lm3FVTyaPDTKEGIPS4wJKHgqH1
+QPDhqNm85ey7TEtI9oYjsNim/Rb+iGkIAMXaxt58SzxbjvP0kMr1JfJIZbic9vye
+NwIspMFIpP3FB8ywyu0T0hWtCQgL4J47nigCHpOu58deP88fS/Nyz/fyGVWOZ76b
+WhWwgM3P3X95fQ3d7oFPR/bVh0YV+Cf861INwplokXgXQ3/TCQ+HNXeAMWn3JLWv
+XFwk8owk9dq/kQGdndGgy3KTEW4ctPX5GNhf3LJ9Q7dLji4ReQ4=
+-----END CERTIFICATE-----
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/rsa_chain_key.pem b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/rsa_chain_key.pem
new file mode 100644
index 000000000..d94d70442
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/rsa_chain_key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDRvaz8CC/cshpC
+afJo4jLkHEoBqDLhdgFelJoAiQUyIqyWl2O7YHPnpJH+TgR7oelzNzt/kLRcH89M
+/TszB6zqyLTC4aqmvzKL0peD/jL2LWBucR0WXIvjA3zoRuF/x86+rYH3tHb+xs2P
+Ss8EGL/Ev+ss+qTzTGEn26fuGNHkNw6tOwPpc+o8+wUtzf/kAthamo+cIDs2rQ+l
+P7+aLZTLeU/q4gcLutlzcK5imex5xy2jPkweq48kijK0kIzl1cPlA5d1z7C8jU50
+Pj9X9sQDJTN32j7UYRisJeeYQF8GaaN8SbrDI6zHgKzrRLyxDt/KQa9ViLeXANgZ
+i+Xx9KgfAgMBAAECggEBAK0VjSJzkyPaamcyTVSWjo7GdaBGcK60lk657RjR+lK0
+YJ7pkej4oM2hdsVZFsP8Cs4E33nXLa/0pDsRov/qrp0WQm2skwqGMC1I/bZ0WRPk
+wHaDrBBfESWnJDX/AGpVtlyOjPmgmK6J2usMPihQUDkKdAYrVWJePrMIxt1q6BMe
+iczs3qriMmtY3bUc4UyUwJ5fhDLjshHvfuIpYQyI6EXZM6dZksn9LylXJnigY6QJ
+HxOYO0BDwOsZ8yQ8J8afLk88i0GizEkgE1z3REtQUwgWfxr1WV/ud+T6/ZhSAgH9
+042mQvSFZnIUSEsmCvjhWuAunfxHKCTcAoYISWfzWpkCgYEA7gpf3HHU5Tn+CgUn
+1X5uGpG3DmcMgfeGgs2r2f/IIg/5Ac1dfYILiybL1tN9zbyLCJfcbFpWBc9hJL6f
+CPc5hUiwWFJqBJewxQkC1Ae/HakHbip+IZ+Jr0842O4BAArvixk4Lb7/N2Ct9sTE
+NJO6RtK9lbEZ5uK61DglHy8CS2UCgYEA4ZC1o36kPAMQBggajgnucb2yuUEelk0f
+AEr+GI32MGE+93xMr7rAhBoqLg4AITyIfEnOSQ5HwagnIHonBbv1LV/Gf9ursx8Z
+YOGbvT8zzzC+SU1bkDzdjAYnFQVGIjMtKOBJ3K07++ypwX1fr4QsQ8uKL8WSOWwt
+Z3Bym6XiZzMCgYADnhy+2OwHX85AkLt+PyGlPbmuelpyTzS4IDAQbBa6jcuW/2wA
+UE2km75VUXmD+u2R/9zVuLm99NzhFhSMqlUxdV1YukfqMfP5yp1EY6m/5aW7QuIP
+2MDa7TVL9rIFMiVZ09RKvbBbQxjhuzPQKL6X/PPspnhiTefQ+dl2k9xREQKBgHDS
+fMfGNEeAEKezrfSVqxphE9/tXms3L+ZpnCaT+yu/uEr5dTIAawKoQ6i9f/sf1/Sy
+xedsqR+IB+oKrzIDDWMgoJybN4pkZ8E5lzhVQIjFjKgFdWLzzqyW9z1gYfABQPlN
+FiS20WX0vgP1vcKAjdNrHzc9zyHBpgQzDmAj3NZZAoGBAI8vKCKdH7w3aL5CNkZQ
+2buIeWNA2HZazVwAGG5F2TU/LmXfRKnG6dX5bkU+AkBZh56jNZy//hfFSewJB4Kk
+buB7ERSdaNbO21zXt9FEA3+z0RfMd/Zv2vlIWOSB5nzl/7UKti3sribK6s9ZVLfi
+SxpiPQ8d/hmSGwn4ksrWUsJD
+-----END PRIVATE KEY-----
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/runner.go b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/runner.go
new file mode 100644
index 000000000..d90485c8f
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/runner.go
@@ -0,0 +1,10468 @@
+// Copyright (c) 2016, 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 runner
+
+import (
+ "bytes"
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "crypto/rand"
+ "crypto/x509"
+ "crypto/x509/pkix"
+ "encoding/base64"
+ "encoding/hex"
+ "encoding/json"
+ "encoding/pem"
+ "errors"
+ "flag"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "math/big"
+ "net"
+ "os"
+ "os/exec"
+ "path"
+ "path/filepath"
+ "runtime"
+ "strconv"
+ "strings"
+ "sync"
+ "syscall"
+ "time"
+)
+
+var (
+ useValgrind = flag.Bool("valgrind", false, "If true, run code under valgrind")
+ useGDB = flag.Bool("gdb", false, "If true, run BoringSSL code under gdb")
+ useLLDB = flag.Bool("lldb", false, "If true, run BoringSSL code under lldb")
+ flagDebug = flag.Bool("debug", false, "Hexdump the contents of the connection")
+ mallocTest = flag.Int64("malloc-test", -1, "If non-negative, run each test with each malloc in turn failing from the given number onwards.")
+ mallocTestDebug = flag.Bool("malloc-test-debug", false, "If true, ask bssl_shim to abort rather than fail a malloc. This can be used with a specific value for --malloc-test to identity the malloc failing that is causing problems.")
+ jsonOutput = flag.String("json-output", "", "The file to output JSON results to.")
+ pipe = flag.Bool("pipe", false, "If true, print status output suitable for piping into another program.")
+ testToRun = flag.String("test", "", "The pattern to filter tests to run, or empty to run all tests")
+ numWorkers = flag.Int("num-workers", runtime.NumCPU(), "The number of workers to run in parallel.")
+ shimPath = flag.String("shim-path", "../../../build/ssl/test/bssl_shim", "The location of the shim binary.")
+ resourceDir = flag.String("resource-dir", ".", "The directory in which to find certificate and key files.")
+ fuzzer = flag.Bool("fuzzer", false, "If true, tests against a BoringSSL built in fuzzer mode.")
+ transcriptDir = flag.String("transcript-dir", "", "The directory in which to write transcripts.")
+ idleTimeout = flag.Duration("idle-timeout", 15*time.Second, "The number of seconds to wait for a read or write to bssl_shim.")
+ deterministic = flag.Bool("deterministic", false, "If true, uses a deterministic PRNG in the runner.")
+ allowUnimplemented = flag.Bool("allow-unimplemented", false, "If true, report pass even if some tests are unimplemented.")
+ looseErrors = flag.Bool("loose-errors", false, "If true, allow shims to report an untranslated error code.")
+ shimConfigFile = flag.String("shim-config", "", "A config file to use to configure the tests for this shim.")
+ includeDisabled = flag.Bool("include-disabled", false, "If true, also runs disabled tests.")
+ repeatUntilFailure = flag.Bool("repeat-until-failure", false, "If true, the first selected test will be run repeatedly until failure.")
+)
+
+// ShimConfigurations is used with the “json” package and represents a shim
+// config file.
+type ShimConfiguration struct {
+ // DisabledTests maps from a glob-based pattern to a freeform string.
+ // The glob pattern is used to exclude tests from being run and the
+ // freeform string is unparsed but expected to explain why the test is
+ // disabled.
+ DisabledTests map[string]string
+
+ // ErrorMap maps from expected error strings to the correct error
+ // string for the shim in question. For example, it might map
+ // “:NO_SHARED_CIPHER:” (a BoringSSL error string) to something
+ // like “SSL_ERROR_NO_CYPHER_OVERLAP”.
+ ErrorMap map[string]string
+}
+
+var shimConfig ShimConfiguration
+
+type testCert int
+
+const (
+ testCertRSA testCert = iota
+ testCertRSA1024
+ testCertRSAChain
+ testCertECDSAP224
+ testCertECDSAP256
+ testCertECDSAP384
+ testCertECDSAP521
+)
+
+const (
+ rsaCertificateFile = "cert.pem"
+ rsa1024CertificateFile = "rsa_1024_cert.pem"
+ rsaChainCertificateFile = "rsa_chain_cert.pem"
+ ecdsaP224CertificateFile = "ecdsa_p224_cert.pem"
+ ecdsaP256CertificateFile = "ecdsa_p256_cert.pem"
+ ecdsaP384CertificateFile = "ecdsa_p384_cert.pem"
+ ecdsaP521CertificateFile = "ecdsa_p521_cert.pem"
+)
+
+const (
+ rsaKeyFile = "key.pem"
+ rsa1024KeyFile = "rsa_1024_key.pem"
+ rsaChainKeyFile = "rsa_chain_key.pem"
+ ecdsaP224KeyFile = "ecdsa_p224_key.pem"
+ ecdsaP256KeyFile = "ecdsa_p256_key.pem"
+ ecdsaP384KeyFile = "ecdsa_p384_key.pem"
+ ecdsaP521KeyFile = "ecdsa_p521_key.pem"
+ channelIDKeyFile = "channel_id_key.pem"
+)
+
+var (
+ rsaCertificate Certificate
+ rsa1024Certificate Certificate
+ rsaChainCertificate Certificate
+ ecdsaP224Certificate Certificate
+ ecdsaP256Certificate Certificate
+ ecdsaP384Certificate Certificate
+ ecdsaP521Certificate Certificate
+)
+
+var testCerts = []struct {
+ id testCert
+ certFile, keyFile string
+ cert *Certificate
+}{
+ {
+ id: testCertRSA,
+ certFile: rsaCertificateFile,
+ keyFile: rsaKeyFile,
+ cert: &rsaCertificate,
+ },
+ {
+ id: testCertRSA1024,
+ certFile: rsa1024CertificateFile,
+ keyFile: rsa1024KeyFile,
+ cert: &rsa1024Certificate,
+ },
+ {
+ id: testCertRSAChain,
+ certFile: rsaChainCertificateFile,
+ keyFile: rsaChainKeyFile,
+ cert: &rsaChainCertificate,
+ },
+ {
+ id: testCertECDSAP224,
+ certFile: ecdsaP224CertificateFile,
+ keyFile: ecdsaP224KeyFile,
+ cert: &ecdsaP224Certificate,
+ },
+ {
+ id: testCertECDSAP256,
+ certFile: ecdsaP256CertificateFile,
+ keyFile: ecdsaP256KeyFile,
+ cert: &ecdsaP256Certificate,
+ },
+ {
+ id: testCertECDSAP384,
+ certFile: ecdsaP384CertificateFile,
+ keyFile: ecdsaP384KeyFile,
+ cert: &ecdsaP384Certificate,
+ },
+ {
+ id: testCertECDSAP521,
+ certFile: ecdsaP521CertificateFile,
+ keyFile: ecdsaP521KeyFile,
+ cert: &ecdsaP521Certificate,
+ },
+}
+
+var channelIDKey *ecdsa.PrivateKey
+var channelIDBytes []byte
+
+var testOCSPResponse = []byte{1, 2, 3, 4}
+var testSCTList = []byte{0, 6, 0, 4, 5, 6, 7, 8}
+
+var testOCSPExtension = append([]byte{byte(extensionStatusRequest) >> 8, byte(extensionStatusRequest), 0, 8, statusTypeOCSP, 0, 0, 4}, testOCSPResponse...)
+var testSCTExtension = append([]byte{byte(extensionSignedCertificateTimestamp) >> 8, byte(extensionSignedCertificateTimestamp), 0, byte(len(testSCTList))}, testSCTList...)
+
+func initCertificates() {
+ for i := range testCerts {
+ cert, err := LoadX509KeyPair(path.Join(*resourceDir, testCerts[i].certFile), path.Join(*resourceDir, testCerts[i].keyFile))
+ if err != nil {
+ panic(err)
+ }
+ cert.OCSPStaple = testOCSPResponse
+ cert.SignedCertificateTimestampList = testSCTList
+ *testCerts[i].cert = cert
+ }
+
+ channelIDPEMBlock, err := ioutil.ReadFile(path.Join(*resourceDir, channelIDKeyFile))
+ if err != nil {
+ panic(err)
+ }
+ channelIDDERBlock, _ := pem.Decode(channelIDPEMBlock)
+ if channelIDDERBlock.Type != "EC PRIVATE KEY" {
+ panic("bad key type")
+ }
+ channelIDKey, err = x509.ParseECPrivateKey(channelIDDERBlock.Bytes)
+ if err != nil {
+ panic(err)
+ }
+ if channelIDKey.Curve != elliptic.P256() {
+ panic("bad curve")
+ }
+
+ channelIDBytes = make([]byte, 64)
+ writeIntPadded(channelIDBytes[:32], channelIDKey.X)
+ writeIntPadded(channelIDBytes[32:], channelIDKey.Y)
+}
+
+func getRunnerCertificate(t testCert) Certificate {
+ for _, cert := range testCerts {
+ if cert.id == t {
+ return *cert.cert
+ }
+ }
+ panic("Unknown test certificate")
+}
+
+func getShimCertificate(t testCert) string {
+ for _, cert := range testCerts {
+ if cert.id == t {
+ return cert.certFile
+ }
+ }
+ panic("Unknown test certificate")
+}
+
+func getShimKey(t testCert) string {
+ for _, cert := range testCerts {
+ if cert.id == t {
+ return cert.keyFile
+ }
+ }
+ panic("Unknown test certificate")
+}
+
+// encodeDERValues encodes a series of bytestrings in comma-separated-hex form.
+func encodeDERValues(values [][]byte) string {
+ var ret string
+ for i, v := range values {
+ if i > 0 {
+ ret += ","
+ }
+ ret += hex.EncodeToString(v)
+ }
+
+ return ret
+}
+
+type testType int
+
+const (
+ clientTest testType = iota
+ serverTest
+)
+
+type protocol int
+
+const (
+ tls protocol = iota
+ dtls
+)
+
+const (
+ alpn = 1
+ npn = 2
+)
+
+type testCase struct {
+ testType testType
+ protocol protocol
+ name string
+ config Config
+ shouldFail bool
+ expectedError string
+ // expectedLocalError, if not empty, contains a substring that must be
+ // found in the local error.
+ expectedLocalError string
+ // expectedVersion, if non-zero, specifies the TLS version that must be
+ // negotiated.
+ expectedVersion uint16
+ // expectedResumeVersion, if non-zero, specifies the TLS version that
+ // must be negotiated on resumption. If zero, expectedVersion is used.
+ expectedResumeVersion uint16
+ // expectedCipher, if non-zero, specifies the TLS cipher suite that
+ // should be negotiated.
+ expectedCipher uint16
+ // expectChannelID controls whether the connection should have
+ // negotiated a Channel ID with channelIDKey.
+ expectChannelID bool
+ // expectedNextProto controls whether the connection should
+ // negotiate a next protocol via NPN or ALPN.
+ expectedNextProto string
+ // expectNoNextProto, if true, means that no next protocol should be
+ // negotiated.
+ expectNoNextProto bool
+ // expectedNextProtoType, if non-zero, is the expected next
+ // protocol negotiation mechanism.
+ expectedNextProtoType int
+ // expectedSRTPProtectionProfile is the DTLS-SRTP profile that
+ // should be negotiated. If zero, none should be negotiated.
+ expectedSRTPProtectionProfile uint16
+ // expectedOCSPResponse, if not nil, is the expected OCSP response to be received.
+ expectedOCSPResponse []uint8
+ // expectedSCTList, if not nil, is the expected SCT list to be received.
+ expectedSCTList []uint8
+ // expectedPeerSignatureAlgorithm, if not zero, is the signature
+ // algorithm that the peer should have used in the handshake.
+ expectedPeerSignatureAlgorithm signatureAlgorithm
+ // expectedCurveID, if not zero, is the curve that the handshake should
+ // have used.
+ expectedCurveID CurveID
+ // messageLen is the length, in bytes, of the test message that will be
+ // sent.
+ messageLen int
+ // messageCount is the number of test messages that will be sent.
+ messageCount int
+ // certFile is the path to the certificate to use for the server.
+ certFile string
+ // keyFile is the path to the private key to use for the server.
+ keyFile string
+ // resumeSession controls whether a second connection should be tested
+ // which attempts to resume the first session.
+ resumeSession bool
+ // resumeRenewedSession controls whether a third connection should be
+ // tested which attempts to resume the second connection's session.
+ resumeRenewedSession bool
+ // expectResumeRejected, if true, specifies that the attempted
+ // resumption must be rejected by the client. This is only valid for a
+ // serverTest.
+ expectResumeRejected bool
+ // resumeConfig, if not nil, points to a Config to be used on
+ // resumption. Unless newSessionsOnResume is set,
+ // SessionTicketKey, ServerSessionCache, and
+ // ClientSessionCache are copied from the initial connection's
+ // config. If nil, the initial connection's config is used.
+ resumeConfig *Config
+ // newSessionsOnResume, if true, will cause resumeConfig to
+ // use a different session resumption context.
+ newSessionsOnResume bool
+ // noSessionCache, if true, will cause the server to run without a
+ // session cache.
+ noSessionCache bool
+ // sendPrefix sends a prefix on the socket before actually performing a
+ // handshake.
+ sendPrefix string
+ // shimWritesFirst controls whether the shim sends an initial "hello"
+ // message before doing a roundtrip with the runner.
+ shimWritesFirst bool
+ // shimShutsDown, if true, runs a test where the shim shuts down the
+ // connection immediately after the handshake rather than echoing
+ // messages from the runner.
+ shimShutsDown bool
+ // renegotiate indicates the number of times the connection should be
+ // renegotiated during the exchange.
+ renegotiate int
+ // sendHalfHelloRequest, if true, causes the server to send half a
+ // HelloRequest when the handshake completes.
+ sendHalfHelloRequest bool
+ // renegotiateCiphers is a list of ciphersuite ids that will be
+ // switched in just before renegotiation.
+ renegotiateCiphers []uint16
+ // replayWrites, if true, configures the underlying transport
+ // to replay every write it makes in DTLS tests.
+ replayWrites bool
+ // damageFirstWrite, if true, configures the underlying transport to
+ // damage the final byte of the first application data write.
+ damageFirstWrite bool
+ // exportKeyingMaterial, if non-zero, configures the test to exchange
+ // keying material and verify they match.
+ exportKeyingMaterial int
+ exportLabel string
+ exportContext string
+ useExportContext bool
+ // flags, if not empty, contains a list of command-line flags that will
+ // be passed to the shim program.
+ flags []string
+ // testTLSUnique, if true, causes the shim to send the tls-unique value
+ // which will be compared against the expected value.
+ testTLSUnique bool
+ // sendEmptyRecords is the number of consecutive empty records to send
+ // before and after the test message.
+ sendEmptyRecords int
+ // sendWarningAlerts is the number of consecutive warning alerts to send
+ // before and after the test message.
+ sendWarningAlerts int
+ // sendKeyUpdates is the number of consecutive key updates to send
+ // before and after the test message.
+ sendKeyUpdates int
+ // keyUpdateRequest is the KeyUpdateRequest value to send in KeyUpdate messages.
+ keyUpdateRequest byte
+ // expectMessageDropped, if true, means the test message is expected to
+ // be dropped by the client rather than echoed back.
+ expectMessageDropped bool
+ // expectPeerCertificate, if not nil, is the certificate chain the peer
+ // is expected to send.
+ expectPeerCertificate *Certificate
+}
+
+var testCases []testCase
+
+func writeTranscript(test *testCase, num int, data []byte) {
+ if len(data) == 0 {
+ return
+ }
+
+ protocol := "tls"
+ if test.protocol == dtls {
+ protocol = "dtls"
+ }
+
+ side := "client"
+ if test.testType == serverTest {
+ side = "server"
+ }
+
+ dir := path.Join(*transcriptDir, protocol, side)
+ if err := os.MkdirAll(dir, 0755); err != nil {
+ fmt.Fprintf(os.Stderr, "Error making %s: %s\n", dir, err)
+ return
+ }
+
+ name := fmt.Sprintf("%s-%d", test.name, num)
+ if err := ioutil.WriteFile(path.Join(dir, name), data, 0644); err != nil {
+ fmt.Fprintf(os.Stderr, "Error writing %s: %s\n", name, err)
+ }
+}
+
+// A timeoutConn implements an idle timeout on each Read and Write operation.
+type timeoutConn struct {
+ net.Conn
+ timeout time.Duration
+}
+
+func (t *timeoutConn) Read(b []byte) (int, error) {
+ 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
+ }
+ return t.Conn.Write(b)
+}
+
+func doExchange(test *testCase, config *Config, conn net.Conn, isResume bool, num int) error {
+ if !test.noSessionCache {
+ if config.ClientSessionCache == nil {
+ config.ClientSessionCache = NewLRUClientSessionCache(1)
+ }
+ if config.ServerSessionCache == nil {
+ config.ServerSessionCache = NewLRUServerSessionCache(1)
+ }
+ }
+ if test.testType == clientTest {
+ if len(config.Certificates) == 0 {
+ config.Certificates = []Certificate{rsaCertificate}
+ }
+ } else {
+ // Supply a ServerName to ensure a constant session cache key,
+ // rather than falling back to net.Conn.RemoteAddr.
+ if len(config.ServerName) == 0 {
+ config.ServerName = "test"
+ }
+ }
+ if *fuzzer {
+ config.Bugs.NullAllCiphers = true
+ }
+ if *deterministic {
+ config.Time = func() time.Time { return time.Unix(1234, 1234) }
+ }
+
+ conn = &timeoutConn{conn, *idleTimeout}
+
+ if test.protocol == dtls {
+ config.Bugs.PacketAdaptor = newPacketAdaptor(conn)
+ conn = config.Bugs.PacketAdaptor
+ }
+
+ if *flagDebug || len(*transcriptDir) != 0 {
+ local, peer := "client", "server"
+ if test.testType == clientTest {
+ local, peer = peer, local
+ }
+ connDebug := &recordingConn{
+ Conn: conn,
+ isDatagram: test.protocol == dtls,
+ local: local,
+ peer: peer,
+ }
+ conn = connDebug
+ if *flagDebug {
+ defer connDebug.WriteTo(os.Stdout)
+ }
+ if len(*transcriptDir) != 0 {
+ defer func() {
+ writeTranscript(test, num, connDebug.Transcript())
+ }()
+ }
+
+ if config.Bugs.PacketAdaptor != nil {
+ config.Bugs.PacketAdaptor.debug = connDebug
+ }
+ }
+
+ if test.replayWrites {
+ conn = newReplayAdaptor(conn)
+ }
+
+ var connDamage *damageAdaptor
+ if test.damageFirstWrite {
+ connDamage = newDamageAdaptor(conn)
+ conn = connDamage
+ }
+
+ if test.sendPrefix != "" {
+ if _, err := conn.Write([]byte(test.sendPrefix)); err != nil {
+ return err
+ }
+ }
+
+ var tlsConn *Conn
+ if test.testType == clientTest {
+ if test.protocol == dtls {
+ tlsConn = DTLSServer(conn, config)
+ } else {
+ tlsConn = Server(conn, config)
+ }
+ } else {
+ config.InsecureSkipVerify = true
+ if test.protocol == dtls {
+ tlsConn = DTLSClient(conn, config)
+ } else {
+ tlsConn = Client(conn, config)
+ }
+ }
+ defer tlsConn.Close()
+
+ if err := tlsConn.Handshake(); err != nil {
+ return err
+ }
+
+ // TODO(davidben): move all per-connection expectations into a dedicated
+ // expectations struct that can be specified separately for the two
+ // legs.
+ expectedVersion := test.expectedVersion
+ if isResume && test.expectedResumeVersion != 0 {
+ expectedVersion = test.expectedResumeVersion
+ }
+ connState := tlsConn.ConnectionState()
+ if vers := connState.Version; expectedVersion != 0 && vers != expectedVersion {
+ return fmt.Errorf("got version %x, expected %x", vers, expectedVersion)
+ }
+
+ if cipher := connState.CipherSuite; test.expectedCipher != 0 && cipher != test.expectedCipher {
+ return fmt.Errorf("got cipher %x, expected %x", cipher, test.expectedCipher)
+ }
+ if didResume := connState.DidResume; isResume && didResume == test.expectResumeRejected {
+ return fmt.Errorf("didResume is %t, but we expected the opposite", didResume)
+ }
+
+ if test.expectChannelID {
+ channelID := connState.ChannelID
+ if channelID == nil {
+ return fmt.Errorf("no channel ID negotiated")
+ }
+ if channelID.Curve != channelIDKey.Curve ||
+ channelIDKey.X.Cmp(channelIDKey.X) != 0 ||
+ channelIDKey.Y.Cmp(channelIDKey.Y) != 0 {
+ return fmt.Errorf("incorrect channel ID")
+ }
+ }
+
+ if expected := test.expectedNextProto; expected != "" {
+ if actual := connState.NegotiatedProtocol; actual != expected {
+ return fmt.Errorf("next proto mismatch: got %s, wanted %s", actual, expected)
+ }
+ }
+
+ if test.expectNoNextProto {
+ if actual := connState.NegotiatedProtocol; actual != "" {
+ return fmt.Errorf("got unexpected next proto %s", actual)
+ }
+ }
+
+ if test.expectedNextProtoType != 0 {
+ if (test.expectedNextProtoType == alpn) != connState.NegotiatedProtocolFromALPN {
+ return fmt.Errorf("next proto type mismatch")
+ }
+ }
+
+ if p := connState.SRTPProtectionProfile; p != test.expectedSRTPProtectionProfile {
+ return fmt.Errorf("SRTP profile mismatch: got %d, wanted %d", p, test.expectedSRTPProtectionProfile)
+ }
+
+ if test.expectedOCSPResponse != nil && !bytes.Equal(test.expectedOCSPResponse, tlsConn.OCSPResponse()) {
+ return fmt.Errorf("OCSP Response mismatch: got %x, wanted %x", tlsConn.OCSPResponse(), test.expectedOCSPResponse)
+ }
+
+ if test.expectedSCTList != nil && !bytes.Equal(test.expectedSCTList, connState.SCTList) {
+ return fmt.Errorf("SCT list mismatch")
+ }
+
+ if expected := test.expectedPeerSignatureAlgorithm; expected != 0 && expected != connState.PeerSignatureAlgorithm {
+ return fmt.Errorf("expected peer to use signature algorithm %04x, but got %04x", expected, connState.PeerSignatureAlgorithm)
+ }
+
+ if expected := test.expectedCurveID; expected != 0 && expected != connState.CurveID {
+ return fmt.Errorf("expected peer to use curve %04x, but got %04x", expected, connState.CurveID)
+ }
+
+ if test.expectPeerCertificate != nil {
+ if len(connState.PeerCertificates) != len(test.expectPeerCertificate.Certificate) {
+ return fmt.Errorf("expected peer to send %d certificates, but got %d", len(connState.PeerCertificates), len(test.expectPeerCertificate.Certificate))
+ }
+ for i, cert := range connState.PeerCertificates {
+ if !bytes.Equal(cert.Raw, test.expectPeerCertificate.Certificate[i]) {
+ return fmt.Errorf("peer certificate %d did not match", i+1)
+ }
+ }
+ }
+
+ if test.exportKeyingMaterial > 0 {
+ actual := make([]byte, test.exportKeyingMaterial)
+ if _, err := io.ReadFull(tlsConn, actual); err != nil {
+ return err
+ }
+ expected, err := tlsConn.ExportKeyingMaterial(test.exportKeyingMaterial, []byte(test.exportLabel), []byte(test.exportContext), test.useExportContext)
+ if err != nil {
+ return err
+ }
+ if !bytes.Equal(actual, expected) {
+ return fmt.Errorf("keying material mismatch")
+ }
+ }
+
+ if test.testTLSUnique {
+ var peersValue [12]byte
+ if _, err := io.ReadFull(tlsConn, peersValue[:]); err != nil {
+ return err
+ }
+ expected := tlsConn.ConnectionState().TLSUnique
+ if !bytes.Equal(peersValue[:], expected) {
+ return fmt.Errorf("tls-unique mismatch: peer sent %x, but %x was expected", peersValue[:], expected)
+ }
+ }
+
+ if test.shimWritesFirst {
+ var buf [5]byte
+ _, err := io.ReadFull(tlsConn, buf[:])
+ if err != nil {
+ return err
+ }
+ if string(buf[:]) != "hello" {
+ return fmt.Errorf("bad initial message")
+ }
+ }
+
+ for i := 0; i < test.sendKeyUpdates; i++ {
+ if err := tlsConn.SendKeyUpdate(test.keyUpdateRequest); err != nil {
+ return err
+ }
+ }
+
+ for i := 0; i < test.sendEmptyRecords; i++ {
+ tlsConn.Write(nil)
+ }
+
+ for i := 0; i < test.sendWarningAlerts; i++ {
+ tlsConn.SendAlert(alertLevelWarning, alertUnexpectedMessage)
+ }
+
+ if test.sendHalfHelloRequest {
+ tlsConn.SendHalfHelloRequest()
+ }
+
+ if test.renegotiate > 0 {
+ if test.renegotiateCiphers != nil {
+ config.CipherSuites = test.renegotiateCiphers
+ }
+ for i := 0; i < test.renegotiate; i++ {
+ if err := tlsConn.Renegotiate(); err != nil {
+ return err
+ }
+ }
+ } else if test.renegotiateCiphers != nil {
+ panic("renegotiateCiphers without renegotiate")
+ }
+
+ if test.damageFirstWrite {
+ connDamage.setDamage(true)
+ tlsConn.Write([]byte("DAMAGED WRITE"))
+ connDamage.setDamage(false)
+ }
+
+ messageLen := test.messageLen
+ if messageLen < 0 {
+ if test.protocol == dtls {
+ return fmt.Errorf("messageLen < 0 not supported for DTLS tests")
+ }
+ // Read until EOF.
+ _, err := io.Copy(ioutil.Discard, tlsConn)
+ return err
+ }
+ if messageLen == 0 {
+ messageLen = 32
+ }
+
+ messageCount := test.messageCount
+ if messageCount == 0 {
+ messageCount = 1
+ }
+
+ for j := 0; j < messageCount; j++ {
+ testMessage := make([]byte, messageLen)
+ for i := range testMessage {
+ testMessage[i] = 0x42 ^ byte(j)
+ }
+ tlsConn.Write(testMessage)
+
+ for i := 0; i < test.sendKeyUpdates; i++ {
+ tlsConn.SendKeyUpdate(test.keyUpdateRequest)
+ }
+
+ for i := 0; i < test.sendEmptyRecords; i++ {
+ tlsConn.Write(nil)
+ }
+
+ for i := 0; i < test.sendWarningAlerts; i++ {
+ tlsConn.SendAlert(alertLevelWarning, alertUnexpectedMessage)
+ }
+
+ if test.shimShutsDown || test.expectMessageDropped {
+ // The shim will not respond.
+ continue
+ }
+
+ buf := make([]byte, len(testMessage))
+ if test.protocol == dtls {
+ bufTmp := make([]byte, len(buf)+1)
+ n, err := tlsConn.Read(bufTmp)
+ if err != nil {
+ return err
+ }
+ if n != len(buf) {
+ return fmt.Errorf("bad reply; length mismatch (%d vs %d)", n, len(buf))
+ }
+ copy(buf, bufTmp)
+ } else {
+ _, err := io.ReadFull(tlsConn, buf)
+ if err != nil {
+ return err
+ }
+ }
+
+ for i, v := range buf {
+ if v != testMessage[i]^0xff {
+ return fmt.Errorf("bad reply contents at byte %d", i)
+ }
+ }
+ }
+
+ return nil
+}
+
+func valgrindOf(dbAttach bool, path string, args ...string) *exec.Cmd {
+ valgrindArgs := []string{"--error-exitcode=99", "--track-origins=yes", "--leak-check=full", "--quiet"}
+ if dbAttach {
+ valgrindArgs = append(valgrindArgs, "--db-attach=yes", "--db-command=xterm -e gdb -nw %f %p")
+ }
+ valgrindArgs = append(valgrindArgs, path)
+ valgrindArgs = append(valgrindArgs, args...)
+
+ return exec.Command("valgrind", valgrindArgs...)
+}
+
+func gdbOf(path string, args ...string) *exec.Cmd {
+ xtermArgs := []string{"-e", "gdb", "--args"}
+ xtermArgs = append(xtermArgs, path)
+ xtermArgs = append(xtermArgs, args...)
+
+ return exec.Command("xterm", xtermArgs...)
+}
+
+func lldbOf(path string, args ...string) *exec.Cmd {
+ xtermArgs := []string{"-e", "lldb", "--"}
+ xtermArgs = append(xtermArgs, path)
+ xtermArgs = append(xtermArgs, args...)
+
+ return exec.Command("xterm", xtermArgs...)
+}
+
+var (
+ errMoreMallocs = errors.New("child process did not exhaust all allocation calls")
+ errUnimplemented = errors.New("child process does not implement needed flags")
+)
+
+// accept accepts a connection from listener, unless waitChan signals a process
+// exit first.
+func acceptOrWait(listener net.Listener, waitChan chan error) (net.Conn, error) {
+ type connOrError struct {
+ conn net.Conn
+ err error
+ }
+ connChan := make(chan connOrError, 1)
+ go func() {
+ conn, err := listener.Accept()
+ connChan <- connOrError{conn, err}
+ close(connChan)
+ }()
+ select {
+ case result := <-connChan:
+ return result.conn, result.err
+ case childErr := <-waitChan:
+ waitChan <- childErr
+ return nil, fmt.Errorf("child exited early: %s", childErr)
+ }
+}
+
+func translateExpectedError(errorStr string) string {
+ if translated, ok := shimConfig.ErrorMap[errorStr]; ok {
+ return translated
+ }
+
+ if *looseErrors {
+ return ""
+ }
+
+ return errorStr
+}
+
+func runTest(test *testCase, shimPath string, mallocNumToFail int64) error {
+ // Help debugging panics on the Go side.
+ defer func() {
+ if r := recover(); r != nil {
+ fmt.Fprintf(os.Stderr, "Test '%s' panicked.\n", test.name)
+ panic(r)
+ }
+ }()
+
+ if !test.shouldFail && (len(test.expectedError) > 0 || len(test.expectedLocalError) > 0) {
+ panic("Error expected without shouldFail in " + test.name)
+ }
+
+ if test.expectResumeRejected && !test.resumeSession {
+ panic("expectResumeRejected without resumeSession in " + test.name)
+ }
+
+ for _, ver := range tlsVersions {
+ if !strings.Contains("-"+test.name+"-", "-"+ver.name+"-") {
+ continue
+ }
+
+ if test.config.MaxVersion != 0 || test.config.MinVersion != 0 || test.expectedVersion != 0 {
+ continue
+ }
+
+ panic(fmt.Sprintf("The name of test %q suggests that it's version specific, but min/max version in the Config is %x/%x. One of them should probably be %x", test.name, test.config.MinVersion, test.config.MaxVersion, ver.version))
+ }
+
+ listener, err := net.ListenTCP("tcp4", &net.TCPAddr{IP: net.IP{127, 0, 0, 1}})
+ if err != nil {
+ panic(err)
+ }
+ defer func() {
+ if listener != nil {
+ listener.Close()
+ }
+ }()
+
+ flags := []string{"-port", strconv.Itoa(listener.Addr().(*net.TCPAddr).Port)}
+ if test.testType == serverTest {
+ flags = append(flags, "-server")
+
+ flags = append(flags, "-key-file")
+ if test.keyFile == "" {
+ flags = append(flags, path.Join(*resourceDir, rsaKeyFile))
+ } else {
+ flags = append(flags, path.Join(*resourceDir, test.keyFile))
+ }
+
+ flags = append(flags, "-cert-file")
+ if test.certFile == "" {
+ flags = append(flags, path.Join(*resourceDir, rsaCertificateFile))
+ } else {
+ flags = append(flags, path.Join(*resourceDir, test.certFile))
+ }
+ }
+
+ if test.protocol == dtls {
+ flags = append(flags, "-dtls")
+ }
+
+ var resumeCount int
+ if test.resumeSession {
+ resumeCount++
+ if test.resumeRenewedSession {
+ resumeCount++
+ }
+ }
+
+ if resumeCount > 0 {
+ flags = append(flags, "-resume-count", strconv.Itoa(resumeCount))
+ }
+
+ if test.shimWritesFirst {
+ flags = append(flags, "-shim-writes-first")
+ }
+
+ if test.shimShutsDown {
+ flags = append(flags, "-shim-shuts-down")
+ }
+
+ if test.exportKeyingMaterial > 0 {
+ flags = append(flags, "-export-keying-material", strconv.Itoa(test.exportKeyingMaterial))
+ flags = append(flags, "-export-label", test.exportLabel)
+ flags = append(flags, "-export-context", test.exportContext)
+ if test.useExportContext {
+ flags = append(flags, "-use-export-context")
+ }
+ }
+ if test.expectResumeRejected {
+ flags = append(flags, "-expect-session-miss")
+ }
+
+ if test.testTLSUnique {
+ flags = append(flags, "-tls-unique")
+ }
+
+ flags = append(flags, test.flags...)
+
+ var shim *exec.Cmd
+ if *useValgrind {
+ shim = valgrindOf(false, shimPath, flags...)
+ } else if *useGDB {
+ shim = gdbOf(shimPath, flags...)
+ } else if *useLLDB {
+ shim = lldbOf(shimPath, flags...)
+ } else {
+ shim = exec.Command(shimPath, flags...)
+ }
+ shim.Stdin = os.Stdin
+ var stdoutBuf, stderrBuf bytes.Buffer
+ shim.Stdout = &stdoutBuf
+ shim.Stderr = &stderrBuf
+ if mallocNumToFail >= 0 {
+ shim.Env = os.Environ()
+ shim.Env = append(shim.Env, "MALLOC_NUMBER_TO_FAIL="+strconv.FormatInt(mallocNumToFail, 10))
+ if *mallocTestDebug {
+ shim.Env = append(shim.Env, "MALLOC_BREAK_ON_FAIL=1")
+ }
+ shim.Env = append(shim.Env, "_MALLOC_CHECK=1")
+ }
+
+ if err := shim.Start(); err != nil {
+ panic(err)
+ }
+ waitChan := make(chan error, 1)
+ go func() { waitChan <- shim.Wait() }()
+
+ config := test.config
+
+ if *deterministic {
+ config.Rand = &deterministicRand{}
+ }
+
+ conn, err := acceptOrWait(listener, waitChan)
+ if err == nil {
+ err = doExchange(test, &config, conn, false /* not a resumption */, 0)
+ conn.Close()
+ }
+
+ for i := 0; err == nil && i < resumeCount; i++ {
+ var resumeConfig Config
+ if test.resumeConfig != nil {
+ resumeConfig = *test.resumeConfig
+ if !test.newSessionsOnResume {
+ resumeConfig.SessionTicketKey = config.SessionTicketKey
+ resumeConfig.ClientSessionCache = config.ClientSessionCache
+ resumeConfig.ServerSessionCache = config.ServerSessionCache
+ }
+ resumeConfig.Rand = config.Rand
+ } else {
+ resumeConfig = config
+ }
+ var connResume net.Conn
+ connResume, err = acceptOrWait(listener, waitChan)
+ if err == nil {
+ err = doExchange(test, &resumeConfig, connResume, true /* resumption */, i+1)
+ connResume.Close()
+ }
+ }
+
+ // Close the listener now. This is to avoid hangs should the shim try to
+ // open more connections than expected.
+ listener.Close()
+ listener = nil
+
+ childErr := <-waitChan
+ var isValgrindError bool
+ if exitError, ok := childErr.(*exec.ExitError); ok {
+ switch exitError.Sys().(syscall.WaitStatus).ExitStatus() {
+ case 88:
+ return errMoreMallocs
+ case 89:
+ return errUnimplemented
+ case 99:
+ isValgrindError = true
+ }
+ }
+
+ // Account for Windows line endings.
+ stdout := strings.Replace(string(stdoutBuf.Bytes()), "\r\n", "\n", -1)
+ stderr := strings.Replace(string(stderrBuf.Bytes()), "\r\n", "\n", -1)
+
+ // Separate the errors from the shim and those from tools like
+ // AddressSanitizer.
+ var extraStderr string
+ if stderrParts := strings.SplitN(stderr, "--- DONE ---\n", 2); len(stderrParts) == 2 {
+ stderr = stderrParts[0]
+ extraStderr = stderrParts[1]
+ }
+
+ failed := err != nil || childErr != nil
+ expectedError := translateExpectedError(test.expectedError)
+ correctFailure := len(expectedError) == 0 || strings.Contains(stderr, expectedError)
+
+ localError := "none"
+ if err != nil {
+ localError = err.Error()
+ }
+ if len(test.expectedLocalError) != 0 {
+ correctFailure = correctFailure && strings.Contains(localError, test.expectedLocalError)
+ }
+
+ if failed != test.shouldFail || failed && !correctFailure {
+ childError := "none"
+ if childErr != nil {
+ childError = childErr.Error()
+ }
+
+ var msg string
+ switch {
+ case failed && !test.shouldFail:
+ msg = "unexpected failure"
+ case !failed && test.shouldFail:
+ msg = "unexpected success"
+ case failed && !correctFailure:
+ msg = "bad error (wanted '" + expectedError + "' / '" + test.expectedLocalError + "')"
+ default:
+ panic("internal error")
+ }
+
+ return fmt.Errorf("%s: local error '%s', child error '%s', stdout:\n%s\nstderr:\n%s\n%s", msg, localError, childError, stdout, stderr, extraStderr)
+ }
+
+ if len(extraStderr) > 0 || (!failed && len(stderr) > 0) {
+ return fmt.Errorf("unexpected error output:\n%s\n%s", stderr, extraStderr)
+ }
+
+ if *useValgrind && isValgrindError {
+ return fmt.Errorf("valgrind error:\n%s\n%s", stderr, extraStderr)
+ }
+
+ return nil
+}
+
+type tlsVersion struct {
+ name string
+ version uint16
+ flag string
+ hasDTLS bool
+}
+
+var tlsVersions = []tlsVersion{
+ {"SSL3", VersionSSL30, "-no-ssl3", false},
+ {"TLS1", VersionTLS10, "-no-tls1", true},
+ {"TLS11", VersionTLS11, "-no-tls11", false},
+ {"TLS12", VersionTLS12, "-no-tls12", true},
+ {"TLS13", VersionTLS13, "-no-tls13", false},
+}
+
+type testCipherSuite struct {
+ name string
+ id uint16
+}
+
+var testCipherSuites = []testCipherSuite{
+ {"3DES-SHA", TLS_RSA_WITH_3DES_EDE_CBC_SHA},
+ {"AES128-GCM", TLS_RSA_WITH_AES_128_GCM_SHA256},
+ {"AES128-SHA", TLS_RSA_WITH_AES_128_CBC_SHA},
+ {"AES128-SHA256", TLS_RSA_WITH_AES_128_CBC_SHA256},
+ {"AES256-GCM", TLS_RSA_WITH_AES_256_GCM_SHA384},
+ {"AES256-SHA", TLS_RSA_WITH_AES_256_CBC_SHA},
+ {"AES256-SHA256", TLS_RSA_WITH_AES_256_CBC_SHA256},
+ {"DHE-RSA-AES128-GCM", TLS_DHE_RSA_WITH_AES_128_GCM_SHA256},
+ {"DHE-RSA-AES128-SHA", TLS_DHE_RSA_WITH_AES_128_CBC_SHA},
+ {"DHE-RSA-AES128-SHA256", TLS_DHE_RSA_WITH_AES_128_CBC_SHA256},
+ {"DHE-RSA-AES256-GCM", TLS_DHE_RSA_WITH_AES_256_GCM_SHA384},
+ {"DHE-RSA-AES256-SHA", TLS_DHE_RSA_WITH_AES_256_CBC_SHA},
+ {"DHE-RSA-AES256-SHA256", TLS_DHE_RSA_WITH_AES_256_CBC_SHA256},
+ {"ECDHE-ECDSA-AES128-GCM", TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
+ {"ECDHE-ECDSA-AES128-SHA", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA},
+ {"ECDHE-ECDSA-AES128-SHA256", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256},
+ {"ECDHE-ECDSA-AES256-GCM", TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384},
+ {"ECDHE-ECDSA-AES256-SHA", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA},
+ {"ECDHE-ECDSA-AES256-SHA384", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384},
+ {"ECDHE-ECDSA-CHACHA20-POLY1305", TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256},
+ {"ECDHE-RSA-AES128-GCM", TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ {"ECDHE-RSA-AES128-SHA", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
+ {"ECDHE-RSA-AES128-SHA256", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256},
+ {"ECDHE-RSA-AES256-GCM", TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384},
+ {"ECDHE-RSA-AES256-SHA", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA},
+ {"ECDHE-RSA-AES256-SHA384", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384},
+ {"ECDHE-RSA-CHACHA20-POLY1305", TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256},
+ {"PSK-AES128-CBC-SHA", TLS_PSK_WITH_AES_128_CBC_SHA},
+ {"PSK-AES256-CBC-SHA", TLS_PSK_WITH_AES_256_CBC_SHA},
+ {"ECDHE-PSK-AES128-CBC-SHA", TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA},
+ {"ECDHE-PSK-AES256-CBC-SHA", TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA},
+ {"ECDHE-PSK-CHACHA20-POLY1305", TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256},
+ {"AEAD-CHACHA20-POLY1305", TLS_CHACHA20_POLY1305_SHA256},
+ {"AEAD-AES128-GCM-SHA256", TLS_AES_128_GCM_SHA256},
+ {"AEAD-AES256-GCM-SHA384", TLS_AES_256_GCM_SHA384},
+ {"NULL-SHA", TLS_RSA_WITH_NULL_SHA},
+}
+
+func hasComponent(suiteName, component string) bool {
+ return strings.Contains("-"+suiteName+"-", "-"+component+"-")
+}
+
+func isTLS12Only(suiteName string) bool {
+ return hasComponent(suiteName, "GCM") ||
+ hasComponent(suiteName, "SHA256") ||
+ hasComponent(suiteName, "SHA384") ||
+ hasComponent(suiteName, "POLY1305")
+}
+
+func isTLS13Suite(suiteName string) bool {
+ return strings.HasPrefix(suiteName, "AEAD-")
+}
+
+func isDTLSCipher(suiteName string) bool {
+ return !hasComponent(suiteName, "RC4") && !hasComponent(suiteName, "NULL")
+}
+
+func bigFromHex(hex string) *big.Int {
+ ret, ok := new(big.Int).SetString(hex, 16)
+ if !ok {
+ panic("failed to parse hex number 0x" + hex)
+ }
+ return ret
+}
+
+func addBasicTests() {
+ basicTests := []testCase{
+ {
+ name: "NoFallbackSCSV",
+ config: Config{
+ Bugs: ProtocolBugs{
+ FailIfNotFallbackSCSV: true,
+ },
+ },
+ shouldFail: true,
+ expectedLocalError: "no fallback SCSV found",
+ },
+ {
+ name: "SendFallbackSCSV",
+ config: Config{
+ Bugs: ProtocolBugs{
+ FailIfNotFallbackSCSV: true,
+ },
+ },
+ flags: []string{"-fallback-scsv"},
+ },
+ {
+ name: "ClientCertificateTypes",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ ClientAuth: RequestClientCert,
+ ClientCertificateTypes: []byte{
+ CertTypeDSSSign,
+ CertTypeRSASign,
+ CertTypeECDSASign,
+ },
+ },
+ flags: []string{
+ "-expect-certificate-types",
+ base64.StdEncoding.EncodeToString([]byte{
+ CertTypeDSSSign,
+ CertTypeRSASign,
+ CertTypeECDSASign,
+ }),
+ },
+ },
+ {
+ name: "UnauthenticatedECDH",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ Bugs: ProtocolBugs{
+ UnauthenticatedECDH: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_MESSAGE:",
+ },
+ {
+ name: "SkipCertificateStatus",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ Bugs: ProtocolBugs{
+ SkipCertificateStatus: true,
+ },
+ },
+ flags: []string{
+ "-enable-ocsp-stapling",
+ },
+ },
+ {
+ name: "SkipServerKeyExchange",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ Bugs: ProtocolBugs{
+ SkipServerKeyExchange: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_MESSAGE:",
+ },
+ {
+ testType: serverTest,
+ name: "Alert",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendSpuriousAlert: alertRecordOverflow,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":TLSV1_ALERT_RECORD_OVERFLOW:",
+ },
+ {
+ protocol: dtls,
+ testType: serverTest,
+ name: "Alert-DTLS",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendSpuriousAlert: alertRecordOverflow,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":TLSV1_ALERT_RECORD_OVERFLOW:",
+ },
+ {
+ testType: serverTest,
+ name: "FragmentAlert",
+ config: Config{
+ Bugs: ProtocolBugs{
+ FragmentAlert: true,
+ SendSpuriousAlert: alertRecordOverflow,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":BAD_ALERT:",
+ },
+ {
+ protocol: dtls,
+ testType: serverTest,
+ name: "FragmentAlert-DTLS",
+ config: Config{
+ Bugs: ProtocolBugs{
+ FragmentAlert: true,
+ SendSpuriousAlert: alertRecordOverflow,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":BAD_ALERT:",
+ },
+ {
+ testType: serverTest,
+ name: "DoubleAlert",
+ config: Config{
+ Bugs: ProtocolBugs{
+ DoubleAlert: true,
+ SendSpuriousAlert: alertRecordOverflow,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":BAD_ALERT:",
+ },
+ {
+ protocol: dtls,
+ testType: serverTest,
+ name: "DoubleAlert-DTLS",
+ config: Config{
+ Bugs: ProtocolBugs{
+ DoubleAlert: true,
+ SendSpuriousAlert: alertRecordOverflow,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":BAD_ALERT:",
+ },
+ {
+ name: "SkipNewSessionTicket",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ SkipNewSessionTicket: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_RECORD:",
+ },
+ {
+ testType: serverTest,
+ name: "FallbackSCSV",
+ config: Config{
+ MaxVersion: VersionTLS11,
+ Bugs: ProtocolBugs{
+ SendFallbackSCSV: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":INAPPROPRIATE_FALLBACK:",
+ expectedLocalError: "remote error: inappropriate fallback",
+ },
+ {
+ testType: serverTest,
+ name: "FallbackSCSV-VersionMatch-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendFallbackSCSV: true,
+ },
+ },
+ },
+ {
+ testType: serverTest,
+ name: "FallbackSCSV-VersionMatch-TLS12",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ SendFallbackSCSV: true,
+ },
+ },
+ flags: []string{"-max-version", strconv.Itoa(VersionTLS12)},
+ },
+ {
+ testType: serverTest,
+ name: "FragmentedClientVersion",
+ config: Config{
+ Bugs: ProtocolBugs{
+ MaxHandshakeRecordLength: 1,
+ FragmentClientVersion: true,
+ },
+ },
+ expectedVersion: VersionTLS13,
+ },
+ {
+ testType: serverTest,
+ name: "HttpGET",
+ sendPrefix: "GET / HTTP/1.0\n",
+ shouldFail: true,
+ expectedError: ":HTTP_REQUEST:",
+ },
+ {
+ testType: serverTest,
+ name: "HttpPOST",
+ sendPrefix: "POST / HTTP/1.0\n",
+ shouldFail: true,
+ expectedError: ":HTTP_REQUEST:",
+ },
+ {
+ testType: serverTest,
+ name: "HttpHEAD",
+ sendPrefix: "HEAD / HTTP/1.0\n",
+ shouldFail: true,
+ expectedError: ":HTTP_REQUEST:",
+ },
+ {
+ testType: serverTest,
+ name: "HttpPUT",
+ sendPrefix: "PUT / HTTP/1.0\n",
+ shouldFail: true,
+ expectedError: ":HTTP_REQUEST:",
+ },
+ {
+ testType: serverTest,
+ name: "HttpCONNECT",
+ sendPrefix: "CONNECT www.google.com:443 HTTP/1.0\n",
+ shouldFail: true,
+ expectedError: ":HTTPS_PROXY_REQUEST:",
+ },
+ {
+ testType: serverTest,
+ name: "Garbage",
+ sendPrefix: "blah",
+ shouldFail: true,
+ expectedError: ":WRONG_VERSION_NUMBER:",
+ },
+ {
+ name: "RSAEphemeralKey",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA},
+ Bugs: ProtocolBugs{
+ RSAEphemeralKey: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_MESSAGE:",
+ },
+ {
+ name: "DisableEverything",
+ flags: []string{"-no-tls13", "-no-tls12", "-no-tls11", "-no-tls1", "-no-ssl3"},
+ shouldFail: true,
+ expectedError: ":WRONG_SSL_VERSION:",
+ },
+ {
+ protocol: dtls,
+ name: "DisableEverything-DTLS",
+ flags: []string{"-no-tls12", "-no-tls1"},
+ shouldFail: true,
+ expectedError: ":WRONG_SSL_VERSION:",
+ },
+ {
+ protocol: dtls,
+ testType: serverTest,
+ name: "MTU",
+ config: Config{
+ Bugs: ProtocolBugs{
+ MaxPacketLength: 256,
+ },
+ },
+ flags: []string{"-mtu", "256"},
+ },
+ {
+ protocol: dtls,
+ testType: serverTest,
+ name: "MTUExceeded",
+ config: Config{
+ Bugs: ProtocolBugs{
+ MaxPacketLength: 255,
+ },
+ },
+ flags: []string{"-mtu", "256"},
+ shouldFail: true,
+ expectedLocalError: "dtls: exceeded maximum packet length",
+ },
+ {
+ name: "CertMismatchRSA",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
+ Certificates: []Certificate{ecdsaP256Certificate},
+ Bugs: ProtocolBugs{
+ SendCipherSuite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":WRONG_CERTIFICATE_TYPE:",
+ },
+ {
+ name: "CertMismatchECDSA",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ Certificates: []Certificate{rsaCertificate},
+ Bugs: ProtocolBugs{
+ SendCipherSuite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":WRONG_CERTIFICATE_TYPE:",
+ },
+ {
+ name: "EmptyCertificateList",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ EmptyCertificateList: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":DECODE_ERROR:",
+ },
+ {
+ name: "EmptyCertificateList-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ EmptyCertificateList: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":PEER_DID_NOT_RETURN_A_CERTIFICATE:",
+ },
+ {
+ name: "TLSFatalBadPackets",
+ damageFirstWrite: true,
+ shouldFail: true,
+ expectedError: ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:",
+ },
+ {
+ protocol: dtls,
+ name: "DTLSIgnoreBadPackets",
+ damageFirstWrite: true,
+ },
+ {
+ protocol: dtls,
+ name: "DTLSIgnoreBadPackets-Async",
+ damageFirstWrite: true,
+ flags: []string{"-async"},
+ },
+ {
+ name: "AppDataBeforeHandshake",
+ config: Config{
+ Bugs: ProtocolBugs{
+ AppDataBeforeHandshake: []byte("TEST MESSAGE"),
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_RECORD:",
+ },
+ {
+ name: "AppDataBeforeHandshake-Empty",
+ config: Config{
+ Bugs: ProtocolBugs{
+ AppDataBeforeHandshake: []byte{},
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_RECORD:",
+ },
+ {
+ protocol: dtls,
+ name: "AppDataBeforeHandshake-DTLS",
+ config: Config{
+ Bugs: ProtocolBugs{
+ AppDataBeforeHandshake: []byte("TEST MESSAGE"),
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_RECORD:",
+ },
+ {
+ protocol: dtls,
+ name: "AppDataBeforeHandshake-DTLS-Empty",
+ config: Config{
+ Bugs: ProtocolBugs{
+ AppDataBeforeHandshake: []byte{},
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_RECORD:",
+ },
+ {
+ name: "AppDataAfterChangeCipherSpec",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ AppDataAfterChangeCipherSpec: []byte("TEST MESSAGE"),
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_RECORD:",
+ },
+ {
+ name: "AppDataAfterChangeCipherSpec-Empty",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ AppDataAfterChangeCipherSpec: []byte{},
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_RECORD:",
+ },
+ {
+ protocol: dtls,
+ name: "AppDataAfterChangeCipherSpec-DTLS",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ AppDataAfterChangeCipherSpec: []byte("TEST MESSAGE"),
+ },
+ },
+ // BoringSSL's DTLS implementation will drop the out-of-order
+ // application data.
+ },
+ {
+ protocol: dtls,
+ name: "AppDataAfterChangeCipherSpec-DTLS-Empty",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ AppDataAfterChangeCipherSpec: []byte{},
+ },
+ },
+ // BoringSSL's DTLS implementation will drop the out-of-order
+ // application data.
+ },
+ {
+ name: "AlertAfterChangeCipherSpec",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ AlertAfterChangeCipherSpec: alertRecordOverflow,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":TLSV1_ALERT_RECORD_OVERFLOW:",
+ },
+ {
+ protocol: dtls,
+ name: "AlertAfterChangeCipherSpec-DTLS",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ AlertAfterChangeCipherSpec: alertRecordOverflow,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":TLSV1_ALERT_RECORD_OVERFLOW:",
+ },
+ {
+ protocol: dtls,
+ name: "ReorderHandshakeFragments-Small-DTLS",
+ config: Config{
+ Bugs: ProtocolBugs{
+ ReorderHandshakeFragments: true,
+ // Small enough that every handshake message is
+ // fragmented.
+ MaxHandshakeRecordLength: 2,
+ },
+ },
+ },
+ {
+ protocol: dtls,
+ name: "ReorderHandshakeFragments-Large-DTLS",
+ config: Config{
+ Bugs: ProtocolBugs{
+ ReorderHandshakeFragments: true,
+ // Large enough that no handshake message is
+ // fragmented.
+ MaxHandshakeRecordLength: 2048,
+ },
+ },
+ },
+ {
+ protocol: dtls,
+ name: "MixCompleteMessageWithFragments-DTLS",
+ config: Config{
+ Bugs: ProtocolBugs{
+ ReorderHandshakeFragments: true,
+ MixCompleteMessageWithFragments: true,
+ MaxHandshakeRecordLength: 2,
+ },
+ },
+ },
+ {
+ name: "SendInvalidRecordType",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendInvalidRecordType: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_RECORD:",
+ },
+ {
+ protocol: dtls,
+ name: "SendInvalidRecordType-DTLS",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendInvalidRecordType: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_RECORD:",
+ },
+ {
+ name: "FalseStart-SkipServerSecondLeg",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ NextProtos: []string{"foo"},
+ Bugs: ProtocolBugs{
+ SkipNewSessionTicket: true,
+ SkipChangeCipherSpec: true,
+ SkipFinished: true,
+ ExpectFalseStart: true,
+ },
+ },
+ flags: []string{
+ "-false-start",
+ "-handshake-never-done",
+ "-advertise-alpn", "\x03foo",
+ },
+ shimWritesFirst: true,
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_RECORD:",
+ },
+ {
+ name: "FalseStart-SkipServerSecondLeg-Implicit",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ NextProtos: []string{"foo"},
+ Bugs: ProtocolBugs{
+ SkipNewSessionTicket: true,
+ SkipChangeCipherSpec: true,
+ SkipFinished: true,
+ },
+ },
+ flags: []string{
+ "-implicit-handshake",
+ "-false-start",
+ "-handshake-never-done",
+ "-advertise-alpn", "\x03foo",
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_RECORD:",
+ },
+ {
+ testType: serverTest,
+ name: "FailEarlyCallback",
+ flags: []string{"-fail-early-callback"},
+ shouldFail: true,
+ expectedError: ":CONNECTION_REJECTED:",
+ expectedLocalError: "remote error: handshake failure",
+ },
+ {
+ name: "FailCertCallback-Client-TLS12",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ ClientAuth: RequestClientCert,
+ },
+ flags: []string{"-fail-cert-callback"},
+ shouldFail: true,
+ expectedError: ":CERT_CB_ERROR:",
+ expectedLocalError: "remote error: internal error",
+ },
+ {
+ testType: serverTest,
+ name: "FailCertCallback-Server-TLS12",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ },
+ flags: []string{"-fail-cert-callback"},
+ shouldFail: true,
+ expectedError: ":CERT_CB_ERROR:",
+ expectedLocalError: "remote error: internal error",
+ },
+ {
+ name: "FailCertCallback-Client-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ ClientAuth: RequestClientCert,
+ },
+ flags: []string{"-fail-cert-callback"},
+ shouldFail: true,
+ expectedError: ":CERT_CB_ERROR:",
+ expectedLocalError: "remote error: internal error",
+ },
+ {
+ testType: serverTest,
+ name: "FailCertCallback-Server-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ },
+ flags: []string{"-fail-cert-callback"},
+ shouldFail: true,
+ expectedError: ":CERT_CB_ERROR:",
+ expectedLocalError: "remote error: internal error",
+ },
+ {
+ protocol: dtls,
+ name: "FragmentMessageTypeMismatch-DTLS",
+ config: Config{
+ Bugs: ProtocolBugs{
+ MaxHandshakeRecordLength: 2,
+ FragmentMessageTypeMismatch: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":FRAGMENT_MISMATCH:",
+ },
+ {
+ protocol: dtls,
+ name: "FragmentMessageLengthMismatch-DTLS",
+ config: Config{
+ Bugs: ProtocolBugs{
+ MaxHandshakeRecordLength: 2,
+ FragmentMessageLengthMismatch: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":FRAGMENT_MISMATCH:",
+ },
+ {
+ protocol: dtls,
+ name: "SplitFragments-Header-DTLS",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SplitFragments: 2,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":BAD_HANDSHAKE_RECORD:",
+ },
+ {
+ protocol: dtls,
+ name: "SplitFragments-Boundary-DTLS",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SplitFragments: dtlsRecordHeaderLen,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":BAD_HANDSHAKE_RECORD:",
+ },
+ {
+ protocol: dtls,
+ name: "SplitFragments-Body-DTLS",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SplitFragments: dtlsRecordHeaderLen + 1,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":BAD_HANDSHAKE_RECORD:",
+ },
+ {
+ protocol: dtls,
+ name: "SendEmptyFragments-DTLS",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendEmptyFragments: true,
+ },
+ },
+ },
+ {
+ name: "BadFinished-Client",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ BadFinished: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":DIGEST_CHECK_FAILED:",
+ },
+ {
+ name: "BadFinished-Client-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ BadFinished: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":DIGEST_CHECK_FAILED:",
+ },
+ {
+ testType: serverTest,
+ name: "BadFinished-Server",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ BadFinished: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":DIGEST_CHECK_FAILED:",
+ },
+ {
+ testType: serverTest,
+ name: "BadFinished-Server-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ BadFinished: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":DIGEST_CHECK_FAILED:",
+ },
+ {
+ name: "FalseStart-BadFinished",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ NextProtos: []string{"foo"},
+ Bugs: ProtocolBugs{
+ BadFinished: true,
+ ExpectFalseStart: true,
+ },
+ },
+ flags: []string{
+ "-false-start",
+ "-handshake-never-done",
+ "-advertise-alpn", "\x03foo",
+ },
+ shimWritesFirst: true,
+ shouldFail: true,
+ expectedError: ":DIGEST_CHECK_FAILED:",
+ },
+ {
+ name: "NoFalseStart-NoALPN",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ Bugs: ProtocolBugs{
+ ExpectFalseStart: true,
+ AlertBeforeFalseStartTest: alertAccessDenied,
+ },
+ },
+ flags: []string{
+ "-false-start",
+ },
+ shimWritesFirst: true,
+ shouldFail: true,
+ expectedError: ":TLSV1_ALERT_ACCESS_DENIED:",
+ expectedLocalError: "tls: peer did not false start: EOF",
+ },
+ {
+ name: "NoFalseStart-NoAEAD",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
+ NextProtos: []string{"foo"},
+ Bugs: ProtocolBugs{
+ ExpectFalseStart: true,
+ AlertBeforeFalseStartTest: alertAccessDenied,
+ },
+ },
+ flags: []string{
+ "-false-start",
+ "-advertise-alpn", "\x03foo",
+ },
+ shimWritesFirst: true,
+ shouldFail: true,
+ expectedError: ":TLSV1_ALERT_ACCESS_DENIED:",
+ expectedLocalError: "tls: peer did not false start: EOF",
+ },
+ {
+ name: "NoFalseStart-RSA",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
+ NextProtos: []string{"foo"},
+ Bugs: ProtocolBugs{
+ ExpectFalseStart: true,
+ AlertBeforeFalseStartTest: alertAccessDenied,
+ },
+ },
+ flags: []string{
+ "-false-start",
+ "-advertise-alpn", "\x03foo",
+ },
+ shimWritesFirst: true,
+ shouldFail: true,
+ expectedError: ":TLSV1_ALERT_ACCESS_DENIED:",
+ expectedLocalError: "tls: peer did not false start: EOF",
+ },
+ {
+ name: "NoFalseStart-DHE_RSA",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_DHE_RSA_WITH_AES_128_GCM_SHA256},
+ NextProtos: []string{"foo"},
+ Bugs: ProtocolBugs{
+ ExpectFalseStart: true,
+ AlertBeforeFalseStartTest: alertAccessDenied,
+ },
+ },
+ flags: []string{
+ "-false-start",
+ "-advertise-alpn", "\x03foo",
+ },
+ shimWritesFirst: true,
+ shouldFail: true,
+ expectedError: ":TLSV1_ALERT_ACCESS_DENIED:",
+ expectedLocalError: "tls: peer did not false start: EOF",
+ },
+ {
+ protocol: dtls,
+ name: "SendSplitAlert-Sync",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendSplitAlert: true,
+ },
+ },
+ },
+ {
+ protocol: dtls,
+ name: "SendSplitAlert-Async",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendSplitAlert: true,
+ },
+ },
+ flags: []string{"-async"},
+ },
+ {
+ protocol: dtls,
+ name: "PackDTLSHandshake",
+ config: Config{
+ Bugs: ProtocolBugs{
+ MaxHandshakeRecordLength: 2,
+ PackHandshakeFragments: 20,
+ PackHandshakeRecords: 200,
+ },
+ },
+ },
+ {
+ name: "SendEmptyRecords-Pass",
+ sendEmptyRecords: 32,
+ },
+ {
+ name: "SendEmptyRecords",
+ sendEmptyRecords: 33,
+ shouldFail: true,
+ expectedError: ":TOO_MANY_EMPTY_FRAGMENTS:",
+ },
+ {
+ name: "SendEmptyRecords-Async",
+ sendEmptyRecords: 33,
+ flags: []string{"-async"},
+ shouldFail: true,
+ expectedError: ":TOO_MANY_EMPTY_FRAGMENTS:",
+ },
+ {
+ name: "SendWarningAlerts-Pass",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ },
+ sendWarningAlerts: 4,
+ },
+ {
+ protocol: dtls,
+ name: "SendWarningAlerts-DTLS-Pass",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ },
+ sendWarningAlerts: 4,
+ },
+ {
+ name: "SendWarningAlerts-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ },
+ sendWarningAlerts: 4,
+ shouldFail: true,
+ expectedError: ":BAD_ALERT:",
+ expectedLocalError: "remote error: error decoding message",
+ },
+ {
+ name: "SendWarningAlerts",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ },
+ sendWarningAlerts: 5,
+ shouldFail: true,
+ expectedError: ":TOO_MANY_WARNING_ALERTS:",
+ },
+ {
+ name: "SendWarningAlerts-Async",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ },
+ sendWarningAlerts: 5,
+ flags: []string{"-async"},
+ shouldFail: true,
+ expectedError: ":TOO_MANY_WARNING_ALERTS:",
+ },
+ {
+ name: "TooManyKeyUpdates",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ },
+ sendKeyUpdates: 33,
+ keyUpdateRequest: keyUpdateNotRequested,
+ shouldFail: true,
+ expectedError: ":TOO_MANY_KEY_UPDATES:",
+ },
+ {
+ name: "EmptySessionID",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ SessionTicketsDisabled: true,
+ },
+ noSessionCache: true,
+ flags: []string{"-expect-no-session"},
+ },
+ {
+ name: "Unclean-Shutdown",
+ config: Config{
+ Bugs: ProtocolBugs{
+ NoCloseNotify: true,
+ ExpectCloseNotify: true,
+ },
+ },
+ shimShutsDown: true,
+ flags: []string{"-check-close-notify"},
+ shouldFail: true,
+ expectedError: "Unexpected SSL_shutdown result: -1 != 1",
+ },
+ {
+ name: "Unclean-Shutdown-Ignored",
+ config: Config{
+ Bugs: ProtocolBugs{
+ NoCloseNotify: true,
+ },
+ },
+ shimShutsDown: true,
+ },
+ {
+ name: "Unclean-Shutdown-Alert",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendAlertOnShutdown: alertDecompressionFailure,
+ ExpectCloseNotify: true,
+ },
+ },
+ shimShutsDown: true,
+ flags: []string{"-check-close-notify"},
+ shouldFail: true,
+ expectedError: ":SSLV3_ALERT_DECOMPRESSION_FAILURE:",
+ },
+ {
+ name: "LargePlaintext",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendLargeRecords: true,
+ },
+ },
+ messageLen: maxPlaintext + 1,
+ shouldFail: true,
+ expectedError: ":DATA_LENGTH_TOO_LONG:",
+ },
+ {
+ protocol: dtls,
+ name: "LargePlaintext-DTLS",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendLargeRecords: true,
+ },
+ },
+ messageLen: maxPlaintext + 1,
+ shouldFail: true,
+ expectedError: ":DATA_LENGTH_TOO_LONG:",
+ },
+ {
+ name: "LargeCiphertext",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendLargeRecords: true,
+ },
+ },
+ messageLen: maxPlaintext * 2,
+ shouldFail: true,
+ expectedError: ":ENCRYPTED_LENGTH_TOO_LONG:",
+ },
+ {
+ protocol: dtls,
+ name: "LargeCiphertext-DTLS",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendLargeRecords: true,
+ },
+ },
+ messageLen: maxPlaintext * 2,
+ // Unlike the other four cases, DTLS drops records which
+ // are invalid before authentication, so the connection
+ // does not fail.
+ expectMessageDropped: true,
+ },
+ {
+ name: "BadHelloRequest-1",
+ renegotiate: 1,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ BadHelloRequest: []byte{typeHelloRequest, 0, 0, 1, 1},
+ },
+ },
+ flags: []string{
+ "-renegotiate-freely",
+ "-expect-total-renegotiations", "1",
+ },
+ shouldFail: true,
+ expectedError: ":EXCESSIVE_MESSAGE_SIZE:",
+ },
+ {
+ name: "BadHelloRequest-2",
+ renegotiate: 1,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ BadHelloRequest: []byte{typeServerKeyExchange, 0, 0, 0},
+ },
+ },
+ flags: []string{
+ "-renegotiate-freely",
+ "-expect-total-renegotiations", "1",
+ },
+ shouldFail: true,
+ expectedError: ":BAD_HELLO_REQUEST:",
+ },
+ {
+ testType: serverTest,
+ name: "SupportTicketsWithSessionID",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ SessionTicketsDisabled: true,
+ },
+ resumeConfig: &Config{
+ MaxVersion: VersionTLS12,
+ },
+ resumeSession: true,
+ },
+ {
+ protocol: dtls,
+ name: "DTLS-SendExtraFinished",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendExtraFinished: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_RECORD:",
+ },
+ {
+ protocol: dtls,
+ name: "DTLS-SendExtraFinished-Reordered",
+ config: Config{
+ Bugs: ProtocolBugs{
+ MaxHandshakeRecordLength: 2,
+ ReorderHandshakeFragments: true,
+ SendExtraFinished: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_RECORD:",
+ },
+ {
+ testType: serverTest,
+ name: "V2ClientHello-EmptyRecordPrefix",
+ config: Config{
+ // Choose a cipher suite that does not involve
+ // elliptic curves, so no extensions are
+ // involved.
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_RSA_WITH_3DES_EDE_CBC_SHA},
+ Bugs: ProtocolBugs{
+ SendV2ClientHello: true,
+ },
+ },
+ sendPrefix: string([]byte{
+ byte(recordTypeHandshake),
+ 3, 1, // version
+ 0, 0, // length
+ }),
+ // A no-op empty record may not be sent before V2ClientHello.
+ shouldFail: true,
+ expectedError: ":WRONG_VERSION_NUMBER:",
+ },
+ {
+ testType: serverTest,
+ name: "V2ClientHello-WarningAlertPrefix",
+ config: Config{
+ // Choose a cipher suite that does not involve
+ // elliptic curves, so no extensions are
+ // involved.
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_RSA_WITH_3DES_EDE_CBC_SHA},
+ Bugs: ProtocolBugs{
+ SendV2ClientHello: true,
+ },
+ },
+ sendPrefix: string([]byte{
+ byte(recordTypeAlert),
+ 3, 1, // version
+ 0, 2, // length
+ alertLevelWarning, byte(alertDecompressionFailure),
+ }),
+ // A no-op warning alert may not be sent before V2ClientHello.
+ shouldFail: true,
+ expectedError: ":WRONG_VERSION_NUMBER:",
+ },
+ {
+ name: "KeyUpdate-Client",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ },
+ sendKeyUpdates: 1,
+ keyUpdateRequest: keyUpdateNotRequested,
+ },
+ {
+ testType: serverTest,
+ name: "KeyUpdate-Server",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ },
+ sendKeyUpdates: 1,
+ keyUpdateRequest: keyUpdateNotRequested,
+ },
+ {
+ name: "KeyUpdate-InvalidRequestMode",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ },
+ sendKeyUpdates: 1,
+ keyUpdateRequest: 42,
+ shouldFail: true,
+ expectedError: ":DECODE_ERROR:",
+ },
+ {
+ name: "SendSNIWarningAlert",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ SendSNIWarningAlert: true,
+ },
+ },
+ },
+ {
+ testType: serverTest,
+ name: "ExtraCompressionMethods-TLS12",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ SendCompressionMethods: []byte{1, 2, 3, compressionNone, 4, 5, 6},
+ },
+ },
+ },
+ {
+ testType: serverTest,
+ name: "ExtraCompressionMethods-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendCompressionMethods: []byte{1, 2, 3, compressionNone, 4, 5, 6},
+ },
+ },
+ shouldFail: true,
+ expectedError: ":INVALID_COMPRESSION_LIST:",
+ expectedLocalError: "remote error: illegal parameter",
+ },
+ {
+ testType: serverTest,
+ name: "NoNullCompression-TLS12",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ SendCompressionMethods: []byte{1, 2, 3, 4, 5, 6},
+ },
+ },
+ shouldFail: true,
+ expectedError: ":INVALID_COMPRESSION_LIST:",
+ expectedLocalError: "remote error: illegal parameter",
+ },
+ {
+ testType: serverTest,
+ name: "NoNullCompression-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendCompressionMethods: []byte{1, 2, 3, 4, 5, 6},
+ },
+ },
+ shouldFail: true,
+ expectedError: ":INVALID_COMPRESSION_LIST:",
+ expectedLocalError: "remote error: illegal parameter",
+ },
+ {
+ name: "GREASE-Client-TLS12",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ ExpectGREASE: true,
+ },
+ },
+ flags: []string{"-enable-grease"},
+ },
+ {
+ name: "GREASE-Client-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ ExpectGREASE: true,
+ },
+ },
+ flags: []string{"-enable-grease"},
+ },
+ {
+ testType: serverTest,
+ name: "GREASE-Server-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ // TLS 1.3 servers are expected to
+ // always enable GREASE. TLS 1.3 is new,
+ // so there is no existing ecosystem to
+ // worry about.
+ ExpectGREASE: true,
+ },
+ },
+ },
+ {
+ // Test the server so there is a large certificate as
+ // well as application data.
+ testType: serverTest,
+ name: "MaxSendFragment",
+ config: Config{
+ Bugs: ProtocolBugs{
+ MaxReceivePlaintext: 512,
+ },
+ },
+ messageLen: 1024,
+ flags: []string{
+ "-max-send-fragment", "512",
+ "-read-size", "1024",
+ },
+ },
+ {
+ // Test the server so there is a large certificate as
+ // well as application data.
+ testType: serverTest,
+ name: "MaxSendFragment-TooLarge",
+ config: Config{
+ Bugs: ProtocolBugs{
+ // Ensure that some of the records are
+ // 512.
+ MaxReceivePlaintext: 511,
+ },
+ },
+ messageLen: 1024,
+ flags: []string{
+ "-max-send-fragment", "512",
+ "-read-size", "1024",
+ },
+ shouldFail: true,
+ expectedLocalError: "local error: record overflow",
+ },
+ }
+ testCases = append(testCases, basicTests...)
+
+ // Test that very large messages can be received.
+ cert := rsaCertificate
+ for i := 0; i < 50; i++ {
+ cert.Certificate = append(cert.Certificate, cert.Certificate[0])
+ }
+ testCases = append(testCases, testCase{
+ name: "LargeMessage",
+ config: Config{
+ Certificates: []Certificate{cert},
+ },
+ })
+ testCases = append(testCases, testCase{
+ protocol: dtls,
+ name: "LargeMessage-DTLS",
+ config: Config{
+ Certificates: []Certificate{cert},
+ },
+ })
+
+ // They are rejected if the maximum certificate chain length is capped.
+ testCases = append(testCases, testCase{
+ name: "LargeMessage-Reject",
+ config: Config{
+ Certificates: []Certificate{cert},
+ },
+ flags: []string{"-max-cert-list", "16384"},
+ shouldFail: true,
+ expectedError: ":EXCESSIVE_MESSAGE_SIZE:",
+ })
+ testCases = append(testCases, testCase{
+ protocol: dtls,
+ name: "LargeMessage-Reject-DTLS",
+ config: Config{
+ Certificates: []Certificate{cert},
+ },
+ flags: []string{"-max-cert-list", "16384"},
+ shouldFail: true,
+ expectedError: ":EXCESSIVE_MESSAGE_SIZE:",
+ })
+}
+
+func addTestForCipherSuite(suite testCipherSuite, ver tlsVersion, protocol protocol) {
+ const psk = "12345"
+ const pskIdentity = "luggage combo"
+
+ var prefix string
+ if protocol == dtls {
+ if !ver.hasDTLS {
+ return
+ }
+ prefix = "D"
+ }
+
+ var cert Certificate
+ var certFile string
+ var keyFile string
+ if hasComponent(suite.name, "ECDSA") {
+ cert = ecdsaP256Certificate
+ certFile = ecdsaP256CertificateFile
+ keyFile = ecdsaP256KeyFile
+ } else {
+ cert = rsaCertificate
+ certFile = rsaCertificateFile
+ keyFile = rsaKeyFile
+ }
+
+ var flags []string
+ if hasComponent(suite.name, "PSK") {
+ flags = append(flags,
+ "-psk", psk,
+ "-psk-identity", pskIdentity)
+ }
+ if hasComponent(suite.name, "NULL") {
+ // NULL ciphers must be explicitly enabled.
+ flags = append(flags, "-cipher", "DEFAULT:NULL-SHA")
+ }
+
+ var shouldServerFail, shouldClientFail bool
+ if hasComponent(suite.name, "ECDHE") && ver.version == VersionSSL30 {
+ // BoringSSL clients accept ECDHE on SSLv3, but
+ // a BoringSSL server will never select it
+ // because the extension is missing.
+ shouldServerFail = true
+ }
+ if isTLS12Only(suite.name) && ver.version < VersionTLS12 {
+ shouldClientFail = true
+ shouldServerFail = true
+ }
+ if !isTLS13Suite(suite.name) && ver.version >= VersionTLS13 {
+ shouldClientFail = true
+ shouldServerFail = true
+ }
+ if isTLS13Suite(suite.name) && ver.version < VersionTLS13 {
+ shouldClientFail = true
+ shouldServerFail = true
+ }
+ if !isDTLSCipher(suite.name) && protocol == dtls {
+ shouldClientFail = true
+ shouldServerFail = true
+ }
+
+ var sendCipherSuite uint16
+ var expectedServerError, expectedClientError string
+ serverCipherSuites := []uint16{suite.id}
+ if shouldServerFail {
+ expectedServerError = ":NO_SHARED_CIPHER:"
+ }
+ if shouldClientFail {
+ expectedClientError = ":WRONG_CIPHER_RETURNED:"
+ // Configure the server to select ciphers as normal but
+ // select an incompatible cipher in ServerHello.
+ serverCipherSuites = nil
+ sendCipherSuite = suite.id
+ }
+
+ // For cipher suites and versions where exporters are defined, verify
+ // that they interoperate.
+ var exportKeyingMaterial int
+ if ver.version > VersionSSL30 {
+ exportKeyingMaterial = 1024
+ }
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ protocol: protocol,
+ name: prefix + ver.name + "-" + suite.name + "-server",
+ config: Config{
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
+ CipherSuites: []uint16{suite.id},
+ Certificates: []Certificate{cert},
+ PreSharedKey: []byte(psk),
+ PreSharedKeyIdentity: pskIdentity,
+ Bugs: ProtocolBugs{
+ AdvertiseAllConfiguredCiphers: true,
+ },
+ },
+ certFile: certFile,
+ keyFile: keyFile,
+ flags: flags,
+ resumeSession: true,
+ shouldFail: shouldServerFail,
+ expectedError: expectedServerError,
+ exportKeyingMaterial: exportKeyingMaterial,
+ })
+
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ protocol: protocol,
+ name: prefix + ver.name + "-" + suite.name + "-client",
+ config: Config{
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
+ CipherSuites: serverCipherSuites,
+ Certificates: []Certificate{cert},
+ PreSharedKey: []byte(psk),
+ PreSharedKeyIdentity: pskIdentity,
+ Bugs: ProtocolBugs{
+ IgnorePeerCipherPreferences: shouldClientFail,
+ SendCipherSuite: sendCipherSuite,
+ },
+ },
+ flags: flags,
+ resumeSession: true,
+ shouldFail: shouldClientFail,
+ expectedError: expectedClientError,
+ exportKeyingMaterial: exportKeyingMaterial,
+ })
+
+ if shouldClientFail {
+ return
+ }
+
+ // Ensure the maximum record size is accepted.
+ testCases = append(testCases, testCase{
+ protocol: protocol,
+ name: prefix + ver.name + "-" + suite.name + "-LargeRecord",
+ config: Config{
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
+ CipherSuites: []uint16{suite.id},
+ Certificates: []Certificate{cert},
+ PreSharedKey: []byte(psk),
+ PreSharedKeyIdentity: pskIdentity,
+ },
+ flags: flags,
+ messageLen: maxPlaintext,
+ })
+
+ // Test bad records for all ciphers. Bad records are fatal in TLS
+ // and ignored in DTLS.
+ var shouldFail bool
+ var expectedError string
+ if protocol == tls {
+ shouldFail = true
+ expectedError = ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:"
+ }
+
+ testCases = append(testCases, testCase{
+ protocol: protocol,
+ name: prefix + ver.name + "-" + suite.name + "-BadRecord",
+ config: Config{
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
+ CipherSuites: []uint16{suite.id},
+ Certificates: []Certificate{cert},
+ PreSharedKey: []byte(psk),
+ PreSharedKeyIdentity: pskIdentity,
+ },
+ flags: flags,
+ damageFirstWrite: true,
+ messageLen: maxPlaintext,
+ shouldFail: shouldFail,
+ expectedError: expectedError,
+ })
+}
+
+func addCipherSuiteTests() {
+ const bogusCipher = 0xfe00
+
+ for _, suite := range testCipherSuites {
+ for _, ver := range tlsVersions {
+ for _, protocol := range []protocol{tls, dtls} {
+ addTestForCipherSuite(suite, ver, protocol)
+ }
+ }
+ }
+
+ testCases = append(testCases, testCase{
+ name: "NoSharedCipher",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{},
+ },
+ shouldFail: true,
+ expectedError: ":HANDSHAKE_FAILURE_ON_CLIENT_HELLO:",
+ })
+
+ testCases = append(testCases, testCase{
+ name: "NoSharedCipher-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ CipherSuites: []uint16{},
+ },
+ shouldFail: true,
+ expectedError: ":HANDSHAKE_FAILURE_ON_CLIENT_HELLO:",
+ })
+
+ testCases = append(testCases, testCase{
+ name: "UnsupportedCipherSuite",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA},
+ Bugs: ProtocolBugs{
+ IgnorePeerCipherPreferences: true,
+ },
+ },
+ flags: []string{"-cipher", "DEFAULT:!AES"},
+ shouldFail: true,
+ expectedError: ":WRONG_CIPHER_RETURNED:",
+ })
+
+ testCases = append(testCases, testCase{
+ name: "ServerHelloBogusCipher",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ SendCipherSuite: bogusCipher,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNKNOWN_CIPHER_RETURNED:",
+ })
+ testCases = append(testCases, testCase{
+ name: "ServerHelloBogusCipher-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendCipherSuite: bogusCipher,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNKNOWN_CIPHER_RETURNED:",
+ })
+
+ testCases = append(testCases, testCase{
+ name: "WeakDH",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_DHE_RSA_WITH_AES_128_GCM_SHA256},
+ Bugs: ProtocolBugs{
+ // This is a 1023-bit prime number, generated
+ // with:
+ // openssl gendh 1023 | openssl asn1parse -i
+ DHGroupPrime: bigFromHex("518E9B7930CE61C6E445C8360584E5FC78D9137C0FFDC880B495D5338ADF7689951A6821C17A76B3ACB8E0156AEA607B7EC406EBEDBB84D8376EB8FE8F8BA1433488BEE0C3EDDFD3A32DBB9481980A7AF6C96BFCF490A094CFFB2B8192C1BB5510B77B658436E27C2D4D023FE3718222AB0CA1273995B51F6D625A4944D0DD4B"),
+ },
+ },
+ shouldFail: true,
+ expectedError: ":BAD_DH_P_LENGTH:",
+ })
+
+ testCases = append(testCases, testCase{
+ name: "SillyDH",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_DHE_RSA_WITH_AES_128_GCM_SHA256},
+ Bugs: ProtocolBugs{
+ // This is a 4097-bit prime number, generated
+ // with:
+ // openssl gendh 4097 | openssl asn1parse -i
+ DHGroupPrime: bigFromHex("01D366FA64A47419B0CD4A45918E8D8C8430F674621956A9F52B0CA592BC104C6E38D60C58F2CA66792A2B7EBDC6F8FFE75AB7D6862C261F34E96A2AEEF53AB7C21365C2E8FB0582F71EB57B1C227C0E55AE859E9904A25EFECD7B435C4D4357BD840B03649D4A1F8037D89EA4E1967DBEEF1CC17A6111C48F12E9615FFF336D3F07064CB17C0B765A012C850B9E3AA7A6984B96D8C867DDC6D0F4AB52042572244796B7ECFF681CD3B3E2E29AAECA391A775BEE94E502FB15881B0F4AC60314EA947C0C82541C3D16FD8C0E09BB7F8F786582032859D9C13187CE6C0CB6F2D3EE6C3C9727C15F14B21D3CD2E02BDB9D119959B0E03DC9E5A91E2578762300B1517D2352FC1D0BB934A4C3E1B20CE9327DB102E89A6C64A8C3148EDFC5A94913933853442FA84451B31FD21E492F92DD5488E0D871AEBFE335A4B92431DEC69591548010E76A5B365D346786E9A2D3E589867D796AA5E25211201D757560D318A87DFB27F3E625BC373DB48BF94A63161C674C3D4265CB737418441B7650EABC209CF675A439BEB3E9D1AA1B79F67198A40CEFD1C89144F7D8BAF61D6AD36F466DA546B4174A0E0CAF5BD788C8243C7C2DDDCC3DB6FC89F12F17D19FBD9B0BC76FE92891CD6BA07BEA3B66EF12D0D85E788FD58675C1B0FBD16029DCC4D34E7A1A41471BDEDF78BF591A8B4E96D88BEC8EDC093E616292BFC096E69A916E8D624B"),
+ },
+ },
+ shouldFail: true,
+ expectedError: ":DH_P_TOO_LONG:",
+ })
+
+ // This test ensures that Diffie-Hellman public values are padded with
+ // zeros so that they're the same length as the prime. This is to avoid
+ // hitting a bug in yaSSL.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "DHPublicValuePadded",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_DHE_RSA_WITH_AES_128_GCM_SHA256},
+ Bugs: ProtocolBugs{
+ RequireDHPublicValueLen: (1025 + 7) / 8,
+ },
+ },
+ flags: []string{"-use-sparse-dh-prime"},
+ })
+
+ // The server must be tolerant to bogus ciphers.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "UnknownCipher",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{bogusCipher, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ Bugs: ProtocolBugs{
+ AdvertiseAllConfiguredCiphers: true,
+ },
+ },
+ })
+
+ // The server must be tolerant to bogus ciphers.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "UnknownCipher-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ CipherSuites: []uint16{bogusCipher, TLS_AES_128_GCM_SHA256},
+ Bugs: ProtocolBugs{
+ AdvertiseAllConfiguredCiphers: true,
+ },
+ },
+ })
+
+ // Test empty ECDHE_PSK identity hints work as expected.
+ testCases = append(testCases, testCase{
+ name: "EmptyECDHEPSKHint",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA},
+ PreSharedKey: []byte("secret"),
+ },
+ flags: []string{"-psk", "secret"},
+ })
+
+ // Test empty PSK identity hints work as expected, even if an explicit
+ // ServerKeyExchange is sent.
+ testCases = append(testCases, testCase{
+ name: "ExplicitEmptyPSKHint",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_PSK_WITH_AES_128_CBC_SHA},
+ PreSharedKey: []byte("secret"),
+ Bugs: ProtocolBugs{
+ AlwaysSendPreSharedKeyIdentityHint: true,
+ },
+ },
+ flags: []string{"-psk", "secret"},
+ })
+}
+
+func addBadECDSASignatureTests() {
+ for badR := BadValue(1); badR < NumBadValues; badR++ {
+ for badS := BadValue(1); badS < NumBadValues; badS++ {
+ testCases = append(testCases, testCase{
+ name: fmt.Sprintf("BadECDSA-%d-%d", badR, badS),
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
+ Certificates: []Certificate{ecdsaP256Certificate},
+ Bugs: ProtocolBugs{
+ BadECDSAR: badR,
+ BadECDSAS: badS,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":BAD_SIGNATURE:",
+ })
+ testCases = append(testCases, testCase{
+ name: fmt.Sprintf("BadECDSA-%d-%d-TLS13", badR, badS),
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Certificates: []Certificate{ecdsaP256Certificate},
+ Bugs: ProtocolBugs{
+ BadECDSAR: badR,
+ BadECDSAS: badS,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":BAD_SIGNATURE:",
+ })
+ }
+ }
+}
+
+func addCBCPaddingTests() {
+ testCases = append(testCases, testCase{
+ name: "MaxCBCPadding",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
+ Bugs: ProtocolBugs{
+ MaxPadding: true,
+ },
+ },
+ messageLen: 12, // 20 bytes of SHA-1 + 12 == 0 % block size
+ })
+ testCases = append(testCases, testCase{
+ name: "BadCBCPadding",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
+ Bugs: ProtocolBugs{
+ PaddingFirstByteBad: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:",
+ })
+ // OpenSSL previously had an issue where the first byte of padding in
+ // 255 bytes of padding wasn't checked.
+ testCases = append(testCases, testCase{
+ name: "BadCBCPadding255",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
+ Bugs: ProtocolBugs{
+ MaxPadding: true,
+ PaddingFirstByteBadIf255: true,
+ },
+ },
+ messageLen: 12, // 20 bytes of SHA-1 + 12 == 0 % block size
+ shouldFail: true,
+ expectedError: ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:",
+ })
+}
+
+func addCBCSplittingTests() {
+ testCases = append(testCases, testCase{
+ name: "CBCRecordSplitting",
+ config: Config{
+ MaxVersion: VersionTLS10,
+ MinVersion: VersionTLS10,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
+ },
+ messageLen: -1, // read until EOF
+ resumeSession: true,
+ flags: []string{
+ "-async",
+ "-write-different-record-sizes",
+ "-cbc-record-splitting",
+ },
+ })
+ testCases = append(testCases, testCase{
+ name: "CBCRecordSplittingPartialWrite",
+ config: Config{
+ MaxVersion: VersionTLS10,
+ MinVersion: VersionTLS10,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
+ },
+ messageLen: -1, // read until EOF
+ flags: []string{
+ "-async",
+ "-write-different-record-sizes",
+ "-cbc-record-splitting",
+ "-partial-write",
+ },
+ })
+}
+
+func addClientAuthTests() {
+ // Add a dummy cert pool to stress certificate authority parsing.
+ certPool := x509.NewCertPool()
+ for _, cert := range []Certificate{rsaCertificate, rsa1024Certificate} {
+ cert, err := x509.ParseCertificate(cert.Certificate[0])
+ if err != nil {
+ panic(err)
+ }
+ certPool.AddCert(cert)
+ }
+ caNames := certPool.Subjects()
+
+ for _, ver := range tlsVersions {
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: ver.name + "-Client-ClientAuth-RSA",
+ config: Config{
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
+ ClientAuth: RequireAnyClientCert,
+ ClientCAs: certPool,
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaKeyFile),
+ },
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: ver.name + "-Server-ClientAuth-RSA",
+ config: Config{
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
+ Certificates: []Certificate{rsaCertificate},
+ },
+ flags: []string{"-require-any-client-certificate"},
+ })
+ if ver.version != VersionSSL30 {
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: ver.name + "-Server-ClientAuth-ECDSA",
+ config: Config{
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
+ Certificates: []Certificate{ecdsaP256Certificate},
+ },
+ flags: []string{"-require-any-client-certificate"},
+ })
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: ver.name + "-Client-ClientAuth-ECDSA",
+ config: Config{
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
+ ClientAuth: RequireAnyClientCert,
+ ClientCAs: certPool,
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, ecdsaP256CertificateFile),
+ "-key-file", path.Join(*resourceDir, ecdsaP256KeyFile),
+ },
+ })
+ }
+
+ testCases = append(testCases, testCase{
+ name: "NoClientCertificate-" + ver.name,
+ config: Config{
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
+ ClientAuth: RequireAnyClientCert,
+ },
+ shouldFail: true,
+ expectedLocalError: "client didn't provide a certificate",
+ })
+
+ testCases = append(testCases, testCase{
+ // Even if not configured to expect a certificate, OpenSSL will
+ // return X509_V_OK as the verify_result.
+ testType: serverTest,
+ name: "NoClientCertificateRequested-Server-" + ver.name,
+ config: Config{
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
+ },
+ flags: []string{
+ "-expect-verify-result",
+ },
+ resumeSession: true,
+ })
+
+ testCases = append(testCases, testCase{
+ // If a client certificate is not provided, OpenSSL will still
+ // return X509_V_OK as the verify_result.
+ testType: serverTest,
+ name: "NoClientCertificate-Server-" + ver.name,
+ config: Config{
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
+ },
+ flags: []string{
+ "-expect-verify-result",
+ "-verify-peer",
+ },
+ resumeSession: true,
+ })
+
+ certificateRequired := "remote error: certificate required"
+ if ver.version < VersionTLS13 {
+ // Prior to TLS 1.3, the generic handshake_failure alert
+ // was used.
+ certificateRequired = "remote error: handshake failure"
+ }
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "RequireAnyClientCertificate-" + ver.name,
+ config: Config{
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
+ },
+ flags: []string{"-require-any-client-certificate"},
+ shouldFail: true,
+ expectedError: ":PEER_DID_NOT_RETURN_A_CERTIFICATE:",
+ expectedLocalError: certificateRequired,
+ })
+
+ if ver.version != VersionSSL30 {
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "SkipClientCertificate-" + ver.name,
+ config: Config{
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
+ Bugs: ProtocolBugs{
+ SkipClientCertificate: true,
+ },
+ },
+ // Setting SSL_VERIFY_PEER allows anonymous clients.
+ flags: []string{"-verify-peer"},
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_MESSAGE:",
+ })
+ }
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: ver.name + "-Server-CertReq-CA-List",
+ config: Config{
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
+ Certificates: []Certificate{rsaCertificate},
+ Bugs: ProtocolBugs{
+ ExpectCertificateReqNames: caNames,
+ },
+ },
+ flags: []string{
+ "-require-any-client-certificate",
+ "-use-client-ca-list", encodeDERValues(caNames),
+ },
+ })
+
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: ver.name + "-Client-CertReq-CA-List",
+ config: Config{
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
+ Certificates: []Certificate{rsaCertificate},
+ ClientAuth: RequireAnyClientCert,
+ ClientCAs: certPool,
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaKeyFile),
+ "-expect-client-ca-list", encodeDERValues(caNames),
+ },
+ })
+ }
+
+ // Client auth is only legal in certificate-based ciphers.
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "ClientAuth-PSK",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_PSK_WITH_AES_128_CBC_SHA},
+ PreSharedKey: []byte("secret"),
+ ClientAuth: RequireAnyClientCert,
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaKeyFile),
+ "-psk", "secret",
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_MESSAGE:",
+ })
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "ClientAuth-ECDHE_PSK",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA},
+ PreSharedKey: []byte("secret"),
+ ClientAuth: RequireAnyClientCert,
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaKeyFile),
+ "-psk", "secret",
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_MESSAGE:",
+ })
+
+ // Regression test for a bug where the client CA list, if explicitly
+ // set to NULL, was mis-encoded.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "Null-Client-CA-List",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Certificates: []Certificate{rsaCertificate},
+ Bugs: ProtocolBugs{
+ ExpectCertificateReqNames: [][]byte{},
+ },
+ },
+ flags: []string{
+ "-require-any-client-certificate",
+ "-use-client-ca-list", "<NULL>",
+ },
+ })
+}
+
+func addExtendedMasterSecretTests() {
+ const expectEMSFlag = "-expect-extended-master-secret"
+
+ for _, with := range []bool{false, true} {
+ prefix := "No"
+ if with {
+ prefix = ""
+ }
+
+ for _, isClient := range []bool{false, true} {
+ suffix := "-Server"
+ testType := serverTest
+ if isClient {
+ suffix = "-Client"
+ testType = clientTest
+ }
+
+ for _, ver := range tlsVersions {
+ // In TLS 1.3, the extension is irrelevant and
+ // always reports as enabled.
+ var flags []string
+ if with || ver.version >= VersionTLS13 {
+ flags = []string{expectEMSFlag}
+ }
+
+ test := testCase{
+ testType: testType,
+ name: prefix + "ExtendedMasterSecret-" + ver.name + suffix,
+ config: Config{
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
+ Bugs: ProtocolBugs{
+ NoExtendedMasterSecret: !with,
+ RequireExtendedMasterSecret: with,
+ },
+ },
+ flags: flags,
+ shouldFail: ver.version == VersionSSL30 && with,
+ }
+ if test.shouldFail {
+ test.expectedLocalError = "extended master secret required but not supported by peer"
+ }
+ testCases = append(testCases, test)
+ }
+ }
+ }
+
+ for _, isClient := range []bool{false, true} {
+ for _, supportedInFirstConnection := range []bool{false, true} {
+ for _, supportedInResumeConnection := range []bool{false, true} {
+ boolToWord := func(b bool) string {
+ if b {
+ return "Yes"
+ }
+ return "No"
+ }
+ suffix := boolToWord(supportedInFirstConnection) + "To" + boolToWord(supportedInResumeConnection) + "-"
+ if isClient {
+ suffix += "Client"
+ } else {
+ suffix += "Server"
+ }
+
+ supportedConfig := Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ RequireExtendedMasterSecret: true,
+ },
+ }
+
+ noSupportConfig := Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ NoExtendedMasterSecret: true,
+ },
+ }
+
+ test := testCase{
+ name: "ExtendedMasterSecret-" + suffix,
+ resumeSession: true,
+ }
+
+ if !isClient {
+ test.testType = serverTest
+ }
+
+ if supportedInFirstConnection {
+ test.config = supportedConfig
+ } else {
+ test.config = noSupportConfig
+ }
+
+ if supportedInResumeConnection {
+ test.resumeConfig = &supportedConfig
+ } else {
+ test.resumeConfig = &noSupportConfig
+ }
+
+ switch suffix {
+ case "YesToYes-Client", "YesToYes-Server":
+ // When a session is resumed, it should
+ // still be aware that its master
+ // secret was generated via EMS and
+ // thus it's safe to use tls-unique.
+ test.flags = []string{expectEMSFlag}
+ case "NoToYes-Server":
+ // If an original connection did not
+ // contain EMS, but a resumption
+ // handshake does, then a server should
+ // not resume the session.
+ test.expectResumeRejected = true
+ case "YesToNo-Server":
+ // Resuming an EMS session without the
+ // EMS extension should cause the
+ // server to abort the connection.
+ test.shouldFail = true
+ test.expectedError = ":RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION:"
+ case "NoToYes-Client":
+ // A client should abort a connection
+ // where the server resumed a non-EMS
+ // session but echoed the EMS
+ // extension.
+ test.shouldFail = true
+ test.expectedError = ":RESUMED_NON_EMS_SESSION_WITH_EMS_EXTENSION:"
+ case "YesToNo-Client":
+ // A client should abort a connection
+ // where the server didn't echo EMS
+ // when the session used it.
+ test.shouldFail = true
+ test.expectedError = ":RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION:"
+ }
+
+ testCases = append(testCases, test)
+ }
+ }
+ }
+
+ // Switching EMS on renegotiation is forbidden.
+ testCases = append(testCases, testCase{
+ name: "ExtendedMasterSecret-Renego-NoEMS",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ NoExtendedMasterSecret: true,
+ NoExtendedMasterSecretOnRenegotiation: true,
+ },
+ },
+ renegotiate: 1,
+ flags: []string{
+ "-renegotiate-freely",
+ "-expect-total-renegotiations", "1",
+ },
+ })
+
+ testCases = append(testCases, testCase{
+ name: "ExtendedMasterSecret-Renego-Upgrade",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ NoExtendedMasterSecret: true,
+ },
+ },
+ renegotiate: 1,
+ flags: []string{
+ "-renegotiate-freely",
+ "-expect-total-renegotiations", "1",
+ },
+ shouldFail: true,
+ expectedError: ":RENEGOTIATION_EMS_MISMATCH:",
+ })
+
+ testCases = append(testCases, testCase{
+ name: "ExtendedMasterSecret-Renego-Downgrade",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ NoExtendedMasterSecretOnRenegotiation: true,
+ },
+ },
+ renegotiate: 1,
+ flags: []string{
+ "-renegotiate-freely",
+ "-expect-total-renegotiations", "1",
+ },
+ shouldFail: true,
+ expectedError: ":RENEGOTIATION_EMS_MISMATCH:",
+ })
+}
+
+type stateMachineTestConfig struct {
+ protocol protocol
+ async bool
+ splitHandshake, packHandshakeFlight bool
+}
+
+// Adds tests that try to cover the range of the handshake state machine, under
+// various conditions. Some of these are redundant with other tests, but they
+// only cover the synchronous case.
+func addAllStateMachineCoverageTests() {
+ for _, async := range []bool{false, true} {
+ for _, protocol := range []protocol{tls, dtls} {
+ addStateMachineCoverageTests(stateMachineTestConfig{
+ protocol: protocol,
+ async: async,
+ })
+ addStateMachineCoverageTests(stateMachineTestConfig{
+ protocol: protocol,
+ async: async,
+ splitHandshake: true,
+ })
+ if protocol == tls {
+ addStateMachineCoverageTests(stateMachineTestConfig{
+ protocol: protocol,
+ async: async,
+ packHandshakeFlight: true,
+ })
+ }
+ }
+ }
+}
+
+func addStateMachineCoverageTests(config stateMachineTestConfig) {
+ var tests []testCase
+
+ // Basic handshake, with resumption. Client and server,
+ // session ID and session ticket.
+ tests = append(tests, testCase{
+ name: "Basic-Client",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ },
+ resumeSession: true,
+ // Ensure session tickets are used, not session IDs.
+ noSessionCache: true,
+ })
+ tests = append(tests, testCase{
+ name: "Basic-Client-RenewTicket",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ RenewTicketOnResume: true,
+ },
+ },
+ flags: []string{"-expect-ticket-renewal"},
+ resumeSession: true,
+ resumeRenewedSession: true,
+ })
+ tests = append(tests, testCase{
+ name: "Basic-Client-NoTicket",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ SessionTicketsDisabled: true,
+ },
+ resumeSession: true,
+ })
+ tests = append(tests, testCase{
+ name: "Basic-Client-Implicit",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ },
+ flags: []string{"-implicit-handshake"},
+ resumeSession: true,
+ })
+ tests = append(tests, testCase{
+ testType: serverTest,
+ name: "Basic-Server",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ RequireSessionTickets: true,
+ },
+ },
+ resumeSession: true,
+ flags: []string{"-expect-no-session-id"},
+ })
+ tests = append(tests, testCase{
+ testType: serverTest,
+ name: "Basic-Server-NoTickets",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ SessionTicketsDisabled: true,
+ },
+ resumeSession: true,
+ flags: []string{"-expect-session-id"},
+ })
+ tests = append(tests, testCase{
+ testType: serverTest,
+ name: "Basic-Server-Implicit",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ },
+ flags: []string{"-implicit-handshake"},
+ resumeSession: true,
+ })
+ tests = append(tests, testCase{
+ testType: serverTest,
+ name: "Basic-Server-EarlyCallback",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ },
+ flags: []string{"-use-early-callback"},
+ resumeSession: true,
+ })
+
+ // TLS 1.3 basic handshake shapes.
+ if config.protocol == tls {
+ tests = append(tests, testCase{
+ name: "TLS13-1RTT-Client",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ MinVersion: VersionTLS13,
+ },
+ resumeSession: true,
+ resumeRenewedSession: true,
+ })
+
+ tests = append(tests, testCase{
+ testType: serverTest,
+ name: "TLS13-1RTT-Server",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ MinVersion: VersionTLS13,
+ },
+ resumeSession: true,
+ resumeRenewedSession: true,
+ // TLS 1.3 uses tickets, so the session should not be
+ // cached statefully.
+ flags: []string{"-expect-no-session-id"},
+ })
+
+ tests = append(tests, testCase{
+ name: "TLS13-HelloRetryRequest-Client",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ MinVersion: VersionTLS13,
+ // P-384 requires a HelloRetryRequest against BoringSSL's default
+ // configuration. Assert this with ExpectMissingKeyShare.
+ CurvePreferences: []CurveID{CurveP384},
+ Bugs: ProtocolBugs{
+ ExpectMissingKeyShare: true,
+ },
+ },
+ // Cover HelloRetryRequest during an ECDHE-PSK resumption.
+ resumeSession: true,
+ })
+
+ tests = append(tests, testCase{
+ testType: serverTest,
+ name: "TLS13-HelloRetryRequest-Server",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ MinVersion: VersionTLS13,
+ // Require a HelloRetryRequest for every curve.
+ DefaultCurves: []CurveID{},
+ },
+ // Cover HelloRetryRequest during an ECDHE-PSK resumption.
+ resumeSession: true,
+ })
+ }
+
+ // TLS client auth.
+ tests = append(tests, testCase{
+ testType: clientTest,
+ name: "ClientAuth-NoCertificate-Client",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ ClientAuth: RequestClientCert,
+ },
+ })
+ tests = append(tests, testCase{
+ testType: serverTest,
+ name: "ClientAuth-NoCertificate-Server",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ },
+ // Setting SSL_VERIFY_PEER allows anonymous clients.
+ flags: []string{"-verify-peer"},
+ })
+ if config.protocol == tls {
+ tests = append(tests, testCase{
+ testType: clientTest,
+ name: "ClientAuth-NoCertificate-Client-SSL3",
+ config: Config{
+ MaxVersion: VersionSSL30,
+ ClientAuth: RequestClientCert,
+ },
+ })
+ tests = append(tests, testCase{
+ testType: serverTest,
+ name: "ClientAuth-NoCertificate-Server-SSL3",
+ config: Config{
+ MaxVersion: VersionSSL30,
+ },
+ // Setting SSL_VERIFY_PEER allows anonymous clients.
+ flags: []string{"-verify-peer"},
+ })
+ tests = append(tests, testCase{
+ testType: clientTest,
+ name: "ClientAuth-NoCertificate-Client-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ ClientAuth: RequestClientCert,
+ },
+ })
+ tests = append(tests, testCase{
+ testType: serverTest,
+ name: "ClientAuth-NoCertificate-Server-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ },
+ // Setting SSL_VERIFY_PEER allows anonymous clients.
+ flags: []string{"-verify-peer"},
+ })
+ }
+ tests = append(tests, testCase{
+ testType: clientTest,
+ name: "ClientAuth-RSA-Client",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ ClientAuth: RequireAnyClientCert,
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaKeyFile),
+ },
+ })
+ tests = append(tests, testCase{
+ testType: clientTest,
+ name: "ClientAuth-RSA-Client-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ ClientAuth: RequireAnyClientCert,
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaKeyFile),
+ },
+ })
+ tests = append(tests, testCase{
+ testType: clientTest,
+ name: "ClientAuth-ECDSA-Client",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ ClientAuth: RequireAnyClientCert,
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, ecdsaP256CertificateFile),
+ "-key-file", path.Join(*resourceDir, ecdsaP256KeyFile),
+ },
+ })
+ tests = append(tests, testCase{
+ testType: clientTest,
+ name: "ClientAuth-ECDSA-Client-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ ClientAuth: RequireAnyClientCert,
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, ecdsaP256CertificateFile),
+ "-key-file", path.Join(*resourceDir, ecdsaP256KeyFile),
+ },
+ })
+ tests = append(tests, testCase{
+ testType: clientTest,
+ name: "ClientAuth-NoCertificate-OldCallback",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ ClientAuth: RequestClientCert,
+ },
+ flags: []string{"-use-old-client-cert-callback"},
+ })
+ tests = append(tests, testCase{
+ testType: clientTest,
+ name: "ClientAuth-NoCertificate-OldCallback-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ ClientAuth: RequestClientCert,
+ },
+ flags: []string{"-use-old-client-cert-callback"},
+ })
+ tests = append(tests, testCase{
+ testType: clientTest,
+ name: "ClientAuth-OldCallback",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ ClientAuth: RequireAnyClientCert,
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaKeyFile),
+ "-use-old-client-cert-callback",
+ },
+ })
+ tests = append(tests, testCase{
+ testType: clientTest,
+ name: "ClientAuth-OldCallback-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ ClientAuth: RequireAnyClientCert,
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaKeyFile),
+ "-use-old-client-cert-callback",
+ },
+ })
+ tests = append(tests, testCase{
+ testType: serverTest,
+ name: "ClientAuth-Server",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Certificates: []Certificate{rsaCertificate},
+ },
+ flags: []string{"-require-any-client-certificate"},
+ })
+ tests = append(tests, testCase{
+ testType: serverTest,
+ name: "ClientAuth-Server-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Certificates: []Certificate{rsaCertificate},
+ },
+ flags: []string{"-require-any-client-certificate"},
+ })
+
+ // Test each key exchange on the server side for async keys.
+ tests = append(tests, testCase{
+ testType: serverTest,
+ name: "Basic-Server-RSA",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaKeyFile),
+ },
+ })
+ tests = append(tests, testCase{
+ testType: serverTest,
+ name: "Basic-Server-ECDHE-RSA",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaKeyFile),
+ },
+ })
+ tests = append(tests, testCase{
+ testType: serverTest,
+ name: "Basic-Server-ECDHE-ECDSA",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, ecdsaP256CertificateFile),
+ "-key-file", path.Join(*resourceDir, ecdsaP256KeyFile),
+ },
+ })
+
+ // No session ticket support; server doesn't send NewSessionTicket.
+ tests = append(tests, testCase{
+ name: "SessionTicketsDisabled-Client",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ SessionTicketsDisabled: true,
+ },
+ })
+ tests = append(tests, testCase{
+ testType: serverTest,
+ name: "SessionTicketsDisabled-Server",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ SessionTicketsDisabled: true,
+ },
+ })
+
+ // Skip ServerKeyExchange in PSK key exchange if there's no
+ // identity hint.
+ tests = append(tests, testCase{
+ name: "EmptyPSKHint-Client",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_PSK_WITH_AES_128_CBC_SHA},
+ PreSharedKey: []byte("secret"),
+ },
+ flags: []string{"-psk", "secret"},
+ })
+ tests = append(tests, testCase{
+ testType: serverTest,
+ name: "EmptyPSKHint-Server",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_PSK_WITH_AES_128_CBC_SHA},
+ PreSharedKey: []byte("secret"),
+ },
+ flags: []string{"-psk", "secret"},
+ })
+
+ // OCSP stapling tests.
+ tests = append(tests, testCase{
+ testType: clientTest,
+ name: "OCSPStapling-Client",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ },
+ flags: []string{
+ "-enable-ocsp-stapling",
+ "-expect-ocsp-response",
+ base64.StdEncoding.EncodeToString(testOCSPResponse),
+ "-verify-peer",
+ },
+ resumeSession: true,
+ })
+ tests = append(tests, testCase{
+ testType: serverTest,
+ name: "OCSPStapling-Server",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ },
+ expectedOCSPResponse: testOCSPResponse,
+ flags: []string{
+ "-ocsp-response",
+ base64.StdEncoding.EncodeToString(testOCSPResponse),
+ },
+ resumeSession: true,
+ })
+ tests = append(tests, testCase{
+ testType: clientTest,
+ name: "OCSPStapling-Client-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ },
+ flags: []string{
+ "-enable-ocsp-stapling",
+ "-expect-ocsp-response",
+ base64.StdEncoding.EncodeToString(testOCSPResponse),
+ "-verify-peer",
+ },
+ resumeSession: true,
+ })
+ tests = append(tests, testCase{
+ testType: serverTest,
+ name: "OCSPStapling-Server-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ },
+ expectedOCSPResponse: testOCSPResponse,
+ flags: []string{
+ "-ocsp-response",
+ base64.StdEncoding.EncodeToString(testOCSPResponse),
+ },
+ resumeSession: true,
+ })
+
+ // Certificate verification tests.
+ for _, vers := range tlsVersions {
+ if config.protocol == dtls && !vers.hasDTLS {
+ continue
+ }
+ for _, testType := range []testType{clientTest, serverTest} {
+ suffix := "-Client"
+ if testType == serverTest {
+ suffix = "-Server"
+ }
+ suffix += "-" + vers.name
+
+ flag := "-verify-peer"
+ if testType == serverTest {
+ flag = "-require-any-client-certificate"
+ }
+
+ tests = append(tests, testCase{
+ testType: testType,
+ name: "CertificateVerificationSucceed" + suffix,
+ config: Config{
+ MaxVersion: vers.version,
+ Certificates: []Certificate{rsaCertificate},
+ },
+ flags: []string{
+ flag,
+ "-expect-verify-result",
+ },
+ resumeSession: true,
+ })
+ tests = append(tests, testCase{
+ testType: testType,
+ name: "CertificateVerificationFail" + suffix,
+ config: Config{
+ MaxVersion: vers.version,
+ Certificates: []Certificate{rsaCertificate},
+ },
+ flags: []string{
+ flag,
+ "-verify-fail",
+ },
+ shouldFail: true,
+ expectedError: ":CERTIFICATE_VERIFY_FAILED:",
+ })
+ }
+
+ // By default, the client is in a soft fail mode where the peer
+ // certificate is verified but failures are non-fatal.
+ tests = append(tests, testCase{
+ testType: clientTest,
+ name: "CertificateVerificationSoftFail-" + vers.name,
+ config: Config{
+ MaxVersion: vers.version,
+ Certificates: []Certificate{rsaCertificate},
+ },
+ flags: []string{
+ "-verify-fail",
+ "-expect-verify-result",
+ },
+ resumeSession: true,
+ })
+ }
+
+ tests = append(tests, testCase{
+ name: "ShimSendAlert",
+ flags: []string{"-send-alert"},
+ shimWritesFirst: true,
+ shouldFail: true,
+ expectedLocalError: "remote error: decompression failure",
+ })
+
+ if config.protocol == tls {
+ tests = append(tests, testCase{
+ name: "Renegotiate-Client",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ },
+ renegotiate: 1,
+ flags: []string{
+ "-renegotiate-freely",
+ "-expect-total-renegotiations", "1",
+ },
+ })
+
+ tests = append(tests, testCase{
+ name: "SendHalfHelloRequest",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ PackHelloRequestWithFinished: config.packHandshakeFlight,
+ },
+ },
+ sendHalfHelloRequest: true,
+ flags: []string{"-renegotiate-ignore"},
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_RECORD:",
+ })
+
+ // NPN on client and server; results in post-handshake message.
+ tests = append(tests, testCase{
+ name: "NPN-Client",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ NextProtos: []string{"foo"},
+ },
+ flags: []string{"-select-next-proto", "foo"},
+ resumeSession: true,
+ expectedNextProto: "foo",
+ expectedNextProtoType: npn,
+ })
+ tests = append(tests, testCase{
+ testType: serverTest,
+ name: "NPN-Server",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ NextProtos: []string{"bar"},
+ },
+ flags: []string{
+ "-advertise-npn", "\x03foo\x03bar\x03baz",
+ "-expect-next-proto", "bar",
+ },
+ resumeSession: true,
+ expectedNextProto: "bar",
+ expectedNextProtoType: npn,
+ })
+
+ // TODO(davidben): Add tests for when False Start doesn't trigger.
+
+ // Client does False Start and negotiates NPN.
+ tests = append(tests, testCase{
+ name: "FalseStart",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ NextProtos: []string{"foo"},
+ Bugs: ProtocolBugs{
+ ExpectFalseStart: true,
+ },
+ },
+ flags: []string{
+ "-false-start",
+ "-select-next-proto", "foo",
+ },
+ shimWritesFirst: true,
+ resumeSession: true,
+ })
+
+ // Client does False Start and negotiates ALPN.
+ tests = append(tests, testCase{
+ name: "FalseStart-ALPN",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ NextProtos: []string{"foo"},
+ Bugs: ProtocolBugs{
+ ExpectFalseStart: true,
+ },
+ },
+ flags: []string{
+ "-false-start",
+ "-advertise-alpn", "\x03foo",
+ },
+ shimWritesFirst: true,
+ resumeSession: true,
+ })
+
+ // Client does False Start but doesn't explicitly call
+ // SSL_connect.
+ tests = append(tests, testCase{
+ name: "FalseStart-Implicit",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ NextProtos: []string{"foo"},
+ },
+ flags: []string{
+ "-implicit-handshake",
+ "-false-start",
+ "-advertise-alpn", "\x03foo",
+ },
+ })
+
+ // False Start without session tickets.
+ tests = append(tests, testCase{
+ name: "FalseStart-SessionTicketsDisabled",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ NextProtos: []string{"foo"},
+ SessionTicketsDisabled: true,
+ Bugs: ProtocolBugs{
+ ExpectFalseStart: true,
+ },
+ },
+ flags: []string{
+ "-false-start",
+ "-select-next-proto", "foo",
+ },
+ shimWritesFirst: true,
+ })
+
+ // Server parses a V2ClientHello.
+ tests = append(tests, testCase{
+ testType: serverTest,
+ name: "SendV2ClientHello",
+ config: Config{
+ // Choose a cipher suite that does not involve
+ // elliptic curves, so no extensions are
+ // involved.
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_RSA_WITH_3DES_EDE_CBC_SHA},
+ Bugs: ProtocolBugs{
+ SendV2ClientHello: true,
+ },
+ },
+ })
+
+ // Test Channel ID
+ for _, ver := range tlsVersions {
+ if ver.version < VersionTLS10 {
+ continue
+ }
+ // Client sends a Channel ID.
+ tests = append(tests, testCase{
+ name: "ChannelID-Client-" + ver.name,
+ config: Config{
+ MaxVersion: ver.version,
+ RequestChannelID: true,
+ },
+ flags: []string{"-send-channel-id", path.Join(*resourceDir, channelIDKeyFile)},
+ resumeSession: true,
+ expectChannelID: true,
+ })
+
+ // Server accepts a Channel ID.
+ tests = append(tests, testCase{
+ testType: serverTest,
+ name: "ChannelID-Server-" + ver.name,
+ config: Config{
+ MaxVersion: ver.version,
+ ChannelID: channelIDKey,
+ },
+ flags: []string{
+ "-expect-channel-id",
+ base64.StdEncoding.EncodeToString(channelIDBytes),
+ },
+ resumeSession: true,
+ expectChannelID: true,
+ })
+
+ tests = append(tests, testCase{
+ testType: serverTest,
+ name: "InvalidChannelIDSignature-" + ver.name,
+ config: Config{
+ MaxVersion: ver.version,
+ ChannelID: channelIDKey,
+ Bugs: ProtocolBugs{
+ InvalidChannelIDSignature: true,
+ },
+ },
+ flags: []string{"-enable-channel-id"},
+ shouldFail: true,
+ expectedError: ":CHANNEL_ID_SIGNATURE_INVALID:",
+ })
+ }
+
+ // Channel ID and NPN at the same time, to ensure their relative
+ // ordering is correct.
+ tests = append(tests, testCase{
+ name: "ChannelID-NPN-Client",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ RequestChannelID: true,
+ NextProtos: []string{"foo"},
+ },
+ flags: []string{
+ "-send-channel-id", path.Join(*resourceDir, channelIDKeyFile),
+ "-select-next-proto", "foo",
+ },
+ resumeSession: true,
+ expectChannelID: true,
+ expectedNextProto: "foo",
+ expectedNextProtoType: npn,
+ })
+ tests = append(tests, testCase{
+ testType: serverTest,
+ name: "ChannelID-NPN-Server",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ ChannelID: channelIDKey,
+ NextProtos: []string{"bar"},
+ },
+ flags: []string{
+ "-expect-channel-id",
+ base64.StdEncoding.EncodeToString(channelIDBytes),
+ "-advertise-npn", "\x03foo\x03bar\x03baz",
+ "-expect-next-proto", "bar",
+ },
+ resumeSession: true,
+ expectChannelID: true,
+ expectedNextProto: "bar",
+ expectedNextProtoType: npn,
+ })
+
+ // Bidirectional shutdown with the runner initiating.
+ tests = append(tests, testCase{
+ name: "Shutdown-Runner",
+ config: Config{
+ Bugs: ProtocolBugs{
+ ExpectCloseNotify: true,
+ },
+ },
+ flags: []string{"-check-close-notify"},
+ })
+
+ // Bidirectional shutdown with the shim initiating. The runner,
+ // in the meantime, sends garbage before the close_notify which
+ // the shim must ignore.
+ tests = append(tests, testCase{
+ name: "Shutdown-Shim",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ ExpectCloseNotify: true,
+ },
+ },
+ shimShutsDown: true,
+ sendEmptyRecords: 1,
+ sendWarningAlerts: 1,
+ flags: []string{"-check-close-notify"},
+ })
+ } else {
+ // TODO(davidben): DTLS 1.3 will want a similar thing for
+ // HelloRetryRequest.
+ tests = append(tests, testCase{
+ name: "SkipHelloVerifyRequest",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ SkipHelloVerifyRequest: true,
+ },
+ },
+ })
+ }
+
+ for _, test := range tests {
+ test.protocol = config.protocol
+ if config.protocol == dtls {
+ test.name += "-DTLS"
+ }
+ if config.async {
+ test.name += "-Async"
+ test.flags = append(test.flags, "-async")
+ } else {
+ test.name += "-Sync"
+ }
+ if config.splitHandshake {
+ test.name += "-SplitHandshakeRecords"
+ test.config.Bugs.MaxHandshakeRecordLength = 1
+ if config.protocol == dtls {
+ test.config.Bugs.MaxPacketLength = 256
+ test.flags = append(test.flags, "-mtu", "256")
+ }
+ }
+ if config.packHandshakeFlight {
+ test.name += "-PackHandshakeFlight"
+ test.config.Bugs.PackHandshakeFlight = true
+ }
+ testCases = append(testCases, test)
+ }
+}
+
+func addDDoSCallbackTests() {
+ // DDoS callback.
+ for _, resume := range []bool{false, true} {
+ suffix := "Resume"
+ if resume {
+ suffix = "No" + suffix
+ }
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "Server-DDoS-OK-" + suffix,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ },
+ flags: []string{"-install-ddos-callback"},
+ resumeSession: resume,
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "Server-DDoS-OK-" + suffix + "-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ },
+ flags: []string{"-install-ddos-callback"},
+ resumeSession: resume,
+ })
+
+ failFlag := "-fail-ddos-callback"
+ if resume {
+ failFlag = "-fail-second-ddos-callback"
+ }
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "Server-DDoS-Reject-" + suffix,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ },
+ flags: []string{"-install-ddos-callback", failFlag},
+ resumeSession: resume,
+ shouldFail: true,
+ expectedError: ":CONNECTION_REJECTED:",
+ expectedLocalError: "remote error: internal error",
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "Server-DDoS-Reject-" + suffix + "-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ },
+ flags: []string{"-install-ddos-callback", failFlag},
+ resumeSession: resume,
+ shouldFail: true,
+ expectedError: ":CONNECTION_REJECTED:",
+ expectedLocalError: "remote error: internal error",
+ })
+ }
+}
+
+func addVersionNegotiationTests() {
+ for i, shimVers := range tlsVersions {
+ // Assemble flags to disable all newer versions on the shim.
+ var flags []string
+ for _, vers := range tlsVersions[i+1:] {
+ flags = append(flags, vers.flag)
+ }
+
+ // Test configuring the runner's maximum version.
+ for _, runnerVers := range tlsVersions {
+ protocols := []protocol{tls}
+ if runnerVers.hasDTLS && shimVers.hasDTLS {
+ protocols = append(protocols, dtls)
+ }
+ for _, protocol := range protocols {
+ expectedVersion := shimVers.version
+ if runnerVers.version < shimVers.version {
+ expectedVersion = runnerVers.version
+ }
+
+ suffix := shimVers.name + "-" + runnerVers.name
+ if protocol == dtls {
+ suffix += "-DTLS"
+ }
+
+ shimVersFlag := strconv.Itoa(int(versionToWire(shimVers.version, protocol == dtls)))
+
+ // Determine the expected initial record-layer versions.
+ clientVers := shimVers.version
+ if clientVers > VersionTLS10 {
+ clientVers = VersionTLS10
+ }
+ clientVers = versionToWire(clientVers, protocol == dtls)
+ serverVers := expectedVersion
+ if expectedVersion >= VersionTLS13 {
+ serverVers = VersionTLS10
+ }
+ serverVers = versionToWire(serverVers, protocol == dtls)
+
+ testCases = append(testCases, testCase{
+ protocol: protocol,
+ testType: clientTest,
+ name: "VersionNegotiation-Client-" + suffix,
+ config: Config{
+ MaxVersion: runnerVers.version,
+ Bugs: ProtocolBugs{
+ ExpectInitialRecordVersion: clientVers,
+ },
+ },
+ flags: flags,
+ expectedVersion: expectedVersion,
+ })
+ testCases = append(testCases, testCase{
+ protocol: protocol,
+ testType: clientTest,
+ name: "VersionNegotiation-Client2-" + suffix,
+ config: Config{
+ MaxVersion: runnerVers.version,
+ Bugs: ProtocolBugs{
+ ExpectInitialRecordVersion: clientVers,
+ },
+ },
+ flags: []string{"-max-version", shimVersFlag},
+ expectedVersion: expectedVersion,
+ })
+
+ testCases = append(testCases, testCase{
+ protocol: protocol,
+ testType: serverTest,
+ name: "VersionNegotiation-Server-" + suffix,
+ config: Config{
+ MaxVersion: runnerVers.version,
+ Bugs: ProtocolBugs{
+ ExpectInitialRecordVersion: serverVers,
+ },
+ },
+ flags: flags,
+ expectedVersion: expectedVersion,
+ })
+ testCases = append(testCases, testCase{
+ protocol: protocol,
+ testType: serverTest,
+ name: "VersionNegotiation-Server2-" + suffix,
+ config: Config{
+ MaxVersion: runnerVers.version,
+ Bugs: ProtocolBugs{
+ ExpectInitialRecordVersion: serverVers,
+ },
+ },
+ flags: []string{"-max-version", shimVersFlag},
+ expectedVersion: expectedVersion,
+ })
+ }
+ }
+ }
+
+ // Test the version extension at all versions.
+ for _, vers := range tlsVersions {
+ protocols := []protocol{tls}
+ if vers.hasDTLS {
+ protocols = append(protocols, dtls)
+ }
+ for _, protocol := range protocols {
+ suffix := vers.name
+ if protocol == dtls {
+ suffix += "-DTLS"
+ }
+
+ wireVersion := versionToWire(vers.version, protocol == dtls)
+ testCases = append(testCases, testCase{
+ protocol: protocol,
+ testType: serverTest,
+ name: "VersionNegotiationExtension-" + suffix,
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendSupportedVersions: []uint16{0x1111, wireVersion, 0x2222},
+ },
+ },
+ expectedVersion: vers.version,
+ })
+ }
+
+ }
+
+ // If all versions are unknown, negotiation fails.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "NoSupportedVersions",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendSupportedVersions: []uint16{0x1111},
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNSUPPORTED_PROTOCOL:",
+ })
+ testCases = append(testCases, testCase{
+ protocol: dtls,
+ testType: serverTest,
+ name: "NoSupportedVersions-DTLS",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendSupportedVersions: []uint16{0x1111},
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNSUPPORTED_PROTOCOL:",
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "ClientHelloVersionTooHigh",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendClientVersion: 0x0304,
+ OmitSupportedVersions: true,
+ },
+ },
+ expectedVersion: VersionTLS12,
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "ConflictingVersionNegotiation",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendClientVersion: VersionTLS12,
+ SendSupportedVersions: []uint16{VersionTLS11},
+ },
+ },
+ // The extension takes precedence over the ClientHello version.
+ expectedVersion: VersionTLS11,
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "ConflictingVersionNegotiation-2",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendClientVersion: VersionTLS11,
+ SendSupportedVersions: []uint16{VersionTLS12},
+ },
+ },
+ // The extension takes precedence over the ClientHello version.
+ expectedVersion: VersionTLS12,
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "RejectFinalTLS13",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendSupportedVersions: []uint16{VersionTLS13, VersionTLS12},
+ },
+ },
+ // We currently implement a draft TLS 1.3 version. Ensure that
+ // the true TLS 1.3 value is ignored for now.
+ expectedVersion: VersionTLS12,
+ })
+
+ // Test that the maximum version is selected regardless of the
+ // client-sent order.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "IgnoreClientVersionOrder",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendSupportedVersions: []uint16{VersionTLS12, tls13DraftVersion},
+ },
+ },
+ expectedVersion: VersionTLS13,
+ })
+
+ // Test for version tolerance.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "MinorVersionTolerance",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendClientVersion: 0x03ff,
+ OmitSupportedVersions: true,
+ },
+ },
+ expectedVersion: VersionTLS12,
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "MajorVersionTolerance",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendClientVersion: 0x0400,
+ OmitSupportedVersions: true,
+ },
+ },
+ // TLS 1.3 must be negotiated with the supported_versions
+ // extension, not ClientHello.version.
+ expectedVersion: VersionTLS12,
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "VersionTolerance-TLS13",
+ config: Config{
+ Bugs: ProtocolBugs{
+ // Although TLS 1.3 does not use
+ // ClientHello.version, it still tolerates high
+ // values there.
+ SendClientVersion: 0x0400,
+ },
+ },
+ expectedVersion: VersionTLS13,
+ })
+
+ testCases = append(testCases, testCase{
+ protocol: dtls,
+ testType: serverTest,
+ name: "MinorVersionTolerance-DTLS",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendClientVersion: 0xfe00,
+ OmitSupportedVersions: true,
+ },
+ },
+ expectedVersion: VersionTLS12,
+ })
+ testCases = append(testCases, testCase{
+ protocol: dtls,
+ testType: serverTest,
+ name: "MajorVersionTolerance-DTLS",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendClientVersion: 0xfdff,
+ OmitSupportedVersions: true,
+ },
+ },
+ expectedVersion: VersionTLS12,
+ })
+
+ // Test that versions below 3.0 are rejected.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "VersionTooLow",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendClientVersion: 0x0200,
+ OmitSupportedVersions: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNSUPPORTED_PROTOCOL:",
+ })
+ testCases = append(testCases, testCase{
+ protocol: dtls,
+ testType: serverTest,
+ name: "VersionTooLow-DTLS",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendClientVersion: 0xffff,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNSUPPORTED_PROTOCOL:",
+ })
+
+ testCases = append(testCases, testCase{
+ name: "ServerBogusVersion",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendServerHelloVersion: 0x1234,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNSUPPORTED_PROTOCOL:",
+ })
+
+ // Test TLS 1.3's downgrade signal.
+ testCases = append(testCases, testCase{
+ name: "Downgrade-TLS12-Client",
+ config: Config{
+ Bugs: ProtocolBugs{
+ NegotiateVersion: VersionTLS12,
+ },
+ },
+ expectedVersion: VersionTLS12,
+ // TODO(davidben): This test should fail once TLS 1.3 is final
+ // and the fallback signal restored.
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "Downgrade-TLS12-Server",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendSupportedVersions: []uint16{VersionTLS12},
+ },
+ },
+ expectedVersion: VersionTLS12,
+ // TODO(davidben): This test should fail once TLS 1.3 is final
+ // and the fallback signal restored.
+ })
+}
+
+func addMinimumVersionTests() {
+ for i, shimVers := range tlsVersions {
+ // Assemble flags to disable all older versions on the shim.
+ var flags []string
+ for _, vers := range tlsVersions[:i] {
+ flags = append(flags, vers.flag)
+ }
+
+ for _, runnerVers := range tlsVersions {
+ protocols := []protocol{tls}
+ if runnerVers.hasDTLS && shimVers.hasDTLS {
+ protocols = append(protocols, dtls)
+ }
+ for _, protocol := range protocols {
+ suffix := shimVers.name + "-" + runnerVers.name
+ if protocol == dtls {
+ suffix += "-DTLS"
+ }
+ shimVersFlag := strconv.Itoa(int(versionToWire(shimVers.version, protocol == dtls)))
+
+ var expectedVersion uint16
+ var shouldFail bool
+ var expectedError, expectedLocalError string
+ if runnerVers.version >= shimVers.version {
+ expectedVersion = runnerVers.version
+ } else {
+ shouldFail = true
+ expectedError = ":UNSUPPORTED_PROTOCOL:"
+ expectedLocalError = "remote error: protocol version not supported"
+ }
+
+ testCases = append(testCases, testCase{
+ protocol: protocol,
+ testType: clientTest,
+ name: "MinimumVersion-Client-" + suffix,
+ config: Config{
+ MaxVersion: runnerVers.version,
+ Bugs: ProtocolBugs{
+ // Ensure the server does not decline to
+ // select a version (versions extension) or
+ // cipher (some ciphers depend on versions).
+ NegotiateVersion: runnerVers.version,
+ IgnorePeerCipherPreferences: shouldFail,
+ },
+ },
+ flags: flags,
+ expectedVersion: expectedVersion,
+ shouldFail: shouldFail,
+ expectedError: expectedError,
+ expectedLocalError: expectedLocalError,
+ })
+ testCases = append(testCases, testCase{
+ protocol: protocol,
+ testType: clientTest,
+ name: "MinimumVersion-Client2-" + suffix,
+ config: Config{
+ MaxVersion: runnerVers.version,
+ Bugs: ProtocolBugs{
+ // Ensure the server does not decline to
+ // select a version (versions extension) or
+ // cipher (some ciphers depend on versions).
+ NegotiateVersion: runnerVers.version,
+ IgnorePeerCipherPreferences: shouldFail,
+ },
+ },
+ flags: []string{"-min-version", shimVersFlag},
+ expectedVersion: expectedVersion,
+ shouldFail: shouldFail,
+ expectedError: expectedError,
+ expectedLocalError: expectedLocalError,
+ })
+
+ testCases = append(testCases, testCase{
+ protocol: protocol,
+ testType: serverTest,
+ name: "MinimumVersion-Server-" + suffix,
+ config: Config{
+ MaxVersion: runnerVers.version,
+ },
+ flags: flags,
+ expectedVersion: expectedVersion,
+ shouldFail: shouldFail,
+ expectedError: expectedError,
+ expectedLocalError: expectedLocalError,
+ })
+ testCases = append(testCases, testCase{
+ protocol: protocol,
+ testType: serverTest,
+ name: "MinimumVersion-Server2-" + suffix,
+ config: Config{
+ MaxVersion: runnerVers.version,
+ },
+ flags: []string{"-min-version", shimVersFlag},
+ expectedVersion: expectedVersion,
+ shouldFail: shouldFail,
+ expectedError: expectedError,
+ expectedLocalError: expectedLocalError,
+ })
+ }
+ }
+ }
+}
+
+func addExtensionTests() {
+ // TODO(davidben): Extensions, where applicable, all move their server
+ // halves to EncryptedExtensions in TLS 1.3. Duplicate each of these
+ // tests for both. Also test interaction with 0-RTT when implemented.
+
+ // Repeat extensions tests all versions except SSL 3.0.
+ for _, ver := range tlsVersions {
+ if ver.version == VersionSSL30 {
+ continue
+ }
+
+ // Test that duplicate extensions are rejected.
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "DuplicateExtensionClient-" + ver.name,
+ config: Config{
+ MaxVersion: ver.version,
+ Bugs: ProtocolBugs{
+ DuplicateExtension: true,
+ },
+ },
+ shouldFail: true,
+ expectedLocalError: "remote error: error decoding message",
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "DuplicateExtensionServer-" + ver.name,
+ config: Config{
+ MaxVersion: ver.version,
+ Bugs: ProtocolBugs{
+ DuplicateExtension: true,
+ },
+ },
+ shouldFail: true,
+ expectedLocalError: "remote error: error decoding message",
+ })
+
+ // Test SNI.
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "ServerNameExtensionClient-" + ver.name,
+ config: Config{
+ MaxVersion: ver.version,
+ Bugs: ProtocolBugs{
+ ExpectServerName: "example.com",
+ },
+ },
+ flags: []string{"-host-name", "example.com"},
+ })
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "ServerNameExtensionClientMismatch-" + ver.name,
+ config: Config{
+ MaxVersion: ver.version,
+ Bugs: ProtocolBugs{
+ ExpectServerName: "mismatch.com",
+ },
+ },
+ flags: []string{"-host-name", "example.com"},
+ shouldFail: true,
+ expectedLocalError: "tls: unexpected server name",
+ })
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "ServerNameExtensionClientMissing-" + ver.name,
+ config: Config{
+ MaxVersion: ver.version,
+ Bugs: ProtocolBugs{
+ ExpectServerName: "missing.com",
+ },
+ },
+ shouldFail: true,
+ expectedLocalError: "tls: unexpected server name",
+ })
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "TolerateServerNameAck-" + ver.name,
+ config: Config{
+ MaxVersion: ver.version,
+ Bugs: ProtocolBugs{
+ SendServerNameAck: true,
+ },
+ },
+ flags: []string{"-host-name", "example.com"},
+ resumeSession: true,
+ })
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "UnsolicitedServerNameAck-" + ver.name,
+ config: Config{
+ MaxVersion: ver.version,
+ Bugs: ProtocolBugs{
+ SendServerNameAck: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_EXTENSION:",
+ expectedLocalError: "remote error: unsupported extension",
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "ServerNameExtensionServer-" + ver.name,
+ config: Config{
+ MaxVersion: ver.version,
+ ServerName: "example.com",
+ },
+ flags: []string{"-expect-server-name", "example.com"},
+ resumeSession: true,
+ })
+
+ // Test ALPN.
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "ALPNClient-" + ver.name,
+ config: Config{
+ MaxVersion: ver.version,
+ NextProtos: []string{"foo"},
+ },
+ flags: []string{
+ "-advertise-alpn", "\x03foo\x03bar\x03baz",
+ "-expect-alpn", "foo",
+ },
+ expectedNextProto: "foo",
+ expectedNextProtoType: alpn,
+ resumeSession: true,
+ })
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "ALPNClient-Mismatch-" + ver.name,
+ config: Config{
+ MaxVersion: ver.version,
+ Bugs: ProtocolBugs{
+ SendALPN: "baz",
+ },
+ },
+ flags: []string{
+ "-advertise-alpn", "\x03foo\x03bar",
+ },
+ shouldFail: true,
+ expectedError: ":INVALID_ALPN_PROTOCOL:",
+ expectedLocalError: "remote error: illegal parameter",
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "ALPNServer-" + ver.name,
+ config: Config{
+ MaxVersion: ver.version,
+ NextProtos: []string{"foo", "bar", "baz"},
+ },
+ flags: []string{
+ "-expect-advertised-alpn", "\x03foo\x03bar\x03baz",
+ "-select-alpn", "foo",
+ },
+ expectedNextProto: "foo",
+ expectedNextProtoType: alpn,
+ resumeSession: true,
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "ALPNServer-Decline-" + ver.name,
+ config: Config{
+ MaxVersion: ver.version,
+ NextProtos: []string{"foo", "bar", "baz"},
+ },
+ flags: []string{"-decline-alpn"},
+ expectNoNextProto: true,
+ resumeSession: true,
+ })
+
+ // Test ALPN in async mode as well to ensure that extensions callbacks are only
+ // called once.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "ALPNServer-Async-" + ver.name,
+ config: Config{
+ MaxVersion: ver.version,
+ NextProtos: []string{"foo", "bar", "baz"},
+ // Prior to TLS 1.3, exercise the asynchronous session callback.
+ SessionTicketsDisabled: ver.version < VersionTLS13,
+ },
+ flags: []string{
+ "-expect-advertised-alpn", "\x03foo\x03bar\x03baz",
+ "-select-alpn", "foo",
+ "-async",
+ },
+ expectedNextProto: "foo",
+ expectedNextProtoType: alpn,
+ resumeSession: true,
+ })
+
+ var emptyString string
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "ALPNClient-EmptyProtocolName-" + ver.name,
+ config: Config{
+ MaxVersion: ver.version,
+ NextProtos: []string{""},
+ Bugs: ProtocolBugs{
+ // A server returning an empty ALPN protocol
+ // should be rejected.
+ ALPNProtocol: &emptyString,
+ },
+ },
+ flags: []string{
+ "-advertise-alpn", "\x03foo",
+ },
+ shouldFail: true,
+ expectedError: ":PARSE_TLSEXT:",
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "ALPNServer-EmptyProtocolName-" + ver.name,
+ config: Config{
+ MaxVersion: ver.version,
+ // A ClientHello containing an empty ALPN protocol
+ // should be rejected.
+ NextProtos: []string{"foo", "", "baz"},
+ },
+ flags: []string{
+ "-select-alpn", "foo",
+ },
+ shouldFail: true,
+ expectedError: ":PARSE_TLSEXT:",
+ })
+
+ // Test NPN and the interaction with ALPN.
+ if ver.version < VersionTLS13 {
+ // Test that the server prefers ALPN over NPN.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "ALPNServer-Preferred-" + ver.name,
+ config: Config{
+ MaxVersion: ver.version,
+ NextProtos: []string{"foo", "bar", "baz"},
+ },
+ flags: []string{
+ "-expect-advertised-alpn", "\x03foo\x03bar\x03baz",
+ "-select-alpn", "foo",
+ "-advertise-npn", "\x03foo\x03bar\x03baz",
+ },
+ expectedNextProto: "foo",
+ expectedNextProtoType: alpn,
+ resumeSession: true,
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "ALPNServer-Preferred-Swapped-" + ver.name,
+ config: Config{
+ MaxVersion: ver.version,
+ NextProtos: []string{"foo", "bar", "baz"},
+ Bugs: ProtocolBugs{
+ SwapNPNAndALPN: true,
+ },
+ },
+ flags: []string{
+ "-expect-advertised-alpn", "\x03foo\x03bar\x03baz",
+ "-select-alpn", "foo",
+ "-advertise-npn", "\x03foo\x03bar\x03baz",
+ },
+ expectedNextProto: "foo",
+ expectedNextProtoType: alpn,
+ resumeSession: true,
+ })
+
+ // Test that negotiating both NPN and ALPN is forbidden.
+ testCases = append(testCases, testCase{
+ name: "NegotiateALPNAndNPN-" + ver.name,
+ config: Config{
+ MaxVersion: ver.version,
+ NextProtos: []string{"foo", "bar", "baz"},
+ Bugs: ProtocolBugs{
+ NegotiateALPNAndNPN: true,
+ },
+ },
+ flags: []string{
+ "-advertise-alpn", "\x03foo",
+ "-select-next-proto", "foo",
+ },
+ shouldFail: true,
+ expectedError: ":NEGOTIATED_BOTH_NPN_AND_ALPN:",
+ })
+ testCases = append(testCases, testCase{
+ name: "NegotiateALPNAndNPN-Swapped-" + ver.name,
+ config: Config{
+ MaxVersion: ver.version,
+ NextProtos: []string{"foo", "bar", "baz"},
+ Bugs: ProtocolBugs{
+ NegotiateALPNAndNPN: true,
+ SwapNPNAndALPN: true,
+ },
+ },
+ flags: []string{
+ "-advertise-alpn", "\x03foo",
+ "-select-next-proto", "foo",
+ },
+ shouldFail: true,
+ expectedError: ":NEGOTIATED_BOTH_NPN_AND_ALPN:",
+ })
+ }
+
+ // Test ticket behavior.
+
+ // Resume with a corrupt ticket.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "CorruptTicket-" + ver.name,
+ config: Config{
+ MaxVersion: ver.version,
+ Bugs: ProtocolBugs{
+ FilterTicket: func(in []byte) ([]byte, error) {
+ in[len(in)-1] ^= 1
+ return in, nil
+ },
+ },
+ },
+ resumeSession: true,
+ expectResumeRejected: true,
+ })
+ // Test the ticket callback, with and without renewal.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "TicketCallback-" + ver.name,
+ config: Config{
+ MaxVersion: ver.version,
+ },
+ resumeSession: true,
+ flags: []string{"-use-ticket-callback"},
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "TicketCallback-Renew-" + ver.name,
+ config: Config{
+ MaxVersion: ver.version,
+ Bugs: ProtocolBugs{
+ ExpectNewTicket: true,
+ },
+ },
+ flags: []string{"-use-ticket-callback", "-renew-ticket"},
+ resumeSession: true,
+ })
+
+ // Test that the ticket callback is only called once when everything before
+ // it in the ClientHello is asynchronous. This corrupts the ticket so
+ // certificate selection callbacks run.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "TicketCallback-SingleCall-" + ver.name,
+ config: Config{
+ MaxVersion: ver.version,
+ Bugs: ProtocolBugs{
+ FilterTicket: func(in []byte) ([]byte, error) {
+ in[len(in)-1] ^= 1
+ return in, nil
+ },
+ },
+ },
+ resumeSession: true,
+ expectResumeRejected: true,
+ flags: []string{
+ "-use-ticket-callback",
+ "-async",
+ },
+ })
+
+ // Resume with various lengths of ticket session id.
+ if ver.version < VersionTLS13 {
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "TicketSessionIDLength-0-" + ver.name,
+ config: Config{
+ MaxVersion: ver.version,
+ Bugs: ProtocolBugs{
+ EmptyTicketSessionID: true,
+ },
+ },
+ resumeSession: true,
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "TicketSessionIDLength-16-" + ver.name,
+ config: Config{
+ MaxVersion: ver.version,
+ Bugs: ProtocolBugs{
+ TicketSessionIDLength: 16,
+ },
+ },
+ resumeSession: true,
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "TicketSessionIDLength-32-" + ver.name,
+ config: Config{
+ MaxVersion: ver.version,
+ Bugs: ProtocolBugs{
+ TicketSessionIDLength: 32,
+ },
+ },
+ resumeSession: true,
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "TicketSessionIDLength-33-" + ver.name,
+ config: Config{
+ MaxVersion: ver.version,
+ Bugs: ProtocolBugs{
+ TicketSessionIDLength: 33,
+ },
+ },
+ resumeSession: true,
+ shouldFail: true,
+ // The maximum session ID length is 32.
+ expectedError: ":DECODE_ERROR:",
+ })
+ }
+
+ // Basic DTLS-SRTP tests. Include fake profiles to ensure they
+ // are ignored.
+ if ver.hasDTLS {
+ testCases = append(testCases, testCase{
+ protocol: dtls,
+ name: "SRTP-Client-" + ver.name,
+ config: Config{
+ MaxVersion: ver.version,
+ SRTPProtectionProfiles: []uint16{40, SRTP_AES128_CM_HMAC_SHA1_80, 42},
+ },
+ flags: []string{
+ "-srtp-profiles",
+ "SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32",
+ },
+ expectedSRTPProtectionProfile: SRTP_AES128_CM_HMAC_SHA1_80,
+ })
+ testCases = append(testCases, testCase{
+ protocol: dtls,
+ testType: serverTest,
+ name: "SRTP-Server-" + ver.name,
+ config: Config{
+ MaxVersion: ver.version,
+ SRTPProtectionProfiles: []uint16{40, SRTP_AES128_CM_HMAC_SHA1_80, 42},
+ },
+ flags: []string{
+ "-srtp-profiles",
+ "SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32",
+ },
+ expectedSRTPProtectionProfile: SRTP_AES128_CM_HMAC_SHA1_80,
+ })
+ // Test that the MKI is ignored.
+ testCases = append(testCases, testCase{
+ protocol: dtls,
+ testType: serverTest,
+ name: "SRTP-Server-IgnoreMKI-" + ver.name,
+ config: Config{
+ MaxVersion: ver.version,
+ SRTPProtectionProfiles: []uint16{SRTP_AES128_CM_HMAC_SHA1_80},
+ Bugs: ProtocolBugs{
+ SRTPMasterKeyIdentifer: "bogus",
+ },
+ },
+ flags: []string{
+ "-srtp-profiles",
+ "SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32",
+ },
+ expectedSRTPProtectionProfile: SRTP_AES128_CM_HMAC_SHA1_80,
+ })
+ // Test that SRTP isn't negotiated on the server if there were
+ // no matching profiles.
+ testCases = append(testCases, testCase{
+ protocol: dtls,
+ testType: serverTest,
+ name: "SRTP-Server-NoMatch-" + ver.name,
+ config: Config{
+ MaxVersion: ver.version,
+ SRTPProtectionProfiles: []uint16{100, 101, 102},
+ },
+ flags: []string{
+ "-srtp-profiles",
+ "SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32",
+ },
+ expectedSRTPProtectionProfile: 0,
+ })
+ // Test that the server returning an invalid SRTP profile is
+ // flagged as an error by the client.
+ testCases = append(testCases, testCase{
+ protocol: dtls,
+ name: "SRTP-Client-NoMatch-" + ver.name,
+ config: Config{
+ MaxVersion: ver.version,
+ Bugs: ProtocolBugs{
+ SendSRTPProtectionProfile: SRTP_AES128_CM_HMAC_SHA1_32,
+ },
+ },
+ flags: []string{
+ "-srtp-profiles",
+ "SRTP_AES128_CM_SHA1_80",
+ },
+ shouldFail: true,
+ expectedError: ":BAD_SRTP_PROTECTION_PROFILE_LIST:",
+ })
+ }
+
+ // Test SCT list.
+ testCases = append(testCases, testCase{
+ name: "SignedCertificateTimestampList-Client-" + ver.name,
+ testType: clientTest,
+ config: Config{
+ MaxVersion: ver.version,
+ },
+ flags: []string{
+ "-enable-signed-cert-timestamps",
+ "-expect-signed-cert-timestamps",
+ base64.StdEncoding.EncodeToString(testSCTList),
+ },
+ resumeSession: true,
+ })
+
+ var differentSCTList []byte
+ differentSCTList = append(differentSCTList, testSCTList...)
+ differentSCTList[len(differentSCTList)-1] ^= 1
+
+ // The SCT extension did not specify that it must only be sent on resumption as it
+ // should have, so test that we tolerate but ignore it.
+ testCases = append(testCases, testCase{
+ name: "SendSCTListOnResume-" + ver.name,
+ config: Config{
+ MaxVersion: ver.version,
+ Bugs: ProtocolBugs{
+ SendSCTListOnResume: differentSCTList,
+ },
+ },
+ flags: []string{
+ "-enable-signed-cert-timestamps",
+ "-expect-signed-cert-timestamps",
+ base64.StdEncoding.EncodeToString(testSCTList),
+ },
+ resumeSession: true,
+ })
+
+ testCases = append(testCases, testCase{
+ name: "SignedCertificateTimestampList-Server-" + ver.name,
+ testType: serverTest,
+ config: Config{
+ MaxVersion: ver.version,
+ },
+ flags: []string{
+ "-signed-cert-timestamps",
+ base64.StdEncoding.EncodeToString(testSCTList),
+ },
+ expectedSCTList: testSCTList,
+ resumeSession: true,
+ })
+
+ emptySCTListCert := *testCerts[0].cert
+ emptySCTListCert.SignedCertificateTimestampList = []byte{0, 0}
+
+ // Test empty SCT list.
+ testCases = append(testCases, testCase{
+ name: "SignedCertificateTimestampListEmpty-Client-" + ver.name,
+ testType: clientTest,
+ config: Config{
+ MaxVersion: ver.version,
+ Certificates: []Certificate{emptySCTListCert},
+ },
+ flags: []string{
+ "-enable-signed-cert-timestamps",
+ },
+ shouldFail: true,
+ expectedError: ":ERROR_PARSING_EXTENSION:",
+ })
+
+ emptySCTCert := *testCerts[0].cert
+ emptySCTCert.SignedCertificateTimestampList = []byte{0, 6, 0, 2, 1, 2, 0, 0}
+
+ // Test empty SCT in non-empty list.
+ testCases = append(testCases, testCase{
+ name: "SignedCertificateTimestampListEmptySCT-Client-" + ver.name,
+ testType: clientTest,
+ config: Config{
+ MaxVersion: ver.version,
+ Certificates: []Certificate{emptySCTCert},
+ },
+ flags: []string{
+ "-enable-signed-cert-timestamps",
+ },
+ shouldFail: true,
+ expectedError: ":ERROR_PARSING_EXTENSION:",
+ })
+
+ // Test that certificate-related extensions are not sent unsolicited.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "UnsolicitedCertificateExtensions-" + ver.name,
+ config: Config{
+ MaxVersion: ver.version,
+ Bugs: ProtocolBugs{
+ NoOCSPStapling: true,
+ NoSignedCertificateTimestamps: true,
+ },
+ },
+ flags: []string{
+ "-ocsp-response",
+ base64.StdEncoding.EncodeToString(testOCSPResponse),
+ "-signed-cert-timestamps",
+ base64.StdEncoding.EncodeToString(testSCTList),
+ },
+ })
+ }
+
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "ClientHelloPadding",
+ config: Config{
+ Bugs: ProtocolBugs{
+ RequireClientHelloSize: 512,
+ },
+ },
+ // This hostname just needs to be long enough to push the
+ // ClientHello into F5's danger zone between 256 and 511 bytes
+ // long.
+ flags: []string{"-host-name", "01234567890123456789012345678901234567890123456789012345678901234567890123456789.com"},
+ })
+
+ // Extensions should not function in SSL 3.0.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "SSLv3Extensions-NoALPN",
+ config: Config{
+ MaxVersion: VersionSSL30,
+ NextProtos: []string{"foo", "bar", "baz"},
+ },
+ flags: []string{
+ "-select-alpn", "foo",
+ },
+ expectNoNextProto: true,
+ })
+
+ // Test session tickets separately as they follow a different codepath.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "SSLv3Extensions-NoTickets",
+ config: Config{
+ MaxVersion: VersionSSL30,
+ Bugs: ProtocolBugs{
+ // Historically, session tickets in SSL 3.0
+ // failed in different ways depending on whether
+ // the client supported renegotiation_info.
+ NoRenegotiationInfo: true,
+ },
+ },
+ resumeSession: true,
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "SSLv3Extensions-NoTickets2",
+ config: Config{
+ MaxVersion: VersionSSL30,
+ },
+ resumeSession: true,
+ })
+
+ // But SSL 3.0 does send and process renegotiation_info.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "SSLv3Extensions-RenegotiationInfo",
+ config: Config{
+ MaxVersion: VersionSSL30,
+ Bugs: ProtocolBugs{
+ RequireRenegotiationInfo: true,
+ },
+ },
+ flags: []string{"-expect-secure-renegotiation"},
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "SSLv3Extensions-RenegotiationInfo-SCSV",
+ config: Config{
+ MaxVersion: VersionSSL30,
+ Bugs: ProtocolBugs{
+ NoRenegotiationInfo: true,
+ SendRenegotiationSCSV: true,
+ RequireRenegotiationInfo: true,
+ },
+ },
+ flags: []string{"-expect-secure-renegotiation"},
+ })
+
+ // Test that illegal extensions in TLS 1.3 are rejected by the client if
+ // in ServerHello.
+ testCases = append(testCases, testCase{
+ name: "NPN-Forbidden-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ NextProtos: []string{"foo"},
+ Bugs: ProtocolBugs{
+ NegotiateNPNAtAllVersions: true,
+ },
+ },
+ flags: []string{"-select-next-proto", "foo"},
+ shouldFail: true,
+ expectedError: ":ERROR_PARSING_EXTENSION:",
+ })
+ testCases = append(testCases, testCase{
+ name: "EMS-Forbidden-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ NegotiateEMSAtAllVersions: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":ERROR_PARSING_EXTENSION:",
+ })
+ testCases = append(testCases, testCase{
+ name: "RenegotiationInfo-Forbidden-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ NegotiateRenegotiationInfoAtAllVersions: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":ERROR_PARSING_EXTENSION:",
+ })
+ testCases = append(testCases, testCase{
+ name: "Ticket-Forbidden-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ },
+ resumeConfig: &Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ AdvertiseTicketExtension: true,
+ },
+ },
+ resumeSession: true,
+ shouldFail: true,
+ expectedError: ":ERROR_PARSING_EXTENSION:",
+ })
+
+ // Test that illegal extensions in TLS 1.3 are declined by the server if
+ // offered in ClientHello. The runner's server will fail if this occurs,
+ // so we exercise the offering path. (EMS and Renegotiation Info are
+ // implicit in every test.)
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "NPN-Declined-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ NextProtos: []string{"bar"},
+ },
+ flags: []string{"-advertise-npn", "\x03foo\x03bar\x03baz"},
+ })
+
+ // OpenSSL sends the status_request extension on resumption in TLS 1.2. Test that this is
+ // tolerated.
+ testCases = append(testCases, testCase{
+ name: "SendOCSPResponseOnResume-TLS12",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ SendOCSPResponseOnResume: []byte("bogus"),
+ },
+ },
+ flags: []string{
+ "-enable-ocsp-stapling",
+ "-expect-ocsp-response",
+ base64.StdEncoding.EncodeToString(testOCSPResponse),
+ },
+ resumeSession: true,
+ })
+
+ testCases = append(testCases, testCase{
+ name: "SendUnsolicitedOCSPOnCertificate-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendExtensionOnCertificate: testOCSPExtension,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_EXTENSION:",
+ })
+
+ testCases = append(testCases, testCase{
+ name: "SendUnsolicitedSCTOnCertificate-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendExtensionOnCertificate: testSCTExtension,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_EXTENSION:",
+ })
+
+ // Test that extensions on client certificates are never accepted.
+ testCases = append(testCases, testCase{
+ name: "SendExtensionOnClientCertificate-TLS13",
+ testType: serverTest,
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Certificates: []Certificate{rsaCertificate},
+ Bugs: ProtocolBugs{
+ SendExtensionOnCertificate: testOCSPExtension,
+ },
+ },
+ flags: []string{
+ "-enable-ocsp-stapling",
+ "-require-any-client-certificate",
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_EXTENSION:",
+ })
+
+ testCases = append(testCases, testCase{
+ name: "SendUnknownExtensionOnCertificate-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendExtensionOnCertificate: []byte{0x00, 0x7f, 0, 0},
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_EXTENSION:",
+ })
+
+ var differentSCTList []byte
+ differentSCTList = append(differentSCTList, testSCTList...)
+ differentSCTList[len(differentSCTList)-1] ^= 1
+
+ // Test that extensions on intermediates are allowed but ignored.
+ testCases = append(testCases, testCase{
+ name: "IgnoreExtensionsOnIntermediates-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Certificates: []Certificate{rsaChainCertificate},
+ Bugs: ProtocolBugs{
+ // Send different values on the intermediate. This tests
+ // the intermediate's extensions do not override the
+ // leaf's.
+ SendOCSPOnIntermediates: []byte{1, 3, 3, 7},
+ SendSCTOnIntermediates: differentSCTList,
+ },
+ },
+ flags: []string{
+ "-enable-ocsp-stapling",
+ "-expect-ocsp-response",
+ base64.StdEncoding.EncodeToString(testOCSPResponse),
+ "-enable-signed-cert-timestamps",
+ "-expect-signed-cert-timestamps",
+ base64.StdEncoding.EncodeToString(testSCTList),
+ },
+ resumeSession: true,
+ })
+
+ // Test that extensions are not sent on intermediates when configured
+ // only for a leaf.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "SendNoExtensionsOnIntermediate-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ ExpectNoExtensionsOnIntermediate: true,
+ },
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, rsaChainCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaChainKeyFile),
+ "-ocsp-response",
+ base64.StdEncoding.EncodeToString(testOCSPResponse),
+ "-signed-cert-timestamps",
+ base64.StdEncoding.EncodeToString(testSCTList),
+ },
+ })
+
+ // Test that extensions are not sent on client certificates.
+ testCases = append(testCases, testCase{
+ name: "SendNoClientCertificateExtensions-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ ClientAuth: RequireAnyClientCert,
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaKeyFile),
+ "-ocsp-response",
+ base64.StdEncoding.EncodeToString(testOCSPResponse),
+ "-signed-cert-timestamps",
+ base64.StdEncoding.EncodeToString(testSCTList),
+ },
+ })
+
+ testCases = append(testCases, testCase{
+ name: "SendDuplicateExtensionsOnCerts-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendDuplicateCertExtensions: true,
+ },
+ },
+ flags: []string{
+ "-enable-ocsp-stapling",
+ "-enable-signed-cert-timestamps",
+ },
+ resumeSession: true,
+ shouldFail: true,
+ expectedError: ":DUPLICATE_EXTENSION:",
+ })
+
+ testCases = append(testCases, testCase{
+ name: "SignedCertificateTimestampListInvalid-Server",
+ testType: serverTest,
+ flags: []string{
+ "-signed-cert-timestamps",
+ base64.StdEncoding.EncodeToString([]byte{0, 0}),
+ },
+ shouldFail: true,
+ expectedError: ":INVALID_SCT_LIST:",
+ })
+}
+
+func addResumptionVersionTests() {
+ for _, sessionVers := range tlsVersions {
+ for _, resumeVers := range tlsVersions {
+ // SSL 3.0 does not have tickets and TLS 1.3 does not
+ // have session IDs, so skip their cross-resumption
+ // tests.
+ if (sessionVers.version >= VersionTLS13 && resumeVers.version == VersionSSL30) ||
+ (resumeVers.version >= VersionTLS13 && sessionVers.version == VersionSSL30) {
+ continue
+ }
+
+ protocols := []protocol{tls}
+ if sessionVers.hasDTLS && resumeVers.hasDTLS {
+ protocols = append(protocols, dtls)
+ }
+ for _, protocol := range protocols {
+ suffix := "-" + sessionVers.name + "-" + resumeVers.name
+ if protocol == dtls {
+ suffix += "-DTLS"
+ }
+
+ if sessionVers.version == resumeVers.version {
+ testCases = append(testCases, testCase{
+ protocol: protocol,
+ name: "Resume-Client" + suffix,
+ resumeSession: true,
+ config: Config{
+ MaxVersion: sessionVers.version,
+ Bugs: ProtocolBugs{
+ ExpectNoTLS12Session: sessionVers.version >= VersionTLS13,
+ ExpectNoTLS13PSK: sessionVers.version < VersionTLS13,
+ },
+ },
+ expectedVersion: sessionVers.version,
+ expectedResumeVersion: resumeVers.version,
+ })
+ } else {
+ error := ":OLD_SESSION_VERSION_NOT_RETURNED:"
+
+ // Offering a TLS 1.3 session sends an empty session ID, so
+ // there is no way to convince a non-lookahead client the
+ // session was resumed. It will appear to the client that a
+ // stray ChangeCipherSpec was sent.
+ if resumeVers.version < VersionTLS13 && sessionVers.version >= VersionTLS13 {
+ error = ":UNEXPECTED_RECORD:"
+ }
+
+ testCases = append(testCases, testCase{
+ protocol: protocol,
+ name: "Resume-Client-Mismatch" + suffix,
+ resumeSession: true,
+ config: Config{
+ MaxVersion: sessionVers.version,
+ },
+ expectedVersion: sessionVers.version,
+ resumeConfig: &Config{
+ MaxVersion: resumeVers.version,
+ Bugs: ProtocolBugs{
+ AcceptAnySession: true,
+ },
+ },
+ expectedResumeVersion: resumeVers.version,
+ shouldFail: true,
+ expectedError: error,
+ })
+ }
+
+ testCases = append(testCases, testCase{
+ protocol: protocol,
+ name: "Resume-Client-NoResume" + suffix,
+ resumeSession: true,
+ config: Config{
+ MaxVersion: sessionVers.version,
+ },
+ expectedVersion: sessionVers.version,
+ resumeConfig: &Config{
+ MaxVersion: resumeVers.version,
+ },
+ newSessionsOnResume: true,
+ expectResumeRejected: true,
+ expectedResumeVersion: resumeVers.version,
+ })
+
+ testCases = append(testCases, testCase{
+ protocol: protocol,
+ testType: serverTest,
+ name: "Resume-Server" + suffix,
+ resumeSession: true,
+ config: Config{
+ MaxVersion: sessionVers.version,
+ },
+ expectedVersion: sessionVers.version,
+ expectResumeRejected: sessionVers.version != resumeVers.version,
+ resumeConfig: &Config{
+ MaxVersion: resumeVers.version,
+ Bugs: ProtocolBugs{
+ SendBothTickets: true,
+ },
+ },
+ expectedResumeVersion: resumeVers.version,
+ })
+ }
+ }
+ }
+
+ // Make sure shim ticket mutations are functional.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "ShimTicketRewritable",
+ resumeSession: true,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ Bugs: ProtocolBugs{
+ FilterTicket: func(in []byte) ([]byte, error) {
+ in, err := SetShimTicketVersion(in, VersionTLS12)
+ if err != nil {
+ return nil, err
+ }
+ return SetShimTicketCipherSuite(in, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256)
+ },
+ },
+ },
+ flags: []string{
+ "-ticket-key",
+ base64.StdEncoding.EncodeToString(TestShimTicketKey),
+ },
+ })
+
+ // Resumptions are declined if the version does not match.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "Resume-Server-DeclineCrossVersion",
+ resumeSession: true,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ ExpectNewTicket: true,
+ FilterTicket: func(in []byte) ([]byte, error) {
+ return SetShimTicketVersion(in, VersionTLS13)
+ },
+ },
+ },
+ flags: []string{
+ "-ticket-key",
+ base64.StdEncoding.EncodeToString(TestShimTicketKey),
+ },
+ expectResumeRejected: true,
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "Resume-Server-DeclineCrossVersion-TLS13",
+ resumeSession: true,
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ FilterTicket: func(in []byte) ([]byte, error) {
+ return SetShimTicketVersion(in, VersionTLS12)
+ },
+ },
+ },
+ flags: []string{
+ "-ticket-key",
+ base64.StdEncoding.EncodeToString(TestShimTicketKey),
+ },
+ expectResumeRejected: true,
+ })
+
+ // Resumptions are declined if the cipher is invalid or disabled.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "Resume-Server-DeclineBadCipher",
+ resumeSession: true,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ ExpectNewTicket: true,
+ FilterTicket: func(in []byte) ([]byte, error) {
+ return SetShimTicketCipherSuite(in, TLS_AES_128_GCM_SHA256)
+ },
+ },
+ },
+ flags: []string{
+ "-ticket-key",
+ base64.StdEncoding.EncodeToString(TestShimTicketKey),
+ },
+ expectResumeRejected: true,
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "Resume-Server-DeclineBadCipher-2",
+ resumeSession: true,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ ExpectNewTicket: true,
+ FilterTicket: func(in []byte) ([]byte, error) {
+ return SetShimTicketCipherSuite(in, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384)
+ },
+ },
+ },
+ flags: []string{
+ "-cipher", "AES128",
+ "-ticket-key",
+ base64.StdEncoding.EncodeToString(TestShimTicketKey),
+ },
+ expectResumeRejected: true,
+ })
+
+ // Sessions are not resumed if they do not use the preferred cipher.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "Resume-Server-CipherNotPreferred",
+ resumeSession: true,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ ExpectNewTicket: true,
+ FilterTicket: func(in []byte) ([]byte, error) {
+ return SetShimTicketCipherSuite(in, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA)
+ },
+ },
+ },
+ flags: []string{
+ "-ticket-key",
+ base64.StdEncoding.EncodeToString(TestShimTicketKey),
+ },
+ shouldFail: false,
+ expectResumeRejected: true,
+ })
+
+ // TLS 1.3 allows sessions to be resumed at a different cipher if their
+ // PRF hashes match, but BoringSSL will always decline such resumptions.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "Resume-Server-CipherNotPreferred-TLS13",
+ resumeSession: true,
+ config: Config{
+ MaxVersion: VersionTLS13,
+ CipherSuites: []uint16{TLS_CHACHA20_POLY1305_SHA256, TLS_AES_128_GCM_SHA256},
+ Bugs: ProtocolBugs{
+ FilterTicket: func(in []byte) ([]byte, error) {
+ // If the client (runner) offers ChaCha20-Poly1305 first, the
+ // server (shim) always prefers it. Switch it to AES-GCM.
+ return SetShimTicketCipherSuite(in, TLS_AES_128_GCM_SHA256)
+ },
+ },
+ },
+ flags: []string{
+ "-ticket-key",
+ base64.StdEncoding.EncodeToString(TestShimTicketKey),
+ },
+ shouldFail: false,
+ expectResumeRejected: true,
+ })
+
+ // Sessions may not be resumed if they contain another version's cipher.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "Resume-Server-DeclineBadCipher-TLS13",
+ resumeSession: true,
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ FilterTicket: func(in []byte) ([]byte, error) {
+ return SetShimTicketCipherSuite(in, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256)
+ },
+ },
+ },
+ flags: []string{
+ "-ticket-key",
+ base64.StdEncoding.EncodeToString(TestShimTicketKey),
+ },
+ expectResumeRejected: true,
+ })
+
+ // If the client does not offer the cipher from the session, decline to
+ // resume. Clients are forbidden from doing this, but BoringSSL selects
+ // the cipher first, so we only decline.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "Resume-Server-UnofferedCipher",
+ resumeSession: true,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256},
+ },
+ resumeConfig: &Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256},
+ Bugs: ProtocolBugs{
+ SendCipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ },
+ },
+ expectResumeRejected: true,
+ })
+
+ // In TLS 1.3, clients may advertise a cipher list which does not
+ // include the selected cipher. Test that we tolerate this. Servers may
+ // resume at another cipher if the PRF matches, but BoringSSL will
+ // always decline.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "Resume-Server-UnofferedCipher-TLS13",
+ resumeSession: true,
+ config: Config{
+ MaxVersion: VersionTLS13,
+ CipherSuites: []uint16{TLS_CHACHA20_POLY1305_SHA256},
+ },
+ resumeConfig: &Config{
+ MaxVersion: VersionTLS13,
+ CipherSuites: []uint16{TLS_CHACHA20_POLY1305_SHA256},
+ Bugs: ProtocolBugs{
+ SendCipherSuites: []uint16{TLS_AES_128_GCM_SHA256},
+ },
+ },
+ expectResumeRejected: true,
+ })
+
+ // Sessions may not be resumed at a different cipher.
+ testCases = append(testCases, testCase{
+ name: "Resume-Client-CipherMismatch",
+ resumeSession: true,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
+ },
+ resumeConfig: &Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
+ Bugs: ProtocolBugs{
+ SendCipherSuite: TLS_RSA_WITH_AES_128_CBC_SHA,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":OLD_SESSION_CIPHER_NOT_RETURNED:",
+ })
+
+ // Session resumption in TLS 1.3 may change the cipher suite if the PRF
+ // matches.
+ testCases = append(testCases, testCase{
+ name: "Resume-Client-CipherMismatch-TLS13",
+ resumeSession: true,
+ config: Config{
+ MaxVersion: VersionTLS13,
+ CipherSuites: []uint16{TLS_AES_128_GCM_SHA256},
+ },
+ resumeConfig: &Config{
+ MaxVersion: VersionTLS13,
+ CipherSuites: []uint16{TLS_CHACHA20_POLY1305_SHA256},
+ },
+ })
+
+ // Session resumption in TLS 1.3 is forbidden if the PRF does not match.
+ testCases = append(testCases, testCase{
+ name: "Resume-Client-PRFMismatch-TLS13",
+ resumeSession: true,
+ config: Config{
+ MaxVersion: VersionTLS13,
+ CipherSuites: []uint16{TLS_AES_128_GCM_SHA256},
+ },
+ resumeConfig: &Config{
+ MaxVersion: VersionTLS13,
+ CipherSuites: []uint16{TLS_AES_128_GCM_SHA256},
+ Bugs: ProtocolBugs{
+ SendCipherSuite: TLS_AES_256_GCM_SHA384,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":OLD_SESSION_PRF_HASH_MISMATCH:",
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "Resume-Server-BinderWrongLength",
+ resumeSession: true,
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendShortPSKBinder: true,
+ },
+ },
+ shouldFail: true,
+ expectedLocalError: "remote error: error decrypting message",
+ expectedError: ":DIGEST_CHECK_FAILED:",
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "Resume-Server-NoPSKBinder",
+ resumeSession: true,
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendNoPSKBinder: true,
+ },
+ },
+ shouldFail: true,
+ expectedLocalError: "remote error: error decoding message",
+ expectedError: ":DECODE_ERROR:",
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "Resume-Server-ExtraPSKBinder",
+ resumeSession: true,
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendExtraPSKBinder: true,
+ },
+ },
+ shouldFail: true,
+ expectedLocalError: "remote error: illegal parameter",
+ expectedError: ":PSK_IDENTITY_BINDER_COUNT_MISMATCH:",
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "Resume-Server-ExtraIdentityNoBinder",
+ resumeSession: true,
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ ExtraPSKIdentity: true,
+ },
+ },
+ shouldFail: true,
+ expectedLocalError: "remote error: illegal parameter",
+ expectedError: ":PSK_IDENTITY_BINDER_COUNT_MISMATCH:",
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "Resume-Server-InvalidPSKBinder",
+ resumeSession: true,
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendInvalidPSKBinder: true,
+ },
+ },
+ shouldFail: true,
+ expectedLocalError: "remote error: error decrypting message",
+ expectedError: ":DIGEST_CHECK_FAILED:",
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "Resume-Server-PSKBinderFirstExtension",
+ resumeSession: true,
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ PSKBinderFirst: true,
+ },
+ },
+ shouldFail: true,
+ expectedLocalError: "remote error: illegal parameter",
+ expectedError: ":PRE_SHARED_KEY_MUST_BE_LAST:",
+ })
+}
+
+func addRenegotiationTests() {
+ // Servers cannot renegotiate.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "Renegotiate-Server-Forbidden",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ },
+ renegotiate: 1,
+ shouldFail: true,
+ expectedError: ":NO_RENEGOTIATION:",
+ expectedLocalError: "remote error: no renegotiation",
+ })
+ // The server shouldn't echo the renegotiation extension unless
+ // requested by the client.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "Renegotiate-Server-NoExt",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ NoRenegotiationInfo: true,
+ RequireRenegotiationInfo: true,
+ },
+ },
+ shouldFail: true,
+ expectedLocalError: "renegotiation extension missing",
+ })
+ // The renegotiation SCSV should be sufficient for the server to echo
+ // the extension.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "Renegotiate-Server-NoExt-SCSV",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ NoRenegotiationInfo: true,
+ SendRenegotiationSCSV: true,
+ RequireRenegotiationInfo: true,
+ },
+ },
+ })
+ testCases = append(testCases, testCase{
+ name: "Renegotiate-Client",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ FailIfResumeOnRenego: true,
+ },
+ },
+ renegotiate: 1,
+ flags: []string{
+ "-renegotiate-freely",
+ "-expect-total-renegotiations", "1",
+ "-expect-secure-renegotiation",
+ },
+ })
+ testCases = append(testCases, testCase{
+ name: "Renegotiate-Client-EmptyExt",
+ renegotiate: 1,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ EmptyRenegotiationInfo: true,
+ },
+ },
+ flags: []string{"-renegotiate-freely"},
+ shouldFail: true,
+ expectedError: ":RENEGOTIATION_MISMATCH:",
+ })
+ testCases = append(testCases, testCase{
+ name: "Renegotiate-Client-BadExt",
+ renegotiate: 1,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ BadRenegotiationInfo: true,
+ },
+ },
+ flags: []string{"-renegotiate-freely"},
+ shouldFail: true,
+ expectedError: ":RENEGOTIATION_MISMATCH:",
+ })
+ testCases = append(testCases, testCase{
+ name: "Renegotiate-Client-Downgrade",
+ renegotiate: 1,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ NoRenegotiationInfoAfterInitial: true,
+ },
+ },
+ flags: []string{"-renegotiate-freely"},
+ shouldFail: true,
+ expectedError: ":RENEGOTIATION_MISMATCH:",
+ })
+ testCases = append(testCases, testCase{
+ name: "Renegotiate-Client-Upgrade",
+ renegotiate: 1,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ NoRenegotiationInfoInInitial: true,
+ },
+ },
+ flags: []string{"-renegotiate-freely"},
+ shouldFail: true,
+ expectedError: ":RENEGOTIATION_MISMATCH:",
+ })
+ testCases = append(testCases, testCase{
+ name: "Renegotiate-Client-NoExt-Allowed",
+ renegotiate: 1,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ NoRenegotiationInfo: true,
+ },
+ },
+ flags: []string{
+ "-renegotiate-freely",
+ "-expect-total-renegotiations", "1",
+ "-expect-no-secure-renegotiation",
+ },
+ })
+
+ // Test that the server may switch ciphers on renegotiation without
+ // problems.
+ testCases = append(testCases, testCase{
+ name: "Renegotiate-Client-SwitchCiphers",
+ renegotiate: 1,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_RSA_WITH_3DES_EDE_CBC_SHA},
+ },
+ renegotiateCiphers: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ flags: []string{
+ "-renegotiate-freely",
+ "-expect-total-renegotiations", "1",
+ },
+ })
+ testCases = append(testCases, testCase{
+ name: "Renegotiate-Client-SwitchCiphers2",
+ renegotiate: 1,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ },
+ renegotiateCiphers: []uint16{TLS_RSA_WITH_3DES_EDE_CBC_SHA},
+ flags: []string{
+ "-renegotiate-freely",
+ "-expect-total-renegotiations", "1",
+ },
+ })
+
+ // Test that the server may not switch versions on renegotiation.
+ testCases = append(testCases, testCase{
+ name: "Renegotiate-Client-SwitchVersion",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ // Pick a cipher which exists at both versions.
+ CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA},
+ Bugs: ProtocolBugs{
+ NegotiateVersionOnRenego: VersionTLS11,
+ // Avoid failing early at the record layer.
+ SendRecordVersion: VersionTLS12,
+ },
+ },
+ renegotiate: 1,
+ flags: []string{
+ "-renegotiate-freely",
+ "-expect-total-renegotiations", "1",
+ },
+ shouldFail: true,
+ expectedError: ":WRONG_SSL_VERSION:",
+ })
+
+ testCases = append(testCases, testCase{
+ name: "Renegotiate-SameClientVersion",
+ renegotiate: 1,
+ config: Config{
+ MaxVersion: VersionTLS10,
+ Bugs: ProtocolBugs{
+ RequireSameRenegoClientVersion: true,
+ },
+ },
+ flags: []string{
+ "-renegotiate-freely",
+ "-expect-total-renegotiations", "1",
+ },
+ })
+ testCases = append(testCases, testCase{
+ name: "Renegotiate-FalseStart",
+ renegotiate: 1,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ NextProtos: []string{"foo"},
+ },
+ flags: []string{
+ "-false-start",
+ "-select-next-proto", "foo",
+ "-renegotiate-freely",
+ "-expect-total-renegotiations", "1",
+ },
+ shimWritesFirst: true,
+ })
+
+ // Client-side renegotiation controls.
+ testCases = append(testCases, testCase{
+ name: "Renegotiate-Client-Forbidden-1",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ },
+ renegotiate: 1,
+ shouldFail: true,
+ expectedError: ":NO_RENEGOTIATION:",
+ expectedLocalError: "remote error: no renegotiation",
+ })
+ testCases = append(testCases, testCase{
+ name: "Renegotiate-Client-Once-1",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ },
+ renegotiate: 1,
+ flags: []string{
+ "-renegotiate-once",
+ "-expect-total-renegotiations", "1",
+ },
+ })
+ testCases = append(testCases, testCase{
+ name: "Renegotiate-Client-Freely-1",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ },
+ renegotiate: 1,
+ flags: []string{
+ "-renegotiate-freely",
+ "-expect-total-renegotiations", "1",
+ },
+ })
+ testCases = append(testCases, testCase{
+ name: "Renegotiate-Client-Once-2",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ },
+ renegotiate: 2,
+ flags: []string{"-renegotiate-once"},
+ shouldFail: true,
+ expectedError: ":NO_RENEGOTIATION:",
+ expectedLocalError: "remote error: no renegotiation",
+ })
+ testCases = append(testCases, testCase{
+ name: "Renegotiate-Client-Freely-2",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ },
+ renegotiate: 2,
+ flags: []string{
+ "-renegotiate-freely",
+ "-expect-total-renegotiations", "2",
+ },
+ })
+ testCases = append(testCases, testCase{
+ name: "Renegotiate-Client-NoIgnore",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ SendHelloRequestBeforeEveryAppDataRecord: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":NO_RENEGOTIATION:",
+ })
+ testCases = append(testCases, testCase{
+ name: "Renegotiate-Client-Ignore",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ SendHelloRequestBeforeEveryAppDataRecord: true,
+ },
+ },
+ flags: []string{
+ "-renegotiate-ignore",
+ "-expect-total-renegotiations", "0",
+ },
+ })
+
+ // Renegotiation is not allowed at SSL 3.0.
+ testCases = append(testCases, testCase{
+ name: "Renegotiate-Client-SSL3",
+ config: Config{
+ MaxVersion: VersionSSL30,
+ },
+ renegotiate: 1,
+ flags: []string{
+ "-renegotiate-freely",
+ "-expect-total-renegotiations", "1",
+ },
+ shouldFail: true,
+ expectedError: ":NO_RENEGOTIATION:",
+ expectedLocalError: "remote error: no renegotiation",
+ })
+
+ // Renegotiation is not allowed when there is an unfinished write.
+ testCases = append(testCases, testCase{
+ name: "Renegotiate-Client-UnfinishedWrite",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ },
+ renegotiate: 1,
+ flags: []string{
+ "-async",
+ "-renegotiate-freely",
+ "-read-with-unfinished-write",
+ },
+ shouldFail: true,
+ expectedError: ":NO_RENEGOTIATION:",
+ // We do not successfully send the no_renegotiation alert in
+ // this case. https://crbug.com/boringssl/130
+ })
+
+ // We reject stray HelloRequests during the handshake in TLS 1.2.
+ testCases = append(testCases, testCase{
+ name: "StrayHelloRequest",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ SendHelloRequestBeforeEveryHandshakeMessage: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_MESSAGE:",
+ })
+ testCases = append(testCases, testCase{
+ name: "StrayHelloRequest-Packed",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ PackHandshakeFlight: true,
+ SendHelloRequestBeforeEveryHandshakeMessage: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_MESSAGE:",
+ })
+
+ // Test renegotiation works if HelloRequest and server Finished come in
+ // the same record.
+ testCases = append(testCases, testCase{
+ name: "Renegotiate-Client-Packed",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ PackHandshakeFlight: true,
+ PackHelloRequestWithFinished: true,
+ },
+ },
+ renegotiate: 1,
+ flags: []string{
+ "-renegotiate-freely",
+ "-expect-total-renegotiations", "1",
+ },
+ })
+
+ // Renegotiation is forbidden in TLS 1.3.
+ testCases = append(testCases, testCase{
+ name: "Renegotiate-Client-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendHelloRequestBeforeEveryAppDataRecord: true,
+ },
+ },
+ flags: []string{
+ "-renegotiate-freely",
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_MESSAGE:",
+ })
+
+ // Stray HelloRequests during the handshake are forbidden in TLS 1.3.
+ testCases = append(testCases, testCase{
+ name: "StrayHelloRequest-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendHelloRequestBeforeEveryHandshakeMessage: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_MESSAGE:",
+ })
+
+ // The renegotiation_info extension is not sent in TLS 1.3, but TLS 1.3
+ // always reads as supporting it, regardless of whether it was
+ // negotiated.
+ testCases = append(testCases, testCase{
+ name: "AlwaysReportRenegotiationInfo-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ NoRenegotiationInfo: true,
+ },
+ },
+ flags: []string{
+ "-expect-secure-renegotiation",
+ },
+ })
+
+ // Certificates may not change on renegotiation.
+ testCases = append(testCases, testCase{
+ name: "Renegotiation-CertificateChange",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Certificates: []Certificate{rsaCertificate},
+ Bugs: ProtocolBugs{
+ RenegotiationCertificate: &rsaChainCertificate,
+ },
+ },
+ renegotiate: 1,
+ flags: []string{"-renegotiate-freely"},
+ shouldFail: true,
+ expectedError: ":SERVER_CERT_CHANGED:",
+ })
+ testCases = append(testCases, testCase{
+ name: "Renegotiation-CertificateChange-2",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Certificates: []Certificate{rsaCertificate},
+ Bugs: ProtocolBugs{
+ RenegotiationCertificate: &rsa1024Certificate,
+ },
+ },
+ renegotiate: 1,
+ flags: []string{"-renegotiate-freely"},
+ shouldFail: true,
+ expectedError: ":SERVER_CERT_CHANGED:",
+ })
+}
+
+func addDTLSReplayTests() {
+ // Test that sequence number replays are detected.
+ testCases = append(testCases, testCase{
+ protocol: dtls,
+ name: "DTLS-Replay",
+ messageCount: 200,
+ replayWrites: true,
+ })
+
+ // Test the incoming sequence number skipping by values larger
+ // than the retransmit window.
+ testCases = append(testCases, testCase{
+ protocol: dtls,
+ name: "DTLS-Replay-LargeGaps",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SequenceNumberMapping: func(in uint64) uint64 {
+ return in * 127
+ },
+ },
+ },
+ messageCount: 200,
+ replayWrites: true,
+ })
+
+ // Test the incoming sequence number changing non-monotonically.
+ testCases = append(testCases, testCase{
+ protocol: dtls,
+ name: "DTLS-Replay-NonMonotonic",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SequenceNumberMapping: func(in uint64) uint64 {
+ return in ^ 31
+ },
+ },
+ },
+ messageCount: 200,
+ replayWrites: true,
+ })
+}
+
+var testSignatureAlgorithms = []struct {
+ name string
+ id signatureAlgorithm
+ cert testCert
+}{
+ {"RSA-PKCS1-SHA1", signatureRSAPKCS1WithSHA1, testCertRSA},
+ {"RSA-PKCS1-SHA256", signatureRSAPKCS1WithSHA256, testCertRSA},
+ {"RSA-PKCS1-SHA384", signatureRSAPKCS1WithSHA384, testCertRSA},
+ {"RSA-PKCS1-SHA512", signatureRSAPKCS1WithSHA512, testCertRSA},
+ {"ECDSA-SHA1", signatureECDSAWithSHA1, testCertECDSAP256},
+ {"ECDSA-P256-SHA256", signatureECDSAWithP256AndSHA256, testCertECDSAP256},
+ {"ECDSA-P384-SHA384", signatureECDSAWithP384AndSHA384, testCertECDSAP384},
+ {"ECDSA-P521-SHA512", signatureECDSAWithP521AndSHA512, testCertECDSAP521},
+ {"RSA-PSS-SHA256", signatureRSAPSSWithSHA256, testCertRSA},
+ {"RSA-PSS-SHA384", signatureRSAPSSWithSHA384, testCertRSA},
+ {"RSA-PSS-SHA512", signatureRSAPSSWithSHA512, testCertRSA},
+ // Tests for key types prior to TLS 1.2.
+ {"RSA", 0, testCertRSA},
+ {"ECDSA", 0, testCertECDSAP256},
+}
+
+const fakeSigAlg1 signatureAlgorithm = 0x2a01
+const fakeSigAlg2 signatureAlgorithm = 0xff01
+
+func addSignatureAlgorithmTests() {
+ // Not all ciphers involve a signature. Advertise a list which gives all
+ // versions a signing cipher.
+ signingCiphers := []uint16{
+ TLS_AES_128_GCM_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
+ }
+
+ var allAlgorithms []signatureAlgorithm
+ for _, alg := range testSignatureAlgorithms {
+ if alg.id != 0 {
+ allAlgorithms = append(allAlgorithms, alg.id)
+ }
+ }
+
+ // Make sure each signature algorithm works. Include some fake values in
+ // the list and ensure they're ignored.
+ for _, alg := range testSignatureAlgorithms {
+ for _, ver := range tlsVersions {
+ if (ver.version < VersionTLS12) != (alg.id == 0) {
+ continue
+ }
+
+ // TODO(davidben): Support ECDSA in SSL 3.0 in Go for testing
+ // or remove it in C.
+ if ver.version == VersionSSL30 && alg.cert != testCertRSA {
+ continue
+ }
+
+ var shouldSignFail, shouldVerifyFail bool
+ // ecdsa_sha1 does not exist in TLS 1.3.
+ if ver.version >= VersionTLS13 && alg.id == signatureECDSAWithSHA1 {
+ shouldSignFail = true
+ shouldVerifyFail = true
+ }
+ // RSA-PKCS1 does not exist in TLS 1.3.
+ if ver.version == VersionTLS13 && hasComponent(alg.name, "PKCS1") {
+ shouldSignFail = true
+ shouldVerifyFail = true
+ }
+
+ // BoringSSL will sign SHA-1 and SHA-512 with ECDSA but not accept them.
+ if alg.id == signatureECDSAWithSHA1 || alg.id == signatureECDSAWithP521AndSHA512 {
+ shouldVerifyFail = true
+ }
+
+ var signError, verifyError string
+ if shouldSignFail {
+ signError = ":NO_COMMON_SIGNATURE_ALGORITHMS:"
+ }
+ if shouldVerifyFail {
+ verifyError = ":WRONG_SIGNATURE_TYPE:"
+ }
+
+ suffix := "-" + alg.name + "-" + ver.name
+
+ testCases = append(testCases, testCase{
+ name: "ClientAuth-Sign" + suffix,
+ config: Config{
+ MaxVersion: ver.version,
+ ClientAuth: RequireAnyClientCert,
+ VerifySignatureAlgorithms: []signatureAlgorithm{
+ fakeSigAlg1,
+ alg.id,
+ fakeSigAlg2,
+ },
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, getShimCertificate(alg.cert)),
+ "-key-file", path.Join(*resourceDir, getShimKey(alg.cert)),
+ "-enable-all-curves",
+ },
+ shouldFail: shouldSignFail,
+ expectedError: signError,
+ expectedPeerSignatureAlgorithm: alg.id,
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "ClientAuth-Verify" + suffix,
+ config: Config{
+ MaxVersion: ver.version,
+ Certificates: []Certificate{getRunnerCertificate(alg.cert)},
+ SignSignatureAlgorithms: []signatureAlgorithm{
+ alg.id,
+ },
+ Bugs: ProtocolBugs{
+ SkipECDSACurveCheck: shouldVerifyFail,
+ IgnoreSignatureVersionChecks: shouldVerifyFail,
+ // Some signature algorithms may not be advertised.
+ IgnorePeerSignatureAlgorithmPreferences: shouldVerifyFail,
+ },
+ },
+ flags: []string{
+ "-require-any-client-certificate",
+ "-expect-peer-signature-algorithm", strconv.Itoa(int(alg.id)),
+ "-enable-all-curves",
+ },
+ // Resume the session to assert the peer signature
+ // algorithm is reported on both handshakes.
+ resumeSession: !shouldVerifyFail,
+ shouldFail: shouldVerifyFail,
+ expectedError: verifyError,
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "ServerAuth-Sign" + suffix,
+ config: Config{
+ MaxVersion: ver.version,
+ CipherSuites: signingCiphers,
+ VerifySignatureAlgorithms: []signatureAlgorithm{
+ fakeSigAlg1,
+ alg.id,
+ fakeSigAlg2,
+ },
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, getShimCertificate(alg.cert)),
+ "-key-file", path.Join(*resourceDir, getShimKey(alg.cert)),
+ "-enable-all-curves",
+ },
+ shouldFail: shouldSignFail,
+ expectedError: signError,
+ expectedPeerSignatureAlgorithm: alg.id,
+ })
+
+ testCases = append(testCases, testCase{
+ name: "ServerAuth-Verify" + suffix,
+ config: Config{
+ MaxVersion: ver.version,
+ Certificates: []Certificate{getRunnerCertificate(alg.cert)},
+ CipherSuites: signingCiphers,
+ SignSignatureAlgorithms: []signatureAlgorithm{
+ alg.id,
+ },
+ Bugs: ProtocolBugs{
+ SkipECDSACurveCheck: shouldVerifyFail,
+ IgnoreSignatureVersionChecks: shouldVerifyFail,
+ // Some signature algorithms may not be advertised.
+ IgnorePeerSignatureAlgorithmPreferences: shouldVerifyFail,
+ },
+ },
+ flags: []string{
+ "-expect-peer-signature-algorithm", strconv.Itoa(int(alg.id)),
+ "-enable-all-curves",
+ },
+ // Resume the session to assert the peer signature
+ // algorithm is reported on both handshakes.
+ resumeSession: !shouldVerifyFail,
+ shouldFail: shouldVerifyFail,
+ expectedError: verifyError,
+ })
+
+ if !shouldVerifyFail {
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "ClientAuth-InvalidSignature" + suffix,
+ config: Config{
+ MaxVersion: ver.version,
+ Certificates: []Certificate{getRunnerCertificate(alg.cert)},
+ SignSignatureAlgorithms: []signatureAlgorithm{
+ alg.id,
+ },
+ Bugs: ProtocolBugs{
+ InvalidSignature: true,
+ },
+ },
+ flags: []string{
+ "-require-any-client-certificate",
+ "-enable-all-curves",
+ },
+ shouldFail: true,
+ expectedError: ":BAD_SIGNATURE:",
+ })
+
+ testCases = append(testCases, testCase{
+ name: "ServerAuth-InvalidSignature" + suffix,
+ config: Config{
+ MaxVersion: ver.version,
+ Certificates: []Certificate{getRunnerCertificate(alg.cert)},
+ CipherSuites: signingCiphers,
+ SignSignatureAlgorithms: []signatureAlgorithm{
+ alg.id,
+ },
+ Bugs: ProtocolBugs{
+ InvalidSignature: true,
+ },
+ },
+ flags: []string{"-enable-all-curves"},
+ shouldFail: true,
+ expectedError: ":BAD_SIGNATURE:",
+ })
+ }
+
+ if ver.version >= VersionTLS12 && !shouldSignFail {
+ testCases = append(testCases, testCase{
+ name: "ClientAuth-Sign-Negotiate" + suffix,
+ config: Config{
+ MaxVersion: ver.version,
+ ClientAuth: RequireAnyClientCert,
+ VerifySignatureAlgorithms: allAlgorithms,
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, getShimCertificate(alg.cert)),
+ "-key-file", path.Join(*resourceDir, getShimKey(alg.cert)),
+ "-enable-all-curves",
+ "-signing-prefs", strconv.Itoa(int(alg.id)),
+ },
+ expectedPeerSignatureAlgorithm: alg.id,
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "ServerAuth-Sign-Negotiate" + suffix,
+ config: Config{
+ MaxVersion: ver.version,
+ CipherSuites: signingCiphers,
+ VerifySignatureAlgorithms: allAlgorithms,
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, getShimCertificate(alg.cert)),
+ "-key-file", path.Join(*resourceDir, getShimKey(alg.cert)),
+ "-enable-all-curves",
+ "-signing-prefs", strconv.Itoa(int(alg.id)),
+ },
+ expectedPeerSignatureAlgorithm: alg.id,
+ })
+ }
+ }
+ }
+
+ // Test that algorithm selection takes the key type into account.
+ testCases = append(testCases, testCase{
+ name: "ClientAuth-SignatureType",
+ config: Config{
+ ClientAuth: RequireAnyClientCert,
+ MaxVersion: VersionTLS12,
+ VerifySignatureAlgorithms: []signatureAlgorithm{
+ signatureECDSAWithP521AndSHA512,
+ signatureRSAPKCS1WithSHA384,
+ signatureECDSAWithSHA1,
+ },
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaKeyFile),
+ },
+ expectedPeerSignatureAlgorithm: signatureRSAPKCS1WithSHA384,
+ })
+
+ testCases = append(testCases, testCase{
+ name: "ClientAuth-SignatureType-TLS13",
+ config: Config{
+ ClientAuth: RequireAnyClientCert,
+ MaxVersion: VersionTLS13,
+ VerifySignatureAlgorithms: []signatureAlgorithm{
+ signatureECDSAWithP521AndSHA512,
+ signatureRSAPKCS1WithSHA384,
+ signatureRSAPSSWithSHA384,
+ signatureECDSAWithSHA1,
+ },
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaKeyFile),
+ },
+ expectedPeerSignatureAlgorithm: signatureRSAPSSWithSHA384,
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "ServerAuth-SignatureType",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ VerifySignatureAlgorithms: []signatureAlgorithm{
+ signatureECDSAWithP521AndSHA512,
+ signatureRSAPKCS1WithSHA384,
+ signatureECDSAWithSHA1,
+ },
+ },
+ expectedPeerSignatureAlgorithm: signatureRSAPKCS1WithSHA384,
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "ServerAuth-SignatureType-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ VerifySignatureAlgorithms: []signatureAlgorithm{
+ signatureECDSAWithP521AndSHA512,
+ signatureRSAPKCS1WithSHA384,
+ signatureRSAPSSWithSHA384,
+ signatureECDSAWithSHA1,
+ },
+ },
+ expectedPeerSignatureAlgorithm: signatureRSAPSSWithSHA384,
+ })
+
+ // Test that signature verification takes the key type into account.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "Verify-ClientAuth-SignatureType",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Certificates: []Certificate{rsaCertificate},
+ SignSignatureAlgorithms: []signatureAlgorithm{
+ signatureRSAPKCS1WithSHA256,
+ },
+ Bugs: ProtocolBugs{
+ SendSignatureAlgorithm: signatureECDSAWithP256AndSHA256,
+ },
+ },
+ flags: []string{
+ "-require-any-client-certificate",
+ },
+ shouldFail: true,
+ expectedError: ":WRONG_SIGNATURE_TYPE:",
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "Verify-ClientAuth-SignatureType-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Certificates: []Certificate{rsaCertificate},
+ SignSignatureAlgorithms: []signatureAlgorithm{
+ signatureRSAPSSWithSHA256,
+ },
+ Bugs: ProtocolBugs{
+ SendSignatureAlgorithm: signatureECDSAWithP256AndSHA256,
+ },
+ },
+ flags: []string{
+ "-require-any-client-certificate",
+ },
+ shouldFail: true,
+ expectedError: ":WRONG_SIGNATURE_TYPE:",
+ })
+
+ testCases = append(testCases, testCase{
+ name: "Verify-ServerAuth-SignatureType",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ SignSignatureAlgorithms: []signatureAlgorithm{
+ signatureRSAPKCS1WithSHA256,
+ },
+ Bugs: ProtocolBugs{
+ SendSignatureAlgorithm: signatureECDSAWithP256AndSHA256,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":WRONG_SIGNATURE_TYPE:",
+ })
+
+ testCases = append(testCases, testCase{
+ name: "Verify-ServerAuth-SignatureType-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ SignSignatureAlgorithms: []signatureAlgorithm{
+ signatureRSAPSSWithSHA256,
+ },
+ Bugs: ProtocolBugs{
+ SendSignatureAlgorithm: signatureECDSAWithP256AndSHA256,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":WRONG_SIGNATURE_TYPE:",
+ })
+
+ // Test that, if the list is missing, the peer falls back to SHA-1 in
+ // TLS 1.2, but not TLS 1.3.
+ testCases = append(testCases, testCase{
+ name: "ClientAuth-SHA1-Fallback-RSA",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ ClientAuth: RequireAnyClientCert,
+ VerifySignatureAlgorithms: []signatureAlgorithm{
+ signatureRSAPKCS1WithSHA1,
+ },
+ Bugs: ProtocolBugs{
+ NoSignatureAlgorithms: true,
+ },
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaKeyFile),
+ },
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "ServerAuth-SHA1-Fallback-RSA",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ VerifySignatureAlgorithms: []signatureAlgorithm{
+ signatureRSAPKCS1WithSHA1,
+ },
+ Bugs: ProtocolBugs{
+ NoSignatureAlgorithms: true,
+ },
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaKeyFile),
+ },
+ })
+
+ testCases = append(testCases, testCase{
+ name: "ClientAuth-SHA1-Fallback-ECDSA",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ ClientAuth: RequireAnyClientCert,
+ VerifySignatureAlgorithms: []signatureAlgorithm{
+ signatureECDSAWithSHA1,
+ },
+ Bugs: ProtocolBugs{
+ NoSignatureAlgorithms: true,
+ },
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, ecdsaP256CertificateFile),
+ "-key-file", path.Join(*resourceDir, ecdsaP256KeyFile),
+ },
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "ServerAuth-SHA1-Fallback-ECDSA",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ VerifySignatureAlgorithms: []signatureAlgorithm{
+ signatureECDSAWithSHA1,
+ },
+ Bugs: ProtocolBugs{
+ NoSignatureAlgorithms: true,
+ },
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, ecdsaP256CertificateFile),
+ "-key-file", path.Join(*resourceDir, ecdsaP256KeyFile),
+ },
+ })
+
+ testCases = append(testCases, testCase{
+ name: "ClientAuth-NoFallback-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ ClientAuth: RequireAnyClientCert,
+ VerifySignatureAlgorithms: []signatureAlgorithm{
+ signatureRSAPKCS1WithSHA1,
+ },
+ Bugs: ProtocolBugs{
+ NoSignatureAlgorithms: true,
+ },
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaKeyFile),
+ },
+ shouldFail: true,
+ // An empty CertificateRequest signature algorithm list is a
+ // syntax error in TLS 1.3.
+ expectedError: ":DECODE_ERROR:",
+ expectedLocalError: "remote error: error decoding message",
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "ServerAuth-NoFallback-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ VerifySignatureAlgorithms: []signatureAlgorithm{
+ signatureRSAPKCS1WithSHA1,
+ },
+ Bugs: ProtocolBugs{
+ NoSignatureAlgorithms: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":NO_COMMON_SIGNATURE_ALGORITHMS:",
+ })
+
+ // Test that hash preferences are enforced. BoringSSL does not implement
+ // MD5 signatures.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "ClientAuth-Enforced",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Certificates: []Certificate{rsaCertificate},
+ SignSignatureAlgorithms: []signatureAlgorithm{
+ signatureRSAPKCS1WithMD5,
+ },
+ Bugs: ProtocolBugs{
+ IgnorePeerSignatureAlgorithmPreferences: true,
+ },
+ },
+ flags: []string{"-require-any-client-certificate"},
+ shouldFail: true,
+ expectedError: ":WRONG_SIGNATURE_TYPE:",
+ })
+
+ testCases = append(testCases, testCase{
+ name: "ServerAuth-Enforced",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ SignSignatureAlgorithms: []signatureAlgorithm{
+ signatureRSAPKCS1WithMD5,
+ },
+ Bugs: ProtocolBugs{
+ IgnorePeerSignatureAlgorithmPreferences: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":WRONG_SIGNATURE_TYPE:",
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "ClientAuth-Enforced-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Certificates: []Certificate{rsaCertificate},
+ SignSignatureAlgorithms: []signatureAlgorithm{
+ signatureRSAPKCS1WithMD5,
+ },
+ Bugs: ProtocolBugs{
+ IgnorePeerSignatureAlgorithmPreferences: true,
+ IgnoreSignatureVersionChecks: true,
+ },
+ },
+ flags: []string{"-require-any-client-certificate"},
+ shouldFail: true,
+ expectedError: ":WRONG_SIGNATURE_TYPE:",
+ })
+
+ testCases = append(testCases, testCase{
+ name: "ServerAuth-Enforced-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ SignSignatureAlgorithms: []signatureAlgorithm{
+ signatureRSAPKCS1WithMD5,
+ },
+ Bugs: ProtocolBugs{
+ IgnorePeerSignatureAlgorithmPreferences: true,
+ IgnoreSignatureVersionChecks: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":WRONG_SIGNATURE_TYPE:",
+ })
+
+ // Test that the agreed upon digest respects the client preferences and
+ // the server digests.
+ testCases = append(testCases, testCase{
+ name: "NoCommonAlgorithms-Digests",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ ClientAuth: RequireAnyClientCert,
+ VerifySignatureAlgorithms: []signatureAlgorithm{
+ signatureRSAPKCS1WithSHA512,
+ signatureRSAPKCS1WithSHA1,
+ },
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaKeyFile),
+ "-digest-prefs", "SHA256",
+ },
+ shouldFail: true,
+ expectedError: ":NO_COMMON_SIGNATURE_ALGORITHMS:",
+ })
+ testCases = append(testCases, testCase{
+ name: "NoCommonAlgorithms",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ ClientAuth: RequireAnyClientCert,
+ VerifySignatureAlgorithms: []signatureAlgorithm{
+ signatureRSAPKCS1WithSHA512,
+ signatureRSAPKCS1WithSHA1,
+ },
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaKeyFile),
+ "-signing-prefs", strconv.Itoa(int(signatureRSAPKCS1WithSHA256)),
+ },
+ shouldFail: true,
+ expectedError: ":NO_COMMON_SIGNATURE_ALGORITHMS:",
+ })
+ testCases = append(testCases, testCase{
+ name: "NoCommonAlgorithms-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ ClientAuth: RequireAnyClientCert,
+ VerifySignatureAlgorithms: []signatureAlgorithm{
+ signatureRSAPSSWithSHA512,
+ signatureRSAPSSWithSHA384,
+ },
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaKeyFile),
+ "-signing-prefs", strconv.Itoa(int(signatureRSAPSSWithSHA256)),
+ },
+ shouldFail: true,
+ expectedError: ":NO_COMMON_SIGNATURE_ALGORITHMS:",
+ })
+ testCases = append(testCases, testCase{
+ name: "Agree-Digest-SHA256",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ ClientAuth: RequireAnyClientCert,
+ VerifySignatureAlgorithms: []signatureAlgorithm{
+ signatureRSAPKCS1WithSHA1,
+ signatureRSAPKCS1WithSHA256,
+ },
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaKeyFile),
+ "-digest-prefs", "SHA256,SHA1",
+ },
+ expectedPeerSignatureAlgorithm: signatureRSAPKCS1WithSHA256,
+ })
+ testCases = append(testCases, testCase{
+ name: "Agree-Digest-SHA1",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ ClientAuth: RequireAnyClientCert,
+ VerifySignatureAlgorithms: []signatureAlgorithm{
+ signatureRSAPKCS1WithSHA1,
+ },
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaKeyFile),
+ "-digest-prefs", "SHA512,SHA256,SHA1",
+ },
+ expectedPeerSignatureAlgorithm: signatureRSAPKCS1WithSHA1,
+ })
+ testCases = append(testCases, testCase{
+ name: "Agree-Digest-Default",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ ClientAuth: RequireAnyClientCert,
+ VerifySignatureAlgorithms: []signatureAlgorithm{
+ signatureRSAPKCS1WithSHA256,
+ signatureECDSAWithP256AndSHA256,
+ signatureRSAPKCS1WithSHA1,
+ signatureECDSAWithSHA1,
+ },
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaKeyFile),
+ },
+ expectedPeerSignatureAlgorithm: signatureRSAPKCS1WithSHA256,
+ })
+
+ // Test that the signing preference list may include extra algorithms
+ // without negotiation problems.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "FilterExtraAlgorithms",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ VerifySignatureAlgorithms: []signatureAlgorithm{
+ signatureRSAPKCS1WithSHA256,
+ },
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaKeyFile),
+ "-signing-prefs", strconv.Itoa(int(fakeSigAlg1)),
+ "-signing-prefs", strconv.Itoa(int(signatureECDSAWithP256AndSHA256)),
+ "-signing-prefs", strconv.Itoa(int(signatureRSAPKCS1WithSHA256)),
+ "-signing-prefs", strconv.Itoa(int(fakeSigAlg2)),
+ },
+ expectedPeerSignatureAlgorithm: signatureRSAPKCS1WithSHA256,
+ })
+
+ // In TLS 1.2 and below, ECDSA uses the curve list rather than the
+ // signature algorithms.
+ testCases = append(testCases, testCase{
+ name: "CheckLeafCurve",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
+ Certificates: []Certificate{ecdsaP256Certificate},
+ },
+ flags: []string{"-p384-only"},
+ shouldFail: true,
+ expectedError: ":BAD_ECC_CERT:",
+ })
+
+ // In TLS 1.3, ECDSA does not use the ECDHE curve list.
+ testCases = append(testCases, testCase{
+ name: "CheckLeafCurve-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Certificates: []Certificate{ecdsaP256Certificate},
+ },
+ flags: []string{"-p384-only"},
+ })
+
+ // In TLS 1.2, the ECDSA curve is not in the signature algorithm.
+ testCases = append(testCases, testCase{
+ name: "ECDSACurveMismatch-Verify-TLS12",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
+ Certificates: []Certificate{ecdsaP256Certificate},
+ SignSignatureAlgorithms: []signatureAlgorithm{
+ signatureECDSAWithP384AndSHA384,
+ },
+ },
+ })
+
+ // In TLS 1.3, the ECDSA curve comes from the signature algorithm.
+ testCases = append(testCases, testCase{
+ name: "ECDSACurveMismatch-Verify-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Certificates: []Certificate{ecdsaP256Certificate},
+ SignSignatureAlgorithms: []signatureAlgorithm{
+ signatureECDSAWithP384AndSHA384,
+ },
+ Bugs: ProtocolBugs{
+ SkipECDSACurveCheck: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":WRONG_SIGNATURE_TYPE:",
+ })
+
+ // Signature algorithm selection in TLS 1.3 should take the curve into
+ // account.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "ECDSACurveMismatch-Sign-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ VerifySignatureAlgorithms: []signatureAlgorithm{
+ signatureECDSAWithP384AndSHA384,
+ signatureECDSAWithP256AndSHA256,
+ },
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, ecdsaP256CertificateFile),
+ "-key-file", path.Join(*resourceDir, ecdsaP256KeyFile),
+ },
+ expectedPeerSignatureAlgorithm: signatureECDSAWithP256AndSHA256,
+ })
+
+ // RSASSA-PSS with SHA-512 is too large for 1024-bit RSA. Test that the
+ // server does not attempt to sign in that case.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "RSA-PSS-Large",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ VerifySignatureAlgorithms: []signatureAlgorithm{
+ signatureRSAPSSWithSHA512,
+ },
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, rsa1024CertificateFile),
+ "-key-file", path.Join(*resourceDir, rsa1024KeyFile),
+ },
+ shouldFail: true,
+ expectedError: ":NO_COMMON_SIGNATURE_ALGORITHMS:",
+ })
+
+ // Test that RSA-PSS is enabled by default for TLS 1.2.
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "RSA-PSS-Default-Verify",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ SignSignatureAlgorithms: []signatureAlgorithm{
+ signatureRSAPSSWithSHA256,
+ },
+ },
+ flags: []string{"-max-version", strconv.Itoa(VersionTLS12)},
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "RSA-PSS-Default-Sign",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ VerifySignatureAlgorithms: []signatureAlgorithm{
+ signatureRSAPSSWithSHA256,
+ },
+ },
+ flags: []string{"-max-version", strconv.Itoa(VersionTLS12)},
+ })
+
+ // A server certificate with a P-224 key will only work up to TLS 1.2
+ // and we only test it with BoringSSL acting as a server because that's
+ // all Alphabet requires with it.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "P224-Server",
+ config: Config{
+ VerifySignatureAlgorithms: []signatureAlgorithm{
+ // TLS 1.2 does not require that the curve
+ // match the hash, thus P-256 with SHA-256 is
+ // the same signature algorithm value as P-224
+ // with SHA-256.
+ signatureECDSAWithP256AndSHA256,
+ },
+ // P-256 must be offered as well because ECDHE requires
+ // it.
+ CurvePreferences: []CurveID{CurveP224, CurveP256},
+ },
+ flags: []string{
+ "-max-version", strconv.Itoa(VersionTLS12),
+ "-cert-file", path.Join(*resourceDir, ecdsaP224CertificateFile),
+ "-key-file", path.Join(*resourceDir, ecdsaP224KeyFile),
+ },
+ })
+}
+
+// timeouts is the retransmit schedule for BoringSSL. It doubles and
+// caps at 60 seconds. On the 13th timeout, it gives up.
+var timeouts = []time.Duration{
+ 1 * time.Second,
+ 2 * time.Second,
+ 4 * time.Second,
+ 8 * time.Second,
+ 16 * time.Second,
+ 32 * time.Second,
+ 60 * time.Second,
+ 60 * time.Second,
+ 60 * time.Second,
+ 60 * time.Second,
+ 60 * time.Second,
+ 60 * time.Second,
+ 60 * time.Second,
+}
+
+// shortTimeouts is an alternate set of timeouts which would occur if the
+// initial timeout duration was set to 250ms.
+var shortTimeouts = []time.Duration{
+ 250 * time.Millisecond,
+ 500 * time.Millisecond,
+ 1 * time.Second,
+ 2 * time.Second,
+ 4 * time.Second,
+ 8 * time.Second,
+ 16 * time.Second,
+ 32 * time.Second,
+ 60 * time.Second,
+ 60 * time.Second,
+ 60 * time.Second,
+ 60 * time.Second,
+ 60 * time.Second,
+}
+
+func addDTLSRetransmitTests() {
+ // These tests work by coordinating some behavior on both the shim and
+ // the runner.
+ //
+ // TimeoutSchedule configures the runner to send a series of timeout
+ // opcodes to the shim (see packetAdaptor) immediately before reading
+ // each peer handshake flight N. The timeout opcode both simulates a
+ // timeout in the shim and acts as a synchronization point to help the
+ // runner bracket each handshake flight.
+ //
+ // We assume the shim does not read from the channel eagerly. It must
+ // first wait until it has sent flight N and is ready to receive
+ // handshake flight N+1. At this point, it will process the timeout
+ // opcode. It must then immediately respond with a timeout ACK and act
+ // as if the shim was idle for the specified amount of time.
+ //
+ // The runner then drops all packets received before the ACK and
+ // continues waiting for flight N. This ordering results in one attempt
+ // at sending flight N to be dropped. For the test to complete, the
+ // shim must send flight N again, testing that the shim implements DTLS
+ // retransmit on a timeout.
+
+ // TODO(davidben): Add DTLS 1.3 versions of these tests. There will
+ // likely be more epochs to cross and the final message's retransmit may
+ // be more complex.
+
+ // Test that this is indeed the timeout schedule. Stress all
+ // four patterns of handshake.
+ for i := 1; i < len(timeouts); i++ {
+ number := strconv.Itoa(i)
+ testCases = append(testCases, testCase{
+ protocol: dtls,
+ name: "DTLS-Retransmit-Client-" + number,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ TimeoutSchedule: timeouts[:i],
+ },
+ },
+ resumeSession: true,
+ flags: []string{"-async"},
+ })
+ testCases = append(testCases, testCase{
+ protocol: dtls,
+ testType: serverTest,
+ name: "DTLS-Retransmit-Server-" + number,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ TimeoutSchedule: timeouts[:i],
+ },
+ },
+ resumeSession: true,
+ flags: []string{"-async"},
+ })
+ }
+
+ // Test that exceeding the timeout schedule hits a read
+ // timeout.
+ testCases = append(testCases, testCase{
+ protocol: dtls,
+ name: "DTLS-Retransmit-Timeout",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ TimeoutSchedule: timeouts,
+ },
+ },
+ resumeSession: true,
+ flags: []string{"-async"},
+ shouldFail: true,
+ expectedError: ":READ_TIMEOUT_EXPIRED:",
+ })
+
+ // Test that timeout handling has a fudge factor, due to API
+ // problems.
+ testCases = append(testCases, testCase{
+ protocol: dtls,
+ name: "DTLS-Retransmit-Fudge",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ TimeoutSchedule: []time.Duration{
+ timeouts[0] - 10*time.Millisecond,
+ },
+ },
+ },
+ resumeSession: true,
+ flags: []string{"-async"},
+ })
+
+ // Test that the final Finished retransmitting isn't
+ // duplicated if the peer badly fragments everything.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ protocol: dtls,
+ name: "DTLS-Retransmit-Fragmented",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ TimeoutSchedule: []time.Duration{timeouts[0]},
+ MaxHandshakeRecordLength: 2,
+ },
+ },
+ flags: []string{"-async"},
+ })
+
+ // Test the timeout schedule when a shorter initial timeout duration is set.
+ testCases = append(testCases, testCase{
+ protocol: dtls,
+ name: "DTLS-Retransmit-Short-Client",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ TimeoutSchedule: shortTimeouts[:len(shortTimeouts)-1],
+ },
+ },
+ resumeSession: true,
+ flags: []string{
+ "-async",
+ "-initial-timeout-duration-ms", "250",
+ },
+ })
+ testCases = append(testCases, testCase{
+ protocol: dtls,
+ testType: serverTest,
+ name: "DTLS-Retransmit-Short-Server",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ TimeoutSchedule: shortTimeouts[:len(shortTimeouts)-1],
+ },
+ },
+ resumeSession: true,
+ flags: []string{
+ "-async",
+ "-initial-timeout-duration-ms", "250",
+ },
+ })
+}
+
+func addExportKeyingMaterialTests() {
+ for _, vers := range tlsVersions {
+ if vers.version == VersionSSL30 {
+ continue
+ }
+ testCases = append(testCases, testCase{
+ name: "ExportKeyingMaterial-" + vers.name,
+ config: Config{
+ MaxVersion: vers.version,
+ },
+ exportKeyingMaterial: 1024,
+ exportLabel: "label",
+ exportContext: "context",
+ useExportContext: true,
+ })
+ testCases = append(testCases, testCase{
+ name: "ExportKeyingMaterial-NoContext-" + vers.name,
+ config: Config{
+ MaxVersion: vers.version,
+ },
+ exportKeyingMaterial: 1024,
+ })
+ testCases = append(testCases, testCase{
+ name: "ExportKeyingMaterial-EmptyContext-" + vers.name,
+ config: Config{
+ MaxVersion: vers.version,
+ },
+ exportKeyingMaterial: 1024,
+ useExportContext: true,
+ })
+ testCases = append(testCases, testCase{
+ name: "ExportKeyingMaterial-Small-" + vers.name,
+ config: Config{
+ MaxVersion: vers.version,
+ },
+ exportKeyingMaterial: 1,
+ exportLabel: "label",
+ exportContext: "context",
+ useExportContext: true,
+ })
+ }
+
+ testCases = append(testCases, testCase{
+ name: "ExportKeyingMaterial-SSL3",
+ config: Config{
+ MaxVersion: VersionSSL30,
+ },
+ exportKeyingMaterial: 1024,
+ exportLabel: "label",
+ exportContext: "context",
+ useExportContext: true,
+ shouldFail: true,
+ expectedError: "failed to export keying material",
+ })
+
+ // Exporters work during a False Start.
+ testCases = append(testCases, testCase{
+ name: "ExportKeyingMaterial-FalseStart",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ NextProtos: []string{"foo"},
+ Bugs: ProtocolBugs{
+ ExpectFalseStart: true,
+ },
+ },
+ flags: []string{
+ "-false-start",
+ "-advertise-alpn", "\x03foo",
+ },
+ shimWritesFirst: true,
+ exportKeyingMaterial: 1024,
+ exportLabel: "label",
+ exportContext: "context",
+ useExportContext: true,
+ })
+
+ // Exporters do not work in the middle of a renegotiation. Test this by
+ // triggering the exporter after every SSL_read call and configuring the
+ // shim to run asynchronously.
+ testCases = append(testCases, testCase{
+ name: "ExportKeyingMaterial-Renegotiate",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ },
+ renegotiate: 1,
+ flags: []string{
+ "-async",
+ "-use-exporter-between-reads",
+ "-renegotiate-freely",
+ "-expect-total-renegotiations", "1",
+ },
+ shouldFail: true,
+ expectedError: "failed to export keying material",
+ })
+}
+
+func addTLSUniqueTests() {
+ for _, isClient := range []bool{false, true} {
+ for _, isResumption := range []bool{false, true} {
+ for _, hasEMS := range []bool{false, true} {
+ var suffix string
+ if isResumption {
+ suffix = "Resume-"
+ } else {
+ suffix = "Full-"
+ }
+
+ if hasEMS {
+ suffix += "EMS-"
+ } else {
+ suffix += "NoEMS-"
+ }
+
+ if isClient {
+ suffix += "Client"
+ } else {
+ suffix += "Server"
+ }
+
+ test := testCase{
+ name: "TLSUnique-" + suffix,
+ testTLSUnique: true,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ NoExtendedMasterSecret: !hasEMS,
+ },
+ },
+ }
+
+ if isResumption {
+ test.resumeSession = true
+ test.resumeConfig = &Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ NoExtendedMasterSecret: !hasEMS,
+ },
+ }
+ }
+
+ if isResumption && !hasEMS {
+ test.shouldFail = true
+ test.expectedError = "failed to get tls-unique"
+ }
+
+ testCases = append(testCases, test)
+ }
+ }
+ }
+}
+
+func addCustomExtensionTests() {
+ expectedContents := "custom extension"
+ emptyString := ""
+
+ for _, isClient := range []bool{false, true} {
+ suffix := "Server"
+ flag := "-enable-server-custom-extension"
+ testType := serverTest
+ if isClient {
+ suffix = "Client"
+ flag = "-enable-client-custom-extension"
+ testType = clientTest
+ }
+
+ testCases = append(testCases, testCase{
+ testType: testType,
+ name: "CustomExtensions-" + suffix,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ CustomExtension: expectedContents,
+ ExpectedCustomExtension: &expectedContents,
+ },
+ },
+ flags: []string{flag},
+ })
+ testCases = append(testCases, testCase{
+ testType: testType,
+ name: "CustomExtensions-" + suffix + "-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ CustomExtension: expectedContents,
+ ExpectedCustomExtension: &expectedContents,
+ },
+ },
+ flags: []string{flag},
+ })
+
+ // If the parse callback fails, the handshake should also fail.
+ testCases = append(testCases, testCase{
+ testType: testType,
+ name: "CustomExtensions-ParseError-" + suffix,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ CustomExtension: expectedContents + "foo",
+ ExpectedCustomExtension: &expectedContents,
+ },
+ },
+ flags: []string{flag},
+ shouldFail: true,
+ expectedError: ":CUSTOM_EXTENSION_ERROR:",
+ })
+ testCases = append(testCases, testCase{
+ testType: testType,
+ name: "CustomExtensions-ParseError-" + suffix + "-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ CustomExtension: expectedContents + "foo",
+ ExpectedCustomExtension: &expectedContents,
+ },
+ },
+ flags: []string{flag},
+ shouldFail: true,
+ expectedError: ":CUSTOM_EXTENSION_ERROR:",
+ })
+
+ // If the add callback fails, the handshake should also fail.
+ testCases = append(testCases, testCase{
+ testType: testType,
+ name: "CustomExtensions-FailAdd-" + suffix,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ CustomExtension: expectedContents,
+ ExpectedCustomExtension: &expectedContents,
+ },
+ },
+ flags: []string{flag, "-custom-extension-fail-add"},
+ shouldFail: true,
+ expectedError: ":CUSTOM_EXTENSION_ERROR:",
+ })
+ testCases = append(testCases, testCase{
+ testType: testType,
+ name: "CustomExtensions-FailAdd-" + suffix + "-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ CustomExtension: expectedContents,
+ ExpectedCustomExtension: &expectedContents,
+ },
+ },
+ flags: []string{flag, "-custom-extension-fail-add"},
+ shouldFail: true,
+ expectedError: ":CUSTOM_EXTENSION_ERROR:",
+ })
+
+ // If the add callback returns zero, no extension should be
+ // added.
+ skipCustomExtension := expectedContents
+ if isClient {
+ // For the case where the client skips sending the
+ // custom extension, the server must not “echo” it.
+ skipCustomExtension = ""
+ }
+ testCases = append(testCases, testCase{
+ testType: testType,
+ name: "CustomExtensions-Skip-" + suffix,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ CustomExtension: skipCustomExtension,
+ ExpectedCustomExtension: &emptyString,
+ },
+ },
+ flags: []string{flag, "-custom-extension-skip"},
+ })
+ testCases = append(testCases, testCase{
+ testType: testType,
+ name: "CustomExtensions-Skip-" + suffix + "-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ CustomExtension: skipCustomExtension,
+ ExpectedCustomExtension: &emptyString,
+ },
+ },
+ flags: []string{flag, "-custom-extension-skip"},
+ })
+ }
+
+ // The custom extension add callback should not be called if the client
+ // doesn't send the extension.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "CustomExtensions-NotCalled-Server",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ ExpectedCustomExtension: &emptyString,
+ },
+ },
+ flags: []string{"-enable-server-custom-extension", "-custom-extension-fail-add"},
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "CustomExtensions-NotCalled-Server-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ ExpectedCustomExtension: &emptyString,
+ },
+ },
+ flags: []string{"-enable-server-custom-extension", "-custom-extension-fail-add"},
+ })
+
+ // Test an unknown extension from the server.
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "UnknownExtension-Client",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ CustomExtension: expectedContents,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_EXTENSION:",
+ expectedLocalError: "remote error: unsupported extension",
+ })
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "UnknownExtension-Client-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ CustomExtension: expectedContents,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_EXTENSION:",
+ expectedLocalError: "remote error: unsupported extension",
+ })
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "UnknownUnencryptedExtension-Client-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ CustomUnencryptedExtension: expectedContents,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_EXTENSION:",
+ // The shim must send an alert, but alerts at this point do not
+ // get successfully decrypted by the runner.
+ expectedLocalError: "local error: bad record MAC",
+ })
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "UnexpectedUnencryptedExtension-Client-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendUnencryptedALPN: "foo",
+ },
+ },
+ flags: []string{
+ "-advertise-alpn", "\x03foo\x03bar",
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_EXTENSION:",
+ // The shim must send an alert, but alerts at this point do not
+ // get successfully decrypted by the runner.
+ expectedLocalError: "local error: bad record MAC",
+ })
+
+ // Test a known but unoffered extension from the server.
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "UnofferedExtension-Client",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ SendALPN: "alpn",
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_EXTENSION:",
+ expectedLocalError: "remote error: unsupported extension",
+ })
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "UnofferedExtension-Client-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendALPN: "alpn",
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_EXTENSION:",
+ expectedLocalError: "remote error: unsupported extension",
+ })
+}
+
+func addRSAClientKeyExchangeTests() {
+ for bad := RSABadValue(1); bad < NumRSABadValues; bad++ {
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: fmt.Sprintf("BadRSAClientKeyExchange-%d", bad),
+ config: Config{
+ // Ensure the ClientHello version and final
+ // version are different, to detect if the
+ // server uses the wrong one.
+ MaxVersion: VersionTLS11,
+ CipherSuites: []uint16{TLS_RSA_WITH_3DES_EDE_CBC_SHA},
+ Bugs: ProtocolBugs{
+ BadRSAClientKeyExchange: bad,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:",
+ })
+ }
+
+ // The server must compare whatever was in ClientHello.version for the
+ // RSA premaster.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "SendClientVersion-RSA",
+ config: Config{
+ CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
+ Bugs: ProtocolBugs{
+ SendClientVersion: 0x1234,
+ },
+ },
+ flags: []string{"-max-version", strconv.Itoa(VersionTLS12)},
+ })
+}
+
+var testCurves = []struct {
+ name string
+ id CurveID
+}{
+ {"P-256", CurveP256},
+ {"P-384", CurveP384},
+ {"P-521", CurveP521},
+ {"X25519", CurveX25519},
+}
+
+const bogusCurve = 0x1234
+
+func addCurveTests() {
+ for _, curve := range testCurves {
+ testCases = append(testCases, testCase{
+ name: "CurveTest-Client-" + curve.name,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ CurvePreferences: []CurveID{curve.id},
+ },
+ flags: []string{
+ "-enable-all-curves",
+ "-expect-curve-id", strconv.Itoa(int(curve.id)),
+ },
+ expectedCurveID: curve.id,
+ })
+ testCases = append(testCases, testCase{
+ name: "CurveTest-Client-" + curve.name + "-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ CurvePreferences: []CurveID{curve.id},
+ },
+ flags: []string{
+ "-enable-all-curves",
+ "-expect-curve-id", strconv.Itoa(int(curve.id)),
+ },
+ expectedCurveID: curve.id,
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "CurveTest-Server-" + curve.name,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ CurvePreferences: []CurveID{curve.id},
+ },
+ flags: []string{
+ "-enable-all-curves",
+ "-expect-curve-id", strconv.Itoa(int(curve.id)),
+ },
+ expectedCurveID: curve.id,
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "CurveTest-Server-" + curve.name + "-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ CurvePreferences: []CurveID{curve.id},
+ },
+ flags: []string{
+ "-enable-all-curves",
+ "-expect-curve-id", strconv.Itoa(int(curve.id)),
+ },
+ expectedCurveID: curve.id,
+ })
+ }
+
+ // The server must be tolerant to bogus curves.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "UnknownCurve",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ CurvePreferences: []CurveID{bogusCurve, CurveP256},
+ },
+ })
+
+ // The server must be tolerant to bogus curves.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "UnknownCurve-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ CurvePreferences: []CurveID{bogusCurve, CurveP256},
+ },
+ })
+
+ // The server must not consider ECDHE ciphers when there are no
+ // supported curves.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "NoSupportedCurves",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ Bugs: ProtocolBugs{
+ NoSupportedCurves: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":NO_SHARED_CIPHER:",
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "NoSupportedCurves-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ NoSupportedCurves: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":NO_SHARED_GROUP:",
+ })
+
+ // The server must fall back to another cipher when there are no
+ // supported curves.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "NoCommonCurves",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
+ },
+ CurvePreferences: []CurveID{CurveP224},
+ },
+ expectedCipher: TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
+ })
+
+ // The client must reject bogus curves and disabled curves.
+ testCases = append(testCases, testCase{
+ name: "BadECDHECurve",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ Bugs: ProtocolBugs{
+ SendCurve: bogusCurve,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":WRONG_CURVE:",
+ })
+ testCases = append(testCases, testCase{
+ name: "BadECDHECurve-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendCurve: bogusCurve,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":WRONG_CURVE:",
+ })
+
+ testCases = append(testCases, testCase{
+ name: "UnsupportedCurve",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ CurvePreferences: []CurveID{CurveP256},
+ Bugs: ProtocolBugs{
+ IgnorePeerCurvePreferences: true,
+ },
+ },
+ flags: []string{"-p384-only"},
+ shouldFail: true,
+ expectedError: ":WRONG_CURVE:",
+ })
+
+ testCases = append(testCases, testCase{
+ // TODO(davidben): Add a TLS 1.3 version where
+ // HelloRetryRequest requests an unsupported curve.
+ name: "UnsupportedCurve-ServerHello-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ CurvePreferences: []CurveID{CurveP384},
+ Bugs: ProtocolBugs{
+ SendCurve: CurveP256,
+ },
+ },
+ flags: []string{"-p384-only"},
+ shouldFail: true,
+ expectedError: ":WRONG_CURVE:",
+ })
+
+ // Test invalid curve points.
+ testCases = append(testCases, testCase{
+ name: "InvalidECDHPoint-Client",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ CurvePreferences: []CurveID{CurveP256},
+ Bugs: ProtocolBugs{
+ InvalidECDHPoint: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":INVALID_ENCODING:",
+ })
+ testCases = append(testCases, testCase{
+ name: "InvalidECDHPoint-Client-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ CurvePreferences: []CurveID{CurveP256},
+ Bugs: ProtocolBugs{
+ InvalidECDHPoint: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":INVALID_ENCODING:",
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "InvalidECDHPoint-Server",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ CurvePreferences: []CurveID{CurveP256},
+ Bugs: ProtocolBugs{
+ InvalidECDHPoint: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":INVALID_ENCODING:",
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "InvalidECDHPoint-Server-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ CurvePreferences: []CurveID{CurveP256},
+ Bugs: ProtocolBugs{
+ InvalidECDHPoint: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":INVALID_ENCODING:",
+ })
+
+ // The previous curve ID should be reported on TLS 1.2 resumption.
+ testCases = append(testCases, testCase{
+ name: "CurveID-Resume-Client",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ CurvePreferences: []CurveID{CurveX25519},
+ },
+ flags: []string{"-expect-curve-id", strconv.Itoa(int(CurveX25519))},
+ resumeSession: true,
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "CurveID-Resume-Server",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ CurvePreferences: []CurveID{CurveX25519},
+ },
+ flags: []string{"-expect-curve-id", strconv.Itoa(int(CurveX25519))},
+ resumeSession: true,
+ })
+
+ // TLS 1.3 allows resuming at a differet curve. If this happens, the new
+ // one should be reported.
+ testCases = append(testCases, testCase{
+ name: "CurveID-Resume-Client-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ CurvePreferences: []CurveID{CurveX25519},
+ },
+ resumeConfig: &Config{
+ MaxVersion: VersionTLS13,
+ CurvePreferences: []CurveID{CurveP256},
+ },
+ flags: []string{
+ "-expect-curve-id", strconv.Itoa(int(CurveX25519)),
+ "-expect-resume-curve-id", strconv.Itoa(int(CurveP256)),
+ },
+ resumeSession: true,
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "CurveID-Resume-Server-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ CurvePreferences: []CurveID{CurveX25519},
+ },
+ resumeConfig: &Config{
+ MaxVersion: VersionTLS13,
+ CurvePreferences: []CurveID{CurveP256},
+ },
+ flags: []string{
+ "-expect-curve-id", strconv.Itoa(int(CurveX25519)),
+ "-expect-resume-curve-id", strconv.Itoa(int(CurveP256)),
+ },
+ resumeSession: true,
+ })
+
+ // Server-sent point formats are legal in TLS 1.2, but not in TLS 1.3.
+ testCases = append(testCases, testCase{
+ name: "PointFormat-ServerHello-TLS12",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ SendSupportedPointFormats: []byte{pointFormatUncompressed},
+ },
+ },
+ })
+ testCases = append(testCases, testCase{
+ name: "PointFormat-EncryptedExtensions-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendSupportedPointFormats: []byte{pointFormatUncompressed},
+ },
+ },
+ shouldFail: true,
+ expectedError: ":ERROR_PARSING_EXTENSION:",
+ })
+
+ // Test that we tolerate unknown point formats, as long as
+ // pointFormatUncompressed is present. Limit ciphers to ECDHE ciphers to
+ // check they are still functional.
+ testCases = append(testCases, testCase{
+ name: "PointFormat-Client-Tolerance",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ SendSupportedPointFormats: []byte{42, pointFormatUncompressed, 99, pointFormatCompressedPrime},
+ },
+ },
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "PointFormat-Server-Tolerance",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256},
+ Bugs: ProtocolBugs{
+ SendSupportedPointFormats: []byte{42, pointFormatUncompressed, 99, pointFormatCompressedPrime},
+ },
+ },
+ })
+
+ // Test TLS 1.2 does not require the point format extension to be
+ // present.
+ testCases = append(testCases, testCase{
+ name: "PointFormat-Client-Missing",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256},
+ Bugs: ProtocolBugs{
+ SendSupportedPointFormats: []byte{},
+ },
+ },
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "PointFormat-Server-Missing",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256},
+ Bugs: ProtocolBugs{
+ SendSupportedPointFormats: []byte{},
+ },
+ },
+ })
+
+ // If the point format extension is present, uncompressed points must be
+ // offered. BoringSSL requires this whether or not ECDHE is used.
+ testCases = append(testCases, testCase{
+ name: "PointFormat-Client-MissingUncompressed",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ SendSupportedPointFormats: []byte{pointFormatCompressedPrime},
+ },
+ },
+ shouldFail: true,
+ expectedError: ":ERROR_PARSING_EXTENSION:",
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "PointFormat-Server-MissingUncompressed",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ SendSupportedPointFormats: []byte{pointFormatCompressedPrime},
+ },
+ },
+ shouldFail: true,
+ expectedError: ":ERROR_PARSING_EXTENSION:",
+ })
+}
+
+func addTLS13RecordTests() {
+ testCases = append(testCases, testCase{
+ name: "TLS13-RecordPadding",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ MinVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ RecordPadding: 10,
+ },
+ },
+ })
+
+ testCases = append(testCases, testCase{
+ name: "TLS13-EmptyRecords",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ MinVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ OmitRecordContents: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:",
+ })
+
+ testCases = append(testCases, testCase{
+ name: "TLS13-OnlyPadding",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ MinVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ OmitRecordContents: true,
+ RecordPadding: 10,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:",
+ })
+
+ testCases = append(testCases, testCase{
+ name: "TLS13-WrongOuterRecord",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ MinVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ OuterRecordType: recordTypeHandshake,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":INVALID_OUTER_RECORD_TYPE:",
+ })
+}
+
+func addSessionTicketTests() {
+ testCases = append(testCases, testCase{
+ // In TLS 1.2 and below, empty NewSessionTicket messages
+ // mean the server changed its mind on sending a ticket.
+ name: "SendEmptySessionTicket",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ SendEmptySessionTicket: true,
+ },
+ },
+ flags: []string{"-expect-no-session"},
+ })
+
+ // Test that the server ignores unknown PSK modes.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "TLS13-SendUnknownModeSessionTicket-Server",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendPSKKeyExchangeModes: []byte{0x1a, pskDHEKEMode, 0x2a},
+ },
+ },
+ resumeSession: true,
+ expectedResumeVersion: VersionTLS13,
+ })
+
+ // Test that the server does not send session tickets with no matching key exchange mode.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "TLS13-ExpectNoSessionTicketOnBadKEMode-Server",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendPSKKeyExchangeModes: []byte{0x1a},
+ ExpectNoNewSessionTicket: true,
+ },
+ },
+ })
+
+ // Test that the server does not accept a session with no matching key exchange mode.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "TLS13-SendBadKEModeSessionTicket-Server",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ },
+ resumeConfig: &Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendPSKKeyExchangeModes: []byte{0x1a},
+ },
+ },
+ resumeSession: true,
+ expectResumeRejected: true,
+ })
+
+ // Test that the client ticket age is sent correctly.
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "TLS13-TestValidTicketAge-Client",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ ExpectTicketAge: 10 * time.Second,
+ },
+ },
+ resumeSession: true,
+ flags: []string{
+ "-resumption-delay", "10",
+ },
+ })
+
+ // Test that the client ticket age is enforced.
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "TLS13-TestBadTicketAge-Client",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ ExpectTicketAge: 1000 * time.Second,
+ },
+ },
+ resumeSession: true,
+ shouldFail: true,
+ expectedLocalError: "tls: invalid ticket age",
+ })
+
+ // Test that the server's ticket age skew reporting works.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "TLS13-TicketAgeSkew-Forward",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendTicketAge: 15 * time.Second,
+ },
+ },
+ resumeSession: true,
+ flags: []string{
+ "-resumption-delay", "10",
+ "-expect-ticket-age-skew", "5",
+ },
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "TLS13-TicketAgeSkew-Backward",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendTicketAge: 5 * time.Second,
+ },
+ },
+ resumeSession: true,
+ flags: []string{
+ "-resumption-delay", "10",
+ "-expect-ticket-age-skew", "-5",
+ },
+ })
+
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "TLS13-SendTicketEarlyDataInfo",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ MaxEarlyDataSize: 16384,
+ },
+ flags: []string{
+ "-enable-early-data",
+ "-expect-early-data-info",
+ },
+ })
+
+ // Test that 0-RTT tickets are ignored in clients unless opted in.
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "TLS13-SendTicketEarlyDataInfo-Disabled",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ MaxEarlyDataSize: 16384,
+ },
+ })
+
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "TLS13-DuplicateTicketEarlyDataInfo",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ MaxEarlyDataSize: 16384,
+ Bugs: ProtocolBugs{
+ DuplicateTicketEarlyDataInfo: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":DUPLICATE_EXTENSION:",
+ expectedLocalError: "remote error: illegal parameter",
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "TLS13-ExpectTicketEarlyDataInfo",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ ExpectTicketEarlyDataInfo: true,
+ },
+ },
+ flags: []string{
+ "-enable-early-data",
+ },
+ })
+
+ // Test that, in TLS 1.3, the server-offered NewSessionTicket lifetime
+ // is honored.
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "TLS13-HonorServerSessionTicketLifetime",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendTicketLifetime: 20 * time.Second,
+ },
+ },
+ flags: []string{
+ "-resumption-delay", "19",
+ },
+ resumeSession: true,
+ })
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "TLS13-HonorServerSessionTicketLifetime-2",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendTicketLifetime: 20 * time.Second,
+ // The client should not offer the expired session.
+ ExpectNoTLS13PSK: true,
+ },
+ },
+ flags: []string{
+ "-resumption-delay", "21",
+ },
+ resumeSession: true,
+ expectResumeRejected: true,
+ })
+}
+
+func addChangeCipherSpecTests() {
+ // Test missing ChangeCipherSpecs.
+ testCases = append(testCases, testCase{
+ name: "SkipChangeCipherSpec-Client",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ SkipChangeCipherSpec: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_RECORD:",
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "SkipChangeCipherSpec-Server",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ SkipChangeCipherSpec: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_RECORD:",
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "SkipChangeCipherSpec-Server-NPN",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ NextProtos: []string{"bar"},
+ Bugs: ProtocolBugs{
+ SkipChangeCipherSpec: true,
+ },
+ },
+ flags: []string{
+ "-advertise-npn", "\x03foo\x03bar\x03baz",
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_RECORD:",
+ })
+
+ // Test synchronization between the handshake and ChangeCipherSpec.
+ // Partial post-CCS handshake messages before ChangeCipherSpec should be
+ // rejected. Test both with and without handshake packing to handle both
+ // when the partial post-CCS message is in its own record and when it is
+ // attached to the pre-CCS message.
+ for _, packed := range []bool{false, true} {
+ var suffix string
+ if packed {
+ suffix = "-Packed"
+ }
+
+ testCases = append(testCases, testCase{
+ name: "FragmentAcrossChangeCipherSpec-Client" + suffix,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ FragmentAcrossChangeCipherSpec: true,
+ PackHandshakeFlight: packed,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_RECORD:",
+ })
+ testCases = append(testCases, testCase{
+ name: "FragmentAcrossChangeCipherSpec-Client-Resume" + suffix,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ },
+ resumeSession: true,
+ resumeConfig: &Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ FragmentAcrossChangeCipherSpec: true,
+ PackHandshakeFlight: packed,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_RECORD:",
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "FragmentAcrossChangeCipherSpec-Server" + suffix,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ FragmentAcrossChangeCipherSpec: true,
+ PackHandshakeFlight: packed,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_RECORD:",
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "FragmentAcrossChangeCipherSpec-Server-Resume" + suffix,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ },
+ resumeSession: true,
+ resumeConfig: &Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ FragmentAcrossChangeCipherSpec: true,
+ PackHandshakeFlight: packed,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_RECORD:",
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "FragmentAcrossChangeCipherSpec-Server-NPN" + suffix,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ NextProtos: []string{"bar"},
+ Bugs: ProtocolBugs{
+ FragmentAcrossChangeCipherSpec: true,
+ PackHandshakeFlight: packed,
+ },
+ },
+ flags: []string{
+ "-advertise-npn", "\x03foo\x03bar\x03baz",
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_RECORD:",
+ })
+ }
+
+ // Test that, in DTLS, ChangeCipherSpec is not allowed when there are
+ // messages in the handshake queue. Do this by testing the server
+ // reading the client Finished, reversing the flight so Finished comes
+ // first.
+ testCases = append(testCases, testCase{
+ protocol: dtls,
+ testType: serverTest,
+ name: "SendUnencryptedFinished-DTLS",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ SendUnencryptedFinished: true,
+ ReverseHandshakeFragments: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":BUFFERED_MESSAGES_ON_CIPHER_CHANGE:",
+ })
+
+ // Test synchronization between encryption changes and the handshake in
+ // TLS 1.3, where ChangeCipherSpec is implicit.
+ testCases = append(testCases, testCase{
+ name: "PartialEncryptedExtensionsWithServerHello",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ PartialEncryptedExtensionsWithServerHello: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":BUFFERED_MESSAGES_ON_CIPHER_CHANGE:",
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "PartialClientFinishedWithClientHello",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ PartialClientFinishedWithClientHello: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":BUFFERED_MESSAGES_ON_CIPHER_CHANGE:",
+ })
+
+ // Test that early ChangeCipherSpecs are handled correctly.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "EarlyChangeCipherSpec-server-1",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ EarlyChangeCipherSpec: 1,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_RECORD:",
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "EarlyChangeCipherSpec-server-2",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ EarlyChangeCipherSpec: 2,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_RECORD:",
+ })
+ testCases = append(testCases, testCase{
+ protocol: dtls,
+ name: "StrayChangeCipherSpec",
+ config: Config{
+ // TODO(davidben): Once DTLS 1.3 exists, test
+ // that stray ChangeCipherSpec messages are
+ // rejected.
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ StrayChangeCipherSpec: true,
+ },
+ },
+ })
+
+ // Test that the contents of ChangeCipherSpec are checked.
+ testCases = append(testCases, testCase{
+ name: "BadChangeCipherSpec-1",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ BadChangeCipherSpec: []byte{2},
+ },
+ },
+ shouldFail: true,
+ expectedError: ":BAD_CHANGE_CIPHER_SPEC:",
+ })
+ testCases = append(testCases, testCase{
+ name: "BadChangeCipherSpec-2",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ BadChangeCipherSpec: []byte{1, 1},
+ },
+ },
+ shouldFail: true,
+ expectedError: ":BAD_CHANGE_CIPHER_SPEC:",
+ })
+ testCases = append(testCases, testCase{
+ protocol: dtls,
+ name: "BadChangeCipherSpec-DTLS-1",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ BadChangeCipherSpec: []byte{2},
+ },
+ },
+ shouldFail: true,
+ expectedError: ":BAD_CHANGE_CIPHER_SPEC:",
+ })
+ testCases = append(testCases, testCase{
+ protocol: dtls,
+ name: "BadChangeCipherSpec-DTLS-2",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ BadChangeCipherSpec: []byte{1, 1},
+ },
+ },
+ shouldFail: true,
+ expectedError: ":BAD_CHANGE_CIPHER_SPEC:",
+ })
+}
+
+type perMessageTest struct {
+ messageType uint8
+ test testCase
+}
+
+// makePerMessageTests returns a series of test templates which cover each
+// message in the TLS handshake. These may be used with bugs like
+// WrongMessageType to fully test a per-message bug.
+func makePerMessageTests() []perMessageTest {
+ var ret []perMessageTest
+ for _, protocol := range []protocol{tls, dtls} {
+ var suffix string
+ if protocol == dtls {
+ suffix = "-DTLS"
+ }
+
+ ret = append(ret, perMessageTest{
+ messageType: typeClientHello,
+ test: testCase{
+ protocol: protocol,
+ testType: serverTest,
+ name: "ClientHello" + suffix,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ },
+ },
+ })
+
+ if protocol == dtls {
+ ret = append(ret, perMessageTest{
+ messageType: typeHelloVerifyRequest,
+ test: testCase{
+ protocol: protocol,
+ name: "HelloVerifyRequest" + suffix,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ },
+ },
+ })
+ }
+
+ ret = append(ret, perMessageTest{
+ messageType: typeServerHello,
+ test: testCase{
+ protocol: protocol,
+ name: "ServerHello" + suffix,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ },
+ },
+ })
+
+ ret = append(ret, perMessageTest{
+ messageType: typeCertificate,
+ test: testCase{
+ protocol: protocol,
+ name: "ServerCertificate" + suffix,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ },
+ },
+ })
+
+ ret = append(ret, perMessageTest{
+ messageType: typeCertificateStatus,
+ test: testCase{
+ protocol: protocol,
+ name: "CertificateStatus" + suffix,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ },
+ flags: []string{"-enable-ocsp-stapling"},
+ },
+ })
+
+ ret = append(ret, perMessageTest{
+ messageType: typeServerKeyExchange,
+ test: testCase{
+ protocol: protocol,
+ name: "ServerKeyExchange" + suffix,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ },
+ },
+ })
+
+ ret = append(ret, perMessageTest{
+ messageType: typeCertificateRequest,
+ test: testCase{
+ protocol: protocol,
+ name: "CertificateRequest" + suffix,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ ClientAuth: RequireAnyClientCert,
+ },
+ },
+ })
+
+ ret = append(ret, perMessageTest{
+ messageType: typeServerHelloDone,
+ test: testCase{
+ protocol: protocol,
+ name: "ServerHelloDone" + suffix,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ },
+ },
+ })
+
+ ret = append(ret, perMessageTest{
+ messageType: typeCertificate,
+ test: testCase{
+ testType: serverTest,
+ protocol: protocol,
+ name: "ClientCertificate" + suffix,
+ config: Config{
+ Certificates: []Certificate{rsaCertificate},
+ MaxVersion: VersionTLS12,
+ },
+ flags: []string{"-require-any-client-certificate"},
+ },
+ })
+
+ ret = append(ret, perMessageTest{
+ messageType: typeCertificateVerify,
+ test: testCase{
+ testType: serverTest,
+ protocol: protocol,
+ name: "CertificateVerify" + suffix,
+ config: Config{
+ Certificates: []Certificate{rsaCertificate},
+ MaxVersion: VersionTLS12,
+ },
+ flags: []string{"-require-any-client-certificate"},
+ },
+ })
+
+ ret = append(ret, perMessageTest{
+ messageType: typeClientKeyExchange,
+ test: testCase{
+ testType: serverTest,
+ protocol: protocol,
+ name: "ClientKeyExchange" + suffix,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ },
+ },
+ })
+
+ if protocol != dtls {
+ ret = append(ret, perMessageTest{
+ messageType: typeNextProtocol,
+ test: testCase{
+ testType: serverTest,
+ protocol: protocol,
+ name: "NextProtocol" + suffix,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ NextProtos: []string{"bar"},
+ },
+ flags: []string{"-advertise-npn", "\x03foo\x03bar\x03baz"},
+ },
+ })
+
+ ret = append(ret, perMessageTest{
+ messageType: typeChannelID,
+ test: testCase{
+ testType: serverTest,
+ protocol: protocol,
+ name: "ChannelID" + suffix,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ ChannelID: channelIDKey,
+ },
+ flags: []string{
+ "-expect-channel-id",
+ base64.StdEncoding.EncodeToString(channelIDBytes),
+ },
+ },
+ })
+ }
+
+ ret = append(ret, perMessageTest{
+ messageType: typeFinished,
+ test: testCase{
+ testType: serverTest,
+ protocol: protocol,
+ name: "ClientFinished" + suffix,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ },
+ },
+ })
+
+ ret = append(ret, perMessageTest{
+ messageType: typeNewSessionTicket,
+ test: testCase{
+ protocol: protocol,
+ name: "NewSessionTicket" + suffix,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ },
+ },
+ })
+
+ ret = append(ret, perMessageTest{
+ messageType: typeFinished,
+ test: testCase{
+ protocol: protocol,
+ name: "ServerFinished" + suffix,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ },
+ },
+ })
+
+ }
+
+ ret = append(ret, perMessageTest{
+ messageType: typeClientHello,
+ test: testCase{
+ testType: serverTest,
+ name: "TLS13-ClientHello",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ },
+ },
+ })
+
+ ret = append(ret, perMessageTest{
+ messageType: typeServerHello,
+ test: testCase{
+ name: "TLS13-ServerHello",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ },
+ },
+ })
+
+ ret = append(ret, perMessageTest{
+ messageType: typeEncryptedExtensions,
+ test: testCase{
+ name: "TLS13-EncryptedExtensions",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ },
+ },
+ })
+
+ ret = append(ret, perMessageTest{
+ messageType: typeCertificateRequest,
+ test: testCase{
+ name: "TLS13-CertificateRequest",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ ClientAuth: RequireAnyClientCert,
+ },
+ },
+ })
+
+ ret = append(ret, perMessageTest{
+ messageType: typeCertificate,
+ test: testCase{
+ name: "TLS13-ServerCertificate",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ },
+ },
+ })
+
+ ret = append(ret, perMessageTest{
+ messageType: typeCertificateVerify,
+ test: testCase{
+ name: "TLS13-ServerCertificateVerify",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ },
+ },
+ })
+
+ ret = append(ret, perMessageTest{
+ messageType: typeFinished,
+ test: testCase{
+ name: "TLS13-ServerFinished",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ },
+ },
+ })
+
+ ret = append(ret, perMessageTest{
+ messageType: typeCertificate,
+ test: testCase{
+ testType: serverTest,
+ name: "TLS13-ClientCertificate",
+ config: Config{
+ Certificates: []Certificate{rsaCertificate},
+ MaxVersion: VersionTLS13,
+ },
+ flags: []string{"-require-any-client-certificate"},
+ },
+ })
+
+ ret = append(ret, perMessageTest{
+ messageType: typeCertificateVerify,
+ test: testCase{
+ testType: serverTest,
+ name: "TLS13-ClientCertificateVerify",
+ config: Config{
+ Certificates: []Certificate{rsaCertificate},
+ MaxVersion: VersionTLS13,
+ },
+ flags: []string{"-require-any-client-certificate"},
+ },
+ })
+
+ ret = append(ret, perMessageTest{
+ messageType: typeFinished,
+ test: testCase{
+ testType: serverTest,
+ name: "TLS13-ClientFinished",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ },
+ },
+ })
+
+ return ret
+}
+
+func addWrongMessageTypeTests() {
+ for _, t := range makePerMessageTests() {
+ t.test.name = "WrongMessageType-" + t.test.name
+ t.test.config.Bugs.SendWrongMessageType = t.messageType
+ t.test.shouldFail = true
+ t.test.expectedError = ":UNEXPECTED_MESSAGE:"
+ t.test.expectedLocalError = "remote error: unexpected message"
+
+ if t.test.config.MaxVersion >= VersionTLS13 && t.messageType == typeServerHello {
+ // In TLS 1.3, a bad ServerHello means the client sends
+ // an unencrypted alert while the server expects
+ // encryption, so the alert is not readable by runner.
+ t.test.expectedLocalError = "local error: bad record MAC"
+ }
+
+ testCases = append(testCases, t.test)
+ }
+}
+
+func addTrailingMessageDataTests() {
+ for _, t := range makePerMessageTests() {
+ t.test.name = "TrailingMessageData-" + t.test.name
+ t.test.config.Bugs.SendTrailingMessageData = t.messageType
+ t.test.shouldFail = true
+ t.test.expectedError = ":DECODE_ERROR:"
+ t.test.expectedLocalError = "remote error: error decoding message"
+
+ if t.test.config.MaxVersion >= VersionTLS13 && t.messageType == typeServerHello {
+ // In TLS 1.3, a bad ServerHello means the client sends
+ // an unencrypted alert while the server expects
+ // encryption, so the alert is not readable by runner.
+ t.test.expectedLocalError = "local error: bad record MAC"
+ }
+
+ if t.messageType == typeFinished {
+ // Bad Finished messages read as the verify data having
+ // the wrong length.
+ t.test.expectedError = ":DIGEST_CHECK_FAILED:"
+ t.test.expectedLocalError = "remote error: error decrypting message"
+ }
+
+ testCases = append(testCases, t.test)
+ }
+}
+
+func addTLS13HandshakeTests() {
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "NegotiatePSKResumption-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ NegotiatePSKResumption: true,
+ },
+ },
+ resumeSession: true,
+ shouldFail: true,
+ expectedError: ":MISSING_KEY_SHARE:",
+ })
+
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "MissingKeyShare-Client",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ MissingKeyShare: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":MISSING_KEY_SHARE:",
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "MissingKeyShare-Server",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ MissingKeyShare: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":MISSING_KEY_SHARE:",
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "DuplicateKeyShares",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ DuplicateKeyShares: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":DUPLICATE_KEY_SHARE:",
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "SkipEarlyData",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendFakeEarlyDataLength: 4,
+ },
+ },
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "SkipEarlyData-OmitEarlyDataExtension",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendFakeEarlyDataLength: 4,
+ OmitEarlyDataExtension: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:",
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "SkipEarlyData-TooMuchData",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendFakeEarlyDataLength: 16384 + 1,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":TOO_MUCH_SKIPPED_EARLY_DATA:",
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "SkipEarlyData-Interleaved",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendFakeEarlyDataLength: 4,
+ InterleaveEarlyData: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:",
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "SkipEarlyData-EarlyDataInTLS12",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendFakeEarlyDataLength: 4,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_RECORD:",
+ flags: []string{"-max-version", strconv.Itoa(VersionTLS12)},
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "SkipEarlyData-HRR",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendFakeEarlyDataLength: 4,
+ },
+ DefaultCurves: []CurveID{},
+ },
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "SkipEarlyData-HRR-Interleaved",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendFakeEarlyDataLength: 4,
+ InterleaveEarlyData: true,
+ },
+ DefaultCurves: []CurveID{},
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_RECORD:",
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "SkipEarlyData-HRR-TooMuchData",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendFakeEarlyDataLength: 16384 + 1,
+ },
+ DefaultCurves: []CurveID{},
+ },
+ shouldFail: true,
+ expectedError: ":TOO_MUCH_SKIPPED_EARLY_DATA:",
+ })
+
+ // Test that skipping early data looking for cleartext correctly
+ // processes an alert record.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "SkipEarlyData-HRR-FatalAlert",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendEarlyAlert: true,
+ SendFakeEarlyDataLength: 4,
+ },
+ DefaultCurves: []CurveID{},
+ },
+ shouldFail: true,
+ expectedError: ":SSLV3_ALERT_HANDSHAKE_FAILURE:",
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "SkipEarlyData-SecondClientHelloEarlyData",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendEarlyDataOnSecondClientHello: true,
+ },
+ DefaultCurves: []CurveID{},
+ },
+ shouldFail: true,
+ expectedLocalError: "remote error: bad record MAC",
+ })
+
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "EmptyEncryptedExtensions",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ EmptyEncryptedExtensions: true,
+ },
+ },
+ shouldFail: true,
+ expectedLocalError: "remote error: error decoding message",
+ })
+
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "EncryptedExtensionsWithKeyShare",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ EncryptedExtensionsWithKeyShare: true,
+ },
+ },
+ shouldFail: true,
+ expectedLocalError: "remote error: unsupported extension",
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "SendHelloRetryRequest",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ // Require a HelloRetryRequest for every curve.
+ DefaultCurves: []CurveID{},
+ },
+ expectedCurveID: CurveX25519,
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "SendHelloRetryRequest-2",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ DefaultCurves: []CurveID{CurveP384},
+ },
+ // Although the ClientHello did not predict our preferred curve,
+ // we always select it whether it is predicted or not.
+ expectedCurveID: CurveX25519,
+ })
+
+ testCases = append(testCases, testCase{
+ name: "UnknownCurve-HelloRetryRequest",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ // P-384 requires HelloRetryRequest in BoringSSL.
+ CurvePreferences: []CurveID{CurveP384},
+ Bugs: ProtocolBugs{
+ SendHelloRetryRequestCurve: bogusCurve,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":WRONG_CURVE:",
+ })
+
+ testCases = append(testCases, testCase{
+ name: "DisabledCurve-HelloRetryRequest",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ CurvePreferences: []CurveID{CurveP256},
+ Bugs: ProtocolBugs{
+ IgnorePeerCurvePreferences: true,
+ },
+ },
+ flags: []string{"-p384-only"},
+ shouldFail: true,
+ expectedError: ":WRONG_CURVE:",
+ })
+
+ testCases = append(testCases, testCase{
+ name: "UnnecessaryHelloRetryRequest",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ CurvePreferences: []CurveID{CurveX25519},
+ Bugs: ProtocolBugs{
+ SendHelloRetryRequestCurve: CurveX25519,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":WRONG_CURVE:",
+ })
+
+ testCases = append(testCases, testCase{
+ name: "SecondHelloRetryRequest",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ // P-384 requires HelloRetryRequest in BoringSSL.
+ CurvePreferences: []CurveID{CurveP384},
+ Bugs: ProtocolBugs{
+ SecondHelloRetryRequest: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_MESSAGE:",
+ })
+
+ testCases = append(testCases, testCase{
+ name: "HelloRetryRequest-Empty",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ AlwaysSendHelloRetryRequest: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":DECODE_ERROR:",
+ })
+
+ testCases = append(testCases, testCase{
+ name: "HelloRetryRequest-DuplicateCurve",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ // P-384 requires a HelloRetryRequest against BoringSSL's default
+ // configuration. Assert this ExpectMissingKeyShare.
+ CurvePreferences: []CurveID{CurveP384},
+ Bugs: ProtocolBugs{
+ ExpectMissingKeyShare: true,
+ DuplicateHelloRetryRequestExtensions: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":DUPLICATE_EXTENSION:",
+ expectedLocalError: "remote error: illegal parameter",
+ })
+
+ testCases = append(testCases, testCase{
+ name: "HelloRetryRequest-Cookie",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendHelloRetryRequestCookie: []byte("cookie"),
+ },
+ },
+ })
+
+ testCases = append(testCases, testCase{
+ name: "HelloRetryRequest-DuplicateCookie",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendHelloRetryRequestCookie: []byte("cookie"),
+ DuplicateHelloRetryRequestExtensions: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":DUPLICATE_EXTENSION:",
+ expectedLocalError: "remote error: illegal parameter",
+ })
+
+ testCases = append(testCases, testCase{
+ name: "HelloRetryRequest-EmptyCookie",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendHelloRetryRequestCookie: []byte{},
+ },
+ },
+ shouldFail: true,
+ expectedError: ":DECODE_ERROR:",
+ })
+
+ testCases = append(testCases, testCase{
+ name: "HelloRetryRequest-Cookie-Curve",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ // P-384 requires HelloRetryRequest in BoringSSL.
+ CurvePreferences: []CurveID{CurveP384},
+ Bugs: ProtocolBugs{
+ SendHelloRetryRequestCookie: []byte("cookie"),
+ ExpectMissingKeyShare: true,
+ },
+ },
+ })
+
+ testCases = append(testCases, testCase{
+ name: "HelloRetryRequest-Unknown",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ CustomHelloRetryRequestExtension: "extension",
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_EXTENSION:",
+ expectedLocalError: "remote error: unsupported extension",
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "SecondClientHelloMissingKeyShare",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ DefaultCurves: []CurveID{},
+ Bugs: ProtocolBugs{
+ SecondClientHelloMissingKeyShare: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":MISSING_KEY_SHARE:",
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "SecondClientHelloWrongCurve",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ DefaultCurves: []CurveID{},
+ Bugs: ProtocolBugs{
+ MisinterpretHelloRetryRequestCurve: CurveP521,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":WRONG_CURVE:",
+ })
+
+ testCases = append(testCases, testCase{
+ name: "HelloRetryRequestVersionMismatch",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ // P-384 requires HelloRetryRequest in BoringSSL.
+ CurvePreferences: []CurveID{CurveP384},
+ Bugs: ProtocolBugs{
+ SendServerHelloVersion: 0x0305,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":WRONG_VERSION_NUMBER:",
+ })
+
+ testCases = append(testCases, testCase{
+ name: "HelloRetryRequestCurveMismatch",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ // P-384 requires HelloRetryRequest in BoringSSL.
+ CurvePreferences: []CurveID{CurveP384},
+ Bugs: ProtocolBugs{
+ // Send P-384 (correct) in the HelloRetryRequest.
+ SendHelloRetryRequestCurve: CurveP384,
+ // But send P-256 in the ServerHello.
+ SendCurve: CurveP256,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":WRONG_CURVE:",
+ })
+
+ // Test the server selecting a curve that requires a HelloRetryRequest
+ // without sending it.
+ testCases = append(testCases, testCase{
+ name: "SkipHelloRetryRequest",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ // P-384 requires HelloRetryRequest in BoringSSL.
+ CurvePreferences: []CurveID{CurveP384},
+ Bugs: ProtocolBugs{
+ SkipHelloRetryRequest: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":WRONG_CURVE:",
+ })
+
+ testCases = append(testCases, testCase{
+ name: "TLS13-RequestContextInHandshake",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ MinVersion: VersionTLS13,
+ ClientAuth: RequireAnyClientCert,
+ Bugs: ProtocolBugs{
+ SendRequestContext: []byte("request context"),
+ },
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaKeyFile),
+ },
+ shouldFail: true,
+ expectedError: ":DECODE_ERROR:",
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "TLS13-TrailingKeyShareData",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ TrailingKeyShareData: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":DECODE_ERROR:",
+ })
+
+ testCases = append(testCases, testCase{
+ name: "TLS13-AlwaysSelectPSKIdentity",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ AlwaysSelectPSKIdentity: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_EXTENSION:",
+ })
+
+ testCases = append(testCases, testCase{
+ name: "TLS13-InvalidPSKIdentity",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SelectPSKIdentityOnResume: 1,
+ },
+ },
+ resumeSession: true,
+ shouldFail: true,
+ expectedError: ":PSK_IDENTITY_NOT_FOUND:",
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "TLS13-ExtraPSKIdentity",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ ExtraPSKIdentity: true,
+ SendExtraPSKBinder: true,
+ },
+ },
+ resumeSession: true,
+ })
+
+ // Test that unknown NewSessionTicket extensions are tolerated.
+ testCases = append(testCases, testCase{
+ name: "TLS13-CustomTicketExtension",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ CustomTicketExtension: "1234",
+ },
+ },
+ })
+}
+
+func addTLS13CipherPreferenceTests() {
+ // Test that client preference is honored if the shim has AES hardware
+ // and ChaCha20-Poly1305 is preferred otherwise.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "TLS13-CipherPreference-Server-ChaCha20-AES",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ CipherSuites: []uint16{
+ TLS_CHACHA20_POLY1305_SHA256,
+ TLS_AES_128_GCM_SHA256,
+ },
+ },
+ flags: []string{
+ "-expect-cipher-aes", strconv.Itoa(int(TLS_CHACHA20_POLY1305_SHA256)),
+ "-expect-cipher-no-aes", strconv.Itoa(int(TLS_CHACHA20_POLY1305_SHA256)),
+ },
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "TLS13-CipherPreference-Server-AES-ChaCha20",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ CipherSuites: []uint16{
+ TLS_AES_128_GCM_SHA256,
+ TLS_CHACHA20_POLY1305_SHA256,
+ },
+ },
+ flags: []string{
+ "-expect-cipher-aes", strconv.Itoa(int(TLS_AES_128_GCM_SHA256)),
+ "-expect-cipher-no-aes", strconv.Itoa(int(TLS_CHACHA20_POLY1305_SHA256)),
+ },
+ })
+
+ // Test that the client orders ChaCha20-Poly1305 and AES-GCM based on
+ // whether it has AES hardware.
+ testCases = append(testCases, testCase{
+ name: "TLS13-CipherPreference-Client",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ // Use the client cipher order. (This is the default but
+ // is listed to be explicit.)
+ PreferServerCipherSuites: false,
+ },
+ flags: []string{
+ "-expect-cipher-aes", strconv.Itoa(int(TLS_AES_128_GCM_SHA256)),
+ "-expect-cipher-no-aes", strconv.Itoa(int(TLS_CHACHA20_POLY1305_SHA256)),
+ },
+ })
+}
+
+func addPeekTests() {
+ // Test SSL_peek works, including on empty records.
+ testCases = append(testCases, testCase{
+ name: "Peek-Basic",
+ sendEmptyRecords: 1,
+ flags: []string{"-peek-then-read"},
+ })
+
+ // Test SSL_peek can drive the initial handshake.
+ testCases = append(testCases, testCase{
+ name: "Peek-ImplicitHandshake",
+ flags: []string{
+ "-peek-then-read",
+ "-implicit-handshake",
+ },
+ })
+
+ // Test SSL_peek can discover and drive a renegotiation.
+ testCases = append(testCases, testCase{
+ name: "Peek-Renegotiate",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ },
+ renegotiate: 1,
+ flags: []string{
+ "-peek-then-read",
+ "-renegotiate-freely",
+ "-expect-total-renegotiations", "1",
+ },
+ })
+
+ // Test SSL_peek can discover a close_notify.
+ testCases = append(testCases, testCase{
+ name: "Peek-Shutdown",
+ config: Config{
+ Bugs: ProtocolBugs{
+ ExpectCloseNotify: true,
+ },
+ },
+ flags: []string{
+ "-peek-then-read",
+ "-check-close-notify",
+ },
+ })
+
+ // Test SSL_peek can discover an alert.
+ testCases = append(testCases, testCase{
+ name: "Peek-Alert",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendSpuriousAlert: alertRecordOverflow,
+ },
+ },
+ flags: []string{"-peek-then-read"},
+ shouldFail: true,
+ expectedError: ":TLSV1_ALERT_RECORD_OVERFLOW:",
+ })
+
+ // Test SSL_peek can handle KeyUpdate.
+ testCases = append(testCases, testCase{
+ name: "Peek-KeyUpdate",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ },
+ sendKeyUpdates: 1,
+ keyUpdateRequest: keyUpdateNotRequested,
+ flags: []string{"-peek-then-read"},
+ })
+}
+
+func addRecordVersionTests() {
+ for _, ver := range tlsVersions {
+ // Test that the record version is enforced.
+ testCases = append(testCases, testCase{
+ name: "CheckRecordVersion-" + ver.name,
+ config: Config{
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
+ Bugs: ProtocolBugs{
+ SendRecordVersion: 0x03ff,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":WRONG_VERSION_NUMBER:",
+ })
+
+ // Test that the ClientHello may use any record version, for
+ // compatibility reasons.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "LooseInitialRecordVersion-" + ver.name,
+ config: Config{
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
+ Bugs: ProtocolBugs{
+ SendInitialRecordVersion: 0x03ff,
+ },
+ },
+ })
+
+ // Test that garbage ClientHello record versions are rejected.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "GarbageInitialRecordVersion-" + ver.name,
+ config: Config{
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
+ Bugs: ProtocolBugs{
+ SendInitialRecordVersion: 0xffff,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":WRONG_VERSION_NUMBER:",
+ })
+ }
+}
+
+func addCertificateTests() {
+ // Test that a certificate chain with intermediate may be sent and
+ // received as both client and server.
+ for _, ver := range tlsVersions {
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "SendReceiveIntermediate-Client-" + ver.name,
+ config: Config{
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
+ Certificates: []Certificate{rsaChainCertificate},
+ ClientAuth: RequireAnyClientCert,
+ },
+ expectPeerCertificate: &rsaChainCertificate,
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, rsaChainCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaChainKeyFile),
+ "-expect-peer-cert-file", path.Join(*resourceDir, rsaChainCertificateFile),
+ },
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "SendReceiveIntermediate-Server-" + ver.name,
+ config: Config{
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
+ Certificates: []Certificate{rsaChainCertificate},
+ },
+ expectPeerCertificate: &rsaChainCertificate,
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, rsaChainCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaChainKeyFile),
+ "-require-any-client-certificate",
+ "-expect-peer-cert-file", path.Join(*resourceDir, rsaChainCertificateFile),
+ },
+ })
+ }
+}
+
+func addRetainOnlySHA256ClientCertTests() {
+ for _, ver := range tlsVersions {
+ // Test that enabling
+ // SSL_CTX_set_retain_only_sha256_of_client_certs without
+ // actually requesting a client certificate is a no-op.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "RetainOnlySHA256-NoCert-" + ver.name,
+ config: Config{
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
+ },
+ flags: []string{
+ "-retain-only-sha256-client-cert-initial",
+ "-retain-only-sha256-client-cert-resume",
+ },
+ resumeSession: true,
+ })
+
+ // Test that when retaining only a SHA-256 certificate is
+ // enabled, the hash appears as expected.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "RetainOnlySHA256-Cert-" + ver.name,
+ config: Config{
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
+ Certificates: []Certificate{rsaCertificate},
+ },
+ flags: []string{
+ "-verify-peer",
+ "-retain-only-sha256-client-cert-initial",
+ "-retain-only-sha256-client-cert-resume",
+ "-expect-sha256-client-cert-initial",
+ "-expect-sha256-client-cert-resume",
+ },
+ resumeSession: true,
+ })
+
+ // Test that when the config changes from on to off, a
+ // resumption is rejected because the server now wants the full
+ // certificate chain.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "RetainOnlySHA256-OnOff-" + ver.name,
+ config: Config{
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
+ Certificates: []Certificate{rsaCertificate},
+ },
+ flags: []string{
+ "-verify-peer",
+ "-retain-only-sha256-client-cert-initial",
+ "-expect-sha256-client-cert-initial",
+ },
+ resumeSession: true,
+ expectResumeRejected: true,
+ })
+
+ // Test that when the config changes from off to on, a
+ // resumption is rejected because the server now wants just the
+ // hash.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "RetainOnlySHA256-OffOn-" + ver.name,
+ config: Config{
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
+ Certificates: []Certificate{rsaCertificate},
+ },
+ flags: []string{
+ "-verify-peer",
+ "-retain-only-sha256-client-cert-resume",
+ "-expect-sha256-client-cert-resume",
+ },
+ resumeSession: true,
+ expectResumeRejected: true,
+ })
+ }
+}
+
+func addECDSAKeyUsageTests() {
+ p256 := elliptic.P256()
+ priv, err := ecdsa.GenerateKey(p256, rand.Reader)
+ if err != nil {
+ panic(err)
+ }
+
+ serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
+ serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
+ if err != nil {
+ panic(err)
+ }
+
+ template := x509.Certificate{
+ SerialNumber: serialNumber,
+ Subject: pkix.Name{
+ Organization: []string{"Acme Co"},
+ },
+ NotBefore: time.Now(),
+ NotAfter: time.Now(),
+
+ // An ECC certificate with only the keyAgreement key usgae may
+ // be used with ECDH, but not ECDSA.
+ KeyUsage: x509.KeyUsageKeyAgreement,
+ ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
+ BasicConstraintsValid: true,
+ }
+
+ derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
+ if err != nil {
+ panic(err)
+ }
+
+ cert := Certificate{
+ Certificate: [][]byte{derBytes},
+ PrivateKey: priv,
+ }
+
+ for _, ver := range tlsVersions {
+ if ver.version < VersionTLS12 {
+ continue
+ }
+
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "ECDSAKeyUsage-" + ver.name,
+ config: Config{
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
+ Certificates: []Certificate{cert},
+ },
+ shouldFail: true,
+ expectedError: ":ECC_CERT_NOT_FOR_SIGNING:",
+ })
+ }
+}
+
+func worker(statusChan chan statusMsg, c chan *testCase, shimPath string, wg *sync.WaitGroup) {
+ defer wg.Done()
+
+ for test := range c {
+ var err error
+
+ if *mallocTest >= 0 {
+ for mallocNumToFail := int64(*mallocTest); ; mallocNumToFail++ {
+ statusChan <- statusMsg{test: test, started: true}
+ if err = runTest(test, shimPath, mallocNumToFail); err != errMoreMallocs {
+ if err != nil {
+ fmt.Printf("\n\nmalloc test failed at %d: %s\n", mallocNumToFail, err)
+ }
+ break
+ }
+ }
+ } else if *repeatUntilFailure {
+ for err == nil {
+ statusChan <- statusMsg{test: test, started: true}
+ err = runTest(test, shimPath, -1)
+ }
+ } else {
+ statusChan <- statusMsg{test: test, started: true}
+ err = runTest(test, shimPath, -1)
+ }
+ statusChan <- statusMsg{test: test, err: err}
+ }
+}
+
+type statusMsg struct {
+ test *testCase
+ started bool
+ err error
+}
+
+func statusPrinter(doneChan chan *testOutput, statusChan chan statusMsg, total int) {
+ var started, done, failed, unimplemented, lineLen int
+
+ testOutput := newTestOutput()
+ for msg := range statusChan {
+ if !*pipe {
+ // Erase the previous status line.
+ var erase string
+ for i := 0; i < lineLen; i++ {
+ erase += "\b \b"
+ }
+ fmt.Print(erase)
+ }
+
+ if msg.started {
+ started++
+ } else {
+ done++
+
+ if msg.err != nil {
+ if msg.err == errUnimplemented {
+ if *pipe {
+ // Print each test instead of a status line.
+ fmt.Printf("UNIMPLEMENTED (%s)\n", msg.test.name)
+ }
+ unimplemented++
+ testOutput.addResult(msg.test.name, "UNIMPLEMENTED")
+ } else {
+ fmt.Printf("FAILED (%s)\n%s\n", msg.test.name, msg.err)
+ failed++
+ testOutput.addResult(msg.test.name, "FAIL")
+ }
+ } else {
+ if *pipe {
+ // Print each test instead of a status line.
+ fmt.Printf("PASSED (%s)\n", msg.test.name)
+ }
+ testOutput.addResult(msg.test.name, "PASS")
+ }
+ }
+
+ if !*pipe {
+ // Print a new status line.
+ line := fmt.Sprintf("%d/%d/%d/%d/%d", failed, unimplemented, done, started, total)
+ lineLen = len(line)
+ os.Stdout.WriteString(line)
+ }
+ }
+
+ doneChan <- testOutput
+}
+
+func main() {
+ flag.Parse()
+ *resourceDir = path.Clean(*resourceDir)
+ initCertificates()
+
+ addBasicTests()
+ addCipherSuiteTests()
+ addBadECDSASignatureTests()
+ addCBCPaddingTests()
+ addCBCSplittingTests()
+ addClientAuthTests()
+ addDDoSCallbackTests()
+ addVersionNegotiationTests()
+ addMinimumVersionTests()
+ addExtensionTests()
+ addResumptionVersionTests()
+ addExtendedMasterSecretTests()
+ addRenegotiationTests()
+ addDTLSReplayTests()
+ addSignatureAlgorithmTests()
+ addDTLSRetransmitTests()
+ addExportKeyingMaterialTests()
+ addTLSUniqueTests()
+ addCustomExtensionTests()
+ addRSAClientKeyExchangeTests()
+ addCurveTests()
+ addSessionTicketTests()
+ addTLS13RecordTests()
+ addAllStateMachineCoverageTests()
+ addChangeCipherSpecTests()
+ addWrongMessageTypeTests()
+ addTrailingMessageDataTests()
+ addTLS13HandshakeTests()
+ addTLS13CipherPreferenceTests()
+ addPeekTests()
+ addRecordVersionTests()
+ addCertificateTests()
+ addRetainOnlySHA256ClientCertTests()
+ addECDSAKeyUsageTests()
+
+ var wg sync.WaitGroup
+
+ statusChan := make(chan statusMsg, *numWorkers)
+ testChan := make(chan *testCase, *numWorkers)
+ doneChan := make(chan *testOutput)
+
+ if len(*shimConfigFile) != 0 {
+ encoded, err := ioutil.ReadFile(*shimConfigFile)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Couldn't read config file %q: %s\n", *shimConfigFile, err)
+ os.Exit(1)
+ }
+
+ if err := json.Unmarshal(encoded, &shimConfig); err != nil {
+ fmt.Fprintf(os.Stderr, "Couldn't decode config file %q: %s\n", *shimConfigFile, err)
+ os.Exit(1)
+ }
+ }
+
+ go statusPrinter(doneChan, statusChan, len(testCases))
+
+ for i := 0; i < *numWorkers; i++ {
+ wg.Add(1)
+ go worker(statusChan, testChan, *shimPath, &wg)
+ }
+
+ var foundTest bool
+ for i := range testCases {
+ matched := true
+ if len(*testToRun) != 0 {
+ var err error
+ matched, err = filepath.Match(*testToRun, testCases[i].name)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Error matching pattern: %s\n", err)
+ os.Exit(1)
+ }
+ }
+
+ if !*includeDisabled {
+ for pattern := range shimConfig.DisabledTests {
+ isDisabled, err := filepath.Match(pattern, testCases[i].name)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Error matching pattern %q from config file: %s\n", pattern, err)
+ os.Exit(1)
+ }
+
+ if isDisabled {
+ matched = false
+ break
+ }
+ }
+ }
+
+ if matched {
+ foundTest = true
+ testChan <- &testCases[i]
+
+ // Only run one test if repeating until failure.
+ if *repeatUntilFailure {
+ break
+ }
+ }
+ }
+
+ if !foundTest {
+ fmt.Fprintf(os.Stderr, "No tests run\n")
+ os.Exit(1)
+ }
+
+ close(testChan)
+ wg.Wait()
+ close(statusChan)
+ testOutput := <-doneChan
+
+ fmt.Printf("\n")
+
+ if *jsonOutput != "" {
+ if err := testOutput.writeTo(*jsonOutput); err != nil {
+ fmt.Fprintf(os.Stderr, "Error: %s\n", err)
+ }
+ }
+
+ if !*allowUnimplemented && testOutput.NumFailuresByType["UNIMPLEMENTED"] > 0 {
+ os.Exit(1)
+ }
+
+ if !testOutput.noneFailed {
+ os.Exit(1)
+ }
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/runner_test.go b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/runner_test.go
new file mode 100644
index 000000000..6c7fcb0c9
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/runner_test.go
@@ -0,0 +1,21 @@
+// Copyright (c) 2016, 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 runner
+
+import "testing"
+
+func TestAll(t *testing.T) {
+ main()
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/shim_ticket.go b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/shim_ticket.go
new file mode 100644
index 000000000..9e57d482a
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/shim_ticket.go
@@ -0,0 +1,249 @@
+// Copyright (c) 2016, 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 runner
+
+import (
+ "bytes"
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/hmac"
+ "crypto/sha256"
+ "encoding/asn1"
+ "errors"
+)
+
+// TestShimTicketKey is the testing key assumed for the shim.
+var TestShimTicketKey = make([]byte, 48)
+
+func DecryptShimTicket(in []byte) ([]byte, error) {
+ name := TestShimTicketKey[:16]
+ macKey := TestShimTicketKey[16:32]
+ encKey := TestShimTicketKey[32:48]
+
+ h := hmac.New(sha256.New, macKey)
+
+ block, err := aes.NewCipher(encKey)
+ if err != nil {
+ panic(err)
+ }
+
+ if len(in) < len(name)+block.BlockSize()+1+h.Size() {
+ return nil, errors.New("tls: shim ticket too short")
+ }
+
+ // Check the key name.
+ if !bytes.Equal(name, in[:len(name)]) {
+ return nil, errors.New("tls: shim ticket name mismatch")
+ }
+
+ // Check the MAC at the end of the ticket.
+ mac := in[len(in)-h.Size():]
+ in = in[:len(in)-h.Size()]
+ h.Write(in)
+ if !hmac.Equal(mac, h.Sum(nil)) {
+ return nil, errors.New("tls: shim ticket MAC mismatch")
+ }
+
+ // The MAC covers the key name, but the encryption does not.
+ in = in[len(name):]
+
+ // Decrypt in-place.
+ iv := in[:block.BlockSize()]
+ in = in[block.BlockSize():]
+ if l := len(in); l == 0 || l%block.BlockSize() != 0 {
+ return nil, errors.New("tls: ticket ciphertext not a multiple of the block size")
+ }
+ out := make([]byte, len(in))
+ cbc := cipher.NewCBCDecrypter(block, iv)
+ cbc.CryptBlocks(out, in)
+
+ // Remove the padding.
+ pad := int(out[len(out)-1])
+ if pad == 0 || pad > block.BlockSize() || pad > len(in) {
+ return nil, errors.New("tls: bad shim ticket CBC pad")
+ }
+
+ for i := 0; i < pad; i++ {
+ if out[len(out)-1-i] != byte(pad) {
+ return nil, errors.New("tls: bad shim ticket CBC pad")
+ }
+ }
+
+ return out[:len(out)-pad], nil
+}
+
+func EncryptShimTicket(in []byte) []byte {
+ name := TestShimTicketKey[:16]
+ macKey := TestShimTicketKey[16:32]
+ encKey := TestShimTicketKey[32:48]
+
+ h := hmac.New(sha256.New, macKey)
+
+ block, err := aes.NewCipher(encKey)
+ if err != nil {
+ panic(err)
+ }
+
+ // Use the zero IV for rewritten tickets.
+ iv := make([]byte, block.BlockSize())
+ cbc := cipher.NewCBCEncrypter(block, iv)
+ pad := block.BlockSize() - (len(in) % block.BlockSize())
+
+ out := make([]byte, 0, len(name)+len(iv)+len(in)+pad+h.Size())
+ out = append(out, name...)
+ out = append(out, iv...)
+ out = append(out, in...)
+ for i := 0; i < pad; i++ {
+ out = append(out, byte(pad))
+ }
+
+ ciphertext := out[len(name)+len(iv):]
+ cbc.CryptBlocks(ciphertext, ciphertext)
+
+ h.Write(out)
+ return h.Sum(out)
+}
+
+const asn1Constructed = 0x20
+
+func parseDERElement(in []byte) (tag byte, body, rest []byte, ok bool) {
+ rest = in
+ if len(rest) < 1 {
+ return
+ }
+
+ tag = rest[0]
+ rest = rest[1:]
+
+ if tag&0x1f == 0x1f {
+ // Long-form tags not supported.
+ return
+ }
+
+ if len(rest) < 1 {
+ return
+ }
+
+ length := int(rest[0])
+ rest = rest[1:]
+ if length > 0x7f {
+ lengthLength := length & 0x7f
+ length = 0
+ if lengthLength == 0 {
+ // No indefinite-length encoding.
+ return
+ }
+
+ // Decode long-form lengths.
+ for lengthLength > 0 {
+ if len(rest) < 1 || (length<<8)>>8 != length {
+ return
+ }
+ if length == 0 && rest[0] == 0 {
+ // Length not minimally-encoded.
+ return
+ }
+ length <<= 8
+ length |= int(rest[0])
+ rest = rest[1:]
+ lengthLength--
+ }
+
+ if length < 0x80 {
+ // Length not minimally-encoded.
+ return
+ }
+ }
+
+ if len(rest) < length {
+ return
+ }
+
+ body = rest[:length]
+ rest = rest[length:]
+ ok = true
+ return
+}
+
+func SetShimTicketVersion(in []byte, vers uint16) ([]byte, error) {
+ plaintext, err := DecryptShimTicket(in)
+ if err != nil {
+ return nil, err
+ }
+
+ tag, session, _, ok := parseDERElement(plaintext)
+ if !ok || tag != asn1.TagSequence|asn1Constructed {
+ return nil, errors.New("tls: could not decode shim session")
+ }
+
+ // Skip the session version.
+ tag, _, session, ok = parseDERElement(session)
+ if !ok || tag != asn1.TagInteger {
+ return nil, errors.New("tls: could not decode shim session")
+ }
+
+ // Next field is the protocol version.
+ tag, version, _, ok := parseDERElement(session)
+ if !ok || tag != asn1.TagInteger {
+ return nil, errors.New("tls: could not decode shim session")
+ }
+
+ // This code assumes both old and new versions are encoded in two
+ // bytes. This isn't quite right as INTEGERs are minimally-encoded, but
+ // we do not need to support other caess for now.
+ if len(version) != 2 || vers < 0x80 || vers >= 0x8000 {
+ return nil, errors.New("tls: unsupported version in shim session")
+ }
+
+ version[0] = byte(vers >> 8)
+ version[1] = byte(vers)
+
+ return EncryptShimTicket(plaintext), nil
+}
+
+func SetShimTicketCipherSuite(in []byte, id uint16) ([]byte, error) {
+ plaintext, err := DecryptShimTicket(in)
+ if err != nil {
+ return nil, err
+ }
+
+ tag, session, _, ok := parseDERElement(plaintext)
+ if !ok || tag != asn1.TagSequence|asn1Constructed {
+ return nil, errors.New("tls: could not decode shim session")
+ }
+
+ // Skip the session version.
+ tag, _, session, ok = parseDERElement(session)
+ if !ok || tag != asn1.TagInteger {
+ return nil, errors.New("tls: could not decode shim session")
+ }
+
+ // Skip the protocol version.
+ tag, _, session, ok = parseDERElement(session)
+ if !ok || tag != asn1.TagInteger {
+ return nil, errors.New("tls: could not decode shim session")
+ }
+
+ // Next field is the cipher suite.
+ tag, cipherSuite, _, ok := parseDERElement(session)
+ if !ok || tag != asn1.TagOctetString || len(cipherSuite) != 2 {
+ return nil, errors.New("tls: could not decode shim session")
+ }
+
+ cipherSuite[0] = byte(id >> 8)
+ cipherSuite[1] = byte(id)
+
+ return EncryptShimTicket(plaintext), nil
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/sign.go b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/sign.go
new file mode 100644
index 000000000..5f56ff960
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/sign.go
@@ -0,0 +1,297 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runner
+
+import (
+ "crypto"
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "crypto/md5"
+ "crypto/rsa"
+ "crypto/sha1"
+ _ "crypto/sha256"
+ _ "crypto/sha512"
+ "encoding/asn1"
+ "errors"
+ "fmt"
+ "math/big"
+)
+
+type signer interface {
+ supportsKey(key crypto.PrivateKey) bool
+ signMessage(key crypto.PrivateKey, config *Config, msg []byte) ([]byte, error)
+ verifyMessage(key crypto.PublicKey, msg, sig []byte) error
+}
+
+func selectSignatureAlgorithm(version uint16, key crypto.PrivateKey, config *Config, peerSigAlgs []signatureAlgorithm) (signatureAlgorithm, error) {
+ // If the client didn't specify any signature_algorithms extension then
+ // we can assume that it supports SHA1. See
+ // http://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
+ if len(peerSigAlgs) == 0 {
+ peerSigAlgs = []signatureAlgorithm{signatureRSAPKCS1WithSHA1, signatureECDSAWithSHA1}
+ }
+
+ for _, sigAlg := range config.signSignatureAlgorithms() {
+ if !isSupportedSignatureAlgorithm(sigAlg, peerSigAlgs) {
+ continue
+ }
+
+ signer, err := getSigner(version, key, config, sigAlg)
+ if err != nil {
+ continue
+ }
+
+ if signer.supportsKey(key) {
+ return sigAlg, nil
+ }
+ }
+ return 0, errors.New("tls: no common signature algorithms")
+}
+
+func signMessage(version uint16, key crypto.PrivateKey, config *Config, sigAlg signatureAlgorithm, msg []byte) ([]byte, error) {
+ if config.Bugs.InvalidSignature {
+ newMsg := make([]byte, len(msg))
+ copy(newMsg, msg)
+ newMsg[0] ^= 0x80
+ msg = newMsg
+ }
+
+ signer, err := getSigner(version, key, config, sigAlg)
+ if err != nil {
+ return nil, err
+ }
+
+ return signer.signMessage(key, config, msg)
+}
+
+func verifyMessage(version uint16, key crypto.PublicKey, config *Config, sigAlg signatureAlgorithm, msg, sig []byte) error {
+ if version >= VersionTLS12 && !isSupportedSignatureAlgorithm(sigAlg, config.verifySignatureAlgorithms()) {
+ return errors.New("tls: unsupported signature algorithm")
+ }
+
+ signer, err := getSigner(version, key, config, sigAlg)
+ if err != nil {
+ return err
+ }
+
+ return signer.verifyMessage(key, msg, sig)
+}
+
+type rsaPKCS1Signer struct {
+ hash crypto.Hash
+}
+
+func (r *rsaPKCS1Signer) computeHash(msg []byte) []byte {
+ if r.hash == crypto.MD5SHA1 {
+ // crypto.MD5SHA1 is not a real hash function.
+ hashMD5 := md5.New()
+ hashMD5.Write(msg)
+ hashSHA1 := sha1.New()
+ hashSHA1.Write(msg)
+ return hashSHA1.Sum(hashMD5.Sum(nil))
+ }
+
+ h := r.hash.New()
+ h.Write(msg)
+ return h.Sum(nil)
+}
+
+func (r *rsaPKCS1Signer) supportsKey(key crypto.PrivateKey) bool {
+ _, ok := key.(*rsa.PrivateKey)
+ return ok
+}
+
+func (r *rsaPKCS1Signer) signMessage(key crypto.PrivateKey, config *Config, msg []byte) ([]byte, error) {
+ rsaKey, ok := key.(*rsa.PrivateKey)
+ if !ok {
+ return nil, errors.New("invalid key type for RSA-PKCS1")
+ }
+
+ return rsa.SignPKCS1v15(config.rand(), rsaKey, r.hash, r.computeHash(msg))
+}
+
+func (r *rsaPKCS1Signer) verifyMessage(key crypto.PublicKey, msg, sig []byte) error {
+ rsaKey, ok := key.(*rsa.PublicKey)
+ if !ok {
+ return errors.New("invalid key type for RSA-PKCS1")
+ }
+
+ return rsa.VerifyPKCS1v15(rsaKey, r.hash, r.computeHash(msg), sig)
+}
+
+type ecdsaSigner struct {
+ version uint16
+ config *Config
+ curve elliptic.Curve
+ hash crypto.Hash
+}
+
+func (e *ecdsaSigner) isCurveValid(curve elliptic.Curve) bool {
+ if e.config.Bugs.SkipECDSACurveCheck {
+ return true
+ }
+ if e.version <= VersionTLS12 {
+ return true
+ }
+ return e.curve != nil && curve == e.curve
+}
+
+func (e *ecdsaSigner) supportsKey(key crypto.PrivateKey) bool {
+ ecdsaKey, ok := key.(*ecdsa.PrivateKey)
+ return ok && e.isCurveValid(ecdsaKey.Curve)
+}
+
+func maybeCorruptECDSAValue(n *big.Int, typeOfCorruption BadValue, limit *big.Int) *big.Int {
+ switch typeOfCorruption {
+ case BadValueNone:
+ return n
+ case BadValueNegative:
+ return new(big.Int).Neg(n)
+ case BadValueZero:
+ return big.NewInt(0)
+ case BadValueLimit:
+ return limit
+ case BadValueLarge:
+ bad := new(big.Int).Set(limit)
+ return bad.Lsh(bad, 20)
+ default:
+ panic("unknown BadValue type")
+ }
+}
+
+func (e *ecdsaSigner) signMessage(key crypto.PrivateKey, config *Config, msg []byte) ([]byte, error) {
+ ecdsaKey, ok := key.(*ecdsa.PrivateKey)
+ if !ok {
+ return nil, errors.New("invalid key type for ECDSA")
+ }
+ if !e.isCurveValid(ecdsaKey.Curve) {
+ return nil, errors.New("invalid curve for ECDSA")
+ }
+
+ h := e.hash.New()
+ h.Write(msg)
+ digest := h.Sum(nil)
+
+ r, s, err := ecdsa.Sign(config.rand(), ecdsaKey, digest)
+ if err != nil {
+ return nil, errors.New("failed to sign ECDHE parameters: " + err.Error())
+ }
+ order := ecdsaKey.Curve.Params().N
+ r = maybeCorruptECDSAValue(r, config.Bugs.BadECDSAR, order)
+ s = maybeCorruptECDSAValue(s, config.Bugs.BadECDSAS, order)
+ return asn1.Marshal(ecdsaSignature{r, s})
+}
+
+func (e *ecdsaSigner) verifyMessage(key crypto.PublicKey, msg, sig []byte) error {
+ ecdsaKey, ok := key.(*ecdsa.PublicKey)
+ if !ok {
+ return errors.New("invalid key type for ECDSA")
+ }
+ if !e.isCurveValid(ecdsaKey.Curve) {
+ return errors.New("invalid curve for ECDSA")
+ }
+
+ ecdsaSig := new(ecdsaSignature)
+ if _, err := asn1.Unmarshal(sig, ecdsaSig); err != nil {
+ return err
+ }
+ if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 {
+ return errors.New("ECDSA signature contained zero or negative values")
+ }
+
+ h := e.hash.New()
+ h.Write(msg)
+ if !ecdsa.Verify(ecdsaKey, h.Sum(nil), ecdsaSig.R, ecdsaSig.S) {
+ return errors.New("ECDSA verification failure")
+ }
+ return nil
+}
+
+var pssOptions = rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash}
+
+type rsaPSSSigner struct {
+ hash crypto.Hash
+}
+
+func (r *rsaPSSSigner) supportsKey(key crypto.PrivateKey) bool {
+ _, ok := key.(*rsa.PrivateKey)
+ return ok
+}
+
+func (r *rsaPSSSigner) signMessage(key crypto.PrivateKey, config *Config, msg []byte) ([]byte, error) {
+ rsaKey, ok := key.(*rsa.PrivateKey)
+ if !ok {
+ return nil, errors.New("invalid key type for RSA-PSS")
+ }
+
+ h := r.hash.New()
+ h.Write(msg)
+ return rsa.SignPSS(config.rand(), rsaKey, r.hash, h.Sum(nil), &pssOptions)
+}
+
+func (r *rsaPSSSigner) verifyMessage(key crypto.PublicKey, msg, sig []byte) error {
+ rsaKey, ok := key.(*rsa.PublicKey)
+ if !ok {
+ return errors.New("invalid key type for RSA-PSS")
+ }
+
+ h := r.hash.New()
+ h.Write(msg)
+ return rsa.VerifyPSS(rsaKey, r.hash, h.Sum(nil), sig, &pssOptions)
+}
+
+func getSigner(version uint16, key interface{}, config *Config, sigAlg signatureAlgorithm) (signer, error) {
+ // TLS 1.1 and below use legacy signature algorithms.
+ if version < VersionTLS12 {
+ switch key.(type) {
+ case *rsa.PrivateKey, *rsa.PublicKey:
+ return &rsaPKCS1Signer{crypto.MD5SHA1}, nil
+ case *ecdsa.PrivateKey, *ecdsa.PublicKey:
+ return &ecdsaSigner{version, config, nil, crypto.SHA1}, nil
+ default:
+ return nil, errors.New("unknown key type")
+ }
+ }
+
+ // TODO(davidben): Forbid RSASSA-PKCS1-v1_5 in TLS 1.3.
+ switch sigAlg {
+ case signatureRSAPKCS1WithMD5:
+ if version < VersionTLS13 || config.Bugs.IgnoreSignatureVersionChecks {
+ return &rsaPKCS1Signer{crypto.MD5}, nil
+ }
+ case signatureRSAPKCS1WithSHA1:
+ if version < VersionTLS13 || config.Bugs.IgnoreSignatureVersionChecks {
+ return &rsaPKCS1Signer{crypto.SHA1}, nil
+ }
+ case signatureRSAPKCS1WithSHA256:
+ if version < VersionTLS13 || config.Bugs.IgnoreSignatureVersionChecks {
+ return &rsaPKCS1Signer{crypto.SHA256}, nil
+ }
+ case signatureRSAPKCS1WithSHA384:
+ if version < VersionTLS13 || config.Bugs.IgnoreSignatureVersionChecks {
+ return &rsaPKCS1Signer{crypto.SHA384}, nil
+ }
+ case signatureRSAPKCS1WithSHA512:
+ if version < VersionTLS13 || config.Bugs.IgnoreSignatureVersionChecks {
+ return &rsaPKCS1Signer{crypto.SHA512}, nil
+ }
+ case signatureECDSAWithSHA1:
+ return &ecdsaSigner{version, config, nil, crypto.SHA1}, nil
+ case signatureECDSAWithP256AndSHA256:
+ return &ecdsaSigner{version, config, elliptic.P256(), crypto.SHA256}, nil
+ case signatureECDSAWithP384AndSHA384:
+ return &ecdsaSigner{version, config, elliptic.P384(), crypto.SHA384}, nil
+ case signatureECDSAWithP521AndSHA512:
+ return &ecdsaSigner{version, config, elliptic.P521(), crypto.SHA512}, nil
+ case signatureRSAPSSWithSHA256:
+ return &rsaPSSSigner{crypto.SHA256}, nil
+ case signatureRSAPSSWithSHA384:
+ return &rsaPSSSigner{crypto.SHA384}, nil
+ case signatureRSAPSSWithSHA512:
+ return &rsaPSSSigner{crypto.SHA512}, nil
+ }
+
+ return nil, fmt.Errorf("unsupported signature algorithm %04x", sigAlg)
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/test_output.go b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/test_output.go
new file mode 100644
index 000000000..eb5463824
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/test_output.go
@@ -0,0 +1,79 @@
+/* Copyright (c) 2015, 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 runner
+
+import (
+ "encoding/json"
+ "os"
+ "time"
+)
+
+// testOutput is a representation of Chromium's JSON test result format. See
+// https://www.chromium.org/developers/the-json-test-results-format
+type testOutput struct {
+ Version int `json:"version"`
+ Interrupted bool `json:"interrupted"`
+ PathDelimiter string `json:"path_delimiter"`
+ SecondsSinceEpoch float64 `json:"seconds_since_epoch"`
+ NumFailuresByType map[string]int `json:"num_failures_by_type"`
+ Tests map[string]testResult `json:"tests"`
+ noneFailed bool
+}
+
+type testResult struct {
+ Actual string `json:"actual"`
+ Expected string `json:"expected"`
+ IsUnexpected bool `json:"is_unexpected"`
+}
+
+func newTestOutput() *testOutput {
+ return &testOutput{
+ Version: 3,
+ PathDelimiter: ".",
+ SecondsSinceEpoch: float64(time.Now().UnixNano()) / float64(time.Second/time.Nanosecond),
+ NumFailuresByType: make(map[string]int),
+ Tests: make(map[string]testResult),
+ noneFailed: true,
+ }
+}
+
+func (t *testOutput) addResult(name, result string) {
+ if _, found := t.Tests[name]; found {
+ panic(name)
+ }
+ t.Tests[name] = testResult{
+ Actual: result,
+ Expected: "PASS",
+ IsUnexpected: result != "PASS",
+ }
+ t.NumFailuresByType[result]++
+ if result != "PASS" && result != "UNIMPLEMENTED" {
+ t.noneFailed = false
+ }
+}
+
+func (t *testOutput) writeTo(name string) error {
+ file, err := os.Create(name)
+ if err != nil {
+ return err
+ }
+ defer file.Close()
+ out, err := json.MarshalIndent(t, "", " ")
+ if err != nil {
+ return err
+ }
+ _, err = file.Write(out)
+ return err
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/ticket.go b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/ticket.go
new file mode 100644
index 000000000..4a4540c5d
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/ticket.go
@@ -0,0 +1,197 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runner
+
+import (
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/hmac"
+ "crypto/sha256"
+ "crypto/subtle"
+ "encoding/binary"
+ "errors"
+ "io"
+ "time"
+)
+
+// sessionState contains the information that is serialized into a session
+// ticket in order to later resume a connection.
+type sessionState struct {
+ vers uint16
+ cipherSuite uint16
+ masterSecret []byte
+ handshakeHash []byte
+ certificates [][]byte
+ extendedMasterSecret bool
+ ticketCreationTime time.Time
+ ticketExpiration time.Time
+ ticketFlags uint32
+ ticketAgeAdd uint32
+}
+
+func (s *sessionState) marshal() []byte {
+ msg := newByteBuilder()
+ msg.addU16(s.vers)
+ msg.addU16(s.cipherSuite)
+ masterSecret := msg.addU16LengthPrefixed()
+ masterSecret.addBytes(s.masterSecret)
+ handshakeHash := msg.addU16LengthPrefixed()
+ handshakeHash.addBytes(s.handshakeHash)
+ msg.addU16(uint16(len(s.certificates)))
+ for _, cert := range s.certificates {
+ certMsg := msg.addU32LengthPrefixed()
+ certMsg.addBytes(cert)
+ }
+
+ if s.extendedMasterSecret {
+ msg.addU8(1)
+ } else {
+ msg.addU8(0)
+ }
+
+ if s.vers >= VersionTLS13 {
+ msg.addU64(uint64(s.ticketCreationTime.UnixNano()))
+ msg.addU64(uint64(s.ticketExpiration.UnixNano()))
+ msg.addU32(s.ticketFlags)
+ msg.addU32(s.ticketAgeAdd)
+ }
+
+ return msg.finish()
+}
+
+func (s *sessionState) unmarshal(data []byte) bool {
+ if len(data) < 8 {
+ return false
+ }
+
+ s.vers = uint16(data[0])<<8 | uint16(data[1])
+ s.cipherSuite = uint16(data[2])<<8 | uint16(data[3])
+ masterSecretLen := int(data[4])<<8 | int(data[5])
+ data = data[6:]
+ if len(data) < masterSecretLen {
+ return false
+ }
+
+ s.masterSecret = data[:masterSecretLen]
+ data = data[masterSecretLen:]
+
+ if len(data) < 2 {
+ return false
+ }
+
+ handshakeHashLen := int(data[0])<<8 | int(data[1])
+ data = data[2:]
+ if len(data) < handshakeHashLen {
+ return false
+ }
+
+ s.handshakeHash = data[:handshakeHashLen]
+ data = data[handshakeHashLen:]
+
+ if len(data) < 2 {
+ return false
+ }
+
+ numCerts := int(data[0])<<8 | int(data[1])
+ data = data[2:]
+
+ s.certificates = make([][]byte, numCerts)
+ for i := range s.certificates {
+ if len(data) < 4 {
+ return false
+ }
+ certLen := int(data[0])<<24 | int(data[1])<<16 | int(data[2])<<8 | int(data[3])
+ data = data[4:]
+ if certLen < 0 {
+ return false
+ }
+ if len(data) < certLen {
+ return false
+ }
+ s.certificates[i] = data[:certLen]
+ data = data[certLen:]
+ }
+
+ if len(data) < 1 {
+ return false
+ }
+
+ s.extendedMasterSecret = false
+ if data[0] == 1 {
+ s.extendedMasterSecret = true
+ }
+ data = data[1:]
+
+ if s.vers >= VersionTLS13 {
+ if len(data) < 24 {
+ return false
+ }
+ s.ticketCreationTime = time.Unix(0, int64(binary.BigEndian.Uint64(data)))
+ data = data[8:]
+ s.ticketExpiration = time.Unix(0, int64(binary.BigEndian.Uint64(data)))
+ data = data[8:]
+ s.ticketFlags = binary.BigEndian.Uint32(data)
+ data = data[4:]
+ s.ticketAgeAdd = binary.BigEndian.Uint32(data)
+ data = data[4:]
+ }
+
+ if len(data) > 0 {
+ return false
+ }
+
+ return true
+}
+
+func (c *Conn) encryptTicket(state *sessionState) ([]byte, error) {
+ serialized := state.marshal()
+ encrypted := make([]byte, aes.BlockSize+len(serialized)+sha256.Size)
+ iv := encrypted[:aes.BlockSize]
+ macBytes := encrypted[len(encrypted)-sha256.Size:]
+
+ if _, err := io.ReadFull(c.config.rand(), iv); err != nil {
+ return nil, err
+ }
+ block, err := aes.NewCipher(c.config.SessionTicketKey[:16])
+ if err != nil {
+ return nil, errors.New("tls: failed to create cipher while encrypting ticket: " + err.Error())
+ }
+ cipher.NewCTR(block, iv).XORKeyStream(encrypted[aes.BlockSize:], serialized)
+
+ mac := hmac.New(sha256.New, c.config.SessionTicketKey[16:32])
+ mac.Write(encrypted[:len(encrypted)-sha256.Size])
+ mac.Sum(macBytes[:0])
+
+ return encrypted, nil
+}
+
+func (c *Conn) decryptTicket(encrypted []byte) (*sessionState, bool) {
+ if len(encrypted) < aes.BlockSize+sha256.Size {
+ return nil, false
+ }
+
+ iv := encrypted[:aes.BlockSize]
+ macBytes := encrypted[len(encrypted)-sha256.Size:]
+
+ mac := hmac.New(sha256.New, c.config.SessionTicketKey[16:32])
+ mac.Write(encrypted[:len(encrypted)-sha256.Size])
+ expected := mac.Sum(nil)
+
+ if subtle.ConstantTimeCompare(macBytes, expected) != 1 {
+ return nil, false
+ }
+
+ block, err := aes.NewCipher(c.config.SessionTicketKey[:16])
+ if err != nil {
+ return nil, false
+ }
+ ciphertext := encrypted[aes.BlockSize : len(encrypted)-sha256.Size]
+ plaintext := make([]byte, len(ciphertext))
+ cipher.NewCTR(block, iv).XORKeyStream(plaintext, ciphertext)
+
+ state := new(sessionState)
+ ok := state.unmarshal(plaintext)
+ return state, ok
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/tls.go b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/tls.go
new file mode 100644
index 000000000..24f9b1ec8
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/runner/tls.go
@@ -0,0 +1,279 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package tls partially implements TLS 1.2, as specified in RFC 5246.
+package runner
+
+import (
+ "crypto"
+ "crypto/ecdsa"
+ "crypto/rsa"
+ "crypto/x509"
+ "encoding/pem"
+ "errors"
+ "io/ioutil"
+ "net"
+ "strings"
+ "time"
+)
+
+// Server returns a new TLS server side connection
+// using conn as the underlying transport.
+// The configuration config must be non-nil and must have
+// at least one certificate.
+func Server(conn net.Conn, config *Config) *Conn {
+ c := &Conn{conn: conn, config: config}
+ c.init()
+ return c
+}
+
+// Client returns a new TLS client side connection
+// using conn as the underlying transport.
+// The config cannot be nil: users must set either ServerHostname or
+// InsecureSkipVerify in the config.
+func Client(conn net.Conn, config *Config) *Conn {
+ c := &Conn{conn: conn, config: config, isClient: true}
+ c.init()
+ return c
+}
+
+// A listener implements a network listener (net.Listener) for TLS connections.
+type listener struct {
+ net.Listener
+ config *Config
+}
+
+// Accept waits for and returns the next incoming TLS connection.
+// The returned connection c is a *tls.Conn.
+func (l *listener) Accept() (c net.Conn, err error) {
+ c, err = l.Listener.Accept()
+ if err != nil {
+ return
+ }
+ c = Server(c, l.config)
+ return
+}
+
+// NewListener creates a Listener which accepts connections from an inner
+// Listener and wraps each connection with Server.
+// The configuration config must be non-nil and must have
+// at least one certificate.
+func NewListener(inner net.Listener, config *Config) net.Listener {
+ l := new(listener)
+ l.Listener = inner
+ l.config = config
+ return l
+}
+
+// Listen creates a TLS listener accepting connections on the
+// given network address using net.Listen.
+// The configuration config must be non-nil and must have
+// at least one certificate.
+func Listen(network, laddr string, config *Config) (net.Listener, error) {
+ if config == nil || len(config.Certificates) == 0 {
+ return nil, errors.New("tls.Listen: no certificates in configuration")
+ }
+ l, err := net.Listen(network, laddr)
+ if err != nil {
+ return nil, err
+ }
+ return NewListener(l, config), nil
+}
+
+type timeoutError struct{}
+
+func (timeoutError) Error() string { return "tls: DialWithDialer timed out" }
+func (timeoutError) Timeout() bool { return true }
+func (timeoutError) Temporary() bool { return true }
+
+// DialWithDialer connects to the given network address using dialer.Dial and
+// then initiates a TLS handshake, returning the resulting TLS connection. Any
+// timeout or deadline given in the dialer apply to connection and TLS
+// handshake as a whole.
+//
+// DialWithDialer interprets a nil configuration as equivalent to the zero
+// configuration; see the documentation of Config for the defaults.
+func DialWithDialer(dialer *net.Dialer, network, addr string, config *Config) (*Conn, error) {
+ // We want the Timeout and Deadline values from dialer to cover the
+ // whole process: TCP connection and TLS handshake. This means that we
+ // also need to start our own timers now.
+ timeout := dialer.Timeout
+
+ if !dialer.Deadline.IsZero() {
+ deadlineTimeout := dialer.Deadline.Sub(time.Now())
+ if timeout == 0 || deadlineTimeout < timeout {
+ timeout = deadlineTimeout
+ }
+ }
+
+ var errChannel chan error
+
+ if timeout != 0 {
+ errChannel = make(chan error, 2)
+ time.AfterFunc(timeout, func() {
+ errChannel <- timeoutError{}
+ })
+ }
+
+ rawConn, err := dialer.Dial(network, addr)
+ if err != nil {
+ return nil, err
+ }
+
+ colonPos := strings.LastIndex(addr, ":")
+ if colonPos == -1 {
+ colonPos = len(addr)
+ }
+ hostname := addr[:colonPos]
+
+ if config == nil {
+ config = defaultConfig()
+ }
+ // If no ServerName is set, infer the ServerName
+ // from the hostname we're connecting to.
+ if config.ServerName == "" {
+ // Make a copy to avoid polluting argument or default.
+ c := *config
+ c.ServerName = hostname
+ config = &c
+ }
+
+ conn := Client(rawConn, config)
+
+ if timeout == 0 {
+ err = conn.Handshake()
+ } else {
+ go func() {
+ errChannel <- conn.Handshake()
+ }()
+
+ err = <-errChannel
+ }
+
+ if err != nil {
+ rawConn.Close()
+ return nil, err
+ }
+
+ return conn, nil
+}
+
+// Dial connects to the given network address using net.Dial
+// and then initiates a TLS handshake, returning the resulting
+// TLS connection.
+// Dial interprets a nil configuration as equivalent to
+// the zero configuration; see the documentation of Config
+// for the defaults.
+func Dial(network, addr string, config *Config) (*Conn, error) {
+ return DialWithDialer(new(net.Dialer), network, addr, config)
+}
+
+// LoadX509KeyPair reads and parses a public/private key pair from a pair of
+// files. The files must contain PEM encoded data.
+func LoadX509KeyPair(certFile, keyFile string) (cert Certificate, err error) {
+ certPEMBlock, err := ioutil.ReadFile(certFile)
+ if err != nil {
+ return
+ }
+ keyPEMBlock, err := ioutil.ReadFile(keyFile)
+ if err != nil {
+ return
+ }
+ return X509KeyPair(certPEMBlock, keyPEMBlock)
+}
+
+// X509KeyPair parses a public/private key pair from a pair of
+// PEM encoded data.
+func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (cert Certificate, err error) {
+ var certDERBlock *pem.Block
+ for {
+ certDERBlock, certPEMBlock = pem.Decode(certPEMBlock)
+ if certDERBlock == nil {
+ break
+ }
+ if certDERBlock.Type == "CERTIFICATE" {
+ cert.Certificate = append(cert.Certificate, certDERBlock.Bytes)
+ }
+ }
+
+ if len(cert.Certificate) == 0 {
+ err = errors.New("crypto/tls: failed to parse certificate PEM data")
+ return
+ }
+
+ var keyDERBlock *pem.Block
+ for {
+ keyDERBlock, keyPEMBlock = pem.Decode(keyPEMBlock)
+ if keyDERBlock == nil {
+ err = errors.New("crypto/tls: failed to parse key PEM data")
+ return
+ }
+ if keyDERBlock.Type == "PRIVATE KEY" || strings.HasSuffix(keyDERBlock.Type, " PRIVATE KEY") {
+ break
+ }
+ }
+
+ cert.PrivateKey, err = parsePrivateKey(keyDERBlock.Bytes)
+ if err != nil {
+ return
+ }
+
+ // We don't need to parse the public key for TLS, but we so do anyway
+ // to check that it looks sane and matches the private key.
+ x509Cert, err := x509.ParseCertificate(cert.Certificate[0])
+ if err != nil {
+ return
+ }
+
+ switch pub := x509Cert.PublicKey.(type) {
+ case *rsa.PublicKey:
+ priv, ok := cert.PrivateKey.(*rsa.PrivateKey)
+ if !ok {
+ err = errors.New("crypto/tls: private key type does not match public key type")
+ return
+ }
+ if pub.N.Cmp(priv.N) != 0 {
+ err = errors.New("crypto/tls: private key does not match public key")
+ return
+ }
+ case *ecdsa.PublicKey:
+ priv, ok := cert.PrivateKey.(*ecdsa.PrivateKey)
+ if !ok {
+ err = errors.New("crypto/tls: private key type does not match public key type")
+ return
+
+ }
+ if pub.X.Cmp(priv.X) != 0 || pub.Y.Cmp(priv.Y) != 0 {
+ err = errors.New("crypto/tls: private key does not match public key")
+ return
+ }
+ default:
+ err = errors.New("crypto/tls: unknown public key algorithm")
+ return
+ }
+
+ return
+}
+
+// Attempt to parse the given private key DER block. OpenSSL 0.9.8 generates
+// PKCS#1 private keys by default, while OpenSSL 1.0.0 generates PKCS#8 keys.
+// OpenSSL ecparam generates SEC1 EC private keys for ECDSA. We try all three.
+func parsePrivateKey(der []byte) (crypto.PrivateKey, error) {
+ if key, err := x509.ParsePKCS1PrivateKey(der); err == nil {
+ return key, nil
+ }
+ if key, err := x509.ParsePKCS8PrivateKey(der); err == nil {
+ switch key := key.(type) {
+ case *rsa.PrivateKey, *ecdsa.PrivateKey:
+ return key, nil
+ default:
+ return nil, errors.New("crypto/tls: found unknown private key type in PKCS#8 wrapping")
+ }
+ }
+ if key, err := x509.ParseECPrivateKey(der); err == nil {
+ return key, nil
+ }
+
+ return nil, errors.New("crypto/tls: failed to parse private key")
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/test_config.cc b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/test_config.cc
new file mode 100644
index 000000000..e58158197
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/test_config.cc
@@ -0,0 +1,264 @@
+/* Copyright (c) 2014, 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 "test_config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <memory>
+
+#include <openssl/base64.h>
+
+namespace {
+
+template <typename T>
+struct Flag {
+ const char *flag;
+ T TestConfig::*member;
+};
+
+// FindField looks for the flag in |flags| that matches |flag|. If one is found,
+// it returns a pointer to the corresponding field in |config|. Otherwise, it
+// returns NULL.
+template<typename T, size_t N>
+T *FindField(TestConfig *config, const Flag<T> (&flags)[N], const char *flag) {
+ for (size_t i = 0; i < N; i++) {
+ if (strcmp(flag, flags[i].flag) == 0) {
+ return &(config->*(flags[i].member));
+ }
+ }
+ return NULL;
+}
+
+const Flag<bool> kBoolFlags[] = {
+ { "-server", &TestConfig::is_server },
+ { "-dtls", &TestConfig::is_dtls },
+ { "-fallback-scsv", &TestConfig::fallback_scsv },
+ { "-require-any-client-certificate",
+ &TestConfig::require_any_client_certificate },
+ { "-false-start", &TestConfig::false_start },
+ { "-async", &TestConfig::async },
+ { "-write-different-record-sizes",
+ &TestConfig::write_different_record_sizes },
+ { "-cbc-record-splitting", &TestConfig::cbc_record_splitting },
+ { "-partial-write", &TestConfig::partial_write },
+ { "-no-tls13", &TestConfig::no_tls13 },
+ { "-no-tls12", &TestConfig::no_tls12 },
+ { "-no-tls11", &TestConfig::no_tls11 },
+ { "-no-tls1", &TestConfig::no_tls1 },
+ { "-no-ssl3", &TestConfig::no_ssl3 },
+ { "-enable-channel-id", &TestConfig::enable_channel_id },
+ { "-shim-writes-first", &TestConfig::shim_writes_first },
+ { "-expect-session-miss", &TestConfig::expect_session_miss },
+ { "-decline-alpn", &TestConfig::decline_alpn },
+ { "-expect-extended-master-secret",
+ &TestConfig::expect_extended_master_secret },
+ { "-enable-ocsp-stapling", &TestConfig::enable_ocsp_stapling },
+ { "-enable-signed-cert-timestamps",
+ &TestConfig::enable_signed_cert_timestamps },
+ { "-implicit-handshake", &TestConfig::implicit_handshake },
+ { "-use-early-callback", &TestConfig::use_early_callback },
+ { "-fail-early-callback", &TestConfig::fail_early_callback },
+ { "-install-ddos-callback", &TestConfig::install_ddos_callback },
+ { "-fail-ddos-callback", &TestConfig::fail_ddos_callback },
+ { "-fail-second-ddos-callback", &TestConfig::fail_second_ddos_callback },
+ { "-fail-cert-callback", &TestConfig::fail_cert_callback },
+ { "-handshake-never-done", &TestConfig::handshake_never_done },
+ { "-use-export-context", &TestConfig::use_export_context },
+ { "-tls-unique", &TestConfig::tls_unique },
+ { "-expect-ticket-renewal", &TestConfig::expect_ticket_renewal },
+ { "-expect-no-session", &TestConfig::expect_no_session },
+ { "-expect-early-data-info", &TestConfig::expect_early_data_info },
+ { "-use-ticket-callback", &TestConfig::use_ticket_callback },
+ { "-renew-ticket", &TestConfig::renew_ticket },
+ { "-enable-early-data", &TestConfig::enable_early_data },
+ { "-enable-client-custom-extension",
+ &TestConfig::enable_client_custom_extension },
+ { "-enable-server-custom-extension",
+ &TestConfig::enable_server_custom_extension },
+ { "-custom-extension-skip", &TestConfig::custom_extension_skip },
+ { "-custom-extension-fail-add", &TestConfig::custom_extension_fail_add },
+ { "-check-close-notify", &TestConfig::check_close_notify },
+ { "-shim-shuts-down", &TestConfig::shim_shuts_down },
+ { "-verify-fail", &TestConfig::verify_fail },
+ { "-verify-peer", &TestConfig::verify_peer },
+ { "-expect-verify-result", &TestConfig::expect_verify_result },
+ { "-renegotiate-once", &TestConfig::renegotiate_once },
+ { "-renegotiate-freely", &TestConfig::renegotiate_freely },
+ { "-renegotiate-ignore", &TestConfig::renegotiate_ignore },
+ { "-p384-only", &TestConfig::p384_only },
+ { "-enable-all-curves", &TestConfig::enable_all_curves },
+ { "-use-sparse-dh-prime", &TestConfig::use_sparse_dh_prime },
+ { "-use-old-client-cert-callback",
+ &TestConfig::use_old_client_cert_callback },
+ { "-send-alert", &TestConfig::send_alert },
+ { "-peek-then-read", &TestConfig::peek_then_read },
+ { "-enable-grease", &TestConfig::enable_grease },
+ { "-use-exporter-between-reads", &TestConfig::use_exporter_between_reads },
+ { "-retain-only-sha256-client-cert-initial",
+ &TestConfig::retain_only_sha256_client_cert_initial },
+ { "-retain-only-sha256-client-cert-resume",
+ &TestConfig::retain_only_sha256_client_cert_resume },
+ { "-expect-sha256-client-cert-initial",
+ &TestConfig::expect_sha256_client_cert_initial },
+ { "-expect-sha256-client-cert-resume",
+ &TestConfig::expect_sha256_client_cert_resume },
+ { "-read-with-unfinished-write", &TestConfig::read_with_unfinished_write },
+ { "-expect-secure-renegotiation",
+ &TestConfig::expect_secure_renegotiation },
+ { "-expect-no-secure-renegotiation",
+ &TestConfig::expect_no_secure_renegotiation },
+ { "-expect-session-id", &TestConfig::expect_session_id },
+ { "-expect-no-session-id", &TestConfig::expect_no_session_id },
+};
+
+const Flag<std::string> kStringFlags[] = {
+ { "-digest-prefs", &TestConfig::digest_prefs },
+ { "-key-file", &TestConfig::key_file },
+ { "-cert-file", &TestConfig::cert_file },
+ { "-expect-server-name", &TestConfig::expected_server_name },
+ { "-advertise-npn", &TestConfig::advertise_npn },
+ { "-expect-next-proto", &TestConfig::expected_next_proto },
+ { "-select-next-proto", &TestConfig::select_next_proto },
+ { "-send-channel-id", &TestConfig::send_channel_id },
+ { "-host-name", &TestConfig::host_name },
+ { "-advertise-alpn", &TestConfig::advertise_alpn },
+ { "-expect-alpn", &TestConfig::expected_alpn },
+ { "-expect-advertised-alpn", &TestConfig::expected_advertised_alpn },
+ { "-select-alpn", &TestConfig::select_alpn },
+ { "-psk", &TestConfig::psk },
+ { "-psk-identity", &TestConfig::psk_identity },
+ { "-srtp-profiles", &TestConfig::srtp_profiles },
+ { "-cipher", &TestConfig::cipher },
+ { "-export-label", &TestConfig::export_label },
+ { "-export-context", &TestConfig::export_context },
+ { "-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 },
+};
+
+const Flag<std::string> kBase64Flags[] = {
+ { "-expect-certificate-types", &TestConfig::expected_certificate_types },
+ { "-expect-channel-id", &TestConfig::expected_channel_id },
+ { "-expect-ocsp-response", &TestConfig::expected_ocsp_response },
+ { "-expect-signed-cert-timestamps",
+ &TestConfig::expected_signed_cert_timestamps },
+ { "-ocsp-response", &TestConfig::ocsp_response },
+ { "-signed-cert-timestamps", &TestConfig::signed_cert_timestamps },
+ { "-ticket-key", &TestConfig::ticket_key },
+};
+
+const Flag<int> kIntFlags[] = {
+ { "-port", &TestConfig::port },
+ { "-resume-count", &TestConfig::resume_count },
+ { "-min-version", &TestConfig::min_version },
+ { "-max-version", &TestConfig::max_version },
+ { "-mtu", &TestConfig::mtu },
+ { "-export-keying-material", &TestConfig::export_keying_material },
+ { "-expect-total-renegotiations", &TestConfig::expect_total_renegotiations },
+ { "-expect-peer-signature-algorithm",
+ &TestConfig::expect_peer_signature_algorithm },
+ { "-expect-curve-id", &TestConfig::expect_curve_id },
+ { "-expect-resume-curve-id", &TestConfig::expect_resume_curve_id },
+ { "-initial-timeout-duration-ms", &TestConfig::initial_timeout_duration_ms },
+ { "-max-cert-list", &TestConfig::max_cert_list },
+ { "-expect-cipher-aes", &TestConfig::expect_cipher_aes },
+ { "-expect-cipher-no-aes", &TestConfig::expect_cipher_no_aes },
+ { "-resumption-delay", &TestConfig::resumption_delay },
+ { "-max-send-fragment", &TestConfig::max_send_fragment },
+ { "-read-size", &TestConfig::read_size },
+ { "-expect-ticket-age-skew", &TestConfig::expect_ticket_age_skew },
+};
+
+const Flag<std::vector<int>> kIntVectorFlags[] = {
+ { "-signing-prefs", &TestConfig::signing_prefs },
+};
+
+} // namespace
+
+bool ParseConfig(int argc, char **argv, TestConfig *out_config) {
+ for (int i = 0; i < argc; i++) {
+ bool *bool_field = FindField(out_config, kBoolFlags, argv[i]);
+ if (bool_field != NULL) {
+ *bool_field = true;
+ continue;
+ }
+
+ std::string *string_field = FindField(out_config, kStringFlags, argv[i]);
+ if (string_field != NULL) {
+ i++;
+ if (i >= argc) {
+ fprintf(stderr, "Missing parameter\n");
+ return false;
+ }
+ string_field->assign(argv[i]);
+ continue;
+ }
+
+ std::string *base64_field = FindField(out_config, kBase64Flags, argv[i]);
+ if (base64_field != NULL) {
+ i++;
+ if (i >= argc) {
+ fprintf(stderr, "Missing parameter\n");
+ return false;
+ }
+ size_t len;
+ if (!EVP_DecodedLength(&len, strlen(argv[i]))) {
+ fprintf(stderr, "Invalid base64: %s\n", argv[i]);
+ return false;
+ }
+ std::unique_ptr<uint8_t[]> decoded(new uint8_t[len]);
+ if (!EVP_DecodeBase64(decoded.get(), &len, len,
+ reinterpret_cast<const uint8_t *>(argv[i]),
+ strlen(argv[i]))) {
+ fprintf(stderr, "Invalid base64: %s\n", argv[i]);
+ return false;
+ }
+ base64_field->assign(reinterpret_cast<const char *>(decoded.get()), len);
+ continue;
+ }
+
+ int *int_field = FindField(out_config, kIntFlags, argv[i]);
+ if (int_field) {
+ i++;
+ if (i >= argc) {
+ fprintf(stderr, "Missing parameter\n");
+ return false;
+ }
+ *int_field = atoi(argv[i]);
+ continue;
+ }
+
+ std::vector<int> *int_vector_field =
+ FindField(out_config, kIntVectorFlags, argv[i]);
+ if (int_vector_field) {
+ i++;
+ if (i >= argc) {
+ fprintf(stderr, "Missing parameter\n");
+ return false;
+ }
+
+ // Each instance of the flag adds to the list.
+ int_vector_field->push_back(atoi(argv[i]));
+ continue;
+ }
+
+ fprintf(stderr, "Unknown argument: %s\n", argv[i]);
+ return false;
+ }
+
+ return true;
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/test_config.h b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/test_config.h
new file mode 100644
index 000000000..7057b4866
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/test/test_config.h
@@ -0,0 +1,142 @@
+/* Copyright (c) 2014, 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 HEADER_TEST_CONFIG
+#define HEADER_TEST_CONFIG
+
+#include <string>
+#include <vector>
+
+
+struct TestConfig {
+ int port = 0;
+ bool is_server = false;
+ bool is_dtls = false;
+ int resume_count = 0;
+ bool fallback_scsv = false;
+ std::string digest_prefs;
+ std::vector<int> signing_prefs;
+ std::string key_file;
+ std::string cert_file;
+ std::string expected_server_name;
+ std::string expected_certificate_types;
+ bool require_any_client_certificate = false;
+ std::string advertise_npn;
+ std::string expected_next_proto;
+ bool false_start = false;
+ std::string select_next_proto;
+ bool async = false;
+ bool write_different_record_sizes = false;
+ bool cbc_record_splitting = false;
+ bool partial_write = false;
+ bool no_tls13 = false;
+ bool no_tls12 = false;
+ bool no_tls11 = false;
+ bool no_tls1 = false;
+ bool no_ssl3 = false;
+ std::string expected_channel_id;
+ bool enable_channel_id = false;
+ std::string send_channel_id;
+ bool shim_writes_first = false;
+ std::string host_name;
+ std::string advertise_alpn;
+ std::string expected_alpn;
+ std::string expected_advertised_alpn;
+ std::string select_alpn;
+ bool decline_alpn = false;
+ bool expect_session_miss = false;
+ bool expect_extended_master_secret = false;
+ std::string psk;
+ std::string psk_identity;
+ std::string srtp_profiles;
+ bool enable_ocsp_stapling = false;
+ std::string expected_ocsp_response;
+ bool enable_signed_cert_timestamps = false;
+ std::string expected_signed_cert_timestamps;
+ int min_version = 0;
+ int max_version = 0;
+ int mtu = 0;
+ bool implicit_handshake = false;
+ bool use_early_callback = false;
+ bool fail_early_callback = false;
+ bool install_ddos_callback = false;
+ bool fail_ddos_callback = false;
+ bool fail_second_ddos_callback = false;
+ bool fail_cert_callback = false;
+ std::string cipher;
+ bool handshake_never_done = false;
+ int export_keying_material = 0;
+ std::string export_label;
+ std::string export_context;
+ bool use_export_context = false;
+ bool tls_unique = false;
+ bool expect_ticket_renewal = false;
+ bool expect_no_session = false;
+ bool expect_early_data_info = false;
+ bool use_ticket_callback = false;
+ bool renew_ticket = false;
+ bool enable_early_data = false;
+ bool enable_client_custom_extension = false;
+ bool enable_server_custom_extension = false;
+ bool custom_extension_skip = false;
+ bool custom_extension_fail_add = false;
+ std::string ocsp_response;
+ bool check_close_notify = false;
+ bool shim_shuts_down = false;
+ bool verify_fail = false;
+ bool verify_peer = false;
+ bool expect_verify_result = false;
+ std::string signed_cert_timestamps;
+ int expect_total_renegotiations = 0;
+ bool renegotiate_once = false;
+ bool renegotiate_freely = false;
+ bool renegotiate_ignore = false;
+ int expect_peer_signature_algorithm = 0;
+ bool p384_only = false;
+ bool enable_all_curves = false;
+ bool use_sparse_dh_prime = false;
+ int expect_curve_id = 0;
+ int expect_resume_curve_id = 0;
+ bool use_old_client_cert_callback = false;
+ int initial_timeout_duration_ms = 0;
+ std::string use_client_ca_list;
+ std::string expected_client_ca_list;
+ bool send_alert = false;
+ bool peek_then_read = false;
+ bool enable_grease = false;
+ int max_cert_list = 0;
+ std::string ticket_key;
+ bool use_exporter_between_reads = false;
+ int expect_cipher_aes = 0;
+ int expect_cipher_no_aes = 0;
+ std::string expect_peer_cert_file;
+ int resumption_delay = 0;
+ bool retain_only_sha256_client_cert_initial = false;
+ bool retain_only_sha256_client_cert_resume = false;
+ bool expect_sha256_client_cert_initial = false;
+ bool expect_sha256_client_cert_resume = false;
+ bool read_with_unfinished_write = false;
+ bool expect_secure_renegotiation = false;
+ bool expect_no_secure_renegotiation = false;
+ int max_send_fragment = 0;
+ int read_size = 0;
+ bool expect_session_id = false;
+ bool expect_no_session_id = false;
+ int expect_ticket_age_skew = 0;
+};
+
+bool ParseConfig(int argc, char **argv, TestConfig *out_config);
+
+
+#endif // HEADER_TEST_CONFIG
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/tls13_both.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/tls13_both.c
new file mode 100644
index 000000000..624392357
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/tls13_both.c
@@ -0,0 +1,638 @@
+/* Copyright (c) 2016, 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 <openssl/ssl.h>
+
+#include <assert.h>
+#include <string.h>
+
+#include <openssl/bytestring.h>
+#include <openssl/err.h>
+#include <openssl/hkdf.h>
+#include <openssl/mem.h>
+#include <openssl/stack.h>
+#include <openssl/x509.h>
+
+#include "../crypto/internal.h"
+#include "internal.h"
+
+
+/* kMaxKeyUpdates is the number of consecutive KeyUpdates that will be
+ * processed. Without this limit an attacker could force unbounded processing
+ * without being able to return application data. */
+static const uint8_t kMaxKeyUpdates = 32;
+
+int tls13_handshake(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ for (;;) {
+ /* Resolve the operation the handshake was waiting on. */
+ switch (hs->wait) {
+ case ssl_hs_error:
+ OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_HANDSHAKE_FAILURE);
+ return -1;
+
+ case ssl_hs_flush:
+ case ssl_hs_flush_and_read_message: {
+ int ret = ssl->method->flush_flight(ssl);
+ if (ret <= 0) {
+ return ret;
+ }
+ if (hs->wait != ssl_hs_flush_and_read_message) {
+ break;
+ }
+ ssl->method->expect_flight(ssl);
+ hs->wait = ssl_hs_read_message;
+ /* Fall-through. */
+ }
+
+ case ssl_hs_read_message: {
+ int ret = ssl->method->ssl_get_message(ssl);
+ if (ret <= 0) {
+ return ret;
+ }
+ break;
+ }
+
+ case ssl_hs_x509_lookup:
+ ssl->rwstate = SSL_X509_LOOKUP;
+ hs->wait = ssl_hs_ok;
+ return -1;
+
+ case ssl_hs_channel_id_lookup:
+ ssl->rwstate = SSL_CHANNEL_ID_LOOKUP;
+ hs->wait = ssl_hs_ok;
+ return -1;
+
+ case ssl_hs_private_key_operation:
+ ssl->rwstate = SSL_PRIVATE_KEY_OPERATION;
+ hs->wait = ssl_hs_ok;
+ return -1;
+
+ case ssl_hs_pending_ticket:
+ ssl->rwstate = SSL_PENDING_TICKET;
+ hs->wait = ssl_hs_ok;
+ return -1;
+
+ case ssl_hs_ok:
+ break;
+ }
+
+ /* Run the state machine again. */
+ hs->wait = hs->do_tls13_handshake(hs);
+ if (hs->wait == ssl_hs_error) {
+ /* Don't loop around to avoid a stray |SSL_R_SSL_HANDSHAKE_FAILURE| the
+ * first time around. */
+ return -1;
+ }
+ if (hs->wait == ssl_hs_ok) {
+ /* The handshake has completed. */
+ return 1;
+ }
+
+ /* Otherwise, loop to the beginning and resolve what was blocking the
+ * handshake. */
+ }
+}
+
+int tls13_get_cert_verify_signature_input(
+ SSL_HANDSHAKE *hs, uint8_t **out, size_t *out_len,
+ enum ssl_cert_verify_context_t cert_verify_context) {
+ CBB cbb;
+ if (!CBB_init(&cbb, 64 + 33 + 1 + 2 * EVP_MAX_MD_SIZE)) {
+ goto err;
+ }
+
+ for (size_t i = 0; i < 64; i++) {
+ if (!CBB_add_u8(&cbb, 0x20)) {
+ goto err;
+ }
+ }
+
+ const uint8_t *context;
+ size_t context_len;
+ if (cert_verify_context == ssl_cert_verify_server) {
+ /* Include the NUL byte. */
+ static const char kContext[] = "TLS 1.3, server CertificateVerify";
+ context = (const uint8_t *)kContext;
+ context_len = sizeof(kContext);
+ } else if (cert_verify_context == ssl_cert_verify_client) {
+ static const char kContext[] = "TLS 1.3, client CertificateVerify";
+ context = (const uint8_t *)kContext;
+ context_len = sizeof(kContext);
+ } else if (cert_verify_context == ssl_cert_verify_channel_id) {
+ static const char kContext[] = "TLS 1.3, Channel ID";
+ context = (const uint8_t *)kContext;
+ context_len = sizeof(kContext);
+ } else {
+ goto err;
+ }
+
+ if (!CBB_add_bytes(&cbb, context, context_len)) {
+ goto err;
+ }
+
+ uint8_t context_hash[EVP_MAX_MD_SIZE];
+ size_t context_hash_len;
+ if (!SSL_TRANSCRIPT_get_hash(&hs->transcript, context_hash,
+ &context_hash_len) ||
+ !CBB_add_bytes(&cbb, context_hash, context_hash_len) ||
+ !CBB_finish(&cbb, out, out_len)) {
+ goto err;
+ }
+
+ return 1;
+
+err:
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ CBB_cleanup(&cbb);
+ return 0;
+}
+
+int tls13_process_certificate(SSL_HANDSHAKE *hs, int allow_anonymous) {
+ SSL *const ssl = hs->ssl;
+ 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) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ return 0;
+ }
+
+ const int retain_sha256 =
+ ssl->server && ssl->retain_only_sha256_of_client_certs;
+ int ret = 0;
+
+ EVP_PKEY *pkey = NULL;
+ STACK_OF(CRYPTO_BUFFER) *certs = sk_CRYPTO_BUFFER_new_null();
+ if (certs == NULL) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ 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);
+ goto err;
+ }
+
+ while (CBS_len(&certificate_list) > 0) {
+ CBS certificate, extensions;
+ if (!CBS_get_u24_length_prefixed(&certificate_list, &certificate) ||
+ !CBS_get_u16_length_prefixed(&certificate_list, &extensions) ||
+ CBS_len(&certificate) == 0) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_LENGTH_MISMATCH);
+ goto err;
+ }
+
+ if (sk_CRYPTO_BUFFER_num(certs) == 0) {
+ pkey = ssl_cert_parse_pubkey(&certificate);
+ if (pkey == NULL) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ goto err;
+ }
+ /* TLS 1.3 always uses certificate keys for signing thus the correct
+ * keyUsage is enforced. */
+ if (!ssl_cert_check_digital_signature_key_usage(&certificate)) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+ goto err;
+ }
+
+ if (retain_sha256) {
+ /* Retain the hash of the leaf certificate if requested. */
+ SHA256(CBS_data(&certificate), CBS_len(&certificate),
+ hs->new_session->peer_sha256);
+ }
+ }
+
+ CRYPTO_BUFFER *buf =
+ CRYPTO_BUFFER_new_from_CBS(&certificate, ssl->ctx->pool);
+ if (buf == NULL ||
+ !sk_CRYPTO_BUFFER_push(certs, buf)) {
+ CRYPTO_BUFFER_free(buf);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ /* Parse out the extensions. */
+ int have_status_request = 0, have_sct = 0;
+ CBS status_request, sct;
+ const SSL_EXTENSION_TYPE ext_types[] = {
+ {TLSEXT_TYPE_status_request, &have_status_request, &status_request},
+ {TLSEXT_TYPE_certificate_timestamp, &have_sct, &sct},
+ };
+
+ uint8_t alert = SSL_AD_DECODE_ERROR;
+ if (!ssl_parse_extensions(&extensions, &alert, ext_types,
+ OPENSSL_ARRAY_SIZE(ext_types),
+ 0 /* reject unknown */)) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
+ goto err;
+ }
+
+ /* All Certificate extensions are parsed, but only the leaf extensions are
+ * stored. */
+ if (have_status_request) {
+ if (ssl->server || !ssl->ocsp_stapling_enabled) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION);
+ goto err;
+ }
+
+ uint8_t status_type;
+ CBS ocsp_response;
+ if (!CBS_get_u8(&status_request, &status_type) ||
+ status_type != TLSEXT_STATUSTYPE_ocsp ||
+ !CBS_get_u24_length_prefixed(&status_request, &ocsp_response) ||
+ CBS_len(&ocsp_response) == 0 ||
+ CBS_len(&status_request) != 0) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ goto err;
+ }
+
+ if (sk_CRYPTO_BUFFER_num(certs) == 1 &&
+ !CBS_stow(&ocsp_response, &hs->new_session->ocsp_response,
+ &hs->new_session->ocsp_response_length)) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ goto err;
+ }
+ }
+
+ if (have_sct) {
+ if (ssl->server || !ssl->signed_cert_timestamps_enabled) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION);
+ goto err;
+ }
+
+ if (!ssl_is_sct_list_valid(&sct)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_PARSING_EXTENSION);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ goto err;
+ }
+
+ if (sk_CRYPTO_BUFFER_num(certs) == 1 &&
+ !CBS_stow(
+ &sct, &hs->new_session->tlsext_signed_cert_timestamp_list,
+ &hs->new_session->tlsext_signed_cert_timestamp_list_length)) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ goto err;
+ }
+ }
+ }
+
+ if (CBS_len(&cbs) != 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ goto err;
+ }
+
+ EVP_PKEY_free(hs->peer_pubkey);
+ hs->peer_pubkey = pkey;
+ pkey = NULL;
+
+ sk_CRYPTO_BUFFER_pop_free(hs->new_session->certs, CRYPTO_BUFFER_free);
+ hs->new_session->certs = certs;
+ certs = NULL;
+
+ if (!ssl->ctx->x509_method->session_cache_objects(hs->new_session)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ goto err;
+ }
+
+ if (sk_CRYPTO_BUFFER_num(hs->new_session->certs) == 0) {
+ if (!allow_anonymous) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_CERTIFICATE_REQUIRED);
+ goto err;
+ }
+
+ /* OpenSSL returns X509_V_OK when no certificates are requested. This is
+ * classed by them as a bug, but it's assumed by at least NGINX. */
+ hs->new_session->verify_result = X509_V_OK;
+
+ /* No certificate, so nothing more to do. */
+ ret = 1;
+ goto err;
+ }
+
+ hs->new_session->peer_sha256_valid = retain_sha256;
+
+ if (!ssl->ctx->x509_method->session_verify_cert_chain(hs->new_session,
+ ssl)) {
+ goto err;
+ }
+
+ ret = 1;
+
+err:
+ sk_CRYPTO_BUFFER_pop_free(certs, CRYPTO_BUFFER_free);
+ EVP_PKEY_free(pkey);
+ return ret;
+}
+
+int tls13_process_certificate_verify(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ int ret = 0;
+ uint8_t *msg = NULL;
+ size_t msg_len;
+
+ if (hs->peer_pubkey == NULL) {
+ goto err;
+ }
+
+ CBS cbs, signature;
+ uint16_t signature_algorithm;
+ CBS_init(&cbs, ssl->init_msg, ssl->init_num);
+ if (!CBS_get_u16(&cbs, &signature_algorithm) ||
+ !CBS_get_u16_length_prefixed(&cbs, &signature) ||
+ CBS_len(&cbs) != 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ goto err;
+ }
+
+ int al;
+ if (!tls12_check_peer_sigalg(ssl, &al, signature_algorithm)) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, al);
+ goto err;
+ }
+ hs->new_session->peer_signature_algorithm = signature_algorithm;
+
+ if (!tls13_get_cert_verify_signature_input(
+ hs, &msg, &msg_len,
+ ssl->server ? ssl_cert_verify_client : ssl_cert_verify_server)) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ goto err;
+ }
+
+ int sig_ok =
+ ssl_public_key_verify(ssl, CBS_data(&signature), CBS_len(&signature),
+ signature_algorithm, hs->peer_pubkey, msg, msg_len);
+#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+ sig_ok = 1;
+ ERR_clear_error();
+#endif
+ if (!sig_ok) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SIGNATURE);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECRYPT_ERROR);
+ goto err;
+ }
+
+ ret = 1;
+
+err:
+ OPENSSL_free(msg);
+ return ret;
+}
+
+int tls13_process_finished(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ uint8_t verify_data[EVP_MAX_MD_SIZE];
+ size_t verify_data_len;
+ if (!tls13_finished_mac(hs, verify_data, &verify_data_len, !ssl->server)) {
+ return 0;
+ }
+
+ int finished_ok =
+ ssl->init_num == verify_data_len &&
+ CRYPTO_memcmp(verify_data, ssl->init_msg, verify_data_len) == 0;
+#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+ finished_ok = 1;
+#endif
+ if (!finished_ok) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECRYPT_ERROR);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DIGEST_CHECK_FAILED);
+ return 0;
+ }
+
+ return 1;
+}
+
+int tls13_add_certificate(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ CBB cbb, body, certificate_list;
+ if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_CERTIFICATE) ||
+ /* The request context is always empty in the handshake. */
+ !CBB_add_u8(&body, 0) ||
+ !CBB_add_u24_length_prefixed(&body, &certificate_list)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
+ if (!ssl_has_certificate(ssl)) {
+ if (!ssl_add_message_cbb(ssl, &cbb)) {
+ goto err;
+ }
+
+ return 1;
+ }
+
+ CERT *cert = ssl->cert;
+ CRYPTO_BUFFER *leaf_buf = sk_CRYPTO_BUFFER_value(cert->chain, 0);
+ CBB leaf, extensions;
+ if (!CBB_add_u24_length_prefixed(&certificate_list, &leaf) ||
+ !CBB_add_bytes(&leaf, CRYPTO_BUFFER_data(leaf_buf),
+ CRYPTO_BUFFER_len(leaf_buf)) ||
+ !CBB_add_u16_length_prefixed(&certificate_list, &extensions)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
+ if (hs->scts_requested && ssl->cert->signed_cert_timestamp_list != NULL) {
+ CBB contents;
+ if (!CBB_add_u16(&extensions, TLSEXT_TYPE_certificate_timestamp) ||
+ !CBB_add_u16_length_prefixed(&extensions, &contents) ||
+ !CBB_add_bytes(
+ &contents,
+ CRYPTO_BUFFER_data(ssl->cert->signed_cert_timestamp_list),
+ CRYPTO_BUFFER_len(ssl->cert->signed_cert_timestamp_list)) ||
+ !CBB_flush(&extensions)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ }
+
+ if (hs->ocsp_stapling_requested &&
+ ssl->cert->ocsp_response != NULL) {
+ CBB contents, ocsp_response;
+ if (!CBB_add_u16(&extensions, TLSEXT_TYPE_status_request) ||
+ !CBB_add_u16_length_prefixed(&extensions, &contents) ||
+ !CBB_add_u8(&contents, TLSEXT_STATUSTYPE_ocsp) ||
+ !CBB_add_u24_length_prefixed(&contents, &ocsp_response) ||
+ !CBB_add_bytes(&ocsp_response,
+ CRYPTO_BUFFER_data(ssl->cert->ocsp_response),
+ CRYPTO_BUFFER_len(ssl->cert->ocsp_response)) ||
+ !CBB_flush(&extensions)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ }
+
+ for (size_t i = 1; i < sk_CRYPTO_BUFFER_num(cert->chain); i++) {
+ CRYPTO_BUFFER *cert_buf = sk_CRYPTO_BUFFER_value(cert->chain, i);
+ CBB child;
+ if (!CBB_add_u24_length_prefixed(&certificate_list, &child) ||
+ !CBB_add_bytes(&child, CRYPTO_BUFFER_data(cert_buf),
+ CRYPTO_BUFFER_len(cert_buf)) ||
+ !CBB_add_u16(&certificate_list, 0 /* no extensions */)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ }
+
+ if (!ssl_add_message_cbb(ssl, &cbb)) {
+ goto err;
+ }
+
+ return 1;
+
+err:
+ CBB_cleanup(&cbb);
+ return 0;
+}
+
+enum ssl_private_key_result_t tls13_add_certificate_verify(SSL_HANDSHAKE *hs,
+ int is_first_run) {
+ SSL *const ssl = hs->ssl;
+ enum ssl_private_key_result_t ret = ssl_private_key_failure;
+ uint8_t *msg = NULL;
+ size_t msg_len;
+ CBB cbb, body;
+ CBB_zero(&cbb);
+
+ uint16_t signature_algorithm;
+ if (!tls1_choose_signature_algorithm(hs, &signature_algorithm)) {
+ goto err;
+ }
+ if (!ssl->method->init_message(ssl, &cbb, &body,
+ SSL3_MT_CERTIFICATE_VERIFY) ||
+ !CBB_add_u16(&body, signature_algorithm)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
+ /* Sign the digest. */
+ CBB child;
+ const size_t max_sig_len = ssl_private_key_max_signature_len(ssl);
+ uint8_t *sig;
+ size_t sig_len;
+ if (!CBB_add_u16_length_prefixed(&body, &child) ||
+ !CBB_reserve(&child, &sig, max_sig_len)) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ goto err;
+ }
+
+ enum ssl_private_key_result_t sign_result;
+ if (is_first_run) {
+ if (!tls13_get_cert_verify_signature_input(
+ hs, &msg, &msg_len,
+ ssl->server ? ssl_cert_verify_server : ssl_cert_verify_client)) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ goto err;
+ }
+ sign_result = ssl_private_key_sign(ssl, sig, &sig_len, max_sig_len,
+ signature_algorithm, msg, msg_len);
+ } else {
+ sign_result = ssl_private_key_complete(ssl, sig, &sig_len, max_sig_len);
+ }
+
+ if (sign_result != ssl_private_key_success) {
+ ret = sign_result;
+ goto err;
+ }
+
+ if (!CBB_did_write(&child, sig_len) ||
+ !ssl_add_message_cbb(ssl, &cbb)) {
+ goto err;
+ }
+
+ ret = ssl_private_key_success;
+
+err:
+ CBB_cleanup(&cbb);
+ OPENSSL_free(msg);
+ return ret;
+}
+
+int tls13_add_finished(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ size_t verify_data_len;
+ uint8_t verify_data[EVP_MAX_MD_SIZE];
+
+ if (!tls13_finished_mac(hs, verify_data, &verify_data_len, ssl->server)) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DIGEST_CHECK_FAILED);
+ return 0;
+ }
+
+ CBB cbb, body;
+ if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_FINISHED) ||
+ !CBB_add_bytes(&body, verify_data, verify_data_len) ||
+ !ssl_add_message_cbb(ssl, &cbb)) {
+ CBB_cleanup(&cbb);
+ return 0;
+ }
+
+ return 1;
+}
+
+static int tls13_receive_key_update(SSL *ssl) {
+ CBS cbs;
+ uint8_t key_update_request;
+ CBS_init(&cbs, ssl->init_msg, ssl->init_num);
+ if (!CBS_get_u8(&cbs, &key_update_request) ||
+ CBS_len(&cbs) != 0 ||
+ (key_update_request != SSL_KEY_UPDATE_NOT_REQUESTED &&
+ key_update_request != SSL_KEY_UPDATE_REQUESTED)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ return 0;
+ }
+
+ /* TODO(svaldez): Send KeyUpdate if |key_update_request| is
+ * |SSL_KEY_UPDATE_REQUESTED|. */
+ return tls13_rotate_traffic_key(ssl, evp_aead_open);
+}
+
+int tls13_post_handshake(SSL *ssl) {
+ if (ssl->s3->tmp.message_type == SSL3_MT_KEY_UPDATE) {
+ ssl->s3->key_update_count++;
+ if (ssl->s3->key_update_count > kMaxKeyUpdates) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_TOO_MANY_KEY_UPDATES);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
+ return 0;
+ }
+
+ return tls13_receive_key_update(ssl);
+ }
+
+ ssl->s3->key_update_count = 0;
+
+ if (ssl->s3->tmp.message_type == SSL3_MT_NEW_SESSION_TICKET &&
+ !ssl->server) {
+ return tls13_process_new_session_ticket(ssl);
+ }
+
+ // TODO(svaldez): Handle post-handshake authentication.
+
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE);
+ return 0;
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/tls13_client.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/tls13_client.c
new file mode 100644
index 000000000..f13a4f780
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/tls13_client.c
@@ -0,0 +1,686 @@
+/* Copyright (c) 2016, 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 <openssl/ssl.h>
+
+#include <assert.h>
+#include <limits.h>
+#include <string.h>
+
+#include <openssl/bytestring.h>
+#include <openssl/digest.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/stack.h>
+
+#include "../crypto/internal.h"
+#include "internal.h"
+
+
+enum client_hs_state_t {
+ state_process_hello_retry_request = 0,
+ state_send_second_client_hello,
+ state_process_server_hello,
+ state_process_encrypted_extensions,
+ state_process_certificate_request,
+ state_process_server_certificate,
+ state_process_server_certificate_verify,
+ state_process_server_finished,
+ state_send_client_certificate,
+ state_send_client_certificate_verify,
+ state_complete_client_certificate_verify,
+ state_complete_second_flight,
+ state_done,
+};
+
+static const uint8_t kZeroes[EVP_MAX_MD_SIZE] = {0};
+
+static enum ssl_hs_wait_t do_process_hello_retry_request(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ if (ssl->s3->tmp.message_type != SSL3_MT_HELLO_RETRY_REQUEST) {
+ hs->tls13_state = state_process_server_hello;
+ return ssl_hs_ok;
+ }
+
+ CBS cbs, extensions;
+ uint16_t server_wire_version;
+ CBS_init(&cbs, ssl->init_msg, ssl->init_num);
+ if (!CBS_get_u16(&cbs, &server_wire_version) ||
+ !CBS_get_u16_length_prefixed(&cbs, &extensions) ||
+ /* HelloRetryRequest may not be empty. */
+ CBS_len(&extensions) == 0 ||
+ CBS_len(&cbs) != 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ return ssl_hs_error;
+ }
+
+ int have_cookie, have_key_share;
+ CBS cookie, key_share;
+ const SSL_EXTENSION_TYPE ext_types[] = {
+ {TLSEXT_TYPE_key_share, &have_key_share, &key_share},
+ {TLSEXT_TYPE_cookie, &have_cookie, &cookie},
+ };
+
+ uint8_t alert = SSL_AD_DECODE_ERROR;
+ if (!ssl_parse_extensions(&extensions, &alert, ext_types,
+ OPENSSL_ARRAY_SIZE(ext_types),
+ 0 /* reject unknown */)) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
+ return ssl_hs_error;
+ }
+
+ if (have_cookie) {
+ CBS cookie_value;
+ if (!CBS_get_u16_length_prefixed(&cookie, &cookie_value) ||
+ CBS_len(&cookie_value) == 0 ||
+ CBS_len(&cookie) != 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ return ssl_hs_error;
+ }
+
+ if (!CBS_stow(&cookie_value, &hs->cookie, &hs->cookie_len)) {
+ return ssl_hs_error;
+ }
+ }
+
+ if (have_key_share) {
+ uint16_t group_id;
+ if (!CBS_get_u16(&key_share, &group_id) || CBS_len(&key_share) != 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ return ssl_hs_error;
+ }
+
+ /* The group must be supported. */
+ const uint16_t *groups;
+ size_t groups_len;
+ tls1_get_grouplist(ssl, &groups, &groups_len);
+ int found = 0;
+ for (size_t i = 0; i < groups_len; i++) {
+ if (groups[i] == group_id) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE);
+ return ssl_hs_error;
+ }
+
+ /* Check that the HelloRetryRequest does not request the key share that
+ * was provided in the initial ClientHello. */
+ if (SSL_ECDH_CTX_get_id(&hs->ecdh_ctx) == group_id) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE);
+ return ssl_hs_error;
+ }
+
+ SSL_ECDH_CTX_cleanup(&hs->ecdh_ctx);
+ hs->retry_group = group_id;
+ }
+
+ if (!ssl_hash_current_message(hs)) {
+ return ssl_hs_error;
+ }
+
+ hs->received_hello_retry_request = 1;
+ hs->tls13_state = state_send_second_client_hello;
+ return ssl_hs_ok;
+}
+
+static enum ssl_hs_wait_t do_send_second_client_hello(SSL_HANDSHAKE *hs) {
+ if (!ssl_write_client_hello(hs)) {
+ return ssl_hs_error;
+ }
+
+ hs->tls13_state = state_process_server_hello;
+ return ssl_hs_flush_and_read_message;
+}
+
+static enum ssl_hs_wait_t do_process_server_hello(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ if (!ssl_check_message_type(ssl, SSL3_MT_SERVER_HELLO)) {
+ return ssl_hs_error;
+ }
+
+ CBS cbs, server_random, extensions;
+ uint16_t server_wire_version;
+ uint16_t cipher_suite;
+ CBS_init(&cbs, ssl->init_msg, ssl->init_num);
+ if (!CBS_get_u16(&cbs, &server_wire_version) ||
+ !CBS_get_bytes(&cbs, &server_random, SSL3_RANDOM_SIZE) ||
+ !CBS_get_u16(&cbs, &cipher_suite) ||
+ !CBS_get_u16_length_prefixed(&cbs, &extensions) ||
+ CBS_len(&cbs) != 0) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ return ssl_hs_error;
+ }
+
+ if (server_wire_version != ssl->version) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_VERSION_NUMBER);
+ return ssl_hs_error;
+ }
+
+ assert(ssl->s3->have_version);
+ OPENSSL_memcpy(ssl->s3->server_random, CBS_data(&server_random),
+ SSL3_RANDOM_SIZE);
+
+ const SSL_CIPHER *cipher = SSL_get_cipher_by_value(cipher_suite);
+ if (cipher == NULL) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CIPHER_RETURNED);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+ return ssl_hs_error;
+ }
+
+ /* Check if the cipher is a TLS 1.3 cipher. */
+ if (SSL_CIPHER_get_min_version(cipher) > ssl3_protocol_version(ssl) ||
+ SSL_CIPHER_get_max_version(cipher) < ssl3_protocol_version(ssl)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CIPHER_RETURNED);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+ return ssl_hs_error;
+ }
+
+ /* Parse out the extensions. */
+ int have_key_share = 0, have_pre_shared_key = 0;
+ CBS key_share, pre_shared_key;
+ const SSL_EXTENSION_TYPE ext_types[] = {
+ {TLSEXT_TYPE_key_share, &have_key_share, &key_share},
+ {TLSEXT_TYPE_pre_shared_key, &have_pre_shared_key, &pre_shared_key},
+ };
+
+ uint8_t alert = SSL_AD_DECODE_ERROR;
+ if (!ssl_parse_extensions(&extensions, &alert, ext_types,
+ OPENSSL_ARRAY_SIZE(ext_types),
+ 0 /* reject unknown */)) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
+ return ssl_hs_error;
+ }
+
+ alert = SSL_AD_DECODE_ERROR;
+ if (have_pre_shared_key) {
+ if (ssl->session == NULL) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION);
+ return ssl_hs_error;
+ }
+
+ if (!ssl_ext_pre_shared_key_parse_serverhello(hs, &alert,
+ &pre_shared_key)) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
+ return ssl_hs_error;
+ }
+
+ if (ssl->session->ssl_version != ssl->version) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_OLD_SESSION_VERSION_NOT_RETURNED);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+ return ssl_hs_error;
+ }
+
+ if (ssl->session->cipher->algorithm_prf != cipher->algorithm_prf) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_OLD_SESSION_PRF_HASH_MISMATCH);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+ return ssl_hs_error;
+ }
+
+ if (!ssl_session_is_context_valid(ssl, ssl->session)) {
+ /* This is actually a client application bug. */
+ OPENSSL_PUT_ERROR(SSL,
+ SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+ return ssl_hs_error;
+ }
+
+ ssl->s3->session_reused = 1;
+ /* Only authentication information carries over in TLS 1.3. */
+ hs->new_session = SSL_SESSION_dup(ssl->session, SSL_SESSION_DUP_AUTH_ONLY);
+ if (hs->new_session == NULL) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ return ssl_hs_error;
+ }
+ ssl_set_session(ssl, NULL);
+
+ /* Resumption incorporates fresh key material, so refresh the timeout. */
+ ssl_session_renew_timeout(ssl, hs->new_session,
+ ssl->session_ctx->session_psk_dhe_timeout);
+ } else if (!ssl_get_new_session(hs, 0)) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ return ssl_hs_error;
+ }
+
+ hs->new_session->cipher = cipher;
+ hs->new_cipher = cipher;
+
+ /* Store the initial negotiated ALPN in the session. */
+ if (ssl->s3->alpn_selected != NULL) {
+ hs->new_session->early_alpn =
+ BUF_memdup(ssl->s3->alpn_selected, ssl->s3->alpn_selected_len);
+ if (hs->new_session->early_alpn == NULL) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ return ssl_hs_error;
+ }
+ hs->new_session->early_alpn_len = ssl->s3->alpn_selected_len;
+ }
+
+ /* The PRF hash is now known. Set up the key schedule. */
+ if (!tls13_init_key_schedule(hs)) {
+ return ssl_hs_error;
+ }
+
+ /* Incorporate the PSK into the running secret. */
+ if (ssl->s3->session_reused) {
+ if (!tls13_advance_key_schedule(hs, hs->new_session->master_key,
+ hs->new_session->master_key_length)) {
+ return ssl_hs_error;
+ }
+ } else if (!tls13_advance_key_schedule(hs, kZeroes, hs->hash_len)) {
+ return ssl_hs_error;
+ }
+
+ if (!have_key_share) {
+ /* We do not support psk_ke and thus always require a key share. */
+ OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_KEY_SHARE);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_MISSING_EXTENSION);
+ return ssl_hs_error;
+ }
+
+ /* Resolve ECDHE and incorporate it into the secret. */
+ uint8_t *dhe_secret;
+ size_t dhe_secret_len;
+ alert = SSL_AD_DECODE_ERROR;
+ if (!ssl_ext_key_share_parse_serverhello(hs, &dhe_secret, &dhe_secret_len,
+ &alert, &key_share)) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
+ return ssl_hs_error;
+ }
+
+ if (!tls13_advance_key_schedule(hs, dhe_secret, dhe_secret_len)) {
+ OPENSSL_free(dhe_secret);
+ return ssl_hs_error;
+ }
+ OPENSSL_free(dhe_secret);
+
+ if (!ssl_hash_current_message(hs) ||
+ !tls13_derive_handshake_secrets(hs) ||
+ !tls13_set_traffic_key(ssl, evp_aead_open, hs->server_handshake_secret,
+ hs->hash_len) ||
+ !tls13_set_traffic_key(ssl, evp_aead_seal, hs->client_handshake_secret,
+ hs->hash_len)) {
+ return ssl_hs_error;
+ }
+
+ hs->tls13_state = state_process_encrypted_extensions;
+ return ssl_hs_read_message;
+}
+
+static enum ssl_hs_wait_t do_process_encrypted_extensions(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ if (!ssl_check_message_type(ssl, SSL3_MT_ENCRYPTED_EXTENSIONS)) {
+ return ssl_hs_error;
+ }
+
+ CBS cbs;
+ CBS_init(&cbs, ssl->init_msg, ssl->init_num);
+ if (!ssl_parse_serverhello_tlsext(hs, &cbs)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT);
+ return ssl_hs_error;
+ }
+ 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 ssl_hs_error;
+ }
+
+ if (!ssl_hash_current_message(hs)) {
+ return ssl_hs_error;
+ }
+
+ hs->tls13_state = state_process_certificate_request;
+ return ssl_hs_read_message;
+}
+
+static enum ssl_hs_wait_t do_process_certificate_request(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ /* CertificateRequest may only be sent in non-resumption handshakes. */
+ if (ssl->s3->session_reused) {
+ hs->tls13_state = state_process_server_finished;
+ return ssl_hs_ok;
+ }
+
+ /* CertificateRequest is optional. */
+ if (ssl->s3->tmp.message_type != SSL3_MT_CERTIFICATE_REQUEST) {
+ hs->tls13_state = state_process_server_certificate;
+ return ssl_hs_ok;
+ }
+
+ CBS cbs, context, supported_signature_algorithms;
+ CBS_init(&cbs, ssl->init_msg, ssl->init_num);
+ if (!CBS_get_u8_length_prefixed(&cbs, &context) ||
+ /* The request context is always empty during the handshake. */
+ CBS_len(&context) != 0 ||
+ !CBS_get_u16_length_prefixed(&cbs, &supported_signature_algorithms) ||
+ CBS_len(&supported_signature_algorithms) == 0 ||
+ !tls1_parse_peer_sigalgs(hs, &supported_signature_algorithms)) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ return ssl_hs_error;
+ }
+
+ uint8_t alert = SSL_AD_DECODE_ERROR;
+ STACK_OF(CRYPTO_BUFFER) *ca_names =
+ ssl_parse_client_CA_list(ssl, &alert, &cbs);
+ if (ca_names == NULL) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
+ return ssl_hs_error;
+ }
+
+ /* Ignore extensions. */
+ CBS extensions;
+ if (!CBS_get_u16_length_prefixed(&cbs, &extensions) ||
+ CBS_len(&cbs) != 0) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ sk_CRYPTO_BUFFER_pop_free(ca_names, CRYPTO_BUFFER_free);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ return ssl_hs_error;
+ }
+
+ hs->cert_request = 1;
+ sk_CRYPTO_BUFFER_pop_free(hs->ca_names, CRYPTO_BUFFER_free);
+ hs->ca_names = ca_names;
+ ssl->ctx->x509_method->hs_flush_cached_ca_names(hs);
+
+ if (!ssl_hash_current_message(hs)) {
+ return ssl_hs_error;
+ }
+
+ hs->tls13_state = state_process_server_certificate;
+ return ssl_hs_read_message;
+}
+
+static enum ssl_hs_wait_t do_process_server_certificate(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ if (!ssl_check_message_type(ssl, SSL3_MT_CERTIFICATE) ||
+ !tls13_process_certificate(hs, 0 /* certificate required */) ||
+ !ssl_hash_current_message(hs)) {
+ return ssl_hs_error;
+ }
+
+ hs->tls13_state = state_process_server_certificate_verify;
+ return ssl_hs_read_message;
+}
+
+static enum ssl_hs_wait_t do_process_server_certificate_verify(
+ SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ if (!ssl_check_message_type(ssl, SSL3_MT_CERTIFICATE_VERIFY) ||
+ !tls13_process_certificate_verify(hs) ||
+ !ssl_hash_current_message(hs)) {
+ return ssl_hs_error;
+ }
+
+ hs->tls13_state = state_process_server_finished;
+ return ssl_hs_read_message;
+}
+
+static enum ssl_hs_wait_t do_process_server_finished(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ if (!ssl_check_message_type(ssl, SSL3_MT_FINISHED) ||
+ !tls13_process_finished(hs) ||
+ !ssl_hash_current_message(hs) ||
+ /* Update the secret to the master secret and derive traffic keys. */
+ !tls13_advance_key_schedule(hs, kZeroes, hs->hash_len) ||
+ !tls13_derive_application_secrets(hs)) {
+ return ssl_hs_error;
+ }
+
+ ssl->method->received_flight(ssl);
+ hs->tls13_state = state_send_client_certificate;
+ return ssl_hs_ok;
+}
+
+static enum ssl_hs_wait_t do_send_client_certificate(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ /* The peer didn't request a certificate. */
+ if (!hs->cert_request) {
+ hs->tls13_state = state_complete_second_flight;
+ return ssl_hs_ok;
+ }
+
+ /* Call cert_cb to update the certificate. */
+ if (ssl->cert->cert_cb != NULL) {
+ int rv = ssl->cert->cert_cb(ssl, ssl->cert->cert_cb_arg);
+ if (rv == 0) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_CB_ERROR);
+ return ssl_hs_error;
+ }
+ if (rv < 0) {
+ hs->tls13_state = state_send_client_certificate;
+ return ssl_hs_x509_lookup;
+ }
+ }
+
+ if (!ssl->ctx->x509_method->ssl_auto_chain_if_needed(ssl) ||
+ !tls13_add_certificate(hs)) {
+ return ssl_hs_error;
+ }
+
+ hs->tls13_state = state_send_client_certificate_verify;
+ return ssl_hs_ok;
+}
+
+static enum ssl_hs_wait_t do_send_client_certificate_verify(SSL_HANDSHAKE *hs,
+ int is_first_run) {
+ SSL *const ssl = hs->ssl;
+ /* Don't send CertificateVerify if there is no certificate. */
+ if (!ssl_has_certificate(ssl)) {
+ hs->tls13_state = state_complete_second_flight;
+ return ssl_hs_ok;
+ }
+
+ switch (tls13_add_certificate_verify(hs, is_first_run)) {
+ case ssl_private_key_success:
+ hs->tls13_state = state_complete_second_flight;
+ return ssl_hs_ok;
+
+ case ssl_private_key_retry:
+ hs->tls13_state = state_complete_client_certificate_verify;
+ return ssl_hs_private_key_operation;
+
+ case ssl_private_key_failure:
+ return ssl_hs_error;
+ }
+
+ assert(0);
+ return ssl_hs_error;
+}
+
+static enum ssl_hs_wait_t do_complete_second_flight(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+
+ /* Send a Channel ID assertion if necessary. */
+ if (ssl->s3->tlsext_channel_id_valid) {
+ if (!ssl_do_channel_id_callback(ssl)) {
+ hs->tls13_state = state_complete_second_flight;
+ return ssl_hs_error;
+ }
+
+ if (ssl->tlsext_channel_id_private == NULL) {
+ return ssl_hs_channel_id_lookup;
+ }
+
+ CBB cbb, body;
+ if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_CHANNEL_ID) ||
+ !tls1_write_channel_id(hs, &body) ||
+ !ssl_add_message_cbb(ssl, &cbb)) {
+ CBB_cleanup(&cbb);
+ return ssl_hs_error;
+ }
+ }
+
+ /* Send a Finished message. */
+ if (!tls13_add_finished(hs)) {
+ return ssl_hs_error;
+ }
+
+ /* Derive the final keys and enable them. */
+ if (!tls13_set_traffic_key(ssl, evp_aead_open, hs->server_traffic_secret_0,
+ hs->hash_len) ||
+ !tls13_set_traffic_key(ssl, evp_aead_seal, hs->client_traffic_secret_0,
+ hs->hash_len) ||
+ !tls13_derive_resumption_secret(hs)) {
+ return ssl_hs_error;
+ }
+
+ hs->tls13_state = state_done;
+ return ssl_hs_flush;
+}
+
+enum ssl_hs_wait_t tls13_client_handshake(SSL_HANDSHAKE *hs) {
+ while (hs->tls13_state != state_done) {
+ enum ssl_hs_wait_t ret = ssl_hs_error;
+ enum client_hs_state_t state = hs->tls13_state;
+ switch (state) {
+ case state_process_hello_retry_request:
+ ret = do_process_hello_retry_request(hs);
+ break;
+ case state_send_second_client_hello:
+ ret = do_send_second_client_hello(hs);
+ break;
+ case state_process_server_hello:
+ ret = do_process_server_hello(hs);
+ break;
+ case state_process_encrypted_extensions:
+ ret = do_process_encrypted_extensions(hs);
+ break;
+ case state_process_certificate_request:
+ ret = do_process_certificate_request(hs);
+ break;
+ case state_process_server_certificate:
+ ret = do_process_server_certificate(hs);
+ break;
+ case state_process_server_certificate_verify:
+ ret = do_process_server_certificate_verify(hs);
+ break;
+ case state_process_server_finished:
+ ret = do_process_server_finished(hs);
+ break;
+ case state_send_client_certificate:
+ ret = do_send_client_certificate(hs);
+ break;
+ case state_send_client_certificate_verify:
+ ret = do_send_client_certificate_verify(hs, 1 /* first run */);
+ break;
+ case state_complete_client_certificate_verify:
+ ret = do_send_client_certificate_verify(hs, 0 /* complete */);
+ break;
+ case state_complete_second_flight:
+ ret = do_complete_second_flight(hs);
+ break;
+ case state_done:
+ ret = ssl_hs_ok;
+ break;
+ }
+
+ if (ret != ssl_hs_ok) {
+ return ret;
+ }
+ }
+
+ return ssl_hs_ok;
+}
+
+int tls13_process_new_session_ticket(SSL *ssl) {
+ int ret = 0;
+ SSL_SESSION *session = SSL_SESSION_dup(ssl->s3->established_session,
+ SSL_SESSION_INCLUDE_NONAUTH);
+ if (session == NULL) {
+ return 0;
+ }
+
+ ssl_session_rebase_time(ssl, session);
+
+ uint32_t server_timeout;
+ CBS cbs, ticket, extensions;
+ CBS_init(&cbs, ssl->init_msg, ssl->init_num);
+ if (!CBS_get_u32(&cbs, &server_timeout) ||
+ !CBS_get_u32(&cbs, &session->ticket_age_add) ||
+ !CBS_get_u16_length_prefixed(&cbs, &ticket) ||
+ !CBS_stow(&ticket, &session->tlsext_tick, &session->tlsext_ticklen) ||
+ !CBS_get_u16_length_prefixed(&cbs, &extensions) ||
+ CBS_len(&cbs) != 0) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ goto err;
+ }
+
+ /* Cap the renewable lifetime by the server advertised value. This avoids
+ * wasting bandwidth on 0-RTT when we know the server will reject it. */
+ if (session->timeout > server_timeout) {
+ session->timeout = server_timeout;
+ }
+
+ /* Parse out the extensions. */
+ int have_early_data_info = 0;
+ CBS early_data_info;
+ const SSL_EXTENSION_TYPE ext_types[] = {
+ {TLSEXT_TYPE_ticket_early_data_info, &have_early_data_info,
+ &early_data_info},
+ };
+
+ uint8_t alert = SSL_AD_DECODE_ERROR;
+ if (!ssl_parse_extensions(&extensions, &alert, ext_types,
+ OPENSSL_ARRAY_SIZE(ext_types),
+ 1 /* ignore unknown */)) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
+ goto err;
+ }
+
+ if (have_early_data_info && ssl->ctx->enable_early_data) {
+ if (!CBS_get_u32(&early_data_info, &session->ticket_max_early_data) ||
+ CBS_len(&early_data_info) != 0) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ goto err;
+ }
+ }
+
+ session->ticket_age_add_valid = 1;
+ session->not_resumable = 0;
+
+ if (ssl->ctx->new_session_cb != NULL &&
+ ssl->ctx->new_session_cb(ssl, session)) {
+ /* |new_session_cb|'s return value signals that it took ownership. */
+ session = NULL;
+ }
+
+ ret = 1;
+
+err:
+ SSL_SESSION_free(session);
+ return ret;
+}
+
+void ssl_clear_tls13_state(SSL_HANDSHAKE *hs) {
+ SSL_ECDH_CTX_cleanup(&hs->ecdh_ctx);
+
+ OPENSSL_free(hs->key_share_bytes);
+ hs->key_share_bytes = NULL;
+ hs->key_share_bytes_len = 0;
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/tls13_enc.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/tls13_enc.c
new file mode 100644
index 000000000..412705da8
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/tls13_enc.c
@@ -0,0 +1,430 @@
+/* Copyright (c) 2016, 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 <openssl/ssl.h>
+
+#include <assert.h>
+#include <string.h>
+
+#include <openssl/aead.h>
+#include <openssl/bytestring.h>
+#include <openssl/digest.h>
+#include <openssl/hkdf.h>
+#include <openssl/hmac.h>
+#include <openssl/mem.h>
+
+#include "../crypto/internal.h"
+#include "internal.h"
+
+
+int tls13_init_key_schedule(SSL_HANDSHAKE *hs) {
+ if (!SSL_TRANSCRIPT_init_hash(&hs->transcript, ssl3_protocol_version(hs->ssl),
+ hs->new_cipher->algorithm_prf)) {
+ return 0;
+ }
+
+
+ hs->hash_len = SSL_TRANSCRIPT_digest_len(&hs->transcript);
+
+ /* Initialize the secret to the zero key. */
+ OPENSSL_memset(hs->secret, 0, hs->hash_len);
+
+ SSL_TRANSCRIPT_free_buffer(&hs->transcript);
+ return 1;
+}
+
+int tls13_advance_key_schedule(SSL_HANDSHAKE *hs, const uint8_t *in,
+ size_t len) {
+ return HKDF_extract(hs->secret, &hs->hash_len,
+ SSL_TRANSCRIPT_md(&hs->transcript), in, len, hs->secret,
+ hs->hash_len);
+}
+
+static int hkdf_expand_label(uint8_t *out, const EVP_MD *digest,
+ const uint8_t *secret, size_t secret_len,
+ const uint8_t *label, size_t label_len,
+ const uint8_t *hash, size_t hash_len, size_t len) {
+ static const char kTLS13LabelVersion[] = "TLS 1.3, ";
+
+ CBB cbb, child;
+ uint8_t *hkdf_label;
+ size_t hkdf_label_len;
+ if (!CBB_init(&cbb, 2 + 1 + strlen(kTLS13LabelVersion) + label_len + 1 +
+ hash_len) ||
+ !CBB_add_u16(&cbb, len) ||
+ !CBB_add_u8_length_prefixed(&cbb, &child) ||
+ !CBB_add_bytes(&child, (const uint8_t *)kTLS13LabelVersion,
+ strlen(kTLS13LabelVersion)) ||
+ !CBB_add_bytes(&child, label, label_len) ||
+ !CBB_add_u8_length_prefixed(&cbb, &child) ||
+ !CBB_add_bytes(&child, hash, hash_len) ||
+ !CBB_finish(&cbb, &hkdf_label, &hkdf_label_len)) {
+ CBB_cleanup(&cbb);
+ return 0;
+ }
+
+ int ret = HKDF_expand(out, len, digest, secret, secret_len, hkdf_label,
+ hkdf_label_len);
+ OPENSSL_free(hkdf_label);
+ return ret;
+}
+
+/* derive_secret derives a secret of length |len| and writes the result in |out|
+ * with the given label and the current base secret and most recently-saved
+ * handshake context. It returns one on success and zero on error. */
+static int derive_secret(SSL_HANDSHAKE *hs, uint8_t *out, size_t len,
+ const uint8_t *label, size_t label_len) {
+ uint8_t context_hash[EVP_MAX_MD_SIZE];
+ size_t context_hash_len;
+ if (!SSL_TRANSCRIPT_get_hash(&hs->transcript, context_hash,
+ &context_hash_len)) {
+ return 0;
+ }
+
+ return hkdf_expand_label(out, SSL_TRANSCRIPT_md(&hs->transcript), hs->secret,
+ hs->hash_len, label, label_len, context_hash,
+ context_hash_len, len);
+}
+
+int tls13_set_traffic_key(SSL *ssl, enum evp_aead_direction_t direction,
+ const uint8_t *traffic_secret,
+ size_t traffic_secret_len) {
+ if (traffic_secret_len > 0xff) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
+ return 0;
+ }
+
+ /* Look up cipher suite properties. */
+ const EVP_AEAD *aead;
+ size_t discard;
+ if (!ssl_cipher_get_evp_aead(&aead, &discard, &discard,
+ SSL_get_session(ssl)->cipher,
+ ssl3_protocol_version(ssl))) {
+ return 0;
+ }
+
+ const EVP_MD *digest = ssl_get_handshake_digest(
+ SSL_get_session(ssl)->cipher->algorithm_prf, ssl3_protocol_version(ssl));
+
+ /* Derive the key. */
+ size_t key_len = EVP_AEAD_key_length(aead);
+ uint8_t key[EVP_AEAD_MAX_KEY_LENGTH];
+ if (!hkdf_expand_label(key, digest, traffic_secret, traffic_secret_len,
+ (const uint8_t *)"key", 3, NULL, 0, key_len)) {
+ return 0;
+ }
+
+ /* Derive the IV. */
+ size_t iv_len = EVP_AEAD_nonce_length(aead);
+ uint8_t iv[EVP_AEAD_MAX_NONCE_LENGTH];
+ if (!hkdf_expand_label(iv, digest, traffic_secret, traffic_secret_len,
+ (const uint8_t *)"iv", 2, NULL, 0, iv_len)) {
+ return 0;
+ }
+
+ SSL_AEAD_CTX *traffic_aead = SSL_AEAD_CTX_new(
+ direction, ssl3_protocol_version(ssl), SSL_get_session(ssl)->cipher, key,
+ key_len, NULL, 0, iv, iv_len);
+ if (traffic_aead == NULL) {
+ return 0;
+ }
+
+ if (direction == evp_aead_open) {
+ if (!ssl->method->set_read_state(ssl, traffic_aead)) {
+ return 0;
+ }
+ } else {
+ if (!ssl->method->set_write_state(ssl, traffic_aead)) {
+ return 0;
+ }
+ }
+
+ /* Save the traffic secret. */
+ if (direction == evp_aead_open) {
+ OPENSSL_memmove(ssl->s3->read_traffic_secret, traffic_secret,
+ traffic_secret_len);
+ ssl->s3->read_traffic_secret_len = traffic_secret_len;
+ } else {
+ OPENSSL_memmove(ssl->s3->write_traffic_secret, traffic_secret,
+ traffic_secret_len);
+ ssl->s3->write_traffic_secret_len = traffic_secret_len;
+ }
+
+ return 1;
+}
+
+static const char kTLS13LabelClientHandshakeTraffic[] =
+ "client handshake traffic secret";
+static const char kTLS13LabelServerHandshakeTraffic[] =
+ "server handshake traffic secret";
+static const char kTLS13LabelClientApplicationTraffic[] =
+ "client application traffic secret";
+static const char kTLS13LabelServerApplicationTraffic[] =
+ "server application traffic secret";
+
+int tls13_derive_handshake_secrets(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ return derive_secret(hs, hs->client_handshake_secret, hs->hash_len,
+ (const uint8_t *)kTLS13LabelClientHandshakeTraffic,
+ strlen(kTLS13LabelClientHandshakeTraffic)) &&
+ ssl_log_secret(ssl, "CLIENT_HANDSHAKE_TRAFFIC_SECRET",
+ hs->client_handshake_secret, hs->hash_len) &&
+ derive_secret(hs, hs->server_handshake_secret, hs->hash_len,
+ (const uint8_t *)kTLS13LabelServerHandshakeTraffic,
+ strlen(kTLS13LabelServerHandshakeTraffic)) &&
+ ssl_log_secret(ssl, "SERVER_HANDSHAKE_TRAFFIC_SECRET",
+ hs->server_handshake_secret, hs->hash_len);
+}
+
+static const char kTLS13LabelExporter[] = "exporter master secret";
+
+int tls13_derive_application_secrets(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ ssl->s3->exporter_secret_len = hs->hash_len;
+ return derive_secret(hs, hs->client_traffic_secret_0, hs->hash_len,
+ (const uint8_t *)kTLS13LabelClientApplicationTraffic,
+ strlen(kTLS13LabelClientApplicationTraffic)) &&
+ ssl_log_secret(ssl, "CLIENT_TRAFFIC_SECRET_0",
+ hs->client_traffic_secret_0, hs->hash_len) &&
+ derive_secret(hs, hs->server_traffic_secret_0, hs->hash_len,
+ (const uint8_t *)kTLS13LabelServerApplicationTraffic,
+ strlen(kTLS13LabelServerApplicationTraffic)) &&
+ ssl_log_secret(ssl, "SERVER_TRAFFIC_SECRET_0",
+ hs->server_traffic_secret_0, hs->hash_len) &&
+ derive_secret(hs, ssl->s3->exporter_secret, hs->hash_len,
+ (const uint8_t *)kTLS13LabelExporter,
+ strlen(kTLS13LabelExporter));
+}
+
+static const char kTLS13LabelApplicationTraffic[] =
+ "application traffic secret";
+
+int tls13_rotate_traffic_key(SSL *ssl, enum evp_aead_direction_t direction) {
+ const EVP_MD *digest = ssl_get_handshake_digest(
+ SSL_get_session(ssl)->cipher->algorithm_prf, ssl3_protocol_version(ssl));
+
+ uint8_t *secret;
+ size_t secret_len;
+ if (direction == evp_aead_open) {
+ secret = ssl->s3->read_traffic_secret;
+ secret_len = ssl->s3->read_traffic_secret_len;
+ } else {
+ secret = ssl->s3->write_traffic_secret;
+ secret_len = ssl->s3->write_traffic_secret_len;
+ }
+
+ if (!hkdf_expand_label(secret, digest, secret, secret_len,
+ (const uint8_t *)kTLS13LabelApplicationTraffic,
+ strlen(kTLS13LabelApplicationTraffic), NULL, 0,
+ secret_len)) {
+ return 0;
+ }
+
+ return tls13_set_traffic_key(ssl, direction, secret, secret_len);
+}
+
+static const char kTLS13LabelResumption[] = "resumption master secret";
+
+int tls13_derive_resumption_secret(SSL_HANDSHAKE *hs) {
+ if (hs->hash_len > SSL_MAX_MASTER_KEY_LENGTH) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ hs->new_session->master_key_length = hs->hash_len;
+ return derive_secret(
+ hs, hs->new_session->master_key, hs->new_session->master_key_length,
+ (const uint8_t *)kTLS13LabelResumption, strlen(kTLS13LabelResumption));
+}
+
+static const char kTLS13LabelFinished[] = "finished";
+
+/* tls13_verify_data sets |out| to be the HMAC of |context| using a derived
+ * Finished key for both Finished messages and the PSK binder. */
+static int tls13_verify_data(const EVP_MD *digest, uint8_t *out,
+ size_t *out_len, const uint8_t *secret,
+ size_t hash_len, uint8_t *context,
+ size_t context_len) {
+ uint8_t key[EVP_MAX_MD_SIZE];
+ unsigned len;
+ if (!hkdf_expand_label(key, digest, secret, hash_len,
+ (const uint8_t *)kTLS13LabelFinished,
+ strlen(kTLS13LabelFinished), NULL, 0, hash_len) ||
+ HMAC(digest, key, hash_len, context, context_len, out, &len) == NULL) {
+ return 0;
+ }
+ *out_len = len;
+ return 1;
+}
+
+int tls13_finished_mac(SSL_HANDSHAKE *hs, uint8_t *out, size_t *out_len,
+ int is_server) {
+ SSL *const ssl = hs->ssl;
+
+ const uint8_t *traffic_secret;
+ if (is_server == ssl->server) {
+ traffic_secret = ssl->s3->write_traffic_secret;
+ } else {
+ traffic_secret = ssl->s3->read_traffic_secret;
+ }
+
+ uint8_t context_hash[EVP_MAX_MD_SIZE];
+ size_t context_hash_len;
+ if (!SSL_TRANSCRIPT_get_hash(&hs->transcript, context_hash,
+ &context_hash_len) ||
+ !tls13_verify_data(SSL_TRANSCRIPT_md(&hs->transcript), out, out_len,
+ traffic_secret, hs->hash_len, context_hash,
+ context_hash_len)) {
+ return 0;
+ }
+ return 1;
+}
+
+int tls13_export_keying_material(SSL *ssl, uint8_t *out, size_t out_len,
+ const char *label, size_t label_len,
+ const uint8_t *context, size_t context_len,
+ int use_context) {
+ const EVP_MD *digest = ssl_get_handshake_digest(
+ SSL_get_session(ssl)->cipher->algorithm_prf, ssl3_protocol_version(ssl));
+
+ const uint8_t *hash = NULL;
+ size_t hash_len = 0;
+ if (use_context) {
+ hash = context;
+ hash_len = context_len;
+ }
+ return hkdf_expand_label(out, digest, ssl->s3->exporter_secret,
+ ssl->s3->exporter_secret_len, (const uint8_t *)label,
+ label_len, hash, hash_len, out_len);
+}
+
+static const char kTLS13LabelPSKBinder[] = "resumption psk binder key";
+
+static int tls13_psk_binder(uint8_t *out, const EVP_MD *digest, uint8_t *psk,
+ size_t psk_len, uint8_t *context,
+ size_t context_len, size_t hash_len) {
+ uint8_t binder_context[EVP_MAX_MD_SIZE];
+ unsigned binder_context_len;
+ if (!EVP_Digest(NULL, 0, binder_context, &binder_context_len, digest, NULL)) {
+ return 0;
+ }
+
+ uint8_t early_secret[EVP_MAX_MD_SIZE] = {0};
+ size_t early_secret_len;
+ if (!HKDF_extract(early_secret, &early_secret_len, digest, psk, hash_len,
+ NULL, 0)) {
+ return 0;
+ }
+
+ uint8_t binder_key[EVP_MAX_MD_SIZE] = {0};
+ size_t len;
+ if (!hkdf_expand_label(binder_key, digest, early_secret, hash_len,
+ (const uint8_t *)kTLS13LabelPSKBinder,
+ strlen(kTLS13LabelPSKBinder), binder_context,
+ binder_context_len, hash_len) ||
+ !tls13_verify_data(digest, out, &len, binder_key, hash_len, context,
+ context_len)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+int tls13_write_psk_binder(SSL_HANDSHAKE *hs, uint8_t *msg, size_t len) {
+ SSL *const ssl = hs->ssl;
+ const EVP_MD *digest = SSL_SESSION_get_digest(ssl->session, ssl);
+ if (digest == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+ size_t hash_len = EVP_MD_size(digest);
+
+ if (len < hash_len + 3) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ EVP_MD_CTX ctx;
+ EVP_MD_CTX_init(&ctx);
+ uint8_t context[EVP_MAX_MD_SIZE];
+ unsigned context_len;
+ if (!EVP_DigestInit_ex(&ctx, digest, NULL) ||
+ !EVP_DigestUpdate(&ctx, hs->transcript.buffer->data,
+ hs->transcript.buffer->length) ||
+ !EVP_DigestUpdate(&ctx, msg, len - hash_len - 3) ||
+ !EVP_DigestFinal_ex(&ctx, context, &context_len)) {
+ EVP_MD_CTX_cleanup(&ctx);
+ return 0;
+ }
+
+ EVP_MD_CTX_cleanup(&ctx);
+
+ uint8_t verify_data[EVP_MAX_MD_SIZE] = {0};
+ if (!tls13_psk_binder(verify_data, digest, ssl->session->master_key,
+ ssl->session->master_key_length, context, context_len,
+ hash_len)) {
+ return 0;
+ }
+
+ OPENSSL_memcpy(msg + len - hash_len, verify_data, hash_len);
+ return 1;
+}
+
+int tls13_verify_psk_binder(SSL_HANDSHAKE *hs, SSL_SESSION *session,
+ CBS *binders) {
+ size_t hash_len = SSL_TRANSCRIPT_digest_len(&hs->transcript);
+
+ /* Get the full ClientHello, including message header. It must be large enough
+ * to exclude the binders. */
+ CBS message;
+ hs->ssl->method->get_current_message(hs->ssl, &message);
+ if (CBS_len(&message) < CBS_len(binders) + 2) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ /* Hash a ClientHello prefix up to the binders. For now, this assumes we only
+ * ever verify PSK binders on initial ClientHellos. */
+ uint8_t context[EVP_MAX_MD_SIZE];
+ unsigned context_len;
+ if (!EVP_Digest(CBS_data(&message), CBS_len(&message) - CBS_len(binders) - 2,
+ context, &context_len, SSL_TRANSCRIPT_md(&hs->transcript),
+ NULL)) {
+ return 0;
+ }
+
+ uint8_t verify_data[EVP_MAX_MD_SIZE] = {0};
+ CBS binder;
+ if (!tls13_psk_binder(verify_data, SSL_TRANSCRIPT_md(&hs->transcript),
+ session->master_key, session->master_key_length,
+ context, context_len, hash_len) ||
+ /* We only consider the first PSK, so compare against the first binder. */
+ !CBS_get_u8_length_prefixed(binders, &binder)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ int binder_ok =
+ CBS_len(&binder) == hash_len &&
+ CRYPTO_memcmp(CBS_data(&binder), verify_data, hash_len) == 0;
+#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+ binder_ok = 1;
+#endif
+ if (!binder_ok) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DIGEST_CHECK_FAILED);
+ return 0;
+ }
+
+ return 1;
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/tls13_server.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/tls13_server.c
new file mode 100644
index 000000000..9c8d1a15d
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/tls13_server.c
@@ -0,0 +1,753 @@
+/* Copyright (c) 2016, 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 <openssl/ssl.h>
+
+#include <assert.h>
+#include <string.h>
+
+#include <openssl/aead.h>
+#include <openssl/bytestring.h>
+#include <openssl/digest.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/rand.h>
+#include <openssl/stack.h>
+
+#include "../crypto/internal.h"
+#include "internal.h"
+
+
+/* kMaxEarlyDataAccepted is the advertised number of plaintext bytes of early
+ * data that will be accepted. This value should be slightly below
+ * kMaxEarlyDataSkipped in tls_record.c, which is measured in ciphertext. */
+static const size_t kMaxEarlyDataAccepted = 14336;
+
+enum server_hs_state_t {
+ state_select_parameters = 0,
+ state_select_session,
+ state_send_hello_retry_request,
+ state_process_second_client_hello,
+ state_send_server_hello,
+ state_send_server_certificate_verify,
+ state_complete_server_certificate_verify,
+ state_send_server_finished,
+ state_process_client_certificate,
+ state_process_client_certificate_verify,
+ state_process_channel_id,
+ state_process_client_finished,
+ state_send_new_session_ticket,
+ state_done,
+};
+
+static const uint8_t kZeroes[EVP_MAX_MD_SIZE] = {0};
+
+static int resolve_ecdhe_secret(SSL_HANDSHAKE *hs, int *out_need_retry,
+ SSL_CLIENT_HELLO *client_hello) {
+ SSL *const ssl = hs->ssl;
+ *out_need_retry = 0;
+
+ /* We only support connections that include an ECDHE key exchange. */
+ CBS key_share;
+ if (!ssl_client_hello_get_extension(client_hello, &key_share,
+ TLSEXT_TYPE_key_share)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_KEY_SHARE);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_MISSING_EXTENSION);
+ return 0;
+ }
+
+ int found_key_share;
+ uint8_t *dhe_secret;
+ size_t dhe_secret_len;
+ uint8_t alert = SSL_AD_DECODE_ERROR;
+ if (!ssl_ext_key_share_parse_clienthello(hs, &found_key_share, &dhe_secret,
+ &dhe_secret_len, &alert,
+ &key_share)) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
+ return 0;
+ }
+
+ if (!found_key_share) {
+ *out_need_retry = 1;
+ return 0;
+ }
+
+ int ok = tls13_advance_key_schedule(hs, dhe_secret, dhe_secret_len);
+ OPENSSL_free(dhe_secret);
+ return ok;
+}
+
+static const SSL_CIPHER *choose_tls13_cipher(
+ const SSL *ssl, const SSL_CLIENT_HELLO *client_hello) {
+ if (client_hello->cipher_suites_len % 2 != 0) {
+ return NULL;
+ }
+
+ CBS cipher_suites;
+ CBS_init(&cipher_suites, client_hello->cipher_suites,
+ client_hello->cipher_suites_len);
+
+ const int aes_is_fine = EVP_has_aes_hardware();
+ const uint16_t version = ssl3_protocol_version(ssl);
+
+ const SSL_CIPHER *best = NULL;
+ while (CBS_len(&cipher_suites) > 0) {
+ uint16_t cipher_suite;
+ if (!CBS_get_u16(&cipher_suites, &cipher_suite)) {
+ return NULL;
+ }
+
+ /* Limit to TLS 1.3 ciphers we know about. */
+ const SSL_CIPHER *candidate = SSL_get_cipher_by_value(cipher_suite);
+ if (candidate == NULL ||
+ SSL_CIPHER_get_min_version(candidate) > version ||
+ SSL_CIPHER_get_max_version(candidate) < version) {
+ continue;
+ }
+
+ /* TLS 1.3 removes legacy ciphers, so honor the client order, but prefer
+ * ChaCha20 if we do not have AES hardware. */
+ if (aes_is_fine) {
+ return candidate;
+ }
+
+ if (candidate->algorithm_enc == SSL_CHACHA20POLY1305) {
+ return candidate;
+ }
+
+ if (best == NULL) {
+ best = candidate;
+ }
+ }
+
+ return best;
+}
+
+static enum ssl_hs_wait_t do_select_parameters(SSL_HANDSHAKE *hs) {
+ /* At this point, most ClientHello extensions have already been processed by
+ * the common handshake logic. Resolve the remaining non-PSK parameters. */
+ SSL *const ssl = hs->ssl;
+
+ SSL_CLIENT_HELLO client_hello;
+ if (!ssl_client_hello_init(ssl, &client_hello, ssl->init_msg,
+ ssl->init_num)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CLIENTHELLO_PARSE_FAILED);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ return ssl_hs_error;
+ }
+
+ /* Negotiate the cipher suite. */
+ hs->new_cipher = choose_tls13_cipher(ssl, &client_hello);
+ if (hs->new_cipher == NULL) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_SHARED_CIPHER);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
+ return ssl_hs_error;
+ }
+
+ /* HTTP/2 negotiation depends on the cipher suite, so ALPN negotiation was
+ * deferred. Complete it now. */
+ uint8_t alert = SSL_AD_DECODE_ERROR;
+ if (!ssl_negotiate_alpn(hs, &alert, &client_hello)) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
+ return ssl_hs_error;
+ }
+
+ /* The PRF hash is now known. Set up the key schedule and hash the
+ * ClientHello. */
+ if (!tls13_init_key_schedule(hs) ||
+ !ssl_hash_current_message(hs)) {
+ return ssl_hs_error;
+ }
+
+ hs->tls13_state = state_select_session;
+ return ssl_hs_ok;
+}
+
+static enum ssl_ticket_aead_result_t select_session(
+ SSL_HANDSHAKE *hs, uint8_t *out_alert, SSL_SESSION **out_session,
+ int32_t *out_ticket_age_skew, const SSL_CLIENT_HELLO *client_hello) {
+ SSL *const ssl = hs->ssl;
+ *out_session = NULL;
+
+ /* Decode the ticket if we agreed on a PSK key exchange mode. */
+ CBS pre_shared_key;
+ if (!hs->accept_psk_mode ||
+ !ssl_client_hello_get_extension(client_hello, &pre_shared_key,
+ TLSEXT_TYPE_pre_shared_key)) {
+ return ssl_ticket_aead_ignore_ticket;
+ }
+
+ /* Verify that the pre_shared_key extension is the last extension in
+ * ClientHello. */
+ if (CBS_data(&pre_shared_key) + CBS_len(&pre_shared_key) !=
+ client_hello->extensions + client_hello->extensions_len) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_PRE_SHARED_KEY_MUST_BE_LAST);
+ *out_alert = SSL_AD_ILLEGAL_PARAMETER;
+ return ssl_ticket_aead_error;
+ }
+
+ CBS ticket, binders;
+ uint32_t client_ticket_age;
+ if (!ssl_ext_pre_shared_key_parse_clienthello(hs, &ticket, &binders,
+ &client_ticket_age, out_alert,
+ &pre_shared_key)) {
+ return ssl_ticket_aead_error;
+ }
+
+ /* TLS 1.3 session tickets are renewed separately as part of the
+ * NewSessionTicket. */
+ int unused_renew;
+ SSL_SESSION *session = NULL;
+ enum ssl_ticket_aead_result_t ret =
+ ssl_process_ticket(ssl, &session, &unused_renew, CBS_data(&ticket),
+ CBS_len(&ticket), NULL, 0);
+ switch (ret) {
+ case ssl_ticket_aead_success:
+ break;
+ case ssl_ticket_aead_error:
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ return ret;
+ default:
+ return ret;
+ }
+
+ if (!ssl_session_is_resumable(hs, session) ||
+ /* 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;
+ }
+
+ /* Recover the client ticket age and convert to seconds. */
+ client_ticket_age -= session->ticket_age_add;
+ client_ticket_age /= 1000;
+
+ struct OPENSSL_timeval now;
+ ssl_get_current_time(ssl, &now);
+
+ /* Compute the server ticket age in seconds. */
+ assert(now.tv_sec >= session->time);
+ uint64_t server_ticket_age = now.tv_sec - session->time;
+
+ /* 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;
+ }
+
+ /* TODO(davidben,svaldez): Measure this value to decide on tolerance. For
+ * now, accept all values. https://crbug.com/boringssl/113. */
+ *out_ticket_age_skew =
+ (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);
+ *out_alert = SSL_AD_DECRYPT_ERROR;
+ return ssl_ticket_aead_error;
+ }
+
+ *out_session = session;
+ return ssl_ticket_aead_success;
+}
+
+static enum ssl_hs_wait_t do_select_session(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ SSL_CLIENT_HELLO client_hello;
+ if (!ssl_client_hello_init(ssl, &client_hello, ssl->init_msg,
+ ssl->init_num)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CLIENTHELLO_PARSE_FAILED);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ return ssl_hs_error;
+ }
+
+ uint8_t alert = SSL_AD_DECODE_ERROR;
+ SSL_SESSION *session = NULL;
+ switch (select_session(hs, &alert, &session, &ssl->s3->ticket_age_skew,
+ &client_hello)) {
+ case ssl_ticket_aead_ignore_ticket:
+ assert(session == NULL);
+ if (!ssl_get_new_session(hs, 1 /* server */)) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ return ssl_hs_error;
+ }
+ break;
+
+ 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);
+ SSL_SESSION_free(session);
+ if (hs->new_session == NULL) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ return ssl_hs_error;
+ }
+
+ ssl->s3->session_reused = 1;
+
+ /* Resumption incorporates fresh key material, so refresh the timeout. */
+ ssl_session_renew_timeout(ssl, hs->new_session,
+ ssl->session_ctx->session_psk_dhe_timeout);
+ break;
+
+ case ssl_ticket_aead_error:
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
+ return ssl_hs_error;
+
+ case ssl_ticket_aead_retry:
+ hs->tls13_state = state_select_session;
+ return ssl_hs_pending_ticket;
+ }
+
+ /* Record connection properties in the new session. */
+ hs->new_session->cipher = hs->new_cipher;
+
+ if (hs->hostname != NULL) {
+ OPENSSL_free(hs->new_session->tlsext_hostname);
+ hs->new_session->tlsext_hostname = BUF_strdup(hs->hostname);
+ if (hs->new_session->tlsext_hostname == NULL) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ return ssl_hs_error;
+ }
+ }
+
+ if (ssl->s3->alpn_selected != NULL) {
+ hs->new_session->early_alpn =
+ BUF_memdup(ssl->s3->alpn_selected, ssl->s3->alpn_selected_len);
+ if (hs->new_session->early_alpn == NULL) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ return ssl_hs_error;
+ }
+ hs->new_session->early_alpn_len = ssl->s3->alpn_selected_len;
+ }
+
+ if (ssl->ctx->dos_protection_cb != NULL &&
+ ssl->ctx->dos_protection_cb(&client_hello) == 0) {
+ /* Connection rejected for DOS reasons. */
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CONNECTION_REJECTED);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ return ssl_hs_error;
+ }
+
+ /* Incorporate the PSK into the running secret. */
+ if (ssl->s3->session_reused) {
+ if (!tls13_advance_key_schedule(hs, hs->new_session->master_key,
+ hs->new_session->master_key_length)) {
+ return ssl_hs_error;
+ }
+ } else if (!tls13_advance_key_schedule(hs, kZeroes, hs->hash_len)) {
+ return ssl_hs_error;
+ }
+
+ 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)) {
+ if (need_retry) {
+ hs->tls13_state = state_send_hello_retry_request;
+ return ssl_hs_ok;
+ }
+ return ssl_hs_error;
+ }
+
+ hs->tls13_state = state_send_server_hello;
+ return ssl_hs_ok;
+}
+
+static enum ssl_hs_wait_t do_send_hello_retry_request(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ CBB cbb, body, extensions;
+ uint16_t group_id;
+ if (!ssl->method->init_message(ssl, &cbb, &body,
+ SSL3_MT_HELLO_RETRY_REQUEST) ||
+ !CBB_add_u16(&body, ssl->version) ||
+ !tls1_get_shared_group(hs, &group_id) ||
+ !CBB_add_u16_length_prefixed(&body, &extensions) ||
+ !CBB_add_u16(&extensions, TLSEXT_TYPE_key_share) ||
+ !CBB_add_u16(&extensions, 2 /* length */) ||
+ !CBB_add_u16(&extensions, group_id) ||
+ !ssl_add_message_cbb(ssl, &cbb)) {
+ CBB_cleanup(&cbb);
+ return ssl_hs_error;
+ }
+
+ hs->tls13_state = state_process_second_client_hello;
+ return ssl_hs_flush_and_read_message;
+}
+
+static enum ssl_hs_wait_t do_process_second_client_hello(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ if (!ssl_check_message_type(ssl, SSL3_MT_CLIENT_HELLO)) {
+ return ssl_hs_error;
+ }
+
+ SSL_CLIENT_HELLO client_hello;
+ if (!ssl_client_hello_init(ssl, &client_hello, ssl->init_msg,
+ ssl->init_num)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CLIENTHELLO_PARSE_FAILED);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ return ssl_hs_error;
+ }
+
+ int need_retry;
+ if (!resolve_ecdhe_secret(hs, &need_retry, &client_hello)) {
+ if (need_retry) {
+ /* Only send one HelloRetryRequest. */
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE);
+ }
+ return ssl_hs_error;
+ }
+
+ if (!ssl_hash_current_message(hs)) {
+ return ssl_hs_error;
+ }
+
+ ssl->method->received_flight(ssl);
+ hs->tls13_state = state_send_server_hello;
+ return ssl_hs_ok;
+}
+
+static enum ssl_hs_wait_t do_send_server_hello(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+
+ /* Send a ServerHello. */
+ CBB cbb, body, extensions;
+ if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_SERVER_HELLO) ||
+ !CBB_add_u16(&body, ssl->version) ||
+ !RAND_bytes(ssl->s3->server_random, sizeof(ssl->s3->server_random)) ||
+ !CBB_add_bytes(&body, ssl->s3->server_random, SSL3_RANDOM_SIZE) ||
+ !CBB_add_u16(&body, ssl_cipher_get_value(hs->new_cipher)) ||
+ !CBB_add_u16_length_prefixed(&body, &extensions) ||
+ !ssl_ext_pre_shared_key_add_serverhello(hs, &extensions) ||
+ !ssl_ext_key_share_add_serverhello(hs, &extensions) ||
+ !ssl_add_message_cbb(ssl, &cbb)) {
+ goto err;
+ }
+
+ /* Derive and enable the handshake traffic secrets. */
+ if (!tls13_derive_handshake_secrets(hs) ||
+ !tls13_set_traffic_key(ssl, evp_aead_open, hs->client_handshake_secret,
+ hs->hash_len) ||
+ !tls13_set_traffic_key(ssl, evp_aead_seal, hs->server_handshake_secret,
+ hs->hash_len)) {
+ goto err;
+ }
+
+ /* Send EncryptedExtensions. */
+ if (!ssl->method->init_message(ssl, &cbb, &body,
+ SSL3_MT_ENCRYPTED_EXTENSIONS) ||
+ !ssl_add_serverhello_tlsext(hs, &body) ||
+ !ssl_add_message_cbb(ssl, &cbb)) {
+ goto err;
+ }
+
+ /* Determine whether to request a client certificate. */
+ hs->cert_request = !!(ssl->verify_mode & SSL_VERIFY_PEER);
+ /* CertificateRequest may only be sent in non-resumption handshakes. */
+ if (ssl->s3->session_reused) {
+ hs->cert_request = 0;
+ }
+
+ /* Send a CertificateRequest, if necessary. */
+ if (hs->cert_request) {
+ CBB sigalgs_cbb;
+ if (!ssl->method->init_message(ssl, &cbb, &body,
+ SSL3_MT_CERTIFICATE_REQUEST) ||
+ !CBB_add_u8(&body, 0 /* no certificate_request_context. */)) {
+ goto err;
+ }
+
+ const uint16_t *sigalgs;
+ size_t num_sigalgs = tls12_get_verify_sigalgs(ssl, &sigalgs);
+ if (!CBB_add_u16_length_prefixed(&body, &sigalgs_cbb)) {
+ goto err;
+ }
+
+ for (size_t i = 0; i < num_sigalgs; i++) {
+ if (!CBB_add_u16(&sigalgs_cbb, sigalgs[i])) {
+ goto err;
+ }
+ }
+
+ if (!ssl_add_client_CA_list(ssl, &body) ||
+ !CBB_add_u16(&body, 0 /* empty certificate_extensions. */) ||
+ !ssl_add_message_cbb(ssl, &cbb)) {
+ goto err;
+ }
+ }
+
+ /* Send the server Certificate message, if necessary. */
+ if (!ssl->s3->session_reused) {
+ if (!ssl_has_certificate(ssl)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATE_SET);
+ goto err;
+ }
+
+ if (!tls13_add_certificate(hs)) {
+ goto err;
+ }
+
+ hs->tls13_state = state_send_server_certificate_verify;
+ return ssl_hs_ok;
+ }
+
+ hs->tls13_state = state_send_server_finished;
+ return ssl_hs_ok;
+
+err:
+ CBB_cleanup(&cbb);
+ return ssl_hs_error;
+}
+
+static enum ssl_hs_wait_t do_send_server_certificate_verify(SSL_HANDSHAKE *hs,
+ int is_first_run) {
+ switch (tls13_add_certificate_verify(hs, is_first_run)) {
+ case ssl_private_key_success:
+ hs->tls13_state = state_send_server_finished;
+ return ssl_hs_ok;
+
+ case ssl_private_key_retry:
+ hs->tls13_state = state_complete_server_certificate_verify;
+ return ssl_hs_private_key_operation;
+
+ case ssl_private_key_failure:
+ return ssl_hs_error;
+ }
+
+ assert(0);
+ return ssl_hs_error;
+}
+
+static enum ssl_hs_wait_t do_send_server_finished(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ if (!tls13_add_finished(hs) ||
+ /* Update the secret to the master secret and derive traffic keys. */
+ !tls13_advance_key_schedule(hs, kZeroes, hs->hash_len) ||
+ !tls13_derive_application_secrets(hs) ||
+ !tls13_set_traffic_key(ssl, evp_aead_seal, hs->server_traffic_secret_0,
+ hs->hash_len)) {
+ return ssl_hs_error;
+ }
+
+ hs->tls13_state = state_process_client_certificate;
+ return ssl_hs_flush_and_read_message;
+}
+
+static enum ssl_hs_wait_t do_process_client_certificate(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ if (!hs->cert_request) {
+ /* OpenSSL returns X509_V_OK when no certificates are requested. This is
+ * classed by them as a bug, but it's assumed by at least NGINX. */
+ hs->new_session->verify_result = X509_V_OK;
+
+ /* Skip this state. */
+ hs->tls13_state = state_process_channel_id;
+ return ssl_hs_ok;
+ }
+
+ const int allow_anonymous =
+ (ssl->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) == 0;
+
+ if (!ssl_check_message_type(ssl, SSL3_MT_CERTIFICATE) ||
+ !tls13_process_certificate(hs, allow_anonymous) ||
+ !ssl_hash_current_message(hs)) {
+ return ssl_hs_error;
+ }
+
+ hs->tls13_state = state_process_client_certificate_verify;
+ return ssl_hs_read_message;
+}
+
+static enum ssl_hs_wait_t do_process_client_certificate_verify(
+ SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ if (sk_CRYPTO_BUFFER_num(hs->new_session->certs) == 0) {
+ /* Skip this state. */
+ hs->tls13_state = state_process_channel_id;
+ return ssl_hs_ok;
+ }
+
+ if (!ssl_check_message_type(ssl, SSL3_MT_CERTIFICATE_VERIFY) ||
+ !tls13_process_certificate_verify(hs) ||
+ !ssl_hash_current_message(hs)) {
+ return ssl_hs_error;
+ }
+
+ hs->tls13_state = state_process_channel_id;
+ return ssl_hs_read_message;
+}
+
+static enum ssl_hs_wait_t do_process_channel_id(SSL_HANDSHAKE *hs) {
+ if (!hs->ssl->s3->tlsext_channel_id_valid) {
+ hs->tls13_state = state_process_client_finished;
+ return ssl_hs_ok;
+ }
+
+ if (!ssl_check_message_type(hs->ssl, SSL3_MT_CHANNEL_ID) ||
+ !tls1_verify_channel_id(hs) ||
+ !ssl_hash_current_message(hs)) {
+ return ssl_hs_error;
+ }
+
+ hs->tls13_state = state_process_client_finished;
+ return ssl_hs_read_message;
+}
+
+static enum ssl_hs_wait_t do_process_client_finished(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ if (!ssl_check_message_type(ssl, SSL3_MT_FINISHED) ||
+ !tls13_process_finished(hs) ||
+ !ssl_hash_current_message(hs) ||
+ /* evp_aead_seal keys have already been switched. */
+ !tls13_set_traffic_key(ssl, evp_aead_open, hs->client_traffic_secret_0,
+ hs->hash_len) ||
+ !tls13_derive_resumption_secret(hs)) {
+ return ssl_hs_error;
+ }
+
+ ssl->method->received_flight(ssl);
+
+ /* Rebase the session timestamp so that it is measured from ticket
+ * issuance. */
+ ssl_session_rebase_time(ssl, hs->new_session);
+ hs->tls13_state = state_send_new_session_ticket;
+ return ssl_hs_ok;
+}
+
+static enum ssl_hs_wait_t do_send_new_session_ticket(SSL_HANDSHAKE *hs) {
+ /* TLS 1.3 recommends single-use tickets, so issue multiple tickets in case the
+ * client makes several connections before getting a renewal. */
+ static const int kNumTickets = 2;
+
+ SSL *const ssl = hs->ssl;
+ /* If the client doesn't accept resumption with PSK_DHE_KE, don't send a
+ * session ticket. */
+ if (!hs->accept_psk_mode) {
+ hs->tls13_state = state_done;
+ return ssl_hs_ok;
+ }
+
+ SSL_SESSION *session = hs->new_session;
+ CBB cbb;
+ CBB_zero(&cbb);
+
+ for (int i = 0; i < kNumTickets; i++) {
+ if (!RAND_bytes((uint8_t *)&session->ticket_age_add, 4)) {
+ goto err;
+ }
+ session->ticket_age_add_valid = 1;
+
+ CBB body, ticket, extensions;
+ if (!ssl->method->init_message(ssl, &cbb, &body,
+ SSL3_MT_NEW_SESSION_TICKET) ||
+ !CBB_add_u32(&body, session->timeout) ||
+ !CBB_add_u32(&body, session->ticket_age_add) ||
+ !CBB_add_u16_length_prefixed(&body, &ticket) ||
+ !ssl_encrypt_ticket(ssl, &ticket, session) ||
+ !CBB_add_u16_length_prefixed(&body, &extensions)) {
+ goto err;
+ }
+
+ if (ssl->ctx->enable_early_data) {
+ session->ticket_max_early_data = kMaxEarlyDataAccepted;
+
+ CBB early_data_info;
+ if (!CBB_add_u16(&extensions, TLSEXT_TYPE_ticket_early_data_info) ||
+ !CBB_add_u16_length_prefixed(&extensions, &early_data_info) ||
+ !CBB_add_u32(&early_data_info, session->ticket_max_early_data) ||
+ !CBB_flush(&extensions)) {
+ goto err;
+ }
+ }
+
+ /* Add a fake extension. See draft-davidben-tls-grease-01. */
+ if (!CBB_add_u16(&extensions,
+ ssl_get_grease_value(ssl, ssl_grease_ticket_extension)) ||
+ !CBB_add_u16(&extensions, 0 /* empty */)) {
+ goto err;
+ }
+
+ if (!ssl_add_message_cbb(ssl, &cbb)) {
+ goto err;
+ }
+ }
+
+ hs->session_tickets_sent++;
+ hs->tls13_state = state_done;
+ return ssl_hs_flush;
+
+err:
+ CBB_cleanup(&cbb);
+ return ssl_hs_error;
+}
+
+enum ssl_hs_wait_t tls13_server_handshake(SSL_HANDSHAKE *hs) {
+ while (hs->tls13_state != state_done) {
+ enum ssl_hs_wait_t ret = ssl_hs_error;
+ enum server_hs_state_t state = hs->tls13_state;
+ switch (state) {
+ case state_select_parameters:
+ ret = do_select_parameters(hs);
+ break;
+ case state_select_session:
+ ret = do_select_session(hs);
+ break;
+ case state_send_hello_retry_request:
+ ret = do_send_hello_retry_request(hs);
+ break;
+ case state_process_second_client_hello:
+ ret = do_process_second_client_hello(hs);
+ break;
+ case state_send_server_hello:
+ ret = do_send_server_hello(hs);
+ break;
+ case state_send_server_certificate_verify:
+ ret = do_send_server_certificate_verify(hs, 1 /* first run */);
+ break;
+ case state_complete_server_certificate_verify:
+ ret = do_send_server_certificate_verify(hs, 0 /* complete */);
+ break;
+ case state_send_server_finished:
+ ret = do_send_server_finished(hs);
+ break;
+ case state_process_client_certificate:
+ ret = do_process_client_certificate(hs);
+ break;
+ case state_process_client_certificate_verify:
+ ret = do_process_client_certificate_verify(hs);
+ break;
+ case state_process_channel_id:
+ ret = do_process_channel_id(hs);
+ break;
+ case state_process_client_finished:
+ ret = do_process_client_finished(hs);
+ break;
+ case state_send_new_session_ticket:
+ ret = do_send_new_session_ticket(hs);
+ break;
+ case state_done:
+ ret = ssl_hs_ok;
+ break;
+ }
+
+ if (ret != ssl_hs_ok) {
+ return ret;
+ }
+ }
+
+ return ssl_hs_ok;
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/tls_method.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/tls_method.c
new file mode 100644
index 000000000..6144f86c7
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/tls_method.c
@@ -0,0 +1,328 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#include <openssl/ssl.h>
+
+#include <assert.h>
+#include <string.h>
+
+#include <openssl/buf.h>
+
+#include "../crypto/internal.h"
+#include "internal.h"
+
+
+static int ssl3_version_from_wire(uint16_t *out_version,
+ uint16_t wire_version) {
+ switch (wire_version) {
+ case SSL3_VERSION:
+ case TLS1_VERSION:
+ case TLS1_1_VERSION:
+ case TLS1_2_VERSION:
+ *out_version = wire_version;
+ return 1;
+ case TLS1_3_DRAFT_VERSION:
+ *out_version = TLS1_3_VERSION;
+ return 1;
+ }
+
+ return 0;
+}
+
+static uint16_t ssl3_version_to_wire(uint16_t version) {
+ switch (version) {
+ case SSL3_VERSION:
+ case TLS1_VERSION:
+ case TLS1_1_VERSION:
+ case TLS1_2_VERSION:
+ return version;
+ case TLS1_3_VERSION:
+ return TLS1_3_DRAFT_VERSION;
+ }
+
+ /* It is an error to use this function with an invalid version. */
+ assert(0);
+ return 0;
+}
+
+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 int ssl3_set_read_state(SSL *ssl, SSL_AEAD_CTX *aead_ctx) {
+ if (ssl->s3->rrec.length != 0) {
+ /* There may not be unprocessed record data at a cipher change. */
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFERED_MESSAGES_ON_CIPHER_CHANGE);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
+ SSL_AEAD_CTX_free(aead_ctx);
+ return 0;
+ }
+
+ OPENSSL_memset(ssl->s3->read_sequence, 0, sizeof(ssl->s3->read_sequence));
+
+ SSL_AEAD_CTX_free(ssl->s3->aead_read_ctx);
+ ssl->s3->aead_read_ctx = aead_ctx;
+ return 1;
+}
+
+static int ssl3_set_write_state(SSL *ssl, SSL_AEAD_CTX *aead_ctx) {
+ OPENSSL_memset(ssl->s3->write_sequence, 0, sizeof(ssl->s3->write_sequence));
+
+ SSL_AEAD_CTX_free(ssl->s3->aead_write_ctx);
+ ssl->s3->aead_write_ctx = aead_ctx;
+ return 1;
+}
+
+static const SSL_PROTOCOL_METHOD kTLSProtocolMethod = {
+ 0 /* is_dtls */,
+ SSL3_VERSION,
+ TLS1_3_VERSION,
+ ssl3_version_from_wire,
+ ssl3_version_to_wire,
+ ssl3_new,
+ ssl3_free,
+ ssl3_get_message,
+ ssl3_get_current_message,
+ ssl3_release_current_message,
+ ssl3_read_app_data,
+ ssl3_read_change_cipher_spec,
+ ssl3_read_close_notify,
+ ssl3_write_app_data,
+ ssl3_dispatch_alert,
+ ssl3_supports_cipher,
+ ssl3_init_message,
+ ssl3_finish_message,
+ ssl3_add_message,
+ ssl3_add_change_cipher_spec,
+ ssl3_add_alert,
+ ssl3_flush_flight,
+ ssl3_expect_flight,
+ ssl3_received_flight,
+ ssl3_set_read_state,
+ ssl3_set_write_state,
+};
+
+const SSL_METHOD *TLS_method(void) {
+ static const SSL_METHOD kMethod = {
+ 0,
+ &kTLSProtocolMethod,
+ &ssl_crypto_x509_method,
+ };
+ return &kMethod;
+}
+
+const SSL_METHOD *SSLv23_method(void) {
+ return TLS_method();
+}
+
+/* Legacy version-locked methods. */
+
+const SSL_METHOD *TLSv1_2_method(void) {
+ static const SSL_METHOD kMethod = {
+ TLS1_2_VERSION,
+ &kTLSProtocolMethod,
+ &ssl_crypto_x509_method,
+ };
+ return &kMethod;
+}
+
+const SSL_METHOD *TLSv1_1_method(void) {
+ static const SSL_METHOD kMethod = {
+ TLS1_1_VERSION,
+ &kTLSProtocolMethod,
+ &ssl_crypto_x509_method,
+ };
+ return &kMethod;
+}
+
+const SSL_METHOD *TLSv1_method(void) {
+ static const SSL_METHOD kMethod = {
+ TLS1_VERSION,
+ &kTLSProtocolMethod,
+ &ssl_crypto_x509_method,
+ };
+ return &kMethod;
+}
+
+const SSL_METHOD *SSLv3_method(void) {
+ static const SSL_METHOD kMethod = {
+ SSL3_VERSION,
+ &kTLSProtocolMethod,
+ &ssl_crypto_x509_method,
+ };
+ return &kMethod;
+}
+
+/* Legacy side-specific methods. */
+
+const SSL_METHOD *TLSv1_2_server_method(void) {
+ return TLSv1_2_method();
+}
+
+const SSL_METHOD *TLSv1_1_server_method(void) {
+ return TLSv1_1_method();
+}
+
+const SSL_METHOD *TLSv1_server_method(void) {
+ return TLSv1_method();
+}
+
+const SSL_METHOD *SSLv3_server_method(void) {
+ return SSLv3_method();
+}
+
+const SSL_METHOD *TLSv1_2_client_method(void) {
+ return TLSv1_2_method();
+}
+
+const SSL_METHOD *TLSv1_1_client_method(void) {
+ return TLSv1_1_method();
+}
+
+const SSL_METHOD *TLSv1_client_method(void) {
+ return TLSv1_method();
+}
+
+const SSL_METHOD *SSLv3_client_method(void) {
+ return SSLv3_method();
+}
+
+const SSL_METHOD *SSLv23_server_method(void) {
+ return SSLv23_method();
+}
+
+const SSL_METHOD *SSLv23_client_method(void) {
+ return SSLv23_method();
+}
+
+const SSL_METHOD *TLS_server_method(void) {
+ return TLS_method();
+}
+
+const SSL_METHOD *TLS_client_method(void) {
+ return TLS_method();
+}
+
+static int ssl_noop_x509_check_client_CA_names(
+ STACK_OF(CRYPTO_BUFFER) *names) {
+ return 1;
+}
+
+static void ssl_noop_x509_clear(CERT *cert) {}
+static void ssl_noop_x509_free(CERT *cert) {}
+static void ssl_noop_x509_dup(CERT *new_cert, const CERT *cert) {}
+static void ssl_noop_x509_flush_cached_leaf(CERT *cert) {}
+static void ssl_noop_x509_flush_cached_chain(CERT *cert) {}
+static int ssl_noop_x509_session_cache_objects(SSL_SESSION *sess) {
+ return 1;
+}
+static int ssl_noop_x509_session_dup(SSL_SESSION *new_session,
+ const SSL_SESSION *session) {
+ return 1;
+}
+static void ssl_noop_x509_session_clear(SSL_SESSION *session) {}
+static int ssl_noop_x509_session_verify_cert_chain(SSL_SESSION *session,
+ SSL *ssl) {
+ if (!ssl->ctx->i_promise_to_verify_certs_after_the_handshake) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNKNOWN_CA);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CERTIFICATE_VERIFY_FAILED);
+ return 0;
+ }
+
+ session->verify_result = X509_V_OK;
+ return 1;
+}
+
+static void ssl_noop_x509_hs_flush_cached_ca_names(SSL_HANDSHAKE *hs) {}
+static int ssl_noop_x509_ssl_new(SSL *ctx) { return 1; }
+static void ssl_noop_x509_ssl_free(SSL *ctx) { }
+static void ssl_noop_x509_ssl_flush_cached_client_CA(SSL *ssl) {}
+static int ssl_noop_x509_ssl_auto_chain_if_needed(SSL *ssl) { return 1; }
+static int ssl_noop_x509_ssl_ctx_new(SSL_CTX *ctx) { return 1; }
+static void ssl_noop_x509_ssl_ctx_free(SSL_CTX *ctx) { }
+static void ssl_noop_x509_ssl_ctx_flush_cached_client_CA(SSL_CTX *ctx) {}
+
+static const SSL_X509_METHOD ssl_noop_x509_method = {
+ ssl_noop_x509_check_client_CA_names,
+ ssl_noop_x509_clear,
+ ssl_noop_x509_free,
+ ssl_noop_x509_dup,
+ ssl_noop_x509_flush_cached_chain,
+ ssl_noop_x509_flush_cached_leaf,
+ ssl_noop_x509_session_cache_objects,
+ ssl_noop_x509_session_dup,
+ ssl_noop_x509_session_clear,
+ ssl_noop_x509_session_verify_cert_chain,
+ ssl_noop_x509_hs_flush_cached_ca_names,
+ ssl_noop_x509_ssl_new,
+ ssl_noop_x509_ssl_free,
+ ssl_noop_x509_ssl_flush_cached_client_CA,
+ ssl_noop_x509_ssl_auto_chain_if_needed,
+ ssl_noop_x509_ssl_ctx_new,
+ ssl_noop_x509_ssl_ctx_free,
+ ssl_noop_x509_ssl_ctx_flush_cached_client_CA,
+};
+
+const SSL_METHOD *TLS_with_buffers_method(void) {
+ static const SSL_METHOD kMethod = {
+ 0,
+ &kTLSProtocolMethod,
+ &ssl_noop_x509_method,
+ };
+ return &kMethod;
+}
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/tls_record.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/tls_record.c
new file mode 100644
index 000000000..aafb6f513
--- /dev/null
+++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl/ssl/tls_record.c
@@ -0,0 +1,505 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com). */
+
+#include <openssl/ssl.h>
+
+#include <assert.h>
+#include <string.h>
+
+#include <openssl/bytestring.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+#include "internal.h"
+#include "../crypto/internal.h"
+
+
+/* kMaxEmptyRecords is the number of consecutive, empty records that will be
+ * processed. Without this limit an attacker could send empty records at a
+ * faster rate than we can process and cause record processing to loop
+ * forever. */
+static const uint8_t kMaxEmptyRecords = 32;
+
+/* kMaxEarlyDataSkipped is the maximum number of rejected early data bytes that
+ * will be skipped. Without this limit an attacker could send records at a
+ * faster rate than we can process and cause trial decryption to loop forever.
+ * This value should be slightly above kMaxEarlyDataAccepted in tls13_server.c,
+ * which is measured in plaintext. */
+static const size_t kMaxEarlyDataSkipped = 16384;
+
+/* kMaxWarningAlerts is the number of consecutive warning alerts that will be
+ * processed. */
+static const uint8_t kMaxWarningAlerts = 4;
+
+/* ssl_needs_record_splitting returns one if |ssl|'s current outgoing cipher
+ * state needs record-splitting and zero otherwise. */
+static int ssl_needs_record_splitting(const SSL *ssl) {
+ return ssl->s3->aead_write_ctx != NULL &&
+ ssl->s3->aead_write_ctx->version < TLS1_1_VERSION &&
+ (ssl->mode & SSL_MODE_CBC_RECORD_SPLITTING) != 0 &&
+ SSL_CIPHER_is_block_cipher(ssl->s3->aead_write_ctx->cipher);
+}
+
+int ssl_record_sequence_update(uint8_t *seq, size_t seq_len) {
+ for (size_t i = seq_len - 1; i < seq_len; i--) {
+ ++seq[i];
+ if (seq[i] != 0) {
+ return 1;
+ }
+ }
+ OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
+ return 0;
+}
+
+size_t ssl_record_prefix_len(const SSL *ssl) {
+ size_t header_len;
+ if (SSL_is_dtls(ssl)) {
+ header_len = DTLS1_RT_HEADER_LENGTH;
+ } else {
+ header_len = SSL3_RT_HEADER_LENGTH;
+ }
+
+ return header_len + SSL_AEAD_CTX_explicit_nonce_len(ssl->s3->aead_read_ctx);
+}
+
+size_t ssl_seal_align_prefix_len(const SSL *ssl) {
+ if (SSL_is_dtls(ssl)) {
+ return DTLS1_RT_HEADER_LENGTH +
+ SSL_AEAD_CTX_explicit_nonce_len(ssl->s3->aead_write_ctx);
+ }
+
+ size_t ret = SSL3_RT_HEADER_LENGTH +
+ SSL_AEAD_CTX_explicit_nonce_len(ssl->s3->aead_write_ctx);
+ if (ssl_needs_record_splitting(ssl)) {
+ ret += SSL3_RT_HEADER_LENGTH;
+ ret += ssl_cipher_get_record_split_len(ssl->s3->aead_write_ctx->cipher);
+ }
+ return ret;
+}
+
+size_t SSL_max_seal_overhead(const SSL *ssl) {
+ if (SSL_is_dtls(ssl)) {
+ return dtls_max_seal_overhead(ssl, dtls1_use_current_epoch);
+ }
+
+ size_t ret = SSL3_RT_HEADER_LENGTH;
+ ret += SSL_AEAD_CTX_max_overhead(ssl->s3->aead_write_ctx);
+ /* TLS 1.3 needs an extra byte for the encrypted record type. */
+ if (ssl->s3->aead_write_ctx != NULL &&
+ ssl->s3->aead_write_ctx->version >= TLS1_3_VERSION) {
+ ret += 1;
+ }
+ if (ssl_needs_record_splitting(ssl)) {
+ ret *= 2;
+ }
+ return ret;
+}
+
+enum ssl_open_record_t tls_open_record(SSL *ssl, uint8_t *out_type, CBS *out,
+ size_t *out_consumed, uint8_t *out_alert,
+ uint8_t *in, size_t in_len) {
+ *out_consumed = 0;
+
+ CBS cbs;
+ CBS_init(&cbs, in, in_len);
+
+ /* Decode the record header. */
+ uint8_t type;
+ uint16_t version, ciphertext_len;
+ if (!CBS_get_u8(&cbs, &type) ||
+ !CBS_get_u16(&cbs, &version) ||
+ !CBS_get_u16(&cbs, &ciphertext_len)) {
+ *out_consumed = SSL3_RT_HEADER_LENGTH;
+ return ssl_open_record_partial;
+ }
+
+ int version_ok;
+ if (ssl->s3->aead_read_ctx == NULL) {
+ /* Only check the first byte. Enforcing beyond that can prevent decoding
+ * version negotiation failure alerts. */
+ version_ok = (version >> 8) == SSL3_VERSION_MAJOR;
+ } else if (ssl3_protocol_version(ssl) < TLS1_3_VERSION) {
+ /* Earlier versions of TLS switch the record version. */
+ version_ok = version == ssl->version;
+ } else {
+ /* Starting TLS 1.3, the version field is frozen at {3, 1}. */
+ version_ok = version == TLS1_VERSION;
+ }
+
+ if (!version_ok) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_VERSION_NUMBER);
+ *out_alert = SSL_AD_PROTOCOL_VERSION;
+ return ssl_open_record_error;
+ }
+
+ /* Check the ciphertext length. */
+ if (ciphertext_len > SSL3_RT_MAX_ENCRYPTED_LENGTH) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_ENCRYPTED_LENGTH_TOO_LONG);
+ *out_alert = SSL_AD_RECORD_OVERFLOW;
+ return ssl_open_record_error;
+ }
+
+ /* Extract the body. */
+ CBS body;
+ if (!CBS_get_bytes(&cbs, &body, ciphertext_len)) {
+ *out_consumed = SSL3_RT_HEADER_LENGTH + (size_t)ciphertext_len;
+ return ssl_open_record_partial;
+ }
+
+ ssl_do_msg_callback(ssl, 0 /* read */, SSL3_RT_HEADER, in,
+ SSL3_RT_HEADER_LENGTH);
+
+ *out_consumed = in_len - CBS_len(&cbs);
+
+ /* Skip early data received when expecting a second ClientHello if we rejected
+ * 0RTT. */
+ if (ssl->s3->skip_early_data &&
+ ssl->s3->aead_read_ctx == NULL &&
+ type == SSL3_RT_APPLICATION_DATA) {
+ goto skipped_data;
+ }
+
+ /* Decrypt the body in-place. */
+ if (!SSL_AEAD_CTX_open(ssl->s3->aead_read_ctx, out, type, version,
+ ssl->s3->read_sequence, (uint8_t *)CBS_data(&body),
+ CBS_len(&body))) {
+ if (ssl->s3->skip_early_data &&
+ ssl->s3->aead_read_ctx != NULL) {
+ ERR_clear_error();
+ goto skipped_data;
+ }
+
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC);
+ *out_alert = SSL_AD_BAD_RECORD_MAC;
+ return ssl_open_record_error;
+ }
+
+ ssl->s3->skip_early_data = 0;
+
+ if (!ssl_record_sequence_update(ssl->s3->read_sequence, 8)) {
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ return ssl_open_record_error;
+ }
+
+ /* TLS 1.3 hides the record type inside the encrypted data. */
+ if (ssl->s3->aead_read_ctx != NULL &&
+ ssl->s3->aead_read_ctx->version >= TLS1_3_VERSION) {
+ /* The outer record type is always application_data. */
+ if (type != SSL3_RT_APPLICATION_DATA) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_OUTER_RECORD_TYPE);
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return ssl_open_record_error;
+ }
+
+ do {
+ if (!CBS_get_last_u8(out, &type)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC);
+ *out_alert = SSL_AD_DECRYPT_ERROR;
+ return ssl_open_record_error;
+ }
+ } while (type == 0);
+ }
+
+ /* Check the plaintext length. */
+ if (CBS_len(out) > SSL3_RT_MAX_PLAIN_LENGTH) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DATA_LENGTH_TOO_LONG);
+ *out_alert = SSL_AD_RECORD_OVERFLOW;
+ return ssl_open_record_error;
+ }
+
+ /* Limit the number of consecutive empty records. */
+ if (CBS_len(out) == 0) {
+ ssl->s3->empty_record_count++;
+ if (ssl->s3->empty_record_count > kMaxEmptyRecords) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_TOO_MANY_EMPTY_FRAGMENTS);
+ *out_alert = SSL_AD_UNEXPECTED_MESSAGE;
+ return ssl_open_record_error;
+ }
+ /* Apart from the limit, empty records are returned up to the caller. This
+ * allows the caller to reject records of the wrong type. */
+ } else {
+ ssl->s3->empty_record_count = 0;
+ }
+
+ if (type == SSL3_RT_ALERT) {
+ return ssl_process_alert(ssl, out_alert, CBS_data(out), CBS_len(out));
+ }
+
+ ssl->s3->warning_alert_count = 0;
+
+ *out_type = type;
+ return ssl_open_record_success;
+
+skipped_data:
+ ssl->s3->early_data_skipped += *out_consumed;
+ if (ssl->s3->early_data_skipped < *out_consumed) {
+ ssl->s3->early_data_skipped = kMaxEarlyDataSkipped + 1;
+ }
+
+ if (ssl->s3->early_data_skipped > kMaxEarlyDataSkipped) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_TOO_MUCH_SKIPPED_EARLY_DATA);
+ *out_alert = SSL_AD_UNEXPECTED_MESSAGE;
+ return ssl_open_record_error;
+ }
+
+ return ssl_open_record_discard;
+}
+
+static int do_seal_record(SSL *ssl, uint8_t *out, size_t *out_len,
+ size_t max_out, uint8_t type, const uint8_t *in,
+ size_t in_len) {
+ assert(!buffers_alias(in, in_len, out, max_out));
+
+ /* TLS 1.3 hides the actual record type inside the encrypted data. */
+ if (ssl->s3->aead_write_ctx != NULL &&
+ ssl->s3->aead_write_ctx->version >= TLS1_3_VERSION) {
+ if (in_len > in_len + SSL3_RT_HEADER_LENGTH + 1 ||
+ max_out < in_len + SSL3_RT_HEADER_LENGTH + 1) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL);
+ return 0;
+ }
+
+ OPENSSL_memcpy(out + SSL3_RT_HEADER_LENGTH, in, in_len);
+ out[SSL3_RT_HEADER_LENGTH + in_len] = type;
+ in = out + SSL3_RT_HEADER_LENGTH;
+ type = SSL3_RT_APPLICATION_DATA;
+ in_len++;
+ }
+
+ if (max_out < SSL3_RT_HEADER_LENGTH) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL);
+ return 0;
+ }
+
+ /* The TLS record-layer version number is meaningless and, starting in
+ * TLS 1.3, is frozen at TLS 1.0. But for historical reasons, SSL 3.0
+ * ClientHellos should use SSL 3.0 and pre-TLS-1.3 expects the version
+ * to change after version negotiation. */
+ uint16_t wire_version = TLS1_VERSION;
+ if (ssl->version == SSL3_VERSION ||
+ (ssl->s3->have_version && ssl3_protocol_version(ssl) < TLS1_3_VERSION)) {
+ wire_version = ssl->version;
+ }
+
+ /* Write the non-length portions of the header. */
+ out[0] = type;
+ out[1] = wire_version >> 8;
+ out[2] = wire_version & 0xff;
+ out += 3;
+ max_out -= 3;
+
+ /* Write the ciphertext, leaving two bytes for the length. */
+ size_t ciphertext_len;
+ if (!SSL_AEAD_CTX_seal(ssl->s3->aead_write_ctx, out + 2, &ciphertext_len,
+ max_out - 2, type, wire_version,
+ ssl->s3->write_sequence, in, in_len) ||
+ !ssl_record_sequence_update(ssl->s3->write_sequence, 8)) {
+ return 0;
+ }
+
+ /* Fill in the length. */
+ if (ciphertext_len >= 1 << 15) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
+ return 0;
+ }
+ out[0] = ciphertext_len >> 8;
+ out[1] = ciphertext_len & 0xff;
+
+ *out_len = SSL3_RT_HEADER_LENGTH + ciphertext_len;
+
+ ssl_do_msg_callback(ssl, 1 /* write */, SSL3_RT_HEADER, out,
+ SSL3_RT_HEADER_LENGTH);
+ return 1;
+}
+
+int tls_seal_record(SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out,
+ uint8_t type, const uint8_t *in, size_t in_len) {
+ if (buffers_alias(in, in_len, out, max_out)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_OUTPUT_ALIASES_INPUT);
+ return 0;
+ }
+
+ size_t frag_len = 0;
+ if (type == SSL3_RT_APPLICATION_DATA && in_len > 1 &&
+ ssl_needs_record_splitting(ssl)) {
+ if (!do_seal_record(ssl, out, &frag_len, max_out, type, in, 1)) {
+ return 0;
+ }
+ in++;
+ in_len--;
+ out += frag_len;
+ max_out -= frag_len;
+
+#if !defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+ assert(SSL3_RT_HEADER_LENGTH + ssl_cipher_get_record_split_len(
+ ssl->s3->aead_write_ctx->cipher) ==
+ frag_len);
+#endif
+ }
+
+ if (!do_seal_record(ssl, out, out_len, max_out, type, in, in_len)) {
+ return 0;
+ }
+ *out_len += frag_len;
+ return 1;
+}
+
+enum ssl_open_record_t ssl_process_alert(SSL *ssl, uint8_t *out_alert,
+ const uint8_t *in, size_t in_len) {
+ /* Alerts records may not contain fragmented or multiple alerts. */
+ if (in_len != 2) {
+ *out_alert = SSL_AD_DECODE_ERROR;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ALERT);
+ return ssl_open_record_error;
+ }
+
+ ssl_do_msg_callback(ssl, 0 /* read */, SSL3_RT_ALERT, in, in_len);
+
+ const uint8_t alert_level = in[0];
+ const uint8_t alert_descr = in[1];
+
+ uint16_t alert = (alert_level << 8) | alert_descr;
+ ssl_do_info_callback(ssl, SSL_CB_READ_ALERT, alert);
+
+ if (alert_level == SSL3_AL_WARNING) {
+ if (alert_descr == SSL_AD_CLOSE_NOTIFY) {
+ ssl->s3->recv_shutdown = ssl_shutdown_close_notify;
+ return ssl_open_record_close_notify;
+ }
+
+ /* Warning alerts do not exist in TLS 1.3. */
+ if (ssl->s3->have_version &&
+ ssl3_protocol_version(ssl) >= TLS1_3_VERSION) {
+ *out_alert = SSL_AD_DECODE_ERROR;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ALERT);
+ return ssl_open_record_error;
+ }
+
+ ssl->s3->warning_alert_count++;
+ if (ssl->s3->warning_alert_count > kMaxWarningAlerts) {
+ *out_alert = SSL_AD_UNEXPECTED_MESSAGE;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_TOO_MANY_WARNING_ALERTS);
+ return ssl_open_record_error;
+ }
+ return ssl_open_record_discard;
+ }
+
+ if (alert_level == SSL3_AL_FATAL) {
+ ssl->s3->recv_shutdown = ssl_shutdown_fatal_alert;
+
+ char tmp[16];
+ OPENSSL_PUT_ERROR(SSL, SSL_AD_REASON_OFFSET + alert_descr);
+ BIO_snprintf(tmp, sizeof(tmp), "%d", alert_descr);
+ ERR_add_error_data(2, "SSL alert number ", tmp);
+ return ssl_open_record_fatal_alert;
+ }
+
+ *out_alert = SSL_AD_ILLEGAL_PARAMETER;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_ALERT_TYPE);
+ return ssl_open_record_error;
+}