X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=ssl%2Fs3_clnt.c;h=3b3c35b9d3d84dcdd815dc524b1c74ba0628b8dc;hp=1f4e3239aa5601cd8869eb395a2a7fe9c04f082b;hb=792e2ce7f47f90ee18c08da11a25ed907e8d9c33;hpb=6b521df33c92ff05f70556c105fb750e3c7b9f90 diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c index 1f4e3239aa..3b3c35b9d3 100644 --- a/ssl/s3_clnt.c +++ b/ssl/s3_clnt.c @@ -65,11 +65,15 @@ #include #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); @@ -110,7 +114,7 @@ int ssl3_connect(SSL *s) int ret= -1; int new_state,state,skip=0;; - RAND_seed(&Time,sizeof(Time)); + RAND_add(&Time,sizeof(Time),0); ERR_clear_error(); clear_sys_error(); @@ -142,7 +146,12 @@ int ssl3_connect(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; @@ -325,8 +334,8 @@ int ssl3_connect(SSL *s) case SSL3_ST_CW_FINISHED_B: ret=ssl3_send_finished(s, SSL3_ST_CW_FINISHED_A,SSL3_ST_CW_FINISHED_B, - s->method->ssl3_enc->client_finished, - s->method->ssl3_enc->client_finished_len); + s->method->ssl3_enc->client_finished_label, + s->method->ssl3_enc->client_finished_label_len); if (ret <= 0) goto end; s->state=SSL3_ST_CW_FLUSH; @@ -466,7 +475,7 @@ static int ssl3_client_hello(SSL *s) p=s->s3->client_random; Time=time(NULL); /* Time */ l2n(Time,p); - RAND_bytes(p,SSL3_RANDOM_SIZE-sizeof(Time)); + RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-sizeof(Time)); /* Do the message type and length last */ d=p= &(buf[4]); @@ -682,6 +691,7 @@ static int ssl3_get_server_certificate(SSL *s) 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, @@ -764,6 +774,7 @@ static int ssl3_get_server_certificate(SSL *s) 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; @@ -772,12 +783,27 @@ static int ssl3_get_server_certificate(SSL *s) 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; @@ -786,7 +812,7 @@ static int ssl3_get_server_certificate(SSL *s) } i=ssl_cert_type(x,pkey); - if (i < 0) + if (need_cert && i < 0) { x=NULL; al=SSL3_AL_FATAL; @@ -794,19 +820,32 @@ static int ssl3_get_server_certificate(SSL *s) 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; @@ -932,10 +971,12 @@ static int ssl3_get_key_exchange(SSL *s) 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) { @@ -991,10 +1032,12 @@ static int ssl3_get_key_exchange(SSL *s) #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. */ @@ -1008,7 +1051,7 @@ static int ssl3_get_key_exchange(SSL *s) 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; @@ -1053,15 +1096,15 @@ static int ssl3_get_key_exchange(SSL *s) q+=i; j+=i; } - i=RSA_public_decrypt((int)n,p,p,pkey->pkey.rsa, - RSA_PKCS1_PADDING); - if (i <= 0) + i=RSA_verify(NID_md5_sha1, md_buf, j, p, n, + pkey->pkey.rsa); + if (i < 0) { al=SSL_AD_DECRYPT_ERROR; SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_RSA_DECRYPT); goto f_err; } - if ((j != i) || (memcmp(p,md_buf,i) != 0)) + if (i == 0) { /* bad signature */ al=SSL_AD_DECRYPT_ERROR; @@ -1225,7 +1268,7 @@ fclose(out); if ((xn=d2i_X509_NAME(NULL,&q,l)) == NULL) { - /* If netscape tollerance is on, ignore errors */ + /* If netscape tolerance is on, ignore errors */ if (s->options & SSL_OP_NETSCAPE_CA_DN_BUG) goto cont; else @@ -1258,7 +1301,7 @@ cont: ERR_clear_error(); } - /* we should setup a certficate to return.... */ + /* we should setup a certificate to return.... */ s->s3->tmp.cert_req=1; s->s3->tmp.ctype_num=ctype_num; if (s->s3->tmp.ca_names != NULL) @@ -1272,7 +1315,7 @@ err: 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)); } @@ -1309,6 +1352,9 @@ static int ssl3_send_client_key_exchange(SSL *s) 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) { @@ -1317,8 +1363,10 @@ static int ssl3_send_client_key_exchange(SSL *s) 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]; @@ -1336,11 +1384,13 @@ static int ssl3_send_client_key_exchange(SSL *s) goto err; } rsa=pkey->pkey.rsa; + EVP_PKEY_free(pkey); } tmp_buf[0]=s->client_version>>8; tmp_buf[1]=s->client_version&0xff; - RAND_bytes(&(tmp_buf[2]),SSL_MAX_MASTER_KEY_LENGTH-2); + if (RAND_bytes(&(tmp_buf[2]),SSL_MAX_MASTER_KEY_LENGTH-2) <= 0) + goto err; s->session->master_key_length=SSL_MAX_MASTER_KEY_LENGTH; @@ -1373,10 +1423,75 @@ static int ssl3_send_client_key_exchange(SSL *s) 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; @@ -1430,8 +1545,8 @@ static int ssl3_send_client_key_exchange(SSL *s) /* 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); @@ -1459,7 +1574,7 @@ static int ssl3_send_client_verify(SSL *s) unsigned char data[MD5_DIGEST_LENGTH+SHA_DIGEST_LENGTH]; EVP_PKEY *pkey; #ifndef NO_RSA - int i=0; + unsigned u=0; #endif unsigned long n; #ifndef NO_DSA @@ -1480,17 +1595,15 @@ static int ssl3_send_client_verify(SSL *s) { s->method->ssl3_enc->cert_verify_mac(s, &(s->s3->finish_dgst1),&(data[0])); - i=RSA_private_encrypt( - MD5_DIGEST_LENGTH+SHA_DIGEST_LENGTH, - data,&(p[2]),pkey->pkey.rsa, - RSA_PKCS1_PADDING); - if (i <= 0) + if (RSA_sign(NID_md5_sha1, data, + MD5_DIGEST_LENGTH+SHA_DIGEST_LENGTH, + &(p[2]), &u, pkey->pkey.rsa) <= 0 ) { SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY,ERR_R_RSA_LIB); goto err; } - s2n(i,p); - n=i+2; + s2n(u,p); + n=u+2; } else #endif @@ -1628,7 +1741,7 @@ static int ssl3_check_cert_and_algorithm(SSL *s) 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 @@ -1688,13 +1801,13 @@ static int ssl3_check_cert_and_algorithm(SSL *s) #endif #endif - if (SSL_IS_EXPORT(algs) && !has_bits(i,EVP_PKT_EXP)) + if (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) && !has_bits(i,EVP_PKT_EXP)) { #ifndef NO_RSA if (algs & SSL_kRSA) { if (rsa == NULL - || RSA_size(rsa) > SSL_EXPORT_PKEYLENGTH(algs)) + || RSA_size(rsa) > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)) { SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_MISSING_EXPORT_TMP_RSA_KEY); goto f_err; @@ -1706,7 +1819,7 @@ static int ssl3_check_cert_and_algorithm(SSL *s) if (algs & (SSL_kEDH|SSL_kDHr|SSL_kDHd)) { if (dh == NULL - || DH_size(dh) > SSL_EXPORT_PKEYLENGTH(algs)) + || DH_size(dh) > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)) { SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_MISSING_EXPORT_TMP_DH_KEY); goto f_err;