diff options
author | Android Chromium Automerger <chromium-automerger@android> | 2014-09-26 00:30:54 +0000 |
---|---|---|
committer | Android Chromium Automerger <chromium-automerger@android> | 2014-09-26 00:30:54 +0000 |
commit | 885164b8d921ef7dba08b9e5ae031bf7350bf4ff (patch) | |
tree | bbdd45cda3f7f15eae3f9dfa9ac4d6a604d82479 | |
parent | f028ac1b7a2f3ca606ee44f7486a855588a0a7b1 (diff) | |
parent | 01fe820ab957514f6b83e511492de1b3c03649d5 (diff) | |
download | src-885164b8d921ef7dba08b9e5ae031bf7350bf4ff.tar.gz |
Merge third_party/boringssl/src from https://boringssl.googlesource.com/boringssl.git at 01fe820ab957514f6b83e511492de1b3c03649d5
This commit was generated by merge_from_chromium.py.
Change-Id: Ic03398af24c5f9382f97f578539898b8d46d6036
35 files changed, 1250 insertions, 390 deletions
diff --git a/crypto/bio/bio.c b/crypto/bio/bio.c index a35ff65..7bd2976 100644 --- a/crypto/bio/bio.c +++ b/crypto/bio/bio.c @@ -351,6 +351,10 @@ size_t BIO_pending(const BIO *bio) { return BIO_ctrl((BIO *) bio, BIO_CTRL_PENDING, 0, NULL); } +size_t BIO_ctrl_pending(const BIO *bio) { + return BIO_pending(bio); +} + size_t BIO_wpending(const BIO *bio) { return BIO_ctrl((BIO *) bio, BIO_CTRL_WPENDING, 0, NULL); } diff --git a/crypto/cpu-intel.c b/crypto/cpu-intel.c index e2efb2c..3dd08a9 100644 --- a/crypto/cpu-intel.c +++ b/crypto/cpu-intel.c @@ -61,7 +61,7 @@ #include <openssl/cpu.h> -#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64) +#if !defined(OPENSSL_NO_ASM) && (defined(OPENSSL_X86) || defined(OPENSSL_X86_64)) #include <stdio.h> #include <inttypes.h> @@ -132,4 +132,4 @@ void OPENSSL_cpuid_setup(void) { } } -#endif /* OPENSSL_X86 || OPENSSL_X86_64 */ +#endif /* !OPENSSL_NO_ASM && (OPENSSL_X86 || OPENSSL_X86_64) */ diff --git a/crypto/crypto.c b/crypto/crypto.c index 78241da..ee7c405 100644 --- a/crypto/crypto.c +++ b/crypto/crypto.c @@ -16,14 +16,22 @@ #include "internal.h" +#if !defined(OPENSSL_NO_ASM) && \ + (defined(OPENSSL_X86) || defined(OPENSSL_X86_64)) +/* x86 and x86_64 need to record the result of a cpuid call for the asm to work + * correctly, unless compiled without asm code. */ +#define NEED_CPUID -/* Currently, the only configurations which require a static initializer are x86 - * and x86_64. Don't bother emitting one in other cases. */ -#if !defined(OPENSSL_X86) && !defined(OPENSSL_X86_64) && \ - !defined(BORINGSSL_NO_STATIC_INITIALIZER) +#else + +/* Otherwise, don't emit a static initialiser. */ + +#if !defined(BORINGSSL_NO_STATIC_INITIALIZER) #define BORINGSSL_NO_STATIC_INITIALIZER #endif +#endif /* !OPENSSL_NO_ASM && (OPENSSL_X86 || OPENSSL_X86_64) */ + #if defined(OPENSSL_WINDOWS) #define OPENSSL_CDECL __cdecl #else @@ -45,7 +53,7 @@ __declspec(allocate(".CRT$XCU")) void(*library_init_constructor)(void) = * BORINGSSL_NO_STATIC_INITIALIZER isn't defined, this is set as a static * initializer. Otherwise, it is called by CRYPTO_library_init. */ static void OPENSSL_CDECL do_library_init(void) { -#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64) +#if defined(NEED_CPUID) OPENSSL_cpuid_setup(); #endif } diff --git a/crypto/digest/digest.c b/crypto/digest/digest.c index 2bfb0fa..3897c60 100644 --- a/crypto/digest/digest.c +++ b/crypto/digest/digest.c @@ -267,3 +267,7 @@ void EVP_MD_CTX_clear_flags(EVP_MD_CTX *ctx, uint32_t flags) { uint32_t EVP_MD_CTX_test_flags(const EVP_MD_CTX *ctx, uint32_t flags) { return ctx->flags & flags; } + +int EVP_add_digest(const EVP_MD *digest) { + return 1; +} diff --git a/crypto/dsa/dsa.c b/crypto/dsa/dsa.c index 8c66ddf..25d15c0 100644 --- a/crypto/dsa/dsa.c +++ b/crypto/dsa/dsa.c @@ -60,6 +60,7 @@ #include <openssl/dsa.h> #include <openssl/asn1.h> +#include <openssl/dh.h> #include <openssl/engine.h> #include <openssl/err.h> #include <openssl/ex_data.h> @@ -332,3 +333,35 @@ int DSA_set_ex_data(DSA *d, int idx, void *arg) { void *DSA_get_ex_data(const DSA *d, int idx) { return CRYPTO_get_ex_data(&d->ex_data, idx); } + +DH *DSA_dup_DH(const DSA *r) { + DH *ret = NULL; + + if (r == NULL) { + goto err; + } + ret = DH_new(); + if (ret == NULL) { + goto err; + } + if (r->q != NULL) { + ret->priv_length = BN_num_bits(r->q); + if ((ret->q = BN_dup(r->q)) == NULL) { + goto err; + } + } + if ((r->p != NULL && (ret->p = BN_dup(r->p)) == NULL) || + (r->g != NULL && (ret->g = BN_dup(r->g)) == NULL) || + (r->pub_key != NULL && (ret->pub_key = BN_dup(r->pub_key)) == NULL) || + (r->priv_key != NULL && (ret->priv_key = BN_dup(r->priv_key)) == NULL)) { + goto err; + } + + return ret; + +err: + if (ret != NULL) { + DH_free(ret); + } + return NULL; +} diff --git a/crypto/pkcs8/pkcs12_test.c b/crypto/pkcs8/pkcs12_test.c index 6aea1eb..2292b77 100644 --- a/crypto/pkcs8/pkcs12_test.c +++ b/crypto/pkcs8/pkcs12_test.c @@ -705,13 +705,56 @@ static int test(const char *name, const uint8_t *der, size_t der_len) { return 1; } +static int test_compat(const uint8_t *der, size_t der_len) { + PKCS12 *p12; + X509 *cert = NULL; + STACK_OF(X509) *ca_certs = NULL; + EVP_PKEY *key; + BIO *bio; + + bio = BIO_new_mem_buf((void*) der, der_len); + + p12 = d2i_PKCS12_bio(bio, NULL); + if (p12 == NULL) { + fprintf(stderr, "PKCS12_parse failed.\n"); + BIO_print_errors_fp(stderr); + return 0; + } + BIO_free(bio); + + if (!PKCS12_parse(p12, "foo", &key, &cert, &ca_certs)) { + fprintf(stderr, "PKCS12_parse failed.\n"); + BIO_print_errors_fp(stderr); + return 0; + } + + if (key == NULL || cert == NULL) { + fprintf(stderr, "Bad result from PKCS12_parse.\n"); + return 0; + } + + EVP_PKEY_free(key); + X509_free(cert); + + if (sk_X509_num(ca_certs) != 0) { + fprintf(stderr, "Bad result from PKCS12_parse.\n"); + return 0; + } + sk_X509_free(ca_certs); + + PKCS12_free(p12); + + return 1; +} + int main(int argc, char **argv) { CRYPTO_library_init(); ERR_load_crypto_strings(); if (!test("OpenSSL", kOpenSSL, sizeof(kOpenSSL)) || !test("NSS", kNSS, sizeof(kNSS)) || - !test("Windows", kWindows, sizeof(kWindows))) { + !test("Windows", kWindows, sizeof(kWindows)) || + !test_compat(kWindows, sizeof(kWindows))) { return 1; } diff --git a/crypto/pkcs8/pkcs8.c b/crypto/pkcs8/pkcs8.c index 04fce98..58e400d 100644 --- a/crypto/pkcs8/pkcs8.c +++ b/crypto/pkcs8/pkcs8.c @@ -55,8 +55,12 @@ #include <openssl/pkcs8.h> +#include <assert.h> +#include <limits.h> + #include <openssl/asn1.h> #include <openssl/bn.h> +#include <openssl/buf.h> #include <openssl/cipher.h> #include <openssl/digest.h> #include <openssl/err.h> @@ -64,8 +68,6 @@ #include <openssl/mem.h> #include <openssl/x509.h> -#include <limits.h> - #include "../bytestring/internal.h" #include "../evp/internal.h" @@ -879,6 +881,7 @@ int PKCS12_get_key_and_certs(EVP_PKEY **out_key, STACK_OF(X509) *out_certs, /* See ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-12/pkcs-12v1.pdf, section * four. */ if (!CBS_get_asn1(&in, &pfx, CBS_ASN1_SEQUENCE) || + CBS_len(&in) != 0 || !CBS_get_asn1_uint64(&pfx, &version)) { OPENSSL_PUT_ERROR(PKCS8, PKCS12_parse, PKCS8_R_BAD_PKCS12_DATA); goto err; @@ -1015,3 +1018,137 @@ err: return ret; } + +void PKCS12_PBE_add(){}; + +struct pkcs12_st { + uint8_t *ber_bytes; + size_t ber_len; +}; + +PKCS12* d2i_PKCS12(PKCS12 **out_p12, const uint8_t **ber_bytes, size_t ber_len) { + PKCS12 *p12; + + /* out_p12 must be NULL because we don't export the PKCS12 structure. */ + assert(out_p12 == NULL); + + p12 = OPENSSL_malloc(sizeof(PKCS12)); + if (!p12) { + return NULL; + } + + p12->ber_bytes = OPENSSL_malloc(ber_len); + if (!p12->ber_bytes) { + OPENSSL_free(p12); + return NULL; + } + + memcpy(p12->ber_bytes, *ber_bytes, ber_len); + p12->ber_len = ber_len; + *ber_bytes += ber_len; + + return p12; +} + +PKCS12* d2i_PKCS12_bio(BIO *bio, PKCS12 **out_p12) { + size_t used = 0; + BUF_MEM *buf; + const uint8_t *dummy; + static const size_t kMaxSize = 256 * 1024; + PKCS12 *ret = NULL; + + buf = BUF_MEM_new(); + if (buf == NULL) { + return NULL; + } + if (BUF_MEM_grow(buf, 8192) == 0) { + goto out; + } + + for (;;) { + int n = BIO_read(bio, &buf->data[used], buf->length - used); + if (n < 0) { + goto out; + } + + if (n == 0) { + break; + } + used += n; + + if (used < buf->length) { + continue; + } + + if (buf->length > kMaxSize || + BUF_MEM_grow(buf, buf->length * 2) == 0) { + goto out; + } + } + + dummy = (uint8_t*) buf->data; + ret = d2i_PKCS12(out_p12, &dummy, used); + +out: + BUF_MEM_free(buf); + return ret; +} + +PKCS12* d2i_PKCS12_fp(FILE *fp, PKCS12 **out_p12) { + BIO *bio; + PKCS12 *ret; + + bio = BIO_new_fp(fp, 0 /* don't take ownership */); + if (!bio) { + return NULL; + } + + ret = d2i_PKCS12_bio(bio, out_p12); + BIO_free(bio); + return ret; +} + +int PKCS12_parse(const PKCS12 *p12, const char *password, EVP_PKEY **out_pkey, + X509 **out_cert, STACK_OF(X509) **out_ca_certs) { + CBS ber_bytes; + STACK_OF(X509) *ca_certs = NULL; + char ca_certs_alloced = 0; + + if (out_ca_certs != NULL && *out_ca_certs != NULL) { + ca_certs = *out_ca_certs; + } + + if (!ca_certs) { + ca_certs = sk_X509_new_null(); + if (ca_certs == NULL) { + return 0; + } + ca_certs_alloced = 1; + } + + CBS_init(&ber_bytes, p12->ber_bytes, p12->ber_len); + if (!PKCS12_get_key_and_certs(out_pkey, ca_certs, &ber_bytes, password)) { + if (ca_certs_alloced) { + sk_X509_free(ca_certs); + } + return 0; + } + + *out_cert = NULL; + if (sk_X509_num(ca_certs) > 0) { + *out_cert = sk_X509_shift(ca_certs); + } + + if (out_ca_certs) { + *out_ca_certs = ca_certs; + } else { + sk_X509_pop_free(ca_certs, X509_free); + } + + return 1; +} + +void PKCS12_free(PKCS12 *p12) { + OPENSSL_free(p12->ber_bytes); + OPENSSL_free(p12); +} diff --git a/include/openssl/base.h b/include/openssl/base.h index 079b1c4..52cb1e9 100644 --- a/include/openssl/base.h +++ b/include/openssl/base.h @@ -192,6 +192,7 @@ typedef struct hmac_ctx_st HMAC_CTX; typedef struct md4_state_st MD4_CTX; typedef struct md5_state_st MD5_CTX; typedef struct pkcs8_priv_key_info_st PKCS8_PRIV_KEY_INFO; +typedef struct pkcs12_st PKCS12; typedef struct rand_meth_st RAND_METHOD; typedef struct rsa_meth_st RSA_METHOD; typedef struct rsa_st RSA; diff --git a/include/openssl/bio.h b/include/openssl/bio.h index da0a356..547a36a 100644 --- a/include/openssl/bio.h +++ b/include/openssl/bio.h @@ -235,6 +235,10 @@ OPENSSL_EXPORT long BIO_callback_ctrl(BIO *bio, int cmd, bio_info_cb fp); /* BIO_pending returns the number of bytes pending to be read. */ OPENSSL_EXPORT size_t BIO_pending(const BIO *bio); +/* BIO_ctrl_pending calls |BIO_pending| and exists only for compatibility with + * OpenSSL. */ +OPENSSL_EXPORT size_t BIO_ctrl_pending(const BIO *bio); + /* BIO_wpending returns the number of bytes pending to be written. */ OPENSSL_EXPORT size_t BIO_wpending(const BIO *bio); diff --git a/include/openssl/digest.h b/include/openssl/digest.h index 291a548..6d8a165 100644 --- a/include/openssl/digest.h +++ b/include/openssl/digest.h @@ -200,6 +200,10 @@ OPENSSL_EXPORT size_t EVP_MD_block_size(const EVP_MD *md); * |in|. It returns one on success and zero on error. */ OPENSSL_EXPORT int EVP_MD_CTX_copy(EVP_MD_CTX *out, const EVP_MD_CTX *in); +/* EVP_add_digest does nothing and returns one. It exists only for + * compatibility with OpenSSL. */ +OPENSSL_EXPORT int EVP_add_digest(const EVP_MD *digest); + /* Digest operation accessors. */ diff --git a/include/openssl/dsa.h b/include/openssl/dsa.h index c8156fa..5e71ae2 100644 --- a/include/openssl/dsa.h +++ b/include/openssl/dsa.h @@ -291,6 +291,14 @@ OPENSSL_EXPORT int DSA_sign_setup(const DSA *dsa, BN_CTX *ctx, BIGNUM **out_kinv, BIGNUM **out_r); +/* Conversion. */ + +/* DSA_dup_DH returns a |DH| constructed from the parameters of |dsa|. This is + * sometimes needed when Diffie-Hellman parameters are stored in the form of + * DSA parameters. It returns an allocated |DH| on success or NULL on error. */ +OPENSSL_EXPORT DH *DSA_dup_DH(const DSA *dsa); + + /* ex_data functions. * * These functions are wrappers. See |ex_data.h| for details. */ diff --git a/include/openssl/pkcs8.h b/include/openssl/pkcs8.h index 6feb7f1..8735387 100644 --- a/include/openssl/pkcs8.h +++ b/include/openssl/pkcs8.h @@ -59,6 +59,8 @@ #include <openssl/base.h> +#include <stdio.h> + #include <openssl/x509.h> #if defined(__cplusplus) @@ -129,6 +131,43 @@ OPENSSL_EXPORT int PKCS12_get_key_and_certs(EVP_PKEY **out_key, STACK_OF(X509) *out_certs, CBS *in, const char *password); + +/* Deprecated functions. */ + +/* PKCS12_PBE_add does nothing. It exists for compatibility with OpenSSL. */ +OPENSSL_EXPORT void PKCS12_PBE_add(); + +/* d2i_PKCS12 is a dummy function that copies |*ber_bytes| into a + * |PKCS12| structure. The |out_p12| argument must be NULL. On exit, + * |*ber_bytes| will be advanced by |ber_len|. It returns a fresh |PKCS12| + * structure or NULL on error. + * + * Note: unlike other d2i functions, |d2i_PKCS12| will always consume |ber_len| + * bytes.*/ +OPENSSL_EXPORT PKCS12 *d2i_PKCS12(PKCS12 **out_p12, const uint8_t **ber_bytes, + size_t ber_len); + +/* d2i_PKCS12_bio acts like |d2i_PKCS12| but reads from a |BIO|. */ +OPENSSL_EXPORT PKCS12* d2i_PKCS12_bio(BIO *bio, PKCS12 **out_p12); + +/* d2i_PKCS12_fp acts like |d2i_PKCS12| but reads from a |FILE|. */ +OPENSSL_EXPORT PKCS12* d2i_PKCS12_fp(FILE *fp, PKCS12 **out_p12); + +/* PKCS12_parse calls |PKCS12_get_key_and_certs| on the ASN.1 data stored in + * |p12|. The |out_pkey| and |out_cert| arguments must not be NULL and, on + * successful exit, the private key and first certificate will be stored in + * them. The |out_ca_certs| argument may be NULL but, if not, then any extra + * certificates will be appended to |*out_ca_certs|. If |*out_ca_certs| is NULL + * then it will be set to a freshly allocated stack containing the extra certs. + * + * It returns one on success and zero on error. */ +OPENSSL_EXPORT int PKCS12_parse(const PKCS12 *p12, const char *password, + EVP_PKEY **out_pkey, X509 **out_cert, + STACK_OF(X509) **out_ca_certs); + +/* PKCS12_free frees |p12| and its contents. */ +OPENSSL_EXPORT void PKCS12_free(PKCS12 *p12); + #if defined(__cplusplus) } /* extern C */ #endif diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h index 3838511..48ad549 100644 --- a/include/openssl/ssl.h +++ b/include/openssl/ssl.h @@ -522,13 +522,13 @@ struct ssl_session_st #define SSL_OP_NO_SSL_MASK (SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|\ SSL_OP_NO_TLSv1|SSL_OP_NO_TLSv1_1|SSL_OP_NO_TLSv1_2) -/* These next two were never actually used for anything since SSLeay - * zap so we have some more flags. - */ -/* The next flag deliberately changes the ciphertest, this is a check - * for the PKCS#1 attack */ -#define SSL_OP_PKCS1_CHECK_1 0x0 -#define SSL_OP_PKCS1_CHECK_2 0x0 +/* The following flags do nothing and are included only to make it easier to + * compile code with BoringSSL. */ +#define SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS 0 +#define SSL_OP_MICROSOFT_SESS_ID_BUG 0 +#define SSL_OP_NETSCAPE_CHALLENGE_BUG 0 +#define SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG 0 +#define SSL_OP_TLS_BLOCK_PADDING_BUG 0 /* Allow SSL_write(..., n) to return r with 0 < r < n (i.e. report success * when just a single record has been written): */ @@ -783,7 +783,7 @@ DECLARE_LHASH_OF(SSL_SESSION); struct ssl_cipher_preference_list_st { STACK_OF(SSL_CIPHER) *ciphers; - unsigned char *in_group_flags; + uint8_t *in_group_flags; }; struct ssl_ctx_st @@ -2790,6 +2790,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_SSLV3_ALERT_CLOSE_NOTIFY 1000 #define SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE 1010 #define SSL_R_SSLV3_ALERT_BAD_RECORD_MAC 1020 #define SSL_R_TLSV1_ALERT_DECRYPTION_FAILED 1021 @@ -2811,6 +2812,7 @@ OPENSSL_EXPORT void ERR_load_SSL_strings(void); #define SSL_R_TLSV1_ALERT_PROTOCOL_VERSION 1070 #define SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY 1071 #define SSL_R_TLSV1_ALERT_INTERNAL_ERROR 1080 +#define SSL_R_TLSV1_ALERT_INAPPROPRIATE_FALLBACK 1086 #define SSL_R_TLSV1_ALERT_USER_CANCELLED 1090 #define SSL_R_TLSV1_ALERT_NO_RENEGOTIATION 1100 #define SSL_R_TLSV1_UNSUPPORTED_EXTENSION 1110 diff --git a/ssl/CMakeLists.txt b/ssl/CMakeLists.txt index 3db8607..49f7c3d 100644 --- a/ssl/CMakeLists.txt +++ b/ssl/CMakeLists.txt @@ -53,4 +53,4 @@ add_executable( ssl_test.c ) -target_link_libraries(ssl_test crypto) +target_link_libraries(ssl_test ssl crypto) diff --git a/ssl/s23_clnt.c b/ssl/s23_clnt.c index cec6f8c..ccb3e2c 100644 --- a/ssl/s23_clnt.c +++ b/ssl/s23_clnt.c @@ -121,16 +121,13 @@ static int ssl23_client_hello(SSL *s); static int ssl23_get_server_hello(SSL *s); static const SSL_METHOD *ssl23_get_client_method(int ver) { - if (ver == SSL3_VERSION) - return(SSLv3_client_method()); - else if (ver == TLS1_VERSION) - return(TLSv1_client_method()); - else if (ver == TLS1_1_VERSION) - return(TLSv1_1_client_method()); - else if (ver == TLS1_2_VERSION) - return(TLSv1_2_client_method()); - else - return(NULL); + /* When SSL_set_session is called, do NOT switch to the version-specific + * method table. The server may still negotiate a different version when + * rejecting the session. + * + * TODO(davidben): Clean this up. This duplicates logic from the + * version-specific tables. https://crbug.com/403378 */ + return SSLv23_client_method(); } IMPLEMENT_ssl23_meth_func(SSLv23_client_method, @@ -167,12 +164,6 @@ int ssl23_connect(SSL *s) case SSL_ST_BEFORE|SSL_ST_CONNECT: case SSL_ST_OK|SSL_ST_CONNECT: - if (s->session != NULL) - { - OPENSSL_PUT_ERROR(SSL, ssl23_connect, SSL_R_SSL23_DOING_SESSION_ID_REUSE); - ret= -1; - goto end; - } s->server=0; if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_START,1); @@ -288,17 +279,10 @@ static int ssl23_client_hello(SSL *s) * TLS1>=1, it would be insufficient to pass SSL_NO_TLSv1, the * answer is SSL_OP_NO_TLSv1|SSL_OP_NO_SSLv3|SSL_OP_NO_SSLv2. */ - mask = SSL_OP_NO_TLSv1_1|SSL_OP_NO_TLSv1 - |SSL_OP_NO_SSLv3 - ; -#if !defined(OPENSSL_NO_TLS1_2_CLIENT) + mask = SSL_OP_NO_TLSv1_1|SSL_OP_NO_TLSv1|SSL_OP_NO_SSLv3; version = TLS1_2_VERSION; - if ((options & SSL_OP_NO_TLSv1_2) && (options & mask) != mask) version = TLS1_1_VERSION; -#else - version = TLS1_1_VERSION; -#endif mask &= ~SSL_OP_NO_TLSv1_1; if ((options & SSL_OP_NO_TLSv1_1) && (options & mask) != mask) version = TLS1_VERSION; @@ -310,13 +294,17 @@ static int ssl23_client_hello(SSL *s) buf=(unsigned char *)s->init_buf->data; if (s->state == SSL23_ST_CW_CLNT_HELLO_A) { -#if 0 - /* don't reuse session-id's */ - if (!ssl_get_new_session(s,0)) + /* Check if the session is resumable. If not, drop it. */ + if (s->session != NULL) { - return(-1); + if (s->session->ssl_version > version || + s->session->session_id_length == 0 || + s->session->not_resumable) + { + SSL_SESSION_free(s->session); + s->session = NULL; + } } -#endif p=s->s3->client_random; if (ssl_fill_hello_random(s, 0, p, SSL3_RANDOM_SIZE) <= 0) @@ -370,8 +358,22 @@ static int ssl23_client_hello(SSL *s) memcpy(p, s->s3->client_random, SSL3_RANDOM_SIZE); p += SSL3_RANDOM_SIZE; - /* Session ID (zero since there is no reuse) */ - *(p++) = 0; + /* Session ID */ + if (s->new_session || s->session == NULL) + i=0; + else + i=s->session->session_id_length; + *(p++)=i; + if (i != 0) + { + if (i > (int)sizeof(s->session->session_id)) + { + OPENSSL_PUT_ERROR(SSL, ssl23_client_hello, ERR_R_INTERNAL_ERROR); + return -1; + } + memcpy(p,s->session->session_id,i); + p+=i; + } /* Ciphers supported (using SSL 3.0/TLS 1.0 format) */ i = ssl_cipher_list_to_bytes(s, SSL_get_ciphers(s), &p[2]); @@ -568,9 +570,9 @@ static int ssl23_get_server_hello(SSL *s) } s->init_num=0; - /* Since, if we are sending a ssl23 client hello, we are not - * reusing a session-id */ - if (!ssl_get_new_session(s,0)) + /* If there was no session to resume, now that the final version is + * determined, insert a fresh one. */ + if (s->session == NULL && !ssl_get_new_session(s,0)) goto err; return(SSL_connect(s)); diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c index 479b6de..5a1b48d 100644 --- a/ssl/s3_lib.c +++ b/ssl/s3_lib.c @@ -178,7 +178,7 @@ const SSL_CIPHER ssl3_ciphers[]={ SSL_RC4, SSL_MD5, SSL_SSLV3, - SSL_NOT_EXP|SSL_MEDIUM, + SSL_MEDIUM, SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF|SSL_CIPHER_ALGORITHM2_STATEFUL_AEAD, 128, 128, @@ -194,7 +194,7 @@ const SSL_CIPHER ssl3_ciphers[]={ SSL_RC4, SSL_SHA1, SSL_SSLV3, - SSL_NOT_EXP|SSL_MEDIUM, + SSL_MEDIUM, SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, 128, 128, @@ -210,7 +210,7 @@ const SSL_CIPHER ssl3_ciphers[]={ SSL_3DES, SSL_SHA1, SSL_SSLV3, - SSL_NOT_EXP|SSL_HIGH|SSL_FIPS, + SSL_HIGH|SSL_FIPS, SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, 112, 168, @@ -228,7 +228,7 @@ const SSL_CIPHER ssl3_ciphers[]={ SSL_RC4, SSL_MD5, SSL_SSLV3, - SSL_NOT_EXP|SSL_MEDIUM, + SSL_MEDIUM, SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, 128, 128, @@ -245,7 +245,7 @@ const SSL_CIPHER ssl3_ciphers[]={ SSL_AES128, SSL_SHA1, SSL_TLSV1, - SSL_NOT_EXP|SSL_HIGH|SSL_FIPS, + SSL_HIGH|SSL_FIPS, SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, 128, 128, @@ -260,7 +260,7 @@ const SSL_CIPHER ssl3_ciphers[]={ SSL_AES128, SSL_SHA1, SSL_TLSV1, - SSL_NOT_EXP|SSL_HIGH|SSL_FIPS, + SSL_HIGH|SSL_FIPS, SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, 128, 128, @@ -275,7 +275,7 @@ const SSL_CIPHER ssl3_ciphers[]={ SSL_AES128, SSL_SHA1, SSL_TLSV1, - SSL_NOT_EXP|SSL_HIGH|SSL_FIPS, + SSL_HIGH|SSL_FIPS, SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, 128, 128, @@ -291,7 +291,7 @@ const SSL_CIPHER ssl3_ciphers[]={ SSL_AES256, SSL_SHA1, SSL_TLSV1, - SSL_NOT_EXP|SSL_HIGH|SSL_FIPS, + SSL_HIGH|SSL_FIPS, SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, 256, 256, @@ -307,7 +307,7 @@ const SSL_CIPHER ssl3_ciphers[]={ SSL_AES256, SSL_SHA1, SSL_TLSV1, - SSL_NOT_EXP|SSL_HIGH|SSL_FIPS, + SSL_HIGH|SSL_FIPS, SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, 256, 256, @@ -323,7 +323,7 @@ const SSL_CIPHER ssl3_ciphers[]={ SSL_AES256, SSL_SHA1, SSL_TLSV1, - SSL_NOT_EXP|SSL_HIGH|SSL_FIPS, + SSL_HIGH|SSL_FIPS, SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, 256, 256, @@ -340,7 +340,7 @@ const SSL_CIPHER ssl3_ciphers[]={ SSL_AES128, SSL_SHA256, SSL_TLSV1_2, - SSL_NOT_EXP|SSL_HIGH|SSL_FIPS, + SSL_HIGH|SSL_FIPS, SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, 128, 128, @@ -356,7 +356,7 @@ const SSL_CIPHER ssl3_ciphers[]={ SSL_AES256, SSL_SHA256, SSL_TLSV1_2, - SSL_NOT_EXP|SSL_HIGH|SSL_FIPS, + SSL_HIGH|SSL_FIPS, SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, 256, 256, @@ -374,7 +374,7 @@ const SSL_CIPHER ssl3_ciphers[]={ SSL_AES128, SSL_SHA256, SSL_TLSV1_2, - SSL_NOT_EXP|SSL_HIGH|SSL_FIPS, + SSL_HIGH|SSL_FIPS, SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, 128, 128, @@ -390,7 +390,7 @@ const SSL_CIPHER ssl3_ciphers[]={ SSL_AES256, SSL_SHA256, SSL_TLSV1_2, - SSL_NOT_EXP|SSL_HIGH|SSL_FIPS, + SSL_HIGH|SSL_FIPS, SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, 256, 256, @@ -406,7 +406,7 @@ const SSL_CIPHER ssl3_ciphers[]={ SSL_AES128, SSL_SHA256, SSL_TLSV1_2, - SSL_NOT_EXP|SSL_HIGH|SSL_FIPS, + SSL_HIGH|SSL_FIPS, SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, 128, 128, @@ -422,7 +422,7 @@ const SSL_CIPHER ssl3_ciphers[]={ SSL_AES256, SSL_SHA256, SSL_TLSV1_2, - SSL_NOT_EXP|SSL_HIGH|SSL_FIPS, + SSL_HIGH|SSL_FIPS, SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, 256, 256, @@ -439,7 +439,7 @@ const SSL_CIPHER ssl3_ciphers[]={ SSL_RC4, SSL_SHA1, SSL_TLSV1, - SSL_NOT_EXP|SSL_MEDIUM, + SSL_MEDIUM, SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, 128, 128, @@ -455,7 +455,7 @@ const SSL_CIPHER ssl3_ciphers[]={ SSL_AES128, SSL_SHA1, SSL_TLSV1, - SSL_NOT_EXP|SSL_HIGH|SSL_FIPS, + SSL_HIGH|SSL_FIPS, SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, 128, 128, @@ -471,7 +471,7 @@ const SSL_CIPHER ssl3_ciphers[]={ SSL_AES256, SSL_SHA1, SSL_TLSV1, - SSL_NOT_EXP|SSL_HIGH|SSL_FIPS, + SSL_HIGH|SSL_FIPS, SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, 256, 256, @@ -489,7 +489,7 @@ const SSL_CIPHER ssl3_ciphers[]={ SSL_AES128GCM, SSL_AEAD, SSL_TLSV1_2, - SSL_NOT_EXP|SSL_HIGH|SSL_FIPS, + SSL_HIGH|SSL_FIPS, SSL_HANDSHAKE_MAC_SHA256|TLS1_PRF_SHA256|SSL_CIPHER_ALGORITHM2_AEAD|FIXED_NONCE_LEN(4)|SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD, 128, 128, @@ -505,7 +505,7 @@ const SSL_CIPHER ssl3_ciphers[]={ SSL_AES256GCM, SSL_AEAD, SSL_TLSV1_2, - SSL_NOT_EXP|SSL_HIGH|SSL_FIPS, + SSL_HIGH|SSL_FIPS, SSL_HANDSHAKE_MAC_SHA384|TLS1_PRF_SHA384|SSL_CIPHER_ALGORITHM2_AEAD|FIXED_NONCE_LEN(4)| SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD, 256, @@ -522,7 +522,7 @@ const SSL_CIPHER ssl3_ciphers[]={ SSL_AES128GCM, SSL_AEAD, SSL_TLSV1_2, - SSL_NOT_EXP|SSL_HIGH|SSL_FIPS, + SSL_HIGH|SSL_FIPS, SSL_HANDSHAKE_MAC_SHA256|TLS1_PRF_SHA256|SSL_CIPHER_ALGORITHM2_AEAD|FIXED_NONCE_LEN(4)|SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD, 128, 128, @@ -538,7 +538,7 @@ const SSL_CIPHER ssl3_ciphers[]={ SSL_AES256GCM, SSL_AEAD, SSL_TLSV1_2, - SSL_NOT_EXP|SSL_HIGH|SSL_FIPS, + SSL_HIGH|SSL_FIPS, SSL_HANDSHAKE_MAC_SHA384|TLS1_PRF_SHA384|SSL_CIPHER_ALGORITHM2_AEAD|FIXED_NONCE_LEN(4)| SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD, 256, @@ -555,7 +555,7 @@ const SSL_CIPHER ssl3_ciphers[]={ SSL_AES128GCM, SSL_AEAD, SSL_TLSV1_2, - SSL_NOT_EXP|SSL_HIGH|SSL_FIPS, + SSL_HIGH|SSL_FIPS, SSL_HANDSHAKE_MAC_SHA256|TLS1_PRF_SHA256|SSL_CIPHER_ALGORITHM2_AEAD|FIXED_NONCE_LEN(4)|SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD, 128, 128, @@ -571,7 +571,7 @@ const SSL_CIPHER ssl3_ciphers[]={ SSL_AES256GCM, SSL_AEAD, SSL_TLSV1_2, - SSL_NOT_EXP|SSL_HIGH|SSL_FIPS, + SSL_HIGH|SSL_FIPS, SSL_HANDSHAKE_MAC_SHA384|TLS1_PRF_SHA384|SSL_CIPHER_ALGORITHM2_AEAD|FIXED_NONCE_LEN(4)| SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD, 256, @@ -588,7 +588,7 @@ const SSL_CIPHER ssl3_ciphers[]={ SSL_RC4, SSL_SHA1, SSL_TLSV1, - SSL_NOT_EXP|SSL_MEDIUM, + SSL_MEDIUM, SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, 128, 128, @@ -604,7 +604,7 @@ const SSL_CIPHER ssl3_ciphers[]={ SSL_AES128, SSL_SHA1, SSL_TLSV1, - SSL_NOT_EXP|SSL_HIGH|SSL_FIPS, + SSL_HIGH|SSL_FIPS, SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, 128, 128, @@ -620,7 +620,7 @@ const SSL_CIPHER ssl3_ciphers[]={ SSL_AES256, SSL_SHA1, SSL_TLSV1, - SSL_NOT_EXP|SSL_HIGH|SSL_FIPS, + SSL_HIGH|SSL_FIPS, SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, 256, 256, @@ -636,7 +636,7 @@ const SSL_CIPHER ssl3_ciphers[]={ SSL_RC4, SSL_SHA1, SSL_TLSV1, - SSL_NOT_EXP|SSL_MEDIUM, + SSL_MEDIUM, SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, 128, 128, @@ -652,7 +652,7 @@ const SSL_CIPHER ssl3_ciphers[]={ SSL_AES128, SSL_SHA1, SSL_TLSV1, - SSL_NOT_EXP|SSL_HIGH|SSL_FIPS, + SSL_HIGH|SSL_FIPS, SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, 128, 128, @@ -668,7 +668,7 @@ const SSL_CIPHER ssl3_ciphers[]={ SSL_AES256, SSL_SHA1, SSL_TLSV1, - SSL_NOT_EXP|SSL_HIGH|SSL_FIPS, + SSL_HIGH|SSL_FIPS, SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, 256, 256, @@ -684,7 +684,7 @@ const SSL_CIPHER ssl3_ciphers[]={ SSL_RC4, SSL_SHA1, SSL_TLSV1, - SSL_NOT_EXP|SSL_MEDIUM, + SSL_MEDIUM, SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, 128, 128, @@ -700,7 +700,7 @@ const SSL_CIPHER ssl3_ciphers[]={ SSL_AES128, SSL_SHA1, SSL_TLSV1, - SSL_NOT_EXP|SSL_HIGH|SSL_FIPS, + SSL_HIGH|SSL_FIPS, SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, 128, 128, @@ -716,7 +716,7 @@ const SSL_CIPHER ssl3_ciphers[]={ SSL_AES256, SSL_SHA1, SSL_TLSV1, - SSL_NOT_EXP|SSL_HIGH|SSL_FIPS, + SSL_HIGH|SSL_FIPS, SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, 256, 256, @@ -735,7 +735,7 @@ const SSL_CIPHER ssl3_ciphers[]={ SSL_AES128, SSL_SHA256, SSL_TLSV1_2, - SSL_NOT_EXP|SSL_HIGH|SSL_FIPS, + SSL_HIGH|SSL_FIPS, SSL_HANDSHAKE_MAC_SHA256|TLS1_PRF_SHA256, 128, 128, @@ -751,7 +751,7 @@ const SSL_CIPHER ssl3_ciphers[]={ SSL_AES256, SSL_SHA384, SSL_TLSV1_2, - SSL_NOT_EXP|SSL_HIGH|SSL_FIPS, + SSL_HIGH|SSL_FIPS, SSL_HANDSHAKE_MAC_SHA384|TLS1_PRF_SHA384, 256, 256, @@ -767,7 +767,7 @@ const SSL_CIPHER ssl3_ciphers[]={ SSL_AES128, SSL_SHA256, SSL_TLSV1_2, - SSL_NOT_EXP|SSL_HIGH|SSL_FIPS, + SSL_HIGH|SSL_FIPS, SSL_HANDSHAKE_MAC_SHA256|TLS1_PRF_SHA256, 128, 128, @@ -783,7 +783,7 @@ const SSL_CIPHER ssl3_ciphers[]={ SSL_AES256, SSL_SHA384, SSL_TLSV1_2, - SSL_NOT_EXP|SSL_HIGH|SSL_FIPS, + SSL_HIGH|SSL_FIPS, SSL_HANDSHAKE_MAC_SHA384|TLS1_PRF_SHA384, 256, 256, @@ -801,7 +801,7 @@ const SSL_CIPHER ssl3_ciphers[]={ SSL_AES128GCM, SSL_AEAD, SSL_TLSV1_2, - SSL_NOT_EXP|SSL_HIGH|SSL_FIPS, + SSL_HIGH|SSL_FIPS, SSL_HANDSHAKE_MAC_SHA256|TLS1_PRF_SHA256|SSL_CIPHER_ALGORITHM2_AEAD|FIXED_NONCE_LEN(4)|SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD, 128, 128, @@ -817,7 +817,7 @@ const SSL_CIPHER ssl3_ciphers[]={ SSL_AES256GCM, SSL_AEAD, SSL_TLSV1_2, - SSL_NOT_EXP|SSL_HIGH|SSL_FIPS, + SSL_HIGH|SSL_FIPS, SSL_HANDSHAKE_MAC_SHA384|TLS1_PRF_SHA384|SSL_CIPHER_ALGORITHM2_AEAD|FIXED_NONCE_LEN(4)| SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD, 256, @@ -834,7 +834,7 @@ const SSL_CIPHER ssl3_ciphers[]={ SSL_AES128GCM, SSL_AEAD, SSL_TLSV1_2, - SSL_NOT_EXP|SSL_HIGH|SSL_FIPS, + SSL_HIGH|SSL_FIPS, SSL_HANDSHAKE_MAC_SHA256|TLS1_PRF_SHA256|SSL_CIPHER_ALGORITHM2_AEAD|FIXED_NONCE_LEN(4)|SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD, 128, 128, @@ -850,7 +850,7 @@ const SSL_CIPHER ssl3_ciphers[]={ SSL_AES256GCM, SSL_AEAD, SSL_TLSV1_2, - SSL_NOT_EXP|SSL_HIGH|SSL_FIPS, + SSL_HIGH|SSL_FIPS, SSL_HANDSHAKE_MAC_SHA384|TLS1_PRF_SHA384|SSL_CIPHER_ALGORITHM2_AEAD|FIXED_NONCE_LEN(4)| SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD, 256, @@ -868,7 +868,7 @@ const SSL_CIPHER ssl3_ciphers[]={ SSL_AES128GCM, SSL_AEAD, SSL_TLSV1_2, - SSL_NOT_EXP|SSL_HIGH, + SSL_HIGH, SSL_HANDSHAKE_MAC_SHA256|TLS1_PRF_SHA256|SSL_CIPHER_ALGORITHM2_AEAD|FIXED_NONCE_LEN(4)| SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD, 128, @@ -885,7 +885,7 @@ const SSL_CIPHER ssl3_ciphers[]={ SSL_CHACHA20POLY1305, SSL_AEAD, SSL_TLSV1_2, - SSL_NOT_EXP|SSL_HIGH, + SSL_HIGH, SSL_HANDSHAKE_MAC_SHA256|TLS1_PRF_SHA256|SSL_CIPHER_ALGORITHM2_AEAD|FIXED_NONCE_LEN(0), 256, 0, @@ -900,7 +900,7 @@ const SSL_CIPHER ssl3_ciphers[]={ SSL_CHACHA20POLY1305, SSL_AEAD, SSL_TLSV1_2, - SSL_NOT_EXP|SSL_HIGH, + SSL_HIGH, SSL_HANDSHAKE_MAC_SHA256|TLS1_PRF_SHA256|SSL_CIPHER_ALGORITHM2_AEAD|FIXED_NONCE_LEN(0), 256, 0, @@ -915,7 +915,7 @@ const SSL_CIPHER ssl3_ciphers[]={ SSL_CHACHA20POLY1305, SSL_AEAD, SSL_TLSV1_2, - SSL_NOT_EXP|SSL_HIGH, + SSL_HIGH, SSL_HANDSHAKE_MAC_SHA256|TLS1_PRF_SHA256|SSL_CIPHER_ALGORITHM2_AEAD|FIXED_NONCE_LEN(0), 256, 0, diff --git a/ssl/ssl_algs.c b/ssl/ssl_algs.c index 9308d40..a1aa7b2 100644 --- a/ssl/ssl_algs.c +++ b/ssl/ssl_algs.c @@ -63,9 +63,7 @@ extern const ERR_STRING_DATA SSL_error_string_data[]; int SSL_library_init(void) { CRYPTO_library_init(); - ERR_load_crypto_strings(); - ERR_load_strings(SSL_error_string_data); - ssl_load_ciphers(); + SSL_load_error_strings(); return(1); } diff --git a/ssl/ssl_ciph.c b/ssl/ssl_ciph.c index 8361007..fbed548 100644 --- a/ssl/ssl_ciph.c +++ b/ssl/ssl_ciph.c @@ -147,34 +147,18 @@ #include "ssl_locl.h" -#define SSL_ENC_3DES_IDX 0 -#define SSL_ENC_RC4_IDX 1 -#define SSL_ENC_AES128_IDX 2 -#define SSL_ENC_AES256_IDX 3 -#define SSL_ENC_NUM_IDX 4 - - -static const EVP_CIPHER *ssl_cipher_methods[SSL_ENC_NUM_IDX]= { 0 }; - -#define SSL_MD_MD5_IDX 0 -#define SSL_MD_SHA1_IDX 1 -#define SSL_MD_SHA256_IDX 2 -#define SSL_MD_SHA384_IDX 3 -/*Constant SSL_MAX_DIGEST equal to size of digests array should be - * defined in the - * ssl_locl.h */ -#define SSL_MD_NUM_IDX SSL_MAX_DIGEST -static const EVP_MD *ssl_digest_methods[SSL_MD_NUM_IDX] = { 0 }; -static const int ssl_mac_pkey_id[SSL_MD_NUM_IDX]={ - EVP_PKEY_HMAC, EVP_PKEY_HMAC, EVP_PKEY_HMAC, EVP_PKEY_HMAC, +struct handshake_digest + { + long mask; + const EVP_MD *(*md_func)(void); }; -static int ssl_mac_secret_size[SSL_MD_NUM_IDX] = { 0 }; - -static const int ssl_handshake_digest_flag[SSL_MD_NUM_IDX]={ - SSL_HANDSHAKE_MAC_MD5, SSL_HANDSHAKE_MAC_SHA, - SSL_HANDSHAKE_MAC_SHA256, SSL_HANDSHAKE_MAC_SHA384, - }; +static const struct handshake_digest ssl_handshake_digests[SSL_MAX_DIGEST] = { + { SSL_HANDSHAKE_MAC_MD5, EVP_md5 }, + { SSL_HANDSHAKE_MAC_SHA, EVP_sha1 }, + { SSL_HANDSHAKE_MAC_SHA256, EVP_sha256 }, + { SSL_HANDSHAKE_MAC_SHA384, EVP_sha384 }, +}; #define CIPHER_ADD 1 #define CIPHER_KILL 2 @@ -255,26 +239,6 @@ static const SSL_CIPHER cipher_aliases[]={ {0,SSL_TXT_FIPS,0, 0,0,0,0,0,SSL_FIPS, 0,0,0}, }; -void ssl_load_ciphers(void) - { - ssl_cipher_methods[SSL_ENC_3DES_IDX]= EVP_des_ede3_cbc(); - ssl_cipher_methods[SSL_ENC_RC4_IDX]= EVP_rc4(); - ssl_cipher_methods[SSL_ENC_AES128_IDX]= EVP_aes_128_cbc(); - ssl_cipher_methods[SSL_ENC_AES256_IDX]= EVP_aes_256_cbc(); - - ssl_digest_methods[SSL_MD_MD5_IDX]= EVP_md5(); - ssl_mac_secret_size[SSL_MD_MD5_IDX]= EVP_MD_size(EVP_md5()); - assert(ssl_mac_secret_size[SSL_MD_MD5_IDX] >= 0); - ssl_digest_methods[SSL_MD_SHA1_IDX]=EVP_sha1(); - ssl_mac_secret_size[SSL_MD_SHA1_IDX]= EVP_MD_size(EVP_sha1()); - assert(ssl_mac_secret_size[SSL_MD_SHA1_IDX] >= 0); - - ssl_digest_methods[SSL_MD_SHA256_IDX]= EVP_sha256(); - ssl_mac_secret_size[SSL_MD_SHA256_IDX]= EVP_MD_size(EVP_sha256()); - ssl_digest_methods[SSL_MD_SHA384_IDX]= EVP_sha384(); - ssl_mac_secret_size[SSL_MD_SHA384_IDX]= EVP_MD_size(EVP_sha384()); - } - /* ssl_cipher_get_evp_aead sets |*aead| to point to the correct EVP_AEAD object * for |s->cipher|. It returns 1 on success and 0 on error. */ int ssl_cipher_get_evp_aead(const SSL_SESSION *s, const EVP_AEAD **aead) @@ -314,7 +278,6 @@ int ssl_cipher_get_evp_aead(const SSL_SESSION *s, const EVP_AEAD **aead) int ssl_cipher_get_evp(const SSL_SESSION *s, const EVP_CIPHER **enc, const EVP_MD **md, int *mac_pkey_type, int *mac_secret_size) { - int i; const SSL_CIPHER *c; c=s->cipher; @@ -330,39 +293,32 @@ int ssl_cipher_get_evp(const SSL_SESSION *s, const EVP_CIPHER **enc, switch (c->algorithm_enc) { case SSL_3DES: - i=SSL_ENC_3DES_IDX; + *enc = EVP_des_ede3_cbc(); break; case SSL_RC4: - i=SSL_ENC_RC4_IDX; + *enc = EVP_rc4(); break; case SSL_AES128: - i=SSL_ENC_AES128_IDX; + *enc = EVP_aes_128_cbc(); break; case SSL_AES256: - i=SSL_ENC_AES256_IDX; + *enc = EVP_aes_256_cbc(); break; default: - i= -1; - break; + return 0; } - if ((i < 0) || (i >= SSL_ENC_NUM_IDX)) - *enc=NULL; - else - *enc=ssl_cipher_methods[i]; - if (!ssl_cipher_get_mac(s, md, mac_pkey_type, mac_secret_size)) return 0; - if ((*enc != NULL) && (*md != NULL) && - (!mac_pkey_type||*mac_pkey_type != NID_undef)) - { + assert(*enc != NULL && *md != NULL); + + /* TODO(fork): enable the stitched cipher modes. */ +#if 0 if (s->ssl_version>>8 != TLS1_VERSION_MAJOR || s->ssl_version < TLS1_VERSION) return 1; - /* TODO(fork): enable the stitched cipher modes. */ -#if 0 if (c->algorithm_enc == SSL_RC4 && c->algorithm_mac == SSL_MD5 && (evp=EVP_get_cipherbyname("RC4-HMAC-MD5"))) @@ -376,15 +332,12 @@ int ssl_cipher_get_evp(const SSL_SESSION *s, const EVP_CIPHER **enc, (evp=EVP_get_cipherbyname("AES-256-CBC-HMAC-SHA1"))) *enc = evp, *md = NULL; #endif - return(1); - } - else - return(0); + + return 1; } int ssl_cipher_get_mac(const SSL_SESSION *s, const EVP_MD **md, int *mac_pkey_type, int *mac_secret_size) { - int i; const SSL_CIPHER *c; c=s->cipher; @@ -393,49 +346,40 @@ int ssl_cipher_get_mac(const SSL_SESSION *s, const EVP_MD **md, int *mac_pkey_ty switch (c->algorithm_mac) { case SSL_MD5: - i=SSL_MD_MD5_IDX; + *md = EVP_md5(); break; case SSL_SHA1: - i=SSL_MD_SHA1_IDX; + *md = EVP_sha1(); break; case SSL_SHA256: - i=SSL_MD_SHA256_IDX; + *md = EVP_sha256(); break; case SSL_SHA384: - i=SSL_MD_SHA384_IDX; + *md = EVP_sha384(); break; default: - i= -1; - break; + return 0; } - if ((i < 0) || (i >= SSL_MD_NUM_IDX)) + if (mac_pkey_type != NULL) { - *md=NULL; - if (mac_pkey_type!=NULL) *mac_pkey_type = NID_undef; - if (mac_secret_size!=NULL) *mac_secret_size = 0; + *mac_pkey_type = EVP_PKEY_HMAC; } - else + if (mac_secret_size!=NULL) { - *md=ssl_digest_methods[i]; - if (mac_pkey_type!=NULL) *mac_pkey_type = ssl_mac_pkey_id[i]; - if (mac_secret_size!=NULL) *mac_secret_size = ssl_mac_secret_size[i]; + *mac_secret_size = EVP_MD_size(*md); } - return 1; } int ssl_get_handshake_digest(int idx, long *mask, const EVP_MD **md) { - if (idx <0||idx>=SSL_MD_NUM_IDX) + if (idx < 0 || idx >= SSL_MAX_DIGEST) { return 0; } - *mask = ssl_handshake_digest_flag[idx]; - if (*mask) - *md = ssl_digest_methods[idx]; - else - *md = NULL; + *mask = ssl_handshake_digests[idx].mask; + *md = ssl_handshake_digests[idx].md_func(); return 1; } @@ -474,31 +418,8 @@ static void ll_append_head(CIPHER_ORDER **head, CIPHER_ORDER *curr, *head=curr; } -static void ssl_cipher_get_disabled(unsigned long *mkey, unsigned long *auth, unsigned long *enc, unsigned long *mac, unsigned long *ssl) - { - *mkey = 0; - *auth = 0; - *enc = 0; - *mac = 0; - *ssl = 0; - - *enc |= (ssl_cipher_methods[SSL_ENC_3DES_IDX] == NULL) ? SSL_3DES:0; - *enc |= (ssl_cipher_methods[SSL_ENC_RC4_IDX ] == NULL) ? SSL_RC4 :0; - *enc |= (ssl_cipher_methods[SSL_ENC_AES128_IDX] == NULL) ? SSL_AES128:0; - *enc |= (ssl_cipher_methods[SSL_ENC_AES256_IDX] == NULL) ? SSL_AES256:0; - - *mac |= (ssl_digest_methods[SSL_MD_MD5_IDX ] == NULL) ? SSL_MD5 :0; - *mac |= (ssl_digest_methods[SSL_MD_SHA1_IDX] == NULL) ? SSL_SHA1:0; - *mac |= (ssl_digest_methods[SSL_MD_SHA256_IDX] == NULL) ? SSL_SHA256:0; - *mac |= (ssl_digest_methods[SSL_MD_SHA384_IDX] == NULL) ? SSL_SHA384:0; - - } - static void ssl_cipher_collect_ciphers(const SSL_METHOD *ssl_method, int num_of_ciphers, - unsigned long disabled_mkey, unsigned long disabled_auth, - unsigned long disabled_enc, unsigned long disabled_mac, - unsigned long disabled_ssl, CIPHER_ORDER *co_list, CIPHER_ORDER **head_p, CIPHER_ORDER **tail_p) { @@ -518,12 +439,7 @@ static void ssl_cipher_collect_ciphers(const SSL_METHOD *ssl_method, { c = ssl_method->get_cipher(i); /* drop those that use any of that is not available */ - if ((c != NULL) && c->valid && - !(c->algorithm_mkey & disabled_mkey) && - !(c->algorithm_auth & disabled_auth) && - !(c->algorithm_enc & disabled_enc) && - !(c->algorithm_mac & disabled_mac) && - !(c->algorithm_ssl & disabled_ssl)) + if ((c != NULL) && c->valid) { co_list[co_list_num].cipher = c; co_list[co_list_num].next = NULL; @@ -569,19 +485,11 @@ static void ssl_cipher_collect_ciphers(const SSL_METHOD *ssl_method, static void ssl_cipher_collect_aliases(const SSL_CIPHER **ca_list, int num_of_group_aliases, - unsigned long disabled_mkey, unsigned long disabled_auth, - unsigned long disabled_enc, unsigned long disabled_mac, - unsigned long disabled_ssl, CIPHER_ORDER *head) { CIPHER_ORDER *ciph_curr; const SSL_CIPHER **ca_curr; int i; - unsigned long mask_mkey = ~disabled_mkey; - unsigned long mask_auth = ~disabled_auth; - unsigned long mask_enc = ~disabled_enc; - unsigned long mask_mac = ~disabled_mac; - unsigned long mask_ssl = ~disabled_ssl; /* * First, add the real ciphers as already collected @@ -603,32 +511,6 @@ static void ssl_cipher_collect_aliases(const SSL_CIPHER **ca_list, */ for (i = 0; i < num_of_group_aliases; i++) { - unsigned long algorithm_mkey = cipher_aliases[i].algorithm_mkey; - unsigned long algorithm_auth = cipher_aliases[i].algorithm_auth; - unsigned long algorithm_enc = cipher_aliases[i].algorithm_enc; - unsigned long algorithm_mac = cipher_aliases[i].algorithm_mac; - unsigned long algorithm_ssl = cipher_aliases[i].algorithm_ssl; - - if (algorithm_mkey) - if ((algorithm_mkey & mask_mkey) == 0) - continue; - - if (algorithm_auth) - if ((algorithm_auth & mask_auth) == 0) - continue; - - if (algorithm_enc) - if ((algorithm_enc & mask_enc) == 0) - continue; - - if (algorithm_mac) - if ((algorithm_mac & mask_mac) == 0) - continue; - - if (algorithm_ssl) - if ((algorithm_ssl & mask_ssl) == 0) - continue; - *ca_curr = cipher_aliases + i; ca_curr++; } @@ -711,9 +593,7 @@ static void ssl_cipher_apply_rule(unsigned long cipher_id, continue; if (alg_ssl && !(alg_ssl & cp->algorithm_ssl)) continue; - if ((algo_strength & SSL_EXP_MASK) && !(algo_strength & SSL_EXP_MASK & cp->algo_strength)) - continue; - if ((algo_strength & SSL_STRONG_MASK) && !(algo_strength & SSL_STRONG_MASK & cp->algo_strength)) + if (algo_strength && !(algo_strength & cp->algo_strength)) continue; } @@ -881,20 +761,8 @@ static int ssl_cipher_process_rulestr(const char *rule_str, { rule = CIPHER_DEL; l++; } else if (ch == '+') { rule = CIPHER_ORD; l++; } - else if (ch == '!' && has_group) - { - OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr, SSL_R_MIXED_SPECIAL_OPERATOR_WITH_GROUPS); - retval = found = in_group = 0; - break; - } else if (ch == '!') { rule = CIPHER_KILL; l++; } - else if (ch == '@' && has_group) - { - OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr, SSL_R_MIXED_SPECIAL_OPERATOR_WITH_GROUPS); - retval = found = in_group = 0; - break; - } else if (ch == '@') { rule = CIPHER_SPECIAL; l++; } else if (ch == '[') @@ -913,6 +781,16 @@ static int ssl_cipher_process_rulestr(const char *rule_str, else { rule = CIPHER_ADD; } + /* If preference groups are enabled, the only legal + * operator is +. Otherwise the in_group bits will get + * mixed up. */ + if (has_group && rule != CIPHER_ADD) + { + OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr, SSL_R_MIXED_SPECIAL_OPERATOR_WITH_GROUPS); + retval = found = in_group = 0; + break; + } + if (ITEM_SEP(ch)) { l++; @@ -1040,26 +918,15 @@ static int ssl_cipher_process_rulestr(const char *rule_str, alg_mac = ca_list[j]->algorithm_mac; } - if (ca_list[j]->algo_strength & SSL_EXP_MASK) + if (ca_list[j]->algo_strength) { - if (algo_strength & SSL_EXP_MASK) + if (algo_strength) { - algo_strength &= (ca_list[j]->algo_strength & SSL_EXP_MASK) | ~SSL_EXP_MASK; - if (!(algo_strength & SSL_EXP_MASK)) { found = 0; break; } + algo_strength &= ca_list[j]->algo_strength; + if (!algo_strength) { found = 0; break; } } else - algo_strength |= ca_list[j]->algo_strength & SSL_EXP_MASK; - } - - if (ca_list[j]->algo_strength & SSL_STRONG_MASK) - { - if (algo_strength & SSL_STRONG_MASK) - { - algo_strength &= (ca_list[j]->algo_strength & SSL_STRONG_MASK) | ~SSL_STRONG_MASK; - if (!(algo_strength & SSL_STRONG_MASK)) { found = 0; break; } - } - else - algo_strength |= ca_list[j]->algo_strength & SSL_STRONG_MASK; + algo_strength |= ca_list[j]->algo_strength; } if (ca_list[j]->valid) @@ -1122,7 +989,6 @@ static int ssl_cipher_process_rulestr(const char *rule_str, while ((*l != '\0') && !ITEM_SEP(*l)) l++; } - if (*l == '\0') break; /* done */ } if (in_group) @@ -1141,7 +1007,6 @@ STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(const SSL_METHOD *ssl_method, const char *rule_str, CERT *c) { int ok, num_of_ciphers, num_of_alias_max, num_of_group_aliases; - unsigned long disabled_mkey, disabled_auth, disabled_enc, disabled_mac, disabled_ssl; STACK_OF(SSL_CIPHER) *cipherstack = NULL, *tmp_cipher_list = NULL; const char *rule_p; CIPHER_ORDER *co_list = NULL, *head = NULL, *tail = NULL, *curr; @@ -1157,12 +1022,6 @@ STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(const SSL_METHOD *ssl_method, return NULL; /* - * To reduce the work to do we only want to process the compiled - * in algorithms, so we first get the mask of disabled ciphers. - */ - ssl_cipher_get_disabled(&disabled_mkey, &disabled_auth, &disabled_enc, &disabled_mac, &disabled_ssl); - - /* * Now we have to collect the available ciphers from the compiled * in ciphers. We cannot get more than the number compiled in, so * it is used for allocation. @@ -1179,7 +1038,6 @@ STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(const SSL_METHOD *ssl_method, } ssl_cipher_collect_ciphers(ssl_method, num_of_ciphers, - disabled_mkey, disabled_auth, disabled_enc, disabled_mac, disabled_ssl, co_list, &head, &tail); @@ -1242,13 +1100,10 @@ STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(const SSL_METHOD *ssl_method, ca_list = OPENSSL_malloc(sizeof(SSL_CIPHER *) * num_of_alias_max); if (ca_list == NULL) { - OPENSSL_free(co_list); OPENSSL_PUT_ERROR(SSL, ssl_create_cipher_list, ERR_R_MALLOC_FAILURE); - return(NULL); /* Failure */ + goto err; } - ssl_cipher_collect_aliases(ca_list, num_of_group_aliases, - disabled_mkey, disabled_auth, disabled_enc, - disabled_mac, disabled_ssl, head); + ssl_cipher_collect_aliases(ca_list, num_of_group_aliases, head); /* * If the rule_string begins with DEFAULT, apply the default rule diff --git a/ssl/ssl_error.c b/ssl/ssl_error.c index f6120dc..0ba125b 100644 --- a/ssl/ssl_error.c +++ b/ssl/ssl_error.c @@ -453,6 +453,7 @@ const ERR_STRING_DATA SSL_error_string_data[] = { {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED), "SSLV3_ALERT_CERTIFICATE_EXPIRED"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED), "SSLV3_ALERT_CERTIFICATE_REVOKED"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN), "SSLV3_ALERT_CERTIFICATE_UNKNOWN"}, + {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_CLOSE_NOTIFY), "SSLV3_ALERT_CLOSE_NOTIFY"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE), "SSLV3_ALERT_DECOMPRESSION_FAILURE"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE), "SSLV3_ALERT_HANDSHAKE_FAILURE"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER), "SSLV3_ALERT_ILLEGAL_PARAMETER"}, @@ -472,6 +473,7 @@ const ERR_STRING_DATA SSL_error_string_data[] = { {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_DECRYPTION_FAILED), "TLSV1_ALERT_DECRYPTION_FAILED"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_DECRYPT_ERROR), "TLSV1_ALERT_DECRYPT_ERROR"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION), "TLSV1_ALERT_EXPORT_RESTRICTION"}, + {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_INAPPROPRIATE_FALLBACK), "TLSV1_ALERT_INAPPROPRIATE_FALLBACK"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY), "TLSV1_ALERT_INSUFFICIENT_SECURITY"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_INTERNAL_ERROR), "TLSV1_ALERT_INTERNAL_ERROR"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_NO_RENEGOTIATION), "TLSV1_ALERT_NO_RENEGOTIATION"}, diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 1ad825a..720ab54 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -172,6 +172,13 @@ SSL3_ENC_METHOD ssl3_undef_enc_method={ int use_context)) ssl_undefined_function, }; +/* Some error codes are special. Ensure the make_errors.go script + * never regresses this. */ +OPENSSL_COMPILE_ASSERT( + SSL_R_TLSV1_ALERT_NO_RENEGOTIATION == + SSL_AD_NO_RENEGOTIATION + SSL_AD_REASON_OFFSET, + ssl_alert_reason_code_mismatch); + int SSL_clear(SSL *s) { @@ -1144,11 +1151,8 @@ long SSL_ctrl(SSL *s,int cmd,long larg,void *parg) s->max_cert_list=larg; return(l); case SSL_CTRL_SET_MTU: -#ifndef OPENSSL_NO_DTLS1 if (larg < (long)dtls1_min_mtu()) return 0; -#endif - if (SSL_IS_DTLS(s)) { s->d1->mtu = larg; diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index 2d10650..f9f3bed 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -359,14 +359,9 @@ /* * Cipher strength information. */ -#define SSL_EXP_MASK 0x00000003L -#define SSL_STRONG_MASK 0x000001fcL - -#define SSL_NOT_EXP 0x00000001L - -#define SSL_MEDIUM 0x00000040L -#define SSL_HIGH 0x00000080L -#define SSL_FIPS 0x00000100L +#define SSL_MEDIUM 0x00000001L +#define SSL_HIGH 0x00000002L +#define SSL_FIPS 0x00000004L /* we have used 000001ff - 23 bits left to go */ @@ -850,7 +845,6 @@ int ssl_cert_type(X509 *x,EVP_PKEY *pkey); void ssl_set_cert_masks(CERT *c, const SSL_CIPHER *cipher); STACK_OF(SSL_CIPHER) *ssl_get_ciphers_by_id(SSL *s); int ssl_verify_alarm_type(long type); -void ssl_load_ciphers(void); int ssl_fill_hello_random(SSL *s, int server, unsigned char *field, int len); const SSL_CIPHER *ssl3_get_cipher_by_value(uint16_t value); diff --git a/ssl/ssl_test.c b/ssl/ssl_test.c index 97a1967..68889a0 100644 --- a/ssl/ssl_test.c +++ b/ssl/ssl_test.c @@ -14,14 +14,261 @@ #include <stdio.h> -#include "openssl/ssl.h" +#include <openssl/err.h> +#include <openssl/ssl.h> + +typedef struct { + int id; + int in_group_flag; +} EXPECTED_CIPHER; + +typedef struct { + /* The rule string to apply. */ + const char *rule; + /* The list of expected ciphers, in order, terminated with -1. */ + const EXPECTED_CIPHER *expected; +} CIPHER_TEST; + +/* Selecting individual ciphers should work. */ +static const char kRule1[] = + "ECDHE-ECDSA-CHACHA20-POLY1305:" + "ECDHE-RSA-CHACHA20-POLY1305:" + "ECDHE-ECDSA-AES128-GCM-SHA256:" + "ECDHE-RSA-AES128-GCM-SHA256"; + +static const EXPECTED_CIPHER kExpected1[] = { + { TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305, 0 }, + { TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305, 0 }, + { TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0 }, + { TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0 }, + { -1, -1 }, +}; + +/* + reorders selected ciphers to the end, keeping their relative + * order. */ +static const char kRule2[] = + "ECDHE-ECDSA-CHACHA20-POLY1305:" + "ECDHE-RSA-CHACHA20-POLY1305:" + "ECDHE-ECDSA-AES128-GCM-SHA256:" + "ECDHE-RSA-AES128-GCM-SHA256:" + "+aRSA"; + +static const EXPECTED_CIPHER kExpected2[] = { + { TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305, 0 }, + { TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0 }, + { TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305, 0 }, + { TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0 }, + { -1, -1 }, +}; + +/* ! banishes ciphers from future selections. */ +static const char kRule3[] = + "!aRSA:" + "ECDHE-ECDSA-CHACHA20-POLY1305:" + "ECDHE-RSA-CHACHA20-POLY1305:" + "ECDHE-ECDSA-AES128-GCM-SHA256:" + "ECDHE-RSA-AES128-GCM-SHA256"; + +static const EXPECTED_CIPHER kExpected3[] = { + { TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305, 0 }, + { TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0 }, + { -1, -1 }, +}; + +/* Multiple masks can be ANDed in a single rule. */ +static const char kRule4[] = "kRSA+AESGCM+AES128"; + +static const EXPECTED_CIPHER kExpected4[] = { + { TLS1_CK_RSA_WITH_AES_128_GCM_SHA256, 0 }, + { -1, -1 }, +}; + +/* - removes selected ciphers, but preserves their order for future + * selections. Select AES_128_GCM, but order the key exchanges RSA, + * DHE_RSA, ECDHE_RSA. */ +static const char kRule5[] = + "ALL:-kEECDH:-kEDH:-kRSA:-ALL:" + "AESGCM+AES128+aRSA"; + +static const EXPECTED_CIPHER kExpected5[] = { + { TLS1_CK_RSA_WITH_AES_128_GCM_SHA256, 0 }, + { TLS1_CK_DHE_RSA_WITH_AES_128_GCM_SHA256, 0 }, + { TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0 }, + { -1, -1 }, +}; + +/* Unknown selectors are no-ops. */ +static const char kRule6[] = + "ECDHE-ECDSA-CHACHA20-POLY1305:" + "ECDHE-RSA-CHACHA20-POLY1305:" + "ECDHE-ECDSA-AES128-GCM-SHA256:" + "ECDHE-RSA-AES128-GCM-SHA256:" + "BOGUS1:-BOGUS2:+BOGUS3:!BOGUS4"; + +static const EXPECTED_CIPHER kExpected6[] = { + { TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305, 0 }, + { TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305, 0 }, + { TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0 }, + { TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0 }, + { -1, -1 }, +}; + +/* Square brackets specify equi-preference groups. */ +static const char kRule7[] = + "[ECDHE-ECDSA-CHACHA20-POLY1305|ECDHE-ECDSA-AES128-GCM-SHA256]:" + "[ECDHE-RSA-CHACHA20-POLY1305]:" + "ECDHE-RSA-AES128-GCM-SHA256"; + +static const EXPECTED_CIPHER kExpected7[] = { + { TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305, 1 }, + { TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0 }, + { TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305, 0 }, + { TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0 }, + { -1, -1 }, +}; + +/* @STRENGTH performs a stable strength-sort of the selected + * ciphers and only the selected ciphers. */ +static const char kRule8[] = + /* To simplify things, banish all but {ECDHE_RSA,RSA} x + * {CHACHA20,AES_256_CBC,AES_128_CBC,RC4} x SHA1. */ + "!kEDH:!AESGCM:!3DES:!SHA256:!MD5:!SHA384:" + /* Order some ciphers backwards by strength. */ + "ALL:-CHACHA20:-AES256:-AES128:-RC4:-ALL:" + /* Select ECDHE ones and sort them by strength. Ties should resolve + * based on the order above. */ + "kEECDH:@STRENGTH:-ALL:" + /* Now bring back everything uses RSA. ECDHE_RSA should be first, + * sorted by strength. Then RSA, backwards by strength. */ + "aRSA"; + +static const EXPECTED_CIPHER kExpected8[] = { + { TLS1_CK_ECDHE_RSA_WITH_AES_256_CBC_SHA, 0 }, + { TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305, 0 }, + { TLS1_CK_ECDHE_RSA_WITH_RC4_128_SHA, 0 }, + { TLS1_CK_ECDHE_RSA_WITH_AES_128_CBC_SHA, 0 }, + { SSL3_CK_RSA_RC4_128_SHA, 0 }, + { TLS1_CK_RSA_WITH_AES_128_SHA, 0 }, + { TLS1_CK_RSA_WITH_AES_256_SHA, 0 }, + { -1, -1 }, +}; + +static CIPHER_TEST kCipherTests[] = { + { kRule1, kExpected1 }, + { kRule2, kExpected2 }, + { kRule3, kExpected3 }, + { kRule4, kExpected4 }, + { kRule5, kExpected5 }, + { kRule6, kExpected6 }, + { kRule7, kExpected7 }, + { kRule8, kExpected8 }, + { NULL, NULL }, +}; + +static const char *kBadRules[] = { + /* Invalid brackets. */ + "[ECDHE-RSA-CHACHA20-POLY1305|ECDHE-RSA-AES128-GCM-SHA256", + "RSA]", + "[[RSA]]", + /* Operators inside brackets */ + "[+RSA]", + /* Unknown directive. */ + "@BOGUS", + /* Empty cipher lists error at SSL_CTX_set_cipher_list. */ + "", + "BOGUS", + /* Invalid command. */ + "?BAR", + /* Special operators are not allowed if groups are used. */ + "[ECDHE-RSA-CHACHA20-POLY1305|ECDHE-RSA-AES128-GCM-SHA256]:+FOO", + "[ECDHE-RSA-CHACHA20-POLY1305|ECDHE-RSA-AES128-GCM-SHA256]:!FOO", + "[ECDHE-RSA-CHACHA20-POLY1305|ECDHE-RSA-AES128-GCM-SHA256]:-FOO", + "[ECDHE-RSA-CHACHA20-POLY1305|ECDHE-RSA-AES128-GCM-SHA256]:@STRENGTH", + NULL, +}; + +static void print_cipher_preference_list( + struct ssl_cipher_preference_list_st *list) { + size_t i; + int in_group = 0; + for (i = 0; i < sk_SSL_CIPHER_num(list->ciphers); i++) { + const SSL_CIPHER *cipher = sk_SSL_CIPHER_value(list->ciphers, i); + if (!in_group && list->in_group_flags[i]) { + fprintf(stderr, "\t[\n"); + in_group = 1; + } + fprintf(stderr, "\t"); + if (in_group) { + fprintf(stderr, " "); + } + fprintf(stderr, "%s\n", SSL_CIPHER_get_name(cipher)); + if (in_group && !list->in_group_flags[i]) { + fprintf(stderr, "\t]\n"); + in_group = 0; + } + } +} + +static int test_cipher_rule(CIPHER_TEST *t) { + int ret = 0; + SSL_CTX *ctx = SSL_CTX_new(SSLv23_server_method()); + size_t i; + + if (!SSL_CTX_set_cipher_list(ctx, t->rule)) { + fprintf(stderr, "Error testing cipher rule '%s'\n", t->rule); + BIO_print_errors_fp(stderr); + goto done; + } + + /* Compare the two lists. */ + for (i = 0; i < sk_SSL_CIPHER_num(ctx->cipher_list->ciphers); i++) { + const SSL_CIPHER *cipher = + sk_SSL_CIPHER_value(ctx->cipher_list->ciphers, i); + if (t->expected[i].id != SSL_CIPHER_get_id(cipher) || + t->expected[i].in_group_flag != ctx->cipher_list->in_group_flags[i]) { + fprintf(stderr, "Error: cipher rule '%s' evaluted to:\n", t->rule); + print_cipher_preference_list(ctx->cipher_list); + goto done; + } + } + + if (t->expected[i].id != -1) { + fprintf(stderr, "Error: cipher rule '%s' evaluted to:\n", t->rule); + print_cipher_preference_list(ctx->cipher_list); + goto done; + } + + ret = 1; +done: + SSL_CTX_free(ctx); + return ret; +} + +static int test_cipher_rules(void) { + size_t i; + for (i = 0; kCipherTests[i].rule != NULL; i++) { + if (!test_cipher_rule(&kCipherTests[i])) { + return 0; + } + } + + for (i = 0; kBadRules[i] != NULL; i++) { + SSL_CTX *ctx = SSL_CTX_new(SSLv23_server_method()); + if (SSL_CTX_set_cipher_list(ctx, kBadRules[i])) { + fprintf(stderr, "Cipher rule '%s' unexpectedly succeeded\n", kBadRules[i]); + return 0; + } + ERR_clear_error(); + SSL_CTX_free(ctx); + } + + return 1; +} int main(void) { - /* Some error codes are special, but the make_errors.go script doesn't know - * this. This test will catch the case where something regenerates the error - * codes with the script but doesn't fix up the special ones. */ - if (SSL_R_TLSV1_ALERT_NO_RENEGOTIATION != 100 + SSL_AD_REASON_OFFSET) { - fprintf(stderr, "SSL alert errors don't match up.\n"); + SSL_library_init(); + + if (!test_cipher_rules()) { return 1; } diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c index 2f92524..ca6bf6c 100644 --- a/ssl/t1_enc.c +++ b/ssl/t1_enc.c @@ -596,7 +596,9 @@ int tls1_setup_key_block(SSL *s) goto cipher_unavailable_err; key_len = EVP_AEAD_key_length(aead); iv_len = SSL_CIPHER_AEAD_FIXED_NONCE_LEN(s->session->cipher); - if (!ssl_cipher_get_mac(s->session, &hash, &mac_type, &mac_secret_size)) + if ((s->session->cipher->algorithm2 & + SSL_CIPHER_ALGORITHM2_STATEFUL_AEAD) && + !ssl_cipher_get_mac(s->session, &hash, &mac_type, &mac_secret_size)) goto cipher_unavailable_err; /* For "stateful" AEADs (i.e. compatibility with pre-AEAD * cipher suites) the key length reported by diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index b9553a5..eccf875 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c @@ -1783,7 +1783,7 @@ static int ssl_scan_clienthello_tlsext(SSL *s, CBS *cbs, int *out_alert) !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)) { *out_alert = SSL_AD_HANDSHAKE_FAILURE; - OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_tlsext, SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED); + OPENSSL_PUT_ERROR(SSL, ssl_scan_clienthello_tlsext, SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED); return 0; } /* If no signature algorithms extension set default values */ @@ -2193,7 +2193,7 @@ static int ssl_check_serverhello_tlsext(SSL *s) } if (!found_uncompressed) { - OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_tlsext, SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST); + OPENSSL_PUT_ERROR(SSL, ssl_check_serverhello_tlsext, SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST); return -1; } } diff --git a/ssl/test/bssl_shim.cc b/ssl/test/bssl_shim.cc index 0459afc..5ee7c65 100644 --- a/ssl/test/bssl_shim.cc +++ b/ssl/test/bssl_shim.cc @@ -139,6 +139,29 @@ static int next_proto_select_callback(SSL* ssl, return SSL_TLSEXT_ERR_OK; } +static int alpn_select_callback(SSL* ssl, + const uint8_t** out, + uint8_t* outlen, + const uint8_t* in, + unsigned inlen, + void* arg) { + const TestConfig *config = GetConfigPtr(ssl); + if (config->select_alpn.empty()) + return SSL_TLSEXT_ERR_NOACK; + + if (!config->expected_advertised_alpn.empty() && + (config->expected_advertised_alpn.size() != inlen || + memcmp(config->expected_advertised_alpn.data(), + in, inlen) != 0)) { + fprintf(stderr, "bad ALPN select callback inputs\n"); + exit(1); + } + + *out = (const uint8_t*)config->select_alpn.data(); + *outlen = config->select_alpn.size(); + return SSL_TLSEXT_ERR_OK; +} + static int cookie_generate_callback(SSL *ssl, uint8_t *cookie, size_t *cookie_len) { *cookie_len = 32; memset(cookie, 42, *cookie_len); @@ -213,8 +236,13 @@ static SSL_CTX *setup_ctx(const TestConfig *config) { SSL_CTX_set_next_protos_advertised_cb( ssl_ctx, next_protos_advertised_callback, NULL); - SSL_CTX_set_next_proto_select_cb( - ssl_ctx, next_proto_select_callback, NULL); + if (!config->select_next_proto.empty()) { + SSL_CTX_set_next_proto_select_cb(ssl_ctx, next_proto_select_callback, NULL); + } + + if (!config->select_alpn.empty()) { + SSL_CTX_set_alpn_select_cb(ssl_ctx, alpn_select_callback, NULL); + } SSL_CTX_set_cookie_generate_cb(ssl_ctx, cookie_generate_callback); SSL_CTX_set_cookie_verify_cb(ssl_ctx, cookie_verify_callback); @@ -336,6 +364,13 @@ static int do_exchange(SSL_SESSION **out_session, } EVP_PKEY_free(pkey); } + if (!config->host_name.empty()) { + SSL_set_tlsext_host_name(ssl, config->host_name.c_str()); + } + if (!config->advertise_alpn.empty()) { + SSL_set_alpn_protos(ssl, (const uint8_t *)config->advertise_alpn.data(), + config->advertise_alpn.size()); + } BIO *bio = BIO_new_fd(fd, 1 /* take ownership */); if (bio == NULL) { @@ -376,8 +411,9 @@ static int do_exchange(SSL_SESSION **out_session, return 2; } - if (is_resume && !SSL_session_reused(ssl)) { - fprintf(stderr, "session was not reused\n"); + if (is_resume && (SSL_session_reused(ssl) == config->expect_session_miss)) { + fprintf(stderr, "session was%s reused\n", + SSL_session_reused(ssl) ? "" : " not"); return 2; } @@ -422,6 +458,18 @@ static int do_exchange(SSL_SESSION **out_session, } } + if (!config->expected_alpn.empty()) { + const uint8_t *alpn_proto; + unsigned alpn_proto_len; + SSL_get0_alpn_selected(ssl, &alpn_proto, &alpn_proto_len); + if (alpn_proto_len != config->expected_alpn.size() || + memcmp(alpn_proto, config->expected_alpn.data(), + alpn_proto_len) != 0) { + fprintf(stderr, "negotiated alpn proto mismatch\n"); + return 2; + } + } + if (!config->expected_channel_id.empty()) { uint8_t channel_id[64]; if (!SSL_get_tls_channel_id(ssl, channel_id, sizeof(channel_id))) { diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go index f22f95a..cf244bc 100644 --- a/ssl/test/runner/common.go +++ b/ssl/test/runner/common.go @@ -76,6 +76,7 @@ const ( extensionSupportedCurves uint16 = 10 extensionSupportedPoints uint16 = 11 extensionSignatureAlgorithms uint16 = 13 + extensionALPN uint16 = 16 extensionSessionTicket uint16 = 35 extensionNextProtoNeg uint16 = 13172 // not IANA assigned extensionRenegotiationInfo uint16 = 0xff01 @@ -166,6 +167,7 @@ type ConnectionState struct { CipherSuite uint16 // cipher suite in use (TLS_RSA_WITH_RC4_128_SHA, ...) NegotiatedProtocol string // negotiated next protocol (from Config.NextProtos) NegotiatedProtocolIsMutual bool // negotiated protocol was advertised by server + NegotiatedProtocolFromALPN bool // protocol negotiated with ALPN ServerName string // server name requested by client, if any (server side only) PeerCertificates []*x509.Certificate // certificate chain presented by remote peer VerifiedChains [][]*x509.Certificate // verified chains built from PeerCertificates @@ -449,6 +451,19 @@ type ProtocolBugs struct { // SkipCipherVersionCheck causes the server to negotiate // TLS 1.2 ciphers in earlier versions of TLS. SkipCipherVersionCheck bool + + // ExpectServerName, if not empty, is the hostname the client + // must specify in the server_name extension. + ExpectServerName string + + // SwapNPNAndALPN switches the relative order between NPN and + // ALPN on the server. This is to test that server preference + // of ALPN works regardless of their relative order. + SwapNPNAndALPN bool + + // AllowSessionVersionMismatch causes the server to resume sessions + // regardless of the version associated with the session. + AllowSessionVersionMismatch bool } func (c *Config) serverInit() { diff --git a/ssl/test/runner/conn.go b/ssl/test/runner/conn.go index 47b6e61..9f0c328 100644 --- a/ssl/test/runner/conn.go +++ b/ssl/test/runner/conn.go @@ -47,6 +47,7 @@ type Conn struct { clientProtocol string clientProtocolFallback bool + usedALPN bool channelID *ecdsa.PublicKey @@ -1105,6 +1106,7 @@ func (c *Conn) ConnectionState() ConnectionState { state.NegotiatedProtocol = c.clientProtocol state.DidResume = c.didResume state.NegotiatedProtocolIsMutual = !c.clientProtocolFallback + state.NegotiatedProtocolFromALPN = c.usedALPN state.CipherSuite = c.cipherSuite state.PeerCertificates = c.peerCertificates state.VerifiedChains = c.verifiedChains diff --git a/ssl/test/runner/handshake_client.go b/ssl/test/runner/handshake_client.go index 708d282..d78e767 100644 --- a/ssl/test/runner/handshake_client.go +++ b/ssl/test/runner/handshake_client.go @@ -43,6 +43,18 @@ func (c *Conn) clientHandshake() error { c.sendHandshakeSeq = 0 c.recvHandshakeSeq = 0 + nextProtosLength := 0 + for _, proto := range c.config.NextProtos { + if l := len(proto); l == 0 || l > 255 { + return errors.New("tls: invalid NextProtos value") + } else { + nextProtosLength += 1 + l + } + } + if nextProtosLength > 0xffff { + return errors.New("tls: NextProtos values too large") + } + hello := &clientHelloMsg{ isDTLS: c.isDTLS, vers: c.config.maxVersion(), @@ -54,8 +66,10 @@ func (c *Conn) clientHandshake() error { 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, } if c.config.Bugs.SendClientVersion != 0 { @@ -565,11 +579,32 @@ func (hs *clientHandshakeState) processServerHello() (bool, error) { return false, errors.New("tls: server selected unsupported compression format") } - if !hs.hello.nextProtoNeg && hs.serverHello.nextProtoNeg { + clientDidNPN := hs.hello.nextProtoNeg + clientDidALPN := len(hs.hello.alpnProtocols) > 0 + serverHasNPN := hs.serverHello.nextProtoNeg + serverHasALPN := len(hs.serverHello.alpnProtocol) > 0 + + if !clientDidNPN && serverHasNPN { c.sendAlert(alertHandshakeFailure) return false, errors.New("server advertised unrequested NPN extension") } + if !clientDidALPN && serverHasALPN { + c.sendAlert(alertHandshakeFailure) + return false, errors.New("server advertised unrequested ALPN extension") + } + + if serverHasNPN && serverHasALPN { + c.sendAlert(alertHandshakeFailure) + return false, errors.New("server advertised both NPN and ALPN extensions") + } + + if serverHasALPN { + c.clientProtocol = hs.serverHello.alpnProtocol + c.clientProtocolFallback = false + c.usedALPN = true + } + if !hs.hello.channelIDSupported && hs.serverHello.channelIDRequested { c.sendAlert(alertHandshakeFailure) return false, errors.New("server advertised unrequested Channel ID extension") @@ -750,20 +785,20 @@ func clientSessionCacheKey(serverAddr net.Addr, config *Config) string { return serverAddr.String() } -// mutualProtocol finds the mutual Next Protocol Negotiation protocol given the -// set of client and server supported protocols. The set of client supported -// protocols must not be empty. It returns the resulting protocol and flag +// mutualProtocol finds the mutual Next Protocol Negotiation or ALPN protocol +// given list of possible protocols and a list of the preference order. The +// first list must not be empty. It returns the resulting protocol and flag // indicating if the fallback case was reached. -func mutualProtocol(clientProtos, serverProtos []string) (string, bool) { - for _, s := range serverProtos { - for _, c := range clientProtos { +func mutualProtocol(protos, preferenceProtos []string) (string, bool) { + for _, s := range preferenceProtos { + for _, c := range protos { if s == c { return s, false } } } - return clientProtos[0], true + return protos[0], true } // writeIntPadded writes x into b, padded up with leading zeros as diff --git a/ssl/test/runner/handshake_messages.go b/ssl/test/runner/handshake_messages.go index 472aa87..136360d 100644 --- a/ssl/test/runner/handshake_messages.go +++ b/ssl/test/runner/handshake_messages.go @@ -24,8 +24,10 @@ type clientHelloMsg struct { sessionTicket []uint8 signatureAndHashes []signatureAndHash secureRenegotiation bool + alpnProtocols []string duplicateExtension bool channelIDSupported bool + npnLast bool } func (m *clientHelloMsg) equal(i interface{}) bool { @@ -51,8 +53,10 @@ func (m *clientHelloMsg) equal(i interface{}) bool { bytes.Equal(m.sessionTicket, m1.sessionTicket) && eqSignatureAndHashes(m.signatureAndHashes, m1.signatureAndHashes) && m.secureRenegotiation == m1.secureRenegotiation && + eqStrings(m.alpnProtocols, m1.alpnProtocols) && m.duplicateExtension == m1.duplicateExtension && - m.channelIDSupported == m1.channelIDSupported + m.channelIDSupported == m1.channelIDSupported && + m.npnLast == m1.npnLast } func (m *clientHelloMsg) marshal() []byte { @@ -103,6 +107,17 @@ func (m *clientHelloMsg) marshal() []byte { if m.channelIDSupported { numExtensions++ } + if len(m.alpnProtocols) > 0 { + extensionsLength += 2 + for _, s := range m.alpnProtocols { + if l := len(s); l == 0 || l > 255 { + panic("invalid ALPN protocol") + } + extensionsLength++ + extensionsLength += len(s) + } + numExtensions++ + } if numExtensions > 0 { extensionsLength += 4 * numExtensions length += 2 + extensionsLength @@ -147,7 +162,7 @@ func (m *clientHelloMsg) marshal() []byte { z[1] = 0xff z = z[4:] } - if m.nextProtoNeg { + if m.nextProtoNeg && !m.npnLast { z[0] = byte(extensionNextProtoNeg >> 8) z[1] = byte(extensionNextProtoNeg & 0xff) // The length is always 0 @@ -266,11 +281,38 @@ func (m *clientHelloMsg) marshal() []byte { z[3] = 1 z = z[5:] } + if len(m.alpnProtocols) > 0 { + z[0] = byte(extensionALPN >> 8) + z[1] = byte(extensionALPN & 0xff) + lengths := z[2:] + z = z[6:] + + stringsLength := 0 + for _, s := range m.alpnProtocols { + l := len(s) + z[0] = byte(l) + copy(z[1:], s) + z = z[1+l:] + stringsLength += 1 + l + } + + lengths[2] = byte(stringsLength >> 8) + lengths[3] = byte(stringsLength) + stringsLength += 2 + lengths[0] = byte(stringsLength >> 8) + lengths[1] = byte(stringsLength) + } if m.channelIDSupported { z[0] = byte(extensionChannelID >> 8) z[1] = byte(extensionChannelID & 0xff) z = z[4:] } + if m.nextProtoNeg && m.npnLast { + z[0] = byte(extensionNextProtoNeg >> 8) + z[1] = byte(extensionNextProtoNeg & 0xff) + // The length is always 0 + z = z[4:] + } if m.duplicateExtension { // Add a duplicate bogus extension at the beginning and end. z[0] = 0xff @@ -342,6 +384,7 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool { m.ticketSupported = false m.sessionTicket = nil m.signatureAndHashes = nil + m.alpnProtocols = nil if len(data) == 0 { // ClientHello is optionally followed by extension data @@ -451,6 +494,24 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool { return false } m.secureRenegotiation = true + case extensionALPN: + if length < 2 { + return false + } + l := int(data[0])<<8 | int(data[1]) + if l != length-2 { + return false + } + d := data[2:length] + for len(d) != 0 { + stringLen := int(d[0]) + d = d[1:] + if stringLen == 0 || stringLen > len(d) { + return false + } + m.alpnProtocols = append(m.alpnProtocols, string(d[:stringLen])) + d = d[stringLen:] + } case extensionChannelID: if length > 0 { return false @@ -476,6 +537,7 @@ type serverHelloMsg struct { ocspStapling bool ticketSupported bool secureRenegotiation bool + alpnProtocol string duplicateExtension bool channelIDRequested bool } @@ -498,6 +560,7 @@ func (m *serverHelloMsg) equal(i interface{}) bool { m.ocspStapling == m1.ocspStapling && m.ticketSupported == m1.ticketSupported && m.secureRenegotiation == m1.secureRenegotiation && + m.alpnProtocol == m1.alpnProtocol && m.duplicateExtension == m1.duplicateExtension && m.channelIDRequested == m1.channelIDRequested } @@ -536,6 +599,14 @@ func (m *serverHelloMsg) marshal() []byte { if m.channelIDRequested { numExtensions++ } + if alpnLen := len(m.alpnProtocol); alpnLen > 0 { + if alpnLen >= 256 { + panic("invalid ALPN protocol") + } + extensionsLength += 2 + 1 + alpnLen + numExtensions++ + } + if numExtensions > 0 { extensionsLength += 4 * numExtensions length += 2 + extensionsLength @@ -603,6 +674,20 @@ func (m *serverHelloMsg) marshal() []byte { z[3] = 1 z = z[5:] } + if alpnLen := len(m.alpnProtocol); alpnLen > 0 { + z[0] = byte(extensionALPN >> 8) + z[1] = byte(extensionALPN & 0xff) + l := 2 + 1 + alpnLen + z[2] = byte(l >> 8) + z[3] = byte(l) + l -= 2 + z[4] = byte(l >> 8) + z[5] = byte(l) + l -= 1 + z[6] = byte(l) + copy(z[7:], []byte(m.alpnProtocol)) + z = z[7+alpnLen:] + } if m.channelIDRequested { z[0] = byte(extensionChannelID >> 8) z[1] = byte(extensionChannelID & 0xff) @@ -644,6 +729,7 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool { m.nextProtos = nil m.ocspStapling = false m.ticketSupported = false + m.alpnProtocol = "" if len(data) == 0 { // ServerHello is optionally followed by extension data @@ -698,6 +784,22 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool { return false } m.secureRenegotiation = true + case extensionALPN: + d := data[:length] + if len(d) < 3 { + return false + } + l := int(d[0])<<8 | int(d[1]) + if l != len(d)-2 { + return false + } + d = d[2:] + l = int(d[0]) + if l != len(d)-1 { + return false + } + d = d[1:] + m.alpnProtocol = string(d) case extensionChannelID: if length > 0 { return false diff --git a/ssl/test/runner/handshake_server.go b/ssl/test/runner/handshake_server.go index 6d61fd5..1eb3f11 100644 --- a/ssl/test/runner/handshake_server.go +++ b/ssl/test/runner/handshake_server.go @@ -220,13 +220,22 @@ Curves: if len(hs.clientHello.serverName) > 0 { c.serverName = hs.clientHello.serverName } - // Although sending an empty NPN extension is reasonable, Firefox has - // had a bug around this. Best to send nothing at all if - // config.NextProtos is empty. See - // https://code.google.com/p/go/issues/detail?id=5445. - if hs.clientHello.nextProtoNeg && len(config.NextProtos) > 0 { - hs.hello.nextProtoNeg = true - hs.hello.nextProtos = config.NextProtos + + if len(hs.clientHello.alpnProtocols) > 0 { + if selectedProto, fallback := mutualProtocol(hs.clientHello.alpnProtocols, c.config.NextProtos); !fallback { + hs.hello.alpnProtocol = selectedProto + c.clientProtocol = selectedProto + c.usedALPN = true + } + } else { + // Although sending an empty NPN extension is reasonable, Firefox has + // had a bug around this. Best to send nothing at all if + // config.NextProtos is empty. See + // https://code.google.com/p/go/issues/detail?id=5445. + if hs.clientHello.nextProtoNeg && len(config.NextProtos) > 0 { + hs.hello.nextProtoNeg = true + hs.hello.nextProtos = config.NextProtos + } } if len(config.Certificates) == 0 { @@ -237,6 +246,9 @@ Curves: if len(hs.clientHello.serverName) > 0 { hs.cert = config.getCertificateForName(hs.clientHello.serverName) } + if expected := c.config.Bugs.ExpectServerName; expected != "" && expected != hs.clientHello.serverName { + return false, errors.New("tls: unexpected server name") + } if hs.clientHello.channelIDSupported && config.RequestChannelID { hs.hello.channelIDRequested = true @@ -290,16 +302,22 @@ Curves: func (hs *serverHandshakeState) checkForResumption() bool { c := hs.c - var ok bool - if hs.sessionState, ok = c.decryptTicket(hs.clientHello.sessionTicket); !ok { + if c.config.SessionTicketsDisabled { return false } - if hs.sessionState.vers > hs.clientHello.vers { + var ok bool + if hs.sessionState, ok = c.decryptTicket(hs.clientHello.sessionTicket); !ok { return false } - if vers, ok := c.config.mutualVersion(hs.sessionState.vers); !ok || vers != hs.sessionState.vers { - return false + + if !c.config.Bugs.AllowSessionVersionMismatch { + if hs.sessionState.vers > hs.clientHello.vers { + return false + } + if vers, ok := c.config.mutualVersion(hs.sessionState.vers); !ok || vers != hs.sessionState.vers { + return false + } } cipherSuiteOk := false diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go index 64df21d..323f43f 100644 --- a/ssl/test/runner/runner.go +++ b/ssl/test/runner/runner.go @@ -97,6 +97,11 @@ const ( dtls ) +const ( + alpn = 1 + npn = 2 +) + type testCase struct { testType testType protocol protocol @@ -110,9 +115,18 @@ type testCase struct { // expectedVersion, if non-zero, specifies the TLS version that must be // negotiated. expectedVersion uint16 + // expectedResumeVersion, if non-zero, specifies the TLS version that + // must be negotiated on resumption. If zero, expectedVersion is used. + expectedResumeVersion uint16 // expectChannelID controls whether the connection should have // negotiated a Channel ID with channelIDKey. expectChannelID bool + // expectedNextProto controls whether the connection should + // negotiate a next protocol via NPN or ALPN. + expectedNextProto string + // expectedNextProtoType, if non-zero, is the expected next + // protocol negotiation mechanism. + expectedNextProtoType int // messageLen is the length, in bytes, of the test message that will be // sent. messageLen int @@ -121,8 +135,13 @@ type testCase struct { // keyFile is the path to the private key to use for the server. keyFile string // resumeSession controls whether a second connection should be tested - // which resumes the first session. + // which attempts to resume the first session. resumeSession bool + // resumeConfig, if not nil, points to a Config to be used on + // resumption. SessionTicketKey and ClientSessionCache are copied from + // the initial connection's config. If nil, the initial connection's + // config is used. + resumeConfig *Config // sendPrefix sends a prefix on the socket before actually performing a // handshake. sendPrefix string @@ -202,36 +221,6 @@ var testCases = []testCase{ flags: []string{"-fallback-scsv"}, }, { - testType: serverTest, - name: "ServerNameExtension", - config: Config{ - ServerName: "example.com", - }, - flags: []string{"-expect-server-name", "example.com"}, - }, - { - testType: clientTest, - name: "DuplicateExtensionClient", - config: Config{ - Bugs: ProtocolBugs{ - DuplicateExtension: true, - }, - }, - shouldFail: true, - expectedLocalError: "remote error: error decoding message", - }, - { - testType: serverTest, - name: "DuplicateExtensionServer", - config: Config{ - Bugs: ProtocolBugs{ - DuplicateExtension: true, - }, - }, - shouldFail: true, - expectedLocalError: "remote error: error decoding message", - }, - { name: "ClientCertificateTypes", config: Config{ ClientAuth: RequestClientCert, @@ -497,7 +486,7 @@ var testCases = []testCase{ }, } -func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int) error { +func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int, isResume bool) error { if test.protocol == dtls { conn = newPacketAdaptor(conn) } @@ -528,8 +517,15 @@ func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int) e return err } - if vers := tlsConn.ConnectionState().Version; test.expectedVersion != 0 && vers != test.expectedVersion { - return fmt.Errorf("got version %x, expected %x", vers, test.expectedVersion) + // TODO(davidben): move all per-connection expectations into a dedicated + // expectations struct that can be specified separately for the two + // legs. + expectedVersion := test.expectedVersion + if isResume && test.expectedResumeVersion != 0 { + expectedVersion = test.expectedResumeVersion + } + if vers := tlsConn.ConnectionState().Version; expectedVersion != 0 && vers != expectedVersion { + return fmt.Errorf("got version %x, expected %x", vers, expectedVersion) } if test.expectChannelID { @@ -544,6 +540,18 @@ func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int) e } } + if expected := test.expectedNextProto; expected != "" { + if actual := tlsConn.ConnectionState().NegotiatedProtocol; actual != expected { + return fmt.Errorf("next proto mismatch: got %s, wanted %s", actual, expected) + } + } + + if test.expectedNextProtoType != 0 { + if (test.expectedNextProtoType == alpn) != tlsConn.ConnectionState().NegotiatedProtocolFromALPN { + return fmt.Errorf("next proto type mismatch") + } + } + if test.shimWritesFirst { var buf [5]byte _, err := io.ReadFull(tlsConn, buf[:]) @@ -705,12 +713,25 @@ func runTest(test *testCase, buildDir string) error { } } - err := doExchange(test, &config, conn, test.messageLen) + err := doExchange(test, &config, conn, test.messageLen, + false /* not a resumption */) conn.Close() if err == nil && test.resumeSession { - err = doExchange(test, &config, connResume, test.messageLen) - connResume.Close() + var resumeConfig Config + if test.resumeConfig != nil { + resumeConfig = *test.resumeConfig + if len(resumeConfig.Certificates) == 0 { + resumeConfig.Certificates = []Certificate{getRSACertificate()} + } + resumeConfig.SessionTicketKey = config.SessionTicketKey + resumeConfig.ClientSessionCache = config.ClientSessionCache + } else { + resumeConfig = config + } + err = doExchange(test, &resumeConfig, connResume, test.messageLen, + true /* resumption */) } + connResume.Close() childErr := shim.Wait() @@ -1159,13 +1180,14 @@ func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol) protocol: protocol, name: "NPN-Client" + suffix, config: Config{ - CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, - NextProtos: []string{"foo"}, + NextProtos: []string{"foo"}, Bugs: ProtocolBugs{ MaxHandshakeRecordLength: maxHandshakeRecordLength, }, }, - flags: append(flags, "-select-next-proto", "foo"), + flags: append(flags, "-select-next-proto", "foo"), + expectedNextProto: "foo", + expectedNextProtoType: npn, }) testCases = append(testCases, testCase{ protocol: protocol, @@ -1180,6 +1202,8 @@ func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol) flags: append(flags, "-advertise-npn", "\x03foo\x03bar\x03baz", "-expect-next-proto", "bar"), + expectedNextProto: "bar", + expectedNextProtoType: npn, }) // Client does False Start and negotiates NPN. @@ -1201,6 +1225,25 @@ func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol) resumeSession: true, }) + // Client does False Start and negotiates ALPN. + testCases = append(testCases, testCase{ + protocol: protocol, + name: "FalseStart-ALPN" + suffix, + config: Config{ + CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, + NextProtos: []string{"foo"}, + Bugs: ProtocolBugs{ + ExpectFalseStart: true, + MaxHandshakeRecordLength: maxHandshakeRecordLength, + }, + }, + flags: append(flags, + "-false-start", + "-advertise-alpn", "\x03foo"), + shimWritesFirst: true, + resumeSession: true, + }) + // False Start without session tickets. testCases = append(testCases, testCase{ name: "FalseStart-SessionTicketsDisabled", @@ -1372,6 +1415,197 @@ func addD5BugTests() { }) } +func addExtensionTests() { + testCases = append(testCases, testCase{ + testType: clientTest, + name: "DuplicateExtensionClient", + config: Config{ + Bugs: ProtocolBugs{ + DuplicateExtension: true, + }, + }, + shouldFail: true, + expectedLocalError: "remote error: error decoding message", + }) + testCases = append(testCases, testCase{ + testType: serverTest, + name: "DuplicateExtensionServer", + config: Config{ + Bugs: ProtocolBugs{ + DuplicateExtension: true, + }, + }, + shouldFail: true, + expectedLocalError: "remote error: error decoding message", + }) + testCases = append(testCases, testCase{ + testType: clientTest, + name: "ServerNameExtensionClient", + config: Config{ + Bugs: ProtocolBugs{ + ExpectServerName: "example.com", + }, + }, + flags: []string{"-host-name", "example.com"}, + }) + testCases = append(testCases, testCase{ + testType: clientTest, + name: "ServerNameExtensionClient", + config: Config{ + Bugs: ProtocolBugs{ + ExpectServerName: "mismatch.com", + }, + }, + flags: []string{"-host-name", "example.com"}, + shouldFail: true, + expectedLocalError: "tls: unexpected server name", + }) + testCases = append(testCases, testCase{ + testType: clientTest, + name: "ServerNameExtensionClient", + config: Config{ + Bugs: ProtocolBugs{ + ExpectServerName: "missing.com", + }, + }, + shouldFail: true, + expectedLocalError: "tls: unexpected server name", + }) + testCases = append(testCases, testCase{ + testType: serverTest, + name: "ServerNameExtensionServer", + config: Config{ + ServerName: "example.com", + }, + flags: []string{"-expect-server-name", "example.com"}, + resumeSession: true, + }) + testCases = append(testCases, testCase{ + testType: clientTest, + name: "ALPNClient", + config: Config{ + NextProtos: []string{"foo"}, + }, + flags: []string{ + "-advertise-alpn", "\x03foo\x03bar\x03baz", + "-expect-alpn", "foo", + }, + expectedNextProto: "foo", + expectedNextProtoType: alpn, + resumeSession: true, + }) + testCases = append(testCases, testCase{ + testType: serverTest, + name: "ALPNServer", + config: Config{ + NextProtos: []string{"foo", "bar", "baz"}, + }, + flags: []string{ + "-expect-advertised-alpn", "\x03foo\x03bar\x03baz", + "-select-alpn", "foo", + }, + expectedNextProto: "foo", + expectedNextProtoType: alpn, + resumeSession: true, + }) + // Test that the server prefers ALPN over NPN. + testCases = append(testCases, testCase{ + testType: serverTest, + name: "ALPNServer-Preferred", + config: Config{ + NextProtos: []string{"foo", "bar", "baz"}, + }, + flags: []string{ + "-expect-advertised-alpn", "\x03foo\x03bar\x03baz", + "-select-alpn", "foo", + "-advertise-npn", "\x03foo\x03bar\x03baz", + }, + expectedNextProto: "foo", + expectedNextProtoType: alpn, + resumeSession: true, + }) + testCases = append(testCases, testCase{ + testType: serverTest, + name: "ALPNServer-Preferred-Swapped", + config: Config{ + NextProtos: []string{"foo", "bar", "baz"}, + Bugs: ProtocolBugs{ + SwapNPNAndALPN: true, + }, + }, + flags: []string{ + "-expect-advertised-alpn", "\x03foo\x03bar\x03baz", + "-select-alpn", "foo", + "-advertise-npn", "\x03foo\x03bar\x03baz", + }, + expectedNextProto: "foo", + expectedNextProtoType: alpn, + resumeSession: true, + }) +} + +func addResumptionVersionTests() { + // TODO(davidben): Once DTLS 1.2 is working, test that as well. + for _, sessionVers := range tlsVersions { + // TODO(davidben): SSLv3 is omitted here because runner does not + // support resumption with session IDs. + if sessionVers.version == VersionSSL30 { + continue + } + for _, resumeVers := range tlsVersions { + if resumeVers.version == VersionSSL30 { + continue + } + suffix := "-" + sessionVers.name + "-" + resumeVers.name + + // TODO(davidben): Write equivalent tests for the server + // and clean up the server's logic. This requires being + // able to give the shim a different set of SSL_OP_NO_* + // flags between the initial connection and the + // resume. Perhaps resumption should be tested by + // serializing the SSL_SESSION and starting a second + // shim. + testCases = append(testCases, testCase{ + name: "Resume-Client" + suffix, + resumeSession: true, + config: Config{ + MaxVersion: sessionVers.version, + CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA}, + Bugs: ProtocolBugs{ + AllowSessionVersionMismatch: true, + }, + }, + expectedVersion: sessionVers.version, + resumeConfig: &Config{ + MaxVersion: resumeVers.version, + CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA}, + Bugs: ProtocolBugs{ + AllowSessionVersionMismatch: true, + }, + }, + expectedResumeVersion: resumeVers.version, + }) + + testCases = append(testCases, testCase{ + name: "Resume-Client-NoResume" + suffix, + flags: []string{"-expect-session-miss"}, + resumeSession: true, + config: Config{ + MaxVersion: sessionVers.version, + CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA}, + }, + expectedVersion: sessionVers.version, + resumeConfig: &Config{ + MaxVersion: resumeVers.version, + CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA}, + SessionTicketsDisabled: true, + }, + expectedResumeVersion: resumeVers.version, + }) + } + } +} + func worker(statusChan chan statusMsg, c chan *testCase, buildDir string, wg *sync.WaitGroup) { defer wg.Done() @@ -1425,6 +1659,8 @@ func main() { addClientAuthTests() addVersionNegotiationTests() addD5BugTests() + addExtensionTests() + addResumptionVersionTests() for _, async := range []bool{false, true} { for _, splitHandshake := range []bool{false, true} { for _, protocol := range []protocol{tls, dtls} { diff --git a/ssl/test/test_config.cc b/ssl/test/test_config.cc index 41188af..70543cc 100644 --- a/ssl/test/test_config.cc +++ b/ssl/test/test_config.cc @@ -55,6 +55,7 @@ const BoolFlag kBoolFlags[] = { { "-cookie-exchange", &TestConfig::cookie_exchange }, { "-shim-writes-first", &TestConfig::shim_writes_first }, { "-tls-d5-bug", &TestConfig::tls_d5_bug }, + { "-expect-session-miss", &TestConfig::expect_session_miss }, }; const size_t kNumBoolFlags = sizeof(kBoolFlags) / sizeof(kBoolFlags[0]); @@ -67,6 +68,11 @@ const StringFlag kStringFlags[] = { { "-expect-next-proto", &TestConfig::expected_next_proto }, { "-select-next-proto", &TestConfig::select_next_proto }, { "-send-channel-id", &TestConfig::send_channel_id }, + { "-host-name", &TestConfig::host_name }, + { "-advertise-alpn", &TestConfig::advertise_alpn }, + { "-expect-alpn", &TestConfig::expected_alpn }, + { "-expect-advertised-alpn", &TestConfig::expected_advertised_alpn }, + { "-select-alpn", &TestConfig::select_alpn }, }; const size_t kNumStringFlags = sizeof(kStringFlags) / sizeof(kStringFlags[0]); @@ -97,7 +103,8 @@ TestConfig::TestConfig() no_ssl3(false), cookie_exchange(false), shim_writes_first(false), - tls_d5_bug(false) { + tls_d5_bug(false), + expect_session_miss(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 208f19b..acce504 100644 --- a/ssl/test/test_config.h +++ b/ssl/test/test_config.h @@ -47,6 +47,12 @@ struct TestConfig { std::string send_channel_id; bool shim_writes_first; bool tls_d5_bug; + std::string host_name; + std::string advertise_alpn; + std::string expected_alpn; + std::string expected_advertised_alpn; + std::string select_alpn; + bool expect_session_miss; }; bool ParseConfig(int argc, char **argv, TestConfig *out_config); diff --git a/tool/pkcs12.cc b/tool/pkcs12.cc index 10ff630..d35ba0b 100644 --- a/tool/pkcs12.cc +++ b/tool/pkcs12.cc @@ -40,7 +40,7 @@ static const struct argument kArguments[] = { }, }; -bool PKCS12(const std::vector<std::string> &args) { +bool DoPKCS12(const std::vector<std::string> &args) { std::map<std::string, std::string> args_map; if (!ParseKeyValueArguments(&args_map, args, kArguments) || diff --git a/tool/tool.cc b/tool/tool.cc index bf79a47..a0866d7 100644 --- a/tool/tool.cc +++ b/tool/tool.cc @@ -20,7 +20,7 @@ bool Client(const std::vector<std::string> &args); -bool PKCS12(const std::vector<std::string> &args); +bool DoPKCS12(const std::vector<std::string> &args); bool Speed(const std::vector<std::string> &args); static void usage(const char *name) { @@ -45,7 +45,7 @@ int main(int argc, char **argv) { } else if (tool == "s_client" || tool == "client") { return !Client(args); } else if (tool == "pkcs12") { - return !PKCS12(args); + return !DoPKCS12(args); } else { usage(argv[0]); return 1; |