X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=ssl%2Fs3_pkt.c;h=b76aabee80e03f53a557644dff2f6c3fdc216c5c;hp=e95dcd9461ea0b2ce64d7b0195f7cfa1527966b2;hb=bf21446a2a2bed0423ac17cbc007b5da2ce8bf2f;hpb=e7ecc7d4ddcfc5d2a09dde220e3fc0b5e4b46289 diff --git a/ssl/s3_pkt.c b/ssl/s3_pkt.c index e95dcd9461..b76aabee80 100644 --- a/ssl/s3_pkt.c +++ b/ssl/s3_pkt.c @@ -56,7 +56,7 @@ * [including the GNU Public Licence.] */ /* ==================================================================== - * Copyright (c) 1998-1999 The OpenSSL Project. All rights reserved. + * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -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,20 +725,21 @@ 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,n,ret; + int al,i,j,ret; + unsigned int n; SSL3_RECORD *rr; void (*cb)()=NULL; - BIO *bio; if (s->s3->rbuf.buf == NULL) /* Not initialized yet */ 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,7 +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 k; + /* peek == 0 */ n = 0; while ((len > 0) && (s->s3->handshake_fragment_len > 0)) { @@ -735,8 +759,8 @@ int ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len) n++; } /* move any remaining fragment bytes: */ - for (i = 0; i < s->s3->handshake_fragment_len; i++) - s->s3->handshake_fragment[i] = *src++; + for (k = 0; k < s->s3->handshake_fragment_len; k++) + s->s3->handshake_fragment[k] = *src++; return n; } @@ -762,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); @@ -780,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; @@ -804,17 +829,20 @@ start: if (len <= 0) return(len); if ((unsigned int)len > rr->length) - n=rr->length; + n = rr->length; else - n=len; + n = (unsigned int)len; - memcpy(buf,&(rr->data[rr->off]),(unsigned int)n); - rr->length-=n; - rr->off+=n; - if (rr->length == 0) + memcpy(buf,&(rr->data[rr->off]),n); + 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); } @@ -827,9 +855,9 @@ start: * fill that so that we can process the data at a fixed place. */ { - int dest_maxlen = 0; - unsigned char *dest; - int *dest_len; + unsigned int dest_maxlen = 0; + unsigned char *dest = NULL; + unsigned int *dest_len = NULL; if (rr->type == SSL3_RT_HANDSHAKE) { @@ -890,13 +918,30 @@ start: ssl3_renegotiate(s); if (ssl3_renegotiate_check(s)) { - n=s->handshake_func(s); - if (n < 0) return(n); - if (n == 0) + i=s->handshake_func(s); + if (i < 0) return(i); + if (i == 0) { SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_SSL_HANDSHAKE_FAILURE); return(-1); } + + if (!(s->mode & SSL_MODE_AUTO_RETRY)) + { + 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); + } + } } } /* we either finished a handshake or ignored the request, @@ -906,8 +951,8 @@ start: if (s->s3->alert_fragment_len >= 2) { - i = s->s3->alert_fragment[0]; - n = s->s3->alert_fragment[1]; + int alert_level = s->s3->alert_fragment[0]; + int alert_descr = s->s3->alert_fragment[1]; s->s3->alert_fragment_len = 0; @@ -918,28 +963,27 @@ start: if (cb != NULL) { - j=(i<<8)|n; - cb(s,SSL_CB_READ_ALERT,j); + j = (alert_level << 8) | alert_descr; + cb(s, SSL_CB_READ_ALERT, j); } - if (i == 1) /* warning */ + if (alert_level == 1) /* warning */ { - s->s3->warn_alert=n; - if (n == SSL_AD_CLOSE_NOTIFY) + s->s3->warn_alert = alert_descr; + if (alert_descr == SSL_AD_CLOSE_NOTIFY) { - s->shutdown|=SSL_RECEIVED_SHUTDOWN; + s->shutdown |= SSL_RECEIVED_SHUTDOWN; return(0); } } - else if (i == 2) /* fatal */ + else if (alert_level == 2) /* fatal */ { char tmp[16]; s->rwstate=SSL_NOTHING; - s->s3->fatal_alert=n; - SSLerr(SSL_F_SSL3_READ_BYTES, - SSL_AD_REASON_OFFSET+n); - sprintf(tmp,"%d",n); + s->s3->fatal_alert = alert_descr; + SSLerr(SSL_F_SSL3_READ_BYTES, SSL_AD_REASON_OFFSET + 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); @@ -988,36 +1032,48 @@ start: if (((s->state&SSL_ST_MASK) == SSL_ST_OK) && !(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS)) { +#if 0 /* worked only because C operator preferences are not as expected (and + * because this is not really needed for clients except for detecting + * protocol violations): */ s->state=SSL_ST_BEFORE|(s->server) ?SSL_ST_ACCEPT :SSL_ST_CONNECT; +#else + s->state = s->server ? SSL_ST_ACCEPT : SSL_ST_CONNECT; +#endif s->new_session=1; } - n=s->handshake_func(s); - if (n < 0) return(n); - if (n == 0) + i=s->handshake_func(s); + if (i < 0) return(i); + if (i == 0) { SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_SSL_HANDSHAKE_FAILURE); return(-1); } - /* 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 non-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->mode & SSL_MODE_AUTO_RETRY)) + { + 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; } switch (rr->type) { default: -#ifndef NO_TLS +#ifndef OPENSSL_NO_TLS /* TLS just ignores unknown message types */ if (s->version == TLS1_VERSION) { @@ -1034,14 +1090,14 @@ 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, * but have application data. If the library was * running inside ssl3_read() (i.e. in_read_app_data * is set) and it makes sense to read application data - * at this point (session renegotation not yet started), + * at this point (session renegotiation not yet started), * we will indulge it. */ if (s->s3->in_read_app_data && @@ -1129,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 */ @@ -1148,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);