X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=ssl%2Fs3_srvr.c;h=66c063a7ba492449e7ce27c366b59082c801869d;hp=8cf1e1fd823d70fdf3e9ef6d60cf42ad7e246214;hb=bfd502f027ffb83131f3e9c634f95d3176477591;hpb=fcbdde0dfe155592c9b6f39d204025b4d27fa9c1 diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c index 8cf1e1fd82..66c063a7ba 100644 --- a/ssl/s3_srvr.c +++ b/ssl/s3_srvr.c @@ -514,6 +514,9 @@ int ssl3_accept(SSL *s) * the client sends its ECDH pub key in * a certificate, the CertificateVerify * message is not sent. + * Also for GOST ciphersuites when + * the client uses its key from the certificate + * for key exchange. */ s->state=SSL3_ST_SR_FINISHED_A; s->init_num = 0; @@ -522,6 +525,7 @@ int ssl3_accept(SSL *s) { int offset=0; int dgst_num; + s->state=SSL3_ST_SR_CERT_VRFY_A; s->init_num=0; @@ -531,12 +535,21 @@ int ssl3_accept(SSL *s) * should be generalized. But it is next step */ if (s->s3->handshake_buffer) - ssl3_digest_cached_records(s); + if (!ssl3_digest_cached_records(s)) + return -1; for (dgst_num=0; dgst_nums3->handshake_dgst[dgst_num]) { + int dgst_size; + s->method->ssl3_enc->cert_verify_mac(s,EVP_MD_CTX_type(s->s3->handshake_dgst[dgst_num]),&(s->s3->tmp.cert_verify_md[offset])); - offset+=EVP_MD_CTX_size(s->s3->handshake_dgst[dgst_num]); + dgst_size=EVP_MD_CTX_size(s->s3->handshake_dgst[dgst_num]); + if (dgst_size < 0) + { + ret = -1; + goto end; + } + offset+=dgst_size; } } break; @@ -947,22 +960,28 @@ int ssl3_get_client_hello(SSL *s) break; } } - if (j == 0) + if (j == 0 && (s->options & SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG) && (sk_SSL_CIPHER_num(ciphers) == 1)) { - if ((s->options & SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG) && (sk_SSL_CIPHER_num(ciphers) == 1)) + /* Special case as client bug workaround: the previously used cipher may + * not be in the current list, the client instead might be trying to + * continue using a cipher that before wasn't chosen due to server + * preferences. We'll have to reject the connection if the cipher is not + * enabled, though. */ + c = sk_SSL_CIPHER_value(ciphers, 0); + if (sk_SSL_CIPHER_find(SSL_get_ciphers(s), c) >= 0) { - /* Very bad for multi-threading.... */ - s->session->cipher=sk_SSL_CIPHER_value(ciphers, 0); - } - else - { - /* we need to have the cipher in the cipher - * list if we are asked to reuse it */ - al=SSL_AD_ILLEGAL_PARAMETER; - SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_REQUIRED_CIPHER_MISSING); - goto f_err; + s->session->cipher = c; + j = 1; } } + if (j == 0) + { + /* we need to have the cipher in the cipher + * list if we are asked to reuse it */ + al=SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_REQUIRED_CIPHER_MISSING); + goto f_err; + } } /* compression */ @@ -1004,6 +1023,59 @@ int ssl3_get_client_hello(SSL *s) 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 + * handshake for not reused session only. We need to generate + * server_random before calling tls_session_secret_cb in order to allow + * SessionTicket processing to use it in key derivation. */ + { + unsigned long Time; + unsigned char *pos; + Time=(unsigned long)time(NULL); /* Time */ + pos=s->s3->server_random; + l2n(Time,pos); + if (RAND_pseudo_bytes(pos,SSL3_RANDOM_SIZE-4) <= 0) + { + al=SSL_AD_INTERNAL_ERROR; + goto f_err; + } + } + + if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb) + { + SSL_CIPHER *pref_cipher=NULL; + + s->session->master_key_length=sizeof(s->session->master_key); + if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length, + ciphers, &pref_cipher, s->tls_session_secret_cb_arg)) + { + s->hit=1; + s->session->ciphers=ciphers; + s->session->verify_result=X509_V_OK; + + ciphers=NULL; + + /* check if some cipher was preferred by call back */ + pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s)); + if (pref_cipher == NULL) + { + al=SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER); + goto f_err; + } + + s->session->cipher=pref_cipher; + + if (s->cipher_list) + sk_SSL_CIPHER_free(s->cipher_list); + + if (s->cipher_list_by_id) + sk_SSL_CIPHER_free(s->cipher_list_by_id); + + s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers); + s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers); + } + } #endif /* Worst case, we will use the NULL compression, but if we have other @@ -1099,7 +1171,8 @@ int ssl3_get_client_hello(SSL *s) s->s3->tmp.new_cipher=s->session->cipher; } - ssl3_digest_cached_records(s); + if (!ssl3_digest_cached_records(s)) + goto f_err; /* we now have the following setup. * client_random @@ -1128,16 +1201,22 @@ int ssl3_send_server_hello(SSL *s) unsigned char *buf; unsigned char *p,*d; int i,sl; - unsigned long l,Time; + unsigned long l; +#ifdef OPENSSL_NO_TLSEXT + unsigned long Time; +#endif if (s->state == SSL3_ST_SW_SRVR_HELLO_A) { buf=(unsigned char *)s->init_buf->data; +#ifdef OPENSSL_NO_TLSEXT p=s->s3->server_random; + /* Generate server_random if it was not needed previously */ Time=(unsigned long)time(NULL); /* Time */ l2n(Time,p); if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0) return -1; +#endif /* Do the message type and length last */ d=p= &(buf[4]); @@ -1844,7 +1923,7 @@ int ssl3_get_client_key_exchange(SSL *s) } /* TLS and [incidentally] DTLS{0xFEFF} */ - if (s->version > SSL3_VERSION) + if (s->version > SSL3_VERSION && s->version != DTLS1_BAD_VER) { n2s(p,i); if (n != i+2) @@ -1989,7 +2068,7 @@ int ssl3_get_client_key_exchange(SSL *s) krb5_data enc_pms; KSSL_CTX *kssl_ctx = s->kssl_ctx; EVP_CIPHER_CTX ciph_ctx; - EVP_CIPHER *enc = NULL; + const EVP_CIPHER *enc = NULL; unsigned char iv[EVP_MAX_IV_LENGTH]; unsigned char pms[SSL_MAX_MASTER_KEY_LENGTH + EVP_MAX_BLOCK_LENGTH]; @@ -2004,7 +2083,7 @@ int ssl3_get_client_key_exchange(SSL *s) n2s(p,i); enc_ticket.length = i; - if (n < enc_ticket.length + 6) + if (n < (long)(enc_ticket.length + 6)) { SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, SSL_R_DATA_LENGTH_TOO_LONG); @@ -2017,7 +2096,7 @@ int ssl3_get_client_key_exchange(SSL *s) n2s(p,i); authenticator.length = i; - if (n < enc_ticket.length + authenticator.length + 6) + if (n < (long)(enc_ticket.length + authenticator.length + 6)) { SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, SSL_R_DATA_LENGTH_TOO_LONG); @@ -2310,9 +2389,10 @@ int ssl3_get_client_key_exchange(SSL *s) EVP_PKEY_free(clnt_pub_pkey); EC_POINT_free(clnt_ecpoint); - if (srvr_ecdh != NULL) - EC_KEY_free(srvr_ecdh); + EC_KEY_free(srvr_ecdh); BN_CTX_free(bn_ctx); + EC_KEY_free(s->s3->tmp.ecdh); + s->s3->tmp.ecdh = NULL; /* Compute the master secret */ s->session->master_key_length = s->method->ssl3_enc-> \ @@ -2419,33 +2499,70 @@ int ssl3_get_client_key_exchange(SSL *s) else #endif if (alg_k & SSL_kGOST) - { + { + int ret = 0; EVP_PKEY_CTX *pkey_ctx; - unsigned char premaster_secret[32]; - size_t outlen; + EVP_PKEY *client_pub_pkey = NULL; + unsigned char premaster_secret[32], *start; + size_t outlen, inlen; - /* Get our certificate privatec key*/ + /* Get our certificate private key*/ pkey_ctx = EVP_PKEY_CTX_new(s->cert->key->privatekey,NULL); EVP_PKEY_decrypt_init(pkey_ctx); + /* If client certificate is present and is of the same type, maybe + * use it for key exchange. Don't mind errors from + * EVP_PKEY_derive_set_peer, because it is completely valid to use + * a client certificate for authorization only. */ + client_pub_pkey = X509_get_pubkey(s->session->peer); + if (client_pub_pkey) + { + if (EVP_PKEY_derive_set_peer(pkey_ctx, client_pub_pkey) <= 0) + ERR_clear_error(); + } /* Decrypt session key */ - if ((*p!=( V_ASN1_SEQUENCE| V_ASN1_CONSTRUCTED)) || p[1]!=0x81 ) + if ((*p!=( V_ASN1_SEQUENCE| V_ASN1_CONSTRUCTED))) { SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_DECRYPTION_FAILED); - goto err; - } - if (EVP_PKEY_decrypt(pkey_ctx,premaster_secret,&outlen,p+3,p[2]) <0) + goto gerr; + } + if (p[1] == 0x81) + { + start = p+3; + inlen = p[2]; + } + else if (p[1] < 0x80) + { + start = p+2; + inlen = p[1]; + } + else + { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_DECRYPTION_FAILED); + goto gerr; + } + if (EVP_PKEY_decrypt(pkey_ctx,premaster_secret,&outlen,start,inlen) <=0) { SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_DECRYPTION_FAILED); - goto err; + goto gerr; } /* Generate master secret */ - EVP_PKEY_CTX_free(pkey_ctx); s->session->master_key_length= s->method->ssl3_enc->generate_master_secret(s, s->session->master_key,premaster_secret,32); - - } + /* Check if pubkey from client certificate was used */ + if (EVP_PKEY_CTX_ctrl(pkey_ctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 2, NULL) > 0) + ret = 2; + else + ret = 1; + gerr: + EVP_PKEY_free(client_pub_pkey); + EVP_PKEY_CTX_free(pkey_ctx); + if (ret) + return ret; + else + goto err; + } else { al=SSL_AD_HANDSHAKE_FAILURE; @@ -2769,7 +2886,7 @@ int ssl3_get_client_certificate(SSL *s) else { i=ssl_verify_cert_chain(s,sk); - if (!i) + if (i <= 0) { al=ssl_verify_alarm_type(s->verify_result); SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,SSL_R_NO_CERTIFICATE_RETURNED);