Index: openssl/ssl/s3_srvr.c |
=================================================================== |
--- openssl/ssl/s3_srvr.c (revision 105093) |
+++ openssl/ssl/s3_srvr.c (working copy) |
@@ -1,4 +1,4 @@ |
-/* ssl/s3_srvr.c */ |
+/* ssl/s3_srvr.c -*- mode:C; c-file-style: "eay" -*- */ |
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) |
* All rights reserved. |
* |
@@ -56,7 +56,7 @@ |
* [including the GNU Public Licence.] |
*/ |
/* ==================================================================== |
- * Copyright (c) 1998-2005 The OpenSSL Project. All rights reserved. |
+ * Copyright (c) 1998-2007 The OpenSSL Project. All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
@@ -121,6 +121,32 @@ |
* Vipul Gupta and Sumit Gupta of Sun Microsystems Laboratories. |
* |
*/ |
+/* ==================================================================== |
+ * Copyright 2005 Nokia. All rights reserved. |
+ * |
+ * The portions of the attached software ("Contribution") is developed by |
+ * Nokia Corporation and is licensed pursuant to the OpenSSL open source |
+ * license. |
+ * |
+ * The Contribution, originally written by Mika Kousa and Pasi Eronen of |
+ * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites |
+ * support (see RFC 4279) to OpenSSL. |
+ * |
+ * No patent licenses or other rights except those expressly stated in |
+ * the OpenSSL open source license shall be deemed granted or received |
+ * expressly, by implication, estoppel, or otherwise. |
+ * |
+ * No assurances are provided by Nokia that the Contribution does not |
+ * infringe the patent or other intellectual property rights of any third |
+ * party or that the license provides you with all the necessary rights |
+ * to make use of the Contribution. |
+ * |
+ * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN |
+ * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA |
+ * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY |
+ * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR |
+ * OTHERWISE. |
+ */ |
#define REUSE_CIPHER_BUG |
#define NETSCAPE_HANG_BUG |
@@ -143,15 +169,9 @@ |
#endif |
#include <openssl/md5.h> |
-#include "fnv1a64.h" |
+static const SSL_METHOD *ssl3_get_server_method(int ver); |
-static SSL_METHOD *ssl3_get_server_method(int ver); |
-static int ssl3_snap_start_evaluate_handshake(SSL* s); |
-#ifndef OPENSSL_NO_ECDH |
-static int nid2curve_id(int nid); |
-#endif |
- |
-static SSL_METHOD *ssl3_get_server_method(int ver) |
+static const SSL_METHOD *ssl3_get_server_method(int ver) |
{ |
if (ver == SSL3_VERSION) |
return(SSLv3_server_method()); |
@@ -167,7 +187,7 @@ |
int ssl3_accept(SSL *s) |
{ |
BUF_MEM *buf; |
- unsigned long l,Time=(unsigned long)time(NULL); |
+ unsigned long alg_k,Time=(unsigned long)time(NULL); |
void (*cb)(const SSL *ssl,int type,int val)=NULL; |
int ret= -1; |
int new_state,state,skip=0; |
@@ -238,6 +258,7 @@ |
} |
s->init_num=0; |
+ s->s3->flags &= ~SSL3_FLAGS_SGC_RESTART_DONE; |
if (s->state != SSL_ST_RENEGOTIATE) |
{ |
@@ -295,6 +316,7 @@ |
s->shutdown=0; |
ret=ssl3_get_client_hello(s); |
if (ret <= 0) goto end; |
+ |
s->new_session = 2; |
s->state=SSL3_ST_SW_SRVR_HELLO_A; |
s->init_num=0; |
@@ -303,36 +325,10 @@ |
case SSL3_ST_SW_SRVR_HELLO_A: |
case SSL3_ST_SW_SRVR_HELLO_B: |
ret=ssl3_send_server_hello(s); |
- if (ret == SERVER_RANDOM_VALIDATION_PENDING) |
- { |
- s->rwstate = SSL_SERVER_RANDOM_VALIDATE; |
- s->state = SSL3_ST_SW_SRVR_HELLO_A; |
- s->init_num = 0; |
- goto end; |
- } |
if (ret <= 0) goto end; |
#ifndef OPENSSL_NO_TLSEXT |
- if ((s->s3->tmp.new_cipher->algorithms & SSL_MKEY_MASK) != SSL_kRSA && |
- (s->s3->tmp.new_cipher->algorithms & SSL_MKEY_MASK) != SSL_kKRB5 && |
- (s->s3->tmp.new_cipher->algorithms & SSL_MKEY_MASK) != SSL_kDHr && |
- (s->s3->tmp.new_cipher->algorithms & SSL_MKEY_MASK) != SSL_kDHd && |
- (s->s3->tmp.new_cipher->algorithms & SSL_MKEY_MASK) != SSL_kECDH && |
- s->s3->snap_start_requested) |
- { |
- /* There's no point in carrying on with a Snap |
- * Start handshake if we're using a cipher |
- * suite which is going to send a |
- * ServerKeyExchange message. */ |
- ssl3_snap_start_reset_for_recovery(s); |
- s->state = SSL3_ST_SW_SRVR_HELLO_A; |
- break; |
- } |
- |
if (s->hit) |
{ |
- if (ssl3_snap_start_evaluate_handshake(s)) |
- break; |
- |
if (s->tlsext_ticket_expected) |
s->state=SSL3_ST_SW_SESSION_TICKET_A; |
else |
@@ -349,9 +345,11 @@ |
case SSL3_ST_SW_CERT_A: |
case SSL3_ST_SW_CERT_B: |
- /* Check if it is anon DH or anon ECDH or KRB5 */ |
- if (!(s->s3->tmp.new_cipher->algorithms & SSL_aNULL) |
- && !(s->s3->tmp.new_cipher->algorithms & SSL_aKRB5)) |
+ /* Check if it is anon DH or anon ECDH, */ |
+ /* normal PSK or KRB5 */ |
+ 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_aKRB5)) |
{ |
ret=ssl3_send_server_certificate(s); |
if (ret <= 0) goto end; |
@@ -378,13 +376,13 @@ |
case SSL3_ST_SW_KEY_EXCH_A: |
case SSL3_ST_SW_KEY_EXCH_B: |
- l=s->s3->tmp.new_cipher->algorithms; |
+ alg_k = s->s3->tmp.new_cipher->algorithm_mkey; |
/* clear this, it may get reset by |
* send_server_key_exchange */ |
if ((s->options & SSL_OP_EPHEMERAL_RSA) |
#ifndef OPENSSL_NO_KRB5 |
- && !(l & SSL_KRB5) |
+ && !(alg_k & SSL_kKRB5) |
#endif /* OPENSSL_NO_KRB5 */ |
) |
/* option SSL_OP_EPHEMERAL_RSA sends temporary RSA key |
@@ -399,16 +397,23 @@ |
/* only send if a DH key exchange, fortezza or |
* RSA but we have a sign only certificate |
* |
+ * PSK: may send PSK identity hints |
+ * |
* For ECC ciphersuites, we send a serverKeyExchange |
* message only if the cipher suite is either |
* ECDH-anon or ECDHE. In other cases, the |
- * server certificate contains the server's |
+ * server certificate contains the server's |
* public key for key exchange. |
*/ |
if (s->s3->tmp.use_rsa_tmp |
- || (l & SSL_kECDHE) |
- || (l & (SSL_DH|SSL_kFZA)) |
- || ((l & SSL_kRSA) |
+ /* PSK: send ServerKeyExchange if PSK identity |
+ * hint if provided */ |
+#ifndef OPENSSL_NO_PSK |
+ || ((alg_k & SSL_kPSK) && s->ctx->psk_identity_hint) |
+#endif |
+ || (alg_k & (SSL_kDHr|SSL_kDHd|SSL_kEDH)) |
+ || (alg_k & SSL_kEECDH) |
+ || ((alg_k & SSL_kRSA) |
&& (s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL |
|| (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) |
&& EVP_PKEY_size(s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey)*8 > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher) |
@@ -438,12 +443,15 @@ |
/* never request cert in anonymous ciphersuites |
* (see section "Certificate request" in SSL 3 drafts |
* and in RFC 2246): */ |
- ((s->s3->tmp.new_cipher->algorithms & SSL_aNULL) && |
+ ((s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL) && |
/* ... except when the application insists on verification |
* (against the specs, but s3_clnt.c accepts this for SSL 3) */ |
!(s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) || |
- /* never request cert in Kerberos ciphersuites */ |
- (s->s3->tmp.new_cipher->algorithms & SSL_aKRB5)) |
+ /* never request cert in Kerberos ciphersuites */ |
+ (s->s3->tmp.new_cipher->algorithm_auth & SSL_aKRB5) |
+ /* With normal PSK Certificates and |
+ * Certificate Requests are omitted */ |
+ || (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)) |
{ |
/* no cert request */ |
skip=1; |
@@ -469,19 +477,8 @@ |
case SSL3_ST_SW_SRVR_DONE_B: |
ret=ssl3_send_server_done(s); |
if (ret <= 0) goto end; |
- |
- if (s->s3->snap_start_requested) |
- { |
- if (ssl3_snap_start_evaluate_handshake(s)) |
- break; |
- s->state = SSL3_ST_SR_CERT_A; |
- } |
- else |
- { |
- s->s3->tmp.next_state=SSL3_ST_SR_CERT_A; |
- s->state=SSL3_ST_SW_FLUSH; |
- } |
- |
+ s->s3->tmp.next_state=SSL3_ST_SR_CERT_A; |
+ s->state=SSL3_ST_SW_FLUSH; |
s->init_num=0; |
break; |
@@ -530,7 +527,7 @@ |
case SSL3_ST_SR_KEY_EXCH_A: |
case SSL3_ST_SR_KEY_EXCH_B: |
ret=ssl3_get_client_key_exchange(s); |
- if (ret <= 0) |
+ if (ret <= 0) |
goto end; |
if (ret == 2) |
{ |
@@ -538,27 +535,50 @@ |
* the client sends its ECDH pub key in |
* a certificate, the CertificateVerify |
* message is not sent. |
+ * Also for GOST ciphersuites when |
+ * the client uses its key from the certificate |
+ * for key exchange. |
*/ |
+#if defined(OPENSSL_NO_TLSEXT) || defined(OPENSSL_NO_NEXTPROTONEG) |
+ s->state=SSL3_ST_SR_FINISHED_A; |
+#else |
if (s->s3->next_proto_neg_seen) |
s->state=SSL3_ST_SR_NEXT_PROTO_A; |
else |
s->state=SSL3_ST_SR_FINISHED_A; |
+#endif |
s->init_num = 0; |
} |
- else |
+ else |
{ |
+ int offset=0; |
+ int dgst_num; |
+ |
s->state=SSL3_ST_SR_CERT_VRFY_A; |
s->init_num=0; |
/* We need to get hashes here so if there is |
* a client cert, it can be verified |
- */ |
- s->method->ssl3_enc->cert_verify_mac(s, |
- &(s->s3->finish_dgst1), |
- &(s->s3->tmp.cert_verify_md[0])); |
- s->method->ssl3_enc->cert_verify_mac(s, |
- &(s->s3->finish_dgst2), |
- &(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH])); |
+ * FIXME - digest processing for CertificateVerify |
+ * should be generalized. But it is next step |
+ */ |
+ if (s->s3->handshake_buffer) |
+ if (!ssl3_digest_cached_records(s)) |
+ return -1; |
+ for (dgst_num=0; dgst_num<SSL_MAX_DIGEST;dgst_num++) |
+ if (s->s3->handshake_dgst[dgst_num]) |
+ { |
+ int dgst_size; |
+ |
+ s->method->ssl3_enc->cert_verify_mac(s,EVP_MD_CTX_type(s->s3->handshake_dgst[dgst_num]),&(s->s3->tmp.cert_verify_md[offset])); |
+ dgst_size=EVP_MD_CTX_size(s->s3->handshake_dgst[dgst_num]); |
+ if (dgst_size < 0) |
+ { |
+ ret = -1; |
+ goto end; |
+ } |
+ offset+=dgst_size; |
+ } |
} |
break; |
@@ -569,13 +589,18 @@ |
ret=ssl3_get_cert_verify(s); |
if (ret <= 0) goto end; |
+#if defined(OPENSSL_NO_TLSEXT) || defined(OPENSSL_NO_NEXTPROTONEG) |
+ s->state=SSL3_ST_SR_FINISHED_A; |
+#else |
if (s->s3->next_proto_neg_seen) |
s->state=SSL3_ST_SR_NEXT_PROTO_A; |
else |
s->state=SSL3_ST_SR_FINISHED_A; |
+#endif |
s->init_num=0; |
break; |
+#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) |
case SSL3_ST_SR_NEXT_PROTO_A: |
case SSL3_ST_SR_NEXT_PROTO_B: |
ret=ssl3_get_next_proto(s); |
@@ -583,17 +608,21 @@ |
s->init_num = 0; |
s->state=SSL3_ST_SR_FINISHED_A; |
break; |
+#endif |
case SSL3_ST_SR_FINISHED_A: |
case SSL3_ST_SR_FINISHED_B: |
ret=ssl3_get_finished(s,SSL3_ST_SR_FINISHED_A, |
SSL3_ST_SR_FINISHED_B); |
if (ret <= 0) goto end; |
+#ifndef OPENSSL_NO_TLSEXT |
+ if (s->tlsext_ticket_expected) |
+ s->state=SSL3_ST_SW_SESSION_TICKET_A; |
+ else if (s->hit) |
+ s->state=SSL_ST_OK; |
+#else |
if (s->hit) |
s->state=SSL_ST_OK; |
-#ifndef OPENSSL_NO_TLSEXT |
- else if (s->tlsext_ticket_expected) |
- s->state=SSL3_ST_SW_SESSION_TICKET_A; |
#endif |
else |
s->state=SSL3_ST_SW_CHANGE_A; |
@@ -652,10 +681,14 @@ |
s->state=SSL3_ST_SW_FLUSH; |
if (s->hit) |
{ |
+#if defined(OPENSSL_NO_TLSEXT) || defined(OPENSSL_NO_NEXTPROTONEG) |
+ s->s3->tmp.next_state=SSL3_ST_SR_FINISHED_A; |
+#else |
if (s->s3->next_proto_neg_seen) |
s->s3->tmp.next_state=SSL3_ST_SR_NEXT_PROTO_A; |
else |
s->s3->tmp.next_state=SSL3_ST_SR_FINISHED_A; |
+#endif |
} |
else |
s->s3->tmp.next_state=SSL_ST_OK; |
@@ -756,6 +789,14 @@ |
int ok; |
long n; |
+ /* We only allow the client to restart the handshake once per |
+ * negotiation. */ |
+ if (s->s3->flags & SSL3_FLAGS_SGC_RESTART_DONE) |
+ { |
+ SSLerr(SSL_F_SSL3_CHECK_CLIENT_HELLO, SSL_R_MULTIPLE_SGC_RESTARTS); |
+ return -1; |
+ } |
+ |
/* this function is called when we really expect a Certificate message, |
* so permit appropriate message length */ |
n=s->method->ssl_get_message(s, |
@@ -769,9 +810,7 @@ |
if (s->s3->tmp.message_type == SSL3_MT_CLIENT_HELLO) |
{ |
/* Throw away what we have done so far in the current handshake, |
- * which will now be aborted. (A full SSL_clear would be too much.) |
- * I hope that tmp.dh is the only thing that may need to be cleared |
- * when a handshake is not completed ... */ |
+ * which will now be aborted. (A full SSL_clear would be too much.) */ |
#ifndef OPENSSL_NO_DH |
if (s->s3->tmp.dh != NULL) |
{ |
@@ -779,6 +818,14 @@ |
s->s3->tmp.dh = NULL; |
} |
#endif |
+#ifndef OPENSSL_NO_ECDH |
+ if (s->s3->tmp.ecdh != NULL) |
+ { |
+ EC_KEY_free(s->s3->tmp.ecdh); |
+ s->s3->tmp.ecdh = NULL; |
+ } |
+#endif |
+ s->s3->flags |= SSL3_FLAGS_SGC_RESTART_DONE; |
return 2; |
} |
return 1; |
@@ -828,7 +875,7 @@ |
(s->version != DTLS1_VERSION && s->client_version < s->version)) |
{ |
SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_WRONG_VERSION_NUMBER); |
- if ((s->client_version>>8) == SSL3_VERSION_MAJOR) |
+ if ((s->client_version>>8) == SSL3_VERSION_MAJOR) |
{ |
/* similar to ssl3_get_record, send alert using remote version number */ |
s->version = s->client_version; |
@@ -870,6 +917,12 @@ |
*/ |
if ((s->new_session && (s->options & SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION))) |
{ |
+ if (!s->session_creation_enabled) |
+ { |
+ ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_HANDSHAKE_FAILURE); |
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_SESSION_MAY_NOT_BE_CREATED); |
+ goto err; |
+ } |
if (!ssl_get_new_session(s,1)) |
goto err; |
} |
@@ -884,6 +937,12 @@ |
goto err; |
else /* i == 0 */ |
{ |
+ if (!s->session_creation_enabled) |
+ { |
+ ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_HANDSHAKE_FAILURE); |
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_SESSION_MAY_NOT_BE_CREATED); |
+ goto err; |
+ } |
if (!ssl_get_new_session(s,1)) |
goto err; |
} |
@@ -986,6 +1045,10 @@ |
break; |
} |
} |
+/* Disabled because it can be used in a ciphersuite downgrade |
+ * attack: CVE-2010-4180. |
+ */ |
+#if 0 |
if (j == 0 && (s->options & SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG) && (sk_SSL_CIPHER_num(ciphers) == 1)) |
{ |
/* Special case as client bug workaround: the previously used cipher may |
@@ -1000,6 +1063,7 @@ |
j = 1; |
} |
} |
+#endif |
if (j == 0) |
{ |
/* we need to have the cipher in the cipher |
@@ -1049,13 +1113,110 @@ |
SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT); |
goto err; |
} |
+ |
+ /* Check if we want to use external pre-shared secret for this |
+ * handshake for not reused session only. We need to generate |
+ * server_random before calling tls_session_secret_cb in order to allow |
+ * SessionTicket processing to use it in key derivation. */ |
+ { |
+ unsigned long Time; |
+ unsigned char *pos; |
+ Time=(unsigned long)time(NULL); /* Time */ |
+ pos=s->s3->server_random; |
+ l2n(Time,pos); |
+ if (RAND_pseudo_bytes(pos,SSL3_RANDOM_SIZE-4) <= 0) |
+ { |
+ al=SSL_AD_INTERNAL_ERROR; |
+ goto f_err; |
+ } |
+ } |
+ |
+ if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb) |
+ { |
+ SSL_CIPHER *pref_cipher=NULL; |
+ |
+ s->session->master_key_length=sizeof(s->session->master_key); |
+ if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length, |
+ ciphers, &pref_cipher, s->tls_session_secret_cb_arg)) |
+ { |
+ s->hit=1; |
+ s->session->ciphers=ciphers; |
+ s->session->verify_result=X509_V_OK; |
+ |
+ ciphers=NULL; |
+ |
+ /* check if some cipher was preferred by call back */ |
+ pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s)); |
+ if (pref_cipher == NULL) |
+ { |
+ al=SSL_AD_HANDSHAKE_FAILURE; |
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER); |
+ goto f_err; |
+ } |
+ |
+ s->session->cipher=pref_cipher; |
+ |
+ if (s->cipher_list) |
+ sk_SSL_CIPHER_free(s->cipher_list); |
+ |
+ if (s->cipher_list_by_id) |
+ sk_SSL_CIPHER_free(s->cipher_list_by_id); |
+ |
+ s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers); |
+ s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers); |
+ } |
+ } |
#endif |
+ |
/* Worst case, we will use the NULL compression, but if we have other |
* options, we will now look for them. We have i-1 compression |
* algorithms from the client, starting at q. */ |
s->s3->tmp.new_compression=NULL; |
#ifndef OPENSSL_NO_COMP |
- if (s->ctx->comp_methods != NULL) |
+ /* This only happens if we have a cache hit */ |
+ if (s->session->compress_meth != 0) |
+ { |
+ int m, comp_id = s->session->compress_meth; |
+ /* Perform sanity checks on resumed compression algorithm */ |
+ /* Can't disable compression */ |
+ if (s->options & SSL_OP_NO_COMPRESSION) |
+ { |
+ al=SSL_AD_INTERNAL_ERROR; |
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_INCONSISTENT_COMPRESSION); |
+ goto f_err; |
+ } |
+ /* Look for resumed compression method */ |
+ for (m = 0; m < sk_SSL_COMP_num(s->ctx->comp_methods); m++) |
+ { |
+ comp=sk_SSL_COMP_value(s->ctx->comp_methods,m); |
+ if (comp_id == comp->id) |
+ { |
+ s->s3->tmp.new_compression=comp; |
+ break; |
+ } |
+ } |
+ if (s->s3->tmp.new_compression == NULL) |
+ { |
+ al=SSL_AD_INTERNAL_ERROR; |
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_INVALID_COMPRESSION_ALGORITHM); |
+ goto f_err; |
+ } |
+ /* Look for resumed method in compression list */ |
+ for (m = 0; m < i; m++) |
+ { |
+ if (q[m] == comp_id) |
+ break; |
+ } |
+ if (m >= i) |
+ { |
+ al=SSL_AD_ILLEGAL_PARAMETER; |
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_REQUIRED_COMPRESSSION_ALGORITHM_MISSING); |
+ goto f_err; |
+ } |
+ } |
+ else if (s->hit) |
+ comp = NULL; |
+ else if (!(s->options & SSL_OP_NO_COMPRESSION) && s->ctx->comp_methods) |
{ /* See if we have a match */ |
int m,nn,o,v,done=0; |
@@ -1079,22 +1240,15 @@ |
else |
comp=NULL; |
} |
-#endif |
- |
- /* TLS does not mind if there is extra stuff */ |
-#if 0 /* SSL 3.0 does not mind either, so we should disable this test |
- * (was enabled in 0.9.6d through 0.9.6j and 0.9.7 through 0.9.7b, |
- * in earlier SSLeay/OpenSSL releases this test existed but was buggy) */ |
- if (s->version == SSL3_VERSION) |
+#else |
+ /* If compression is disabled we'd better not try to resume a session |
+ * using compression. |
+ */ |
+ if (s->session->compress_meth != 0) |
{ |
- if (p < (d+n)) |
- { |
- /* wrong number of bytes, |
- * there could be more to follow */ |
- al=SSL_AD_DECODE_ERROR; |
- SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_LENGTH_MISMATCH); |
- goto f_err; |
- } |
+ al=SSL_AD_INTERNAL_ERROR; |
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_INCONSISTENT_COMPRESSION); |
+ goto f_err; |
} |
#endif |
@@ -1143,7 +1297,7 @@ |
for (i=0; i<sk_SSL_CIPHER_num(sk); i++) |
{ |
c=sk_SSL_CIPHER_value(sk,i); |
- if (c->algorithms & SSL_eNULL) |
+ if (c->algorithm_enc & SSL_eNULL) |
nc=c; |
if (SSL_C_IS_EXPORT(c)) |
ec=c; |
@@ -1159,6 +1313,9 @@ |
#endif |
s->s3->tmp.new_cipher=s->session->cipher; |
} |
+ |
+ if (!ssl3_digest_cached_records(s)) |
+ goto f_err; |
/* we now have the following setup. |
* client_random |
@@ -1187,24 +1344,22 @@ |
unsigned char *buf; |
unsigned char *p,*d; |
int i,sl; |
- unsigned long l,Time; |
+ unsigned long l; |
+#ifdef OPENSSL_NO_TLSEXT |
+ unsigned long Time; |
+#endif |
if (s->state == SSL3_ST_SW_SRVR_HELLO_A) |
{ |
buf=(unsigned char *)s->init_buf->data; |
- if (!s->s3->snap_start_requested) |
- { |
- p=s->s3->server_random; |
- Time=(unsigned long)time(NULL); /* Time */ |
- l2n(Time,p); |
- if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0) |
- return -1; |
- } |
- else if (s->s3->server_random_suggestion_valid == 0) |
- { |
- return SERVER_RANDOM_VALIDATION_PENDING; |
- } |
- |
+#ifdef OPENSSL_NO_TLSEXT |
+ p=s->s3->server_random; |
+ /* Generate server_random if it was not needed previously */ |
+ Time=(unsigned long)time(NULL); /* Time */ |
+ l2n(Time,p); |
+ if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0) |
+ return -1; |
+#endif |
/* Do the message type and length last */ |
d=p= &(buf[4]); |
@@ -1258,6 +1413,11 @@ |
*(p++)=s->s3->tmp.new_compression->id; |
#endif |
#ifndef OPENSSL_NO_TLSEXT |
+ if (ssl_prepare_serverhello_tlsext(s) <= 0) |
+ { |
+ SSLerr(SSL_F_SSL3_SEND_SERVER_HELLO,SSL_R_SERVERHELLO_TLSEXT); |
+ return -1; |
+ } |
if ((p = ssl_add_serverhello_tlsext(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH)) == NULL) |
{ |
SSLerr(SSL_F_SSL3_SEND_SERVER_HELLO,ERR_R_INTERNAL_ERROR); |
@@ -1337,7 +1497,7 @@ |
EVP_MD_CTX_init(&md_ctx); |
if (s->state == SSL3_ST_SW_KEY_EXCH_A) |
{ |
- type=s->s3->tmp.new_cipher->algorithms & SSL_MKEY_MASK; |
+ type=s->s3->tmp.new_cipher->algorithm_mkey; |
cert=s->cert; |
buf=s->init_buf; |
@@ -1391,7 +1551,6 @@ |
if (s->s3->tmp.dh != NULL) |
{ |
- DH_free(dh); |
SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR); |
goto err; |
} |
@@ -1432,7 +1591,7 @@ |
else |
#endif |
#ifndef OPENSSL_NO_ECDH |
- if (type & SSL_kECDHE) |
+ if (type & SSL_kEECDH) |
{ |
const EC_GROUP *group; |
@@ -1452,7 +1611,6 @@ |
if (s->s3->tmp.ecdh != NULL) |
{ |
- EC_KEY_free(s->s3->tmp.ecdh); |
SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR); |
goto err; |
} |
@@ -1463,12 +1621,11 @@ |
SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB); |
goto err; |
} |
- if (!EC_KEY_up_ref(ecdhp)) |
+ if ((ecdh = EC_KEY_dup(ecdhp)) == NULL) |
{ |
SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB); |
goto err; |
} |
- ecdh = ecdhp; |
s->s3->tmp.ecdh=ecdh; |
if ((EC_KEY_get0_public_key(ecdh) == NULL) || |
@@ -1502,7 +1659,7 @@ |
* supported named curves, curve_id is non-zero. |
*/ |
if ((curve_id = |
- nid2curve_id(EC_GROUP_get_curve_name(group))) |
+ tls1_ec_nid2curve_id(EC_GROUP_get_curve_name(group))) |
== 0) |
{ |
SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_UNSUPPORTED_ELLIPTIC_CURVE); |
@@ -1559,6 +1716,14 @@ |
} |
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 */ |
{ |
al=SSL_AD_HANDSHAKE_FAILURE; |
SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE); |
@@ -1570,7 +1735,8 @@ |
n+=2+nr[i]; |
} |
- if (!(s->s3->tmp.new_cipher->algorithms & SSL_aNULL)) |
+ if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL) |
+ && !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)) |
{ |
if ((pkey=ssl_get_sign_pkey(s,s->s3->tmp.new_cipher)) |
== NULL) |
@@ -1602,7 +1768,7 @@ |
} |
#ifndef OPENSSL_NO_ECDH |
- if (type & SSL_kECDHE) |
+ if (type & SSL_kEECDH) |
{ |
/* XXX: For now, we only support named (not generic) curves. |
* In this situation, the serverKeyExchange message has: |
@@ -1622,10 +1788,21 @@ |
(unsigned char *)encodedPoint, |
encodedlen); |
OPENSSL_free(encodedPoint); |
+ 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 |
+ |
/* not anonymous */ |
if (pkey != NULL) |
{ |
@@ -1638,8 +1815,6 @@ |
j=0; |
for (num=2; num > 0; num--) |
{ |
- EVP_MD_CTX_set_flags(&md_ctx, |
- EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); |
EVP_DigestInit_ex(&md_ctx,(num == 2) |
?s->ctx->md5:s->ctx->sha1, NULL); |
EVP_DigestUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE); |
@@ -1823,7 +1998,7 @@ |
{ |
int i,al,ok; |
long n; |
- unsigned long l; |
+ unsigned long alg_k; |
unsigned char *p; |
#ifndef OPENSSL_NO_RSA |
RSA *rsa=NULL; |
@@ -1834,7 +2009,7 @@ |
DH *dh_srvr; |
#endif |
#ifndef OPENSSL_NO_KRB5 |
- KSSL_ERR kssl_err; |
+ KSSL_ERR kssl_err; |
#endif /* OPENSSL_NO_KRB5 */ |
#ifndef OPENSSL_NO_ECDH |
@@ -1854,10 +2029,10 @@ |
if (!ok) return((int)n); |
p=(unsigned char *)s->init_msg; |
- l=s->s3->tmp.new_cipher->algorithms; |
+ alg_k=s->s3->tmp.new_cipher->algorithm_mkey; |
#ifndef OPENSSL_NO_RSA |
- if (l & SSL_kRSA) |
+ if (alg_k & SSL_kRSA) |
{ |
/* FIX THIS UP EAY EAY EAY EAY */ |
if (s->s3->tmp.use_rsa_tmp) |
@@ -1888,9 +2063,8 @@ |
rsa=pkey->pkey.rsa; |
} |
- /* TLS and [incidentally] DTLS, including pre-0.9.8f */ |
- if (s->version > SSL3_VERSION && |
- s->client_version != DTLS1_BAD_VER) |
+ /* TLS and [incidentally] DTLS{0xFEFF} */ |
+ if (s->version > SSL3_VERSION && s->version != DTLS1_BAD_VER) |
{ |
n2s(p,i); |
if (n != i+2) |
@@ -1964,7 +2138,7 @@ |
else |
#endif |
#ifndef OPENSSL_NO_DH |
- if (l & (SSL_kEDH|SSL_kDHr|SSL_kDHd)) |
+ if (alg_k & (SSL_kEDH|SSL_kDHr|SSL_kDHd)) |
{ |
n2s(p,i); |
if (n != i+2) |
@@ -2011,6 +2185,7 @@ |
if (i <= 0) |
{ |
SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,ERR_R_DH_LIB); |
+ BN_clear_free(pub); |
goto err; |
} |
@@ -2027,30 +2202,30 @@ |
else |
#endif |
#ifndef OPENSSL_NO_KRB5 |
- if (l & SSL_kKRB5) |
- { |
- krb5_error_code krb5rc; |
+ if (alg_k & SSL_kKRB5) |
+ { |
+ krb5_error_code krb5rc; |
krb5_data enc_ticket; |
krb5_data authenticator; |
krb5_data enc_pms; |
- KSSL_CTX *kssl_ctx = s->kssl_ctx; |
+ KSSL_CTX *kssl_ctx = s->kssl_ctx; |
EVP_CIPHER_CTX ciph_ctx; |
- EVP_CIPHER *enc = NULL; |
+ const EVP_CIPHER *enc = NULL; |
unsigned char iv[EVP_MAX_IV_LENGTH]; |
unsigned char pms[SSL_MAX_MASTER_KEY_LENGTH |
- + EVP_MAX_BLOCK_LENGTH]; |
- int padl, outl; |
+ + EVP_MAX_BLOCK_LENGTH]; |
+ int padl, outl; |
krb5_timestamp authtime = 0; |
krb5_ticket_times ttimes; |
EVP_CIPHER_CTX_init(&ciph_ctx); |
- if (!kssl_ctx) kssl_ctx = kssl_ctx_new(); |
+ if (!kssl_ctx) kssl_ctx = kssl_ctx_new(); |
n2s(p,i); |
enc_ticket.length = i; |
- if (n < (int)enc_ticket.length + 6) |
+ if (n < (long)(enc_ticket.length + 6)) |
{ |
SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, |
SSL_R_DATA_LENGTH_TOO_LONG); |
@@ -2063,7 +2238,7 @@ |
n2s(p,i); |
authenticator.length = i; |
- if (n < (int)(enc_ticket.length + authenticator.length) + 6) |
+ if (n < (long)(enc_ticket.length + authenticator.length + 6)) |
{ |
SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, |
SSL_R_DATA_LENGTH_TOO_LONG); |
@@ -2096,19 +2271,19 @@ |
goto err; |
} |
- if ((krb5rc = kssl_sget_tkt(kssl_ctx, &enc_ticket, &ttimes, |
+ if ((krb5rc = kssl_sget_tkt(kssl_ctx, &enc_ticket, &ttimes, |
&kssl_err)) != 0) |
- { |
+ { |
#ifdef KSSL_DEBUG |
- printf("kssl_sget_tkt rtn %d [%d]\n", |
- krb5rc, kssl_err.reason); |
- if (kssl_err.text) |
- printf("kssl_err text= %s\n", kssl_err.text); |
+ printf("kssl_sget_tkt rtn %d [%d]\n", |
+ krb5rc, kssl_err.reason); |
+ if (kssl_err.text) |
+ printf("kssl_err text= %s\n", kssl_err.text); |
#endif /* KSSL_DEBUG */ |
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, |
- kssl_err.reason); |
- goto err; |
- } |
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, |
+ kssl_err.reason); |
+ goto err; |
+ } |
/* Note: no authenticator is not considered an error, |
** but will return authtime == 0. |
@@ -2117,29 +2292,29 @@ |
&authtime, &kssl_err)) != 0) |
{ |
#ifdef KSSL_DEBUG |
- printf("kssl_check_authent rtn %d [%d]\n", |
- krb5rc, kssl_err.reason); |
- if (kssl_err.text) |
- printf("kssl_err text= %s\n", kssl_err.text); |
+ printf("kssl_check_authent rtn %d [%d]\n", |
+ krb5rc, kssl_err.reason); |
+ if (kssl_err.text) |
+ printf("kssl_err text= %s\n", kssl_err.text); |
#endif /* KSSL_DEBUG */ |
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, |
- kssl_err.reason); |
- goto err; |
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, |
+ kssl_err.reason); |
+ goto err; |
} |
if ((krb5rc = kssl_validate_times(authtime, &ttimes)) != 0) |
{ |
SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, krb5rc); |
- goto err; |
+ goto err; |
} |
#ifdef KSSL_DEBUG |
- kssl_ctx_show(kssl_ctx); |
+ kssl_ctx_show(kssl_ctx); |
#endif /* KSSL_DEBUG */ |
enc = kssl_map_enc(kssl_ctx->enctype); |
- if (enc == NULL) |
- goto err; |
+ if (enc == NULL) |
+ goto err; |
memset(iv, 0, sizeof iv); /* per RFC 1510 */ |
@@ -2186,7 +2361,7 @@ |
* (Perhaps we should have a separate BUG value for the Kerberos cipher) |
*/ |
if (!(s->options & SSL_OP_TLS_ROLLBACK_BUG)) |
- { |
+ { |
SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, |
SSL_AD_DECODE_ERROR); |
goto err; |
@@ -2195,32 +2370,32 @@ |
EVP_CIPHER_CTX_cleanup(&ciph_ctx); |
- s->session->master_key_length= |
- s->method->ssl3_enc->generate_master_secret(s, |
- s->session->master_key, pms, outl); |
+ s->session->master_key_length= |
+ s->method->ssl3_enc->generate_master_secret(s, |
+ s->session->master_key, pms, outl); |
- if (kssl_ctx->client_princ) |
- { |
- size_t len = strlen(kssl_ctx->client_princ); |
- if ( len < SSL_MAX_KRB5_PRINCIPAL_LENGTH ) |
- { |
- s->session->krb5_client_princ_len = len; |
- memcpy(s->session->krb5_client_princ,kssl_ctx->client_princ,len); |
- } |
- } |
+ if (kssl_ctx->client_princ) |
+ { |
+ size_t len = strlen(kssl_ctx->client_princ); |
+ if ( len < SSL_MAX_KRB5_PRINCIPAL_LENGTH ) |
+ { |
+ s->session->krb5_client_princ_len = len; |
+ memcpy(s->session->krb5_client_princ,kssl_ctx->client_princ,len); |
+ } |
+ } |
- /* Was doing kssl_ctx_free() here, |
+ /* Was doing kssl_ctx_free() here, |
** but it caused problems for apache. |
- ** kssl_ctx = kssl_ctx_free(kssl_ctx); |
- ** if (s->kssl_ctx) s->kssl_ctx = NULL; |
- */ |
- } |
+ ** kssl_ctx = kssl_ctx_free(kssl_ctx); |
+ ** if (s->kssl_ctx) s->kssl_ctx = NULL; |
+ */ |
+ } |
else |
#endif /* OPENSSL_NO_KRB5 */ |
#ifndef OPENSSL_NO_ECDH |
- if ((l & SSL_kECDH) || (l & SSL_kECDHE)) |
+ if (alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe)) |
{ |
int ret = 1; |
int field_size = 0; |
@@ -2228,18 +2403,18 @@ |
const EC_GROUP *group; |
const BIGNUM *priv_key; |
- /* initialize structures for server's ECDH key pair */ |
+ /* initialize structures for server's ECDH key pair */ |
if ((srvr_ecdh = EC_KEY_new()) == NULL) |
{ |
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, |
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, |
ERR_R_MALLOC_FAILURE); |
- goto err; |
+ goto err; |
} |
/* Let's get server private key and group information */ |
- if (l & SSL_kECDH) |
+ if (alg_k & (SSL_kECDHr|SSL_kECDHe)) |
{ |
- /* use the certificate */ |
+ /* use the certificate */ |
tkey = s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec; |
} |
else |
@@ -2269,20 +2444,20 @@ |
goto err; |
} |
- if (n == 0L) |
- { |
+ if (n == 0L) |
+ { |
/* Client Publickey was in Client Certificate */ |
- if (l & SSL_kECDHE) |
+ if (alg_k & SSL_kEECDH) |
{ |
al=SSL_AD_HANDSHAKE_FAILURE; |
SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_MISSING_TMP_ECDH_KEY); |
goto f_err; |
} |
- if (((clnt_pub_pkey=X509_get_pubkey(s->session->peer)) |
+ if (((clnt_pub_pkey=X509_get_pubkey(s->session->peer)) |
== NULL) || |
(clnt_pub_pkey->type != EVP_PKEY_EC)) |
- { |
+ { |
/* XXX: For now, we do not support client |
* authentication using ECDH certificates |
* so this branch (n == 0L) of the code is |
@@ -2294,11 +2469,11 @@ |
* the two ECDH shares are for the same |
* group. |
*/ |
- al=SSL_AD_HANDSHAKE_FAILURE; |
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, |
+ al=SSL_AD_HANDSHAKE_FAILURE; |
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, |
SSL_R_UNABLE_TO_DECODE_ECDH_CERTS); |
- goto f_err; |
- } |
+ goto f_err; |
+ } |
if (EC_POINT_copy(clnt_ecpoint, |
EC_KEY_get0_public_key(clnt_pub_pkey->pkey.ec)) == 0) |
@@ -2307,10 +2482,10 @@ |
ERR_R_EC_LIB); |
goto err; |
} |
- ret = 2; /* Skip certificate verify processing */ |
- } |
- else |
- { |
+ ret = 2; /* Skip certificate verify processing */ |
+ } |
+ else |
+ { |
/* Get client's public key from encoded point |
* in the ClientKeyExchange message. |
*/ |
@@ -2321,21 +2496,27 @@ |
goto err; |
} |
- /* Get encoded point length */ |
- i = *p; |
+ /* Get encoded point length */ |
+ i = *p; |
p += 1; |
- if (EC_POINT_oct2point(group, |
+ if (n != 1 + i) |
+ { |
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, |
+ ERR_R_EC_LIB); |
+ goto err; |
+ } |
+ if (EC_POINT_oct2point(group, |
clnt_ecpoint, p, i, bn_ctx) == 0) |
{ |
SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, |
ERR_R_EC_LIB); |
goto err; |
} |
- /* p is pointing to somewhere in the buffer |
- * currently, so set it to the start |
- */ |
- p=(unsigned char *)s->init_buf->data; |
- } |
+ /* p is pointing to somewhere in the buffer |
+ * currently, so set it to the start |
+ */ |
+ p=(unsigned char *)s->init_buf->data; |
+ } |
/* Compute the shared pre-master secret */ |
field_size = EC_GROUP_get_degree(group); |
@@ -2346,28 +2527,197 @@ |
goto err; |
} |
i = ECDH_compute_key(p, (field_size+7)/8, clnt_ecpoint, srvr_ecdh, NULL); |
- if (i <= 0) |
- { |
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, |
+ if (i <= 0) |
+ { |
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, |
ERR_R_ECDH_LIB); |
- goto err; |
- } |
+ goto err; |
+ } |
EVP_PKEY_free(clnt_pub_pkey); |
EC_POINT_free(clnt_ecpoint); |
- if (srvr_ecdh != NULL) |
- EC_KEY_free(srvr_ecdh); |
+ EC_KEY_free(srvr_ecdh); |
BN_CTX_free(bn_ctx); |
+ EC_KEY_free(s->s3->tmp.ecdh); |
+ s->s3->tmp.ecdh = NULL; |
/* Compute the master secret */ |
- s->session->master_key_length = s->method->ssl3_enc-> \ |
+ 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); |
+ OPENSSL_cleanse(p, i); |
+ return (ret); |
} |
else |
#endif |
+#ifndef OPENSSL_NO_PSK |
+ if (alg_k & SSL_kPSK) |
+ { |
+ 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) |
+ { |
+ SSLerr(SSL_F_SSL3_GET_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); |
+ psk_err = 0; |
+ psk_err: |
+ OPENSSL_cleanse(psk_or_pre_ms, sizeof(psk_or_pre_ms)); |
+ if (psk_err != 0) |
+ goto f_err; |
+ } |
+ else |
+#endif |
+ 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; |
+ |
+ /* 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 ((*p!=( V_ASN1_SEQUENCE| V_ASN1_CONSTRUCTED))) |
+ { |
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_DECRYPTION_FAILED); |
+ goto gerr; |
+ } |
+ if (p[1] == 0x81) |
+ { |
+ start = p+3; |
+ inlen = p[2]; |
+ } |
+ else if (p[1] < 0x80) |
+ { |
+ start = p+2; |
+ inlen = p[1]; |
+ } |
+ else |
+ { |
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_DECRYPTION_FAILED); |
+ goto gerr; |
+ } |
+ 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 |
{ |
al=SSL_AD_HANDSHAKE_FAILURE; |
SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, |
@@ -2391,70 +2741,6 @@ |
return(-1); |
} |
-/* ssl3_get_next_proto reads a Next Protocol Negotiation handshake message. It |
- * sets the next_proto member in s if found */ |
-int ssl3_get_next_proto(SSL *s) |
- { |
- int ok; |
- unsigned proto_len, padding_len; |
- long n; |
- const unsigned char *p; |
- |
- /* Clients cannot send a NextProtocol message if we didn't see the |
- * extension in their ClientHello */ |
- if (!s->s3->next_proto_neg_seen) { |
- SSLerr(SSL_F_SSL3_GET_NEXT_PROTO,SSL_R_GOT_NEXT_PROTO_WITHOUT_EXTENSION); |
- return -1; |
- } |
- |
- n=s->method->ssl_get_message(s, |
- SSL3_ST_SR_NEXT_PROTO_A, |
- SSL3_ST_SR_NEXT_PROTO_B, |
- SSL3_MT_NEXT_PROTO, |
- 129, |
- &ok); |
- |
- if (!ok) |
- return((int)n); |
- |
- /* s->state doesn't reflect whether ChangeCipherSpec has been received |
- * in this handshake, but s->s3->change_cipher_spec does (will be reset |
- * by ssl3_get_finished). */ |
- if (!s->s3->change_cipher_spec) |
- { |
- SSLerr(SSL_F_SSL3_GET_NEXT_PROTO,SSL_R_GOT_NEXT_PROTO_BEFORE_A_CCS); |
- return -1; |
- } |
- |
- if (n < 2) |
- return 0; // The body must be > 1 bytes long */ |
- |
- p=(unsigned char *)s->init_msg; |
- |
- /* The payload looks like: |
- * uint8 proto_len; |
- * uint8 proto[proto_len]; |
- * uint8 padding_len; |
- * uint8 padding[padding_len]; |
- */ |
- proto_len = p[0]; |
- if (proto_len + 2 > s->init_num) |
- return 0; |
- padding_len = p[proto_len + 1]; |
- if (proto_len + padding_len + 2 != s->init_num) |
- return 0; |
- |
- s->next_proto_negotiated = OPENSSL_malloc(proto_len); |
- if (!s->next_proto_negotiated) { |
- SSLerr(SSL_F_SSL3_GET_NEXT_PROTO,ERR_R_MALLOC_FAILURE); |
- return 0; |
- } |
- memcpy(s->next_proto_negotiated, p + 1, proto_len); |
- s->next_proto_negotiated_len = proto_len; |
- |
- return 1; |
- } |
- |
int ssl3_get_cert_verify(SSL *s) |
{ |
EVP_PKEY *pkey=NULL; |
@@ -2521,15 +2807,25 @@ |
/* we now have a signature that we need to verify */ |
p=(unsigned char *)s->init_msg; |
- n2s(p,i); |
- n-=2; |
- if (i > n) |
+ /* Check for broken implementations of GOST ciphersuites */ |
+ /* If key is GOST and n is exactly 64, it is bare |
+ * signature without length field */ |
+ if (n==64 && (pkey->type==NID_id_GostR3410_94 || |
+ pkey->type == NID_id_GostR3410_2001) ) |
{ |
- SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_LENGTH_MISMATCH); |
- al=SSL_AD_DECODE_ERROR; |
- goto f_err; |
- } |
- |
+ i=64; |
+ } |
+ else |
+ { |
+ n2s(p,i); |
+ n-=2; |
+ if (i > n) |
+ { |
+ SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_LENGTH_MISMATCH); |
+ al=SSL_AD_DECODE_ERROR; |
+ goto f_err; |
+ } |
+ } |
j=EVP_PKEY_size(pkey); |
if ((i > j) || (n > j) || (n <= 0)) |
{ |
@@ -2592,6 +2888,28 @@ |
} |
else |
#endif |
+ if (pkey->type == NID_id_GostR3410_94 || pkey->type == NID_id_GostR3410_2001) |
+ { unsigned char signature[64]; |
+ int idx; |
+ EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new(pkey,NULL); |
+ EVP_PKEY_verify_init(pctx); |
+ if (i!=64) { |
+ fprintf(stderr,"GOST signature length is %d",i); |
+ } |
+ for (idx=0;idx<64;idx++) { |
+ signature[63-idx]=p[idx]; |
+ } |
+ j=EVP_PKEY_verify(pctx,signature,64,s->s3->tmp.cert_verify_md,32); |
+ EVP_PKEY_CTX_free(pctx); |
+ if (j<=0) |
+ { |
+ al=SSL_AD_DECRYPT_ERROR; |
+ SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, |
+ SSL_R_BAD_ECDSA_SIGNATURE); |
+ goto f_err; |
+ } |
+ } |
+ else |
{ |
SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,ERR_R_INTERNAL_ERROR); |
al=SSL_AD_UNSUPPORTED_CERTIFICATE; |
@@ -2774,14 +3092,15 @@ |
if (s->state == SSL3_ST_SW_CERT_A) |
{ |
x=ssl_get_server_send_cert(s); |
- if (x == NULL && |
- /* VRS: allow null cert if auth == KRB5 */ |
- (s->s3->tmp.new_cipher->algorithms |
- & (SSL_MKEY_MASK|SSL_AUTH_MASK)) |
- != (SSL_aKRB5|SSL_kKRB5)) |
+ if (x == NULL) |
{ |
- SSLerr(SSL_F_SSL3_SEND_SERVER_CERTIFICATE,ERR_R_INTERNAL_ERROR); |
- return(0); |
+ /* VRS: allow null cert if auth == KRB5 */ |
+ if ((s->s3->tmp.new_cipher->algorithm_auth != SSL_aKRB5) || |
+ (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kKRB5)) |
+ { |
+ SSLerr(SSL_F_SSL3_SEND_SERVER_CERTIFICATE,ERR_R_INTERNAL_ERROR); |
+ return(0); |
+ } |
} |
l=ssl3_output_cert_chain(s,x); |
@@ -2793,70 +3112,6 @@ |
/* SSL3_ST_SW_CERT_B */ |
return(ssl3_do_write(s,SSL3_RT_HANDSHAKE)); |
} |
- |
- |
-#ifndef OPENSSL_NO_ECDH |
-/* This is the complement of curve_id2nid in s3_clnt.c. */ |
-static int nid2curve_id(int nid) |
-{ |
- /* ECC curves from draft-ietf-tls-ecc-01.txt (Mar 15, 2001) |
- * (no changes in draft-ietf-tls-ecc-03.txt [June 2003]) */ |
- switch (nid) { |
- case NID_sect163k1: /* sect163k1 (1) */ |
- return 1; |
- case NID_sect163r1: /* sect163r1 (2) */ |
- return 2; |
- case NID_sect163r2: /* sect163r2 (3) */ |
- return 3; |
- case NID_sect193r1: /* sect193r1 (4) */ |
- return 4; |
- case NID_sect193r2: /* sect193r2 (5) */ |
- return 5; |
- case NID_sect233k1: /* sect233k1 (6) */ |
- return 6; |
- case NID_sect233r1: /* sect233r1 (7) */ |
- return 7; |
- case NID_sect239k1: /* sect239k1 (8) */ |
- return 8; |
- case NID_sect283k1: /* sect283k1 (9) */ |
- return 9; |
- case NID_sect283r1: /* sect283r1 (10) */ |
- return 10; |
- case NID_sect409k1: /* sect409k1 (11) */ |
- return 11; |
- case NID_sect409r1: /* sect409r1 (12) */ |
- return 12; |
- case NID_sect571k1: /* sect571k1 (13) */ |
- return 13; |
- case NID_sect571r1: /* sect571r1 (14) */ |
- return 14; |
- case NID_secp160k1: /* secp160k1 (15) */ |
- return 15; |
- case NID_secp160r1: /* secp160r1 (16) */ |
- return 16; |
- case NID_secp160r2: /* secp160r2 (17) */ |
- return 17; |
- case NID_secp192k1: /* secp192k1 (18) */ |
- return 18; |
- case NID_X9_62_prime192v1: /* secp192r1 (19) */ |
- return 19; |
- case NID_secp224k1: /* secp224k1 (20) */ |
- return 20; |
- case NID_secp224r1: /* secp224r1 (21) */ |
- return 21; |
- case NID_secp256k1: /* secp256k1 (22) */ |
- return 22; |
- case NID_X9_62_prime256v1: /* secp256r1 (23) */ |
- return 23; |
- case NID_secp384r1: /* secp384r1 (24) */ |
- return 24; |
- case NID_secp521r1: /* secp521r1 (25) */ |
- return 25; |
- default: |
- return 0; |
- } |
-} |
-#endif |
#ifndef OPENSSL_NO_TLSEXT |
int ssl3_send_newsession_ticket(SSL *s) |
{ |
@@ -2999,56 +3254,72 @@ |
/* SSL3_ST_SW_CERT_STATUS_B */ |
return(ssl3_do_write(s,SSL3_RT_HANDSHAKE)); |
} |
-#endif |
-/* ssl3_snap_start_evaluate_handshake verifies the Snap Start prediction (if |
- * this is a Snap Start handshake). If it returns non-zero, then we are |
- * entering recovery and |s->state| has been set accordingly. */ |
-static int ssl3_snap_start_evaluate_handshake(SSL* s) |
+# ifndef OPENSSL_NO_NPN |
+/* ssl3_get_next_proto reads a Next Protocol Negotiation handshake message. It |
+ * sets the next_proto member in s if found */ |
+int ssl3_get_next_proto(SSL *s) |
{ |
- unsigned char digest[8]; |
+ int ok; |
+ unsigned proto_len, padding_len; |
+ long n; |
+ const unsigned char *p; |
- if (!s->s3->snap_start_requested) |
- return 0; |
- |
- /* Drop the currently queued messages. Either we're entering recovery, |
- * in which case they're wrong, or we're doing snap start, in which |
- * case we don't want to send them. */ |
- if (!ssl_init_wbio_buffer(s, 1 /* push new BIO */)) |
+ /* Clients cannot send a NextProtocol message if we didn't see the |
+ * extension in their ClientHello */ |
+ if (!s->s3->next_proto_neg_seen) |
+ { |
+ SSLerr(SSL_F_SSL3_GET_NEXT_PROTO,SSL_R_GOT_NEXT_PROTO_WITHOUT_EXTENSION); |
return -1; |
+ } |
- fnv1a64_final(digest, (FNV1A64*) s->s3->response_hash); |
+ n=s->method->ssl_get_message(s, |
+ SSL3_ST_SR_NEXT_PROTO_A, |
+ SSL3_ST_SR_NEXT_PROTO_B, |
+ SSL3_MT_NEXT_PROTO, |
+ 514, /* See the payload format below */ |
+ &ok); |
- /* Turn off FNV hashing of handshake messages. */ |
- s->s3->snap_start_requested = 0; |
+ if (!ok) |
+ return((int)n); |
- if (memcmp(digest, s->s3->predicted_response_hash, sizeof(digest)) != 0) |
+ /* s->state doesn't reflect whether ChangeCipherSpec has been received |
+ * in this handshake, but s->s3->change_cipher_spec does (will be reset |
+ * by ssl3_get_finished). */ |
+ if (!s->s3->change_cipher_spec) |
{ |
- /* The predicted handshake didn't match. */ |
- ssl3_snap_start_reset_for_recovery(s); |
- s->state = SSL3_ST_SW_SRVR_HELLO_A; |
- return 1; |
+ SSLerr(SSL_F_SSL3_GET_NEXT_PROTO,SSL_R_GOT_NEXT_PROTO_BEFORE_A_CCS); |
+ return -1; |
} |
- return 0; |
- } |
+ if (n < 2) |
+ return 0; /* The body must be > 1 bytes long */ |
-/* ssl3_snap_start_reset_for_recovery is called is called when a Snap Start |
- * handshake is impossible because either the application layer has rejected |
- * the client's suggested server random, or predicated_response_hash failed to |
- * match response_hash */ |
-int ssl3_snap_start_reset_for_recovery(SSL* s) |
- { |
- s->s3->snap_start_requested = 0; |
- s->s3->snap_start_records.left = 0; |
- s->init_num = 0; |
+ p=(unsigned char *)s->init_msg; |
- /* Reset the handshake hash and hash in the original ClientHello. */ |
- ssl3_init_finished_mac(s); |
- ssl3_finish_mac(s, s->s3->snap_start_client_hello.buf, s->s3->snap_start_client_hello.left); |
+ /* The payload looks like: |
+ * uint8 proto_len; |
+ * uint8 proto[proto_len]; |
+ * uint8 padding_len; |
+ * uint8 padding[padding_len]; |
+ */ |
+ proto_len = p[0]; |
+ if (proto_len + 2 > s->init_num) |
+ return 0; |
+ padding_len = p[proto_len + 1]; |
+ if (proto_len + padding_len + 2 != s->init_num) |
+ return 0; |
- OPENSSL_free(s->s3->snap_start_client_hello.buf); |
- s->s3->snap_start_client_hello.buf = NULL; |
+ s->next_proto_negotiated = OPENSSL_malloc(proto_len); |
+ if (!s->next_proto_negotiated) |
+ { |
+ SSLerr(SSL_F_SSL3_GET_NEXT_PROTO,ERR_R_MALLOC_FAILURE); |
+ return 0; |
+ } |
+ memcpy(s->next_proto_negotiated, p + 1, proto_len); |
+ s->next_proto_negotiated_len = proto_len; |
- return 0; |
+ return 1; |
} |
+# endif |
+#endif |