*/
#define REUSE_CIPHER_BUG
+#define NETSCAPE_HANG_BUG
+
#include <stdio.h>
#include <openssl/buffer.h>
static int ssl3_send_server_key_exchange(SSL *s);
static int ssl3_send_certificate_request(SSL *s);
static int ssl3_send_server_done(SSL *s);
-static int ssl3_get_cert_verify(SSL *s);
static int ssl3_get_client_key_exchange(SSL *s);
static int ssl3_get_client_certificate(SSL *s);
+static int ssl3_get_cert_verify(SSL *s);
static int ssl3_send_hello_request(SSL *s);
static SSL_METHOD *ssl3_get_server_method(int ver)
s->new_session=1;
/* s->state=SSL_ST_ACCEPT; */
- case SSL3_ST_SR_MS_SGC:
case SSL_ST_BEFORE:
case SSL_ST_ACCEPT:
case SSL_ST_BEFORE|SSL_ST_ACCEPT:
if ((s->version>>8) != 3)
abort();
- /* s->version=SSL3_VERSION; */
s->type=SSL_ST_ACCEPT;
if (s->init_buf == NULL)
if (s->state != SSL_ST_RENEGOTIATE)
{
- if(s->state != SSL3_ST_SR_MS_SGC) ssl3_init_finished_mac(s);
+ ssl3_init_finished_mac(s);
s->state=SSL3_ST_SR_CLNT_HELLO_A;
s->ctx->stats.sess_accept++;
}
s->s3->tmp.cert_request=1;
ret=ssl3_send_certificate_request(s);
if (ret <= 0) goto end;
+#ifndef NETSCAPE_HANG_BUG
s->state=SSL3_ST_SW_SRVR_DONE_A;
+#else
+ s->state=SSL3_ST_SW_FLUSH;
+ s->s3->tmp.next_state=SSL3_ST_SR_CERT_A;
+#endif
s->init_num=0;
}
break;
case SSL3_ST_SR_CERT_A:
case SSL3_ST_SR_CERT_B:
- /* Check for second client hello if MS SGC */
+ /* Check for second client hello (MS SGC) */
ret = ssl3_check_client_hello(s);
- if(ret <= 0) goto end;
- if(ret == 2) s->state = SSL3_ST_SR_MS_SGC;
+ if (ret <= 0)
+ goto end;
+ if (ret == 2)
+ s->state = SSL3_ST_SR_CLNT_HELLO_C;
else {
/* could be sent for a DH cert, even if we
* have not asked for it :-) */
&ok);
if (!ok) return((int)n);
s->s3->tmp.reuse_message = 1;
- if(s->s3->tmp.message_type == SSL3_MT_CLIENT_HELLO) return 2;
+ 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 ... */
+#ifndef NO_DH
+ if (s->s3->tmp.dh != NULL)
+ {
+ DH_free(s->s3->tmp.dh);
+ s->s3->tmp.dh = NULL;
+ }
+#endif
+ return 2;
+ }
return 1;
}
* compression - basically ignored right now
* ssl version is set - sslv3
* s->session - The ssl session has been setup.
- * s->hit - sesson reuse flag
+ * s->hit - session reuse flag
* s->tmp.new_cipher - the new cipher to use.
*/
rsa=s->cert->rsa_tmp_cb(s,
SSL_C_IS_EXPORT(s->s3->tmp.new_cipher),
SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher));
+ if(rsa == NULL)
+ {
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_ERROR_GENERATING_TMP_RSA_KEY);
+ goto f_err;
+ }
CRYPTO_add(&rsa->references,1,CRYPTO_LOCK_RSA);
cert->rsa_tmp=rsa;
}
dhp=cert->dh_tmp;
if ((dhp == NULL) && (s->cert->dh_tmp_cb != NULL))
dhp=s->cert->dh_tmp_cb(s,
- !SSL_C_IS_EXPORT(s->s3->tmp.new_cipher),
+ SSL_C_IS_EXPORT(s->s3->tmp.new_cipher),
SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher));
if (dhp == NULL)
{
s->init_num=n+4;
s->init_off=0;
+#ifdef NETSCAPE_HANG_BUG
+ p=(unsigned char *)s->init_buf->data + s->init_num;
+
+ /* do the header */
+ *(p++)=SSL3_MT_SERVER_DONE;
+ *(p++)=0;
+ *(p++)=0;
+ *(p++)=0;
+ s->init_num += 4;
+#endif
+
}
/* SSL3_ST_SW_CERT_REQ_B */
i=RSA_private_decrypt((int)n,p,p,rsa,RSA_PKCS1_PADDING);
-#if 0
- /* If a bad decrypt, use a random master key */
- if ((i != SSL_MAX_MASTER_KEY_LENGTH) ||
- ((p[0] != (s->client_version>>8)) ||
- (p[1] != (s->client_version & 0xff))))
- {
- int bad=1;
-
- if ((i == SSL_MAX_MASTER_KEY_LENGTH) &&
- (p[0] == (s->version>>8)) &&
- (p[1] == 0))
- {
- if (s->options & SSL_OP_TLS_ROLLBACK_BUG)
- bad=0;
- }
- if (bad)
- {
- p[0]=(s->version>>8);
- p[1]=(s->version & 0xff);
- RAND_pseudo_bytes(&(p[2]),SSL_MAX_MASTER_KEY_LENGTH-2);
- i=SSL_MAX_MASTER_KEY_LENGTH;
- }
- /* else, an SSLeay bug, ssl only server, tls client */
- }
-#else
if (i != SSL_MAX_MASTER_KEY_LENGTH)
{
al=SSL_AD_DECODE_ERROR;
goto f_err;
}
- if ((p[0] != (s->client_version>>8)) || (p[1] != (s->client_version & 0xff)))
+ if (!((p[0] == (s->client_version>>8)) && (p[1] == (s->client_version & 0xff))))
{
- al=SSL_AD_DECODE_ERROR;
- SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_BAD_PROTOCOL_VERSION_NUMBER);
- goto f_err;
+ /* The premaster secret must contain the same version number as the
+ * ClientHello to detect version rollback attacks (strangely, the
+ * protocol does not offer such protection for DH ciphersuites).
+ * However, buggy clients exist that send the negotiated protocol
+ * version instead if the server does not support the requested
+ * protocol version.
+ * If SSL_OP_TLS_ROLLBACK_BUG is set, tolerate such clients. */
+ if (!((s->options & SSL_OP_TLS_ROLLBACK_BUG) &&
+ (p[0] == (s->version>>8)) && (p[1] == (s->version & 0xff))))
+ {
+ al=SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_BAD_PROTOCOL_VERSION_NUMBER);
+ goto f_err;
+ }
}
-#endif
s->session->master_key_length=
s->method->ssl3_enc->generate_master_secret(s,
if (s->session->sess_cert->cert_chain != NULL)
sk_X509_pop_free(s->session->sess_cert->cert_chain, X509_free);
s->session->sess_cert->cert_chain=sk;
+ /* Inconsistency alert: cert_chain does *not* include the
+ * peer's own certificate, while we do include it in s3_clnt.c */
sk=NULL;