#include <openssl/buffer.h>
#include <openssl/rand.h>
+#ifndef EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK
+# define EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK 0
+#endif
+
static int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
unsigned int len, int create_empty_fragment);
static int ssl3_get_record(SSL *s);
if (version != s->version)
{
SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_WRONG_VERSION_NUMBER);
- if ((s->version & 0xFF00) == (version & 0xFF00))
+ if ((s->version & 0xFF00) == (version & 0xFF00) && !s->enc_write_ctx && !s->write_hash)
/* Send back error using their minor version number :-) */
s->version = (unsigned short)version;
al=SSL_AD_PROTOCOL_VERSION;
/* decrypt in place in 'rr->input' */
rr->data=rr->input;
rr->orig_len=rr->length;
+ /* If in encrypt-then-mac mode calculate mac from encrypted record.
+ * All the details below are public so no timing details can leak.
+ */
+ if (SSL_USE_ETM(s) && s->read_hash)
+ {
+ unsigned char *mac;
+ mac_size=EVP_MD_CTX_size(s->read_hash);
+ OPENSSL_assert(mac_size <= EVP_MAX_MD_SIZE);
+ if (rr->length < mac_size)
+ {
+ al=SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_LENGTH_TOO_SHORT);
+ goto f_err;
+ }
+ rr->length -= mac_size;
+ mac = rr->data + rr->length;
+ i=s->method->ssl3_enc->mac(s,md,0 /* not send */);
+ if (i < 0 || CRYPTO_memcmp(md, mac, (size_t)mac_size) != 0)
+ {
+ al=SSL_AD_BAD_RECORD_MAC;
+ SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC);
+ goto f_err;
+ }
+ }
enc_err = s->method->ssl3_enc->enc(s,0);
/* enc_err is:
/* r->length is now the compressed data plus mac */
if ((sess != NULL) &&
(s->enc_read_ctx != NULL) &&
- (EVP_MD_CTX_md(s->read_hash) != NULL))
+ (EVP_MD_CTX_md(s->read_hash) != NULL) && !SSL_USE_ETM(s))
{
/* s->read_hash != NULL => mac_size != -1 */
unsigned char *mac = NULL;
/* A 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
+ * we should not reveal which kind of error occurred -- this
* might become visible to an attacker (e.g. via a logfile) */
al=SSL_AD_BAD_RECORD_MAC;
SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC);
goto err;
}
+#if !defined(OPENSSL_NO_MULTIBLOCK) && EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK
+ if (type==SSL3_RT_APPLICATION_DATA && s->compress==NULL &&
+ !SSL_USE_ETM(s) && SSL_USE_EXPLICIT_IV(s) && /*!SSL_IS_DTLS(s) &&*/
+ EVP_CIPHER_flags(s->enc_write_ctx->cipher)&EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK)
+ do {
+ unsigned char aad[13];
+ EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM mb_param = {NULL,aad,sizeof(aad),0};
+ int packlen;
+
+ memcpy(aad,s->s3->write_sequence,8);
+ aad[8]=type;
+ aad[9]=(unsigned char)(s->version>>8);
+ aad[10]=(unsigned char)(s->version);
+ aad[11]=(unsigned char)(len>>8);
+ aad[12]=(unsigned char)len;
+ packlen = EVP_CIPHER_CTX_ctrl(s->enc_write_ctx,
+ EVP_CTRL_TLS1_1_MULTIBLOCK_AAD,
+ sizeof(mb_param),&mb_param);
+
+ if (packlen==0 || packlen > wb->len) break;
+
+ mb_param.out = wb->buf;
+ mb_param.inp = buf;
+ mb_param.len = len;
+ EVP_CIPHER_CTX_ctrl(s->enc_write_ctx,
+ EVP_CTRL_TLS1_1_MULTIBLOCK_ENCRYPT,
+ sizeof(mb_param),&mb_param);
+
+ s->s3->write_sequence[7] += mb_param.interleave;
+ if (s->s3->write_sequence[7] < mb_param.interleave)
+ {
+ int j=6;
+ while (j>=0 && (++s->s3->write_sequence[j--])==0) ;
+ }
+
+ wb->offset=0;
+ wb->left = packlen;
+
+ /* memorize arguments so that ssl3_write_pending can detect bad write retries later */
+ s->s3->wpend_tot=len;
+ s->s3->wpend_buf=buf;
+ s->s3->wpend_type=type;
+ s->s3->wpend_ret=len;
+
+ /* we now just need to write the buffer */
+ return ssl3_write_pending(s,type,buf,len);
+ } while (0);
+#endif
+
/* 'create_empty_fragment' is true only when this function calls itself */
if (!clear && !create_empty_fragment && !s->s3->empty_fragment_done)
{
* from wr->input. Length should be wr->length.
* wr->data still points in the wb->buf */
- if (mac_size != 0)
+ if (!SSL_USE_ETM(s) && mac_size != 0)
{
if (s->method->ssl3_enc->mac(s,&(p[wr->length + eivlen]),1) < 0)
goto err;
/* ssl3_enc can only have an error on read */
s->method->ssl3_enc->enc(s,1);
+ if (SSL_USE_ETM(s) && mac_size != 0)
+ {
+ if (s->method->ssl3_enc->mac(s,p + wr->length,1) < 0)
+ goto err;
+ wr->length+=mac_size;
+ }
+
/* record length after mac and block padding */
s2n(wr->length,plen);
slen=s->method->ssl3_enc->client_finished_label_len;
}
- s->s3->tmp.peer_finish_md_len = s->method->ssl3_enc->final_finish_mac(s,
+ i = s->method->ssl3_enc->final_finish_mac(s,
sender,slen,s->s3->tmp.peer_finish_md);
+ if (i == 0)
+ {
+ SSLerr(SSL_F_SSL3_DO_CHANGE_CIPHER_SPEC, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+ s->s3->tmp.peer_finish_md_len = i;
return(1);
}