From a375025e4dd58a05e926a5384774a85671695dd9 Mon Sep 17 00:00:00 2001 From: mancha Date: Thu, 27 Mar 2014 00:47:14 +0000 Subject: [PATCH] Fix alert handling. Fix OpenSSL 0.9.8 alert handling. PR#3038 --- CHANGES | 6 +++ apps/s_cb.c | 18 ++++++++ crypto/err/openssl.ec | 5 +++ ssl/s23_clnt.c | 97 ++++++++++++++++++++++--------------------- ssl/s3_enc.c | 6 +++ ssl/ssl.h | 7 ++++ ssl/ssl_err.c | 5 +++ ssl/ssl_stat.c | 24 +++++++++++ ssl/t1_enc.c | 6 +++ 9 files changed, 127 insertions(+), 47 deletions(-) diff --git a/CHANGES b/CHANGES index 2d9b81e898..6a305e14ef 100644 --- a/CHANGES +++ b/CHANGES @@ -4,6 +4,12 @@ Changes between 0.9.8y and 0.9.8za [xx XXX xxxx] + *) Fix handling of warning-level alerts in SSL23 client mode so they + don't cause client-side termination (eg. on SNI unrecognized_name + warnings). Add client and server support for six additional alerts + per RFC 6066 and RFC 4279. + [mancha] + *) Add option SSL_OP_SAFARI_ECDHE_ECDSA_BUG (part of SSL_OP_ALL) which avoids preferring ECDHE-ECDSA ciphers when the client appears to be Safari on OS X. Safari on OS X 10.8..10.8.3 advertises support for diff --git a/apps/s_cb.c b/apps/s_cb.c index 97caffc401..df922f3af5 100644 --- a/apps/s_cb.c +++ b/apps/s_cb.c @@ -518,6 +518,24 @@ void MS_CALLBACK msg_cb(int write_p, int version, int content_type, const void * case 100: str_details2 = " no_renegotiation"; break; + case 110: + str_details2 = " unsupported_extension"; + break; + case 111: + str_details2 = " certificate_unobtainable"; + break; + case 112: + str_details2 = " unrecognized_name"; + break; + case 113: + str_details2 = " bad_certificate_status_response"; + break; + case 114: + str_details2 = " bad_certificate_hash_value"; + break; + case 115: + str_details2 = " unknown_psk_identity"; + break; } } } diff --git a/crypto/err/openssl.ec b/crypto/err/openssl.ec index 868826624d..1a580c5afb 100644 --- a/crypto/err/openssl.ec +++ b/crypto/err/openssl.ec @@ -71,6 +71,11 @@ R SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY 1071 R SSL_R_TLSV1_ALERT_INTERNAL_ERROR 1080 R SSL_R_TLSV1_ALERT_USER_CANCELLED 1090 R SSL_R_TLSV1_ALERT_NO_RENEGOTIATION 1100 +R SSL_R_TLSV1_UNSUPPORTED_EXTENSION 1110 +R SSL_R_TLSV1_CERTIFICATE_UNOBTAINABLE 1111 +R SSL_R_TLSV1_UNRECOGNIZED_NAME 1112 +R SSL_R_TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE 1113 +R SSL_R_TLSV1_BAD_CERTIFICATE_HASH_VALUE 1114 R RSAREF_R_CONTENT_ENCODING 0x0400 R RSAREF_R_DATA 0x0401 diff --git a/ssl/s23_clnt.c b/ssl/s23_clnt.c index c6b9142c90..830eff0f51 100644 --- a/ssl/s23_clnt.c +++ b/ssl/s23_clnt.c @@ -509,7 +509,7 @@ static int ssl23_get_server_hello(SSL *s) /* use special padding (SSL 3.0 draft/RFC 2246, App. E.2) */ s->s2->ssl2_rollback=1; - /* setup the 5 bytes we have read so we get them from + /* setup the 7 bytes we have read so we get them from * the sslv2 buffer */ s->rstate=SSL_ST_READ_HEADER; s->packet_length=n; @@ -525,27 +525,13 @@ static int ssl23_get_server_hello(SSL *s) s->handshake_func=s->method->ssl_connect; #endif } - else if ((p[0] == SSL3_RT_HANDSHAKE) && - (p[1] == SSL3_VERSION_MAJOR) && - ((p[2] == SSL3_VERSION_MINOR) || - (p[2] == TLS1_VERSION_MINOR)) && - (p[5] == SSL3_MT_SERVER_HELLO)) + else if (p[1] == SSL3_VERSION_MAJOR && + ((p[2] == SSL3_VERSION_MINOR) || + (p[2] == TLS1_VERSION_MINOR)) && + ((p[0] == SSL3_RT_HANDSHAKE && p[5] == SSL3_MT_SERVER_HELLO) || + (p[0] == SSL3_RT_ALERT && p[3] == 0 && p[4] == 2))) { - /* we have sslv3 or tls1 */ - - if (!ssl_init_wbio_buffer(s,1)) goto err; - - /* we are in this state */ - s->state=SSL3_ST_CR_SRVR_HELLO_A; - - /* put the 5 bytes we have read into the input buffer - * for SSLv3 */ - s->rstate=SSL_ST_READ_HEADER; - s->packet_length=n; - s->packet= &(s->s3->rbuf.buf[0]); - memcpy(s->packet,buf,n); - s->s3->rbuf.left=n; - s->s3->rbuf.offset=0; + /* we have sslv3 or tls1 (server hello or alert) */ if ((p[2] == SSL3_VERSION_MINOR) && !(s->options & SSL_OP_NO_SSLv3)) @@ -572,35 +558,52 @@ static int ssl23_get_server_hello(SSL *s) SSLerr(SSL_F_SSL23_GET_SERVER_HELLO,SSL_R_UNSUPPORTED_PROTOCOL); goto err; } - - s->handshake_func=s->method->ssl_connect; - } - else if ((p[0] == SSL3_RT_ALERT) && - (p[1] == SSL3_VERSION_MAJOR) && - ((p[2] == SSL3_VERSION_MINOR) || - (p[2] == TLS1_VERSION_MINOR)) && - (p[3] == 0) && - (p[4] == 2)) - { - void (*cb)(const SSL *ssl,int type,int val)=NULL; - int j; - - /* An alert */ - if (s->info_callback != NULL) - cb=s->info_callback; - else if (s->ctx->info_callback != NULL) - cb=s->ctx->info_callback; - - i=p[5]; - if (cb != NULL) + + if (p[0] == SSL3_RT_ALERT && p[5] != SSL3_AL_WARNING) { - j=(i<<8)|p[6]; - cb(s,SSL_CB_READ_ALERT,j); + /* fatal alert */ + + void (*cb)(const SSL *ssl,int type,int val)=NULL; + int j; + + if (s->info_callback != NULL) + cb=s->info_callback; + else if (s->ctx->info_callback != NULL) + cb=s->ctx->info_callback; + + i=p[5]; + if (cb != NULL) + { + j=(i<<8)|p[6]; + cb(s,SSL_CB_READ_ALERT,j); + } + + if (s->msg_callback) + s->msg_callback(0, s->version, SSL3_RT_ALERT, p+5, 2, s, s->msg_callback_arg); + + s->rwstate=SSL_NOTHING; + SSLerr(SSL_F_SSL23_GET_SERVER_HELLO,SSL_AD_REASON_OFFSET+p[6]); + goto err; } - s->rwstate=SSL_NOTHING; - SSLerr(SSL_F_SSL23_GET_SERVER_HELLO,SSL_AD_REASON_OFFSET+p[6]); - goto err; + if (!ssl_init_wbio_buffer(s,1)) goto err; + + /* we are in this state */ + s->state=SSL3_ST_CR_SRVR_HELLO_A; + + /* put the 7 bytes we have read into the input buffer + * for SSLv3 */ + s->rstate=SSL_ST_READ_HEADER; + s->packet_length=n; + if (s->s3->rbuf.buf == NULL) + if (!ssl3_setup_buffers(s)) + goto err; + s->packet= &(s->s3->rbuf.buf[0]); + memcpy(s->packet,buf,n); + s->s3->rbuf.left=n; + s->s3->rbuf.offset=0; + + s->handshake_func=s->method->ssl_connect; } else { diff --git a/ssl/s3_enc.c b/ssl/s3_enc.c index 5d8f8ae52a..736bfacc69 100644 --- a/ssl/s3_enc.c +++ b/ssl/s3_enc.c @@ -758,6 +758,12 @@ int ssl3_alert_code(int code) case SSL_AD_INTERNAL_ERROR: return(SSL3_AD_HANDSHAKE_FAILURE); case SSL_AD_USER_CANCELLED: return(SSL3_AD_HANDSHAKE_FAILURE); case SSL_AD_NO_RENEGOTIATION: return(-1); /* Don't send it :-) */ + case SSL_AD_UNSUPPORTED_EXTENSION: return(SSL3_AD_HANDSHAKE_FAILURE); + case SSL_AD_CERTIFICATE_UNOBTAINABLE: return(SSL3_AD_HANDSHAKE_FAILURE); + case SSL_AD_UNRECOGNIZED_NAME: return(SSL3_AD_HANDSHAKE_FAILURE); + case SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE: return(SSL3_AD_HANDSHAKE_FAILURE); + case SSL_AD_BAD_CERTIFICATE_HASH_VALUE: return(SSL3_AD_HANDSHAKE_FAILURE); + case SSL_AD_UNKNOWN_PSK_IDENTITY:return(TLS1_AD_UNKNOWN_PSK_IDENTITY); default: return(-1); } } diff --git a/ssl/ssl.h b/ssl/ssl.h index eebc99ef49..5f2a04e83d 100644 --- a/ssl/ssl.h +++ b/ssl/ssl.h @@ -1207,6 +1207,8 @@ size_t SSL_get_peer_finished(const SSL *s, void *buf, size_t count); #define SSL_AD_CERTIFICATE_UNOBTAINABLE TLS1_AD_CERTIFICATE_UNOBTAINABLE #define SSL_AD_UNRECOGNIZED_NAME TLS1_AD_UNRECOGNIZED_NAME #define SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE +#define SSL_AD_BAD_CERTIFICATE_HASH_VALUE TLS1_AD_BAD_CERTIFICATE_HASH_VALUE +#define SSL_AD_UNKNOWN_PSK_IDENTITY TLS1_AD_UNKNOWN_PSK_IDENTITY /* fatal */ #define SSL_ERROR_NONE 0 #define SSL_ERROR_SSL 1 @@ -2077,6 +2079,11 @@ void ERR_load_SSL_strings(void); #define SSL_R_TLSV1_ALERT_RECORD_OVERFLOW 1022 #define SSL_R_TLSV1_ALERT_UNKNOWN_CA 1048 #define SSL_R_TLSV1_ALERT_USER_CANCELLED 1090 +#define SSL_R_TLSV1_BAD_CERTIFICATE_HASH_VALUE 1114 +#define SSL_R_TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE 1113 +#define SSL_R_TLSV1_CERTIFICATE_UNOBTAINABLE 1111 +#define SSL_R_TLSV1_UNRECOGNIZED_NAME 1112 +#define SSL_R_TLSV1_UNSUPPORTED_EXTENSION 1110 #define SSL_R_TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER 232 #define SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST 227 #define SSL_R_TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST 233 diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c index 60e7e9d16c..9e28dfddf1 100644 --- a/ssl/ssl_err.c +++ b/ssl/ssl_err.c @@ -475,6 +475,11 @@ static ERR_STRING_DATA SSL_str_reasons[]= {ERR_REASON(SSL_R_TLSV1_ALERT_RECORD_OVERFLOW),"tlsv1 alert record overflow"}, {ERR_REASON(SSL_R_TLSV1_ALERT_UNKNOWN_CA),"tlsv1 alert unknown ca"}, {ERR_REASON(SSL_R_TLSV1_ALERT_USER_CANCELLED),"tlsv1 alert user cancelled"}, +{ERR_REASON(SSL_R_TLSV1_BAD_CERTIFICATE_HASH_VALUE),"tlsv1 bad certificate hash value"}, +{ERR_REASON(SSL_R_TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE),"tlsv1 bad certificate status response"}, +{ERR_REASON(SSL_R_TLSV1_CERTIFICATE_UNOBTAINABLE),"tlsv1 certificate unobtainable"}, +{ERR_REASON(SSL_R_TLSV1_UNRECOGNIZED_NAME),"tlsv1 unrecognized name"}, +{ERR_REASON(SSL_R_TLSV1_UNSUPPORTED_EXTENSION),"tlsv1 unsupported extension"}, {ERR_REASON(SSL_R_TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER),"tls client cert req with anon cipher"}, {ERR_REASON(SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST),"tls invalid ecpointformat list"}, {ERR_REASON(SSL_R_TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST),"tls peer did not respond with certificate list"}, diff --git a/ssl/ssl_stat.c b/ssl/ssl_stat.c index e7509f0303..cd52184a99 100644 --- a/ssl/ssl_stat.c +++ b/ssl/ssl_stat.c @@ -414,6 +414,12 @@ const char *SSL_alert_desc_string(int value) case TLS1_AD_INTERNAL_ERROR: str="IE"; break; case TLS1_AD_USER_CANCELLED: str="US"; break; case TLS1_AD_NO_RENEGOTIATION: str="NR"; break; + case TLS1_AD_UNSUPPORTED_EXTENSION: str="UE"; break; + case TLS1_AD_CERTIFICATE_UNOBTAINABLE: str="CO"; break; + case TLS1_AD_UNRECOGNIZED_NAME: str="UN"; break; + case TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE: str="BR"; break; + case TLS1_AD_BAD_CERTIFICATE_HASH_VALUE: str="BH"; break; + case TLS1_AD_UNKNOWN_PSK_IDENTITY: str="UP"; break; default: str="UK"; break; } return(str); @@ -497,6 +503,24 @@ const char *SSL_alert_desc_string_long(int value) case TLS1_AD_NO_RENEGOTIATION: str="no renegotiation"; break; + case TLS1_AD_UNSUPPORTED_EXTENSION: + str="unsupported extension"; + break; + case TLS1_AD_CERTIFICATE_UNOBTAINABLE: + str="certificate unobtainable"; + break; + case TLS1_AD_UNRECOGNIZED_NAME: + str="unrecognized name"; + break; + case TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE: + str="bad certificate status response"; + break; + case TLS1_AD_BAD_CERTIFICATE_HASH_VALUE: + str="bad certificate hash value"; + break; + case TLS1_AD_UNKNOWN_PSK_IDENTITY: + str="unknown PSK identity"; + break; default: str="unknown"; break; } return(str); diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c index 323d3847d4..ad6b637c89 100644 --- a/ssl/t1_enc.c +++ b/ssl/t1_enc.c @@ -853,6 +853,12 @@ int tls1_alert_code(int code) case SSL_AD_INTERNAL_ERROR: return(TLS1_AD_INTERNAL_ERROR); case SSL_AD_USER_CANCELLED: return(TLS1_AD_USER_CANCELLED); case SSL_AD_NO_RENEGOTIATION: return(TLS1_AD_NO_RENEGOTIATION); + case SSL_AD_UNSUPPORTED_EXTENSION: return(TLS1_AD_UNSUPPORTED_EXTENSION); + case SSL_AD_CERTIFICATE_UNOBTAINABLE: return(TLS1_AD_CERTIFICATE_UNOBTAINABLE); + case SSL_AD_UNRECOGNIZED_NAME: return(TLS1_AD_UNRECOGNIZED_NAME); + case SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE: return(TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE); + case SSL_AD_BAD_CERTIFICATE_HASH_VALUE: return(TLS1_AD_BAD_CERTIFICATE_HASH_VALUE); + case SSL_AD_UNKNOWN_PSK_IDENTITY:return(TLS1_AD_UNKNOWN_PSK_IDENTITY); #ifdef DTLS1_AD_MISSING_HANDSHAKE_MESSAGE case DTLS1_AD_MISSING_HANDSHAKE_MESSAGE: return (DTLS1_AD_MISSING_HANDSHAKE_MESSAGE); -- 2.25.1