}
#ifndef OPENSSL_NO_SRP
-static int SSL_check_srp_ext_ClientHello(SSL *s, int *ad)
+static int ssl_check_srp_ext_ClientHello(SSL *s, int *al)
{
int ret = SSL_ERROR_NONE;
- *ad = SSL_AD_UNRECOGNIZED_NAME;
+ *al = SSL_AD_UNRECOGNIZED_NAME;
if ((s->s3->tmp.new_cipher->algorithm_mkey & SSL_kSRP) &&
(s->srp_ctx.TLS_ext_srp_username_callback != NULL))
{
if(s->srp_ctx.login == NULL)
{
- /* There isn't any srp login extension !!! */
- ret = SSL3_AL_WARNING;
- *ad = SSL_AD_MISSING_SRP_USERNAME;
+ /* RFC 5054 says SHOULD reject,
+ we do so if There is no srp login name */
+ ret = SSL3_AL_FATAL;
+ *al = SSL_AD_UNKNOWN_PSK_IDENTITY;
}
else
{
- ret = SSL_srp_server_param_with_username(s,ad);
+ ret = SSL_srp_server_param_with_username(s,al);
}
}
return ret;
void (*cb)(const SSL *ssl,int type,int val)=NULL;
int ret= -1;
int new_state,state,skip=0;
-#ifndef OPENSSL_NO_SRP
- int srp_no_username=0;
- int extension_error,al;
-#endif
RAND_add(&Time,sizeof(Time),0);
ERR_clear_error();
return(-1);
}
+#ifndef OPENSSL_NO_HEARTBEATS
+ /* If we're awaiting a HeartbeatResponse, pretend we
+ * already got and don't await it anymore, because
+ * Heartbeats don't make sense during handshakes anyway.
+ */
+ if (s->tlsext_hb_pending)
+ {
+ s->tlsext_hb_pending = 0;
+ s->tlsext_hb_seq++;
+ }
+#endif
+
for (;;)
{
state=s->state;
}
s->init_num=0;
+ s->s3->flags &= ~SSL3_FLAGS_SGC_RESTART_DONE;
+ s->s3->flags &= ~TLS1_FLAGS_SKIP_CERT_VERIFY;
if (s->state != SSL_ST_RENEGOTIATE)
{
case SSL3_ST_SR_CLNT_HELLO_A:
case SSL3_ST_SR_CLNT_HELLO_B:
case SSL3_ST_SR_CLNT_HELLO_C:
-#ifndef OPENSSL_NO_SRP
- case SSL3_ST_SR_CLNT_HELLO_SRP_USERNAME:
-#endif
s->shutdown=0;
- ret=ssl3_get_client_hello(s);
- if (ret <= 0) goto end;
+ if (s->rwstate != SSL_X509_LOOKUP)
+ {
+ ret=ssl3_get_client_hello(s);
+ if (ret <= 0) goto end;
+ }
#ifndef OPENSSL_NO_SRP
- extension_error = 0;
- if ((al = SSL_check_srp_ext_ClientHello(s,&extension_error)) != SSL_ERROR_NONE)
- {
- ssl3_send_alert(s,al,extension_error);
- if (extension_error == SSL_AD_MISSING_SRP_USERNAME)
+ {
+ int al;
+ if ((ret = ssl_check_srp_ext_ClientHello(s,&al)) < 0)
{
- if (srp_no_username) goto end;
- ERR_clear_error();
- srp_no_username = 1;
- s->state=SSL3_ST_SR_CLNT_HELLO_SRP_USERNAME;
- if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_START,1);
- if ((ret=BIO_flush(s->wbio)) <= 0) goto end;
- s->init_num=0;
- break;
+ /* callback indicates firther work to be done */
+ s->rwstate=SSL_X509_LOOKUP;
+ goto end;
}
- ret = -1;
- SSLerr(SSL_F_SSL3_ACCEPT,SSL_R_CLIENTHELLO_TLSEXT);
- goto end;
+ if (ret != SSL_ERROR_NONE)
+ {
+ ssl3_send_alert(s,SSL3_AL_FATAL,al);
+ /* This is not really an error but the only means to
+ for a client to detect whether srp is supported. */
+ if (al != TLS1_AD_UNKNOWN_PSK_IDENTITY)
+ SSLerr(SSL_F_SSL3_ACCEPT,SSL_R_CLIENTHELLO_TLSEXT);
+ ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+ ret= -1;
+ goto end;
}
-#endif
+ }
+#endif
s->renegotiate = 2;
s->state=SSL3_ST_SW_SRVR_HELLO_A;
s->state=SSL3_ST_SW_CHANGE_A;
#endif
else
- s->state=SSL3_ST_SW_CERT_A;
- s->init_num=0;
+#ifndef OPENSSL_NO_TLSEXT
+ s->state = SSL3_ST_SW_SUPPLEMENTAL_DATA_A;
+#else
+ s->state = SSL3_ST_SW_CERT_A;
+#endif
+ s->init_num = 0;
+ break;
+
+#ifndef OPENSSL_NO_TLSEXT
+ case SSL3_ST_SW_SUPPLEMENTAL_DATA_A:
+ case SSL3_ST_SW_SUPPLEMENTAL_DATA_B:
+ /* We promised to send an audit proof in the hello. */
+ if (s->s3->tlsext_authz_promised_to_client)
+ {
+ ret = tls1_send_server_supplemental_data(s);
+ if (ret <= 0) goto end;
+ }
+ else
+ skip = 1;
+
+ s->state = SSL3_ST_SW_CERT_A;
+ s->init_num = 0;
break;
+#endif
case SSL3_ST_SW_CERT_A:
case SSL3_ST_SW_CERT_B:
/* SRP: send ServerKeyExchange */
|| (alg_k & SSL_kSRP)
#endif
- || (alg_k & (SSL_kDHr|SSL_kDHd|SSL_kEDH))
+ || (alg_k & SSL_kEDH)
|| (alg_k & SSL_kEECDH)
|| ((alg_k & SSL_kRSA)
&& (s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL
s->s3->tmp.reuse_message = 1;
if (s->s3->tmp.message_type == SSL3_MT_CLIENT_HELLO)
{
+ /* 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;
+ }
/* 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.) */
#ifndef OPENSSL_NO_DH
s->s3->tmp.ecdh = NULL;
}
#endif
+ s->s3->flags |= SSL3_FLAGS_SGC_RESTART_DONE;
return 2;
}
return 1;
int ssl3_get_client_hello(SSL *s)
{
- int i,j,ok,al,ret= -1;
+ int i,j,ok,al=SSL_AD_INTERNAL_ERROR,ret= -1;
unsigned int cookie_len;
long n;
unsigned long id;
* TLSv1.
*/
if (s->state == SSL3_ST_SR_CLNT_HELLO_A
-#ifndef OPENSSL_NO_SRP
- || (s->state == SSL3_ST_SR_CLNT_HELLO_SRP_USERNAME)
-#endif
)
{
s->state=SSL3_ST_SR_CLNT_HELLO_B;
/* TLS extensions*/
if (s->version >= SSL3_VERSION)
{
- if (!ssl_parse_clienthello_tlsext(s,&p,d,n, &al))
+ if (!ssl_parse_clienthello_tlsext(s,&p,d,n))
{
- /* 'al' set by ssl_parse_clienthello_tlsext */
SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_PARSE_TLSEXT);
- goto f_err;
- }
- }
- if (ssl_check_clienthello_tlsext(s) <= 0) {
- 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
l2n(Time,pos);
if (RAND_pseudo_bytes(pos,SSL3_RANDOM_SIZE-4) <= 0)
{
- al=SSL_AD_INTERNAL_ERROR;
goto f_err;
}
}
/* 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;
}
}
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;
}
*/
if (s->session->compress_meth != 0)
{
- al=SSL_AD_INTERNAL_ERROR;
SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_INCONSISTENT_COMPRESSION);
goto f_err;
}
SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_CIPHERS_PASSED);
goto f_err;
}
+ /* Let cert callback update server certificates if required */
+ if (s->cert->cert_cb
+ && s->cert->cert_cb(s, s->cert->cert_cb_arg) <= 0)
+ {
+ al=SSL_AD_INTERNAL_ERROR;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CERT_CB_ERROR);
+ goto f_err;
+ }
ciphers=NULL;
c=ssl3_choose_cipher(s,s->session->ciphers,
SSL_get_ciphers(s));
* s->tmp.new_cipher - the new cipher to use.
*/
+ /* Handles TLS extensions that we couldn't check earlier */
+ if (s->version >= SSL3_VERSION)
+ {
+ if (ssl_check_clienthello_tlsext_late(s) <= 0)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_CLIENTHELLO_TLSEXT);
+ goto err;
+ }
+ }
+
if (ret < 0) ret=1;
if (0)
{
const EC_GROUP *group;
ecdhp=cert->ecdh_tmp;
- if ((ecdhp == NULL) && (s->cert->ecdh_tmp_cb != NULL))
+ if (s->cert->ecdh_tmp_auto)
+ {
+ /* Get NID of first shared curve */
+ int nid = tls1_shared_curve(s, 0);
+ if (nid != NID_undef)
+ ecdhp = EC_KEY_new_by_curve_name(nid);
+ }
+ else if ((ecdhp == NULL) && s->cert->ecdh_tmp_cb)
{
ecdhp=s->cert->ecdh_tmp_cb(s,
SSL_C_IS_EXPORT(s->s3->tmp.new_cipher),
SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB);
goto err;
}
- if ((ecdh = EC_KEY_dup(ecdhp)) == NULL)
+ if (s->cert->ecdh_tmp_auto)
+ ecdh = ecdhp;
+ else if ((ecdh = EC_KEY_dup(ecdhp)) == NULL)
{
SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB);
goto err;
if (TLS1_get_version(s) >= TLS1_2_VERSION)
{
- nl = tls12_get_req_sig_algs(s, p + 2);
+ nl = tls12_get_sig_algs(s, p + 2);
s2n(nl, p);
p += nl + 2;
n += nl + 2;
#endif
#ifndef OPENSSL_NO_DH
BIGNUM *pub=NULL;
- DH *dh_srvr;
+ DH *dh_srvr, *dh_clnt = NULL;
#endif
#ifndef OPENSSL_NO_KRB5
KSSL_ERR kssl_err;
#ifndef OPENSSL_NO_DH
if (alg_k & (SSL_kEDH|SSL_kDHr|SSL_kDHd))
{
- n2s(p,i);
- if (n != i+2)
+ int idx = -1;
+ EVP_PKEY *skey = NULL;
+ if (n)
+ n2s(p,i);
+ else
+ i = 0;
+ if (n && n != i+2)
{
if (!(s->options & SSL_OP_SSLEAY_080_CLIENT_DH_BUG))
{
i=(int)n;
}
}
-
- if (n == 0L) /* the parameters are in the cert */
+ if (alg_k & SSL_kDHr)
+ idx = SSL_PKEY_DH_RSA;
+ else if (alg_k & SSL_kDHd)
+ idx = SSL_PKEY_DH_DSA;
+ if (idx >= 0)
+ {
+ skey = s->cert->pkeys[idx].privatekey;
+ if ((skey == NULL) ||
+ (skey->type != EVP_PKEY_DH) ||
+ (skey->pkey.dh == NULL))
+ {
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_MISSING_RSA_CERTIFICATE);
+ goto f_err;
+ }
+ dh_srvr = skey->pkey.dh;
+ }
+ else if (s->s3->tmp.dh == NULL)
{
al=SSL_AD_HANDSHAKE_FAILURE;
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_UNABLE_TO_DECODE_DH_CERTS);
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_MISSING_TMP_DH_KEY);
goto f_err;
}
else
+ dh_srvr=s->s3->tmp.dh;
+
+ if (n == 0L)
{
- if (s->s3->tmp.dh == NULL)
+ /* Get pubkey from cert */
+ EVP_PKEY *clkey=X509_get_pubkey(s->session->peer);
+ if (clkey)
+ {
+ if (EVP_PKEY_cmp_parameters(clkey, skey) == 1)
+ dh_clnt = EVP_PKEY_get1_DH(clkey);
+ }
+ if (dh_clnt == NULL)
{
al=SSL_AD_HANDSHAKE_FAILURE;
SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_MISSING_TMP_DH_KEY);
goto f_err;
}
- else
- dh_srvr=s->s3->tmp.dh;
+ EVP_PKEY_free(clkey);
+ pub = dh_clnt->pub_key;
}
-
- pub=BN_bin2bn(p,i,NULL);
+ else
+ pub=BN_bin2bn(p,i,NULL);
if (pub == NULL)
{
SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_BN_LIB);
if (i <= 0)
{
SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,ERR_R_DH_LIB);
+ BN_clear_free(pub);
goto err;
}
DH_free(s->s3->tmp.dh);
s->s3->tmp.dh=NULL;
-
- BN_clear_free(pub);
+ if (dh_clnt)
+ DH_free(dh_clnt);
+ else
+ BN_clear_free(pub);
pub=NULL;
s->session->master_key_length=
s->method->ssl3_enc->generate_master_secret(s,
s->session->master_key,p,i);
OPENSSL_cleanse(p,i);
+ if (dh_clnt)
+ return 2;
}
else
#endif
SSL3_ST_SR_CERT_VRFY_A,
SSL3_ST_SR_CERT_VRFY_B,
-1,
- 514, /* 514? */
+ 516, /* Enough for 4096 bit RSA key with TLS v1.2 */
&ok);
if (!ok) return((int)n);
if (s->s3->tmp.message_type != SSL3_MT_CERTIFICATE_VERIFY)
{
s->s3->tmp.reuse_message=1;
- if ((peer != NULL) && (type | EVP_PKT_SIGN))
+ if ((peer != NULL) && (type & EVP_PKT_SIGN))
{
al=SSL_AD_UNEXPECTED_MESSAGE;
SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_MISSING_VERIFY_MESSAGE);
if (i <= 0)
{
al=ssl_verify_alarm_type(s->verify_result);
- SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,SSL_R_NO_CERTIFICATE_RETURNED);
+ SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,SSL_R_CERTIFICATE_VERIFY_FAILED);
goto f_err;
}
}
int ssl3_send_server_certificate(SSL *s)
{
unsigned long l;
- X509 *x;
+ CERT_PKEY *cpk;
if (s->state == SSL3_ST_SW_CERT_A)
{
- x=ssl_get_server_send_cert(s);
- if (x == NULL)
+ cpk=ssl_get_server_send_pkey(s);
+ if (cpk == NULL)
{
/* VRS: allow null cert if auth == KRB5 */
if ((s->s3->tmp.new_cipher->algorithm_auth != SSL_aKRB5) ||
}
}
- l=ssl3_output_cert_chain(s,x);
+ l=ssl3_output_cert_chain(s,cpk);
s->state=SSL3_ST_SW_CERT_B;
s->init_num=(int)l;
s->init_off=0;
return 1;
}
# endif
+
+int tls1_send_server_supplemental_data(SSL *s)
+ {
+ size_t length = 0;
+ const unsigned char *authz, *orig_authz;
+ unsigned char *p;
+ size_t authz_length, i;
+
+ if (s->state != SSL3_ST_SW_SUPPLEMENTAL_DATA_A)
+ return ssl3_do_write(s, SSL3_RT_HANDSHAKE);
+
+ orig_authz = authz = ssl_get_authz_data(s, &authz_length);
+ if (authz == NULL)
+ {
+ /* This should never occur. */
+ return 0;
+ }
+
+ /* First we walk over the authz data to see how long the handshake
+ * message will be. */
+ for (i = 0; i < authz_length; i++)
+ {
+ unsigned short len;
+ unsigned char type;
+
+ type = *(authz++);
+ n2s(authz, len);
+ /* n2s increments authz by 2*/
+ i += 2;
+
+ if (memchr(s->s3->tlsext_authz_client_types,
+ type,
+ s->s3->tlsext_authz_client_types_len) != NULL)
+ length += 1 /* authz type */ + 2 /* length */ + len;
+
+ authz += len;
+ i += len;
+ }
+
+ length += 1 /* handshake type */ +
+ 3 /* handshake length */ +
+ 3 /* supplemental data length */ +
+ 2 /* supplemental entry type */ +
+ 2 /* supplemental entry length */;
+
+ if (!BUF_MEM_grow_clean(s->init_buf, length))
+ {
+ SSLerr(SSL_F_TLS1_SEND_SERVER_SUPPLEMENTAL_DATA,ERR_R_BUF_LIB);
+ return 0;
+ }
+
+ p = (unsigned char *)s->init_buf->data;
+ *(p++) = SSL3_MT_SUPPLEMENTAL_DATA;
+ /* Handshake length */
+ l2n3(length - 4, p);
+ /* Length of supplemental data */
+ l2n3(length - 7, p);
+ /* Supplemental data type */
+ s2n(TLSEXT_SUPPLEMENTALDATATYPE_authz_data, p);
+ /* Its length */
+ s2n(length - 11, p);
+
+ authz = orig_authz;
+
+ /* Walk over the authz again and append the selected elements. */
+ for (i = 0; i < authz_length; i++)
+ {
+ unsigned short len;
+ unsigned char type;
+
+ type = *(authz++);
+ n2s(authz, len);
+ /* n2s increments authz by 2 */
+ i += 2;
+
+ if (memchr(s->s3->tlsext_authz_client_types,
+ type,
+ s->s3->tlsext_authz_client_types_len) != NULL)
+ {
+ *(p++) = type;
+ s2n(len, p);
+ memcpy(p, authz, len);
+ p += len;
+ }
+
+ authz += len;
+ i += len;
+ }
+
+ s->state = SSL3_ST_SW_SUPPLEMENTAL_DATA_B;
+ s->init_num = length;
+ s->init_off = 0;
+
+ return ssl3_do_write(s, SSL3_RT_HANDSHAKE);
+ }
#endif