diff --git a/ssl/record/methods/tlsrecord.c b/ssl/record/methods/tlsrecord.c index 1646ba5ba1811..5a50ef25f0ee0 100644 --- a/ssl/record/methods/tlsrecord.c +++ b/ssl/record/methods/tlsrecord.c @@ -104,6 +104,11 @@ struct ossl_record_layer_st /* Only used by SSLv3 */ unsigned char mac_secret[EVP_MAX_MD_SIZE]; + /* TLSv1.3 static IV */ + unsigned char iv[EVP_MAX_IV_LENGTH]; + + size_t taglen; + /* Function pointers for version specific functions */ /* Function pointers for version specific functions */ struct record_functions_st *funcs; @@ -169,23 +174,6 @@ static int tls_provider_set_tls_parameters(OSSL_RECORD_LAYER *rl, return 1; } -static int tls_fail_set_crypto_state(OSSL_RECORD_LAYER *rl, int level, - unsigned char *key, size_t keylen, - unsigned char *iv, size_t ivlen, - unsigned char *mackey, size_t mackeylen, - const EVP_CIPHER *ciph, - size_t taglen, - /* TODO(RECLAYER): This probably should not be an int */ - int mactype, - const EVP_MD *md, - const SSL_COMP *comp, - /* TODO(RECLAYER): Remove me */ - SSL_CONNECTION *s) -{ - RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); - return 0; -} - static int tls_any_set_crypto_state(OSSL_RECORD_LAYER *rl, int level, unsigned char *key, size_t keylen, unsigned char *iv, size_t ivlen, @@ -410,6 +398,51 @@ static int tls1_set_crypto_state(OSSL_RECORD_LAYER *rl, int level, return 1; } +static int tls13_set_crypto_state(OSSL_RECORD_LAYER *rl, int level, + unsigned char *key, size_t keylen, + unsigned char *iv, size_t ivlen, + unsigned char *mackey, size_t mackeylen, + const EVP_CIPHER *ciph, + size_t taglen, + /* TODO(RECLAYER): This probably should not be an int */ + int mactype, + const EVP_MD *md, + const SSL_COMP *comp, + /* TODO(RECLAYER): Remove me */ + SSL_CONNECTION *s) +{ + EVP_CIPHER_CTX *ciph_ctx; + int mode; + + if (ivlen > sizeof(rl->iv)) { + RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return 0; + } + memcpy(rl->iv, iv, ivlen); + + ciph_ctx = rl->enc_read_ctx = EVP_CIPHER_CTX_new(); + if (ciph_ctx == NULL) { + RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_MALLOC_FAILURE); + return 0; + } + + RECORD_LAYER_reset_read_sequence(&s->rlayer); + rl->taglen = taglen; + + mode = EVP_CIPHER_get_mode(ciph); + + if (EVP_DecryptInit_ex(ciph_ctx, ciph, NULL, NULL, NULL) <= 0 + || !EVP_CIPHER_CTX_ctrl(ciph_ctx, EVP_CTRL_AEAD_SET_IVLEN, ivlen, NULL) + || (mode == EVP_CIPH_CCM_MODE + && !EVP_CIPHER_CTX_ctrl(ciph_ctx, EVP_CTRL_AEAD_SET_TAG, taglen, NULL)) + || EVP_DecryptInit_ex(ciph_ctx, NULL, NULL, key, NULL) <= 0) { + RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_EVP_LIB); + return 0; + } + + return 1; +} + static int tls_any_cipher(OSSL_RECORD_LAYER *rl, SSL3_RECORD *recs, size_t n_recs, int sending, SSL_MAC_BUF *macs, size_t macsize, /* TODO(RECLAYER): Remove me */ SSL_CONNECTION *s) @@ -875,6 +908,139 @@ static int tls1_cipher(OSSL_RECORD_LAYER *rl, SSL3_RECORD *recs, size_t n_recs, return 1; } +static int tls13_cipher(OSSL_RECORD_LAYER *rl, SSL3_RECORD *recs, size_t n_recs, + int sending, SSL_MAC_BUF *mac, size_t macsize, + /* TODO(RECLAYER): Remove me */ SSL_CONNECTION *s) +{ + EVP_CIPHER_CTX *ctx; + unsigned char iv[EVP_MAX_IV_LENGTH], recheader[SSL3_RT_HEADER_LENGTH]; + size_t ivlen, offset, loop, hdrlen; + unsigned char *staticiv; + unsigned char *seq; + int lenu, lenf; + SSL3_RECORD *rec = &recs[0]; + WPACKET wpkt; + const EVP_CIPHER *cipher; + int mode; + + if (n_recs != 1) { + /* Should not happen */ + RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return 0; + } + + if (sending) { + ctx = s->enc_write_ctx; + staticiv = s->write_iv; + seq = RECORD_LAYER_get_write_sequence(&s->rlayer); + } else { + ctx = rl->enc_read_ctx; + staticiv = rl->iv; + seq = RECORD_LAYER_get_read_sequence(&s->rlayer); + } + + cipher = EVP_CIPHER_CTX_get0_cipher(ctx); + if (cipher == NULL) { + RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return 0; + } + mode = EVP_CIPHER_get_mode(cipher); + + /* + * If we're sending an alert and ctx != NULL then we must be forcing + * plaintext alerts. If we're reading and ctx != NULL then we allow + * plaintext alerts at certain points in the handshake. If we've got this + * far then we have already validated that a plaintext alert is ok here. + */ + if (ctx == NULL || rec->type == SSL3_RT_ALERT) { + memmove(rec->data, rec->input, rec->length); + rec->input = rec->data; + return 1; + } + + ivlen = EVP_CIPHER_CTX_get_iv_length(ctx); + + if (!sending) { + /* + * Take off tag. There must be at least one byte of content type as + * well as the tag + */ + if (rec->length < rl->taglen + 1) + return 0; + rec->length -= rl->taglen; + } + + /* Set up IV */ + if (ivlen < SEQ_NUM_SIZE) { + /* Should not happen */ + RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return 0; + } + offset = ivlen - SEQ_NUM_SIZE; + memcpy(iv, staticiv, offset); + for (loop = 0; loop < SEQ_NUM_SIZE; loop++) + iv[offset + loop] = staticiv[offset + loop] ^ seq[loop]; + + /* Increment the sequence counter */ + for (loop = SEQ_NUM_SIZE; loop > 0; loop--) { + ++seq[loop - 1]; + if (seq[loop - 1] != 0) + break; + } + if (loop == 0) { + /* Sequence has wrapped */ + return 0; + } + + if (EVP_CipherInit_ex(ctx, NULL, NULL, NULL, iv, sending) <= 0 + || (!sending && EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, + rl->taglen, + rec->data + rec->length) <= 0)) { + RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return 0; + } + + /* Set up the AAD */ + if (!WPACKET_init_static_len(&wpkt, recheader, sizeof(recheader), 0) + || !WPACKET_put_bytes_u8(&wpkt, rec->type) + || !WPACKET_put_bytes_u16(&wpkt, rec->rec_version) + || !WPACKET_put_bytes_u16(&wpkt, rec->length + rl->taglen) + || !WPACKET_get_total_written(&wpkt, &hdrlen) + || hdrlen != SSL3_RT_HEADER_LENGTH + || !WPACKET_finish(&wpkt)) { + RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + WPACKET_cleanup(&wpkt); + return 0; + } + + /* + * For CCM we must explicitly set the total plaintext length before we add + * any AAD. + */ + if ((mode == EVP_CIPH_CCM_MODE + && EVP_CipherUpdate(ctx, NULL, &lenu, NULL, + (unsigned int)rec->length) <= 0) + || EVP_CipherUpdate(ctx, NULL, &lenu, recheader, + sizeof(recheader)) <= 0 + || EVP_CipherUpdate(ctx, rec->data, &lenu, rec->input, + (unsigned int)rec->length) <= 0 + || EVP_CipherFinal_ex(ctx, rec->data + lenu, &lenf) <= 0 + || (size_t)(lenu + lenf) != rec->length) { + return 0; + } + if (sending) { + /* Add the tag */ + if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, rl->taglen, + rec->data + rec->length) <= 0) { + RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return 0; + } + rec->length += rl->taglen; + } + + return 1; +} + static const unsigned char ssl3_pad_1[48] = { 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, @@ -1102,7 +1268,6 @@ static int tls1_mac(OSSL_RECORD_LAYER *rl, SSL3_RECORD *rec, unsigned char *md, return ret; } - struct record_functions_st tls_any_funcs = { tls_any_set_crypto_state, tls_any_cipher, @@ -1110,8 +1275,8 @@ struct record_functions_st tls_any_funcs = { }; struct record_functions_st tls_1_3_funcs = { - tls_fail_set_crypto_state, - NULL, + tls13_set_crypto_state, + tls13_cipher, NULL }; @@ -1648,7 +1813,7 @@ static int tls_get_more_records(OSSL_RECORD_LAYER *rl, } if (SSL_CONNECTION_IS_TLS13(s) - && s->enc_read_ctx != NULL + && rl->enc_read_ctx != NULL && !using_ktls) { if (thisrr->type != SSL3_RT_APPLICATION_DATA && (thisrr->type != SSL3_RT_CHANGE_CIPHER_SPEC @@ -1866,10 +2031,7 @@ static int tls_get_more_records(OSSL_RECORD_LAYER *rl, * TODO(RECLAYER): Only call rl functions once TLSv1.3/SSLv3 is moved to new * record layer code */ - if (!SSL_CONNECTION_IS_TLS13(s)) - enc_err = rl->funcs->cipher(rl, rr, num_recs, 0, macbufs, mac_size, s); - else - enc_err = ssl->method->ssl3_enc->enc(s, rr, num_recs, 0, macbufs, mac_size); + enc_err = rl->funcs->cipher(rl, rr, num_recs, 0, macbufs, mac_size, s); /*- * enc_err is: @@ -1970,7 +2132,7 @@ static int tls_get_more_records(OSSL_RECORD_LAYER *rl, } if (SSL_CONNECTION_IS_TLS13(s) - && s->enc_read_ctx != NULL + && rl->enc_read_ctx != NULL && thisrr->type != SSL3_RT_ALERT) { /* * The following logic are irrelevant in KTLS: the kernel provides @@ -2288,6 +2450,7 @@ static OSSL_RECORD_LAYER *dtls_new_record_layer(OSSL_LIB_CTX *libctx, static void tls_free(OSSL_RECORD_LAYER *rl) { + /* TODO(RECLAYER): Cleanse sensitive fields */ BIO_free(rl->bio); OPENSSL_free(rl); } diff --git a/ssl/tls13_enc.c b/ssl/tls13_enc.c index 1bfafcb3c93cf..9001a4455a306 100644 --- a/ssl/tls13_enc.c +++ b/ssl/tls13_enc.c @@ -344,12 +344,14 @@ static int derive_secret_key_and_iv(SSL_CONNECTION *s, int sending, const unsigned char *hash, const unsigned char *label, size_t labellen, unsigned char *secret, - unsigned char *key, unsigned char *iv, + unsigned char *key, size_t *keylen, + unsigned char *iv, size_t *ivlen, + size_t *taglen, EVP_CIPHER_CTX *ciph_ctx) { - size_t ivlen, keylen, taglen; int hashleni = EVP_MD_get_size(md); size_t hashlen; + int mode; /* Ensure cast to size_t is safe */ if (!ossl_assert(hashleni >= 0)) { @@ -364,11 +366,13 @@ static int derive_secret_key_and_iv(SSL_CONNECTION *s, int sending, return 0; } - keylen = EVP_CIPHER_get_key_length(ciph); - if (EVP_CIPHER_get_mode(ciph) == EVP_CIPH_CCM_MODE) { + *keylen = EVP_CIPHER_get_key_length(ciph); + + mode = EVP_CIPHER_get_mode(ciph); + if (mode == EVP_CIPH_CCM_MODE) { uint32_t algenc; - ivlen = EVP_CCM_TLS_IV_LEN; + *ivlen = EVP_CCM_TLS_IV_LEN; if (s->s3.tmp.new_cipher != NULL) { algenc = s->s3.tmp.new_cipher->algorithm_enc; } else if (s->session->cipher != NULL) { @@ -382,27 +386,34 @@ static int derive_secret_key_and_iv(SSL_CONNECTION *s, int sending, return 0; } if (algenc & (SSL_AES128CCM8 | SSL_AES256CCM8)) - taglen = EVP_CCM8_TLS_TAG_LEN; + *taglen = EVP_CCM8_TLS_TAG_LEN; else - taglen = EVP_CCM_TLS_TAG_LEN; + *taglen = EVP_CCM_TLS_TAG_LEN; } else { - ivlen = EVP_CIPHER_get_iv_length(ciph); - taglen = 0; + if (mode == EVP_CIPH_GCM_MODE) { + *taglen = EVP_GCM_TLS_TAG_LEN; + } else { + /* CHACHA20P-POLY1305 */ + *taglen = EVP_CHACHAPOLY_TLS_TAG_LEN; + } + *ivlen = EVP_CIPHER_get_iv_length(ciph); } - if (!tls13_derive_key(s, md, secret, key, keylen) - || !tls13_derive_iv(s, md, secret, iv, ivlen)) { + if (!tls13_derive_key(s, md, secret, key, *keylen) + || !tls13_derive_iv(s, md, secret, iv, *ivlen)) { /* SSLfatal() already called */ return 0; } - if (EVP_CipherInit_ex(ciph_ctx, ciph, NULL, NULL, NULL, sending) <= 0 - || EVP_CIPHER_CTX_ctrl(ciph_ctx, EVP_CTRL_AEAD_SET_IVLEN, ivlen, NULL) <= 0 - || (taglen != 0 && EVP_CIPHER_CTX_ctrl(ciph_ctx, EVP_CTRL_AEAD_SET_TAG, - taglen, NULL) <= 0) - || EVP_CipherInit_ex(ciph_ctx, NULL, NULL, key, NULL, -1) <= 0) { - SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_EVP_LIB); - return 0; + if (sending) { + if (EVP_CipherInit_ex(ciph_ctx, ciph, NULL, NULL, NULL, sending) <= 0 + || EVP_CIPHER_CTX_ctrl(ciph_ctx, EVP_CTRL_AEAD_SET_IVLEN, *ivlen, NULL) <= 0 + || (mode == EVP_CIPH_CCM_MODE + && EVP_CIPHER_CTX_ctrl(ciph_ctx, EVP_CTRL_AEAD_SET_TAG, *taglen, NULL) <= 0) + || EVP_CipherInit_ex(ciph_ctx, NULL, NULL, key, NULL, -1) <= 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_EVP_LIB); + return 0; + } } return 1; @@ -411,14 +422,14 @@ static int derive_secret_key_and_iv(SSL_CONNECTION *s, int sending, int tls13_change_cipher_state(SSL_CONNECTION *s, int which) { #ifdef CHARSET_EBCDIC - static const unsigned char client_early_traffic[] = {0x63, 0x20, 0x65, 0x20, /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00}; - static const unsigned char client_handshake_traffic[] = {0x63, 0x20, 0x68, 0x73, 0x20, /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00}; - static const unsigned char client_application_traffic[] = {0x63, 0x20, 0x61, 0x70, 0x20, /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00}; - static const unsigned char server_handshake_traffic[] = {0x73, 0x20, 0x68, 0x73, 0x20, /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00}; - static const unsigned char server_application_traffic[] = {0x73, 0x20, 0x61, 0x70, 0x20, /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00}; - static const unsigned char exporter_master_secret[] = {0x65, 0x78, 0x70, 0x20, /* master*/ 0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x00}; - static const unsigned char resumption_master_secret[] = {0x72, 0x65, 0x73, 0x20, /* master*/ 0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x00}; - static const unsigned char early_exporter_master_secret[] = {0x65, 0x20, 0x65, 0x78, 0x70, 0x20, /* master*/ 0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x00}; + static const unsigned char client_early_traffic[] = {0x63, 0x20, 0x65, 0x20, /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00}; + static const unsigned char client_handshake_traffic[] = {0x63, 0x20, 0x68, 0x73, 0x20, /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00}; + static const unsigned char client_application_traffic[] = {0x63, 0x20, 0x61, 0x70, 0x20, /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00}; + static const unsigned char server_handshake_traffic[] = {0x73, 0x20, 0x68, 0x73, 0x20, /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00}; + static const unsigned char server_application_traffic[] = {0x73, 0x20, 0x61, 0x70, 0x20, /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00}; + static const unsigned char exporter_master_secret[] = {0x65, 0x78, 0x70, 0x20, /* master*/ 0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x00}; + static const unsigned char resumption_master_secret[] = {0x72, 0x65, 0x73, 0x20, /* master*/ 0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x00}; + static const unsigned char early_exporter_master_secret[] = {0x65, 0x20, 0x65, 0x78, 0x70, 0x20, /* master*/ 0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x00}; #else static const unsigned char client_early_traffic[] = "c e traffic"; static const unsigned char client_handshake_traffic[] = "c hs traffic"; @@ -437,7 +448,7 @@ int tls13_change_cipher_state(SSL_CONNECTION *s, int which) unsigned char *insecret; unsigned char *finsecret = NULL; const char *log_label = NULL; - EVP_CIPHER_CTX *ciph_ctx; + EVP_CIPHER_CTX *ciph_ctx = NULL; size_t finsecretlen = 0; const unsigned char *label; size_t labellen, hashlen = 0; @@ -445,6 +456,7 @@ int tls13_change_cipher_state(SSL_CONNECTION *s, int which) const EVP_MD *md = NULL; const EVP_CIPHER *cipher = NULL; SSL_CTX *sctx = SSL_CONNECTION_GET_CTX(s); + size_t keylen, ivlen, taglen; #if !defined(OPENSSL_NO_KTLS) && defined(OPENSSL_KTLS_TLS13) ktls_crypto_info_t crypto_info; void *rl_sequence; @@ -452,16 +464,6 @@ int tls13_change_cipher_state(SSL_CONNECTION *s, int which) #endif if (which & SSL3_CC_READ) { - if (s->enc_read_ctx != NULL) { - EVP_CIPHER_CTX_reset(s->enc_read_ctx); - } else { - s->enc_read_ctx = EVP_CIPHER_CTX_new(); - if (s->enc_read_ctx == NULL) { - SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_MALLOC_FAILURE); - goto err; - } - } - ciph_ctx = s->enc_read_ctx; iv = s->read_iv; RECORD_LAYER_reset_read_sequence(&s->rlayer); @@ -659,7 +661,7 @@ int tls13_change_cipher_state(SSL_CONNECTION *s, int which) if (!derive_secret_key_and_iv(s, which & SSL3_CC_WRITE, md, cipher, insecret, hash, label, labellen, secret, key, - iv, ciph_ctx)) { + &keylen, iv, &ivlen, &taglen, ciph_ctx)) { /* SSLfatal() already called */ goto err; } @@ -700,6 +702,29 @@ int tls13_change_cipher_state(SSL_CONNECTION *s, int which) s->statem.enc_write_state = ENC_WRITE_STATE_WRITE_PLAIN_ALERTS; else s->statem.enc_write_state = ENC_WRITE_STATE_VALID; + + if ((which & SSL3_CC_READ) != 0) { + int level = (which & SSL3_CC_EARLY) != 0 + ? OSSL_RECORD_PROTECTION_LEVEL_EARLY + : ((which &SSL3_CC_HANDSHAKE) != 0 + ? OSSL_RECORD_PROTECTION_LEVEL_HANDSHAKE + : OSSL_RECORD_PROTECTION_LEVEL_APPLICATION); + s->rrlmethod->free(s->rrl); + s->rrl = s->rrlmethod->new_record_layer(sctx->libctx, + sctx->propq, + s->version, s->server, + OSSL_RECORD_DIRECTION_READ, + level, key, keylen, iv, ivlen, + NULL, 0, cipher, taglen, + NID_undef, NULL, NULL, s->rbio, + NULL, NULL, NULL, NULL, s); + if (s->rrl == NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + goto err; + } + } + + #ifndef OPENSSL_NO_KTLS # if defined(OPENSSL_KTLS_TLS13) if (!(which & SSL3_CC_APPLICATION) @@ -776,7 +801,9 @@ int tls13_update_key(SSL_CONNECTION *s, int sending) unsigned char *insecret, *iv; unsigned char secret[EVP_MAX_MD_SIZE]; EVP_CIPHER_CTX *ciph_ctx; + size_t keylen, ivlen, taglen; int ret = 0; + SSL_CTX *sctx = SSL_CONNECTION_GET_CTX(s); if (s->server == sending) insecret = s->server_app_traffic_secret; @@ -798,13 +825,32 @@ int tls13_update_key(SSL_CONNECTION *s, int sending) s->s3.tmp.new_sym_enc, insecret, NULL, application_traffic, sizeof(application_traffic) - 1, secret, key, - iv, ciph_ctx)) { + &keylen, iv, &ivlen, &taglen, ciph_ctx)) { /* SSLfatal() already called */ goto err; } memcpy(insecret, secret, hashlen); + if (!sending) { + s->rrlmethod->free(s->rrl); + s->rrl = s->rrlmethod->new_record_layer(sctx->libctx, + sctx->propq, + s->version, s->server, + OSSL_RECORD_DIRECTION_READ, + OSSL_RECORD_PROTECTION_LEVEL_APPLICATION, + key, keylen, iv, ivlen, + NULL, 0, s->s3.tmp.new_sym_enc, + taglen, NID_undef, NULL, NULL, + s->rbio, NULL, NULL, NULL, NULL, + s); + if (s->rrl == NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + goto err; + } + } + + s->statem.enc_write_state = ENC_WRITE_STATE_VALID; ret = 1; err: