X-Git-Url: https://git.openssl.org/gitweb/?a=blobdiff_plain;f=ssl%2Fs3_pkt.c;h=e0b13d99b99b195f983874ceefcdd9abd806bb21;hb=1a095560f79c002ca5bcbac531e12f7e770d8d37;hp=a3d656be407d4aaead90771ae16a17c45a0a917f;hpb=87a025cbb44d976b6f9e6ee7ea09d8ade450bf08;p=openssl.git diff --git a/ssl/s3_pkt.c b/ssl/s3_pkt.c index a3d656be40..e0b13d99b9 100644 --- a/ssl/s3_pkt.c +++ b/ssl/s3_pkt.c @@ -170,7 +170,7 @@ static int ssl3_read_n(SSL *s, int n, int max, int extend) } if (n > max) /* does not happen */ { - SSLerr(SSL_F_SSL3_READ_N,SSL_R_INTERNAL_ERROR); + SSLerr(SSL_F_SSL3_READ_N,ERR_R_INTERNAL_ERROR); return -1; } @@ -231,7 +231,7 @@ static int ssl3_read_n(SSL *s, int n, int max, int extend) static int ssl3_get_record(SSL *s) { int ssl_major,ssl_minor,al; - int n,i,ret= -1; + int enc_err,n,i,ret= -1; SSL3_RECORD *rr; SSL_SESSION *sess; unsigned char *p; @@ -342,16 +342,23 @@ again: /* decrypt in place in 'rr->input' */ rr->data=rr->input; - if (!s->method->ssl3_enc->enc(s,0)) + enc_err = s->method->ssl3_enc->enc(s,0); + if (enc_err <= 0) { - al=SSL_AD_DECRYPT_ERROR; - goto f_err; + if (enc_err == 0) + /* SSLerr() and ssl3_send_alert() have been called */ + goto err; + + /* otherwise enc_err == -1 */ + goto decryption_failed_or_bad_record_mac; } + #ifdef TLS_DEBUG printf("dec %d\n",rr->length); { unsigned int z; for (z=0; zlength; z++) printf("%02X%c",rr->data[z],((z+1)%16)?' ':'\n'); } printf("\n"); #endif + /* r->length is now the compressed data plus mac */ if ( (sess == NULL) || (s->enc_read_ctx == NULL) || @@ -364,25 +371,30 @@ printf("\n"); if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH+extra+mac_size) { +#if 0 /* OK only for stream ciphers (then rr->length is visible from ciphertext anyway) */ al=SSL_AD_RECORD_OVERFLOW; SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_PRE_MAC_LENGTH_TOO_LONG); goto f_err; +#else + goto decryption_failed_or_bad_record_mac; +#endif } /* check the MAC for rr->input (it's in mac_size bytes at the tail) */ if (rr->length < mac_size) { +#if 0 /* OK only for stream ciphers */ al=SSL_AD_DECODE_ERROR; SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_LENGTH_TOO_SHORT); goto f_err; +#else + goto decryption_failed_or_bad_record_mac; +#endif } rr->length-=mac_size; i=s->method->ssl3_enc->mac(s,md,0); if (memcmp(md,&(rr->data[rr->length]),mac_size) != 0) { - al=SSL_AD_BAD_RECORD_MAC; - SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_BAD_MAC_DECODE); - ret= -1; - goto f_err; + goto decryption_failed_or_bad_record_mac; } } @@ -427,6 +439,15 @@ printf("\n"); if (rr->length == 0) goto again; return(1); + +decryption_failed_or_bad_record_mac: + /* Separate 'decryption_failed' alert was introduced with TLS 1.0, + * SSL 3.0 only has 'bad_record_mac'. But unless a decryption + * failure is directly visible from the ciphertext anyway, + * we should not reveal which kind of error occured -- this + * might become visible to an attacker (e.g. via logfile) */ + al=SSL_AD_BAD_RECORD_MAC; + SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC); f_err: ssl3_send_alert(s,SSL3_AL_FATAL,al); err: @@ -704,7 +725,7 @@ static int ssl3_write_pending(SSL *s, int type, const unsigned char *buf, * Application data protocol * none of our business */ -int ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len) +int ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek) { int al,i,j,ret; unsigned int n; @@ -715,9 +736,10 @@ int ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len) if (!ssl3_setup_buffers(s)) return(-1); - if ((type != SSL3_RT_APPLICATION_DATA) && (type != SSL3_RT_HANDSHAKE) && type) + if ((type && (type != SSL3_RT_APPLICATION_DATA) && (type != SSL3_RT_HANDSHAKE) && type) || + (peek && (type != SSL3_RT_APPLICATION_DATA))) { - SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_INTERNAL_ERROR); + SSLerr(SSL_F_SSL3_READ_BYTES, ERR_R_INTERNAL_ERROR); return -1; } @@ -726,8 +748,9 @@ int ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len) { unsigned char *src = s->s3->handshake_fragment; unsigned char *dst = buf; - unsigned int j; + unsigned int k; + /* peek == 0 */ n = 0; while ((len > 0) && (s->s3->handshake_fragment_len > 0)) { @@ -736,8 +759,8 @@ int ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len) n++; } /* move any remaining fragment bytes: */ - for (j = 0; j < s->s3->handshake_fragment_len; j++) - s->s3->handshake_fragment[j] = *src++; + for (k = 0; k < s->s3->handshake_fragment_len; k++) + s->s3->handshake_fragment[k] = *src++; return n; } @@ -763,7 +786,7 @@ start: * s->s3->rrec.length, - number of bytes. */ rr = &(s->s3->rrec); - /* get new packet */ + /* get new packet if necessary */ if ((rr->length == 0) || (s->rstate == SSL_ST_READ_BODY)) { ret=ssl3_get_record(s); @@ -781,7 +804,8 @@ start: goto err; } - /* If the other end has shutdown, throw anything we read away */ + /* If the other end has shut down, throw anything we read away + * (even in 'peek' mode) */ if (s->shutdown & SSL_RECEIVED_SHUTDOWN) { rr->length=0; @@ -810,12 +834,15 @@ start: n = (unsigned int)len; memcpy(buf,&(rr->data[rr->off]),n); - rr->length-=n; - rr->off+=n; - if (rr->length == 0) + if (!peek) { - s->rstate=SSL_ST_READ_HEADER; - rr->off=0; + rr->length-=n; + rr->off+=n; + if (rr->length == 0) + { + s->rstate=SSL_ST_READ_HEADER; + rr->off=0; + } } return(n); } @@ -899,19 +926,21 @@ start: return(-1); } - if (s->s3->rbuf.left == 0) /* no read-ahead left? */ + if (!(s->mode & SSL_MODE_AUTO_RETRY)) { - BIO *bio; - /* In the case where we try to read application data - * the first time, but we trigger an SSL handshake, we - * return -1 with the retry option set. I do this - * otherwise renegotiation can cause nasty problems - * in the blocking world */ /* ? */ - s->rwstate=SSL_READING; - bio=SSL_get_rbio(s); - BIO_clear_retry_flags(bio); - BIO_set_retry_read(bio); - return(-1); + if (s->s3->rbuf.left == 0) /* no read-ahead left? */ + { + BIO *bio; + /* In the case where we try to read application data, + * but we trigger an SSL handshake, we return -1 with + * the retry option set. Otherwise renegotiation may + * cause nasty problems in the blocking world */ + s->rwstate=SSL_READING; + bio=SSL_get_rbio(s); + BIO_clear_retry_flags(bio); + BIO_set_retry_read(bio); + return(-1); + } } } } @@ -954,7 +983,7 @@ start: s->rwstate=SSL_NOTHING; s->s3->fatal_alert = alert_descr; SSLerr(SSL_F_SSL3_READ_BYTES, SSL_AD_REASON_OFFSET + alert_descr); - sprintf(tmp,"%d",alert_descr); + BIO_snprintf(tmp,sizeof tmp,"%d",alert_descr); ERR_add_error_data(2,"SSL alert number ",tmp); s->shutdown|=SSL_RECEIVED_SHUTDOWN; SSL_CTX_remove_session(s->ctx,s->session); @@ -1022,19 +1051,21 @@ start: return(-1); } - if (s->s3->rbuf.left == 0) /* no read-ahead left? */ + if (!(s->mode & SSL_MODE_AUTO_RETRY)) { - BIO *bio; - /* In the case where we try to read application data - * the first time, but we trigger an SSL handshake, we - * return -1 with the retry option set. I do this - * otherwise renegotiation can cause nasty problems - * in the blocking world */ /* ? */ - s->rwstate=SSL_READING; - bio=SSL_get_rbio(s); - BIO_clear_retry_flags(bio); - BIO_set_retry_read(bio); - return(-1); + if (s->s3->rbuf.left == 0) /* no read-ahead left? */ + { + BIO *bio; + /* In the case where we try to read application data, + * but we trigger an SSL handshake, we return -1 with + * the retry option set. Otherwise renegotiation may + * cause nasty problems in the blocking world */ + s->rwstate=SSL_READING; + bio=SSL_get_rbio(s); + BIO_clear_retry_flags(bio); + BIO_set_retry_read(bio); + return(-1); + } } goto start; } @@ -1042,7 +1073,7 @@ start: switch (rr->type) { default: -#ifndef NO_TLS +#ifndef OPENSSL_NO_TLS /* TLS just ignores unknown message types */ if (s->version == TLS1_VERSION) { @@ -1059,7 +1090,7 @@ start: * of SSL3_RT_HANDSHAKE when s->in_handshake is set, but that * should not happen when type != rr->type */ al=SSL_AD_UNEXPECTED_MESSAGE; - SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_INTERNAL_ERROR); + SSLerr(SSL_F_SSL3_READ_BYTES,ERR_R_INTERNAL_ERROR); goto f_err; case SSL3_RT_APPLICATION_DATA: /* At this point, we were expecting handshake data, @@ -1154,7 +1185,7 @@ void ssl3_send_alert(SSL *s, int level, int desc) s->s3->alert_dispatch=1; s->s3->send_alert[0]=level; s->s3->send_alert[1]=desc; - if (s->s3->wbuf.left == 0) /* data still being written out */ + if (s->s3->wbuf.left == 0) /* data still being written out? */ ssl3_dispatch_alert(s); /* else data is still being written out, we will get written * some time in the future */ @@ -1173,9 +1204,9 @@ int ssl3_dispatch_alert(SSL *s) } else { - /* If it is important, send it now. If the message - * does not get sent due to non-blocking IO, we will - * not worry too much. */ + /* Alert sent to BIO. If it is important, flush it now. + * If the message does not get sent due to non-blocking IO, + * we will not worry too much. */ if (s->s3->send_alert[0] == SSL3_AL_FATAL) (void)BIO_flush(s->wbio);