#include <openssl/evp.h>
#include "ssl_locl.h"
+#ifndef NO_KRB5
+#include "kssl.h"
+#endif
+
static SSL_METHOD *ssl3_get_client_method(int ver);
static int ssl3_client_hello(SSL *s);
static int ssl3_get_server_hello(SSL *s);
static int ssl3_get_certificate_request(SSL *s);
-static int ca_dn_cmp(X509_NAME **a,X509_NAME **b);
+static int ca_dn_cmp(const X509_NAME * const *a,const X509_NAME * const *b);
static int ssl3_get_server_done(SSL *s);
static int ssl3_send_client_verify(SSL *s);
static int ssl3_send_client_certificate(SSL *s);
if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_START,1);
if ((s->version & 0xff00 ) != 0x0300)
- abort();
+ {
+ SSLerr(SSL_F_SSL3_CONNECT, SSL_R_INTERNAL_ERROR);
+ ret = -1;
+ goto end;
+ }
+
/* s->version=SSL3_VERSION; */
s->type=SSL_ST_CONNECT;
STACK_OF(X509) *sk=NULL;
SESS_CERT *sc;
EVP_PKEY *pkey=NULL;
+ int need_cert = 1; /* VRS: 0=> will allow null cert if auth == KRB5 */
n=ssl3_get_message(s,
SSL3_ST_CR_CERT_A,
SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,SSL_R_CERTIFICATE_VERIFY_FAILED);
goto f_err;
}
+ ERR_clear_error(); /* but we keep s->verify_result */
sc=ssl_sess_cert_new();
if (sc == NULL) goto err;
s->session->sess_cert=sc;
sc->cert_chain=sk;
+ /* Inconsistency alert: cert_chain does include the peer's
+ * certificate, which we don't include in s3_srvr.c */
x=sk_X509_value(sk,0);
sk=NULL;
+ /* VRS 19990621: possible memory leak; sk=null ==> !sk_pop_free() @end */
pkey=X509_get_pubkey(x);
- if ((pkey == NULL) || EVP_PKEY_missing_parameters(pkey))
+ /* VRS: allow null cert if auth == KRB5 */
+ need_cert =
+ ((s->s3->tmp.new_cipher->algorithms & (SSL_MKEY_MASK|SSL_AUTH_MASK))
+ == (SSL_aKRB5|SSL_kKRB5))? 0: 1;
+
+#ifdef KSSL_DEBUG
+ printf("pkey,x = %p, %p\n", pkey,x);
+ printf("ssl_cert_type(x,pkey) = %d\n", ssl_cert_type(x,pkey));
+ printf("cipher, alg, nc = %s, %lx, %d\n", s->s3->tmp.new_cipher->name,
+ s->s3->tmp.new_cipher->algorithms, need_cert);
+#endif /* KSSL_DEBUG */
+
+ if (need_cert && ((pkey == NULL) || EVP_PKEY_missing_parameters(pkey)))
{
x=NULL;
al=SSL3_AL_FATAL;
}
i=ssl_cert_type(x,pkey);
- if (i < 0)
+ if (need_cert && i < 0)
{
x=NULL;
al=SSL3_AL_FATAL;
goto f_err;
}
- sc->peer_cert_type=i;
- CRYPTO_add(&x->references,1,CRYPTO_LOCK_X509);
- if (sc->peer_pkeys[i].x509 != NULL) /* Why would this ever happen?
- * We just created sc a couple of
- * lines ago. */
- X509_free(sc->peer_pkeys[i].x509);
- sc->peer_pkeys[i].x509=x;
- sc->peer_key= &(sc->peer_pkeys[i]);
-
- if (s->session->peer != NULL)
- X509_free(s->session->peer);
- CRYPTO_add(&x->references,1,CRYPTO_LOCK_X509);
- s->session->peer=x;
+ if (need_cert)
+ {
+ sc->peer_cert_type=i;
+ CRYPTO_add(&x->references,1,CRYPTO_LOCK_X509);
+ /* Why would the following ever happen?
+ * We just created sc a couple of lines ago. */
+ if (sc->peer_pkeys[i].x509 != NULL)
+ X509_free(sc->peer_pkeys[i].x509);
+ sc->peer_pkeys[i].x509=x;
+ sc->peer_key= &(sc->peer_pkeys[i]);
+
+ if (s->session->peer != NULL)
+ X509_free(s->session->peer);
+ CRYPTO_add(&x->references,1,CRYPTO_LOCK_X509);
+ s->session->peer=x;
+ }
+ else
+ {
+ sc->peer_cert_type=i;
+ sc->peer_key= NULL;
+
+ if (s->session->peer != NULL)
+ X509_free(s->session->peer);
+ s->session->peer=NULL;
+ }
+ s->session->verify_result = s->verify_result;
x=NULL;
ret=1;
s->session->sess_cert->peer_rsa_tmp=rsa;
rsa=NULL;
}
- else
+#else /* NO_RSA */
+ if (0)
+ ;
#endif
#ifndef NO_DH
- if (alg & SSL_kEDH)
+ else if (alg & SSL_kEDH)
{
if ((dh=DH_new()) == NULL)
{
#ifndef NO_RSA
if (alg & SSL_aRSA)
pkey=X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_RSA_ENC].x509);
- else
+#else
+ if (0)
+ ;
#endif
#ifndef NO_DSA
- if (alg & SSL_aDSS)
+ else if (alg & SSL_aDSS)
pkey=X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_DSA_SIGN].x509);
#endif
/* else anonymous DH, so no certificate or pkey. */
SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_TRIED_TO_USE_UNSUPPORTED_CIPHER);
goto f_err;
}
-#endif
+#endif /* !NO_DH */
if (alg & SSL_aFZA)
{
al=SSL_AD_HANDSHAKE_FAILURE;
return(ret);
}
-static int ca_dn_cmp(X509_NAME **a, X509_NAME **b)
+static int ca_dn_cmp(const X509_NAME * const *a, const X509_NAME * const *b)
{
return(X509_NAME_cmp(*a,*b));
}
unsigned char *q;
EVP_PKEY *pkey=NULL;
#endif
+#ifndef NO_KRB5
+ KSSL_ERR kssl_err;
+#endif /* NO_KRB5 */
if (s->state == SSL3_ST_CW_KEY_EXCH_A)
{
l=s->s3->tmp.new_cipher->algorithms;
+ /* Fool emacs indentation */
+ if (0) {}
#ifndef NO_RSA
- if (l & SSL_kRSA)
+ else if (l & SSL_kRSA)
{
RSA *rsa;
unsigned char tmp_buf[SSL_MAX_MASTER_KEY_LENGTH];
tmp_buf,SSL_MAX_MASTER_KEY_LENGTH);
memset(tmp_buf,0,SSL_MAX_MASTER_KEY_LENGTH);
}
- else
+#endif
+#ifndef NO_KRB5
+ else if (l & SSL_kKRB5)
+ {
+ krb5_error_code krb5rc;
+ KSSL_CTX *kssl_ctx = s->kssl_ctx;
+ krb5_data krb5_ap_req;
+
+#ifdef KSSL_DEBUG
+ printf("ssl3_send_client_key_exchange(%lx & %lx)\n",
+ l, SSL_kKRB5);
+#endif /* KSSL_DEBUG */
+
+ /*
+ ** Tried to send random tmp_buf[] as PMS in Kerberos ticket
+ ** by passing krb5_mk_req_extended(ctx,authctx,opts, tmp_buf, ...)
+ ** but: I can't retrieve the PMS on the other side! There is
+ ** some indication in the krb5 source that this is only used
+ ** to generate a checksum. OTOH, the Tung book shows data
+ ** ("GET widget01.txt") being passed in krb5_mk_req_extended()
+ ** by way of krb5_sendauth(). I don't get it.
+ ** Until Kerberos goes 3DES, the big PMS secret would only be
+ ** encrypted in 1-DES anyway. So losing the PMS shouldn't be
+ ** a big deal.
+ */
+ krb5rc = kssl_cget_tkt(kssl_ctx, &krb5_ap_req,
+ &kssl_err);
+#ifdef KSSL_DEBUG
+ {
+ printf("kssl_cget_tkt rtn %d\n", krb5rc);
+ kssl_ctx_show(kssl_ctx);
+ if (krb5rc && kssl_err.text)
+ printf("kssl_cget_tkt kssl_err=%s\n", kssl_err.text);
+ }
+#endif /* KSSL_DEBUG */
+
+ if (krb5rc)
+ {
+ ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_HANDSHAKE_FAILURE);
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, kssl_err.reason);
+ goto err;
+ }
+
+ /* Send ticket (copy to *p, set n = length)
+ */
+ n = krb5_ap_req.length;
+ memcpy(p, krb5_ap_req.data, krb5_ap_req.length);
+ if (krb5_ap_req.data)
+ kssl_krb5_free_data_contents(NULL,&krb5_ap_req);
+
+ /* 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 ((s->) client_random, server_random)
+ ** could be sniffed. Mixing in these nonces should help
+ ** protect against replay attacks, however.
+ **
+ ** 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);
+ }
#endif
#ifndef NO_DH
- if (l & (SSL_kEDH|SSL_kDHr|SSL_kDHd))
+ else if (l & (SSL_kEDH|SSL_kDHr|SSL_kDHd))
{
DH *dh_srvr,*dh_clnt;
/* perhaps clean things up a bit EAY EAY EAY EAY*/
}
- else
#endif
+ else
{
ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_HANDSHAKE_FAILURE);
SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,SSL_R_INTERNAL_ERROR);
algs=s->s3->tmp.new_cipher->algorithms;
/* we don't have a certificate */
- if (algs & (SSL_aDH|SSL_aNULL))
+ if (algs & (SSL_aDH|SSL_aNULL|SSL_aKRB5))
return(1);
#ifndef NO_RSA