*/
#define REUSE_CIPHER_BUG
+#define NETSCAPE_HANG_BUG
+
#include <stdio.h>
#include <openssl/buffer.h>
#include <openssl/x509.h>
#include "ssl_locl.h"
+#ifndef NO_KRB5
+#include "kssl.h"
+#endif /* NO_KRB5 */
+
static SSL_METHOD *ssl3_get_server_method(int ver);
static int ssl3_get_client_hello(SSL *s);
static int ssl3_check_client_hello(SSL *s);
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 (cb != NULL) cb(s,SSL_CB_HANDSHAKE_START,1);
if ((s->version>>8) != 3)
- abort();
- /* s->version=SSL3_VERSION; */
+ {
+ SSLerr(SSL_F_SSL3_ACCEPT, SSL_R_INTERNAL_ERROR);
+ return -1;
+ }
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++;
}
/* clear this, it may get reset by
* send_server_key_exchange */
- if (s->options & SSL_OP_EPHEMERAL_RSA)
+ if ((s->options & SSL_OP_EPHEMERAL_RSA)
+#ifndef NO_KRB5
+ && !(l & SSL_KRB5)
+#endif /* NO_KRB5 */
+ )
s->s3->tmp.use_rsa_tmp=1;
else
s->s3->tmp.use_rsa_tmp=0;
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;
}
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 */
BIGNUM *pub=NULL;
DH *dh_srvr;
#endif
+#ifndef NO_KRB5
+ KSSL_ERR kssl_err;
+#endif /* NO_KRB5 */
n=ssl3_get_message(s,
SSL3_ST_SR_KEY_EXCH_A,
SSL3_ST_SR_KEY_EXCH_B,
SSL3_MT_CLIENT_KEY_EXCHANGE,
- 400, /* ???? */
+ 2048, /* ??? */
&ok);
if (!ok) return((int)n);
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,
}
else
#endif
+#ifndef NO_KRB5
+ if (l & SSL_kKRB5)
+ {
+ krb5_error_code krb5rc;
+ KSSL_CTX *kssl_ctx = s->kssl_ctx;
+
+ if (!kssl_ctx) kssl_ctx = kssl_ctx_new();
+ if ((krb5rc = kssl_sget_tkt(kssl_ctx,
+ s->init_buf->data, s->init_buf->length,
+ &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);
+#endif /* KSSL_DEBUG */
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+ kssl_err.reason);
+ goto err;
+ }
+
+#ifdef KSSL_DEBUG
+ kssl_ctx_show(kssl_ctx);
+#endif /* KSSL_DEBUG */
+
+ /* 19991013 VRS - 3DES is kind of bogus here,
+ ** at least until Kerberos supports 3DES. The only
+ ** real secret is the 8-byte Kerberos session key;
+ ** the other key material (client_random, server_random)
+ ** could be sniffed. Nonces may help against replays though.
+ **
+ ** Alternate code for Kerberos Purists:
+ **
+ ** memcpy(s->session->master_key, kssl_ctx->key, kssl_ctx->length);
+ ** s->session->master_key_length = kssl_ctx->length;
+ */
+ s->session->master_key_length=
+ s->method->ssl3_enc->generate_master_secret(s,
+ s->session->master_key, kssl_ctx->key, kssl_ctx->length);
+ /* 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;
+ */
+ }
+ else
+#endif /* NO_KRB5 */
{
al=SSL_AD_HANDSHAKE_FAILURE;
SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_UNKNOWN_CIPHER_TYPE);
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;
if (s->state == SSL3_ST_SW_CERT_A)
{
x=ssl_get_server_send_cert(s);
- if (x == NULL)
+ 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))
{
SSLerr(SSL_F_SSL3_SEND_SERVER_CERTIFICATE,SSL_R_INTERNAL_ERROR);
return(0);