summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Chromium Automerger <chromium-automerger@android>2014-10-30 02:15:04 +0000
committerAndroid Chromium Automerger <chromium-automerger@android>2014-10-30 02:15:04 +0000
commitecf09ca1bc8a217d707f2aa2d90ede43404e47d3 (patch)
tree6d02d5ea2674d24bb2066859bec5b3c8104a84ff
parent71eedb007c5f4cb91a666d7ea5d814c567f31deb (diff)
parent03a739d8d2cdc2560531a7446ead0f705409670a (diff)
downloadsrc-ecf09ca1bc8a217d707f2aa2d90ede43404e47d3.tar.gz
Merge third_party/boringssl/src from https://boringssl.googlesource.com/boringssl.git at 03a739d8d2cdc2560531a7446ead0f705409670a
This commit was generated by merge_from_chromium.py. Change-Id: I52d83e7a5a0a9b94fd10dbaf5350aef57d1c1f88
-rw-r--r--crypto/CMakeLists.txt11
-rw-r--r--crypto/asn1/asn1_locl.h22
-rw-r--r--crypto/bio/CMakeLists.txt3
-rw-r--r--crypto/bn/generic.c2
-rw-r--r--crypto/bytestring/bytestring_test.c190
-rw-r--r--crypto/bytestring/cbb.c36
-rw-r--r--crypto/bytestring/cbs.c88
-rw-r--r--crypto/evp/digestsign.c15
-rw-r--r--crypto/evp/example_sign.c46
-rw-r--r--crypto/perlasm/x86asm.pl4
-rw-r--r--crypto/perlasm/x86masm.pl7
-rw-r--r--crypto/perlasm/x86nasm.pl8
-rw-r--r--crypto/x509/x_crl.c18
-rw-r--r--crypto/x509v3/v3nametest.c4
-rw-r--r--include/openssl/base.h1
-rw-r--r--include/openssl/bytestring.h39
-rw-r--r--include/openssl/evp.h9
-rw-r--r--include/openssl/srtp.h56
-rw-r--r--include/openssl/ssl.h84
-rw-r--r--include/openssl/ssl3.h9
-rw-r--r--include/openssl/tls1.h5
-rw-r--r--include/openssl/x509.h4
-rw-r--r--ssl/d1_both.c9
-rw-r--r--ssl/d1_lib.c31
-rw-r--r--ssl/d1_srtp.c30
-rw-r--r--ssl/d1_srvr.c2
-rw-r--r--ssl/s3_both.c8
-rw-r--r--ssl/s3_clnt.c285
-rw-r--r--ssl/s3_enc.c14
-rw-r--r--ssl/s3_lib.c14
-rw-r--r--ssl/s3_srvr.c101
-rw-r--r--ssl/ssl_asn1.c1050
-rw-r--r--ssl/ssl_error.c7
-rw-r--r--ssl/ssl_lib.c48
-rw-r--r--ssl/ssl_locl.h29
-rw-r--r--ssl/ssl_test.c55
-rw-r--r--ssl/t1_enc.c82
-rw-r--r--ssl/t1_lib.c56
-rw-r--r--ssl/test/bssl_shim.cc60
-rw-r--r--ssl/test/runner/cipher_suites.go35
-rw-r--r--ssl/test/runner/common.go57
-rw-r--r--ssl/test/runner/conn.go21
-rw-r--r--ssl/test/runner/handshake_client.go141
-rw-r--r--ssl/test/runner/handshake_messages.go109
-rw-r--r--ssl/test/runner/handshake_server.go28
-rw-r--r--ssl/test/runner/key_agreement.go198
-rw-r--r--ssl/test/runner/prf.go48
-rw-r--r--ssl/test/runner/recordingconn.go130
-rw-r--r--ssl/test/runner/runner.go161
-rw-r--r--ssl/test/runner/ticket.go30
-rw-r--r--ssl/test/test_config.cc7
-rw-r--r--ssl/test/test_config.h3
-rw-r--r--tool/client.cc8
53 files changed, 2346 insertions, 1172 deletions
diff --git a/crypto/CMakeLists.txt b/crypto/CMakeLists.txt
index 5d656ec..f98c7c8 100644
--- a/crypto/CMakeLists.txt
+++ b/crypto/CMakeLists.txt
@@ -12,12 +12,16 @@ else()
if (CMAKE_CL_64)
message("Using masm")
set(PERLASM_STYLE masm)
+ enable_language(ASM_MASM)
else()
message("Using win32n")
set(PERLASM_STYLE win32n)
+
+ # On 32-bit, upstream supports only NASM, not MASM. We'll use Yasm, specifically.
+ set(CMAKE_ASM_NASM_COMPILER "yasm")
+ enable_language(ASM_NASM)
endif()
set(ASM_EXT asm)
- enable_language(ASM_MASM)
endif()
function(perlasm dest src)
@@ -27,9 +31,10 @@ function(perlasm dest src)
DEPENDS
${src}
${PROJECT_SOURCE_DIR}/crypto/perlasm/x86_64-xlate.pl
- ${PROJECT_SOURCE_DIR}/crypto/perlasm/x86gas.pl
- ${PROJECT_SOURCE_DIR}/crypto/perlasm/x86asm.pl
${PROJECT_SOURCE_DIR}/crypto/perlasm/x86asm.pl
+ ${PROJECT_SOURCE_DIR}/crypto/perlasm/x86gas.pl
+ ${PROJECT_SOURCE_DIR}/crypto/perlasm/x86masm.pl
+ ${PROJECT_SOURCE_DIR}/crypto/perlasm/x86nasm.pl
WORKING_DIRECTORY .
)
endfunction()
diff --git a/crypto/asn1/asn1_locl.h b/crypto/asn1/asn1_locl.h
index 1444390..ca5f612 100644
--- a/crypto/asn1/asn1_locl.h
+++ b/crypto/asn1/asn1_locl.h
@@ -71,25 +71,3 @@ struct asn1_pctx_st
unsigned long oid_flags;
unsigned long str_flags;
} /* ASN1_PCTX */;
-
-/* ASN1 public key method structure */
-
-
-/* Method to handle CRL access.
- * In general a CRL could be very large (several Mb) and can consume large
- * amounts of resources if stored in memory by multiple processes.
- * This method allows general CRL operations to be redirected to more
- * efficient callbacks: for example a CRL entry database.
- */
-
-#define X509_CRL_METHOD_DYNAMIC 1
-
-struct x509_crl_method_st
- {
- int flags;
- int (*crl_init)(X509_CRL *crl);
- int (*crl_free)(X509_CRL *crl);
- int (*crl_lookup)(X509_CRL *crl, X509_REVOKED **ret,
- ASN1_INTEGER *ser, X509_NAME *issuer);
- int (*crl_verify)(X509_CRL *crl, EVP_PKEY *pk);
- };
diff --git a/crypto/bio/CMakeLists.txt b/crypto/bio/CMakeLists.txt
index 86092f0..9178931 100644
--- a/crypto/bio/CMakeLists.txt
+++ b/crypto/bio/CMakeLists.txt
@@ -26,3 +26,6 @@ add_executable(
)
target_link_libraries(bio_test crypto)
+if (WIN32)
+ target_link_libraries(bio_test ws2_32)
+endif()
diff --git a/crypto/bn/generic.c b/crypto/bn/generic.c
index b745750..c60cfd9 100644
--- a/crypto/bn/generic.c
+++ b/crypto/bn/generic.c
@@ -61,7 +61,7 @@
#include "internal.h"
-#if defined(OPENSSL_WINDOWS) || defined(OPENSSL_NO_ASM) || \
+#if defined(OPENSSL_NO_ASM) || \
(!defined(OPENSSL_X86_64) && !defined(OPENSSL_X86))
#if defined(OPENSSL_WINDOWS)
diff --git a/crypto/bytestring/bytestring_test.c b/crypto/bytestring/bytestring_test.c
index f30179d..ba70bcf 100644
--- a/crypto/bytestring/bytestring_test.c
+++ b/crypto/bytestring/bytestring_test.c
@@ -19,6 +19,7 @@
#include <openssl/bytestring.h>
#include "internal.h"
+#include "../internal.h"
static int test_skip(void) {
@@ -105,8 +106,14 @@ static int test_get_asn1(void) {
static const uint8_t kData3[] = {0x30, 0x80};
static const uint8_t kData4[] = {0x30, 0x81, 1, 1};
static const uint8_t kData5[] = {0x30, 0x82, 0, 1, 1};
+ static const uint8_t kData6[] = {0xa1, 3, 0x4, 1, 1};
+ static const uint8_t kData7[] = {0xa1, 3, 0x4, 2, 1};
+ static const uint8_t kData8[] = {0xa1, 3, 0x2, 1, 1};
+ static const uint8_t kData9[] = {0xa1, 3, 0x2, 1, 0xff};
CBS data, contents;
+ int present;
+ uint64_t value;
CBS_init(&data, kData1, sizeof(kData1));
if (CBS_peek_asn1_tag(&data, 0x1) ||
@@ -150,10 +157,106 @@ static int test_get_asn1(void) {
}
CBS_init(&data, NULL, 0);
+ /* peek at empty data. */
if (CBS_peek_asn1_tag(&data, 0x30)) {
return 0;
}
+ CBS_init(&data, NULL, 0);
+ /* optional elements at empty data. */
+ if (!CBS_get_optional_asn1(&data, &contents, &present, 0xa0) ||
+ present ||
+ !CBS_get_optional_asn1_octet_string(&data, &contents, &present, 0xa0) ||
+ present ||
+ CBS_len(&contents) != 0 ||
+ !CBS_get_optional_asn1_octet_string(&data, &contents, NULL, 0xa0) ||
+ CBS_len(&contents) != 0 ||
+ !CBS_get_optional_asn1_uint64(&data, &value, 0xa0, 42) ||
+ value != 42) {
+ return 0;
+ }
+
+ CBS_init(&data, kData6, sizeof(kData6));
+ /* optional element. */
+ if (!CBS_get_optional_asn1(&data, &contents, &present, 0xa0) ||
+ present ||
+ !CBS_get_optional_asn1(&data, &contents, &present, 0xa1) ||
+ !present ||
+ CBS_len(&contents) != 3 ||
+ memcmp(CBS_data(&contents), "\x04\x01\x01", 3) != 0) {
+ return 0;
+ }
+
+ CBS_init(&data, kData6, sizeof(kData6));
+ /* optional octet string. */
+ if (!CBS_get_optional_asn1_octet_string(&data, &contents, &present, 0xa0) ||
+ present ||
+ CBS_len(&contents) != 0 ||
+ !CBS_get_optional_asn1_octet_string(&data, &contents, &present, 0xa1) ||
+ !present ||
+ CBS_len(&contents) != 1 ||
+ CBS_data(&contents)[0] != 1) {
+ return 0;
+ }
+
+ CBS_init(&data, kData7, sizeof(kData7));
+ /* invalid optional octet string. */
+ if (CBS_get_optional_asn1_octet_string(&data, &contents, &present, 0xa1)) {
+ return 0;
+ }
+
+ CBS_init(&data, kData8, sizeof(kData8));
+ /* optional octet string. */
+ if (!CBS_get_optional_asn1_uint64(&data, &value, 0xa0, 42) ||
+ value != 42 ||
+ !CBS_get_optional_asn1_uint64(&data, &value, 0xa1, 42) ||
+ value != 1) {
+ return 0;
+ }
+
+ CBS_init(&data, kData9, sizeof(kData9));
+ /* invalid optional integer. */
+ if (CBS_get_optional_asn1_uint64(&data, &value, 0xa1, 42)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+static int test_get_optional_asn1_bool(void) {
+ CBS data;
+ int val;
+
+ static const uint8_t kTrue[] = {0x0a, 3, CBS_ASN1_BOOLEAN, 1, 0xff};
+ static const uint8_t kFalse[] = {0x0a, 3, CBS_ASN1_BOOLEAN, 1, 0x00};
+ static const uint8_t kInvalid[] = {0x0a, 3, CBS_ASN1_BOOLEAN, 1, 0x01};
+
+ CBS_init(&data, NULL, 0);
+ val = 2;
+ if (!CBS_get_optional_asn1_bool(&data, &val, 0x0a, 0) ||
+ val != 0) {
+ return 0;
+ }
+
+ CBS_init(&data, kTrue, sizeof(kTrue));
+ val = 2;
+ if (!CBS_get_optional_asn1_bool(&data, &val, 0x0a, 0) ||
+ val != 1) {
+ return 0;
+ }
+
+ CBS_init(&data, kFalse, sizeof(kFalse));
+ val = 2;
+ if (!CBS_get_optional_asn1_bool(&data, &val, 0x0a, 1) ||
+ val != 0) {
+ return 0;
+ }
+
+ CBS_init(&data, kInvalid, sizeof(kInvalid));
+ if (CBS_get_optional_asn1_bool(&data, &val, 0x0a, 1)) {
+ return 0;
+ }
+
return 1;
}
@@ -443,6 +546,89 @@ static int test_ber_convert(void) {
sizeof(kNSSBER));
}
+typedef struct {
+ uint64_t value;
+ const char *encoding;
+ size_t encoding_len;
+} ASN1_UINT64_TEST;
+
+static const ASN1_UINT64_TEST kAsn1Uint64Tests[] = {
+ {0, "\x02\x01\x00", 3},
+ {1, "\x02\x01\x01", 3},
+ {127, "\x02\x01\x7f", 3},
+ {128, "\x02\x02\x00\x80", 4},
+ {0xdeadbeef, "\x02\x05\x00\xde\xad\xbe\xef", 7},
+ {OPENSSL_U64(0x0102030405060708),
+ "\x02\x08\x01\x02\x03\x04\x05\x06\x07\x08", 10},
+ {OPENSSL_U64(0xffffffffffffffff),
+ "\x02\x09\x00\xff\xff\xff\xff\xff\xff\xff\xff", 11},
+};
+
+typedef struct {
+ const char *encoding;
+ size_t encoding_len;
+} ASN1_INVALID_UINT64_TEST;
+
+static const ASN1_INVALID_UINT64_TEST kAsn1InvalidUint64Tests[] = {
+ /* Bad tag. */
+ {"\x03\x01\x00", 3},
+ /* Empty contents. */
+ {"\x02\x00", 2},
+ /* Negative number. */
+ {"\x02\x01\x80", 3},
+ /* Overflow */
+ {"\x02\x09\x01\x00\x00\x00\x00\x00\x00\x00\x00", 11},
+};
+
+static int test_asn1_uint64(void) {
+ size_t i;
+
+ for (i = 0; i < sizeof(kAsn1Uint64Tests) / sizeof(kAsn1Uint64Tests[0]); i++) {
+ const ASN1_UINT64_TEST *test = &kAsn1Uint64Tests[i];
+ CBS cbs;
+ uint64_t value;
+ CBB cbb;
+ uint8_t *out;
+ size_t len;
+
+ CBS_init(&cbs, (const uint8_t *)test->encoding, test->encoding_len);
+ if (!CBS_get_asn1_uint64(&cbs, &value) ||
+ CBS_len(&cbs) != 0 ||
+ value != test->value) {
+ return 0;
+ }
+
+ if (!CBB_init(&cbb, 0)) {
+ return 0;
+ }
+ if (!CBB_add_asn1_uint64(&cbb, test->value) ||
+ !CBB_finish(&cbb, &out, &len)) {
+ CBB_cleanup(&cbb);
+ return 0;
+ }
+ if (len != test->encoding_len || memcmp(out, test->encoding, len) != 0) {
+ free(out);
+ return 0;
+ }
+ free(out);
+ }
+
+ for (i = 0;
+ i < sizeof(kAsn1InvalidUint64Tests) / sizeof(kAsn1InvalidUint64Tests[0]);
+ i++) {
+ const ASN1_INVALID_UINT64_TEST *test = &kAsn1InvalidUint64Tests[i];
+ CBS cbs;
+ uint64_t value;
+
+ CBS_init(&cbs, (const uint8_t *)test->encoding, test->encoding_len);
+ if (CBS_get_asn1_uint64(&cbs, &value)) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
int main(void) {
CRYPTO_library_init();
@@ -457,7 +643,9 @@ int main(void) {
!test_cbb_misuse() ||
!test_cbb_prefixed() ||
!test_cbb_asn1() ||
- !test_ber_convert()) {
+ !test_ber_convert() ||
+ !test_asn1_uint64() ||
+ !test_get_optional_asn1_bool()) {
return 1;
}
diff --git a/crypto/bytestring/cbb.c b/crypto/bytestring/cbb.c
index 6767b9d..f8e1070 100644
--- a/crypto/bytestring/cbb.c
+++ b/crypto/bytestring/cbb.c
@@ -336,3 +336,39 @@ int CBB_add_u24(CBB *cbb, uint32_t value) {
return cbb_buffer_add_u(cbb->base, value, 3);
}
+
+int CBB_add_asn1_uint64(CBB *cbb, uint64_t value) {
+ CBB child;
+ size_t i;
+ int started = 0;
+
+ if (!CBB_add_asn1(cbb, &child, CBS_ASN1_INTEGER)) {
+ return 0;
+ }
+
+ for (i = 0; i < 8; i++) {
+ uint8_t byte = (value >> 8*(7-i)) & 0xff;
+ if (!started) {
+ if (byte == 0) {
+ /* Don't encode leading zeros. */
+ continue;
+ }
+ /* If the high bit is set, add a padding byte to make it
+ * unsigned. */
+ if ((byte & 0x80) && !CBB_add_u8(&child, 0)) {
+ return 0;
+ }
+ started = 1;
+ }
+ if (!CBB_add_u8(&child, byte)) {
+ return 0;
+ }
+ }
+
+ /* 0 is encoded as a single 0, not the empty string. */
+ if (!started && !CBB_add_u8(&child, 0)) {
+ return 0;
+ }
+
+ return CBB_flush(cbb);
+}
diff --git a/crypto/bytestring/cbs.c b/crypto/bytestring/cbs.c
index 07cc126..b417716 100644
--- a/crypto/bytestring/cbs.c
+++ b/crypto/bytestring/cbs.c
@@ -284,7 +284,12 @@ int CBS_get_asn1_uint64(CBS *cbs, uint64_t *out) {
data = CBS_data(&bytes);
len = CBS_len(&bytes);
- if (len > 0 && (data[0] & 0x80) != 0) {
+ if (len == 0) {
+ /* An INTEGER is encoded with at least one octet. */
+ return 0;
+ }
+
+ if ((data[0] & 0x80) != 0) {
/* negative number */
return 0;
}
@@ -300,3 +305,84 @@ int CBS_get_asn1_uint64(CBS *cbs, uint64_t *out) {
return 1;
}
+
+int CBS_get_optional_asn1(CBS *cbs, CBS *out, int *out_present, unsigned tag) {
+ if (CBS_peek_asn1_tag(cbs, tag)) {
+ if (!CBS_get_asn1(cbs, out, tag)) {
+ return 0;
+ }
+ *out_present = 1;
+ } else {
+ *out_present = 0;
+ }
+ return 1;
+}
+
+int CBS_get_optional_asn1_octet_string(CBS *cbs, CBS *out, int *out_present,
+ unsigned tag) {
+ CBS child;
+ int present;
+ if (!CBS_get_optional_asn1(cbs, &child, &present, tag)) {
+ return 0;
+ }
+ if (present) {
+ if (!CBS_get_asn1(&child, out, CBS_ASN1_OCTETSTRING) ||
+ CBS_len(&child) != 0) {
+ return 0;
+ }
+ } else {
+ CBS_init(out, NULL, 0);
+ }
+ if (out_present) {
+ *out_present = present;
+ }
+ return 1;
+}
+
+int CBS_get_optional_asn1_uint64(CBS *cbs, uint64_t *out, unsigned tag,
+ uint64_t default_value) {
+ CBS child;
+ int present;
+ if (!CBS_get_optional_asn1(cbs, &child, &present, tag)) {
+ return 0;
+ }
+ if (present) {
+ if (!CBS_get_asn1_uint64(&child, out) ||
+ CBS_len(&child) != 0) {
+ return 0;
+ }
+ } else {
+ *out = default_value;
+ }
+ return 1;
+}
+
+int CBS_get_optional_asn1_bool(CBS *cbs, int *out, unsigned tag,
+ int default_value) {
+ CBS child, child2;
+ int present;
+ if (!CBS_get_optional_asn1(cbs, &child, &present, tag)) {
+ return 0;
+ }
+ if (present) {
+ uint8_t boolean;
+
+ if (!CBS_get_asn1(&child, &child2, CBS_ASN1_BOOLEAN) ||
+ CBS_len(&child2) != 1 ||
+ CBS_len(&child) != 0) {
+ return 0;
+ }
+
+ boolean = CBS_data(&child2)[0];
+ if (boolean == 0) {
+ *out = 0;
+ } else if (boolean == 0xff) {
+ *out = 1;
+ } else {
+ return 0;
+ }
+ } else {
+ *out = default_value;
+ }
+ return 1;
+}
diff --git a/crypto/evp/digestsign.c b/crypto/evp/digestsign.c
index 08968ed..c86b805 100644
--- a/crypto/evp/digestsign.c
+++ b/crypto/evp/digestsign.c
@@ -168,22 +168,15 @@ int EVP_DigestSignFinal(EVP_MD_CTX *ctx, uint8_t *out_sig,
if (has_signctx || !r) {
return r;
}
- if (EVP_PKEY_sign(ctx->pctx, out_sig, out_sig_len, md, mdlen) <= 0) {
- return 0;
- }
+ return EVP_PKEY_sign(ctx->pctx, out_sig, out_sig_len, md, mdlen);
} else {
if (has_signctx) {
- if (ctx->pctx->pmeth->signctx(ctx->pctx, out_sig, out_sig_len, ctx) <= 0) {
- return 0;
- }
+ return ctx->pctx->pmeth->signctx(ctx->pctx, out_sig, out_sig_len, ctx);
} else {
size_t s = EVP_MD_size(ctx->digest);
- if (EVP_PKEY_sign(ctx->pctx, out_sig, out_sig_len, NULL, s) <= 0) {
- return 0;
- }
+ return EVP_PKEY_sign(ctx->pctx, out_sig, out_sig_len, NULL, s);
}
}
- return 1;
}
int EVP_DigestVerifyFinal(EVP_MD_CTX *ctx, const uint8_t *sig,
@@ -196,7 +189,7 @@ int EVP_DigestVerifyFinal(EVP_MD_CTX *ctx, const uint8_t *sig,
EVP_MD_CTX_init(&tmp_ctx);
if (!EVP_MD_CTX_copy_ex(&tmp_ctx, ctx)) {
- return -1;
+ return 0;
}
if (has_verifyctx) {
r = tmp_ctx.pctx->pmeth->verifyctx(tmp_ctx.pctx, sig, sig_len, &tmp_ctx);
diff --git a/crypto/evp/example_sign.c b/crypto/evp/example_sign.c
index 42a19ec..2d4c071 100644
--- a/crypto/evp/example_sign.c
+++ b/crypto/evp/example_sign.c
@@ -196,12 +196,12 @@ static int example_EVP_DigestSignInit(void) {
pkey = load_example_rsa_key();
if (pkey == NULL ||
- EVP_DigestSignInit(&md_ctx, NULL, EVP_sha256(), NULL, pkey) != 1 ||
- EVP_DigestSignUpdate(&md_ctx, kMsg, sizeof(kMsg)) != 1) {
+ !EVP_DigestSignInit(&md_ctx, NULL, EVP_sha256(), NULL, pkey) ||
+ !EVP_DigestSignUpdate(&md_ctx, kMsg, sizeof(kMsg))) {
goto out;
}
/* Determine the size of the signature. */
- if (EVP_DigestSignFinal(&md_ctx, NULL, &sig_len) != 1) {
+ if (!EVP_DigestSignFinal(&md_ctx, NULL, &sig_len)) {
goto out;
}
/* Sanity check for testing. */
@@ -211,14 +211,14 @@ static int example_EVP_DigestSignInit(void) {
}
sig = malloc(sig_len);
- if (sig == NULL || EVP_DigestSignFinal(&md_ctx, sig, &sig_len) != 1) {
+ if (sig == NULL || !EVP_DigestSignFinal(&md_ctx, sig, &sig_len)) {
goto out;
}
/* Ensure that the signature round-trips. */
- if (EVP_DigestVerifyInit(&md_ctx_verify, NULL, EVP_sha256(), NULL, pkey) != 1 ||
- EVP_DigestVerifyUpdate(&md_ctx_verify, kMsg, sizeof(kMsg)) != 1 ||
- EVP_DigestVerifyFinal(&md_ctx_verify, sig, sig_len) != 1) {
+ if (!EVP_DigestVerifyInit(&md_ctx_verify, NULL, EVP_sha256(), NULL, pkey) ||
+ !EVP_DigestVerifyUpdate(&md_ctx_verify, kMsg, sizeof(kMsg)) ||
+ !EVP_DigestVerifyFinal(&md_ctx_verify, sig, sig_len)) {
goto out;
}
@@ -250,9 +250,9 @@ static int example_EVP_DigestVerifyInit(void) {
pkey = load_example_rsa_key();
if (pkey == NULL ||
- EVP_DigestVerifyInit(&md_ctx, NULL, EVP_sha256(), NULL, pkey) != 1 ||
- EVP_DigestVerifyUpdate(&md_ctx, kMsg, sizeof(kMsg)) != 1 ||
- EVP_DigestVerifyFinal(&md_ctx, kSignature, sizeof(kSignature)) != 1) {
+ !EVP_DigestVerifyInit(&md_ctx, NULL, EVP_sha256(), NULL, pkey) ||
+ !EVP_DigestVerifyUpdate(&md_ctx, kMsg, sizeof(kMsg)) ||
+ !EVP_DigestVerifyFinal(&md_ctx, kSignature, sizeof(kSignature))) {
goto out;
}
ret = 1;
@@ -282,7 +282,7 @@ static int test_algorithm_roundtrip(EVP_MD_CTX *md_ctx, EVP_PKEY *pkey) {
EVP_MD_CTX_init(&md_ctx_verify);
- if (EVP_DigestSignUpdate(md_ctx, kMsg, sizeof(kMsg)) != 1) {
+ if (!EVP_DigestSignUpdate(md_ctx, kMsg, sizeof(kMsg))) {
goto out;
}
@@ -293,7 +293,7 @@ static int test_algorithm_roundtrip(EVP_MD_CTX *md_ctx, EVP_PKEY *pkey) {
}
/* Determine the size of the signature. */
- if (EVP_DigestSignFinal(md_ctx, NULL, &sig_len) != 1) {
+ if (!EVP_DigestSignFinal(md_ctx, NULL, &sig_len)) {
goto out;
}
/* Sanity check for testing. */
@@ -303,14 +303,14 @@ static int test_algorithm_roundtrip(EVP_MD_CTX *md_ctx, EVP_PKEY *pkey) {
}
sig = malloc(sig_len);
- if (sig == NULL || EVP_DigestSignFinal(md_ctx, sig, &sig_len) != 1) {
+ if (sig == NULL || !EVP_DigestSignFinal(md_ctx, sig, &sig_len)) {
goto out;
}
/* Ensure that the signature round-trips. */
- if (EVP_DigestVerifyInitFromAlgorithm(&md_ctx_verify, algor, pkey) != 1 ||
- EVP_DigestVerifyUpdate(&md_ctx_verify, kMsg, sizeof(kMsg)) != 1 ||
- EVP_DigestVerifyFinal(&md_ctx_verify, sig, sig_len) != 1) {
+ if (!EVP_DigestVerifyInitFromAlgorithm(&md_ctx_verify, algor, pkey) ||
+ !EVP_DigestVerifyUpdate(&md_ctx_verify, kMsg, sizeof(kMsg)) ||
+ !EVP_DigestVerifyFinal(&md_ctx_verify, sig, sig_len)) {
goto out;
}
@@ -342,7 +342,7 @@ static int test_EVP_DigestSignAlgorithm(void) {
}
/* Test a simple AlgorithmIdentifier. */
- if (EVP_DigestSignInit(&md_ctx, &pkey_ctx, EVP_sha256(), NULL, pkey) != 1 ||
+ if (!EVP_DigestSignInit(&md_ctx, &pkey_ctx, EVP_sha256(), NULL, pkey) ||
!test_algorithm_roundtrip(&md_ctx, pkey)) {
fprintf(stderr, "RSA with SHA-256 failed\n");
goto out;
@@ -352,7 +352,7 @@ static int test_EVP_DigestSignAlgorithm(void) {
EVP_MD_CTX_init(&md_ctx);
/* Test RSA-PSS with custom parameters. */
- if (EVP_DigestSignInit(&md_ctx, &pkey_ctx, EVP_sha256(), NULL, pkey) != 1 ||
+ if (!EVP_DigestSignInit(&md_ctx, &pkey_ctx, EVP_sha256(), NULL, pkey) ||
EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING) != 1 ||
EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, EVP_sha512()) != 1 ||
!test_algorithm_roundtrip(&md_ctx, pkey)) {
@@ -412,11 +412,11 @@ static int example_EVP_DigestVerifyInitFromAlgorithm(void) {
pkey = load_example_rsa_key();
if (pkey == NULL ||
- EVP_DigestVerifyInitFromAlgorithm(&md_ctx, algor, pkey) != 1||
- EVP_DigestVerifyUpdate(&md_ctx, CBS_data(&tbs_cert),
- CBS_len(&tbs_cert)) != 1 ||
- EVP_DigestVerifyFinal(&md_ctx, CBS_data(&signature),
- CBS_len(&signature)) != 1) {
+ !EVP_DigestVerifyInitFromAlgorithm(&md_ctx, algor, pkey) ||
+ !EVP_DigestVerifyUpdate(&md_ctx, CBS_data(&tbs_cert),
+ CBS_len(&tbs_cert)) ||
+ !EVP_DigestVerifyFinal(&md_ctx, CBS_data(&signature),
+ CBS_len(&signature))) {
goto out;
}
ret = 1;
diff --git a/crypto/perlasm/x86asm.pl b/crypto/perlasm/x86asm.pl
index bab15e7..3c7be40 100644
--- a/crypto/perlasm/x86asm.pl
+++ b/crypto/perlasm/x86asm.pl
@@ -235,9 +235,9 @@ sub ::asciz
sub ::asm_finish
{ &file_end();
- print "#if defined(__i386__)\n";
+ print "#if defined(__i386__)\n" unless $win32;
print @out;
- print "#endif\n";
+ print "#endif\n" unless $win32;
}
sub ::asm_init
diff --git a/crypto/perlasm/x86masm.pl b/crypto/perlasm/x86masm.pl
index 1741342..a491529 100644
--- a/crypto/perlasm/x86masm.pl
+++ b/crypto/perlasm/x86masm.pl
@@ -82,7 +82,7 @@ TITLE $_[0].asm
IF \@Version LT 800
ECHO MASM version 8.00 or later is strongly recommended.
ENDIF
-.486
+.686
.MODEL FLAT
OPTION DOTNAME
IF \@Version LT 800
@@ -166,7 +166,10 @@ sub ::data_short
{ push(@out,("DW\t").join(',',@_)."\n"); }
sub ::data_word
-{ push(@out,("DD\t").join(',',@_)."\n"); }
+{ # MASM can't handle long lines, so emit one word at a time.
+ foreach(@_)
+ { push(@out,"DD\t$_\n"); }
+}
sub ::align
{ push(@out,"ALIGN\t$_[0]\n"); }
diff --git a/crypto/perlasm/x86nasm.pl b/crypto/perlasm/x86nasm.pl
index 5d92f60..f8332bb 100644
--- a/crypto/perlasm/x86nasm.pl
+++ b/crypto/perlasm/x86nasm.pl
@@ -83,7 +83,15 @@ sub ::file
%ifidn __OUTPUT_FORMAT__,obj
section code use32 class=code align=64
%elifidn __OUTPUT_FORMAT__,win32
+%ifdef __YASM_VERSION_ID__
+%if __YASM_VERSION_ID__ < 01010000h
+%error yasm version 1.1.0 or later needed.
+%endif
+; Yasm automatically includes @feat.00 and complains about redefining it.
+; https://www.tortall.net/projects/yasm/manual/html/objfmt-win32-safeseh.html
+%else
\$\@feat.00 equ 1
+%endif
section .text code align=64
%else
section .text code
diff --git a/crypto/x509/x_crl.c b/crypto/x509/x_crl.c
index 21785dc..8e64f76 100644
--- a/crypto/x509/x_crl.c
+++ b/crypto/x509/x_crl.c
@@ -64,8 +64,24 @@
#include <openssl/x509.h>
#include <openssl/x509v3.h>
-#include "../asn1/asn1_locl.h"
+/* Method to handle CRL access.
+ * In general a CRL could be very large (several Mb) and can consume large
+ * amounts of resources if stored in memory by multiple processes.
+ * This method allows general CRL operations to be redirected to more
+ * efficient callbacks: for example a CRL entry database.
+ */
+
+#define X509_CRL_METHOD_DYNAMIC 1
+struct x509_crl_method_st
+ {
+ int flags;
+ int (*crl_init)(X509_CRL *crl);
+ int (*crl_free)(X509_CRL *crl);
+ int (*crl_lookup)(X509_CRL *crl, X509_REVOKED **ret,
+ ASN1_INTEGER *ser, X509_NAME *issuer);
+ int (*crl_verify)(X509_CRL *crl, EVP_PKEY *pk);
+ };
static int X509_REVOKED_cmp(const X509_REVOKED **a,
const X509_REVOKED **b);
diff --git a/crypto/x509v3/v3nametest.c b/crypto/x509v3/v3nametest.c
index 6a2ea85..b2e9c09 100644
--- a/crypto/x509v3/v3nametest.c
+++ b/crypto/x509v3/v3nametest.c
@@ -53,9 +53,9 @@
* Hudson (tjh@cryptsoft.com). */
#include <string.h>
-#include <strings.h>
#include <openssl/crypto.h>
+#include <openssl/mem.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
@@ -326,7 +326,7 @@ static void run_cert(X509 *crt, const char *nameincert,
const char *const *pname = names;
while (*pname)
{
- int samename = strcasecmp(nameincert, *pname) == 0;
+ int samename = OPENSSL_strcasecmp(nameincert, *pname) == 0;
size_t namelen = strlen(*pname);
char *name = malloc(namelen);
int match, ret;
diff --git a/include/openssl/base.h b/include/openssl/base.h
index 52cb1e9..6207c54 100644
--- a/include/openssl/base.h
+++ b/include/openssl/base.h
@@ -159,7 +159,6 @@ typedef struct X509_POLICY_NODE_st X509_POLICY_NODE;
typedef struct X509_POLICY_TREE_st X509_POLICY_TREE;
typedef struct X509_algor_st X509_ALGOR;
typedef struct X509_crl_st X509_CRL;
-typedef struct X509_name_st X509_NAME;
typedef struct X509_pubkey_st X509_PUBKEY;
typedef struct bignum_ctx BN_CTX;
typedef struct bignum_st BIGNUM;
diff --git a/include/openssl/bytestring.h b/include/openssl/bytestring.h
index acaba8e..d5e6cf9 100644
--- a/include/openssl/bytestring.h
+++ b/include/openssl/bytestring.h
@@ -166,6 +166,41 @@ OPENSSL_EXPORT int CBS_get_any_asn1_element(CBS *cbs, CBS *out,
* in 64 bits. */
OPENSSL_EXPORT int CBS_get_asn1_uint64(CBS *cbs, uint64_t *out);
+/* CBS_get_optional_asn1 gets an optional explicitly-tagged element
+ * from |cbs| tagged with |tag| and sets |*out| to its contents. If
+ * present, it sets |*out_present| to one, otherwise zero. It returns
+ * one on success, whether or not the element was present, and zero on
+ * decode failure. */
+OPENSSL_EXPORT int CBS_get_optional_asn1(CBS *cbs, CBS *out, int *out_present,
+ unsigned tag);
+
+/* CBS_get_optional_asn1_octet_string gets an optional
+ * explicitly-tagged OCTET STRING from |cbs|. If present, it sets
+ * |*out| to the string and |*out_present| to one. Otherwise, it sets
+ * |*out| to empty and |*out_present| to zero. |out_present| may be
+ * NULL. It returns one on success, whether or not the element was
+ * present, and zero on decode failure. */
+OPENSSL_EXPORT int CBS_get_optional_asn1_octet_string(CBS *cbs, CBS *out,
+ int *out_present,
+ unsigned tag);
+
+/* CBS_get_optional_asn1_uint64 gets an optional explicitly-tagged
+ * INTEGER from |cbs|. If present, it sets |*out| to the
+ * value. Otherwise, it sets |*out| to |default_value|. It returns one
+ * on success, whether or not the element was present, and zero on
+ * decode failure. */
+OPENSSL_EXPORT int CBS_get_optional_asn1_uint64(CBS *cbs, uint64_t *out,
+ unsigned tag,
+ uint64_t default_value);
+
+/* CBS_get_optional_asn1_bool gets an optional, explicitly-tagged BOOLEAN from
+ * |cbs|. If present, it sets |*out| to either zero or one, based on the
+ * boolean. Otherwise, it sets |*out| to |default_value|. It returns one on
+ * success, whether or not the element was present, and zero on decode
+ * failure. */
+OPENSSL_EXPORT int CBS_get_optional_asn1_bool(CBS *cbs, int *out, unsigned tag,
+ int default_value);
+
/* CRYPTO ByteBuilder.
*
@@ -277,6 +312,10 @@ OPENSSL_EXPORT int CBB_add_u16(CBB *cbb, uint16_t value);
* returns one on success and zero otherwise. */
OPENSSL_EXPORT int CBB_add_u24(CBB *cbb, uint32_t value);
+/* CBB_add_asn1_uint64 writes an ASN.1 INTEGER into |cbb| using |CBB_add_asn1|
+ * and writes |value| in its contents. It returns one on success and zero on
+ * error. */
+OPENSSL_EXPORT int CBB_add_asn1_uint64(CBB *cbb, uint64_t value);
#if defined(__cplusplus)
} /* extern C */
diff --git a/include/openssl/evp.h b/include/openssl/evp.h
index e3922a3..1f60145 100644
--- a/include/openssl/evp.h
+++ b/include/openssl/evp.h
@@ -290,10 +290,7 @@ OPENSSL_EXPORT int EVP_DigestVerifyUpdate(EVP_MD_CTX *ctx, const void *data,
/* EVP_DigestVerifyFinal verifies that |sig_len| bytes of |sig| are a valid
* signature for the data that has been included by one or more calls to
- * |EVP_DigestVerifyUpdate|.
- *
- * It returns one on success and <= 0 on error. WARNING: this differs from the
- * usual return value convention. */
+ * |EVP_DigestVerifyUpdate|. It returns one on success and zero otherwise. */
OPENSSL_EXPORT int EVP_DigestVerifyFinal(EVP_MD_CTX *ctx, const uint8_t *sig,
size_t sig_len);
@@ -462,8 +459,8 @@ OPENSSL_EXPORT int EVP_PKEY_sign_init(EVP_PKEY_CTX *ctx);
* space available at |sig|. If sufficient, the signature will be written to
* |sig| and |*sig_len| updated with the true length.
*
- * WARNING: Setting |out| to NULL only gives the maximum size of the
- * plaintext. The actual plaintext may be smaller.
+ * WARNING: Setting |sig| to NULL only gives the maximum size of the
+ * signature. The actual signature may be smaller.
*
* It returns one on success or zero on error. (Note: this differs from
* OpenSSL, which can also return negative values to indicate an error. ) */
diff --git a/include/openssl/srtp.h b/include/openssl/srtp.h
index c11608e..860362b 100644
--- a/include/openssl/srtp.h
+++ b/include/openssl/srtp.h
@@ -115,14 +115,15 @@
Copyright (C) 2011, RTFM, Inc.
*/
-#ifndef HEADER_D1_SRTP_H
-#define HEADER_D1_SRTP_H
+#ifndef OPENSSL_HEADER_SRTP_H
+#define OPENSSL_HEADER_SRTP_H
#ifdef __cplusplus
extern "C" {
#endif
-
+
+/* Constants for SRTP profiles */
#define SRTP_AES128_CM_SHA1_80 0x0001
#define SRTP_AES128_CM_SHA1_32 0x0002
#define SRTP_AES128_F8_SHA1_80 0x0003
@@ -130,32 +131,47 @@ extern "C" {
#define SRTP_NULL_SHA1_80 0x0005
#define SRTP_NULL_SHA1_32 0x0006
-/* SSL_CTX_set_tlsext_use_srtp enables SRTP for all SSL objects
- * created from |ctx|. |profile| contains a colon-separated list of
- * profile names. It returns zero on success and one on failure.
+/* SSL_CTX_set_srtp_profiles enables SRTP for all SSL objects created from
+ * |ctx|. |profile| contains a colon-separated list of profile names. It returns
+ * one on success and zero on failure. */
+OPENSSL_EXPORT int SSL_CTX_set_srtp_profiles(SSL_CTX *ctx,
+ const char *profiles);
+
+/* SSL_set_srtp_profiles enables SRTP for |ssl|. |profile| contains a
+ * colon-separated list of profile names. It returns one on success and zero on
+ * failure. */
+OPENSSL_EXPORT int SSL_set_srtp_profiles(SSL *ctx, const char *profiles);
+
+/* SSL_get_srtp_profiles returns the SRTP profiles supported by |ssl|. */
+OPENSSL_EXPORT STACK_OF(SRTP_PROTECTION_PROFILE) *SSL_get_srtp_profiles(
+ SSL *ssl);
+
+/* SSL_get_selected_srtp_profile returns the selected SRTP profile, or NULL if
+ * SRTP was not negotiated. */
+OPENSSL_EXPORT SRTP_PROTECTION_PROFILE *SSL_get_selected_srtp_profile(SSL *s);
+
+
+/* Deprecated functions */
+
+/* SSL_CTX_set_tlsext_use_srtp calls SSL_CTX_set_srtp_profiles. It returns zero
+ * on success and one on failure.
*
- * WARNING: this function is dangerous because it breaks the usual
- * return value convention. */
+ * WARNING: this function is dangerous because it breaks the usual return value
+ * convention. Use SSL_CTX_set_srtp_profiles instead. */
OPENSSL_EXPORT int SSL_CTX_set_tlsext_use_srtp(SSL_CTX *ctx,
const char *profiles);
-/* SSL_set_tlsext_use_srtp enables SRTP for |ssl| with a profile list.
- * |profile| contains a colon-separated list of profile names. It
- * returns zero on success and one on failure.
+/* SSL_set_tlsext_use_srtp calls SSL_set_srtp_profiles. It returns zero on
+ * success and one on failure.
*
- * WARNING: this function is dangerous because it breaks the usual
- * return value convention. */
+ * WARNING: this function is dangerous because it breaks the usual return value
+ * convention. Use SSL_set_srtp_profiles instead. */
OPENSSL_EXPORT int SSL_set_tlsext_use_srtp(SSL *ctx, const char *profiles);
-OPENSSL_EXPORT SRTP_PROTECTION_PROFILE *SSL_get_selected_srtp_profile(SSL *s);
-
-OPENSSL_EXPORT STACK_OF(SRTP_PROTECTION_PROFILE) *
- SSL_get_srtp_profiles(SSL *ssl);
-OPENSSL_EXPORT SRTP_PROTECTION_PROFILE *SSL_get_selected_srtp_profile(SSL *s);
#ifdef __cplusplus
-}
+} /* extern C */
#endif
-#endif
+#endif /* OPENSSL_HEADER_SRTP_H */
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 2168613..37521bd 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -359,34 +359,8 @@ struct ssl_method_st
long (*ssl_ctx_callback_ctrl)(SSL_CTX *s, int cb_id, void (*fp)(void));
};
-/* Lets make this into an ASN.1 type structure as follows
- * SSL_SESSION_ID ::= SEQUENCE {
- * version INTEGER, -- structure version number
- * SSLversion INTEGER, -- SSL version number
- * Cipher OCTET STRING, -- the 3 byte cipher ID
- * Session_ID OCTET STRING, -- the Session ID
- * Master_key OCTET STRING, -- the master key
- * Key_Arg [ 0 ] IMPLICIT OCTET STRING, -- the optional Key argument
- * Time [ 1 ] EXPLICIT INTEGER, -- optional Start Time
- * Timeout [ 2 ] EXPLICIT INTEGER, -- optional Timeout ins seconds
- * Peer [ 3 ] EXPLICIT X509, -- optional Peer Certificate
- * Session_ID_context [ 4 ] EXPLICIT OCTET STRING, -- the Session ID context
- * Verify_result [ 5 ] EXPLICIT INTEGER, -- X509_V_... code for `Peer'
- * HostName [ 6 ] EXPLICIT OCTET STRING, -- optional HostName from servername TLS extension
- * PSK_identity_hint [ 7 ] EXPLICIT OCTET STRING, -- optional PSK identity hint
- * PSK_identity [ 8 ] EXPLICIT OCTET STRING, -- optional PSK identity
- * Ticket_lifetime_hint [9] EXPLICIT INTEGER, -- server's lifetime hint for session ticket
- * Ticket [10] EXPLICIT OCTET STRING, -- session ticket (clients only)
- * Compression_meth [11] EXPLICIT OCTET STRING, -- optional compression method
- * SRP_username [ 12 ] EXPLICIT OCTET STRING -- optional SRP username
- * Peer SHA256 [13] EXPLICIT OCTET STRING, -- optional SHA256 hash of Peer certifiate
- * original handshake hash [14] EXPLICIT OCTET STRING, -- optional original handshake hash
- * tlsext_signed_cert_timestamp_list [15] EXPLICIT OCTET STRING, -- optional signed cert timestamp list extension
- * ocsp_response [16] EXPLICIT OCTET STRING, -- optional saved OCSP response from the server
- * }
- * Look in ssl/ssl_asn1.c for more details
- * I'm using EXPLICIT tags so I can read the damn things using asn1parse :-).
- */
+/* An SSL_SESSION represents an SSL session that may be resumed in an
+ * abbreviated handshake. */
struct ssl_session_st
{
int ssl_version; /* what ssl version session info is
@@ -458,6 +432,11 @@ struct ssl_session_st
* resumption. */
unsigned char original_handshake_hash[EVP_MAX_MD_SIZE];
unsigned int original_handshake_hash_len;
+
+ /* extended_master_secret is true if the master secret in this session
+ * was generated using EMS and thus isn't vulnerable to the Triple
+ * Handshake attack. */
+ char extended_master_secret;
};
#endif
@@ -1978,18 +1957,52 @@ OPENSSL_EXPORT int SSL_SESSION_print_fp(FILE *fp,const SSL_SESSION *ses);
OPENSSL_EXPORT int SSL_SESSION_print(BIO *fp,const SSL_SESSION *ses);
#endif
OPENSSL_EXPORT void SSL_SESSION_free(SSL_SESSION *ses);
-OPENSSL_EXPORT int i2d_SSL_SESSION(SSL_SESSION *in,unsigned char **pp);
OPENSSL_EXPORT int SSL_set_session(SSL *to, SSL_SESSION *session);
OPENSSL_EXPORT int SSL_CTX_add_session(SSL_CTX *s, SSL_SESSION *c);
OPENSSL_EXPORT int SSL_CTX_remove_session(SSL_CTX *,SSL_SESSION *c);
OPENSSL_EXPORT int SSL_CTX_set_generate_session_id(SSL_CTX *, GEN_SESSION_CB);
OPENSSL_EXPORT int SSL_set_generate_session_id(SSL *, GEN_SESSION_CB);
OPENSSL_EXPORT int SSL_has_matching_session_id(const SSL *ssl, const unsigned char *id, unsigned int id_len);
-OPENSSL_EXPORT SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a,const unsigned char **pp, long length);
-#ifdef HEADER_X509_H
+/* SSL_SESSION_to_bytes serializes |in| into a newly allocated buffer
+ * and sets |*out_data| to that buffer and |*out_len| to its
+ * length. The caller takes ownership of the buffer and must call
+ * |OPENSSL_free| when done. It returns one on success and zero on
+ * error. */
+OPENSSL_EXPORT int SSL_SESSION_to_bytes(SSL_SESSION *in, uint8_t **out_data,
+ size_t *out_len);
+
+/* SSL_SESSION_to_bytes_for_ticket serializes |in|, but excludes the
+ * session ID which is not necessary in a session ticket. */
+OPENSSL_EXPORT int SSL_SESSION_to_bytes_for_ticket(SSL_SESSION *in,
+ uint8_t **out_data,
+ size_t *out_len);
+
+/* Deprecated: i2d_SSL_SESSION serializes |in| to the bytes pointed to
+ * by |*pp|. On success, it returns the number of bytes written and
+ * advances |*pp| by that many bytes. On failure, it returns -1. If
+ * |pp| is NULL, no bytes are written and only the length is
+ * returned.
+ *
+ * Use SSL_SESSION_to_bytes instead. */
+OPENSSL_EXPORT int i2d_SSL_SESSION(SSL_SESSION *in, uint8_t **pp);
+
+/* d2i_SSL_SESSION deserializes a serialized buffer contained in the
+ * |length| bytes pointed to by |*pp|. It returns the new SSL_SESSION
+ * and advances |*pp| by the number of bytes consumed on success and
+ * NULL on failure. If |a| is NULL, the caller takes ownership of the
+ * new session and must call |SSL_SESSION_free| when done.
+ *
+ * If |a| and |*a| are not NULL, the SSL_SESSION at |*a| is overridden
+ * with the deserialized session rather than allocating a new one. In
+ * addition, |a| is not NULL, but |*a| is, |*a| is set to the new
+ * SSL_SESSION.
+ *
+ * Passing a value other than NULL to |a| is deprecated. */
+OPENSSL_EXPORT SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const uint8_t **pp,
+ long length);
+
OPENSSL_EXPORT X509 * SSL_get_peer_certificate(const SSL *s);
-#endif
OPENSSL_EXPORT STACK_OF(X509) *SSL_get_peer_cert_chain(const SSL *s);
@@ -2461,6 +2474,12 @@ OPENSSL_EXPORT void ERR_load_SSL_strings(void);
#define SSL_F_ssl3_cert_verify_hash 284
#define SSL_F_ssl_ctx_log_rsa_client_key_exchange 285
#define SSL_F_ssl_ctx_log_master_secret 286
+#define SSL_F_d2i_SSL_SESSION 287
+#define SSL_F_i2d_SSL_SESSION 288
+#define SSL_F_d2i_SSL_SESSION_get_octet_string 289
+#define SSL_F_d2i_SSL_SESSION_get_string 290
+#define SSL_F_ssl3_send_new_session_ticket 291
+#define SSL_F_SSL_SESSION_to_bytes_full 292
#define SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS 100
#define SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC 101
#define SSL_R_INVALID_NULL_CMD_NAME 102
@@ -2774,6 +2793,7 @@ OPENSSL_EXPORT void ERR_load_SSL_strings(void);
#define SSL_R_UNPROCESSED_HANDSHAKE_DATA 440
#define SSL_R_HANDSHAKE_RECORD_BEFORE_CCS 441
#define SSL_R_SESSION_MAY_NOT_BE_CREATED 442
+#define SSL_R_INVALID_SSL_SESSION 443
#define SSL_R_SSLV3_ALERT_CLOSE_NOTIFY 1000
#define SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE 1010
#define SSL_R_SSLV3_ALERT_BAD_RECORD_MAC 1020
diff --git a/include/openssl/ssl3.h b/include/openssl/ssl3.h
index 2a201aa..3d62763 100644
--- a/include/openssl/ssl3.h
+++ b/include/openssl/ssl3.h
@@ -485,6 +485,15 @@ typedef struct ssl3_state_st
* this extension to the client. */
uint16_t *peer_ellipticcurvelist;
size_t peer_ellipticcurvelist_length;
+
+ /* extended_master_secret indicates whether the extended master
+ * secret computation is used in this handshake. Note that this
+ * is different from whether it was used for the current
+ * session. If this is a resumption handshake then EMS might be
+ * negotiated in the client and server hello messages, but it
+ * doesn't matter if the session that's being resumed didn't
+ * use it to create the master secret initially. */
+ char extended_master_secret;
} tmp;
/* Connection binding to prevent renegotiation attacks */
diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h
index 08ad8e8..d2682dd 100644
--- a/include/openssl/tls1.h
+++ b/include/openssl/tls1.h
@@ -240,6 +240,9 @@ extern "C" {
*/
#define TLSEXT_TYPE_padding 21
+/* https://tools.ietf.org/html/draft-ietf-tls-session-hash-01 */
+#define TLSEXT_TYPE_extended_master_secret 23
+
/* ExtensionType value from RFC4507 */
#define TLSEXT_TYPE_session_ticket 35
@@ -704,6 +707,8 @@ SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB,(void (*)(void))cb)
#define TLS_MD_IV_BLOCK_CONST_SIZE 8
#define TLS_MD_MASTER_SECRET_CONST "master secret"
#define TLS_MD_MASTER_SECRET_CONST_SIZE 13
+#define TLS_MD_EXTENDED_MASTER_SECRET_CONST "extended master secret"
+#define TLS_MD_EXTENDED_MASTER_SECRET_CONST_SIZE 22
/* TLS Session Ticket extension struct */
diff --git a/include/openssl/x509.h b/include/openssl/x509.h
index 398bec7..9766f74 100644
--- a/include/openssl/x509.h
+++ b/include/openssl/x509.h
@@ -143,7 +143,7 @@ DECLARE_STACK_OF(X509_NAME_ENTRY)
DECLARE_ASN1_SET_OF(X509_NAME_ENTRY)
/* we always keep X509_NAMEs in 2 forms. */
-struct X509_name_st
+typedef struct X509_name_st
{
STACK_OF(X509_NAME_ENTRY) *entries;
int modified; /* true if 'bytes' needs to be built */
@@ -155,7 +155,7 @@ struct X509_name_st
/* unsigned long hash; Keep the hash around for lookups */
unsigned char *canon_enc;
int canon_enclen;
- } /* X509_NAME */;
+ } X509_NAME;
DECLARE_STACK_OF(X509_NAME)
diff --git a/ssl/d1_both.c b/ssl/d1_both.c
index 2d944d8..8b225e5 100644
--- a/ssl/d1_both.c
+++ b/ssl/d1_both.c
@@ -229,7 +229,7 @@ dtls1_hm_fragment_free(hm_fragment *frag)
}
/* send s->init_buf in records of type 'type' (SSL3_RT_HANDSHAKE or SSL3_RT_CHANGE_CIPHER_SPEC) */
-int dtls1_do_write(SSL *s, int type)
+int dtls1_do_write(SSL *s, int type, enum should_add_to_finished_hash should_add_to_finished_hash)
{
int ret;
int curr_mtu;
@@ -365,7 +365,8 @@ int dtls1_do_write(SSL *s, int type)
* message got sent. but why would this happen? */
assert(len == (unsigned int)ret);
- if (type == SSL3_RT_HANDSHAKE && ! s->d1->retransmitting)
+ if (type == SSL3_RT_HANDSHAKE && !s->d1->retransmitting &&
+ should_add_to_finished_hash == add_to_finished_hash)
{
/* should not be done for 'Hello Request's, but in that case
* we'll ignore the result anyway */
@@ -967,7 +968,7 @@ int dtls1_send_change_cipher_spec(SSL *s, int a, int b)
}
/* SSL3_ST_CW_CHANGE_B */
- return(dtls1_do_write(s,SSL3_RT_CHANGE_CIPHER_SPEC));
+ return(dtls1_do_write(s,SSL3_RT_CHANGE_CIPHER_SPEC, dont_add_to_finished_hash));
}
int dtls1_read_failed(SSL *s, int code)
@@ -1181,7 +1182,7 @@ dtls1_retransmit_message(SSL *s, unsigned short seq, unsigned long frag_off,
}
ret = dtls1_do_write(s, frag->msg_header.is_ccs ?
- SSL3_RT_CHANGE_CIPHER_SPEC : SSL3_RT_HANDSHAKE);
+ SSL3_RT_CHANGE_CIPHER_SPEC : SSL3_RT_HANDSHAKE, add_to_finished_hash);
/* restore current state */
s->enc_write_ctx = saved_state.enc_write_ctx;
diff --git a/ssl/d1_lib.c b/ssl/d1_lib.c
index 96ce496..650d8e7 100644
--- a/ssl/d1_lib.c
+++ b/ssl/d1_lib.c
@@ -74,8 +74,9 @@
static void get_current_time(OPENSSL_timeval *t);
static OPENSSL_timeval* dtls1_get_timeout(SSL *s, OPENSSL_timeval* timeleft);
static void dtls1_set_handshake_header(SSL *s, int type, unsigned long len);
-static int dtls1_handshake_write(SSL *s);
+static int dtls1_handshake_write(SSL *s, enum should_add_to_finished_hash should_add_to_finished_hash);
int dtls1_listen(SSL *s, struct sockaddr *client);
+static void dtls1_add_to_finished_hash(SSL *s);
SSL3_ENC_METHOD DTLSv1_enc_data={
tls1_enc,
@@ -93,7 +94,8 @@ SSL3_ENC_METHOD DTLSv1_enc_data={
SSL_ENC_FLAG_DTLS|SSL_ENC_FLAG_EXPLICIT_IV,
DTLS1_HM_HEADER_LENGTH,
dtls1_set_handshake_header,
- dtls1_handshake_write
+ dtls1_handshake_write,
+ dtls1_add_to_finished_hash,
};
SSL3_ENC_METHOD DTLSv1_2_enc_data={
@@ -113,7 +115,8 @@ SSL3_ENC_METHOD DTLSv1_2_enc_data={
|SSL_ENC_FLAG_SHA256_PRF|SSL_ENC_FLAG_TLS1_2_CIPHERS,
DTLS1_HM_HEADER_LENGTH,
dtls1_set_handshake_header,
- dtls1_handshake_write
+ dtls1_handshake_write,
+ dtls1_add_to_finished_hash,
};
int dtls1_new(SSL *s)
@@ -502,7 +505,25 @@ static void dtls1_set_handshake_header(SSL *s, int htype, unsigned long len)
dtls1_buffer_message(s, 0);
}
-static int dtls1_handshake_write(SSL *s)
+static int dtls1_handshake_write(SSL *s, enum should_add_to_finished_hash should_add_to_finished_hash)
{
- return dtls1_do_write(s, SSL3_RT_HANDSHAKE);
+ return dtls1_do_write(s, SSL3_RT_HANDSHAKE, should_add_to_finished_hash);
+ }
+
+static void dtls1_add_to_finished_hash(SSL *s)
+ {
+ uint8_t *record = (uint8_t *) &s->init_buf->data[s->init_off];
+ const struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr;
+ uint8_t serialised_header[DTLS1_HM_HEADER_LENGTH];
+ uint8_t *p = serialised_header;
+
+ /* Construct the message header as if it were a single fragment. */
+ *p++ = msg_hdr->type;
+ l2n3(msg_hdr->msg_len, p);
+ s2n (msg_hdr->seq, p);
+ l2n3(0, p);
+ l2n3(msg_hdr->msg_len, p);
+ ssl3_finish_mac(s, serialised_header, sizeof(serialised_header));
+ ssl3_finish_mac(s, record + DTLS1_HM_HEADER_LENGTH,
+ s->init_num - DTLS1_HM_HEADER_LENGTH);
}
diff --git a/ssl/d1_srtp.c b/ssl/d1_srtp.c
index bc278c3..69b11ad 100644
--- a/ssl/d1_srtp.c
+++ b/ssl/d1_srtp.c
@@ -114,8 +114,6 @@
Copyright (C) 2011, RTFM, Inc.
*/
-#ifndef OPENSSL_NO_SRTP
-
#include <stdio.h>
#include <openssl/bytestring.h>
@@ -226,20 +224,17 @@ static int ssl_ctx_make_profiles(const char *profiles_string,STACK_OF(SRTP_PROTE
return 1;
}
-
-int SSL_CTX_set_tlsext_use_srtp(SSL_CTX *ctx,const char *profiles)
+
+int SSL_CTX_set_srtp_profiles(SSL_CTX *ctx, const char *profiles)
{
- /* This API inverts its return value. */
- return !ssl_ctx_make_profiles(profiles,&ctx->srtp_profiles);
+ return ssl_ctx_make_profiles(profiles, &ctx->srtp_profiles);
}
-int SSL_set_tlsext_use_srtp(SSL *s,const char *profiles)
+int SSL_set_srtp_profiles(SSL *s, const char *profiles)
{
- /* This API inverts its return value. */
- return !ssl_ctx_make_profiles(profiles,&s->srtp_profiles);
+ return ssl_ctx_make_profiles(profiles, &s->srtp_profiles);
}
-
STACK_OF(SRTP_PROTECTION_PROFILE) *SSL_get_srtp_profiles(SSL *s)
{
if(s != NULL)
@@ -263,6 +258,18 @@ SRTP_PROTECTION_PROFILE *SSL_get_selected_srtp_profile(SSL *s)
return s->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 *s, const char *profiles)
+ {
+ /* This API inverts its return value. */
+ return !SSL_set_srtp_profiles(s, profiles);
+ }
+
/* Note: this function returns 0 length if there are no
profiles specified */
int ssl_add_clienthello_use_srtp_ext(SSL *s, unsigned char *p, int *len, int maxlen)
@@ -464,6 +471,3 @@ int ssl_parse_serverhello_use_srtp_ext(SSL *s, CBS *cbs, int *out_alert)
*out_alert = SSL_AD_ILLEGAL_PARAMETER;
return 0;
}
-
-
-#endif
diff --git a/ssl/d1_srvr.c b/ssl/d1_srvr.c
index 79da484..e1c5616 100644
--- a/ssl/d1_srvr.c
+++ b/ssl/d1_srvr.c
@@ -687,5 +687,5 @@ int dtls1_send_hello_verify_request(SSL *s)
}
/* s->state = DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B */
- return(dtls1_do_write(s,SSL3_RT_HANDSHAKE));
+ return(dtls1_do_write(s,SSL3_RT_HANDSHAKE, add_to_finished_hash));
}
diff --git a/ssl/s3_both.c b/ssl/s3_both.c
index 6604fc7..bbdeadb 100644
--- a/ssl/s3_both.c
+++ b/ssl/s3_both.c
@@ -127,17 +127,19 @@
#include "ssl_locl.h"
/* send s->init_buf in records of type 'type' (SSL3_RT_HANDSHAKE or SSL3_RT_CHANGE_CIPHER_SPEC) */
-int ssl3_do_write(SSL *s, int type)
+int ssl3_do_write(SSL *s, int type, enum should_add_to_finished_hash should_add_to_finished_hash)
{
int ret;
ret=ssl3_write_bytes(s,type,&s->init_buf->data[s->init_off],
s->init_num);
if (ret < 0) return(-1);
- if (type == SSL3_RT_HANDSHAKE)
+ if (type == SSL3_RT_HANDSHAKE && should_add_to_finished_hash == add_to_finished_hash)
+ {
/* should not be done for 'Hello Request's, but in that case
* we'll ignore the result anyway */
ssl3_finish_mac(s,(unsigned char *)&s->init_buf->data[s->init_off],ret);
+ }
if (ret == s->init_num)
{
@@ -320,7 +322,7 @@ int ssl3_send_change_cipher_spec(SSL *s, int a, int b)
}
/* SSL3_ST_CW_CHANGE_B */
- return(ssl3_do_write(s,SSL3_RT_CHANGE_CIPHER_SPEC));
+ return(ssl3_do_write(s,SSL3_RT_CHANGE_CIPHER_SPEC, dont_add_to_finished_hash));
}
unsigned long ssl3_output_cert_chain(SSL *s, CERT_PKEY *cpk)
diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c
index 6574f5a..355cb0e 100644
--- a/ssl/s3_clnt.c
+++ b/ssl/s3_clnt.c
@@ -982,7 +982,7 @@ int ssl3_get_server_hello(SSL *s)
/* Don't digest cached records if no sigalgs: we may need them for
* client authentication.
*/
- if (!SSL_USE_SIGALGS(s) && !ssl3_digest_cached_records(s))
+ if (!SSL_USE_SIGALGS(s) && !ssl3_digest_cached_records(s, free_handshake_buffer))
goto f_err;
/* Only the NULL compression algorithm is supported. */
@@ -1637,7 +1637,7 @@ int ssl3_get_certificate_request(SSL *s)
*/
if (s->s3->handshake_buffer)
{
- if (!ssl3_digest_cached_records(s))
+ if (!ssl3_digest_cached_records(s, free_handshake_buffer))
goto err;
}
return(1);
@@ -1909,6 +1909,8 @@ int ssl3_send_client_key_exchange(SSL *s)
BN_CTX * bn_ctx = NULL;
unsigned int psk_len = 0;
unsigned char psk[PSK_MAX_PSK_LEN];
+ uint8_t *pms = NULL;
+ size_t pms_len = 0;
if (s->state == SSL3_ST_CW_KEY_EXCH_A)
{
@@ -1917,16 +1919,12 @@ int ssl3_send_client_key_exchange(SSL *s)
alg_k=s->s3->tmp.new_cipher->algorithm_mkey;
alg_a=s->s3->tmp.new_cipher->algorithm_auth;
+ /* If using a PSK key exchange, prepare the pre-shared key. */
if (alg_a & SSL_aPSK)
{
char identity[PSK_MAX_IDENTITY_LEN + 1];
size_t identity_len;
- unsigned char *t = NULL;
- unsigned char pre_ms[PSK_MAX_PSK_LEN*2+4];
- unsigned int pre_ms_len = 0;
- int psk_err = 1;
- n = 0;
if (s->psk_client_callback == NULL)
{
OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, SSL_R_PSK_NO_CLIENT_CB);
@@ -1939,40 +1937,19 @@ int ssl3_send_client_key_exchange(SSL *s)
if (psk_len > PSK_MAX_PSK_LEN)
{
OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_INTERNAL_ERROR);
- goto psk_err;
+ goto err;
}
else if (psk_len == 0)
{
OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, SSL_R_PSK_IDENTITY_NOT_FOUND);
- goto psk_err;
+ ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
+ goto err;
}
identity_len = OPENSSL_strnlen(identity, sizeof(identity));
if (identity_len > PSK_MAX_IDENTITY_LEN)
{
OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_INTERNAL_ERROR);
- goto psk_err;
- }
-
- if (!(alg_k & SSL_kEECDH))
- {
- /* Create the shared secret now if we're not using ECDHE-PSK.
- * TODO(davidben): Refactor this logic similarly
- * to ssl3_get_client_key_exchange. */
- pre_ms_len = 2+psk_len+2+psk_len;
- t = pre_ms;
- s2n(psk_len, t);
- memset(t, 0, psk_len);
- t+=psk_len;
- s2n(psk_len, t);
- memcpy(t, psk, psk_len);
-
- s->session->master_key_length =
- s->method->ssl3_enc->generate_master_secret(s,
- s->session->master_key,
- pre_ms, pre_ms_len);
- s2n(identity_len, p);
- memcpy(p, identity, identity_len);
- n = 2 + identity_len;
+ goto err;
}
if (s->session->psk_identity != NULL)
@@ -1981,23 +1958,30 @@ int ssl3_send_client_key_exchange(SSL *s)
if (s->session->psk_identity == NULL)
{
OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_MALLOC_FAILURE);
- goto psk_err;
- }
- psk_err = 0;
- psk_err:
- OPENSSL_cleanse(identity, sizeof(identity));
- OPENSSL_cleanse(pre_ms, sizeof(pre_ms));
- if (psk_err != 0)
- {
- ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
goto err;
}
+
+ /* Write out psk_identity. */
+ s2n(identity_len, p);
+ memcpy(p, identity, identity_len);
+ p += identity_len;
+ n = 2 + identity_len;
}
+ /* Depending on the key exchange method, compute |pms|
+ * and |pms_len|. */
if (alg_k & SSL_kRSA)
{
RSA *rsa;
- unsigned char tmp_buf[SSL_MAX_MASTER_KEY_LENGTH];
+ size_t enc_pms_len;
+
+ pms_len = SSL_MAX_MASTER_KEY_LENGTH;
+ pms = OPENSSL_malloc(pms_len);
+ if (pms == NULL)
+ {
+ OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
if (s->session->sess_cert == NULL)
{
@@ -2022,49 +2006,47 @@ int ssl3_send_client_key_exchange(SSL *s)
EVP_PKEY_free(pkey);
}
- tmp_buf[0]=s->client_version>>8;
- tmp_buf[1]=s->client_version&0xff;
- if (RAND_bytes(&(tmp_buf[2]),sizeof tmp_buf-2) <= 0)
+ pms[0]=s->client_version>>8;
+ pms[1]=s->client_version&0xff;
+ if (RAND_bytes(&pms[2],SSL_MAX_MASTER_KEY_LENGTH-2) <= 0)
goto err;
- s->session->master_key_length=sizeof tmp_buf;
+ s->session->master_key_length=SSL_MAX_MASTER_KEY_LENGTH;
q=p;
- /* Fix buf for TLS and beyond */
+ /* In TLS and beyond, reserve space for the length prefix. */
if (s->version > SSL3_VERSION)
- p+=2;
- n=RSA_public_encrypt(sizeof tmp_buf,
- tmp_buf,p,rsa,RSA_PKCS1_PADDING);
- if (n <= 0)
+ {
+ p += 2;
+ n += 2;
+ }
+ if (!RSA_encrypt(rsa, &enc_pms_len, p, RSA_size(rsa),
+ pms, pms_len, RSA_PKCS1_PADDING))
{
OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, SSL_R_BAD_RSA_ENCRYPT);
goto err;
}
+ n += enc_pms_len;
/* Log the premaster secret, if logging is enabled. */
if (!ssl_ctx_log_rsa_client_key_exchange(s->ctx,
- p, n, tmp_buf, sizeof(tmp_buf)))
+ p, enc_pms_len, pms, pms_len))
{
goto err;
}
- /* Fix buf for TLS and beyond */
+ /* Fill in the length prefix. */
if (s->version > SSL3_VERSION)
{
- s2n(n,q);
- n+=2;
+ s2n(enc_pms_len, q);
}
-
- s->session->master_key_length=
- s->method->ssl3_enc->generate_master_secret(s,
- s->session->master_key,
- tmp_buf,sizeof tmp_buf);
- OPENSSL_cleanse(tmp_buf,sizeof tmp_buf);
}
else if (alg_k & SSL_kEDH)
{
- DH *dh_srvr,*dh_clnt;
+ DH *dh_srvr, *dh_clnt;
SESS_CERT *scert = s->session->sess_cert;
+ int dh_len;
+ size_t pub_len;
if (scert == NULL)
{
@@ -2093,44 +2075,38 @@ int ssl3_send_client_key_exchange(SSL *s)
goto err;
}
- /* use the 'p' output buffer for the DH key, but
- * make sure to clear it out afterwards */
+ pms_len = DH_size(dh_clnt);
+ pms = OPENSSL_malloc(pms_len);
+ if (pms == NULL)
+ {
+ OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_MALLOC_FAILURE);
+ DH_free(dh_clnt);
+ goto err;
+ }
- n=DH_compute_key(p,dh_srvr->pub_key,dh_clnt);
- if (n <= 0)
+ dh_len = DH_compute_key(pms, dh_srvr->pub_key, dh_clnt);
+ if (dh_len <= 0)
{
OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_DH_LIB);
DH_free(dh_clnt);
goto err;
}
-
- /* generate master key from the result */
- s->session->master_key_length=
- s->method->ssl3_enc->generate_master_secret(s,
- s->session->master_key,p,n);
- /* clean up */
- memset(p,0,n);
+ pms_len = dh_len;
/* send off the data */
- n=BN_num_bytes(dh_clnt->pub_key);
- s2n(n,p);
- BN_bn2bin(dh_clnt->pub_key,p);
- n+=2;
+ pub_len = BN_num_bytes(dh_clnt->pub_key);
+ s2n(pub_len, p);
+ BN_bn2bin(dh_clnt->pub_key, p);
+ n += 2 + pub_len;
DH_free(dh_clnt);
-
- /* perhaps clean things up a bit EAY EAY EAY EAY*/
}
else if (alg_k & SSL_kEECDH)
{
const EC_GROUP *srvr_group = NULL;
EC_KEY *tkey;
- int field_size = 0;
- unsigned char *pre_ms;
- unsigned char *t;
- unsigned int pre_ms_len;
- unsigned int i;
+ int field_size = 0, ecdh_len;
if (s->session->sess_cert == NULL)
{
@@ -2173,54 +2149,28 @@ int ssl3_send_client_key_exchange(SSL *s)
goto err;
}
- /* use the 'p' output buffer for the ECDH key, but
- * make sure to clear it out afterwards
- */
-
field_size = EC_GROUP_get_degree(srvr_group);
if (field_size <= 0)
{
OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_ECDH_LIB);
goto err;
}
- n=ECDH_compute_key(p, (field_size+7)/8, srvr_ecpoint, clnt_ecdh, NULL);
- if (n <= 0)
+
+ pms_len = (field_size + 7) / 8;
+ pms = OPENSSL_malloc(pms_len);
+ if (pms == NULL)
{
- OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_ECDH_LIB);
+ OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_MALLOC_FAILURE);
goto err;
}
- /* ECDHE PSK ciphersuites from RFC 5489 */
- if ((alg_a & SSL_aPSK) && psk_len != 0)
- {
- pre_ms_len = 2+psk_len+2+n;
- pre_ms = OPENSSL_malloc(pre_ms_len);
- if (pre_ms == NULL)
- {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_MALLOC_FAILURE);
- goto err;
- }
- memset(pre_ms, 0, pre_ms_len);
- t = pre_ms;
- s2n(psk_len, t);
- memcpy(t, psk, psk_len);
- t += psk_len;
- s2n(n, t);
- memcpy(t, p, n);
- s->session->master_key_length = s->method->ssl3_enc \
- -> generate_master_secret(s,
- s->session->master_key, pre_ms, pre_ms_len);
- OPENSSL_cleanse(pre_ms, pre_ms_len);
- OPENSSL_free(pre_ms);
- }
- if (!(alg_a & SSL_aPSK))
+ ecdh_len = ECDH_compute_key(pms, pms_len, srvr_ecpoint, clnt_ecdh, NULL);
+ if (ecdh_len <= 0)
{
- /* generate master key from the result */
- s->session->master_key_length = s->method->ssl3_enc \
- -> generate_master_secret(s,
- s->session->master_key, p, n);
+ OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_ECDH_LIB);
+ goto err;
}
- memset(p, 0, n); /* clean up */
+ pms_len = ecdh_len;
/* First check the size of encoding and
* allocate memory accordingly.
@@ -2248,32 +2198,39 @@ int ssl3_send_client_key_exchange(SSL *s)
POINT_CONVERSION_UNCOMPRESSED,
encodedPoint, encoded_pt_len, bn_ctx);
- n = 0;
- if ((alg_a & SSL_aPSK) && psk_len != 0)
- {
- i = strlen(s->session->psk_identity);
- s2n(i, p);
- memcpy(p, s->session->psk_identity, i);
- p += i;
- n = i + 2;
- }
-
*p = encoded_pt_len; /* length of encoded point */
/* Encoded point will be copied here */
p += 1;
n += 1;
/* copy the point */
- memcpy((unsigned char *)p, encodedPoint, encoded_pt_len);
+ memcpy(p, encodedPoint, encoded_pt_len);
/* increment n to account for length field */
n += encoded_pt_len;
/* Free allocated memory */
BN_CTX_free(bn_ctx);
+ bn_ctx = NULL;
OPENSSL_free(encodedPoint);
+ encodedPoint = NULL;
EC_KEY_free(clnt_ecdh);
+ clnt_ecdh = NULL;
EVP_PKEY_free(srvr_pub_pkey);
+ srvr_pub_pkey = NULL;
+ }
+ 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, ssl3_send_client_key_exchange, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ memset(pms, 0, pms_len);
}
- else if (!(alg_k & SSL_kPSK) || ((alg_k & SSL_kPSK) && !(alg_a & SSL_aPSK)))
+ else
{
ssl3_send_alert(s, SSL3_AL_FATAL,
SSL_AD_HANDSHAKE_FAILURE);
@@ -2281,19 +2238,71 @@ int ssl3_send_client_key_exchange(SSL *s)
goto err;
}
+ /* For a PSK cipher suite, other_secret is combined
+ * with the pre-shared key. */
+ if ((alg_a & SSL_aPSK) && psk_len != 0)
+ {
+ CBB cbb, child;
+ uint8_t *new_pms;
+ size_t new_pms_len;
+
+ if (!CBB_init(&cbb, 2 + psk_len + 2 + pms_len))
+ {
+ OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ if (!CBB_add_u16_length_prefixed(&cbb, &child) ||
+ !CBB_add_bytes(&child, pms, pms_len) ||
+ !CBB_add_u16_length_prefixed(&cbb, &child) ||
+ !CBB_add_bytes(&child, psk, psk_len) ||
+ !CBB_finish(&cbb, &new_pms, &new_pms_len))
+ {
+ CBB_cleanup(&cbb);
+ OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ OPENSSL_cleanse(pms, pms_len);
+ OPENSSL_free(pms);
+ pms = new_pms;
+ pms_len = new_pms_len;
+ }
+
ssl_set_handshake_header(s, SSL3_MT_CLIENT_KEY_EXCHANGE, n);
s->state=SSL3_ST_CW_KEY_EXCH_B;
+
+ /* The message must be added to the finished hash before
+ * calculating the master secret. */
+ s->method->ssl3_enc->add_to_finished_hash(s);
+
+ s->session->master_key_length =
+ s->method->ssl3_enc->generate_master_secret(s,
+ s->session->master_key,
+ pms, pms_len);
+ if (s->session->master_key_length == 0)
+ {
+ goto err;
+ }
+ s->session->extended_master_secret = s->s3->tmp.extended_master_secret;
+ OPENSSL_cleanse(pms, pms_len);
+ OPENSSL_free(pms);
}
/* SSL3_ST_CW_KEY_EXCH_B */
- return ssl_do_write(s);
+ /* The message has already been added to the finished hash. */
+ return s->method->ssl3_enc->do_write(s, dont_add_to_finished_hash);
+
err:
BN_CTX_free(bn_ctx);
if (encodedPoint != NULL) OPENSSL_free(encodedPoint);
if (clnt_ecdh != NULL)
EC_KEY_free(clnt_ecdh);
EVP_PKEY_free(srvr_pub_pkey);
- return(-1);
+ if (pms)
+ {
+ OPENSSL_cleanse(pms, pms_len);
+ OPENSSL_free(pms);
+ }
+ return -1;
}
int ssl3_send_cert_verify(SSL *s)
@@ -2332,7 +2341,7 @@ int ssl3_send_cert_verify(SSL *s)
goto err;
/* The handshake buffer is no longer necessary. */
- if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s))
+ if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s, free_handshake_buffer))
goto err;
/* Sign the digest. */
@@ -2583,7 +2592,7 @@ int ssl3_send_next_proto(SSL *s)
s->init_off = 0;
}
- return ssl3_do_write(s, SSL3_RT_HANDSHAKE);
+ return ssl3_do_write(s, SSL3_RT_HANDSHAKE, add_to_finished_hash);
}
@@ -2597,7 +2606,7 @@ int ssl3_send_channel_id(SSL *s)
unsigned char *public_key = NULL, *derp, *der_sig = NULL;
if (s->state != SSL3_ST_CW_CHANNEL_ID_A)
- return ssl3_do_write(s, SSL3_RT_HANDSHAKE);
+ return ssl3_do_write(s, SSL3_RT_HANDSHAKE, add_to_finished_hash);
if (!s->tlsext_channel_id_private && s->ctx->channel_id_cb)
{
@@ -2700,7 +2709,7 @@ int ssl3_send_channel_id(SSL *s)
s->init_num = 4 + 2 + 2 + TLSEXT_CHANNEL_ID_SIZE;
s->init_off = 0;
- ret = ssl3_do_write(s, SSL3_RT_HANDSHAKE);
+ ret = ssl3_do_write(s, SSL3_RT_HANDSHAKE, add_to_finished_hash);
err:
EVP_MD_CTX_cleanup(&md_ctx);
diff --git a/ssl/s3_enc.c b/ssl/s3_enc.c
index b0ca507..fc94a94 100644
--- a/ssl/s3_enc.c
+++ b/ssl/s3_enc.c
@@ -510,7 +510,7 @@ void ssl3_finish_mac(SSL *s, const unsigned char *buf, int len)
}
}
-int ssl3_digest_cached_records(SSL *s)
+int ssl3_digest_cached_records(SSL *s, enum should_free_handshake_buffer_t should_free_handshake_buffer)
{
int i;
long mask;
@@ -542,9 +542,13 @@ int ssl3_digest_cached_records(SSL *s)
s->s3->handshake_dgst[i]=NULL;
}
}
- /* Free handshake_buffer BIO */
- BIO_free(s->s3->handshake_buffer);
- s->s3->handshake_buffer = NULL;
+
+ if (should_free_handshake_buffer == free_handshake_buffer)
+ {
+ /* Free handshake_buffer BIO */
+ BIO_free(s->s3->handshake_buffer);
+ s->s3->handshake_buffer = NULL;
+ }
return 1;
}
@@ -581,7 +585,7 @@ static int ssl3_handshake_mac(SSL *s, int md_nid,
EVP_MD_CTX ctx,*d=NULL;
if (s->s3->handshake_buffer)
- if (!ssl3_digest_cached_records(s))
+ if (!ssl3_digest_cached_records(s, free_handshake_buffer))
return 0;
/* Search for digest of specified type in the handshake_dgst
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index 215b3f6..7721dec 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -942,7 +942,8 @@ SSL3_ENC_METHOD SSLv3_enc_data={
0,
SSL3_HM_HEADER_LENGTH,
ssl3_set_handshake_header,
- ssl3_handshake_write
+ ssl3_handshake_write,
+ ssl3_add_to_finished_hash,
};
int ssl3_num_ciphers(void)
@@ -975,9 +976,14 @@ void ssl3_set_handshake_header(SSL *s, int htype, unsigned long len)
s->init_off = 0;
}
-int ssl3_handshake_write(SSL *s)
+int ssl3_handshake_write(SSL *s, enum should_add_to_finished_hash should_add_to_finished_hash)
{
- return ssl3_do_write(s, SSL3_RT_HANDSHAKE);
+ return ssl3_do_write(s, SSL3_RT_HANDSHAKE, should_add_to_finished_hash);
+ }
+
+void ssl3_add_to_finished_hash(SSL *s)
+ {
+ ssl3_finish_mac(s, (uint8_t*) s->init_buf->data, s->init_num);
}
int ssl3_new(SSL *s)
@@ -1385,9 +1391,9 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg)
}
case SSL_CTRL_GET_EC_POINT_FORMATS:
{
+ const uint8_t **pformat = parg;
if (!s->s3->tmp.peer_ecpointformatlist)
return 0;
- const uint8_t **pformat = parg;
*pformat = s->s3->tmp.peer_ecpointformatlist;
return (int)s->s3->tmp.peer_ecpointformatlist_length;
}
diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c
index 149d9e7..a212efe 100644
--- a/ssl/s3_srvr.c
+++ b/ssl/s3_srvr.c
@@ -444,7 +444,7 @@ int ssl3_accept(SSL *s)
s->s3->tmp.cert_request=0;
s->state=SSL3_ST_SW_SRVR_DONE_A;
if (s->s3->handshake_buffer)
- if (!ssl3_digest_cached_records(s))
+ if (!ssl3_digest_cached_records(s, free_handshake_buffer))
return -1;
}
else
@@ -993,7 +993,8 @@ int ssl3_get_client_hello(SSL *s)
goto f_err;
}
- if (ssl_bytes_to_cipher_list(s, &cipher_suites, &ciphers) == NULL)
+ ciphers = ssl_bytes_to_cipher_list(s, &cipher_suites);
+ if (ciphers == NULL)
{
goto err;
}
@@ -1143,7 +1144,7 @@ int ssl3_get_client_hello(SSL *s)
if (!SSL_USE_SIGALGS(s) || !(s->verify_mode & SSL_VERIFY_PEER))
{
- if (!ssl3_digest_cached_records(s))
+ if (!ssl3_digest_cached_records(s, free_handshake_buffer))
goto f_err;
}
@@ -2140,9 +2141,13 @@ int ssl3_get_client_key_exchange(SSL *s)
}
EVP_PKEY_free(clnt_pub_pkey);
+ clnt_pub_pkey = NULL;
EC_POINT_free(clnt_ecpoint);
+ clnt_ecpoint = NULL;
EC_KEY_free(srvr_ecdh);
+ srvr_ecdh = NULL;
BN_CTX_free(bn_ctx);
+ bn_ctx = NULL;
EC_KEY_free(s->s3->tmp.ecdh);
s->s3->tmp.ecdh = NULL;
@@ -2202,6 +2207,9 @@ int ssl3_get_client_key_exchange(SSL *s)
s->session->master_key_length = s->method->ssl3_enc
->generate_master_secret(s,
s->session->master_key, premaster_secret, premaster_secret_len);
+ if (s->session->master_key_length == 0)
+ goto err;
+ s->session->extended_master_secret = s->s3->tmp.extended_master_secret;
OPENSSL_cleanse(premaster_secret, premaster_secret_len);
OPENSSL_free(premaster_secret);
@@ -2242,7 +2250,7 @@ int ssl3_get_cert_verify(SSL *s)
* client certificate. */
if (peer == NULL)
{
- if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s))
+ if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s, free_handshake_buffer))
return -1;
return 1;
}
@@ -2283,7 +2291,7 @@ int ssl3_get_cert_verify(SSL *s)
/* The handshake buffer is no longer necessary, and we may hash the
* current message.*/
- if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s))
+ if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s, free_handshake_buffer))
goto err;
ssl3_hash_current_message(s);
@@ -2452,7 +2460,7 @@ int ssl3_get_client_certificate(SSL *s)
goto f_err;
}
/* No client certificate so digest cached records */
- if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s))
+ if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s, free_handshake_buffer))
{
al=SSL_AD_INTERNAL_ERROR;
goto f_err;
@@ -2531,61 +2539,62 @@ int ssl3_send_new_session_ticket(SSL *s)
{
if (s->state == SSL3_ST_SW_SESSION_TICKET_A)
{
- unsigned char *p, *senc, *macstart;
- const unsigned char *const_p;
- int len, slen_full, slen;
- SSL_SESSION *sess;
+ uint8_t *session;
+ size_t session_len;
+ uint8_t *p, *macstart;
+ int len;
unsigned int hlen;
EVP_CIPHER_CTX ctx;
HMAC_CTX hctx;
SSL_CTX *tctx = s->initial_ctx;
unsigned char iv[EVP_MAX_IV_LENGTH];
unsigned char key_name[16];
+ /* The maximum overhead of encrypting the session is 16 (key
+ * name) + IV + one block of encryption overhead + HMAC. */
+ const size_t max_ticket_overhead = 16 + EVP_MAX_IV_LENGTH +
+ EVP_MAX_BLOCK_LENGTH + EVP_MAX_MD_SIZE;
- /* get session encoding length */
- slen_full = i2d_SSL_SESSION(s->session, NULL);
- /* Some length values are 16 bits, so forget it if session is
- * too long
- */
- if (slen_full > 0xFF00)
- return -1;
- senc = OPENSSL_malloc(slen_full);
- if (!senc)
- return -1;
- p = senc;
- i2d_SSL_SESSION(s->session, &p);
-
- /* create a fresh copy (not shared with other threads) to clean up */
- const_p = senc;
- sess = d2i_SSL_SESSION(NULL, &const_p, slen_full);
- if (sess == NULL)
+ /* Serialize the SSL_SESSION to be encoded into the ticket. */
+ if (!SSL_SESSION_to_bytes_for_ticket(s->session, &session,
+ &session_len))
{
- OPENSSL_free(senc);
return -1;
}
- sess->session_id_length = 0; /* ID is irrelevant for the ticket */
- slen = i2d_SSL_SESSION(sess, NULL);
- if (slen > slen_full) /* shouldn't ever happen */
+ /* If the session is too long, emit a dummy value rather than
+ * abort the connection. */
+ if (session_len > 0xFFFF - max_ticket_overhead)
{
- OPENSSL_free(senc);
- return -1;
+ const char kTicketPlaceholder[] = "TICKET TOO LARGE";
+ size_t placeholder_len = strlen(kTicketPlaceholder);
+
+ OPENSSL_free(session);
+
+ p = ssl_handshake_start(s);
+ /* Emit ticket_lifetime_hint. */
+ l2n(0, p);
+ /* Emit ticket. */
+ s2n(placeholder_len, p);
+ memcpy(p, kTicketPlaceholder, placeholder_len);
+ p += placeholder_len;
+
+ len = p - ssl_handshake_start(s);
+ ssl_set_handshake_header(s, SSL3_MT_NEWSESSION_TICKET, len);
+ s->state = SSL3_ST_SW_SESSION_TICKET_B;
+ return ssl_do_write(s);
}
- p = senc;
- i2d_SSL_SESSION(sess, &p);
- SSL_SESSION_free(sess);
/* Grow buffer if need be: the length calculation is as
- * follows handshake_header_length +
+ * follows: handshake_header_length +
* 4 (ticket lifetime hint) + 2 (ticket length) +
- * 16 (key name) + max_iv_len (iv length) +
- * session_length + max_enc_block_size (max encrypted session
- * length) + max_md_size (HMAC).
- */
+ * max_ticket_overhead + * session_length */
if (!BUF_MEM_grow(s->init_buf,
- SSL_HM_HEADER_LENGTH(s) + 22 + EVP_MAX_IV_LENGTH +
- EVP_MAX_BLOCK_LENGTH + EVP_MAX_MD_SIZE + slen))
+ SSL_HM_HEADER_LENGTH(s) + 6 +
+ max_ticket_overhead + session_len))
+ {
+ OPENSSL_free(session);
return -1;
+ }
p = ssl_handshake_start(s);
EVP_CIPHER_CTX_init(&ctx);
HMAC_CTX_init(&hctx);
@@ -2598,7 +2607,7 @@ int ssl3_send_new_session_ticket(SSL *s)
if (tctx->tlsext_ticket_key_cb(s, key_name, iv, &ctx,
&hctx, 1) < 0)
{
- OPENSSL_free(senc);
+ OPENSSL_free(session);
return -1;
}
}
@@ -2628,7 +2637,7 @@ int ssl3_send_new_session_ticket(SSL *s)
memcpy(p, iv, EVP_CIPHER_CTX_iv_length(&ctx));
p += EVP_CIPHER_CTX_iv_length(&ctx);
/* Encrypt session data */
- EVP_EncryptUpdate(&ctx, p, &len, senc, slen);
+ EVP_EncryptUpdate(&ctx, p, &len, session, session_len);
p += len;
EVP_EncryptFinal_ex(&ctx, p, &len);
p += len;
@@ -2647,7 +2656,7 @@ int ssl3_send_new_session_ticket(SSL *s)
p = ssl_handshake_start(s) + 4;
s2n(len - 6, p);
s->state=SSL3_ST_SW_SESSION_TICKET_B;
- OPENSSL_free(senc);
+ OPENSSL_free(session);
}
/* SSL3_ST_SW_SESSION_TICKET_B */
diff --git a/ssl/ssl_asn1.c b/ssl/ssl_asn1.c
index 5e86017..ef7ebdc 100644
--- a/ssl/ssl_asn1.c
+++ b/ssl/ssl_asn1.c
@@ -80,538 +80,530 @@
* OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
* OTHERWISE. */
-#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
-#include <openssl/asn1.h>
-#include <openssl/asn1_mac.h>
+#include <openssl/bytestring.h>
#include <openssl/err.h>
-#include <openssl/mem.h>
-#include <openssl/obj.h>
#include <openssl/x509.h>
#include "ssl_locl.h"
-OPENSSL_DECLARE_ERROR_REASON(SSL, CIPHER_CODE_WRONG_LENGTH);
-OPENSSL_DECLARE_ERROR_REASON(SSL, UNKNOWN_SSL_VERSION);
-OPENSSL_DECLARE_ERROR_REASON(SSL, BAD_LENGTH);
-OPENSSL_DECLARE_ERROR_FUNCTION(SSL, D2I_SSL_SESSION);
-
-
-typedef struct ssl_session_asn1_st
- {
- ASN1_INTEGER version;
- ASN1_INTEGER ssl_version;
- ASN1_OCTET_STRING cipher;
- ASN1_OCTET_STRING comp_id;
- ASN1_OCTET_STRING master_key;
- ASN1_OCTET_STRING session_id;
- ASN1_OCTET_STRING session_id_context;
- ASN1_INTEGER time;
- ASN1_INTEGER timeout;
- ASN1_INTEGER verify_result;
- ASN1_OCTET_STRING tlsext_hostname;
- ASN1_INTEGER tlsext_tick_lifetime;
- ASN1_OCTET_STRING tlsext_tick;
- ASN1_OCTET_STRING psk_identity_hint;
- ASN1_OCTET_STRING psk_identity;
- ASN1_OCTET_STRING peer_sha256;
- ASN1_OCTET_STRING original_handshake_hash;
- ASN1_OCTET_STRING tlsext_signed_cert_timestamp_list;
- ASN1_OCTET_STRING ocsp_response;
- } SSL_SESSION_ASN1;
-
-int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp)
- {
-#define LSIZE2 (sizeof(long)*2)
- int v1=0,v2=0,v3=0,v4=0,v5=0,v7=0,v8=0,v13=0,v14=0,v15=0,v16=0;
- unsigned char buf[4],ibuf1[LSIZE2],ibuf2[LSIZE2];
- unsigned char ibuf3[LSIZE2],ibuf4[LSIZE2],ibuf5[LSIZE2];
- int v6=0,v9=0,v10=0;
- unsigned char ibuf6[LSIZE2];
- long l;
- SSL_SESSION_ASN1 a;
- M_ASN1_I2D_vars(in);
-
- if ((in == NULL) || ((in->cipher == NULL) && (in->cipher_id == 0)))
- return(0);
-
- /* Note that I cheat in the following 2 assignments. I know
- * that if the ASN1_INTEGER passed to ASN1_INTEGER_set
- * is > sizeof(long)+1, the buffer will not be re-OPENSSL_malloc()ed.
- * This is a bit evil but makes things simple, no dynamic allocation
- * to clean up :-) */
- a.version.length=LSIZE2;
- a.version.type=V_ASN1_INTEGER;
- a.version.data=ibuf1;
- ASN1_INTEGER_set(&(a.version),SSL_SESSION_ASN1_VERSION);
-
- a.ssl_version.length=LSIZE2;
- a.ssl_version.type=V_ASN1_INTEGER;
- a.ssl_version.data=ibuf2;
- ASN1_INTEGER_set(&(a.ssl_version),in->ssl_version);
-
- a.cipher.type=V_ASN1_OCTET_STRING;
- a.cipher.data=buf;
-
- if (in->cipher == NULL)
- l=in->cipher_id;
- else
- l=in->cipher->id;
- if (in->ssl_version == SSL2_VERSION)
- {
- a.cipher.length=3;
- buf[0]=((unsigned char)(l>>16L))&0xff;
- buf[1]=((unsigned char)(l>> 8L))&0xff;
- buf[2]=((unsigned char)(l ))&0xff;
- }
- else
- {
- a.cipher.length=2;
- buf[0]=((unsigned char)(l>>8L))&0xff;
- buf[1]=((unsigned char)(l ))&0xff;
- }
-
-
- a.master_key.length=in->master_key_length;
- a.master_key.type=V_ASN1_OCTET_STRING;
- a.master_key.data=in->master_key;
-
- a.session_id.length=in->session_id_length;
- a.session_id.type=V_ASN1_OCTET_STRING;
- a.session_id.data=in->session_id;
-
- a.session_id_context.length=in->sid_ctx_length;
- a.session_id_context.type=V_ASN1_OCTET_STRING;
- a.session_id_context.data=in->sid_ctx;
-
- if (in->time != 0L)
- {
- a.time.length=LSIZE2;
- a.time.type=V_ASN1_INTEGER;
- a.time.data=ibuf3;
- ASN1_INTEGER_set(&(a.time),in->time);
- }
-
- if (in->timeout != 0L)
- {
- a.timeout.length=LSIZE2;
- a.timeout.type=V_ASN1_INTEGER;
- a.timeout.data=ibuf4;
- ASN1_INTEGER_set(&(a.timeout),in->timeout);
- }
-
- if (in->verify_result != X509_V_OK)
- {
- a.verify_result.length=LSIZE2;
- a.verify_result.type=V_ASN1_INTEGER;
- a.verify_result.data=ibuf5;
- ASN1_INTEGER_set(&a.verify_result,in->verify_result);
- }
-
- if (in->tlsext_hostname)
- {
- a.tlsext_hostname.length=strlen(in->tlsext_hostname);
- a.tlsext_hostname.type=V_ASN1_OCTET_STRING;
- a.tlsext_hostname.data=(unsigned char *)in->tlsext_hostname;
- }
- if (in->tlsext_tick)
- {
- a.tlsext_tick.length= in->tlsext_ticklen;
- a.tlsext_tick.type=V_ASN1_OCTET_STRING;
- a.tlsext_tick.data=(unsigned char *)in->tlsext_tick;
- }
- if (in->tlsext_tick_lifetime_hint > 0)
- {
- a.tlsext_tick_lifetime.length=LSIZE2;
- a.tlsext_tick_lifetime.type=V_ASN1_INTEGER;
- a.tlsext_tick_lifetime.data=ibuf6;
- ASN1_INTEGER_set(&a.tlsext_tick_lifetime,in->tlsext_tick_lifetime_hint);
- }
- if (in->psk_identity_hint)
- {
- a.psk_identity_hint.length=strlen(in->psk_identity_hint);
- a.psk_identity_hint.type=V_ASN1_OCTET_STRING;
- a.psk_identity_hint.data=(unsigned char *)(in->psk_identity_hint);
- }
- if (in->psk_identity)
- {
- a.psk_identity.length=strlen(in->psk_identity);
- a.psk_identity.type=V_ASN1_OCTET_STRING;
- a.psk_identity.data=(unsigned char *)(in->psk_identity);
- }
-
- if (in->peer_sha256_valid)
- {
- a.peer_sha256.length = sizeof(in->peer_sha256);
- a.peer_sha256.type = V_ASN1_OCTET_STRING;
- a.peer_sha256.data = in->peer_sha256;
- }
-
- if (in->original_handshake_hash_len > 0)
- {
- a.original_handshake_hash.length = in->original_handshake_hash_len;
- a.original_handshake_hash.type = V_ASN1_OCTET_STRING;
- a.original_handshake_hash.data = in->original_handshake_hash;
- }
-
- if (in->tlsext_signed_cert_timestamp_list_length > 0)
- {
- a.tlsext_signed_cert_timestamp_list.length =
- in->tlsext_signed_cert_timestamp_list_length;
- a.tlsext_signed_cert_timestamp_list.type = V_ASN1_OCTET_STRING;
- a.tlsext_signed_cert_timestamp_list.data =
- in->tlsext_signed_cert_timestamp_list;
- }
-
- if (in->ocsp_response_length > 0)
- {
- a.ocsp_response.length = in->ocsp_response_length;
- a.ocsp_response.type = V_ASN1_OCTET_STRING;
- a.ocsp_response.data = in->ocsp_response;
- }
-
- M_ASN1_I2D_len(&(a.version), i2d_ASN1_INTEGER);
- M_ASN1_I2D_len(&(a.ssl_version), i2d_ASN1_INTEGER);
- M_ASN1_I2D_len(&(a.cipher), i2d_ASN1_OCTET_STRING);
- M_ASN1_I2D_len(&(a.session_id), i2d_ASN1_OCTET_STRING);
- M_ASN1_I2D_len(&(a.master_key), i2d_ASN1_OCTET_STRING);
- if (in->time != 0L)
- M_ASN1_I2D_len_EXP_opt(&(a.time),i2d_ASN1_INTEGER,1,v1);
- if (in->timeout != 0L)
- M_ASN1_I2D_len_EXP_opt(&(a.timeout),i2d_ASN1_INTEGER,2,v2);
- if (in->peer != NULL && in->peer_sha256_valid == 0)
- M_ASN1_I2D_len_EXP_opt(in->peer,i2d_X509,3,v3);
- M_ASN1_I2D_len_EXP_opt(&a.session_id_context,i2d_ASN1_OCTET_STRING,4,v4);
- if (in->verify_result != X509_V_OK)
- M_ASN1_I2D_len_EXP_opt(&(a.verify_result),i2d_ASN1_INTEGER,5,v5);
-
- if (in->tlsext_tick_lifetime_hint > 0)
- M_ASN1_I2D_len_EXP_opt(&a.tlsext_tick_lifetime, i2d_ASN1_INTEGER,9,v9);
- if (in->tlsext_tick)
- M_ASN1_I2D_len_EXP_opt(&(a.tlsext_tick), i2d_ASN1_OCTET_STRING,10,v10);
- if (in->tlsext_hostname)
- M_ASN1_I2D_len_EXP_opt(&(a.tlsext_hostname), i2d_ASN1_OCTET_STRING,6,v6);
- if (in->psk_identity_hint)
- M_ASN1_I2D_len_EXP_opt(&(a.psk_identity_hint), i2d_ASN1_OCTET_STRING,7,v7);
- if (in->psk_identity)
- M_ASN1_I2D_len_EXP_opt(&(a.psk_identity), i2d_ASN1_OCTET_STRING,8,v8);
- if (in->peer_sha256_valid)
- M_ASN1_I2D_len_EXP_opt(&(a.peer_sha256),i2d_ASN1_OCTET_STRING,13,v13);
- if (in->original_handshake_hash_len > 0)
- M_ASN1_I2D_len_EXP_opt(&(a.original_handshake_hash),i2d_ASN1_OCTET_STRING,14,v14);
- if (in->tlsext_signed_cert_timestamp_list_length > 0)
- M_ASN1_I2D_len_EXP_opt(&(a.tlsext_signed_cert_timestamp_list),
- i2d_ASN1_OCTET_STRING, 15, v15);
- if (in->ocsp_response_length > 0)
- M_ASN1_I2D_len_EXP_opt(&(a.ocsp_response), i2d_ASN1_OCTET_STRING, 16, v16);
-
- M_ASN1_I2D_seq_total();
-
- M_ASN1_I2D_put(&(a.version), i2d_ASN1_INTEGER);
- M_ASN1_I2D_put(&(a.ssl_version), i2d_ASN1_INTEGER);
- M_ASN1_I2D_put(&(a.cipher), i2d_ASN1_OCTET_STRING);
- M_ASN1_I2D_put(&(a.session_id), i2d_ASN1_OCTET_STRING);
- M_ASN1_I2D_put(&(a.master_key), i2d_ASN1_OCTET_STRING);
- if (in->time != 0L)
- M_ASN1_I2D_put_EXP_opt(&(a.time),i2d_ASN1_INTEGER,1,v1);
- if (in->timeout != 0L)
- M_ASN1_I2D_put_EXP_opt(&(a.timeout),i2d_ASN1_INTEGER,2,v2);
- if (in->peer != NULL && in->peer_sha256_valid == 0)
- M_ASN1_I2D_put_EXP_opt(in->peer,i2d_X509,3,v3);
- M_ASN1_I2D_put_EXP_opt(&a.session_id_context,i2d_ASN1_OCTET_STRING,4,
- v4);
- if (in->verify_result != X509_V_OK)
- M_ASN1_I2D_put_EXP_opt(&a.verify_result,i2d_ASN1_INTEGER,5,v5);
- if (in->tlsext_hostname)
- M_ASN1_I2D_put_EXP_opt(&(a.tlsext_hostname), i2d_ASN1_OCTET_STRING,6,v6);
- if (in->psk_identity_hint)
- M_ASN1_I2D_put_EXP_opt(&(a.psk_identity_hint), i2d_ASN1_OCTET_STRING,7,v7);
- if (in->psk_identity)
- M_ASN1_I2D_put_EXP_opt(&(a.psk_identity), i2d_ASN1_OCTET_STRING,8,v8);
- if (in->tlsext_tick_lifetime_hint > 0)
- M_ASN1_I2D_put_EXP_opt(&a.tlsext_tick_lifetime, i2d_ASN1_INTEGER,9,v9);
- if (in->tlsext_tick)
- M_ASN1_I2D_put_EXP_opt(&(a.tlsext_tick), i2d_ASN1_OCTET_STRING,10,v10);
- if (in->peer_sha256_valid)
- M_ASN1_I2D_put_EXP_opt(&(a.peer_sha256),i2d_ASN1_OCTET_STRING,13,v13);
- if (in->original_handshake_hash_len > 0)
- M_ASN1_I2D_put_EXP_opt(&(a.original_handshake_hash),i2d_ASN1_OCTET_STRING,14,v14);
- if (in->tlsext_signed_cert_timestamp_list_length > 0)
- M_ASN1_I2D_put_EXP_opt(&(a.tlsext_signed_cert_timestamp_list),
- i2d_ASN1_OCTET_STRING, 15, v15);
- if (in->ocsp_response > 0)
- M_ASN1_I2D_put_EXP_opt(&(a.ocsp_response), i2d_ASN1_OCTET_STRING, 16, v16);
-
- M_ASN1_I2D_finish();
- }
-
-SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp,
- long length)
- {
- int ssl_version=0,i;
- long id;
- ASN1_INTEGER ai,*aip;
- ASN1_OCTET_STRING os,*osp;
- M_ASN1_D2I_vars(a,SSL_SESSION *,SSL_SESSION_new);
-
- aip= &ai;
- osp= &os;
-
- M_ASN1_D2I_Init();
- M_ASN1_D2I_start_sequence();
-
- ai.data=NULL; ai.length=0;
- M_ASN1_D2I_get_x(ASN1_INTEGER,aip,d2i_ASN1_INTEGER);
- if (ai.data != NULL) { OPENSSL_free(ai.data); ai.data=NULL; ai.length=0; }
-
- /* we don't care about the version right now :-) */
- M_ASN1_D2I_get_x(ASN1_INTEGER,aip,d2i_ASN1_INTEGER);
- ssl_version=(int)ASN1_INTEGER_get(aip);
- ret->ssl_version=ssl_version;
- if (ai.data != NULL) { OPENSSL_free(ai.data); ai.data=NULL; ai.length=0; }
-
- os.data=NULL; os.length=0;
- M_ASN1_D2I_get_x(ASN1_OCTET_STRING,osp,d2i_ASN1_OCTET_STRING);
- if (ssl_version == SSL2_VERSION)
- {
- if (os.length != 3)
- {
- c.error=SSL_R_CIPHER_CODE_WRONG_LENGTH;
- c.line=__LINE__;
- goto err;
- }
- id=0x02000000L|
- ((unsigned long)os.data[0]<<16L)|
- ((unsigned long)os.data[1]<< 8L)|
- (unsigned long)os.data[2];
- }
- else if ((ssl_version>>8) >= SSL3_VERSION_MAJOR)
- {
- if (os.length != 2)
- {
- c.error=SSL_R_CIPHER_CODE_WRONG_LENGTH;
- c.line=__LINE__;
- goto err;
- }
- id=0x03000000L|
- ((unsigned long)os.data[0]<<8L)|
- (unsigned long)os.data[1];
- }
- else
- {
- c.error=SSL_R_UNKNOWN_SSL_VERSION;
- c.line=__LINE__;
- goto err;
- }
-
- ret->cipher_id=id;
- ret->cipher = ssl3_get_cipher_by_value(ret->cipher_id & 0xffff);
- if (ret->cipher == NULL)
- {
- c.error=SSL_R_UNSUPPORTED_CIPHER;
- c.line = __LINE__;
- goto err;
- }
-
- M_ASN1_D2I_get_x(ASN1_OCTET_STRING,osp,d2i_ASN1_OCTET_STRING);
- if ((ssl_version>>8) >= SSL3_VERSION_MAJOR)
- i=SSL3_MAX_SSL_SESSION_ID_LENGTH;
- else /* if (ssl_version>>8 == SSL2_VERSION_MAJOR) */
- i=SSL2_MAX_SSL_SESSION_ID_LENGTH;
-
- if (os.length > i)
- os.length = i;
- if (os.length > (int)sizeof(ret->session_id)) /* can't happen */
- os.length = sizeof(ret->session_id);
-
- ret->session_id_length=os.length;
- assert(os.length <= (int)sizeof(ret->session_id));
- memcpy(ret->session_id,os.data,os.length);
-
- M_ASN1_D2I_get_x(ASN1_OCTET_STRING,osp,d2i_ASN1_OCTET_STRING);
- if (os.length > SSL_MAX_MASTER_KEY_LENGTH)
- ret->master_key_length=SSL_MAX_MASTER_KEY_LENGTH;
- else
- ret->master_key_length=os.length;
- memcpy(ret->master_key,os.data,ret->master_key_length);
-
- os.length=0;
-
- /* [0] is the tag for key_arg, a no longer used remnant of
- * SSLv2. */
- M_ASN1_D2I_get_IMP_opt(osp,d2i_ASN1_OCTET_STRING,0,V_ASN1_OCTET_STRING);
- if (os.data != NULL) OPENSSL_free(os.data);
-
- ai.length=0;
- M_ASN1_D2I_get_EXP_opt(aip,d2i_ASN1_INTEGER,1);
- if (ai.data != NULL)
- {
- ret->time=ASN1_INTEGER_get(aip);
- OPENSSL_free(ai.data); ai.data=NULL; ai.length=0;
- }
- else
- ret->time=(unsigned long)time(NULL);
-
- ai.length=0;
- M_ASN1_D2I_get_EXP_opt(aip,d2i_ASN1_INTEGER,2);
- if (ai.data != NULL)
- {
- ret->timeout=ASN1_INTEGER_get(aip);
- OPENSSL_free(ai.data); ai.data=NULL; ai.length=0;
- }
- else
- ret->timeout=3;
-
- if (ret->peer != NULL)
- {
- X509_free(ret->peer);
- ret->peer=NULL;
- }
- M_ASN1_D2I_get_EXP_opt(ret->peer,d2i_X509,3);
-
- os.length=0;
- os.data=NULL;
- M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,4);
-
- if(os.data != NULL)
- {
- if (os.length > SSL_MAX_SID_CTX_LENGTH)
- {
- c.error=SSL_R_BAD_LENGTH;
- c.line=__LINE__;
- goto err;
- }
- else
- {
- ret->sid_ctx_length=os.length;
- memcpy(ret->sid_ctx,os.data,os.length);
- }
- OPENSSL_free(os.data); os.data=NULL; os.length=0;
- }
- else
- ret->sid_ctx_length=0;
-
- ai.length=0;
- M_ASN1_D2I_get_EXP_opt(aip,d2i_ASN1_INTEGER,5);
- if (ai.data != NULL)
- {
- ret->verify_result=ASN1_INTEGER_get(aip);
- OPENSSL_free(ai.data); ai.data=NULL; ai.length=0;
- }
- else
- ret->verify_result=X509_V_OK;
-
- os.length=0;
- os.data=NULL;
- M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,6);
- if (os.data)
- {
- ret->tlsext_hostname = BUF_strndup((char *)os.data, os.length);
- OPENSSL_free(os.data);
- os.data = NULL;
- os.length = 0;
- }
- else
- ret->tlsext_hostname=NULL;
-
- os.length=0;
- os.data=NULL;
- M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,7);
- if (os.data)
- {
- ret->psk_identity_hint = BUF_strndup((char *)os.data, os.length);
- OPENSSL_free(os.data);
- os.data = NULL;
- os.length = 0;
- }
- else
- ret->psk_identity_hint=NULL;
-
- os.length=0;
- os.data=NULL;
- M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,8);
- if (os.data)
- {
- ret->psk_identity = BUF_strndup((char *)os.data, os.length);
- OPENSSL_free(os.data);
- os.data = NULL;
- os.length = 0;
- }
- else
- ret->psk_identity=NULL;
-
- ai.length=0;
- M_ASN1_D2I_get_EXP_opt(aip,d2i_ASN1_INTEGER,9);
- if (ai.data != NULL)
- {
- ret->tlsext_tick_lifetime_hint=ASN1_INTEGER_get(aip);
- OPENSSL_free(ai.data); ai.data=NULL; ai.length=0;
- }
- else if (ret->tlsext_ticklen && ret->session_id_length)
- ret->tlsext_tick_lifetime_hint = -1;
- else
- ret->tlsext_tick_lifetime_hint=0;
- os.length=0;
- os.data=NULL;
- M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,10);
- if (os.data)
- {
- ret->tlsext_tick = os.data;
- ret->tlsext_ticklen = os.length;
- os.data = NULL;
- os.length = 0;
- }
- else
- ret->tlsext_tick=NULL;
-
- os.length=0;
- os.data=NULL;
- M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,13);
- if (os.data && os.length == sizeof(ret->peer_sha256))
- {
- memcpy(ret->peer_sha256, os.data, sizeof(ret->peer_sha256));
- ret->peer_sha256_valid = 1;
- OPENSSL_free(os.data);
- os.data = NULL;
- }
-
- os.length=0;
- os.data=NULL;
- M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,14);
- if (os.data && os.length < (int)sizeof(ret->original_handshake_hash))
- {
- memcpy(ret->original_handshake_hash, os.data, os.length);
- ret->original_handshake_hash_len = os.length;
- OPENSSL_free(os.data);
- os.data = NULL;
- }
-
- os.length = 0;
- os.data = NULL;
- M_ASN1_D2I_get_EXP_opt(osp, d2i_ASN1_OCTET_STRING, 15);
- if (os.data)
- {
- if (ret->tlsext_signed_cert_timestamp_list)
- OPENSSL_free(ret->tlsext_signed_cert_timestamp_list);
- ret->tlsext_signed_cert_timestamp_list = os.data;
- ret->tlsext_signed_cert_timestamp_list_length = os.length;
- os.data = NULL;
- }
-
- os.length = 0;
- os.data = NULL;
- M_ASN1_D2I_get_EXP_opt(osp, d2i_ASN1_OCTET_STRING, 16);
- if (os.data)
- {
- if (ret->ocsp_response)
- OPENSSL_free(ret->ocsp_response);
- ret->ocsp_response = os.data;
- ret->ocsp_response_length = os.length;
- os.data = NULL;
- }
-
-
- M_ASN1_D2I_Finish(a,SSL_SESSION_free,SSL_F_D2I_SSL_SESSION);
- }
+
+/* An SSL_SESSION is serialized as the following ASN.1 structure:
+ *
+ * SSLSession ::= SEQUENCE {
+ * version INTEGER (1), -- ignored
+ * sslVersion INTEGER, -- protocol version number
+ * cipher OCTET STRING, -- two bytes long
+ * sessionID OCTET STRING,
+ * masterKey OCTET STRING,
+ * time [1] INTEGER OPTIONAL, -- seconds since UNIX epoch
+ * timeout [2] INTEGER OPTIONAL, -- 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
+ * pskIdentityHint [7] OCTET STRING OPTIONAL,
+ * 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,
+ * }
+ *
+ * Note: When the relevant features were #ifdef'd out, support for
+ * parsing compressionMethod [11] and srpUsername [12] was lost. */
+
+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 kPSKIdentityHintTag =
+ CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 7;
+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 int SSL_SESSION_to_bytes_full(SSL_SESSION *in, uint8_t **out_data,
+ size_t *out_len, int for_ticket) {
+ CBB cbb, session, child, child2;
+ uint16_t cipher_id;
+
+ if (in == NULL || (in->cipher == NULL && in->cipher_id == 0)) {
+ return 0;
+ }
+
+ if (!CBB_init(&cbb, 0)) {
+ return 0;
+ }
+
+ if (in->cipher == NULL) {
+ cipher_id = in->cipher_id & 0xffff;
+ } else {
+ cipher_id = in->cipher->id & 0xffff;
+ }
+
+ if (!CBB_add_asn1(&cbb, &session, CBS_ASN1_SEQUENCE) ||
+ !CBB_add_asn1_uint64(&session, SSL_SESSION_ASN1_VERSION) ||
+ !CBB_add_asn1_uint64(&session, in->ssl_version) ||
+ !CBB_add_asn1(&session, &child, CBS_ASN1_OCTETSTRING) ||
+ !CBB_add_u16(&child, cipher_id) ||
+ !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)) {
+ OPENSSL_PUT_ERROR(SSL, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if (in->time != 0) {
+ if (!CBB_add_asn1(&session, &child, kTimeTag) ||
+ !CBB_add_asn1_uint64(&child, in->time)) {
+ OPENSSL_PUT_ERROR(SSL, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ }
+
+ if (in->timeout != 0) {
+ if (!CBB_add_asn1(&session, &child, kTimeoutTag) ||
+ !CBB_add_asn1_uint64(&child, in->timeout)) {
+ OPENSSL_PUT_ERROR(SSL, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ }
+
+ /* The peer certificate is only serialized if the SHA-256 isn't
+ * serialized instead. */
+ if (in->peer && !in->peer_sha256_valid) {
+ uint8_t *buf;
+ int len = i2d_X509(in->peer, NULL);
+ if (len < 0) {
+ goto err;
+ }
+ if (!CBB_add_asn1(&session, &child, kPeerTag) ||
+ !CBB_add_space(&child, &buf, len)) {
+ OPENSSL_PUT_ERROR(SSL, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ if (buf != NULL && i2d_X509(in->peer, &buf) < 0) {
+ 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, i2d_SSL_SESSION, 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, i2d_SSL_SESSION, 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, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ }
+
+ if (in->psk_identity_hint) {
+ if (!CBB_add_asn1(&session, &child, kPSKIdentityHintTag) ||
+ !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) ||
+ !CBB_add_bytes(&child2, (const uint8_t *)in->psk_identity_hint,
+ strlen(in->psk_identity_hint))) {
+ OPENSSL_PUT_ERROR(SSL, i2d_SSL_SESSION, 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, i2d_SSL_SESSION, 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, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ }
+
+ if (in->tlsext_tick) {
+ 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, i2d_SSL_SESSION, 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, i2d_SSL_SESSION, 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, i2d_SSL_SESSION, 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, i2d_SSL_SESSION, 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, i2d_SSL_SESSION, 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, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ }
+
+ if (!CBB_finish(&cbb, out_data, out_len)) {
+ OPENSSL_PUT_ERROR(SSL, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ return 1;
+
+ err:
+ CBB_cleanup(&cbb);
+ return 0;
+}
+
+int SSL_SESSION_to_bytes(SSL_SESSION *in, uint8_t **out_data, size_t *out_len) {
+ return SSL_SESSION_to_bytes_full(in, out_data, out_len, 0);
+}
+
+int SSL_SESSION_to_bytes_for_ticket(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, i2d_SSL_SESSION, ERR_R_OVERFLOW);
+ return -1;
+ }
+
+ if (pp) {
+ memcpy(*pp, out, len);
+ *pp += len;
+ }
+ OPENSSL_free(out);
+
+ return len;
+}
+
+/* d2i_SSL_SESSION_get_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 d2i_SSL_SESSION_get_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, d2i_SSL_SESSION, SSL_R_INVALID_SSL_SESSION);
+ return 0;
+ }
+ if (present) {
+ if (CBS_contains_zero_byte(&value)) {
+ OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_INVALID_SSL_SESSION);
+ return 0;
+ }
+ if (!CBS_strdup(&value, out)) {
+ OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ } else if (*out) {
+ OPENSSL_free(*out);
+ *out = NULL;
+ }
+ return 1;
+}
+
+/* d2i_SSL_SESSION_get_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 d2i_SSL_SESSION_get_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, d2i_SSL_SESSION, SSL_R_INVALID_SSL_SESSION);
+ return 0;
+ }
+ if (!CBS_stow(&value, out_ptr, out_len)) {
+ OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ return 1;
+}
+
+SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const uint8_t **pp, long length) {
+ SSL_SESSION *ret = NULL;
+ CBS cbs, session, cipher, session_id, master_key;
+ CBS peer, sid_ctx, peer_sha256, original_handshake_hash;
+ int has_peer, has_peer_sha256, extended_master_secret;
+ uint64_t version, ssl_version;
+ uint64_t session_time, timeout, verify_result, ticket_lifetime_hint;
+
+ if (a && *a) {
+ ret = *a;
+ } else {
+ ret = SSL_SESSION_new();
+ if (ret == NULL) {
+ goto err;
+ }
+ }
+
+ CBS_init(&cbs, *pp, length);
+ if (!CBS_get_asn1(&cbs, &session, CBS_ASN1_SEQUENCE) ||
+ !CBS_get_asn1_uint64(&session, &version) ||
+ !CBS_get_asn1_uint64(&session, &ssl_version) ||
+ !CBS_get_asn1(&session, &cipher, CBS_ASN1_OCTETSTRING) ||
+ !CBS_get_asn1(&session, &session_id, CBS_ASN1_OCTETSTRING) ||
+ !CBS_get_asn1(&session, &master_key, CBS_ASN1_OCTETSTRING) ||
+ !CBS_get_optional_asn1_uint64(&session, &session_time, kTimeTag,
+ time(NULL)) ||
+ !CBS_get_optional_asn1_uint64(&session, &timeout, kTimeoutTag, 3) ||
+ !CBS_get_optional_asn1(&session, &peer, &has_peer, kPeerTag) ||
+ !CBS_get_optional_asn1_octet_string(&session, &sid_ctx, NULL,
+ kSessionIDContextTag) ||
+ !CBS_get_optional_asn1_uint64(&session, &verify_result, kVerifyResultTag,
+ X509_V_OK)) {
+ OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_INVALID_SSL_SESSION);
+ goto err;
+ }
+ if (!d2i_SSL_SESSION_get_string(&session, &ret->tlsext_hostname,
+ kHostNameTag) ||
+ !d2i_SSL_SESSION_get_string(&session, &ret->psk_identity_hint,
+ kPSKIdentityHintTag) ||
+ !d2i_SSL_SESSION_get_string(&session, &ret->psk_identity,
+ kPSKIdentityTag)) {
+ goto err;
+ }
+ if (!CBS_get_optional_asn1_uint64(&session, &ticket_lifetime_hint,
+ kTicketLifetimeHintTag, 0)) {
+ OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_INVALID_SSL_SESSION);
+ goto err;
+ }
+ if (!d2i_SSL_SESSION_get_octet_string(&session, &ret->tlsext_tick,
+ &ret->tlsext_ticklen, kTicketTag)) {
+ goto err;
+ }
+ if (!CBS_get_optional_asn1_octet_string(&session, &peer_sha256,
+ &has_peer_sha256, kPeerSHA256Tag) ||
+ !CBS_get_optional_asn1_octet_string(&session, &original_handshake_hash,
+ NULL, kOriginalHandshakeHashTag)) {
+ OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_INVALID_SSL_SESSION);
+ goto err;
+ }
+ if (!d2i_SSL_SESSION_get_octet_string(
+ &session, &ret->tlsext_signed_cert_timestamp_list,
+ &ret->tlsext_signed_cert_timestamp_list_length,
+ kSignedCertTimestampListTag) ||
+ !d2i_SSL_SESSION_get_octet_string(
+ &session, &ret->ocsp_response, &ret->ocsp_response_length,
+ kOCSPResponseTag)) {
+ goto err;
+ }
+ if (!CBS_get_optional_asn1_bool(&session, &extended_master_secret,
+ kExtendedMasterSecretTag,
+ 0 /* default to false */)) {
+ OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_INVALID_SSL_SESSION);
+ goto err;
+ }
+ ret->extended_master_secret = extended_master_secret;
+
+ /* Ignore |version|. The structure version number is ignored. */
+
+ /* Only support SSLv3/TLS and DTLS. */
+ if ((ssl_version >> 8) != SSL3_VERSION_MAJOR &&
+ (ssl_version >> 8) != (DTLS1_VERSION >> 8)) {
+ OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_UNKNOWN_SSL_VERSION);
+ goto err;
+ }
+ ret->ssl_version = ssl_version;
+
+ if (CBS_len(&cipher) != 2) {
+ OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_CIPHER_CODE_WRONG_LENGTH);
+ goto err;
+ }
+ ret->cipher_id =
+ 0x03000000L | (CBS_data(&cipher)[0] << 8L) | CBS_data(&cipher)[1];
+ ret->cipher = ssl3_get_cipher_by_value(ret->cipher_id & 0xffff);
+ if (ret->cipher == NULL) {
+ OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_UNSUPPORTED_CIPHER);
+ goto err;
+ }
+
+ if (CBS_len(&session_id) > SSL3_MAX_SSL_SESSION_ID_LENGTH) {
+ OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_INVALID_SSL_SESSION);
+ goto err;
+ }
+ memcpy(ret->session_id, CBS_data(&session_id), CBS_len(&session_id));
+ ret->session_id_length = CBS_len(&session_id);
+
+ if (CBS_len(&master_key) > SSL_MAX_MASTER_KEY_LENGTH) {
+ OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_INVALID_SSL_SESSION);
+ goto err;
+ }
+ memcpy(ret->master_key, CBS_data(&master_key), CBS_len(&master_key));
+ ret->master_key_length = CBS_len(&master_key);
+
+ if (session_time > LONG_MAX ||
+ timeout > LONG_MAX) {
+ OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_INVALID_SSL_SESSION);
+ goto err;
+ }
+ ret->time = session_time;
+ ret->timeout = timeout;
+
+ if (ret->peer != NULL) {
+ X509_free(ret->peer);
+ ret->peer = NULL;
+ }
+ if (has_peer) {
+ const uint8_t *ptr;
+ ptr = CBS_data(&peer);
+ ret->peer = d2i_X509(NULL, &ptr, CBS_len(&peer));
+ if (ret->peer == NULL) {
+ goto err;
+ }
+ if (ptr != CBS_data(&peer) + CBS_len(&peer)) {
+ OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_INVALID_SSL_SESSION);
+ goto err;
+ }
+ }
+
+ if (CBS_len(&sid_ctx) > sizeof(ret->sid_ctx)) {
+ OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_INVALID_SSL_SESSION);
+ goto err;
+ }
+ memcpy(ret->sid_ctx, CBS_data(&sid_ctx), CBS_len(&sid_ctx));
+ ret->sid_ctx_length = CBS_len(&sid_ctx);
+
+ if (verify_result > LONG_MAX ||
+ ticket_lifetime_hint > 0xffffffff) {
+ OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_INVALID_SSL_SESSION);
+ goto err;
+ }
+ ret->verify_result = verify_result;
+ ret->tlsext_tick_lifetime_hint = ticket_lifetime_hint;
+
+ if (has_peer_sha256) {
+ if (CBS_len(&peer_sha256) != sizeof(ret->peer_sha256)) {
+ OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_INVALID_SSL_SESSION);
+ goto err;
+ }
+ memcpy(ret->peer_sha256, CBS_data(&peer_sha256), sizeof(ret->peer_sha256));
+ ret->peer_sha256_valid = 1;
+ } else {
+ ret->peer_sha256_valid = 0;
+ }
+
+ if (CBS_len(&original_handshake_hash) >
+ sizeof(ret->original_handshake_hash)) {
+ OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_INVALID_SSL_SESSION);
+ goto err;
+ }
+ memcpy(ret->original_handshake_hash, CBS_data(&original_handshake_hash),
+ CBS_len(&original_handshake_hash));
+ ret->original_handshake_hash_len = CBS_len(&original_handshake_hash);
+
+ if (a) {
+ *a = ret;
+ }
+ *pp = CBS_data(&cbs);
+ return ret;
+
+err:
+ if (a && *a != ret) {
+ SSL_SESSION_free(ret);
+ }
+ return NULL;
+}
diff --git a/ssl/ssl_error.c b/ssl/ssl_error.c
index 0ba125b..b070b5f 100644
--- a/ssl/ssl_error.c
+++ b/ssl/ssl_error.c
@@ -39,6 +39,7 @@ const ERR_STRING_DATA SSL_error_string_data[] = {
{ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SESSION_new, 0), "SSL_SESSION_new"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SESSION_print_fp, 0), "SSL_SESSION_print_fp"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SESSION_set1_id_context, 0), "SSL_SESSION_set1_id_context"},
+ {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SESSION_to_bytes_full, 0), "SSL_SESSION_to_bytes_full"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_add_dir_cert_subjects_to_stack, 0), "SSL_add_dir_cert_subjects_to_stack"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_add_file_cert_subjects_to_stack, 0), "SSL_add_file_cert_subjects_to_stack"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_check_private_key, 0), "SSL_check_private_key"},
@@ -70,6 +71,9 @@ const ERR_STRING_DATA SSL_error_string_data[] = {
{ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_write, 0), "SSL_write"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_authz_find_data, 0), "authz_find_data"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_check_suiteb_cipher_list, 0), "check_suiteb_cipher_list"},
+ {ERR_PACK(ERR_LIB_SSL, SSL_F_d2i_SSL_SESSION, 0), "d2i_SSL_SESSION"},
+ {ERR_PACK(ERR_LIB_SSL, SSL_F_d2i_SSL_SESSION_get_octet_string, 0), "d2i_SSL_SESSION_get_octet_string"},
+ {ERR_PACK(ERR_LIB_SSL, SSL_F_d2i_SSL_SESSION_get_string, 0), "d2i_SSL_SESSION_get_string"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_do_dtls1_write, 0), "do_dtls1_write"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_do_ssl3_write, 0), "do_ssl3_write"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_dtls1_accept, 0), "dtls1_accept"},
@@ -87,6 +91,7 @@ const ERR_STRING_DATA SSL_error_string_data[] = {
{ERR_PACK(ERR_LIB_SSL, SSL_F_dtls1_write_app_data_bytes, 0), "dtls1_write_app_data_bytes"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_fclose, 0), "fclose"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_fprintf, 0), "fprintf"},
+ {ERR_PACK(ERR_LIB_SSL, SSL_F_i2d_SSL_SESSION, 0), "i2d_SSL_SESSION"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_printf, 0), "printf"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_read_authz, 0), "read_authz"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_ssl23_accept, 0), "ssl23_accept"},
@@ -136,6 +141,7 @@ const ERR_STRING_DATA SSL_error_string_data[] = {
{ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_client_certificate, 0), "ssl3_send_client_certificate"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_client_hello, 0), "ssl3_send_client_hello"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_client_key_exchange, 0), "ssl3_send_client_key_exchange"},
+ {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_new_session_ticket, 0), "ssl3_send_new_session_ticket"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_server_certificate, 0), "ssl3_send_server_certificate"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_server_hello, 0), "ssl3_send_server_hello"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_server_key_exchange, 0), "ssl3_send_server_key_exchange"},
@@ -320,6 +326,7 @@ const ERR_STRING_DATA SSL_error_string_data[] = {
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_PURPOSE), "INVALID_PURPOSE"},
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_SERVERINFO_DATA), "INVALID_SERVERINFO_DATA"},
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_SRP_USERNAME), "INVALID_SRP_USERNAME"},
+ {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_SSL_SESSION), "INVALID_SSL_SESSION"},
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_STATUS_RESPONSE), "INVALID_STATUS_RESPONSE"},
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_TICKET_KEYS_LENGTH), "INVALID_TICKET_KEYS_LENGTH"},
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_TRUST), "INVALID_TRUST"},
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index f7818ed..8357ff9 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -1495,8 +1495,7 @@ int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk, uint8_t *p)
return(p-q);
}
-STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, const CBS *cbs,
- STACK_OF(SSL_CIPHER) **skp)
+STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, const CBS *cbs)
{
CBS cipher_suites = *cbs;
const SSL_CIPHER *c;
@@ -1508,14 +1507,14 @@ STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, const CBS *cbs,
if (CBS_len(&cipher_suites) % 2 != 0)
{
OPENSSL_PUT_ERROR(SSL, ssl_bytes_to_cipher_list, SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST);
- return(NULL);
+ return NULL;
}
- if ((skp == NULL) || (*skp == NULL))
- sk=sk_SSL_CIPHER_new_null(); /* change perhaps later */
- else
+
+ sk = sk_SSL_CIPHER_new_null();
+ if (sk == NULL)
{
- sk= *skp;
- sk_SSL_CIPHER_zero(sk);
+ OPENSSL_PUT_ERROR(SSL, ssl_bytes_to_cipher_list, ERR_R_MALLOC_FAILURE);
+ goto err;
}
if (!CBS_stow(&cipher_suites,
@@ -1535,10 +1534,10 @@ STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, const CBS *cbs,
goto err;
}
- /* Check for SCSV */
+ /* Check for SCSV. */
if (s->s3 && cipher_suite == (SSL3_CK_SCSV & 0xffff))
{
- /* SCSV fatal if renegotiating */
+ /* SCSV is fatal if renegotiating. */
if (s->renegotiate)
{
OPENSSL_PUT_ERROR(SSL, ssl_bytes_to_cipher_list, SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING);
@@ -1546,25 +1545,25 @@ STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, const CBS *cbs,
goto err;
}
s->s3->send_connection_binding = 1;
-#ifdef OPENSSL_RI_DEBUG
- fprintf(stderr, "SCSV received by server\n");
-#endif
continue;
}
- /* Check for FALLBACK_SCSV */
- if (s->s3 && cipher_suite == (SSL3_CK_FALLBACK_SCSV & 0xffff) &&
- s->version < ssl_get_max_version(s))
+ /* Check for FALLBACK_SCSV. */
+ if (s->s3 && cipher_suite == (SSL3_CK_FALLBACK_SCSV & 0xffff))
{
- OPENSSL_PUT_ERROR(SSL, ssl_bytes_to_cipher_list, SSL_R_INAPPROPRIATE_FALLBACK);
- ssl3_send_alert(s,SSL3_AL_FATAL,SSL3_AD_INAPPROPRIATE_FALLBACK);
- goto err;
+ if (s->version < ssl_get_max_version(s))
+ {
+ OPENSSL_PUT_ERROR(SSL, ssl_bytes_to_cipher_list, SSL_R_INAPPROPRIATE_FALLBACK);
+ ssl3_send_alert(s, SSL3_AL_FATAL, SSL3_AD_INAPPROPRIATE_FALLBACK);
+ goto err;
+ }
+ continue;
}
c = ssl3_get_cipher_by_value(cipher_suite);
if (c != NULL)
{
- if (!sk_SSL_CIPHER_push(sk,c))
+ if (!sk_SSL_CIPHER_push(sk, c))
{
OPENSSL_PUT_ERROR(SSL, ssl_bytes_to_cipher_list, ERR_R_MALLOC_FAILURE);
goto err;
@@ -1572,13 +1571,12 @@ STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, const CBS *cbs,
}
}
- if (skp != NULL)
- *skp=sk;
- return(sk);
+ return sk;
+
err:
- if ((skp == NULL) || (*skp == NULL))
+ if (sk != NULL)
sk_SSL_CIPHER_free(sk);
- return(NULL);
+ return NULL;
}
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index 75c0ba8..c214b91 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -568,6 +568,11 @@ struct tls_sigalgs_st
#define FP_ICC (int (*)(const void *,const void *))
+enum should_add_to_finished_hash {
+ add_to_finished_hash,
+ dont_add_to_finished_hash,
+};
+
/* This is for the SSLv3/TLSv1.0 differences in crypto/hash stuff
* It is a bit of a mess of functions, but hell, think of it as
* an opaque structure :-) */
@@ -597,7 +602,9 @@ typedef struct ssl3_enc_method
/* Set the handshake header */
void (*set_handshake_header)(SSL *s, int type, unsigned long len);
/* Write out handshake message */
- int (*do_write)(SSL *s);
+ int (*do_write)(SSL *s, enum should_add_to_finished_hash should_add_to_finished_hash);
+ /* Add the current handshake message to the finished hash. */
+ void (*add_to_finished_hash)(SSL *s);
} SSL3_ENC_METHOD;
#define SSL_HM_HEADER_LENGTH(s) s->method->ssl3_enc->hhlen
@@ -605,7 +612,7 @@ typedef struct ssl3_enc_method
(((unsigned char *)s->init_buf->data) + s->method->ssl3_enc->hhlen)
#define ssl_set_handshake_header(s, htype, len) \
s->method->ssl3_enc->set_handshake_header(s, htype, len)
-#define ssl_do_write(s) s->method->ssl3_enc->do_write(s)
+#define ssl_do_write(s) s->method->ssl3_enc->do_write(s, add_to_finished_hash)
/* Values for enc_flags */
@@ -768,8 +775,7 @@ int ssl_set_peer_cert_type(SESS_CERT *c, int type);
int ssl_get_prev_session(SSL *s, const struct ssl_early_callback_ctx *ctx);
int ssl_cipher_id_cmp(const void *in_a, const void *in_b);
int ssl_cipher_ptr_id_cmp(const SSL_CIPHER **ap, const SSL_CIPHER **bp);
-STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, const CBS *cbs,
- STACK_OF(SSL_CIPHER) **skp);
+STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, const CBS *cbs);
int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk, uint8_t *p);
STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(const SSL_METHOD *meth,
struct ssl_cipher_preference_list_st **pref,
@@ -824,7 +830,7 @@ int ssl3_setup_key_block(SSL *s);
int ssl3_send_change_cipher_spec(SSL *s,int state_a,int state_b);
int ssl3_change_cipher_state(SSL *s,int which);
void ssl3_cleanup_key_block(SSL *s);
-int ssl3_do_write(SSL *s,int type);
+int ssl3_do_write(SSL *s,int type, enum should_add_to_finished_hash should_add_to_finished_hash);
int ssl3_send_alert(SSL *s,int level, int desc);
int ssl3_generate_master_secret(SSL *s, unsigned char *out,
unsigned char *p, int len);
@@ -866,7 +872,13 @@ int ssl3_setup_read_buffer(SSL *s);
int ssl3_setup_write_buffer(SSL *s);
int ssl3_release_read_buffer(SSL *s);
int ssl3_release_write_buffer(SSL *s);
-int ssl3_digest_cached_records(SSL *s);
+
+enum should_free_handshake_buffer_t {
+ free_handshake_buffer,
+ dont_free_handshake_buffer,
+};
+int ssl3_digest_cached_records(SSL *s, enum should_free_handshake_buffer_t);
+
int ssl3_new(SSL *s);
void ssl3_free(SSL *s);
int ssl3_accept(SSL *s);
@@ -886,13 +898,14 @@ void ssl3_record_sequence_update(unsigned char *seq);
int ssl3_do_change_cipher_spec(SSL *ssl);
void ssl3_set_handshake_header(SSL *s, int htype, unsigned long len);
-int ssl3_handshake_write(SSL *s);
+int ssl3_handshake_write(SSL *s, enum should_add_to_finished_hash should_add_to_finished_hash);
+void ssl3_add_to_finished_hash(SSL *s);
int ssl23_read(SSL *s, void *buf, int len);
int ssl23_peek(SSL *s, void *buf, int len);
int ssl23_write(SSL *s, const void *buf, int len);
-int dtls1_do_write(SSL *s,int type);
+int dtls1_do_write(SSL *s,int type, enum should_add_to_finished_hash should_add_to_finished_hash);
int ssl3_read_n(SSL *s, int n, int max, int extend);
int dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek);
int ssl3_write_pending(SSL *s, int type, const unsigned char *buf,
diff --git a/ssl/ssl_test.c b/ssl/ssl_test.c
index a202273..da9ba4b 100644
--- a/ssl/ssl_test.c
+++ b/ssl/ssl_test.c
@@ -307,20 +307,6 @@ static const char kOpenSSLSession[] =
* filling in missing fields from |kOpenSSLSession|. This includes
* providing |peer_sha256|, so |peer| is not serialized. */
static const char kCustomSession[] =
- "MIIBggIBAQICAwMEAsAvBCAG5Q1ndq4Yfmbeo1zwLkNRKmCXGdNgWvGT3cskV0yQ"
- "kAQwJlrlzkAWBOWiLj/jJ76D7l+UXoizP2KI2C7I2FccqMmIfFmmkUy32nIJ0mZH"
- "IWoJgAEBoQYCBFRDO46iBAICASykAwQBAqUDAgEUphAEDnd3dy5nb29nbGUuY29t"
- "pwcEBWhlbGxvqAcEBXdvcmxkqQUCAwGJwKqBpwSBpBwUQvoeOk0Kg36SYTcLEkXq"
- "KwOBfF9vE4KX0NxeLwjcDTpsuh3qXEaZ992r1N38VDcyS6P7I6HBYN9BsNHM362z"
- "ZnY27GpTw+Kwd751CLoXFPoaMOe57dbBpXoro6Pd3BTbf/Tzr88K06yEOTDKPNj3"
- "+inbMaVigtK4PLyPq+Topyzvx9USFgRvyuoxn0Hgb+R0A3j6SLRuyOdAi4gv7Y5o"
- "liynrSIEIAYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGrgMEAQevAwQB"
- "BLADBAEF";
-
-/* kCustomSession2 is kCustomSession with the old SSLv2-only key_arg
- * field removed. Encoding the decoded version of kCustomSession
- * should not preserve key_arg. */
-static const char kCustomSession2[] =
"MIIBfwIBAQICAwMEAsAvBCAG5Q1ndq4Yfmbeo1zwLkNRKmCXGdNgWvGT3cskV0yQ"
"kAQwJlrlzkAWBOWiLj/jJ76D7l+UXoizP2KI2C7I2FccqMmIfFmmkUy32nIJ0mZH"
"IWoJoQYCBFRDO46iBAICASykAwQBAqUDAgEUphAEDnd3dy5nb29nbGUuY29tpwcE"
@@ -355,18 +341,16 @@ static int decode_base64(uint8_t **out, size_t *out_len, const char *in) {
return 1;
}
-static int test_ssl_session_asn1(const char *input_b64,
- const char *expected_b64) {
+static int test_ssl_session_asn1(const char *input_b64) {
int ret = 0, len;
- size_t input_len, expected_len;
- uint8_t *input = NULL, *expected = NULL, *encoded = NULL;
+ size_t input_len, encoded_len;
+ uint8_t *input = NULL, *encoded = NULL;
const uint8_t *cptr;
uint8_t *ptr;
SSL_SESSION *session = NULL;
/* Decode the input. */
- if (!decode_base64(&input, &input_len, input_b64) ||
- !decode_base64(&expected, &expected_len, expected_b64)) {
+ if (!decode_base64(&input, &input_len, input_b64)) {
goto done;
}
@@ -379,28 +363,41 @@ static int test_ssl_session_asn1(const char *input_b64,
}
/* Verify the SSL_SESSION encoding round-trips. */
+ if (!SSL_SESSION_to_bytes(session, &encoded, &encoded_len)) {
+ fprintf(stderr, "SSL_SESSION_to_bytes failed\n");
+ goto done;
+ }
+ if (encoded_len != input_len ||
+ memcmp(input, encoded, input_len) != 0) {
+ fprintf(stderr, "SSL_SESSION_to_bytes did not round-trip\n");
+ goto done;
+ }
+ OPENSSL_free(encoded);
+ encoded = NULL;
+
+ /* Verify the SSL_SESSION encoding round-trips via the legacy API. */
len = i2d_SSL_SESSION(session, NULL);
- if (len < 0 || (size_t)len != expected_len) {
+ if (len < 0 || (size_t)len != input_len) {
fprintf(stderr, "i2d_SSL_SESSION(NULL) returned invalid length\n");
goto done;
}
- encoded = OPENSSL_malloc(expected_len);
+ encoded = OPENSSL_malloc(input_len);
if (encoded == NULL) {
fprintf(stderr, "malloc failed\n");
goto done;
}
ptr = encoded;
len = i2d_SSL_SESSION(session, &ptr);
- if (len < 0 || (size_t)len != expected_len) {
+ if (len < 0 || (size_t)len != input_len) {
fprintf(stderr, "i2d_SSL_SESSION returned invalid length\n");
goto done;
}
- if (ptr != encoded + expected_len) {
+ if (ptr != encoded + input_len) {
fprintf(stderr, "i2d_SSL_SESSION did not advance ptr correctly\n");
goto done;
}
- if (memcmp(expected, encoded, expected_len) != 0) {
+ if (memcmp(input, encoded, input_len) != 0) {
fprintf(stderr, "i2d_SSL_SESSION did not round-trip\n");
goto done;
}
@@ -418,9 +415,6 @@ static int test_ssl_session_asn1(const char *input_b64,
if (input) {
OPENSSL_free(input);
}
- if (expected) {
- OPENSSL_free(expected);
- }
if (encoded) {
OPENSSL_free(encoded);
}
@@ -431,9 +425,8 @@ int main(void) {
SSL_library_init();
if (!test_cipher_rules() ||
- !test_ssl_session_asn1(kOpenSSLSession, kOpenSSLSession) ||
- !test_ssl_session_asn1(kCustomSession, kCustomSession2) ||
- !test_ssl_session_asn1(kCustomSession2, kCustomSession2)) {
+ !test_ssl_session_asn1(kOpenSSLSession) ||
+ !test_ssl_session_asn1(kCustomSession)) {
return 1;
}
diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c
index dd00d0a..0a4e088 100644
--- a/ssl/t1_enc.c
+++ b/ssl/t1_enc.c
@@ -152,8 +152,6 @@ static int tls1_P_hash(const EVP_MD *md, const unsigned char *sec,
const void *seed1, int seed1_len,
const void *seed2, int seed2_len,
const void *seed3, int seed3_len,
- const void *seed4, int seed4_len,
- const void *seed5, int seed5_len,
unsigned char *out, int olen)
{
int chunk;
@@ -182,10 +180,6 @@ static int tls1_P_hash(const EVP_MD *md, const unsigned char *sec,
goto err;
if (seed3 && !EVP_DigestSignUpdate(&ctx,seed3,seed3_len))
goto err;
- if (seed4 && !EVP_DigestSignUpdate(&ctx,seed4,seed4_len))
- goto err;
- if (seed5 && !EVP_DigestSignUpdate(&ctx,seed5,seed5_len))
- goto err;
A1_len = EVP_MAX_MD_SIZE;
if (!EVP_DigestSignFinal(&ctx,A1,&A1_len))
goto err;
@@ -205,10 +199,6 @@ static int tls1_P_hash(const EVP_MD *md, const unsigned char *sec,
goto err;
if (seed3 && !EVP_DigestSignUpdate(&ctx,seed3,seed3_len))
goto err;
- if (seed4 && !EVP_DigestSignUpdate(&ctx,seed4,seed4_len))
- goto err;
- if (seed5 && !EVP_DigestSignUpdate(&ctx,seed5,seed5_len))
- goto err;
if (olen > chunk)
{
@@ -246,8 +236,6 @@ static int tls1_PRF(long digest_mask,
const void *seed1, int seed1_len,
const void *seed2, int seed2_len,
const void *seed3, int seed3_len,
- const void *seed4, int seed4_len,
- const void *seed5, int seed5_len,
const unsigned char *sec, int slen,
unsigned char *out1,
unsigned char *out2, int olen)
@@ -275,7 +263,7 @@ static int tls1_PRF(long digest_mask,
goto err;
}
if (!tls1_P_hash(md ,S1,len+(slen&1),
- seed1,seed1_len,seed2,seed2_len,seed3,seed3_len,seed4,seed4_len,seed5,seed5_len,
+ seed1,seed1_len,seed2,seed2_len,seed3,seed3_len,
out2,olen))
goto err;
S1+=len;
@@ -298,7 +286,6 @@ static int tls1_generate_key_block(SSL *s, unsigned char *km,
TLS_MD_KEY_EXPANSION_CONST,TLS_MD_KEY_EXPANSION_CONST_SIZE,
s->s3->server_random,SSL3_RANDOM_SIZE,
s->s3->client_random,SSL3_RANDOM_SIZE,
- NULL,0,NULL,0,
s->session->master_key,s->session->master_key_length,
km,tmp,num);
#ifdef KSSL_DEBUG
@@ -1011,8 +998,8 @@ int tls1_cert_verify_mac(SSL *s, int md_nid, unsigned char *out)
EVP_MD_CTX ctx, *d=NULL;
int i;
- if (s->s3->handshake_buffer)
- if (!ssl3_digest_cached_records(s))
+ if (s->s3->handshake_buffer)
+ if (!ssl3_digest_cached_records(s, free_handshake_buffer))
return 0;
for (i=0;i<SSL_MAX_DIGEST;i++)
@@ -1093,7 +1080,7 @@ int tls1_final_finish_mac(SSL *s,
int digests_len;
if (s->s3->handshake_buffer)
- if (!ssl3_digest_cached_records(s))
+ if (!ssl3_digest_cached_records(s, free_handshake_buffer))
return 0;
digests_len = tls1_handshake_digest(s, buf, sizeof(buf));
@@ -1104,7 +1091,7 @@ int tls1_final_finish_mac(SSL *s,
}
if (!tls1_PRF(ssl_get_algorithm2(s),
- str,slen, buf, digests_len, NULL,0, NULL,0, NULL,0,
+ str,slen, buf, digests_len, NULL,0,
s->session->master_key,s->session->master_key_length,
out,buf2,sizeof buf2))
err = 1;
@@ -1212,22 +1199,57 @@ int tls1_generate_master_secret(SSL *s, unsigned char *out, unsigned char *p,
int len)
{
unsigned char buff[SSL_MAX_MASTER_KEY_LENGTH];
- const void *co = NULL, *so = NULL;
- int col = 0, sol = 0;
-
#ifdef KSSL_DEBUG
printf ("tls1_generate_master_secret(%p,%p, %p, %d)\n", s,out, p,len);
#endif /* KSSL_DEBUG */
- tls1_PRF(ssl_get_algorithm2(s),
- TLS_MD_MASTER_SECRET_CONST,TLS_MD_MASTER_SECRET_CONST_SIZE,
- s->s3->client_random,SSL3_RANDOM_SIZE,
- co, col,
- s->s3->server_random,SSL3_RANDOM_SIZE,
- so, sol,
- p,len,
- s->session->master_key,buff,sizeof buff);
+ if (s->s3->tmp.extended_master_secret)
+ {
+ uint8_t digests[2*EVP_MAX_MD_SIZE];
+ int digests_len;
+
+ if (s->s3->handshake_buffer)
+ {
+ /* The master secret is based on the handshake hash
+ * just after sending the ClientKeyExchange. However,
+ * we might have a client certificate to send, in which
+ * case we might need different hashes for the
+ * verification and thus still need the handshake
+ * buffer around. Keeping both a handshake buffer *and*
+ * running hashes isn't yet supported so, when it comes
+ * to calculating the Finished hash, we'll have to hash
+ * the handshake buffer again. */
+ if (!ssl3_digest_cached_records(s, dont_free_handshake_buffer))
+ return 0;
+ }
+
+ digests_len = tls1_handshake_digest(s, digests, sizeof(digests));
+
+ if (digests_len == -1)
+ {
+ return 0;
+ }
+
+ tls1_PRF(ssl_get_algorithm2(s),
+ TLS_MD_EXTENDED_MASTER_SECRET_CONST,
+ TLS_MD_EXTENDED_MASTER_SECRET_CONST_SIZE,
+ digests, digests_len,
+ NULL, 0,
+ p, len,
+ s->session->master_key,
+ buff, sizeof(buff));
+ }
+ else
+ {
+ tls1_PRF(ssl_get_algorithm2(s),
+ TLS_MD_MASTER_SECRET_CONST,TLS_MD_MASTER_SECRET_CONST_SIZE,
+ s->s3->client_random,SSL3_RANDOM_SIZE,
+ s->s3->server_random,SSL3_RANDOM_SIZE,
+ p, len,
+ s->session->master_key,buff,sizeof buff);
+ }
+
#ifdef SSL_DEBUG
fprintf(stderr, "Premaster Secret:\n");
BIO_dump_fp(stderr, (char *)p, len);
@@ -1330,8 +1352,6 @@ int tls1_export_keying_material(SSL *s, unsigned char *out, size_t olen,
val, vallen,
NULL, 0,
NULL, 0,
- NULL, 0,
- NULL, 0,
s->session->master_key,s->session->master_key_length,
out,buff,olen);
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index 4b13cfe..0972515 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -140,7 +140,8 @@ SSL3_ENC_METHOD TLSv1_enc_data={
0,
SSL3_HM_HEADER_LENGTH,
ssl3_set_handshake_header,
- ssl3_handshake_write
+ ssl3_handshake_write,
+ ssl3_add_to_finished_hash,
};
SSL3_ENC_METHOD TLSv1_1_enc_data={
@@ -159,7 +160,8 @@ SSL3_ENC_METHOD TLSv1_1_enc_data={
SSL_ENC_FLAG_EXPLICIT_IV,
SSL3_HM_HEADER_LENGTH,
ssl3_set_handshake_header,
- ssl3_handshake_write
+ ssl3_handshake_write,
+ ssl3_add_to_finished_hash,
};
SSL3_ENC_METHOD TLSv1_2_enc_data={
@@ -179,7 +181,8 @@ SSL3_ENC_METHOD TLSv1_2_enc_data={
|SSL_ENC_FLAG_TLS1_2_CIPHERS,
SSL3_HM_HEADER_LENGTH,
ssl3_set_handshake_header,
- ssl3_handshake_write
+ ssl3_handshake_write,
+ ssl3_add_to_finished_hash,
};
static int compare_uint16_t(const void *p1, const void *p2)
@@ -978,6 +981,15 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf, unsigned c
ret += el;
}
+ /* Add extended master secret. */
+ if (s->version != SSL3_VERSION)
+ {
+ if (limit - ret - 4 < 0)
+ return NULL;
+ s2n(TLSEXT_TYPE_extended_master_secret,ret);
+ s2n(0,ret);
+ }
+
if (!(SSL_get_options(s) & SSL_OP_NO_TICKET))
{
int ticklen;
@@ -1246,6 +1258,14 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *buf, unsigned c
ret += el;
}
+ if (s->s3->tmp.extended_master_secret)
+ {
+ if ((long)(limit - ret - 4) < 0) return NULL;
+
+ s2n(TLSEXT_TYPE_extended_master_secret,ret);
+ s2n(0,ret);
+ }
+
if (using_ecc)
{
const unsigned char *plist;
@@ -1423,6 +1443,7 @@ static int ssl_scan_clienthello_tlsext(SSL *s, CBS *cbs, int *out_alert)
s->should_ack_sni = 0;
s->s3->next_proto_neg_seen = 0;
s->s3->tmp.certificate_status_expected = 0;
+ s->s3->tmp.extended_master_secret = 0;
if (s->s3->alpn_selected)
{
@@ -1782,6 +1803,18 @@ static int ssl_scan_clienthello_tlsext(SSL *s, CBS *cbs, int *out_alert)
if (!ssl_parse_clienthello_use_srtp_ext(s, &extension, out_alert))
return 0;
}
+
+ else if (type == TLSEXT_TYPE_extended_master_secret &&
+ s->version != SSL3_VERSION)
+ {
+ if (CBS_len(&extension) != 0)
+ {
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ s->s3->tmp.extended_master_secret = 1;
+ }
}
ri_check:
@@ -1851,6 +1884,7 @@ static int ssl_scan_serverhello_tlsext(SSL *s, CBS *cbs, int *out_alert)
s->tlsext_ticket_expected = 0;
s->s3->tmp.certificate_status_expected = 0;
+ s->s3->tmp.extended_master_secret = 0;
if (s->s3->alpn_selected)
{
@@ -2086,6 +2120,20 @@ static int ssl_scan_serverhello_tlsext(SSL *s, CBS *cbs, int *out_alert)
if (!ssl_parse_serverhello_use_srtp_ext(s, &extension, out_alert))
return 0;
}
+
+ else if (type == TLSEXT_TYPE_extended_master_secret)
+ {
+ if (/* It is invalid for the server to select EMS and
+ SSLv3. */
+ s->version == SSL3_VERSION ||
+ CBS_len(&extension) != 0)
+ {
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ s->s3->tmp.extended_master_secret = 1;
+ }
}
if (!s->hit && tlsext_servername == 1)
@@ -2779,7 +2827,7 @@ tls1_channel_id_hash(EVP_MD_CTX *md, SSL *s)
static const char kClientIDMagic[] = "TLS Channel ID signature";
if (s->s3->handshake_buffer)
- if (!ssl3_digest_cached_records(s))
+ if (!ssl3_digest_cached_records(s, free_handshake_buffer))
return 0;
EVP_DigestUpdate(md, kClientIDMagic, sizeof(kClientIDMagic));
diff --git a/ssl/test/bssl_shim.cc b/ssl/test/bssl_shim.cc
index 6b27e26..1cf81a7 100644
--- a/ssl/test/bssl_shim.cc
+++ b/ssl/test/bssl_shim.cc
@@ -25,6 +25,7 @@
#include <sys/types.h>
#include <openssl/bio.h>
+#include <openssl/buf.h>
#include <openssl/bytestring.h>
#include <openssl/ssl.h>
@@ -180,6 +181,48 @@ static int cookie_verify_callback(SSL *ssl, const uint8_t *cookie, size_t cookie
return 1;
}
+static unsigned psk_client_callback(SSL *ssl, const char *hint,
+ char *out_identity,
+ unsigned max_identity_len,
+ uint8_t *out_psk, unsigned max_psk_len) {
+ const TestConfig *config = GetConfigPtr(ssl);
+
+ if (strcmp(hint ? 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);
+ memcpy(out_psk, config->psk.data(), config->psk.size());
+ return config->psk.size();
+}
+
+static unsigned psk_server_callback(SSL *ssl, const char *identity,
+ uint8_t *out_psk, unsigned max_psk_len) {
+ const TestConfig *config = GetConfigPtr(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;
+ }
+
+ memcpy(out_psk, config->psk.data(), config->psk.size());
+ return config->psk.size();
+}
+
static SSL_CTX *setup_ctx(const TestConfig *config) {
SSL_CTX *ssl_ctx = NULL;
DH *dh = NULL;
@@ -369,6 +412,16 @@ static int do_exchange(SSL_SESSION **out_session,
SSL_set_alpn_protos(ssl, (const uint8_t *)config->advertise_alpn.data(),
config->advertise_alpn.size());
}
+ if (!config->psk.empty()) {
+ SSL_set_psk_client_callback(ssl, psk_client_callback);
+ SSL_set_psk_server_callback(ssl, psk_server_callback);
+ }
+ if (!config->psk_identity.empty()) {
+ if (!SSL_use_psk_identity_hint(ssl, config->psk_identity.c_str())) {
+ BIO_print_errors_fp(stdout);
+ return 1;
+ }
+ }
BIO *bio = BIO_new_fd(fd, 1 /* take ownership */);
if (bio == NULL) {
@@ -482,6 +535,13 @@ static int do_exchange(SSL_SESSION **out_session,
}
}
+ if (config->expect_extended_master_secret) {
+ if (!ssl->session->extended_master_secret) {
+ fprintf(stderr, "No EMS for session when expected");
+ return 2;
+ }
+ }
+
if (config->write_different_record_sizes) {
if (config->is_dtls) {
fprintf(stderr, "write_different_record_sizes not supported for DTLS\n");
diff --git a/ssl/test/runner/cipher_suites.go b/ssl/test/runner/cipher_suites.go
index 6cd0de9..5a3ac80 100644
--- a/ssl/test/runner/cipher_suites.go
+++ b/ssl/test/runner/cipher_suites.go
@@ -57,6 +57,9 @@ const (
// 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
)
// A cipherSuite is a specific combination of key agreement, cipher and MAC
@@ -109,6 +112,10 @@ var cipherSuites = []*cipherSuite{
{TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, ecdheRSAKA, suiteECDHE, cipher3DES, macSHA1, nil},
{TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, dheRSAKA, 0, cipher3DES, macSHA1, nil},
{TLS_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, rsaKA, 0, cipher3DES, macSHA1, nil},
+ {TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdhePSKKA, suiteECDHE | suiteTLS12 | suitePSK, nil, nil, aeadAESGCM},
+ {TLS_PSK_WITH_RC4_128_SHA, 16, 20, 0, pskKA, suiteNoDTLS | suitePSK, cipherRC4, macSHA1, nil},
+ {TLS_PSK_WITH_AES_128_CBC_SHA, 16, 20, 16, pskKA, suitePSK, cipherAES, macSHA1, nil},
+ {TLS_PSK_WITH_AES_256_CBC_SHA, 32, 20, 16, pskKA, suitePSK, cipherAES, macSHA1, nil},
}
func cipherRC4(key, iv []byte, isRead bool) interface{} {
@@ -287,7 +294,7 @@ func rsaKA(version uint16) keyAgreement {
func ecdheECDSAKA(version uint16) keyAgreement {
return &ecdheKeyAgreement{
- signedKeyAgreement: signedKeyAgreement{
+ auth: &signedKeyAgreement{
sigType: signatureECDSA,
version: version,
},
@@ -296,7 +303,7 @@ func ecdheECDSAKA(version uint16) keyAgreement {
func ecdheRSAKA(version uint16) keyAgreement {
return &ecdheKeyAgreement{
- signedKeyAgreement: signedKeyAgreement{
+ auth: &signedKeyAgreement{
sigType: signatureRSA,
version: version,
},
@@ -305,13 +312,27 @@ func ecdheRSAKA(version uint16) keyAgreement {
func dheRSAKA(version uint16) keyAgreement {
return &dheKeyAgreement{
- signedKeyAgreement: signedKeyAgreement{
+ auth: &signedKeyAgreement{
sigType: signatureRSA,
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 {
@@ -343,6 +364,9 @@ const (
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
@@ -364,3 +388,8 @@ const (
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0xc030
fallbackSCSV uint16 = 0x5600
)
+
+// Additional cipher suite IDs, not IANA-assigned.
+const (
+ TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256 uint16 = 0xcafe
+)
diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go
index 8b2c750..4aa21bb 100644
--- a/ssl/test/runner/common.go
+++ b/ssl/test/runner/common.go
@@ -71,16 +71,17 @@ const (
// TLS extension numbers
const (
- extensionServerName uint16 = 0
- extensionStatusRequest uint16 = 5
- extensionSupportedCurves uint16 = 10
- extensionSupportedPoints uint16 = 11
- extensionSignatureAlgorithms uint16 = 13
- extensionALPN uint16 = 16
- extensionSessionTicket uint16 = 35
- extensionNextProtoNeg uint16 = 13172 // not IANA assigned
- extensionRenegotiationInfo uint16 = 0xff01
- extensionChannelID uint16 = 30032 // not IANA assigned
+ extensionServerName uint16 = 0
+ extensionStatusRequest uint16 = 5
+ extensionSupportedCurves uint16 = 10
+ extensionSupportedPoints uint16 = 11
+ extensionSignatureAlgorithms uint16 = 13
+ extensionALPN uint16 = 16
+ extensionExtendedMasterSecret uint16 = 23
+ extensionSessionTicket uint16 = 35
+ extensionNextProtoNeg uint16 = 13172 // not IANA assigned
+ extensionRenegotiationInfo uint16 = 0xff01
+ extensionChannelID uint16 = 30032 // not IANA assigned
)
// TLS signaling cipher suite values
@@ -189,12 +190,13 @@ const (
// ClientSessionState contains the state needed by clients to resume TLS
// sessions.
type ClientSessionState struct {
- 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
+ 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
}
// ClientSessionCache is a cache of ClientSessionState objects that can be used
@@ -323,6 +325,14 @@ type Config struct {
// 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
+
// Bugs specifies optional misbehaviour to be used for testing other
// implementations.
Bugs ProtocolBugs
@@ -472,6 +482,14 @@ type ProtocolBugs struct {
// OversizedSessionId causes the session id that is sent with a ticket
// resumption attempt to be too large (33 bytes).
OversizedSessionId bool
+
+ // RequireExtendedMasterSecret, if true, requires that the peer support
+ // the extended master secret option.
+ RequireExtendedMasterSecret bool
+
+ // NoExtendedMasterSecret causes the client and server to behave is if
+ // they didn't support an extended master secret.
+ NoExtendedMasterSecret bool
}
func (c *Config) serverInit() {
@@ -727,9 +745,10 @@ func defaultCipherSuites() []uint16 {
}
func initDefaultCipherSuites() {
- varDefaultCipherSuites = make([]uint16, len(cipherSuites))
- for i, suite := range cipherSuites {
- varDefaultCipherSuites[i] = suite.id
+ for _, suite := range cipherSuites {
+ if suite.flags&suitePSK == 0 {
+ varDefaultCipherSuites = append(varDefaultCipherSuites, suite.id)
+ }
}
}
diff --git a/ssl/test/runner/conn.go b/ssl/test/runner/conn.go
index 9f0c328..3ce6c76 100644
--- a/ssl/test/runner/conn.go
+++ b/ssl/test/runner/conn.go
@@ -29,16 +29,17 @@ type Conn struct {
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
- didResume bool // whether this connection was a session resumption
- cipherSuite uint16
- ocspResponse []byte // stapled OCSP response
- peerCertificates []*x509.Certificate
+ 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
+ didResume bool // whether this connection was a session resumption
+ extendedMasterSecret bool // whether this session used an extended master secret
+ cipherSuite uint16
+ ocspResponse []byte // stapled OCSP response
+ peerCertificates []*x509.Certificate
// verifiedChains contains the certificate chains that we built, as
// opposed to the ones presented by the server.
verifiedChains [][]*x509.Certificate
diff --git a/ssl/test/runner/handshake_client.go b/ssl/test/runner/handshake_client.go
index f4cadc2..11a1ed3 100644
--- a/ssl/test/runner/handshake_client.go
+++ b/ssl/test/runner/handshake_client.go
@@ -56,26 +56,31 @@ func (c *Conn) clientHandshake() error {
}
hello := &clientHelloMsg{
- isDTLS: c.isDTLS,
- vers: c.config.maxVersion(),
- compressionMethods: []uint8{compressionNone},
- random: make([]byte, 32),
- ocspStapling: true,
- serverName: c.config.ServerName,
- supportedCurves: c.config.curvePreferences(),
- supportedPoints: []uint8{pointFormatUncompressed},
- nextProtoNeg: len(c.config.NextProtos) > 0,
- secureRenegotiation: true,
- alpnProtocols: c.config.NextProtos,
- duplicateExtension: c.config.Bugs.DuplicateExtension,
- channelIDSupported: c.config.ChannelID != nil,
- npnLast: c.config.Bugs.SwapNPNAndALPN,
+ isDTLS: c.isDTLS,
+ vers: c.config.maxVersion(),
+ compressionMethods: []uint8{compressionNone},
+ random: make([]byte, 32),
+ ocspStapling: true,
+ serverName: c.config.ServerName,
+ supportedCurves: c.config.curvePreferences(),
+ supportedPoints: []uint8{pointFormatUncompressed},
+ nextProtoNeg: len(c.config.NextProtos) > 0,
+ secureRenegotiation: true,
+ alpnProtocols: c.config.NextProtos,
+ duplicateExtension: c.config.Bugs.DuplicateExtension,
+ channelIDSupported: c.config.ChannelID != nil,
+ npnLast: c.config.Bugs.SwapNPNAndALPN,
+ extendedMasterSecret: c.config.maxVersion() >= VersionTLS10,
}
if c.config.Bugs.SendClientVersion != 0 {
hello.vers = c.config.Bugs.SendClientVersion
}
+ if c.config.Bugs.NoExtendedMasterSecret {
+ hello.extendedMasterSecret = false
+ }
+
possibleCipherSuites := c.config.cipherSuites()
hello.cipherSuites = make([]uint16, 0, len(possibleCipherSuites))
@@ -303,60 +308,65 @@ NextCipherSuite:
func (hs *clientHandshakeState) doFullHandshake() error {
c := hs.c
- msg, err := c.readHandshake()
- if err != nil {
- return err
- }
- certMsg, ok := msg.(*certificateMsg)
- if !ok || len(certMsg.certificates) == 0 {
- c.sendAlert(alertUnexpectedMessage)
- return unexpectedMessageError(certMsg, msg)
- }
- hs.writeServerHash(certMsg.marshal())
-
- certs := make([]*x509.Certificate, len(certMsg.certificates))
- for i, asn1Data := range certMsg.certificates {
- cert, err := x509.ParseCertificate(asn1Data)
+ var leaf *x509.Certificate
+ if hs.suite.flags&suitePSK == 0 {
+ msg, err := c.readHandshake()
if err != nil {
- c.sendAlert(alertBadCertificate)
- return errors.New("tls: failed to parse certificate from server: " + err.Error())
+ return err
}
- 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(),
+ certMsg, ok := msg.(*certificateMsg)
+ if !ok || len(certMsg.certificates) == 0 {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(certMsg, msg)
}
+ hs.writeServerHash(certMsg.marshal())
- for i, cert := range certs {
- if i == 0 {
- continue
+ certs := make([]*x509.Certificate, len(certMsg.certificates))
+ for i, asn1Data := range certMsg.certificates {
+ cert, err := x509.ParseCertificate(asn1Data)
+ if err != nil {
+ c.sendAlert(alertBadCertificate)
+ return errors.New("tls: failed to parse certificate from server: " + err.Error())
}
- opts.Intermediates.AddCert(cert)
+ certs[i] = cert
}
- c.verifiedChains, err = certs[0].Verify(opts)
- if err != nil {
- c.sendAlert(alertBadCertificate)
- return err
+ leaf = certs[0]
+
+ 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)
+ }
+ c.verifiedChains, err = leaf.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)
- }
+ switch leaf.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", leaf.PublicKey)
+ }
- c.peerCertificates = certs
+ c.peerCertificates = certs
+ }
if hs.serverHello.ocspStapling {
- msg, err = c.readHandshake()
+ msg, err := c.readHandshake()
if err != nil {
return err
}
@@ -372,7 +382,7 @@ func (hs *clientHandshakeState) doFullHandshake() error {
}
}
- msg, err = c.readHandshake()
+ msg, err := c.readHandshake()
if err != nil {
return err
}
@@ -382,7 +392,7 @@ func (hs *clientHandshakeState) doFullHandshake() error {
skx, ok := msg.(*serverKeyExchangeMsg)
if ok {
hs.writeServerHash(skx.marshal())
- err = keyAgreement.processServerKeyExchange(c.config, hs.hello, hs.serverHello, certs[0], skx)
+ err = keyAgreement.processServerKeyExchange(c.config, hs.hello, hs.serverHello, leaf, skx)
if err != nil {
c.sendAlert(alertUnexpectedMessage)
return err
@@ -483,7 +493,7 @@ func (hs *clientHandshakeState) doFullHandshake() error {
// Certificate message, even if it's empty because we don't have a
// certificate to send.
if certRequested {
- certMsg = new(certificateMsg)
+ certMsg := new(certificateMsg)
if chainToSend != nil {
certMsg.certificates = chainToSend.Certificate
}
@@ -491,7 +501,7 @@ func (hs *clientHandshakeState) doFullHandshake() error {
c.writeRecord(recordTypeHandshake, certMsg.marshal())
}
- preMasterSecret, ckx, err := keyAgreement.generateClientKeyExchange(c.config, hs.hello, certs[0])
+ preMasterSecret, ckx, err := keyAgreement.generateClientKeyExchange(c.config, hs.hello, leaf)
if err != nil {
c.sendAlert(alertInternalError)
return err
@@ -503,7 +513,15 @@ func (hs *clientHandshakeState) doFullHandshake() error {
c.writeRecord(recordTypeHandshake, ckx.marshal())
}
- hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.hello.random, hs.serverHello.random)
+ if hs.serverHello.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 {
var signed []byte
@@ -629,6 +647,7 @@ func (hs *clientHandshakeState) processServerHello() (bool, error) {
// Restore masterSecret and peerCerts from previous state
hs.masterSecret = hs.session.masterSecret
c.peerCertificates = hs.session.serverCertificates
+ c.extendedMasterSecret = hs.session.extendedMasterSecret
hs.finishedHash.discardHandshakeBuffer()
return true, nil
}
diff --git a/ssl/test/runner/handshake_messages.go b/ssl/test/runner/handshake_messages.go
index 136360d..1114a6f 100644
--- a/ssl/test/runner/handshake_messages.go
+++ b/ssl/test/runner/handshake_messages.go
@@ -7,27 +7,28 @@ package main
import "bytes"
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
- ticketSupported bool
- sessionTicket []uint8
- signatureAndHashes []signatureAndHash
- secureRenegotiation bool
- alpnProtocols []string
- duplicateExtension bool
- channelIDSupported bool
- npnLast bool
+ 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
+ ticketSupported bool
+ sessionTicket []uint8
+ signatureAndHashes []signatureAndHash
+ secureRenegotiation bool
+ alpnProtocols []string
+ duplicateExtension bool
+ channelIDSupported bool
+ npnLast bool
+ extendedMasterSecret bool
}
func (m *clientHelloMsg) equal(i interface{}) bool {
@@ -56,7 +57,8 @@ func (m *clientHelloMsg) equal(i interface{}) bool {
eqStrings(m.alpnProtocols, m1.alpnProtocols) &&
m.duplicateExtension == m1.duplicateExtension &&
m.channelIDSupported == m1.channelIDSupported &&
- m.npnLast == m1.npnLast
+ m.npnLast == m1.npnLast &&
+ m.extendedMasterSecret == m1.extendedMasterSecret
}
func (m *clientHelloMsg) marshal() []byte {
@@ -118,6 +120,9 @@ func (m *clientHelloMsg) marshal() []byte {
}
numExtensions++
}
+ if m.extendedMasterSecret {
+ numExtensions++
+ }
if numExtensions > 0 {
extensionsLength += 4 * numExtensions
length += 2 + extensionsLength
@@ -319,6 +324,12 @@ func (m *clientHelloMsg) marshal() []byte {
z[1] = 0xff
z = z[4:]
}
+ if m.extendedMasterSecret {
+ // https://tools.ietf.org/html/draft-ietf-tls-session-hash-01
+ z[0] = byte(extensionExtendedMasterSecret >> 8)
+ z[1] = byte(extensionExtendedMasterSecret & 0xff)
+ z = z[4:]
+ }
m.raw = x
@@ -385,6 +396,7 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
m.sessionTicket = nil
m.signatureAndHashes = nil
m.alpnProtocols = nil
+ m.extendedMasterSecret = false
if len(data) == 0 {
// ClientHello is optionally followed by extension data
@@ -517,6 +529,11 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
return false
}
m.channelIDSupported = true
+ case extensionExtendedMasterSecret:
+ if length != 0 {
+ return false
+ }
+ m.extendedMasterSecret = true
}
data = data[length:]
}
@@ -525,21 +542,22 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
}
type serverHelloMsg struct {
- raw []byte
- isDTLS bool
- vers uint16
- random []byte
- sessionId []byte
- cipherSuite uint16
- compressionMethod uint8
- nextProtoNeg bool
- nextProtos []string
- ocspStapling bool
- ticketSupported bool
- secureRenegotiation bool
- alpnProtocol string
- duplicateExtension bool
- channelIDRequested bool
+ raw []byte
+ isDTLS bool
+ vers uint16
+ random []byte
+ sessionId []byte
+ cipherSuite uint16
+ compressionMethod uint8
+ nextProtoNeg bool
+ nextProtos []string
+ ocspStapling bool
+ ticketSupported bool
+ secureRenegotiation bool
+ alpnProtocol string
+ duplicateExtension bool
+ channelIDRequested bool
+ extendedMasterSecret bool
}
func (m *serverHelloMsg) equal(i interface{}) bool {
@@ -562,7 +580,8 @@ func (m *serverHelloMsg) equal(i interface{}) bool {
m.secureRenegotiation == m1.secureRenegotiation &&
m.alpnProtocol == m1.alpnProtocol &&
m.duplicateExtension == m1.duplicateExtension &&
- m.channelIDRequested == m1.channelIDRequested
+ m.channelIDRequested == m1.channelIDRequested &&
+ m.extendedMasterSecret == m1.extendedMasterSecret
}
func (m *serverHelloMsg) marshal() []byte {
@@ -606,6 +625,9 @@ func (m *serverHelloMsg) marshal() []byte {
extensionsLength += 2 + 1 + alpnLen
numExtensions++
}
+ if m.extendedMasterSecret {
+ numExtensions++
+ }
if numExtensions > 0 {
extensionsLength += 4 * numExtensions
@@ -699,6 +721,11 @@ func (m *serverHelloMsg) marshal() []byte {
z[1] = 0xff
z = z[4:]
}
+ if m.extendedMasterSecret {
+ z[0] = byte(extensionExtendedMasterSecret >> 8)
+ z[1] = byte(extensionExtendedMasterSecret & 0xff)
+ z = z[4:]
+ }
m.raw = x
@@ -730,6 +757,7 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool {
m.ocspStapling = false
m.ticketSupported = false
m.alpnProtocol = ""
+ m.extendedMasterSecret = false
if len(data) == 0 {
// ServerHello is optionally followed by extension data
@@ -805,6 +833,11 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool {
return false
}
m.channelIDRequested = true
+ case extensionExtendedMasterSecret:
+ if length != 0 {
+ return false
+ }
+ m.extendedMasterSecret = true
}
data = data[length:]
}
diff --git a/ssl/test/runner/handshake_server.go b/ssl/test/runner/handshake_server.go
index 1eb3f11..4bf8f1c 100644
--- a/ssl/test/runner/handshake_server.go
+++ b/ssl/test/runner/handshake_server.go
@@ -237,6 +237,7 @@ Curves:
hs.hello.nextProtos = config.NextProtos
}
}
+ hs.hello.extendedMasterSecret = c.vers >= VersionTLS10 && hs.clientHello.extendedMasterSecret && !c.config.Bugs.NoExtendedMasterSecret
if len(config.Certificates) == 0 {
c.sendAlert(alertInternalError)
@@ -373,6 +374,7 @@ func (hs *serverHandshakeState) doResumeHandshake() error {
}
hs.masterSecret = hs.sessionState.masterSecret
+ c.extendedMasterSecret = hs.sessionState.extendedMasterSecret
return nil
}
@@ -381,12 +383,14 @@ func (hs *serverHandshakeState) doFullHandshake() error {
config := hs.c.config
c := hs.c
- if hs.clientHello.ocspStapling && len(hs.cert.OCSPStaple) > 0 {
+ isPSK := hs.suite.flags&suitePSK != 0
+ if !isPSK && hs.clientHello.ocspStapling && len(hs.cert.OCSPStaple) > 0 {
hs.hello.ocspStapling = true
}
hs.hello.ticketSupported = hs.clientHello.ticketSupported && !config.SessionTicketsDisabled
hs.hello.cipherSuite = hs.suite.id
+ c.extendedMasterSecret = hs.hello.extendedMasterSecret
hs.finishedHash = newFinishedHash(c.vers, hs.suite)
hs.writeClientHash(hs.clientHello.marshal())
@@ -394,11 +398,13 @@ func (hs *serverHandshakeState) doFullHandshake() error {
c.writeRecord(recordTypeHandshake, hs.hello.marshal())
- certMsg := new(certificateMsg)
- certMsg.certificates = hs.cert.Certificate
- if !config.Bugs.UnauthenticatedECDH {
- hs.writeServerHash(certMsg.marshal())
- c.writeRecord(recordTypeHandshake, certMsg.marshal())
+ if !isPSK {
+ certMsg := new(certificateMsg)
+ certMsg.certificates = hs.cert.Certificate
+ if !config.Bugs.UnauthenticatedECDH {
+ hs.writeServerHash(certMsg.marshal())
+ c.writeRecord(recordTypeHandshake, certMsg.marshal())
+ }
}
if hs.hello.ocspStapling {
@@ -463,6 +469,7 @@ func (hs *serverHandshakeState) doFullHandshake() error {
// 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
if certMsg, ok = msg.(*certificateMsg); !ok {
c.sendAlert(alertUnexpectedMessage)
return unexpectedMessageError(certMsg, msg)
@@ -502,7 +509,14 @@ func (hs *serverHandshakeState) doFullHandshake() error {
c.sendAlert(alertHandshakeFailure)
return err
}
- hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.clientHello.random, hs.hello.random)
+ 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
diff --git a/ssl/test/runner/key_agreement.go b/ssl/test/runner/key_agreement.go
index f8ba1f8..af54a8f 100644
--- a/ssl/test/runner/key_agreement.go
+++ b/ssl/test/runner/key_agreement.go
@@ -187,8 +187,29 @@ func curveForCurveID(id CurveID) (elliptic.Curve, bool) {
}
-// signedKeyAgreement implements helper functions for key agreement
-// methods that involve signed parameters in the ServerKeyExchange.
+// 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 {
version uint16
sigType uint8
@@ -328,7 +349,7 @@ func (ka *signedKeyAgreement) verifyParameters(config *Config, clientHello *clie
// pre-master secret is then calculated using ECDH. The signature may
// either be ECDSA or RSA.
type ecdheKeyAgreement struct {
- signedKeyAgreement
+ auth keyAgreementAuthentication
privateKey []byte
curve elliptic.Curve
x, y *big.Int
@@ -394,7 +415,7 @@ NextCandidate:
serverECDHParams[3] = byte(len(ecdhePublic))
copy(serverECDHParams[4:], ecdhePublic)
- return ka.signParameters(config, cert, clientHello, hello, serverECDHParams)
+ return ka.auth.signParameters(config, cert, clientHello, hello, serverECDHParams)
}
func (ka *ecdheKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
@@ -438,7 +459,7 @@ func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHell
serverECDHParams := skx.key[:4+publicLen]
sig := skx.key[4+publicLen:]
- return ka.verifyParameters(config, clientHello, serverHello, cert, serverECDHParams, sig)
+ return ka.auth.verifyParameters(config, clientHello, serverHello, cert, serverECDHParams, sig)
}
func (ka *ecdheKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) {
@@ -468,7 +489,7 @@ func (ka *ecdheKeyAgreement) generateClientKeyExchange(config *Config, clientHel
// an ephemeral Diffie-Hellman public/private key pair and signs it. The
// pre-master secret is then calculated using Diffie-Hellman.
type dheKeyAgreement struct {
- signedKeyAgreement
+ auth keyAgreementAuthentication
p, g *big.Int
yTheirs *big.Int
xOurs *big.Int
@@ -500,7 +521,7 @@ func (ka *dheKeyAgreement) generateServerKeyExchange(config *Config, cert *Certi
serverDHParams = append(serverDHParams, byte(len(yBytes)>>8), byte(len(yBytes)))
serverDHParams = append(serverDHParams, yBytes...)
- return ka.signParameters(config, cert, clientHello, hello, serverDHParams)
+ return ka.auth.signParameters(config, cert, clientHello, hello, serverDHParams)
}
func (ka *dheKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
@@ -562,7 +583,7 @@ func (ka *dheKeyAgreement) processServerKeyExchange(config *Config, clientHello
sig := k
serverDHParams := skx.key[:len(skx.key)-len(sig)]
- return ka.verifyParameters(config, clientHello, serverHello, cert, serverDHParams, 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) {
@@ -586,3 +607,164 @@ func (ka *dheKeyAgreement) generateClientKeyExchange(config *Config, clientHello
return preMasterSecret, ckx, nil
}
+
+// 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
+}
+
+// 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 == "" {
+ // 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
+}
diff --git a/ssl/test/runner/prf.go b/ssl/test/runner/prf.go
index 6d0db97..d45c080 100644
--- a/ssl/test/runner/prf.go
+++ b/ssl/test/runner/prf.go
@@ -117,6 +117,7 @@ const (
)
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")
@@ -150,6 +151,15 @@ func masterFromPreMasterSecret(version uint16, suite *cipherSuite, preMasterSecr
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/draft-ietf-tls-session-hash-01
+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.
@@ -221,6 +231,16 @@ func (h *finishedHash) Write(msg []byte) (n int, err error) {
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.
@@ -264,15 +284,7 @@ func (h finishedHash) clientSum(masterSecret []byte) []byte {
}
out := make([]byte, finishedVerifyLength)
- if h.version >= VersionTLS12 {
- seed := h.client.Sum(nil)
- h.prf(out, masterSecret, clientFinishedLabel, seed)
- } else {
- seed := make([]byte, 0, md5.Size+sha1.Size)
- seed = h.clientMD5.Sum(seed)
- seed = h.client.Sum(seed)
- h.prf(out, masterSecret, clientFinishedLabel, seed)
- }
+ h.prf(out, masterSecret, clientFinishedLabel, h.Sum())
return out
}
@@ -284,15 +296,7 @@ func (h finishedHash) serverSum(masterSecret []byte) []byte {
}
out := make([]byte, finishedVerifyLength)
- if h.version >= VersionTLS12 {
- seed := h.server.Sum(nil)
- h.prf(out, masterSecret, serverFinishedLabel, seed)
- } else {
- seed := make([]byte, 0, md5.Size+sha1.Size)
- seed = h.serverMD5.Sum(seed)
- seed = h.server.Sum(seed)
- h.prf(out, masterSecret, serverFinishedLabel, seed)
- }
+ h.prf(out, masterSecret, serverFinishedLabel, h.Sum())
return out
}
@@ -334,14 +338,10 @@ func (h finishedHash) hashForClientCertificate(signatureAndHash signatureAndHash
return digest[:], crypto.SHA256, nil
}
if signatureAndHash.signature == signatureECDSA {
- digest := h.server.Sum(nil)
- return digest, crypto.SHA1, nil
+ return h.server.Sum(nil), crypto.SHA1, nil
}
- digest := make([]byte, 0, 36)
- digest = h.serverMD5.Sum(digest)
- digest = h.server.Sum(digest)
- return digest, crypto.MD5SHA1, nil
+ return h.Sum(), crypto.MD5SHA1, nil
}
// hashForChannelID returns the hash to be signed for TLS Channel
diff --git a/ssl/test/runner/recordingconn.go b/ssl/test/runner/recordingconn.go
new file mode 100644
index 0000000..a67fa48
--- /dev/null
+++ b/ssl/test/runner/recordingconn.go
@@ -0,0 +1,130 @@
+package main
+
+import (
+ "bufio"
+ "encoding/hex"
+ "errors"
+ "fmt"
+ "io"
+ "net"
+ "strconv"
+ "strings"
+ "sync"
+)
+
+// 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 [][]byte
+ reading bool
+}
+
+func (r *recordingConn) Read(b []byte) (n int, err error) {
+ if n, err = r.Conn.Read(b); n == 0 {
+ return
+ }
+ b = b[:n]
+
+ r.Lock()
+ defer r.Unlock()
+
+ if l := len(r.flows); l == 0 || !r.reading {
+ buf := make([]byte, len(b))
+ copy(buf, b)
+ r.flows = append(r.flows, buf)
+ } else {
+ r.flows[l-1] = append(r.flows[l-1], b[:n]...)
+ }
+ r.reading = true
+ return
+}
+
+func (r *recordingConn) Write(b []byte) (n int, err error) {
+ if n, err = r.Conn.Write(b); n == 0 {
+ return
+ }
+ b = b[:n]
+
+ r.Lock()
+ defer r.Unlock()
+
+ if l := len(r.flows); l == 0 || r.reading {
+ buf := make([]byte, len(b))
+ copy(buf, b)
+ r.flows = append(r.flows, buf)
+ } else {
+ r.flows[l-1] = append(r.flows[l-1], b[:n]...)
+ }
+ r.reading = false
+ return
+}
+
+// WriteTo writes hex dumps to w that contains the recorded traffic.
+func (r *recordingConn) WriteTo(w io.Writer) {
+ // TLS always starts with a client to server flow.
+ clientToServer := true
+
+ for i, flow := range r.flows {
+ source, dest := "client", "server"
+ if !clientToServer {
+ source, dest = dest, source
+ }
+ fmt.Fprintf(w, ">>> Flow %d (%s to %s)\n", i+1, source, dest)
+ dumper := hex.Dumper(w)
+ dumper.Write(flow)
+ dumper.Close()
+ clientToServer = !clientToServer
+ }
+}
+
+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/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index b4c2e61..1b461e2 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -22,6 +22,8 @@ import (
)
var useValgrind = flag.Bool("valgrind", false, "If true, run code under valgrind")
+var useGDB = flag.Bool("gdb", false, "If true, run BoringSSL code under gdb")
+var flagDebug *bool = flag.Bool("debug", false, "Hexdump the contents of the connection")
const (
rsaCertificateFile = "cert.pem"
@@ -693,10 +695,11 @@ func runTest(test *testCase, buildDir string) error {
var shim *exec.Cmd
if *useValgrind {
shim = valgrindOf(false, shim_path, flags...)
+ } else if *useGDB {
+ shim = gdbOf(shim_path, flags...)
} else {
shim = exec.Command(shim_path, flags...)
}
- // shim = gdbOf(shim_path, flags...)
shim.ExtraFiles = []*os.File{shimEnd, shimEndResume}
shim.Stdin = os.Stdin
var stdoutBuf, stderrBuf bytes.Buffer
@@ -717,8 +720,19 @@ func runTest(test *testCase, buildDir string) error {
}
}
+ var connDebug *recordingConn
+ if *flagDebug {
+ connDebug = &recordingConn{Conn: conn}
+ conn = connDebug
+ }
+
err := doExchange(test, &config, conn, test.messageLen,
false /* not a resumption */)
+
+ if *flagDebug {
+ connDebug.WriteTo(os.Stdout)
+ }
+
conn.Close()
if err == nil && test.resumeSession {
var resumeConfig Config
@@ -814,6 +828,7 @@ var testCipherSuites = []struct {
{"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-RC4-SHA", TLS_ECDHE_ECDSA_WITH_RC4_128_SHA},
+ {"ECDHE-PSK-WITH-AES-128-GCM-SHA256", TLS_ECDHE_PSK_WITH_AES_128_GCM_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},
@@ -821,6 +836,9 @@ var testCipherSuites = []struct {
{"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-RC4-SHA", TLS_ECDHE_RSA_WITH_RC4_128_SHA},
+ {"PSK-AES128-CBC-SHA", TLS_PSK_WITH_AES_128_CBC_SHA},
+ {"PSK-AES256-CBC-SHA", TLS_PSK_WITH_AES_256_CBC_SHA},
+ {"PSK-RC4-SHA", TLS_PSK_WITH_RC4_128_SHA},
{"RC4-MD5", TLS_RSA_WITH_RC4_128_MD5},
{"RC4-SHA", TLS_RSA_WITH_RC4_128_SHA},
}
@@ -833,6 +851,9 @@ func isTLS12Only(suiteName string) bool {
func addCipherSuiteTests() {
for _, suite := range testCipherSuites {
+ const psk = "12345"
+ const pskIdentity = "luggage combo"
+
var cert Certificate
var certFile string
var keyFile string
@@ -846,6 +867,13 @@ func addCipherSuiteTests() {
keyFile = rsaKeyFile
}
+ var flags []string
+ if strings.HasPrefix(suite.name, "PSK-") || strings.Contains(suite.name, "-PSK-") {
+ flags = append(flags,
+ "-psk", psk,
+ "-psk-identity", pskIdentity)
+ }
+
for _, ver := range tlsVersions {
if ver.version < VersionTLS12 && isTLS12Only(suite.name) {
continue
@@ -860,11 +888,14 @@ func addCipherSuiteTests() {
testType: clientTest,
name: ver.name + "-" + suite.name + "-client",
config: Config{
- MinVersion: ver.version,
- MaxVersion: ver.version,
- CipherSuites: []uint16{suite.id},
- Certificates: []Certificate{cert},
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
+ CipherSuites: []uint16{suite.id},
+ Certificates: []Certificate{cert},
+ PreSharedKey: []byte(psk),
+ PreSharedKeyIdentity: pskIdentity,
},
+ flags: flags,
resumeSession: resumeSession,
})
@@ -872,13 +903,16 @@ func addCipherSuiteTests() {
testType: serverTest,
name: ver.name + "-" + suite.name + "-server",
config: Config{
- MinVersion: ver.version,
- MaxVersion: ver.version,
- CipherSuites: []uint16{suite.id},
- Certificates: []Certificate{cert},
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
+ CipherSuites: []uint16{suite.id},
+ Certificates: []Certificate{cert},
+ PreSharedKey: []byte(psk),
+ PreSharedKeyIdentity: pskIdentity,
},
certFile: certFile,
keyFile: keyFile,
+ flags: flags,
resumeSession: resumeSession,
})
@@ -889,11 +923,14 @@ func addCipherSuiteTests() {
protocol: dtls,
name: "D" + ver.name + "-" + suite.name + "-client",
config: Config{
- MinVersion: ver.version,
- MaxVersion: ver.version,
- CipherSuites: []uint16{suite.id},
- Certificates: []Certificate{cert},
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
+ CipherSuites: []uint16{suite.id},
+ Certificates: []Certificate{cert},
+ PreSharedKey: []byte(psk),
+ PreSharedKeyIdentity: pskIdentity,
},
+ flags: flags,
resumeSession: resumeSession,
})
testCases = append(testCases, testCase{
@@ -901,13 +938,16 @@ func addCipherSuiteTests() {
protocol: dtls,
name: "D" + ver.name + "-" + suite.name + "-server",
config: Config{
- MinVersion: ver.version,
- MaxVersion: ver.version,
- CipherSuites: []uint16{suite.id},
- Certificates: []Certificate{cert},
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
+ CipherSuites: []uint16{suite.id},
+ Certificates: []Certificate{cert},
+ PreSharedKey: []byte(psk),
+ PreSharedKeyIdentity: pskIdentity,
},
certFile: certFile,
keyFile: keyFile,
+ flags: flags,
resumeSession: resumeSession,
})
}
@@ -1070,6 +1110,62 @@ func addClientAuthTests() {
}
}
+func addExtendedMasterSecretTests() {
+ const expectEMSFlag = "-expect-extended-master-secret"
+
+ for _, with := range []bool{false, true} {
+ prefix := "No"
+ var flags []string
+ if with {
+ prefix = ""
+ flags = []string{expectEMSFlag}
+ }
+
+ for _, isClient := range []bool{false, true} {
+ suffix := "-Server"
+ testType := serverTest
+ if isClient {
+ suffix = "-Client"
+ testType = clientTest
+ }
+
+ for _, ver := range tlsVersions {
+ 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)
+ }
+ }
+ }
+
+ // 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.
+ testCases = append(testCases, testCase{
+ name: "ExtendedMasterSecret-Resume",
+ config: Config{
+ Bugs: ProtocolBugs{
+ RequireExtendedMasterSecret: true,
+ },
+ },
+ flags: []string{expectEMSFlag},
+ resumeSession: true,
+ })
+}
+
// 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.
@@ -1178,6 +1274,34 @@ func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol)
flags: flags,
})
+ // Skip ServerKeyExchange in PSK key exchange if there's no
+ // identity hint.
+ testCases = append(testCases, testCase{
+ protocol: protocol,
+ name: "EmptyPSKHint-Client" + suffix,
+ config: Config{
+ CipherSuites: []uint16{TLS_PSK_WITH_AES_128_CBC_SHA},
+ PreSharedKey: []byte("secret"),
+ Bugs: ProtocolBugs{
+ MaxHandshakeRecordLength: maxHandshakeRecordLength,
+ },
+ },
+ flags: append(flags, "-psk", "secret"),
+ })
+ testCases = append(testCases, testCase{
+ protocol: protocol,
+ testType: serverTest,
+ name: "EmptyPSKHint-Server" + suffix,
+ config: Config{
+ CipherSuites: []uint16{TLS_PSK_WITH_AES_128_CBC_SHA},
+ PreSharedKey: []byte("secret"),
+ Bugs: ProtocolBugs{
+ MaxHandshakeRecordLength: maxHandshakeRecordLength,
+ },
+ },
+ flags: append(flags, "-psk", "secret"),
+ })
+
if protocol == tls {
// NPN on client and server; results in post-handshake message.
testCases = append(testCases, testCase{
@@ -1568,7 +1692,7 @@ func addExtensionTests() {
},
},
resumeSession: true,
- shouldFail: true,
+ shouldFail: true,
expectedError: ":DECODE_ERROR:",
})
}
@@ -1690,6 +1814,7 @@ func main() {
addD5BugTests()
addExtensionTests()
addResumptionVersionTests()
+ addExtendedMasterSecretTests()
for _, async := range []bool{false, true} {
for _, splitHandshake := range []bool{false, true} {
for _, protocol := range []protocol{tls, dtls} {
diff --git a/ssl/test/runner/ticket.go b/ssl/test/runner/ticket.go
index 74791d6..8355822 100644
--- a/ssl/test/runner/ticket.go
+++ b/ssl/test/runner/ticket.go
@@ -18,11 +18,12 @@ import (
// 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
+ vers uint16
+ cipherSuite uint16
+ masterSecret []byte
+ handshakeHash []byte
+ certificates [][]byte
+ extendedMasterSecret bool
}
func (s *sessionState) equal(i interface{}) bool {
@@ -34,7 +35,8 @@ func (s *sessionState) equal(i interface{}) bool {
if s.vers != s1.vers ||
s.cipherSuite != s1.cipherSuite ||
!bytes.Equal(s.masterSecret, s1.masterSecret) ||
- !bytes.Equal(s.handshakeHash, s1.handshakeHash) {
+ !bytes.Equal(s.handshakeHash, s1.handshakeHash) ||
+ s.extendedMasterSecret != s1.extendedMasterSecret {
return false
}
@@ -56,6 +58,7 @@ func (s *sessionState) marshal() []byte {
for _, cert := range s.certificates {
length += 4 + len(cert)
}
+ length++
ret := make([]byte, length)
x := ret
@@ -88,6 +91,11 @@ func (s *sessionState) marshal() []byte {
x = x[4+len(cert):]
}
+ if s.extendedMasterSecret {
+ x[0] = 1
+ }
+ x = x[1:]
+
return ret
}
@@ -144,6 +152,16 @@ func (s *sessionState) unmarshal(data []byte) bool {
data = data[certLen:]
}
+ if len(data) < 1 {
+ return false
+ }
+
+ s.extendedMasterSecret = false
+ if data[0] == 1 {
+ s.extendedMasterSecret = true
+ }
+ data = data[1:]
+
if len(data) > 0 {
return false
}
diff --git a/ssl/test/test_config.cc b/ssl/test/test_config.cc
index 270fbfb..c50d9de 100644
--- a/ssl/test/test_config.cc
+++ b/ssl/test/test_config.cc
@@ -57,6 +57,8 @@ const BoolFlag kBoolFlags[] = {
{ "-shim-writes-first", &TestConfig::shim_writes_first },
{ "-tls-d5-bug", &TestConfig::tls_d5_bug },
{ "-expect-session-miss", &TestConfig::expect_session_miss },
+ { "-expect-extended-master-secret",
+ &TestConfig::expect_extended_master_secret },
};
const size_t kNumBoolFlags = sizeof(kBoolFlags) / sizeof(kBoolFlags[0]);
@@ -74,6 +76,8 @@ const StringFlag kStringFlags[] = {
{ "-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 },
};
const size_t kNumStringFlags = sizeof(kStringFlags) / sizeof(kStringFlags[0]);
@@ -105,7 +109,8 @@ TestConfig::TestConfig()
cookie_exchange(false),
shim_writes_first(false),
tls_d5_bug(false),
- expect_session_miss(false) {
+ expect_session_miss(false),
+ expect_extended_master_secret(false) {
}
bool ParseConfig(int argc, char **argv, TestConfig *out_config) {
diff --git a/ssl/test/test_config.h b/ssl/test/test_config.h
index acce504..e5ff8ad 100644
--- a/ssl/test/test_config.h
+++ b/ssl/test/test_config.h
@@ -53,6 +53,9 @@ struct TestConfig {
std::string expected_advertised_alpn;
std::string select_alpn;
bool expect_session_miss;
+ bool expect_extended_master_secret;
+ std::string psk;
+ std::string psk_identity;
};
bool ParseConfig(int argc, char **argv, TestConfig *out_config);
diff --git a/tool/client.cc b/tool/client.cc
index d7d9e22..6cc93d6 100644
--- a/tool/client.cc
+++ b/tool/client.cc
@@ -47,6 +47,10 @@ static const struct argument kArguments[] = {
"The hostname and port of the server to connect to, e.g. foo.com:443",
},
{
+ "-cipher", false,
+ "An OpenSSL-style cipher suite string that configures the offered ciphers",
+ },
+ {
"", false, "",
},
};
@@ -265,6 +269,10 @@ bool Client(const std::vector<std::string> &args) {
SSL_CTX_set_keylog_bio(ctx, keylog_bio);
}
+ if (args_map.count("-cipher") != 0) {
+ SSL_CTX_set_cipher_list(ctx, args_map["-cipher"].c_str());
+ }
+
int sock = -1;
if (!Connect(&sock, args_map["-connect"])) {
return false;