| From 1d43b892d27915843e5714d96de269672b5b35db Mon Sep 17 00:00:00 2001 |
| From: Adam Langley <agl@chromium.org> |
| Date: Thu, 14 Nov 2013 16:12:01 -0500 |
| Subject: Implement ECDHE-PSK-WITH-AES. |
| |
| Add support for TLS-ECDHE-PSK cipher suites: |
| * TLS-ECDHE-PSK-WITH-AES-128-CBC-SHA256, and |
| * TLS-ECDHE-PSK-WITH-AES-256-CBC-SHA384. |
| --- |
| ssl/s3_clnt.c | 360 ++++++++++++++++++++++---------------- |
| ssl/s3_enc.c | 2 +- |
| ssl/s3_lib.c | 38 +++++- |
| ssl/s3_srvr.c | 541 ++++++++++++++++++++++++++++++++-------------------------- |
| ssl/ssl_lib.c | 2 +- |
| ssl/tls1.h | 8 + |
| 6 files changed, 555 insertions(+), 396 deletions(-) |
| |
| diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c |
| index 8f3740f..3672cce 100644 |
| --- a/ssl/s3_clnt.c |
| +++ b/ssl/s3_clnt.c |
| @@ -333,9 +333,10 @@ int ssl3_connect(SSL *s) |
| } |
| #endif |
| /* Check if it is anon DH/ECDH */ |
| - /* or PSK */ |
| + /* or non-RSA PSK */ |
| if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL) && |
| - !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)) |
| + !((s->s3->tmp.new_cipher->algorithm_auth & SSL_aPSK) && |
| + !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kRSA))) |
| { |
| ret=ssl3_get_server_certificate(s); |
| if (ret <= 0) goto end; |
| @@ -1368,7 +1369,7 @@ int ssl3_get_key_exchange(SSL *s) |
| omitted if no identity hint is sent. Set |
| session->sess_cert anyway to avoid problems |
| later.*/ |
| - if (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK) |
| + if (s->s3->tmp.new_cipher->algorithm_auth & SSL_aPSK) |
| { |
| s->session->sess_cert=ssl_sess_cert_new(); |
| if (s->ctx->psk_identity_hint) |
| @@ -1416,52 +1417,56 @@ int ssl3_get_key_exchange(SSL *s) |
| EVP_MD_CTX_init(&md_ctx); |
| |
| #ifndef OPENSSL_NO_PSK |
| - if (alg_k & SSL_kPSK) |
| + if (alg_a & SSL_aPSK) |
| { |
| char tmp_id_hint[PSK_MAX_IDENTITY_LEN+1]; |
| |
| al=SSL_AD_HANDSHAKE_FAILURE; |
| n2s(p,i); |
| param_len=i+2; |
| - /* Store PSK identity hint for later use, hint is used |
| - * in ssl3_send_client_key_exchange. Assume that the |
| - * maximum length of a PSK identity hint can be as |
| - * long as the maximum length of a PSK identity. */ |
| - if (i > PSK_MAX_IDENTITY_LEN) |
| - { |
| - SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, |
| - SSL_R_DATA_LENGTH_TOO_LONG); |
| - goto f_err; |
| - } |
| - if (param_len > n) |
| + s->ctx->psk_identity_hint = NULL; |
| + if (i != 0) |
| { |
| - al=SSL_AD_DECODE_ERROR; |
| - SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, |
| - SSL_R_BAD_PSK_IDENTITY_HINT_LENGTH); |
| - goto f_err; |
| + /* Store PSK identity hint for later use, hint is used |
| + * in ssl3_send_client_key_exchange. Assume that the |
| + * maximum length of a PSK identity hint can be as |
| + * long as the maximum length of a PSK identity. */ |
| + if (i > PSK_MAX_IDENTITY_LEN) |
| + { |
| + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, |
| + SSL_R_DATA_LENGTH_TOO_LONG); |
| + goto f_err; |
| + } |
| + if (param_len > n) |
| + { |
| + al=SSL_AD_DECODE_ERROR; |
| + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, |
| + SSL_R_BAD_PSK_IDENTITY_HINT_LENGTH); |
| + goto f_err; |
| + } |
| + /* If received PSK identity hint contains NULL |
| + * characters, the hint is truncated from the first |
| + * NULL. p may not be ending with NULL, so create a |
| + * NULL-terminated string. */ |
| + memcpy(tmp_id_hint, p, i); |
| + memset(tmp_id_hint+i, 0, PSK_MAX_IDENTITY_LEN+1-i); |
| + if (s->ctx->psk_identity_hint != NULL) |
| + OPENSSL_free(s->ctx->psk_identity_hint); |
| + s->ctx->psk_identity_hint = BUF_strdup(tmp_id_hint); |
| + if (s->ctx->psk_identity_hint == NULL) |
| + { |
| + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE); |
| + goto f_err; |
| + } |
| } |
| - /* If received PSK identity hint contains NULL |
| - * characters, the hint is truncated from the first |
| - * NULL. p may not be ending with NULL, so create a |
| - * NULL-terminated string. */ |
| - memcpy(tmp_id_hint, p, i); |
| - memset(tmp_id_hint+i, 0, PSK_MAX_IDENTITY_LEN+1-i); |
| - if (s->ctx->psk_identity_hint != NULL) |
| - OPENSSL_free(s->ctx->psk_identity_hint); |
| - s->ctx->psk_identity_hint = BUF_strdup(tmp_id_hint); |
| - if (s->ctx->psk_identity_hint == NULL) |
| - { |
| - SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE); |
| - goto f_err; |
| - } |
| - |
| p+=i; |
| n-=param_len; |
| } |
| - else |
| #endif /* !OPENSSL_NO_PSK */ |
| + |
| + if (0) {} |
| #ifndef OPENSSL_NO_SRP |
| - if (alg_k & SSL_kSRP) |
| + else if (alg_k & SSL_kSRP) |
| { |
| n2s(p,i); |
| param_len=i+2; |
| @@ -1538,10 +1543,9 @@ int ssl3_get_key_exchange(SSL *s) |
| pkey=X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_DSA_SIGN].x509); |
| #endif |
| } |
| - else |
| #endif /* !OPENSSL_NO_SRP */ |
| #ifndef OPENSSL_NO_RSA |
| - if (alg_k & SSL_kRSA) |
| + else if (alg_k & SSL_kRSA) |
| { |
| if ((rsa=RSA_new()) == NULL) |
| { |
| @@ -1590,9 +1594,6 @@ int ssl3_get_key_exchange(SSL *s) |
| s->session->sess_cert->peer_rsa_tmp=rsa; |
| rsa=NULL; |
| } |
| -#else /* OPENSSL_NO_RSA */ |
| - if (0) |
| - ; |
| #endif |
| #ifndef OPENSSL_NO_DH |
| else if (alg_k & SSL_kEDH) |
| @@ -1773,14 +1774,14 @@ int ssl3_get_key_exchange(SSL *s) |
| EC_POINT_free(srvr_ecpoint); |
| srvr_ecpoint = NULL; |
| } |
| - else if (alg_k) |
| +#endif /* !OPENSSL_NO_ECDH */ |
| + |
| + else if (!(alg_k & SSL_kPSK)) |
| { |
| al=SSL_AD_UNEXPECTED_MESSAGE; |
| SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_UNEXPECTED_MESSAGE); |
| goto f_err; |
| } |
| -#endif /* !OPENSSL_NO_ECDH */ |
| - |
| |
| /* p points to the next byte, there are 'n' bytes left */ |
| |
| @@ -1885,8 +1886,9 @@ fprintf(stderr, "USING TLSv1.2 HASH %s\n", EVP_MD_name(md)); |
| } |
| else |
| { |
| - if (!(alg_a & SSL_aNULL) && !(alg_k & SSL_kPSK)) |
| - /* aNULL or kPSK do not need public keys */ |
| + if (!(alg_a & SSL_aNULL) && |
| + /* Among PSK ciphers only RSA_PSK needs a public key */ |
| + !((alg_a & SSL_aPSK) && !(alg_k & SSL_kRSA))) |
| { |
| SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR); |
| goto err; |
| @@ -2286,8 +2288,9 @@ int ssl3_get_server_done(SSL *s) |
| int ssl3_send_client_key_exchange(SSL *s) |
| { |
| unsigned char *p,*d; |
| - int n; |
| + int n = 0; |
| unsigned long alg_k; |
| + unsigned long alg_a; |
| #ifndef OPENSSL_NO_RSA |
| unsigned char *q; |
| EVP_PKEY *pkey=NULL; |
| @@ -2302,7 +2305,11 @@ int ssl3_send_client_key_exchange(SSL *s) |
| unsigned char *encodedPoint = NULL; |
| int encoded_pt_len = 0; |
| BN_CTX * bn_ctx = NULL; |
| -#endif |
| +#ifndef OPENSSL_NO_PSK |
| + unsigned int psk_len = 0; |
| + unsigned char psk[PSK_MAX_PSK_LEN]; |
| +#endif /* OPENSSL_NO_PSK */ |
| +#endif /* OPENSSL_NO_ECDH */ |
| |
| if (s->state == SSL3_ST_CW_KEY_EXCH_A) |
| { |
| @@ -2310,7 +2317,96 @@ int ssl3_send_client_key_exchange(SSL *s) |
| p= &(d[4]); |
| |
| alg_k=s->s3->tmp.new_cipher->algorithm_mkey; |
| + alg_a=s->s3->tmp.new_cipher->algorithm_auth; |
| + |
| +#ifndef OPENSSL_NO_PSK |
| + if (alg_a & SSL_aPSK) |
| + { |
| + char identity[PSK_MAX_IDENTITY_LEN]; |
| + unsigned char *t = NULL; |
| + unsigned char pre_ms[PSK_MAX_PSK_LEN*2+4]; |
| + unsigned int pre_ms_len = 0; |
| + int psk_err = 1; |
| + |
| + n = 0; |
| + if (s->psk_client_callback == NULL) |
| + { |
| + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, |
| + SSL_R_PSK_NO_CLIENT_CB); |
| + goto err; |
| + } |
| |
| + psk_len = s->psk_client_callback(s, s->ctx->psk_identity_hint, |
| + identity, PSK_MAX_IDENTITY_LEN, psk, sizeof(psk)); |
| + if (psk_len > PSK_MAX_PSK_LEN) |
| + { |
| + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, |
| + ERR_R_INTERNAL_ERROR); |
| + goto psk_err; |
| + } |
| + else if (psk_len == 0) |
| + { |
| + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, |
| + SSL_R_PSK_IDENTITY_NOT_FOUND); |
| + goto psk_err; |
| + } |
| + |
| + if (!(alg_k & SSL_kEECDH)) |
| + { |
| + /* Create the shared secret now if we're not using ECDHE-PSK.*/ |
| + pre_ms_len = 2+psk_len+2+psk_len; |
| + t = pre_ms; |
| + s2n(psk_len, t); |
| + memset(t, 0, psk_len); |
| + t+=psk_len; |
| + s2n(psk_len, t); |
| + memcpy(t, psk, psk_len); |
| + |
| + s->session->master_key_length = |
| + s->method->ssl3_enc->generate_master_secret(s, |
| + s->session->master_key, |
| + pre_ms, pre_ms_len); |
| + n = strlen(identity); |
| + s2n(n, p); |
| + memcpy(p, identity, n); |
| + n += 2; |
| + } |
| + |
| + if (s->session->psk_identity_hint != NULL) |
| + OPENSSL_free(s->session->psk_identity_hint); |
| + s->session->psk_identity_hint = NULL; |
| + if (s->ctx->psk_identity_hint) |
| + { |
| + s->session->psk_identity_hint = BUF_strdup(s->ctx->psk_identity_hint); |
| + if (s->ctx->psk_identity_hint != NULL && |
| + s->session->psk_identity_hint == NULL) |
| + { |
| + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, |
| + ERR_R_MALLOC_FAILURE); |
| + goto psk_err; |
| + } |
| + } |
| + |
| + if (s->session->psk_identity != NULL) |
| + OPENSSL_free(s->session->psk_identity); |
| + s->session->psk_identity = BUF_strdup(identity); |
| + if (s->session->psk_identity == NULL) |
| + { |
| + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, |
| + ERR_R_MALLOC_FAILURE); |
| + goto psk_err; |
| + } |
| + psk_err = 0; |
| + psk_err: |
| + OPENSSL_cleanse(identity, PSK_MAX_IDENTITY_LEN); |
| + OPENSSL_cleanse(pre_ms, sizeof(pre_ms)); |
| + if (psk_err != 0) |
| + { |
| + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); |
| + goto err; |
| + } |
| + } |
| +#endif |
| /* Fool emacs indentation */ |
| if (0) {} |
| #ifndef OPENSSL_NO_RSA |
| @@ -2571,14 +2667,19 @@ int ssl3_send_client_key_exchange(SSL *s) |
| /* perhaps clean things up a bit EAY EAY EAY EAY*/ |
| } |
| #endif |
| - |
| -#ifndef OPENSSL_NO_ECDH |
| +#ifndef OPENSSL_NO_ECDH |
| else if (alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe)) |
| { |
| const EC_GROUP *srvr_group = NULL; |
| EC_KEY *tkey; |
| int ecdh_clnt_cert = 0; |
| int field_size = 0; |
| +#ifndef OPENSSL_NO_PSK |
| + unsigned char *pre_ms; |
| + unsigned char *t; |
| + unsigned int pre_ms_len; |
| + unsigned int i; |
| +#endif |
| |
| if (s->session->sess_cert == NULL) |
| { |
| @@ -2706,15 +2807,41 @@ int ssl3_send_client_key_exchange(SSL *s) |
| goto err; |
| } |
| |
| - /* generate master key from the result */ |
| - s->session->master_key_length = s->method->ssl3_enc \ |
| - -> generate_master_secret(s, |
| - s->session->master_key, |
| - p, n); |
| - |
| +#ifndef OPENSSL_NO_PSK |
| + /* ECDHE PSK ciphersuites from RFC 5489 */ |
| + if ((alg_a & SSL_aPSK) && psk_len != 0) |
| + { |
| + pre_ms_len = 2+n+2+psk_len; |
| + pre_ms = OPENSSL_malloc(pre_ms_len); |
| + if (pre_ms == NULL) |
| + { |
| + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, |
| + ERR_R_MALLOC_FAILURE); |
| + goto err; |
| + } |
| + memset(pre_ms, 0, pre_ms_len); |
| + t = pre_ms; |
| + s2n(n, t); |
| + memcpy(t, p, n); |
| + t += n; |
| + s2n(psk_len, t); |
| + memcpy(t, psk, psk_len); |
| + s->session->master_key_length = s->method->ssl3_enc \ |
| + -> generate_master_secret(s, |
| + s->session->master_key, pre_ms, pre_ms_len); |
| + OPENSSL_cleanse(pre_ms, pre_ms_len); |
| + OPENSSL_free(pre_ms); |
| + } |
| +#endif /* OPENSSL_NO_PSK */ |
| + if (!(alg_a & SSL_aPSK)) |
| + { |
| + /* generate master key from the result */ |
| + s->session->master_key_length = s->method->ssl3_enc \ |
| + -> generate_master_secret(s, |
| + s->session->master_key, p, n); |
| + } |
| memset(p, 0, n); /* clean up */ |
| - |
| - if (ecdh_clnt_cert) |
| + if (ecdh_clnt_cert) |
| { |
| /* Send empty client key exch message */ |
| n = 0; |
| @@ -2742,29 +2869,42 @@ int ssl3_send_client_key_exchange(SSL *s) |
| } |
| |
| /* Encode the public key */ |
| - n = EC_POINT_point2oct(srvr_group, |
| - EC_KEY_get0_public_key(clnt_ecdh), |
| - POINT_CONVERSION_UNCOMPRESSED, |
| + encoded_pt_len = EC_POINT_point2oct(srvr_group, |
| + EC_KEY_get0_public_key(clnt_ecdh), |
| + POINT_CONVERSION_UNCOMPRESSED, |
| encodedPoint, encoded_pt_len, bn_ctx); |
| + |
| + n = 0; |
| +#ifndef OPENSSL_NO_PSK |
| + if ((alg_a & SSL_aPSK) && psk_len != 0) |
| + { |
| + i = strlen(s->session->psk_identity); |
| + s2n(i, p); |
| + memcpy(p, s->session->psk_identity, i); |
| + p += i; |
| + n = i + 2; |
| + } |
| +#endif |
| |
| - *p = n; /* length of encoded point */ |
| + *p = encoded_pt_len; /* length of encoded point */ |
| /* Encoded point will be copied here */ |
| - p += 1; |
| + p += 1; |
| + n += 1; |
| /* copy the point */ |
| - memcpy((unsigned char *)p, encodedPoint, n); |
| + memcpy((unsigned char *)p, encodedPoint, encoded_pt_len); |
| /* increment n to account for length field */ |
| - n += 1; |
| + n += encoded_pt_len; |
| } |
| |
| /* Free allocated memory */ |
| BN_CTX_free(bn_ctx); |
| if (encodedPoint != NULL) OPENSSL_free(encodedPoint); |
| - if (clnt_ecdh != NULL) |
| + if (clnt_ecdh != NULL) |
| EC_KEY_free(clnt_ecdh); |
| EVP_PKEY_free(srvr_pub_pkey); |
| } |
| #endif /* !OPENSSL_NO_ECDH */ |
| - else if (alg_k & SSL_kGOST) |
| + else if (alg_k & SSL_kGOST) |
| { |
| /* GOST key exchange message creation */ |
| EVP_PKEY_CTX *pkey_ctx; |
| @@ -2887,89 +3027,7 @@ int ssl3_send_client_key_exchange(SSL *s) |
| } |
| } |
| #endif |
| -#ifndef OPENSSL_NO_PSK |
| - else if (alg_k & SSL_kPSK) |
| - { |
| - char identity[PSK_MAX_IDENTITY_LEN]; |
| - unsigned char *t = NULL; |
| - unsigned char psk_or_pre_ms[PSK_MAX_PSK_LEN*2+4]; |
| - unsigned int pre_ms_len = 0, psk_len = 0; |
| - int psk_err = 1; |
| - |
| - n = 0; |
| - if (s->psk_client_callback == NULL) |
| - { |
| - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, |
| - SSL_R_PSK_NO_CLIENT_CB); |
| - goto err; |
| - } |
| - |
| - psk_len = s->psk_client_callback(s, s->ctx->psk_identity_hint, |
| - identity, PSK_MAX_IDENTITY_LEN, |
| - psk_or_pre_ms, sizeof(psk_or_pre_ms)); |
| - if (psk_len > PSK_MAX_PSK_LEN) |
| - { |
| - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, |
| - ERR_R_INTERNAL_ERROR); |
| - goto psk_err; |
| - } |
| - else if (psk_len == 0) |
| - { |
| - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, |
| - SSL_R_PSK_IDENTITY_NOT_FOUND); |
| - goto psk_err; |
| - } |
| - |
| - /* create PSK pre_master_secret */ |
| - pre_ms_len = 2+psk_len+2+psk_len; |
| - t = psk_or_pre_ms; |
| - memmove(psk_or_pre_ms+psk_len+4, psk_or_pre_ms, psk_len); |
| - s2n(psk_len, t); |
| - memset(t, 0, psk_len); |
| - t+=psk_len; |
| - s2n(psk_len, t); |
| - |
| - if (s->session->psk_identity_hint != NULL) |
| - OPENSSL_free(s->session->psk_identity_hint); |
| - s->session->psk_identity_hint = BUF_strdup(s->ctx->psk_identity_hint); |
| - if (s->ctx->psk_identity_hint != NULL && |
| - s->session->psk_identity_hint == NULL) |
| - { |
| - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, |
| - ERR_R_MALLOC_FAILURE); |
| - goto psk_err; |
| - } |
| - |
| - if (s->session->psk_identity != NULL) |
| - OPENSSL_free(s->session->psk_identity); |
| - s->session->psk_identity = BUF_strdup(identity); |
| - if (s->session->psk_identity == NULL) |
| - { |
| - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, |
| - ERR_R_MALLOC_FAILURE); |
| - goto psk_err; |
| - } |
| - |
| - s->session->master_key_length = |
| - s->method->ssl3_enc->generate_master_secret(s, |
| - s->session->master_key, |
| - psk_or_pre_ms, pre_ms_len); |
| - n = strlen(identity); |
| - s2n(n, p); |
| - memcpy(p, identity, n); |
| - n+=2; |
| - psk_err = 0; |
| - psk_err: |
| - OPENSSL_cleanse(identity, PSK_MAX_IDENTITY_LEN); |
| - OPENSSL_cleanse(psk_or_pre_ms, sizeof(psk_or_pre_ms)); |
| - if (psk_err != 0) |
| - { |
| - ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); |
| - goto err; |
| - } |
| - } |
| -#endif |
| - else |
| + else if (!(alg_k & SSL_kPSK) || ((alg_k & SSL_kPSK) && !(alg_a & SSL_aPSK))) |
| { |
| ssl3_send_alert(s, SSL3_AL_FATAL, |
| SSL_AD_HANDSHAKE_FAILURE); |
| @@ -3274,7 +3332,7 @@ int ssl3_check_cert_and_algorithm(SSL *s) |
| alg_a=s->s3->tmp.new_cipher->algorithm_auth; |
| |
| /* we don't have a certificate */ |
| - if ((alg_a & (SSL_aDH|SSL_aNULL|SSL_aKRB5)) || (alg_k & SSL_kPSK)) |
| + if ((alg_a & (SSL_aDH|SSL_aNULL|SSL_aKRB5)) || ((alg_a & SSL_aPSK) && !(alg_k & SSL_kRSA))) |
| return(1); |
| |
| sc=s->session->sess_cert; |
| diff --git a/ssl/s3_enc.c b/ssl/s3_enc.c |
| index 6358e1b..0dac7e7 100644 |
| --- a/ssl/s3_enc.c |
| +++ b/ssl/s3_enc.c |
| @@ -734,7 +734,7 @@ int n_ssl3_mac(SSL *ssl, unsigned char *md, int send) |
| } |
| |
| t=EVP_MD_CTX_size(hash); |
| - if (t < 0) |
| + if (t < 0 || t > 20) |
| return -1; |
| md_size=t; |
| npad=(48/md_size)*md_size; |
| diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c |
| index 1d87ac5..77244d3 100644 |
| --- a/ssl/s3_lib.c |
| +++ b/ssl/s3_lib.c |
| @@ -2827,6 +2827,42 @@ OPENSSL_GLOBAL SSL_CIPHER ssl3_ciphers[]={ |
| 256, |
| }, |
| |
| +#ifndef OPENSSL_NO_PSK |
| + /* ECDH PSK ciphersuites from RFC 5489 */ |
| + |
| + /* Cipher C037 */ |
| + { |
| + 1, |
| + TLS1_TXT_ECDHE_PSK_WITH_AES_128_CBC_SHA256, |
| + TLS1_CK_ECDHE_PSK_WITH_AES_128_CBC_SHA256, |
| + SSL_kEECDH, |
| + SSL_aPSK, |
| + SSL_AES128, |
| + SSL_SHA256, |
| + SSL_TLSV1, |
| + SSL_NOT_EXP|SSL_HIGH, |
| + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF_SHA256, |
| + 128, |
| + 128, |
| + }, |
| + |
| + /* Cipher C038 */ |
| + { |
| + 1, |
| + TLS1_TXT_ECDHE_PSK_WITH_AES_256_CBC_SHA384, |
| + TLS1_CK_ECDHE_PSK_WITH_AES_256_CBC_SHA384, |
| + SSL_kEECDH, |
| + SSL_aPSK, |
| + SSL_AES256, |
| + SSL_SHA384, |
| + SSL_TLSV1, |
| + SSL_NOT_EXP|SSL_HIGH, |
| + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF_SHA384, |
| + 256, |
| + 256, |
| + }, |
| +#endif /* OPENSSL_NO_PSK */ |
| + |
| #endif /* OPENSSL_NO_ECDH */ |
| |
| |
| @@ -3979,7 +3999,7 @@ SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt, |
| #endif /* OPENSSL_NO_KRB5 */ |
| #ifndef OPENSSL_NO_PSK |
| /* with PSK there must be server callback set */ |
| - if ((alg_k & SSL_kPSK) && s->psk_server_callback == NULL) |
| + if ((alg_a & SSL_aPSK) && s->psk_server_callback == NULL) |
| continue; |
| #endif /* OPENSSL_NO_PSK */ |
| |
| diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c |
| index 9335eda..fe70124 100644 |
| --- a/ssl/s3_srvr.c |
| +++ b/ssl/s3_srvr.c |
| @@ -217,6 +217,7 @@ int ssl3_accept(SSL *s) |
| { |
| BUF_MEM *buf; |
| unsigned long alg_k,Time=(unsigned long)time(NULL); |
| + unsigned long alg_a; |
| void (*cb)(const SSL *ssl,int type,int val)=NULL; |
| int ret= -1; |
| int new_state,state,skip=0; |
| @@ -418,9 +419,11 @@ int ssl3_accept(SSL *s) |
| case SSL3_ST_SW_CERT_A: |
| case SSL3_ST_SW_CERT_B: |
| /* Check if it is anon DH or anon ECDH, */ |
| - /* normal PSK or KRB5 or SRP */ |
| + /* non-RSA PSK or KRB5 or SRP */ |
| if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL) |
| - && !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK) |
| + /* Among PSK ciphersuites only RSA_PSK uses server certificate */ |
| + && !(s->s3->tmp.new_cipher->algorithm_auth & SSL_aPSK && |
| + !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kRSA)) |
| && !(s->s3->tmp.new_cipher->algorithm_auth & SSL_aKRB5)) |
| { |
| ret=ssl3_send_server_certificate(s); |
| @@ -449,6 +452,7 @@ int ssl3_accept(SSL *s) |
| case SSL3_ST_SW_KEY_EXCH_A: |
| case SSL3_ST_SW_KEY_EXCH_B: |
| alg_k = s->s3->tmp.new_cipher->algorithm_mkey; |
| + alg_a = s->s3->tmp.new_cipher->algorithm_auth; |
| |
| /* clear this, it may get reset by |
| * send_server_key_exchange */ |
| @@ -478,10 +482,12 @@ int ssl3_accept(SSL *s) |
| * public key for key exchange. |
| */ |
| if (s->s3->tmp.use_rsa_tmp |
| - /* PSK: send ServerKeyExchange if PSK identity |
| - * hint if provided */ |
| + /* PSK: send ServerKeyExchange if either: |
| + * - PSK identity hint is provided, or |
| + * - the key exchange is kEECDH. |
| + */ |
| #ifndef OPENSSL_NO_PSK |
| - || ((alg_k & SSL_kPSK) && s->ctx->psk_identity_hint) |
| + || ((alg_a & SSL_aPSK) && ((alg_k & SSL_kEECDH) || s->ctx->psk_identity_hint)) |
| #endif |
| #ifndef OPENSSL_NO_SRP |
| /* SRP: send ServerKeyExchange */ |
| @@ -1658,7 +1664,8 @@ int ssl3_send_server_key_exchange(SSL *s) |
| const EVP_MD *md = NULL; |
| unsigned char *p,*d; |
| int al,i; |
| - unsigned long type; |
| + unsigned long alg_k; |
| + unsigned long alg_a; |
| int n; |
| CERT *cert; |
| BIGNUM *r[4]; |
| @@ -1669,15 +1676,25 @@ int ssl3_send_server_key_exchange(SSL *s) |
| EVP_MD_CTX_init(&md_ctx); |
| if (s->state == SSL3_ST_SW_KEY_EXCH_A) |
| { |
| - type=s->s3->tmp.new_cipher->algorithm_mkey; |
| + alg_k=s->s3->tmp.new_cipher->algorithm_mkey; |
| + alg_a=s->s3->tmp.new_cipher->algorithm_auth; |
| cert=s->cert; |
| |
| buf=s->init_buf; |
| |
| r[0]=r[1]=r[2]=r[3]=NULL; |
| n=0; |
| +#ifndef OPENSSL_NO_PSK |
| + if (alg_a & SSL_aPSK) |
| + { |
| + /* size for PSK identity hint */ |
| + n+=2; |
| + if (s->ctx->psk_identity_hint) |
| + n+=strlen(s->ctx->psk_identity_hint); |
| + } |
| +#endif /* !OPENSSL_NO_PSK */ |
| #ifndef OPENSSL_NO_RSA |
| - if (type & SSL_kRSA) |
| + if (alg_k & SSL_kRSA) |
| { |
| rsa=cert->rsa_tmp; |
| if ((rsa == NULL) && (s->cert->rsa_tmp_cb != NULL)) |
| @@ -1704,10 +1721,9 @@ int ssl3_send_server_key_exchange(SSL *s) |
| r[1]=rsa->e; |
| s->s3->tmp.use_rsa_tmp=1; |
| } |
| - else |
| #endif |
| #ifndef OPENSSL_NO_DH |
| - if (type & SSL_kEDH) |
| + else if (alg_k & SSL_kEDH) |
| { |
| dhp=cert->dh_tmp; |
| if ((dhp == NULL) && (s->cert->dh_tmp_cb != NULL)) |
| @@ -1760,10 +1776,9 @@ int ssl3_send_server_key_exchange(SSL *s) |
| r[1]=dh->g; |
| r[2]=dh->pub_key; |
| } |
| - else |
| #endif |
| #ifndef OPENSSL_NO_ECDH |
| - if (type & SSL_kEECDH) |
| + else if (alg_k & SSL_kEECDH) |
| { |
| const EC_GROUP *group; |
| |
| @@ -1876,7 +1891,7 @@ int ssl3_send_server_key_exchange(SSL *s) |
| * to encode the entire ServerECDHParams |
| * structure. |
| */ |
| - n = 4 + encodedlen; |
| + n += 4 + encodedlen; |
| |
| /* We'll generate the serverKeyExchange message |
| * explicitly so we can set these to NULLs |
| @@ -1886,18 +1901,9 @@ int ssl3_send_server_key_exchange(SSL *s) |
| r[2]=NULL; |
| r[3]=NULL; |
| } |
| - else |
| #endif /* !OPENSSL_NO_ECDH */ |
| -#ifndef OPENSSL_NO_PSK |
| - if (type & SSL_kPSK) |
| - { |
| - /* reserve size for record length and PSK identity hint*/ |
| - n+=2+strlen(s->ctx->psk_identity_hint); |
| - } |
| - else |
| -#endif /* !OPENSSL_NO_PSK */ |
| #ifndef OPENSSL_NO_SRP |
| - if (type & SSL_kSRP) |
| + else if (alg_k & SSL_kSRP) |
| { |
| if ((s->srp_ctx.N == NULL) || |
| (s->srp_ctx.g == NULL) || |
| @@ -1912,8 +1918,8 @@ int ssl3_send_server_key_exchange(SSL *s) |
| r[2]=s->srp_ctx.s; |
| r[3]=s->srp_ctx.B; |
| } |
| - else |
| #endif |
| + else if (!(alg_k & SSL_kPSK)) |
| { |
| al=SSL_AD_HANDSHAKE_FAILURE; |
| SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE); |
| @@ -1923,15 +1929,16 @@ int ssl3_send_server_key_exchange(SSL *s) |
| { |
| nr[i]=BN_num_bytes(r[i]); |
| #ifndef OPENSSL_NO_SRP |
| - if ((i == 2) && (type & SSL_kSRP)) |
| + if ((i == 2) && (alg_k & SSL_kSRP)) |
| n+=1+nr[i]; |
| else |
| #endif |
| n+=2+nr[i]; |
| } |
| |
| - if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL) |
| - && !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)) |
| + if (!(alg_a & SSL_aNULL) |
| + /* Among PSK ciphersuites only RSA uses a certificate */ |
| + && !((alg_a & SSL_aPSK) && !(alg_k & SSL_kRSA))) |
| { |
| if ((pkey=ssl_get_sign_pkey(s,s->s3->tmp.new_cipher,&md)) |
| == NULL) |
| @@ -1958,7 +1965,7 @@ int ssl3_send_server_key_exchange(SSL *s) |
| for (i=0; i < 4 && r[i] != NULL; i++) |
| { |
| #ifndef OPENSSL_NO_SRP |
| - if ((i == 2) && (type & SSL_kSRP)) |
| + if ((i == 2) && (alg_k & SSL_kSRP)) |
| { |
| *p = nr[i]; |
| p++; |
| @@ -1970,8 +1977,32 @@ int ssl3_send_server_key_exchange(SSL *s) |
| p+=nr[i]; |
| } |
| |
| +/* Note: ECDHE PSK ciphersuites use SSL_kEECDH and SSL_aPSK. |
| + * When one of them is used, the server key exchange record needs to have both |
| + * the psk_identity_hint and the ServerECDHParams. */ |
| +#ifndef OPENSSL_NO_PSK |
| + if (alg_a & SSL_aPSK) |
| + { |
| + if (s->ctx->psk_identity_hint) |
| + { |
| + /* copy PSK identity hint */ |
| + s2n(strlen(s->ctx->psk_identity_hint), p); |
| + strncpy((char *)p, s->ctx->psk_identity_hint, strlen(s->ctx->psk_identity_hint)); |
| + p+=strlen(s->ctx->psk_identity_hint); |
| + } |
| + else |
| + { |
| + /* No identity hint is provided. */ |
| + *p = 0; |
| + p += 1; |
| + *p = 0; |
| + p += 1; |
| + } |
| + } |
| +#endif /* OPENSSL_NO_PSK */ |
| + |
| #ifndef OPENSSL_NO_ECDH |
| - if (type & SSL_kEECDH) |
| + if (alg_k & SSL_kEECDH) |
| { |
| /* XXX: For now, we only support named (not generic) curves. |
| * In this situation, the serverKeyExchange message has: |
| @@ -1994,17 +2025,7 @@ int ssl3_send_server_key_exchange(SSL *s) |
| encodedPoint = NULL; |
| p += encodedlen; |
| } |
| -#endif |
| - |
| -#ifndef OPENSSL_NO_PSK |
| - if (type & SSL_kPSK) |
| - { |
| - /* copy PSK identity hint */ |
| - s2n(strlen(s->ctx->psk_identity_hint), p); |
| - strncpy((char *)p, s->ctx->psk_identity_hint, strlen(s->ctx->psk_identity_hint)); |
| - p+=strlen(s->ctx->psk_identity_hint); |
| - } |
| -#endif |
| +#endif /* OPENSSL_NO_ECDH */ |
| |
| /* not anonymous */ |
| if (pkey != NULL) |
| @@ -2041,7 +2062,7 @@ int ssl3_send_server_key_exchange(SSL *s) |
| n+=u+2; |
| } |
| else |
| -#endif |
| +#endif /* OPENSSL_NO_RSA */ |
| if (md) |
| { |
| /* For TLS1.2 and later send signature |
| @@ -2215,6 +2236,7 @@ int ssl3_get_client_key_exchange(SSL *s) |
| int i,al,ok; |
| long n; |
| unsigned long alg_k; |
| + unsigned long alg_a; |
| unsigned char *p; |
| #ifndef OPENSSL_NO_RSA |
| RSA *rsa=NULL; |
| @@ -2232,7 +2254,11 @@ int ssl3_get_client_key_exchange(SSL *s) |
| EC_KEY *srvr_ecdh = NULL; |
| EVP_PKEY *clnt_pub_pkey = NULL; |
| EC_POINT *clnt_ecpoint = NULL; |
| - BN_CTX *bn_ctx = NULL; |
| + BN_CTX *bn_ctx = NULL; |
| +#ifndef OPENSSL_NO_PSK |
| + unsigned int psk_len = 0; |
| + unsigned char psk[PSK_MAX_PSK_LEN]; |
| +#endif /* OPENSSL_NO_PSK */ |
| #endif |
| |
| n=s->method->ssl_get_message(s, |
| @@ -2246,7 +2272,106 @@ int ssl3_get_client_key_exchange(SSL *s) |
| p=(unsigned char *)s->init_msg; |
| |
| alg_k=s->s3->tmp.new_cipher->algorithm_mkey; |
| + alg_a=s->s3->tmp.new_cipher->algorithm_auth; |
| + |
| +#ifndef OPENSSL_NO_PSK |
| + if (alg_a & SSL_aPSK) |
| + { |
| + unsigned char *t = NULL; |
| + unsigned char pre_ms[PSK_MAX_PSK_LEN*2+4]; |
| + unsigned int pre_ms_len = 0; |
| + int psk_err = 1; |
| + char tmp_id[PSK_MAX_IDENTITY_LEN+1]; |
| + |
| + al=SSL_AD_HANDSHAKE_FAILURE; |
| + |
| + n2s(p, i); |
| + if (n != i+2 && !(alg_k & SSL_kEECDH)) |
| + { |
| + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, |
| + SSL_R_LENGTH_MISMATCH); |
| + goto psk_err; |
| + } |
| + if (i > PSK_MAX_IDENTITY_LEN) |
| + { |
| + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, |
| + SSL_R_DATA_LENGTH_TOO_LONG); |
| + goto psk_err; |
| + } |
| + if (s->psk_server_callback == NULL) |
| + { |
| + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, |
| + SSL_R_PSK_NO_SERVER_CB); |
| + goto psk_err; |
| + } |
| + |
| + /* Create guaranteed NUL-terminated identity |
| + * string for the callback */ |
| + memcpy(tmp_id, p, i); |
| + memset(tmp_id+i, 0, PSK_MAX_IDENTITY_LEN+1-i); |
| + psk_len = s->psk_server_callback(s, tmp_id, psk, sizeof(psk)); |
| |
| + if (psk_len > PSK_MAX_PSK_LEN) |
| + { |
| + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, |
| + ERR_R_INTERNAL_ERROR); |
| + goto psk_err; |
| + } |
| + else if (psk_len == 0) |
| + { |
| + /* PSK related to the given identity not found */ |
| + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, |
| + SSL_R_PSK_IDENTITY_NOT_FOUND); |
| + al=SSL_AD_UNKNOWN_PSK_IDENTITY; |
| + goto psk_err; |
| + } |
| + if (!(alg_k & SSL_kEECDH)) |
| + { |
| + /* Create the shared secret now if we're not using ECDHE-PSK.*/ |
| + pre_ms_len=2+psk_len+2+psk_len; |
| + t = pre_ms; |
| + s2n(psk_len, t); |
| + memset(t, 0, psk_len); |
| + t+=psk_len; |
| + s2n(psk_len, t); |
| + memcpy(t, psk, psk_len); |
| + |
| + s->session->master_key_length= |
| + s->method->ssl3_enc->generate_master_secret(s, |
| + s->session->master_key, pre_ms, pre_ms_len); |
| + } |
| + if (s->session->psk_identity != NULL) |
| + OPENSSL_free(s->session->psk_identity); |
| + s->session->psk_identity = BUF_strdup(tmp_id); |
| + OPENSSL_cleanse(tmp_id, PSK_MAX_IDENTITY_LEN+1); |
| + if (s->session->psk_identity == NULL) |
| + { |
| + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, |
| + ERR_R_MALLOC_FAILURE); |
| + goto psk_err; |
| + } |
| + |
| + if (s->session->psk_identity_hint != NULL) |
| + OPENSSL_free(s->session->psk_identity_hint); |
| + s->session->psk_identity_hint = BUF_strdup(s->ctx->psk_identity_hint); |
| + if (s->ctx->psk_identity_hint != NULL && |
| + s->session->psk_identity_hint == NULL) |
| + { |
| + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, |
| + ERR_R_MALLOC_FAILURE); |
| + goto psk_err; |
| + } |
| + |
| + p += i; |
| + n -= (i + 2); |
| + psk_err = 0; |
| + psk_err: |
| + OPENSSL_cleanse(pre_ms, sizeof(pre_ms)); |
| + if (psk_err != 0) |
| + goto f_err; |
| + } |
| +#endif /* OPENSSL_NO_PSK */ |
| + if (0) {} |
| #ifndef OPENSSL_NO_RSA |
| if (alg_k & SSL_kRSA) |
| { |
| @@ -2410,10 +2535,9 @@ int ssl3_get_client_key_exchange(SSL *s) |
| p,sizeof(rand_premaster_secret)); |
| OPENSSL_cleanse(p,sizeof(rand_premaster_secret)); |
| } |
| - else |
| #endif |
| #ifndef OPENSSL_NO_DH |
| - if (alg_k & (SSL_kEDH|SSL_kDHr|SSL_kDHd)) |
| + else if (alg_k & (SSL_kEDH|SSL_kDHr|SSL_kDHd)) |
| { |
| n2s(p,i); |
| if (n != i+2) |
| @@ -2474,10 +2598,9 @@ int ssl3_get_client_key_exchange(SSL *s) |
| s->session->master_key,p,i); |
| OPENSSL_cleanse(p,i); |
| } |
| - else |
| #endif |
| #ifndef OPENSSL_NO_KRB5 |
| - if (alg_k & SSL_kKRB5) |
| + else if (alg_k & SSL_kKRB5) |
| { |
| krb5_error_code krb5rc; |
| krb5_data enc_ticket; |
| @@ -2666,17 +2789,20 @@ int ssl3_get_client_key_exchange(SSL *s) |
| ** if (s->kssl_ctx) s->kssl_ctx = NULL; |
| */ |
| } |
| - else |
| #endif /* OPENSSL_NO_KRB5 */ |
| - |
| #ifndef OPENSSL_NO_ECDH |
| - if (alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe)) |
| + else if (alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe)) |
| { |
| int ret = 1; |
| int field_size = 0; |
| const EC_KEY *tkey; |
| const EC_GROUP *group; |
| const BIGNUM *priv_key; |
| +#ifndef OPENSSL_NO_PSK |
| + unsigned char *pre_ms; |
| + unsigned int pre_ms_len; |
| + unsigned char *t; |
| +#endif /* OPENSSL_NO_PSK */ |
| |
| /* initialize structures for server's ECDH key pair */ |
| if ((srvr_ecdh = EC_KEY_new()) == NULL) |
| @@ -2772,7 +2898,7 @@ int ssl3_get_client_key_exchange(SSL *s) |
| } |
| |
| /* Get encoded point length */ |
| - i = *p; |
| + i = *p; |
| p += 1; |
| if (n != 1 + i) |
| { |
| @@ -2814,214 +2940,145 @@ int ssl3_get_client_key_exchange(SSL *s) |
| EC_KEY_free(srvr_ecdh); |
| BN_CTX_free(bn_ctx); |
| EC_KEY_free(s->s3->tmp.ecdh); |
| - s->s3->tmp.ecdh = NULL; |
| + s->s3->tmp.ecdh = NULL; |
| |
| - /* Compute the master secret */ |
| - s->session->master_key_length = s->method->ssl3_enc-> \ |
| - generate_master_secret(s, s->session->master_key, p, i); |
| - |
| - OPENSSL_cleanse(p, i); |
| - return (ret); |
| - } |
| - else |
| -#endif |
| #ifndef OPENSSL_NO_PSK |
| - if (alg_k & SSL_kPSK) |
| + /* ECDHE PSK ciphersuites from RFC 5489 */ |
| + if ((alg_a & SSL_aPSK) && psk_len != 0) |
| { |
| - unsigned char *t = NULL; |
| - unsigned char psk_or_pre_ms[PSK_MAX_PSK_LEN*2+4]; |
| - unsigned int pre_ms_len = 0, psk_len = 0; |
| - int psk_err = 1; |
| - char tmp_id[PSK_MAX_IDENTITY_LEN+1]; |
| - |
| - al=SSL_AD_HANDSHAKE_FAILURE; |
| - |
| - n2s(p,i); |
| - if (n != i+2) |
| - { |
| - SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, |
| - SSL_R_LENGTH_MISMATCH); |
| - goto psk_err; |
| - } |
| - if (i > PSK_MAX_IDENTITY_LEN) |
| - { |
| - SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, |
| - SSL_R_DATA_LENGTH_TOO_LONG); |
| - goto psk_err; |
| - } |
| - if (s->psk_server_callback == NULL) |
| - { |
| - SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, |
| - SSL_R_PSK_NO_SERVER_CB); |
| - goto psk_err; |
| - } |
| - |
| - /* Create guaranteed NULL-terminated identity |
| - * string for the callback */ |
| - memcpy(tmp_id, p, i); |
| - memset(tmp_id+i, 0, PSK_MAX_IDENTITY_LEN+1-i); |
| - psk_len = s->psk_server_callback(s, tmp_id, |
| - psk_or_pre_ms, sizeof(psk_or_pre_ms)); |
| - OPENSSL_cleanse(tmp_id, PSK_MAX_IDENTITY_LEN+1); |
| - |
| - if (psk_len > PSK_MAX_PSK_LEN) |
| - { |
| - SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, |
| - ERR_R_INTERNAL_ERROR); |
| - goto psk_err; |
| - } |
| - else if (psk_len == 0) |
| - { |
| - /* PSK related to the given identity not found */ |
| - SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, |
| - SSL_R_PSK_IDENTITY_NOT_FOUND); |
| - al=SSL_AD_UNKNOWN_PSK_IDENTITY; |
| - goto psk_err; |
| - } |
| - |
| - /* create PSK pre_master_secret */ |
| - pre_ms_len=2+psk_len+2+psk_len; |
| - t = psk_or_pre_ms; |
| - memmove(psk_or_pre_ms+psk_len+4, psk_or_pre_ms, psk_len); |
| - s2n(psk_len, t); |
| - memset(t, 0, psk_len); |
| - t+=psk_len; |
| - s2n(psk_len, t); |
| - |
| - if (s->session->psk_identity != NULL) |
| - OPENSSL_free(s->session->psk_identity); |
| - s->session->psk_identity = BUF_strdup((char *)p); |
| - if (s->session->psk_identity == NULL) |
| - { |
| - SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, |
| - ERR_R_MALLOC_FAILURE); |
| - goto psk_err; |
| - } |
| - |
| - if (s->session->psk_identity_hint != NULL) |
| - OPENSSL_free(s->session->psk_identity_hint); |
| - s->session->psk_identity_hint = BUF_strdup(s->ctx->psk_identity_hint); |
| - if (s->ctx->psk_identity_hint != NULL && |
| - s->session->psk_identity_hint == NULL) |
| + pre_ms_len = 2+i+2+psk_len; |
| + pre_ms = OPENSSL_malloc(pre_ms_len); |
| + if (pre_ms == NULL) |
| { |
| SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, |
| ERR_R_MALLOC_FAILURE); |
| - goto psk_err; |
| + goto err; |
| } |
| - |
| - s->session->master_key_length= |
| - s->method->ssl3_enc->generate_master_secret(s, |
| - s->session->master_key, psk_or_pre_ms, pre_ms_len); |
| - psk_err = 0; |
| - psk_err: |
| - OPENSSL_cleanse(psk_or_pre_ms, sizeof(psk_or_pre_ms)); |
| - if (psk_err != 0) |
| - goto f_err; |
| + memset(pre_ms, 0, pre_ms_len); |
| + t = pre_ms; |
| + s2n(i, t); |
| + memcpy(t, p, i); |
| + t += i; |
| + s2n(psk_len, t); |
| + memcpy(t, psk, psk_len); |
| + s->session->master_key_length = s->method->ssl3_enc \ |
| + -> generate_master_secret(s, |
| + s->session->master_key, pre_ms, pre_ms_len); |
| + OPENSSL_cleanse(pre_ms, pre_ms_len); |
| + OPENSSL_free(pre_ms); |
| } |
| - else |
| -#endif |
| -#ifndef OPENSSL_NO_SRP |
| - if (alg_k & SSL_kSRP) |
| +#endif /* OPENSSL_NO_PSK */ |
| + if (!(alg_a & SSL_aPSK)) |
| { |
| - int param_len; |
| - |
| - n2s(p,i); |
| - param_len=i+2; |
| - if (param_len > n) |
| - { |
| - al=SSL_AD_DECODE_ERROR; |
| - SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_BAD_SRP_A_LENGTH); |
| - goto f_err; |
| - } |
| - if (!(s->srp_ctx.A=BN_bin2bn(p,i,NULL))) |
| - { |
| - SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,ERR_R_BN_LIB); |
| - goto err; |
| - } |
| - if (s->session->srp_username != NULL) |
| - OPENSSL_free(s->session->srp_username); |
| - s->session->srp_username = BUF_strdup(s->srp_ctx.login); |
| - if (s->session->srp_username == NULL) |
| - { |
| - SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, |
| - ERR_R_MALLOC_FAILURE); |
| - goto err; |
| - } |
| + /* Compute the master secret */ |
| + s->session->master_key_length = s->method->ssl3_enc \ |
| + -> generate_master_secret(s, |
| + s->session->master_key, p, i); |
| + } |
| |
| - if ((s->session->master_key_length = SRP_generate_server_master_secret(s,s->session->master_key))<0) |
| - { |
| - SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR); |
| - goto err; |
| - } |
| + OPENSSL_cleanse(p, i); |
| + } |
| +#endif |
| +#ifndef OPENSSL_NO_SRP |
| + else if (alg_k & SSL_kSRP) |
| + { |
| + int param_len; |
| |
| - p+=i; |
| + n2s(p,i); |
| + param_len=i+2; |
| + if (param_len > n) |
| + { |
| + al=SSL_AD_DECODE_ERROR; |
| + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_BAD_SRP_A_LENGTH); |
| + goto f_err; |
| + } |
| + if (!(s->srp_ctx.A=BN_bin2bn(p,i,NULL))) |
| + { |
| + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,ERR_R_BN_LIB); |
| + goto err; |
| + } |
| + if (s->session->srp_username != NULL) |
| + OPENSSL_free(s->session->srp_username); |
| + s->session->srp_username = BUF_strdup(s->srp_ctx.login); |
| + if (s->session->srp_username == NULL) |
| + { |
| + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, |
| + ERR_R_MALLOC_FAILURE); |
| + goto err; |
| } |
| - else |
| -#endif /* OPENSSL_NO_SRP */ |
| - if (alg_k & SSL_kGOST) |
| - { |
| - int ret = 0; |
| - EVP_PKEY_CTX *pkey_ctx; |
| - EVP_PKEY *client_pub_pkey = NULL, *pk = NULL; |
| - unsigned char premaster_secret[32], *start; |
| - size_t outlen=32, inlen; |
| - unsigned long alg_a; |
| - int Ttag, Tclass; |
| - long Tlen; |
| - |
| - /* Get our certificate private key*/ |
| - alg_a = s->s3->tmp.new_cipher->algorithm_auth; |
| - if (alg_a & SSL_aGOST94) |
| - pk = s->cert->pkeys[SSL_PKEY_GOST94].privatekey; |
| - else if (alg_a & SSL_aGOST01) |
| - pk = s->cert->pkeys[SSL_PKEY_GOST01].privatekey; |
| |
| - pkey_ctx = EVP_PKEY_CTX_new(pk,NULL); |
| - EVP_PKEY_decrypt_init(pkey_ctx); |
| - /* If client certificate is present and is of the same type, maybe |
| - * use it for key exchange. Don't mind errors from |
| - * EVP_PKEY_derive_set_peer, because it is completely valid to use |
| - * a client certificate for authorization only. */ |
| - client_pub_pkey = X509_get_pubkey(s->session->peer); |
| - if (client_pub_pkey) |
| - { |
| - if (EVP_PKEY_derive_set_peer(pkey_ctx, client_pub_pkey) <= 0) |
| - ERR_clear_error(); |
| - } |
| - /* Decrypt session key */ |
| - if (ASN1_get_object((const unsigned char **)&p, &Tlen, &Ttag, &Tclass, n) != V_ASN1_CONSTRUCTED || |
| - Ttag != V_ASN1_SEQUENCE || |
| - Tclass != V_ASN1_UNIVERSAL) |
| - { |
| - SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_DECRYPTION_FAILED); |
| - goto gerr; |
| - } |
| - start = p; |
| - inlen = Tlen; |
| - if (EVP_PKEY_decrypt(pkey_ctx,premaster_secret,&outlen,start,inlen) <=0) |
| + if ((s->session->master_key_length = SRP_generate_server_master_secret(s,s->session->master_key))<0) |
| + { |
| + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR); |
| + goto err; |
| + } |
| |
| - { |
| - SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_DECRYPTION_FAILED); |
| - goto gerr; |
| - } |
| - /* Generate master secret */ |
| - s->session->master_key_length= |
| - s->method->ssl3_enc->generate_master_secret(s, |
| - s->session->master_key,premaster_secret,32); |
| - /* Check if pubkey from client certificate was used */ |
| - if (EVP_PKEY_CTX_ctrl(pkey_ctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 2, NULL) > 0) |
| - ret = 2; |
| - else |
| - ret = 1; |
| - gerr: |
| - EVP_PKEY_free(client_pub_pkey); |
| - EVP_PKEY_CTX_free(pkey_ctx); |
| - if (ret) |
| - return ret; |
| - else |
| - goto err; |
| + p+=i; |
| + } |
| +#endif /* OPENSSL_NO_SRP */ |
| + else if (alg_k & SSL_kGOST) |
| + { |
| + int ret = 0; |
| + EVP_PKEY_CTX *pkey_ctx; |
| + EVP_PKEY *client_pub_pkey = NULL, *pk = NULL; |
| + unsigned char premaster_secret[32], *start; |
| + size_t outlen=32, inlen; |
| + unsigned long alg_a; |
| + int Ttag, Tclass; |
| + long Tlen; |
| + |
| + /* Get our certificate private key*/ |
| + alg_a = s->s3->tmp.new_cipher->algorithm_auth; |
| + if (alg_a & SSL_aGOST94) |
| + pk = s->cert->pkeys[SSL_PKEY_GOST94].privatekey; |
| + else if (alg_a & SSL_aGOST01) |
| + pk = s->cert->pkeys[SSL_PKEY_GOST01].privatekey; |
| + |
| + pkey_ctx = EVP_PKEY_CTX_new(pk,NULL); |
| + EVP_PKEY_decrypt_init(pkey_ctx); |
| + /* If client certificate is present and is of the same type, maybe |
| + * use it for key exchange. Don't mind errors from |
| + * EVP_PKEY_derive_set_peer, because it is completely valid to use |
| + * a client certificate for authorization only. */ |
| + client_pub_pkey = X509_get_pubkey(s->session->peer); |
| + if (client_pub_pkey) |
| + { |
| + if (EVP_PKEY_derive_set_peer(pkey_ctx, client_pub_pkey) <= 0) |
| + ERR_clear_error(); |
| + } |
| + /* Decrypt session key */ |
| + if (ASN1_get_object((const unsigned char **)&p, &Tlen, &Ttag, &Tclass, n) != V_ASN1_CONSTRUCTED || |
| + Ttag != V_ASN1_SEQUENCE || |
| + Tclass != V_ASN1_UNIVERSAL) |
| + { |
| + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_DECRYPTION_FAILED); |
| + goto gerr; |
| + } |
| + start = p; |
| + inlen = Tlen; |
| + if (EVP_PKEY_decrypt(pkey_ctx,premaster_secret,&outlen,start,inlen) <=0) |
| + { |
| + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_DECRYPTION_FAILED); |
| + goto gerr; |
| } |
| + /* Generate master secret */ |
| + s->session->master_key_length= |
| + s->method->ssl3_enc->generate_master_secret(s, |
| + s->session->master_key,premaster_secret,32); |
| + /* Check if pubkey from client certificate was used */ |
| + if (EVP_PKEY_CTX_ctrl(pkey_ctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 2, NULL) > 0) |
| + ret = 2; |
| + else |
| + ret = 1; |
| + gerr: |
| + EVP_PKEY_free(client_pub_pkey); |
| + EVP_PKEY_CTX_free(pkey_ctx); |
| + if (ret) |
| + return ret; |
| else |
| + goto err; |
| + } |
| + else if (!(alg_k & SSL_kPSK)) |
| { |
| al=SSL_AD_HANDSHAKE_FAILURE; |
| SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, |
| diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c |
| index 0fda4ca..6c57d2a 100644 |
| --- a/ssl/ssl_lib.c |
| +++ b/ssl/ssl_lib.c |
| @@ -1424,7 +1424,7 @@ int ssl_cipher_list_to_bytes(SSL *s,STACK_OF(SSL_CIPHER) *sk,unsigned char *p, |
| #endif /* OPENSSL_NO_KRB5 */ |
| #ifndef OPENSSL_NO_PSK |
| /* with PSK there must be client callback set */ |
| - if (((c->algorithm_mkey & SSL_kPSK) || (c->algorithm_auth & SSL_aPSK)) && |
| + if ((c->algorithm_auth & SSL_aPSK) && |
| s->psk_client_callback == NULL) |
| continue; |
| #endif /* OPENSSL_NO_PSK */ |
| diff --git a/ssl/tls1.h b/ssl/tls1.h |
| index 9e035fb..3e6b7c7 100644 |
| --- a/ssl/tls1.h |
| +++ b/ssl/tls1.h |
| @@ -536,6 +536,10 @@ SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB,(void (*)(void))cb) |
| #define TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305 0x0300CC14 |
| #define TLS1_CK_DHE_RSA_CHACHA20_POLY1305 0x0300CC15 |
| |
| +/* ECDHE PSK ciphersuites from RFC 5489 */ |
| +#define TLS1_CK_ECDHE_PSK_WITH_AES_128_CBC_SHA256 0x0300C037 |
| +#define TLS1_CK_ECDHE_PSK_WITH_AES_256_CBC_SHA384 0x0300C038 |
| + |
| /* XXX |
| * Inconsistency alert: |
| * The OpenSSL names of ciphers with ephemeral DH here include the string |
| @@ -691,6 +698,10 @@ SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB,(void (*)(void))cb) |
| #define TLS1_TXT_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 "ECDHE-ECDSA-CHACHA20-POLY1305" |
| #define TLS1_TXT_DHE_RSA_WITH_CHACHA20_POLY1305 "DHE-RSA-CHACHA20-POLY1305" |
| |
| +/* ECDHE PSK ciphersuites from RFC 5489 */ |
| +#define TLS1_TXT_ECDHE_PSK_WITH_AES_128_CBC_SHA256 "ECDHE-PSK-WITH-AES-128-CBC-SHA256" |
| +#define TLS1_TXT_ECDHE_PSK_WITH_AES_256_CBC_SHA384 "ECDHE-PSK-WITH-AES-256-CBC-SHA384" |
| + |
| #define TLS_CT_RSA_SIGN 1 |
| #define TLS_CT_DSS_SIGN 2 |
| #define TLS_CT_RSA_FIXED_DH 3 |
| 2.0.0.526.g5318336 |
| |