summaryrefslogtreecommitdiffstats
path: root/src/ssl/t1_lib.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ssl/t1_lib.c')
-rw-r--r--src/ssl/t1_lib.c260
1 files changed, 118 insertions, 142 deletions
diff --git a/src/ssl/t1_lib.c b/src/ssl/t1_lib.c
index e26351b..433a647 100644
--- a/src/ssl/t1_lib.c
+++ b/src/ssl/t1_lib.c
@@ -106,18 +106,20 @@
* (eay@cryptsoft.com). This product includes software written by Tim
* Hudson (tjh@cryptsoft.com). */
+#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
-#include <assert.h>
+#include <string.h>
#include <openssl/bytestring.h>
+#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/mem.h>
#include <openssl/obj.h>
#include <openssl/rand.h>
-#include "ssl_locl.h"
+#include "internal.h"
static int tls_decrypt_ticket(SSL *s, const uint8_t *tick, int ticklen,
@@ -133,16 +135,12 @@ const SSL3_ENC_METHOD TLSv1_enc_data = {
tls1_generate_master_secret,
tls1_change_cipher_state,
tls1_final_finish_mac,
- TLS1_FINISH_MAC_LENGTH,
tls1_cert_verify_mac,
TLS_MD_CLIENT_FINISH_CONST,TLS_MD_CLIENT_FINISH_CONST_SIZE,
TLS_MD_SERVER_FINISH_CONST,TLS_MD_SERVER_FINISH_CONST_SIZE,
tls1_alert_code,
tls1_export_keying_material,
0,
- SSL3_HM_HEADER_LENGTH,
- ssl3_set_handshake_header,
- ssl3_handshake_write,
};
const SSL3_ENC_METHOD TLSv1_1_enc_data = {
@@ -152,16 +150,12 @@ const SSL3_ENC_METHOD TLSv1_1_enc_data = {
tls1_generate_master_secret,
tls1_change_cipher_state,
tls1_final_finish_mac,
- TLS1_FINISH_MAC_LENGTH,
tls1_cert_verify_mac,
TLS_MD_CLIENT_FINISH_CONST,TLS_MD_CLIENT_FINISH_CONST_SIZE,
TLS_MD_SERVER_FINISH_CONST,TLS_MD_SERVER_FINISH_CONST_SIZE,
tls1_alert_code,
tls1_export_keying_material,
SSL_ENC_FLAG_EXPLICIT_IV,
- SSL3_HM_HEADER_LENGTH,
- ssl3_set_handshake_header,
- ssl3_handshake_write,
};
const SSL3_ENC_METHOD TLSv1_2_enc_data = {
@@ -171,7 +165,6 @@ const SSL3_ENC_METHOD TLSv1_2_enc_data = {
tls1_generate_master_secret,
tls1_change_cipher_state,
tls1_final_finish_mac,
- TLS1_FINISH_MAC_LENGTH,
tls1_cert_verify_mac,
TLS_MD_CLIENT_FINISH_CONST,TLS_MD_CLIENT_FINISH_CONST_SIZE,
TLS_MD_SERVER_FINISH_CONST,TLS_MD_SERVER_FINISH_CONST_SIZE,
@@ -179,9 +172,6 @@ const SSL3_ENC_METHOD TLSv1_2_enc_data = {
tls1_export_keying_material,
SSL_ENC_FLAG_EXPLICIT_IV|SSL_ENC_FLAG_SIGALGS|SSL_ENC_FLAG_SHA256_PRF
|SSL_ENC_FLAG_TLS1_2_CIPHERS,
- SSL3_HM_HEADER_LENGTH,
- ssl3_set_handshake_header,
- ssl3_handshake_write,
};
static int compare_uint16_t(const void *p1, const void *p2) {
@@ -255,8 +245,7 @@ static int tls1_check_duplicate_extensions(const CBS *cbs) {
ret = 1;
done:
- if (extension_types)
- OPENSSL_free(extension_types);
+ OPENSSL_free(extension_types);
return ret;
}
@@ -367,7 +356,7 @@ static const uint8_t ecformats_default[] = {
};
static const uint16_t eccurves_default[] = {
- 23, /* X9_64_prime256v1 */
+ 23, /* X9_62_prime256v1 */
24, /* secp384r1 */
};
@@ -399,6 +388,9 @@ static void tls1_get_curvelist(SSL *s, int get_peer_curves,
const uint16_t **out_curve_ids,
size_t *out_curve_ids_len) {
if (get_peer_curves) {
+ /* Only clients send a curve list, so this function is only called
+ * on the server. */
+ assert(s->server);
*out_curve_ids = s->s3->tmp.peer_ellipticcurvelist;
*out_curve_ids_len = s->s3->tmp.peer_ellipticcurvelist_length;
return;
@@ -437,22 +429,38 @@ int tls1_check_curve(SSL *s, CBS *cbs, uint16_t *out_curve_id) {
}
int tls1_get_shared_curve(SSL *s) {
- const uint16_t *pref, *supp;
- size_t preflen, supplen, i, j;
+ const uint16_t *curves, *peer_curves, *pref, *supp;
+ size_t curves_len, peer_curves_len, pref_len, supp_len, i, j;
/* Can't do anything on client side */
if (s->server == 0) {
return NID_undef;
}
- /* Return first preference shared curve */
- tls1_get_curvelist(s, !!(s->options & SSL_OP_CIPHER_SERVER_PREFERENCE), &supp,
- &supplen);
- tls1_get_curvelist(s, !(s->options & SSL_OP_CIPHER_SERVER_PREFERENCE), &pref,
- &preflen);
+ tls1_get_curvelist(s, 0 /* local curves */, &curves, &curves_len);
+ tls1_get_curvelist(s, 1 /* peer curves */, &peer_curves, &peer_curves_len);
+
+ if (peer_curves_len == 0) {
+ /* Clients are not required to send a supported_curves extension. In this
+ * case, the server is free to pick any curve it likes. See RFC 4492,
+ * section 4, paragraph 3. */
+ return (curves_len == 0) ? NID_undef : tls1_ec_curve_id2nid(curves[0]);
+ }
+
+ if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE) {
+ pref = curves;
+ pref_len = curves_len;
+ supp = peer_curves;
+ supp_len = peer_curves_len;
+ } else {
+ pref = peer_curves;
+ pref_len = peer_curves_len;
+ supp = curves;
+ supp_len = curves_len;
+ }
- for (i = 0; i < preflen; i++) {
- for (j = 0; j < supplen; j++) {
+ for (i = 0; i < pref_len; i++) {
+ for (j = 0; j < supp_len; j++) {
if (pref[i] == supp[j]) {
return tls1_ec_curve_id2nid(pref[i]);
}
@@ -479,9 +487,7 @@ int tls1_set_curves(uint16_t **out_curve_ids, size_t *out_curve_ids_len,
}
}
- if (*out_curve_ids) {
- OPENSSL_free(*out_curve_ids);
- }
+ OPENSSL_free(*out_curve_ids);
*out_curve_ids = curve_ids;
*out_curve_ids_len = ncurves;
@@ -556,11 +562,23 @@ static int tls1_check_point_format(SSL *s, uint8_t comp_id) {
* preferences are checked; the peer (the server) does not send preferences. */
static int tls1_check_curve_id(SSL *s, uint16_t curve_id) {
const uint16_t *curves;
- size_t curves_len, i, j;
+ size_t curves_len, i, get_peer_curves;
/* Check against our list, then the peer's list. */
- for (j = 0; j <= 1; j++) {
- tls1_get_curvelist(s, j, &curves, &curves_len);
+ for (get_peer_curves = 0; get_peer_curves <= 1; get_peer_curves++) {
+ if (get_peer_curves && !s->server) {
+ /* Servers do not present a preference list so, if we are a client, only
+ * check our list. */
+ continue;
+ }
+
+ tls1_get_curvelist(s, get_peer_curves, &curves, &curves_len);
+ if (get_peer_curves && curves_len == 0) {
+ /* Clients are not required to send a supported_curves extension. In this
+ * case, the server is free to pick any curve it likes. See RFC 4492,
+ * section 4, paragraph 3. */
+ continue;
+ }
for (i = 0; i < curves_len; i++) {
if (curves[i] == curve_id) {
break;
@@ -570,12 +588,6 @@ static int tls1_check_curve_id(SSL *s, uint16_t curve_id) {
if (i == curves_len) {
return 0;
}
-
- /* Servers do not present a preference list so, if we are a client, only
- * check our list. */
- if (!s->server) {
- return 1;
- }
}
return 1;
@@ -610,30 +622,27 @@ int tls1_check_ec_cert(SSL *s, X509 *x) {
ret = 1;
done:
- if (pkey) {
- EVP_PKEY_free(pkey);
- }
+ EVP_PKEY_free(pkey);
return ret;
}
int tls1_check_ec_tmp_key(SSL *s) {
- uint16_t curve_id;
- EC_KEY *ec = s->cert->ecdh_tmp;
-
- if (s->cert->ecdh_tmp_auto) {
- /* Need a shared curve */
- return tls1_get_shared_curve(s) != NID_undef;
+ if (s->cert->ecdh_nid != NID_undef) {
+ /* If the curve is preconfigured, ECDH is acceptable iff the peer supports
+ * the curve. */
+ uint16_t curve_id;
+ return tls1_ec_nid2curve_id(&curve_id, s->cert->ecdh_nid) &&
+ tls1_check_curve_id(s, curve_id);
}
- if (!ec) {
- if (s->cert->ecdh_tmp_cb) {
- return 1;
- }
- return 0;
+ if (s->cert->ecdh_tmp_cb != NULL) {
+ /* Assume the callback will provide an acceptable curve. */
+ return 1;
}
- return tls1_curve_params_from_ec_key(&curve_id, NULL, ec) &&
- tls1_check_curve_id(s, curve_id);
+ /* Otherwise, the curve gets selected automatically. ECDH is acceptable iff
+ * there is a shared curve. */
+ return tls1_get_shared_curve(s) != NID_undef;
}
/* List of supported signature algorithms and hashes. Should make this
@@ -803,7 +812,7 @@ uint8_t *ssl_add_clienthello_tlsext(SSL *s, uint8_t *buf, uint8_t *limit,
if (s->version >= TLS1_VERSION || SSL_IS_DTLS(s)) {
size_t i;
- unsigned long alg_k, alg_a;
+ uint32_t alg_k, alg_a;
STACK_OF(SSL_CIPHER) *cipher_stack = SSL_get_ciphers(s);
for (i = 0; i < sk_SSL_CIPHER_num(cipher_stack); i++) {
@@ -811,7 +820,7 @@ uint8_t *ssl_add_clienthello_tlsext(SSL *s, uint8_t *buf, uint8_t *limit,
alg_k = c->algorithm_mkey;
alg_a = c->algorithm_auth;
- if ((alg_k & SSL_kEECDH) || (alg_a & SSL_aECDSA)) {
+ if ((alg_k & SSL_kECDHE) || (alg_a & SSL_aECDSA)) {
using_ecc = 1;
break;
}
@@ -1117,9 +1126,9 @@ uint8_t *ssl_add_serverhello_tlsext(SSL *s, uint8_t *buf, uint8_t *limit) {
uint8_t *orig = buf;
uint8_t *ret = buf;
int next_proto_neg_seen;
- unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
- unsigned long alg_a = s->s3->tmp.new_cipher->algorithm_auth;
- int using_ecc = (alg_k & SSL_kEECDH) || (alg_a & SSL_aECDSA);
+ uint32_t alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
+ uint32_t alg_a = s->s3->tmp.new_cipher->algorithm_auth;
+ int using_ecc = (alg_k & SSL_kECDHE) || (alg_a & SSL_aECDSA);
using_ecc = using_ecc && (s->s3->tmp.peer_ecpointformatlist != NULL);
/* don't add extensions for SSLv3, unless doing secure renegotiation */
@@ -1331,9 +1340,7 @@ static int tls1_alpn_handle_client_hello(SSL *s, CBS *cbs, int *out_alert) {
s, &selected, &selected_len, CBS_data(&protocol_name_list),
CBS_len(&protocol_name_list), s->ctx->alpn_select_cb_arg);
if (r == SSL_TLSEXT_ERR_OK) {
- if (s->s3->alpn_selected) {
- OPENSSL_free(s->s3->alpn_selected);
- }
+ OPENSSL_free(s->s3->alpn_selected);
s->s3->alpn_selected = BUF_memdup(selected, selected_len);
if (!s->s3->alpn_selected) {
*out_alert = SSL_AD_INTERNAL_ERROR;
@@ -1359,35 +1366,27 @@ static int ssl_scan_clienthello_tlsext(SSL *s, CBS *cbs, int *out_alert) {
s->s3->tmp.certificate_status_expected = 0;
s->s3->tmp.extended_master_secret = 0;
- if (s->s3->alpn_selected) {
- OPENSSL_free(s->s3->alpn_selected);
- s->s3->alpn_selected = NULL;
- }
+ OPENSSL_free(s->s3->alpn_selected);
+ s->s3->alpn_selected = NULL;
/* Clear any signature algorithms extension received */
- if (s->cert->peer_sigalgs) {
- OPENSSL_free(s->cert->peer_sigalgs);
- s->cert->peer_sigalgs = NULL;
- }
+ OPENSSL_free(s->cert->peer_sigalgs);
+ s->cert->peer_sigalgs = NULL;
+ s->cert->peer_sigalgslen = 0;
/* Clear any shared signature algorithms */
- if (s->cert->shared_sigalgs) {
- OPENSSL_free(s->cert->shared_sigalgs);
- s->cert->shared_sigalgs = NULL;
- }
+ OPENSSL_free(s->cert->shared_sigalgs);
+ s->cert->shared_sigalgs = NULL;
+ s->cert->shared_sigalgslen = 0;
/* Clear ECC extensions */
- if (s->s3->tmp.peer_ecpointformatlist != 0) {
- OPENSSL_free(s->s3->tmp.peer_ecpointformatlist);
- s->s3->tmp.peer_ecpointformatlist = NULL;
- s->s3->tmp.peer_ecpointformatlist_length = 0;
- }
+ OPENSSL_free(s->s3->tmp.peer_ecpointformatlist);
+ s->s3->tmp.peer_ecpointformatlist = NULL;
+ s->s3->tmp.peer_ecpointformatlist_length = 0;
- if (s->s3->tmp.peer_ellipticcurvelist != 0) {
- OPENSSL_free(s->s3->tmp.peer_ellipticcurvelist);
- s->s3->tmp.peer_ellipticcurvelist = NULL;
- s->s3->tmp.peer_ellipticcurvelist_length = 0;
- }
+ OPENSSL_free(s->s3->tmp.peer_ellipticcurvelist);
+ s->s3->tmp.peer_ellipticcurvelist = NULL;
+ s->s3->tmp.peer_ellipticcurvelist_length = 0;
/* There may be no extensions. */
if (CBS_len(cbs) == 0) {
@@ -1412,11 +1411,6 @@ static int ssl_scan_clienthello_tlsext(SSL *s, CBS *cbs, int *out_alert) {
return 0;
}
- if (s->tlsext_debug_cb) {
- s->tlsext_debug_cb(s, 0, type, (uint8_t *)CBS_data(&extension),
- CBS_len(&extension), s->tlsext_debug_arg);
- }
-
/* The servername extension is treated as follows:
- Only the hostname type is supported with a maximum length of 255.
@@ -1529,10 +1523,8 @@ static int ssl_scan_clienthello_tlsext(SSL *s, CBS *cbs, int *out_alert) {
return 0;
}
- if (s->s3->tmp.peer_ellipticcurvelist) {
- OPENSSL_free(s->s3->tmp.peer_ellipticcurvelist);
- s->s3->tmp.peer_ellipticcurvelist_length = 0;
- }
+ OPENSSL_free(s->s3->tmp.peer_ellipticcurvelist);
+ s->s3->tmp.peer_ellipticcurvelist_length = 0;
s->s3->tmp.peer_ellipticcurvelist =
(uint16_t *)OPENSSL_malloc(CBS_len(&elliptic_curve_list));
@@ -1586,7 +1578,7 @@ static int ssl_scan_clienthello_tlsext(SSL *s, CBS *cbs, int *out_alert) {
}
/* If sigalgs received and no shared algorithms fatal error. */
if (s->cert->peer_sigalgs && !s->cert->shared_sigalgs) {
- OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_tlsext,
+ OPENSSL_PUT_ERROR(SSL, ssl_scan_clienthello_tlsext,
SSL_R_NO_SHARED_SIGATURE_ALGORITHMS);
*out_alert = SSL_AD_ILLEGAL_PARAMETER;
return 0;
@@ -1714,17 +1706,13 @@ static int ssl_scan_serverhello_tlsext(SSL *s, CBS *cbs, int *out_alert) {
s->s3->tmp.extended_master_secret = 0;
s->srtp_profile = NULL;
- if (s->s3->alpn_selected) {
- OPENSSL_free(s->s3->alpn_selected);
- s->s3->alpn_selected = NULL;
- }
+ OPENSSL_free(s->s3->alpn_selected);
+ s->s3->alpn_selected = NULL;
/* Clear ECC extensions */
- if (s->s3->tmp.peer_ecpointformatlist != 0) {
- OPENSSL_free(s->s3->tmp.peer_ecpointformatlist);
- s->s3->tmp.peer_ecpointformatlist = NULL;
- s->s3->tmp.peer_ecpointformatlist_length = 0;
- }
+ OPENSSL_free(s->s3->tmp.peer_ecpointformatlist);
+ s->s3->tmp.peer_ecpointformatlist = NULL;
+ s->s3->tmp.peer_ecpointformatlist_length = 0;
/* There may be no extensions. */
if (CBS_len(cbs) == 0) {
@@ -1749,11 +1737,6 @@ static int ssl_scan_serverhello_tlsext(SSL *s, CBS *cbs, int *out_alert) {
return 0;
}
- if (s->tlsext_debug_cb) {
- s->tlsext_debug_cb(s, 1, type, (uint8_t *)CBS_data(&extension),
- CBS_len(&extension), s->tlsext_debug_arg);
- }
-
if (type == TLSEXT_TYPE_server_name) {
/* The extension must be empty. */
if (CBS_len(&extension) != 0) {
@@ -1987,9 +1970,9 @@ static int ssl_check_serverhello_tlsext(SSL *s) {
/* If we are client and using an elliptic curve cryptography cipher suite,
* then if server returns an EC point formats lists extension it must contain
* uncompressed. */
- unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
- unsigned long alg_a = s->s3->tmp.new_cipher->algorithm_auth;
- if (((alg_k & SSL_kEECDH) || (alg_a & SSL_aECDSA)) &&
+ uint32_t alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
+ uint32_t alg_a = s->s3->tmp.new_cipher->algorithm_auth;
+ if (((alg_k & SSL_kECDHE) || (alg_a & SSL_aECDSA)) &&
!tls1_check_point_format(s, TLSEXT_ECPOINTFORMAT_uncompressed)) {
OPENSSL_PUT_ERROR(SSL, ssl_check_serverhello_tlsext,
SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST);
@@ -2001,7 +1984,7 @@ static int ssl_check_serverhello_tlsext(SSL *s) {
ret = s->ctx->tlsext_servername_callback(s, &al,
s->ctx->tlsext_servername_arg);
} else if (s->initial_ctx != NULL &&
- s->initial_ctx->tlsext_servername_callback != 0) {
+ s->initial_ctx->tlsext_servername_callback != 0) {
ret = s->initial_ctx->tlsext_servername_callback(
s, &al, s->initial_ctx->tlsext_servername_arg);
}
@@ -2133,8 +2116,11 @@ static int tls_decrypt_ticket(SSL *s, const uint8_t *etick, int eticklen,
EVP_CIPHER_CTX ctx;
SSL_CTX *tctx = s->initial_ctx;
- /* Need at least keyname + iv + some encrypted data */
- if (eticklen < 48) {
+ /* Ensure there is room for the key name and the largest IV
+ * |tlsext_ticket_key_cb| may try to consume. The real limit may be lower, but
+ * the maximum IV length should be well under the minimum size for the
+ * session material and HMAC. */
+ if (eticklen < 16 + EVP_MAX_IV_LENGTH) {
return 2;
}
@@ -2143,7 +2129,8 @@ static int tls_decrypt_ticket(SSL *s, const uint8_t *etick, int eticklen,
EVP_CIPHER_CTX_init(&ctx);
if (tctx->tlsext_ticket_key_cb) {
uint8_t *nctick = (uint8_t *)etick;
- int rv = tctx->tlsext_ticket_key_cb(s, nctick, nctick + 16, &ctx, &hctx, 0);
+ int rv = tctx->tlsext_ticket_key_cb(s, nctick, nctick + 16, &ctx, &hctx,
+ 0 /* decrypt */);
if (rv < 0) {
return -1;
}
@@ -2168,13 +2155,13 @@ static int tls_decrypt_ticket(SSL *s, const uint8_t *etick, int eticklen,
}
}
- /* Attempt to process session ticket, first conduct sanity and integrity
- * checks on ticket. */
+ /* First, check the MAC. The MAC is at the end of the ticket. */
mlen = HMAC_size(&hctx);
- if (mlen < 0) {
+ if ((size_t) eticklen < 16 + EVP_CIPHER_CTX_iv_length(&ctx) + 1 + mlen) {
+ /* The ticket must be large enough for key name, IV, data, and MAC. */
HMAC_CTX_cleanup(&hctx);
EVP_CIPHER_CTX_cleanup(&ctx);
- return -1;
+ return 2;
}
eticklen -= mlen;
/* Check HMAC of encrypted ticket */
@@ -2407,10 +2394,9 @@ static int tls1_set_shared_sigalgs(SSL *s) {
TLS_SIGALGS *salgs = NULL;
CERT *c = s->cert;
- if (c->shared_sigalgs) {
- OPENSSL_free(c->shared_sigalgs);
- c->shared_sigalgs = NULL;
- }
+ OPENSSL_free(c->shared_sigalgs);
+ c->shared_sigalgs = NULL;
+ c->shared_sigalgslen = 0;
/* If client use client signature algorithms if not NULL */
if (!s->server && c->client_sigalgs) {
@@ -2460,21 +2446,12 @@ int tls1_process_sigalgs(SSL *s, const CBS *sigalgs) {
return 1;
}
- /* Length must be even */
- if (CBS_len(sigalgs) % 2 != 0) {
- return 0;
- }
-
- /* Should never happen */
- if (!c) {
- return 0;
- }
-
- if (!CBS_stow(sigalgs, &c->peer_sigalgs, &c->peer_sigalgslen)) {
+ if (CBS_len(sigalgs) % 2 != 0 ||
+ !CBS_stow(sigalgs, &c->peer_sigalgs, &c->peer_sigalgslen) ||
+ !tls1_set_shared_sigalgs(s)) {
return 0;
}
- tls1_set_shared_sigalgs(s);
return 1;
}
@@ -2583,7 +2560,10 @@ int tls1_channel_id_hash(EVP_MD_CTX *md, SSL *s) {
if (s->s3->handshake_dgst[i] == NULL) {
continue;
}
- EVP_MD_CTX_copy_ex(&ctx, s->s3->handshake_dgst[i]);
+ if (!EVP_MD_CTX_copy_ex(&ctx, s->s3->handshake_dgst[i])) {
+ EVP_MD_CTX_cleanup(&ctx);
+ return 0;
+ }
EVP_DigestFinal_ex(&ctx, temp_digest, &temp_digest_len);
EVP_DigestUpdate(md, temp_digest, temp_digest_len);
}
@@ -2650,15 +2630,11 @@ int tls1_set_sigalgs(CERT *c, const int *psig_nids, size_t salglen,
}
if (client) {
- if (c->client_sigalgs) {
- OPENSSL_free(c->client_sigalgs);
- }
+ OPENSSL_free(c->client_sigalgs);
c->client_sigalgs = sigalgs;
c->client_sigalgslen = salglen;
} else {
- if (c->conf_sigalgs) {
- OPENSSL_free(c->conf_sigalgs);
- }
+ OPENSSL_free(c->conf_sigalgs);
c->conf_sigalgs = sigalgs;
c->conf_sigalgslen = salglen;
}