/* tls1_enc encrypts/decrypts the record in |s->wrec| / |s->rrec|, respectively. * * Returns: * 0: (in non-constant time) if the record is publically invalid (i.e. too * short etc). * 1: if the record's padding is valid / the encryption was successful. * -1: if the record's padding/AEAD-authenticator is invalid or, if sending, * an internal error occurred. */ int tls1_enc(SSL *s, int send) { SSL3_RECORD *rec; EVP_CIPHER_CTX *ds; unsigned long l; int bs,i,j,k,pad=0,ret,mac_size=0; const EVP_CIPHER *enc; if (send) { if (EVP_MD_CTX_md(s->write_hash)) { int n=EVP_MD_CTX_size(s->write_hash); OPENSSL_assert(n >= 0); } ds=s->enc_write_ctx; rec= &(s->s3->wrec); if (s->enc_write_ctx == NULL) enc=NULL; else { int ivlen; enc=EVP_CIPHER_CTX_cipher(s->enc_write_ctx); /* For TLSv1.1 and later explicit IV */ if (SSL_USE_EXPLICIT_IV(s) && EVP_CIPHER_mode(enc) == EVP_CIPH_CBC_MODE) ivlen = EVP_CIPHER_iv_length(enc); else ivlen = 0; if (ivlen > 1) { if ( rec->data != rec->input) /* we can't write into the input stream: * Can this ever happen?? (steve) */ fprintf(stderr, "%s:%d: rec->data != rec->input\n", __FILE__, __LINE__); else if (RAND_bytes(rec->input, ivlen) <= 0) return -1; } } } else { if (EVP_MD_CTX_md(s->read_hash)) { int n=EVP_MD_CTX_size(s->read_hash); OPENSSL_assert(n >= 0); } ds=s->enc_read_ctx; rec= &(s->s3->rrec); if (s->enc_read_ctx == NULL) enc=NULL; else enc=EVP_CIPHER_CTX_cipher(s->enc_read_ctx); } #ifdef KSSL_DEBUG printf("tls1_enc(%d)\n", send); #endif /* KSSL_DEBUG */ if ((s->session == NULL) || (ds == NULL) || (enc == NULL)) { memmove(rec->data,rec->input,rec->length); rec->input=rec->data; ret = 1; } else { l=rec->length; bs=EVP_CIPHER_block_size(ds->cipher); if (EVP_CIPHER_flags(ds->cipher)&EVP_CIPH_FLAG_AEAD_CIPHER) { unsigned char buf[13],*seq; seq = send?s->s3->write_sequence:s->s3->read_sequence; if (SSL_IS_DTLS(s)) { unsigned char dtlsseq[9],*p=dtlsseq; s2n(send?s->d1->w_epoch:s->d1->r_epoch,p); memcpy(p,&seq[2],6); memcpy(buf,dtlsseq,8); } else { memcpy(buf,seq,8); for (i=7; i>=0; i--) /* increment */ { ++seq[i]; if (seq[i] != 0) break; } } buf[8]=rec->type; buf[9]=(unsigned char)(s->version>>8); buf[10]=(unsigned char)(s->version); buf[11]=rec->length>>8; buf[12]=rec->length&0xff; pad=EVP_CIPHER_CTX_ctrl(ds,EVP_CTRL_AEAD_TLS1_AAD,13,buf); if (send) { l+=pad; rec->length+=pad; } } else if ((bs != 1) && send)
int tls1_change_cipher_state(SSL *s, int which) { /* is_read is true if we have just read a ChangeCipherSpec message - i.e. we * need to update the read cipherspec. Otherwise we have just written one. */ const char is_read = (which & SSL3_CC_READ) != 0; /* use_client_keys is true if we wish to use the keys for the "client write" * direction. This is the case if we're a client sending a ChangeCipherSpec, * or a server reading a client's ChangeCipherSpec. */ const char use_client_keys = which == SSL3_CHANGE_CIPHER_CLIENT_WRITE || which == SSL3_CHANGE_CIPHER_SERVER_READ; const uint8_t *client_write_mac_secret, *server_write_mac_secret, *mac_secret; const uint8_t *client_write_key, *server_write_key, *key; const uint8_t *client_write_iv, *server_write_iv, *iv; const EVP_AEAD *aead = s->s3->tmp.new_aead; size_t key_len, iv_len, mac_secret_len; const uint8_t *key_data; /* Reset sequence number to zero. */ if (!SSL_IS_DTLS(s)) { memset(is_read ? s->s3->read_sequence : s->s3->write_sequence, 0, 8); } mac_secret_len = s->s3->tmp.new_mac_secret_len; iv_len = s->s3->tmp.new_fixed_iv_len; if (aead == NULL) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); return 0; } key_len = EVP_AEAD_key_length(aead); if (mac_secret_len > 0) { /* For "stateful" AEADs (i.e. compatibility with pre-AEAD cipher * suites) the key length reported by |EVP_AEAD_key_length| will * include the MAC and IV key bytes. */ if (key_len < mac_secret_len + iv_len) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); return 0; } key_len -= mac_secret_len + iv_len; } key_data = s->s3->tmp.key_block; client_write_mac_secret = key_data; key_data += mac_secret_len; server_write_mac_secret = key_data; key_data += mac_secret_len; client_write_key = key_data; key_data += key_len; server_write_key = key_data; key_data += key_len; client_write_iv = key_data; key_data += iv_len; server_write_iv = key_data; key_data += iv_len; if (use_client_keys) { mac_secret = client_write_mac_secret; key = client_write_key; iv = client_write_iv; } else { mac_secret = server_write_mac_secret; key = server_write_key; iv = server_write_iv; } if (key_data - s->s3->tmp.key_block != s->s3->tmp.key_block_length) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); return 0; } if (is_read) { SSL_AEAD_CTX_free(s->aead_read_ctx); s->aead_read_ctx = SSL_AEAD_CTX_new( evp_aead_open, ssl3_version_from_wire(s, s->version), s->s3->tmp.new_cipher, key, key_len, mac_secret, mac_secret_len, iv, iv_len); return s->aead_read_ctx != NULL; } SSL_AEAD_CTX_free(s->aead_write_ctx); s->aead_write_ctx = SSL_AEAD_CTX_new( evp_aead_seal, ssl3_version_from_wire(s, s->version), s->s3->tmp.new_cipher, key, key_len, mac_secret, mac_secret_len, iv, iv_len); if (s->aead_write_ctx == NULL) { return 0; } s->s3->need_record_splitting = 0; if (!SSL_USE_EXPLICIT_IV(s) && (s->mode & SSL_MODE_CBC_RECORD_SPLITTING) != 0 && SSL_CIPHER_is_block_cipher(s->s3->tmp.new_cipher)) { /* Enable 1/n-1 record-splitting to randomize the IV. See * https://www.openssl.org/~bodo/tls-cbc.txt and the BEAST attack. */ s->s3->need_record_splitting = 1; } return 1; }
int tls1_setup_key_block(SSL *s) { uint8_t *p; const EVP_AEAD *aead = NULL; int ret = 0; size_t mac_secret_len, fixed_iv_len, variable_iv_len, key_len; size_t key_block_len; if (s->s3->tmp.key_block_length != 0) { return 1; } if (s->session->cipher == NULL) { goto cipher_unavailable_err; } if (!ssl_cipher_get_evp_aead(&aead, &mac_secret_len, &fixed_iv_len, s->session->cipher, ssl3_version_from_wire(s, s->version))) { goto cipher_unavailable_err; } key_len = EVP_AEAD_key_length(aead); variable_iv_len = EVP_AEAD_nonce_length(aead); if (mac_secret_len > 0) { /* For "stateful" AEADs (i.e. compatibility with pre-AEAD cipher suites) the * key length reported by |EVP_AEAD_key_length| will include the MAC key * bytes and initial implicit IV. */ if (key_len < mac_secret_len + fixed_iv_len) { OPENSSL_PUT_ERROR(SSL, tls1_setup_key_block, ERR_R_INTERNAL_ERROR); return 0; } key_len -= mac_secret_len + fixed_iv_len; } else { /* The nonce is split into a fixed portion and a variable portion. */ if (variable_iv_len < fixed_iv_len) { OPENSSL_PUT_ERROR(SSL, tls1_setup_key_block, ERR_R_INTERNAL_ERROR); return 0; } variable_iv_len -= fixed_iv_len; } assert(mac_secret_len < 256); assert(fixed_iv_len < 256); assert(variable_iv_len < 256); s->s3->tmp.new_aead = aead; s->s3->tmp.new_mac_secret_len = (uint8_t)mac_secret_len; s->s3->tmp.new_fixed_iv_len = (uint8_t)fixed_iv_len; s->s3->tmp.new_variable_iv_len = (uint8_t)variable_iv_len; key_block_len = key_len + mac_secret_len + fixed_iv_len; key_block_len *= 2; ssl3_cleanup_key_block(s); p = (uint8_t *)OPENSSL_malloc(key_block_len); if (p == NULL) { OPENSSL_PUT_ERROR(SSL, tls1_setup_key_block, ERR_R_MALLOC_FAILURE); goto err; } s->s3->tmp.key_block_length = key_block_len; s->s3->tmp.key_block = p; if (!tls1_generate_key_block(s, p, key_block_len)) { goto err; } if (!SSL_USE_EXPLICIT_IV(s) && (s->mode & SSL_MODE_CBC_RECORD_SPLITTING) != 0) { /* enable vulnerability countermeasure for CBC ciphers with known-IV * problem (http://www.openssl.org/~bodo/tls-cbc.txt). */ s->s3->need_record_splitting = 1; if (s->session->cipher != NULL && s->session->cipher->algorithm_enc == SSL_RC4) { s->s3->need_record_splitting = 0; } } ret = 1; err: return ret; cipher_unavailable_err: OPENSSL_PUT_ERROR(SSL, tls1_setup_key_block, SSL_R_CIPHER_OR_HASH_UNAVAILABLE); return 0; }