Factor SSL_AEAD_CTX into a dedicated type.

tls1_enc is now SSL_AEAD_CTX_{open,seal}. This starts tidying up a bit
of the record-layer logic. This removes rr->input, as encrypting and
decrypting records no longer refers to various globals. It also removes
wrec altogether. SSL3_RECORD is now only used to maintain state about
the current incoming record. Outgoing records go straight to the write
buffer.

This also removes the outgoing alignment memcpy and simply calls
SSL_AEAD_CTX_seal with the parameters as appropriate. From bssl speed
tests, this seems to be faster on non-ARM and a bit of a wash on ARM.

Later it may be worth recasting these open/seal functions to write into
a CBB (tweaked so it can be malloc-averse), but for now they take an
out/out_len/max_out trio like their EVP_AEAD counterparts.

BUG=468889

Change-Id: Ie9266a818cc053f695d35ef611fd74c5d4def6c3
Reviewed-on: https://boringssl-review.googlesource.com/4792
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/err/ssl.errordata b/crypto/err/ssl.errordata
index afeaaeb..66ecf52 100644
--- a/crypto/err/ssl.errordata
+++ b/crypto/err/ssl.errordata
@@ -1,3 +1,6 @@
+SSL,function,276,SSL_AEAD_CTX_new
+SSL,function,277,SSL_AEAD_CTX_open
+SSL,function,278,SSL_AEAD_CTX_seal
 SSL,function,100,SSL_CTX_check_private_key
 SSL,function,101,SSL_CTX_new
 SSL,function,272,SSL_CTX_set1_tls_channel_id
@@ -72,6 +75,7 @@
 SSL,function,264,dtls1_process_fragment
 SSL,function,162,dtls1_process_record
 SSL,function,163,dtls1_read_bytes
+SSL,function,279,dtls1_seal_record
 SSL,function,164,dtls1_send_hello_verify_request
 SSL,function,165,dtls1_write_app_data_bytes
 SSL,function,166,i2d_SSL_SESSION
@@ -272,6 +276,7 @@
 SSL,reason,197,NULL_SSL_METHOD_PASSED
 SSL,reason,198,OLD_SESSION_CIPHER_NOT_RETURNED
 SSL,reason,273,OLD_SESSION_VERSION_NOT_RETURNED
+SSL,reason,274,OUTPUT_ALIASES_INPUT
 SSL,reason,199,PACKET_LENGTH_TOO_LONG
 SSL,reason,200,PARSE_TLSEXT
 SSL,reason,201,PATH_TOO_LONG
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 2ce4a84..cd41211 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -2720,6 +2720,10 @@
 #define SSL_F_SSL_set1_tls_channel_id 273
 #define SSL_F_SSL_set_tlsext_host_name 274
 #define SSL_F_ssl3_output_cert_chain 275
+#define SSL_F_SSL_AEAD_CTX_new 276
+#define SSL_F_SSL_AEAD_CTX_open 277
+#define SSL_F_SSL_AEAD_CTX_seal 278
+#define SSL_F_dtls1_seal_record 279
 #define SSL_R_APP_DATA_IN_HANDSHAKE 100
 #define SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT 101
 #define SSL_R_BAD_ALERT 102
@@ -2894,6 +2898,7 @@
 #define SSL_R_FRAGMENT_MISMATCH 271
 #define SSL_R_BUFFER_TOO_SMALL 272
 #define SSL_R_OLD_SESSION_VERSION_NOT_RETURNED 273
+#define SSL_R_OUTPUT_ALIASES_INPUT 274
 #define SSL_R_SSLV3_ALERT_CLOSE_NOTIFY 1000
 #define SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE 1010
 #define SSL_R_SSLV3_ALERT_BAD_RECORD_MAC 1020
diff --git a/include/openssl/ssl3.h b/include/openssl/ssl3.h
index 5c5fa61..24d4aa6 100644
--- a/include/openssl/ssl3.h
+++ b/include/openssl/ssl3.h
@@ -313,13 +313,23 @@
 #define SSL3_AD_INAPPROPRIATE_FALLBACK 86 /* fatal */
 
 typedef struct ssl3_record_st {
-  /*r */ int type;            /* type of record */
-  /*rw*/ unsigned int length; /* How many bytes available */
-  /*r */ unsigned int off;    /* read/write offset into 'buf' */
-  /*rw*/ uint8_t *data;       /* pointer to the record data */
-  /*rw*/ uint8_t *input;      /* where the decode bytes are */
-  /*r */ unsigned long epoch; /* epoch number, needed by DTLS1 */
-  /*r */ uint8_t seq_num[8];  /* sequence number, needed by DTLS1 */
+  /* type is the record type. */
+  uint8_t type;
+  /* length is the number of unconsumed bytes of |data|. */
+  uint16_t length;
+  /* off is the number of consumed bytes of |data|. */
+  uint16_t off;
+  /* data is a non-owning pointer to the record contents. The total length of
+   * the buffer is |off| + |length|. */
+  uint8_t *data;
+  /* epoch, in DTLS, is the epoch number of the record. */
+  uint16_t epoch;
+  /* seq_num, in DTLS, is the sequence number of the record. The top two bytes
+   * are always zero.
+   *
+   * TODO(davidben): This is confusing. They should include the epoch or the
+   * field should be six bytes. */
+  uint8_t seq_num[8];
 } SSL3_RECORD;
 
 typedef struct ssl3_buffer_st {
@@ -379,7 +389,6 @@
   SSL3_BUFFER wbuf; /* write IO goes into here */
 
   SSL3_RECORD rrec; /* each decoded record goes in here */
-  SSL3_RECORD wrec; /* goes out from here */
 
   /* storage for Handshake protocol data received but not yet processed by
    * ssl3_read_bytes: */
diff --git a/ssl/CMakeLists.txt b/ssl/CMakeLists.txt
index 9cc6de4..f016046 100644
--- a/ssl/CMakeLists.txt
+++ b/ssl/CMakeLists.txt
@@ -19,6 +19,7 @@
   s3_meth.c
   s3_pkt.c
   s3_srvr.c
+  ssl_aead_ctx.c
   ssl_algs.c
   ssl_asn1.c
   ssl_cert.c
diff --git a/ssl/d1_both.c b/ssl/d1_both.c
index 662f518..f6442fd 100644
--- a/ssl/d1_both.c
+++ b/ssl/d1_both.c
@@ -263,7 +263,6 @@
   int ret;
   int curr_mtu;
   unsigned int len, frag_off;
-  size_t max_overhead = 0;
 
   /* AHA!  Figure out the MTU, and stick to the right size */
   if (s->d1->mtu < dtls1_min_mtu() &&
@@ -286,12 +285,7 @@
   }
 
   /* Determine the maximum overhead of the current cipher. */
-  if (s->aead_write_ctx != NULL) {
-    max_overhead = EVP_AEAD_max_overhead(s->aead_write_ctx->ctx.aead);
-    if (s->aead_write_ctx->variable_nonce_included_in_record) {
-      max_overhead += s->aead_write_ctx->variable_nonce_len;
-    }
-  }
+  size_t max_overhead = SSL_AEAD_CTX_max_overhead(s->aead_write_ctx);
 
   frag_off = 0;
   while (s->init_num) {
diff --git a/ssl/d1_pkt.c b/ssl/d1_pkt.c
index 9e056ac..e80e773 100644
--- a/ssl/d1_pkt.c
+++ b/ssl/d1_pkt.c
@@ -189,21 +189,7 @@
 
 static int dtls1_process_record(SSL *s) {
   int al;
-  SSL3_RECORD *rr;
-
-  rr = &(s->s3->rrec);
-
-  /* At this point, s->packet_length == SSL3_RT_HEADER_LNGTH + rr->length, and
-   * we have that many bytes in s->packet. */
-  rr->input = &(s->packet[DTLS1_RT_HEADER_LENGTH]);
-
-  /* ok, we can now read from 's->packet' data into 'rr' rr->input points at
-   * rr->length bytes, which need to be copied into rr->data by either the
-   * decryption or by the decompression When the data is 'copied' into the
-   * rr->data buffer, rr->input will be pointed at the new buffer */
-
-  /* We now have - encrypted [ MAC [ compressed [ plain ] ] ] rr->length bytes
-   * of encrypted compressed stuff. */
+  SSL3_RECORD *rr = &s->s3->rrec;
 
   /* check is not needed I believe */
   if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH) {
@@ -213,10 +199,23 @@
     goto f_err;
   }
 
-  /* decrypt in place in 'rr->input' */
-  rr->data = rr->input;
+  /* |rr->data| points to |rr->length| bytes of ciphertext in |s->packet|. */
+  rr->data = &s->packet[DTLS1_RT_HEADER_LENGTH];
 
-  if (!s->enc_method->enc(s, 0)) {
+  uint8_t seq[8];
+  seq[0] = rr->epoch >> 8;
+  seq[1] = rr->epoch & 0xff;
+  memcpy(&seq[2], &rr->seq_num[2], 6);
+
+  /* Decrypt the packet in-place. Note it is important that |SSL_AEAD_CTX_open|
+   * not write beyond |rr->length|. There may be another record in the packet.
+   *
+   * TODO(davidben): This assumes |s->version| is the same as the record-layer
+   * version which isn't always true, but it only differs with the NULL cipher
+   * which ignores the parameter. */
+  size_t plaintext_len;
+  if (!SSL_AEAD_CTX_open(s->aead_read_ctx, rr->data, &plaintext_len, rr->length,
+                         rr->type, s->version, seq, rr->data, rr->length)) {
     /* Bad packets are silently dropped in DTLS. Clear the error queue of any
      * errors decryption may have added. */
     ERR_clear_error();
@@ -225,19 +224,20 @@
     goto err;
   }
 
-  if (rr->length > SSL3_RT_MAX_PLAIN_LENGTH) {
+  if (plaintext_len > SSL3_RT_MAX_PLAIN_LENGTH) {
     al = SSL_AD_RECORD_OVERFLOW;
     OPENSSL_PUT_ERROR(SSL, dtls1_process_record, SSL_R_DATA_LENGTH_TOO_LONG);
     goto f_err;
   }
+  assert(plaintext_len < (1u << 16));
+  rr->length = plaintext_len;
 
   rr->off = 0;
   /* So at this point the following is true
    * ssl->s3->rrec.type 	is the type of record
    * ssl->s3->rrec.length	== number of bytes in record
    * ssl->s3->rrec.off	== offset to first valid byte
-   * ssl->s3->rrec.data	== where to take bytes from, increment
-   *			   after use :-). */
+   * ssl->s3->rrec.data	== the first byte of the record body. */
 
   /* we have pulled in a full packet so zero things */
   s->packet_length = 0;
@@ -260,11 +260,11 @@
  *
  * used only by dtls1_read_bytes */
 int dtls1_get_record(SSL *s) {
-  int ssl_major, ssl_minor;
+  uint8_t ssl_major, ssl_minor;
   int i, n;
   SSL3_RECORD *rr;
-  unsigned char *p = NULL;
-  unsigned short version;
+  uint8_t *p = NULL;
+  uint16_t version;
 
   rr = &(s->s3->rrec);
 
@@ -298,7 +298,7 @@
     rr->type = *(p++);
     ssl_major = *(p++);
     ssl_minor = *(p++);
-    version = (ssl_major << 8) | ssl_minor;
+    version = (((uint16_t)ssl_major) << 8) | ssl_minor;
 
     /* sequence number is 64 bits, with top 2 bytes = epoch */
     n2s(p, rr->epoch);
@@ -710,14 +710,56 @@
   return i;
 }
 
+/* dtls1_seal_record seals a new record of type |type| and plaintext |in| and
+ * writes it to |out|. At most |max_out| bytes will be written. It returns one
+ * on success and zero on error. On success, it updates the write sequence
+ * number. */
+static int dtls1_seal_record(SSL *s, uint8_t *out, size_t *out_len,
+                             size_t max_out, uint8_t type, const uint8_t *in,
+                             size_t in_len) {
+  if (max_out < DTLS1_RT_HEADER_LENGTH) {
+    OPENSSL_PUT_ERROR(SSL, dtls1_seal_record, SSL_R_BUFFER_TOO_SMALL);
+    return 0;
+  }
+
+  out[0] = type;
+
+  uint16_t wire_version = s->s3->have_version ? s->version : DTLS1_VERSION;
+  out[1] = wire_version >> 8;
+  out[2] = wire_version & 0xff;
+
+  out[3] = s->d1->w_epoch >> 8;
+  out[4] = s->d1->w_epoch & 0xff;
+  memcpy(&out[5], &s->s3->write_sequence[2], 6);
+
+  size_t ciphertext_len;
+  if (!SSL_AEAD_CTX_seal(s->aead_write_ctx, out + DTLS1_RT_HEADER_LENGTH,
+                         &ciphertext_len, max_out - DTLS1_RT_HEADER_LENGTH,
+                         type, wire_version, &out[3] /* seq */, in, in_len) ||
+      !ssl3_record_sequence_update(&s->s3->write_sequence[2], 6)) {
+    return 0;
+  }
+
+  if (ciphertext_len >= 1 << 16) {
+    OPENSSL_PUT_ERROR(SSL, dtls1_seal_record, ERR_R_OVERFLOW);
+    return 0;
+  }
+  out[11] = ciphertext_len >> 8;
+  out[12] = ciphertext_len & 0xff;
+
+  *out_len = DTLS1_RT_HEADER_LENGTH + ciphertext_len;
+
+  if (s->msg_callback) {
+    s->msg_callback(1 /* write */, 0, SSL3_RT_HEADER, out,
+                    DTLS1_RT_HEADER_LENGTH, s, s->msg_callback_arg);
+  }
+
+  return 1;
+}
+
 static int do_dtls1_write(SSL *s, int type, const uint8_t *buf,
                           unsigned int len) {
-  uint8_t *p, *pseq;
-  int i;
-  int prefix_len = 0;
-  int eivlen = 0;
-  SSL3_RECORD *wr;
-  SSL3_BUFFER *wb;
+  SSL3_BUFFER *wb = &s->s3->wbuf;
 
   /* ssl3_write_pending drops the write if |BIO_write| fails in DTLS, so there
    * is never pending data. */
@@ -725,88 +767,35 @@
 
   /* If we have an alert to send, lets send it */
   if (s->s3->alert_dispatch) {
-    i = s->method->ssl_dispatch_alert(s);
-    if (i <= 0) {
-      return i;
+    int ret = s->method->ssl_dispatch_alert(s);
+    if (ret <= 0) {
+      return ret;
     }
     /* if it went, fall through and send more stuff */
   }
 
+  if (wb->buf == NULL && !ssl3_setup_write_buffer(s)) {
+    return -1;
+  }
+
   if (len == 0) {
     return 0;
   }
 
-  wr = &(s->s3->wrec);
-  wb = &(s->s3->wbuf);
+  /* Align the output so the ciphertext is aligned to |SSL3_ALIGN_PAYLOAD|. */
+  uintptr_t align = (uintptr_t)wb->buf + DTLS1_RT_HEADER_LENGTH;
+  align = (-align) & (SSL3_ALIGN_PAYLOAD - 1);
+  uint8_t *out = wb->buf + align;
+  wb->offset = align;
+  size_t max_out = wb->len - wb->offset;
 
-  if (wb->buf == NULL && !ssl3_setup_write_buffer(s)) {
+  size_t ciphertext_len;
+  if (!dtls1_seal_record(s, out, &ciphertext_len, max_out, type, buf, len)) {
     return -1;
   }
-  p = wb->buf + prefix_len;
-
-  /* write the header */
-
-  *(p++) = type & 0xff;
-  wr->type = type;
-  /* Special case: for hello verify request, client version 1.0 and
-   * we haven't decided which version to use yet send back using
-   * version 1.0 header: otherwise some clients will ignore it.
-   */
-  if (!s->s3->have_version) {
-    *(p++) = DTLS1_VERSION >> 8;
-    *(p++) = DTLS1_VERSION & 0xff;
-  } else {
-    *(p++) = s->version >> 8;
-    *(p++) = s->version & 0xff;
-  }
-
-  /* field where we are to write out packet epoch, seq num and len */
-  pseq = p;
-  p += 10;
-
-  /* Leave room for the variable nonce for AEADs which specify it explicitly. */
-  if (s->aead_write_ctx != NULL &&
-      s->aead_write_ctx->variable_nonce_included_in_record) {
-    eivlen = s->aead_write_ctx->variable_nonce_len;
-  }
-
-  /* Assemble the input for |s->enc_method->enc|. The input is the plaintext
-   * with |eivlen| bytes of space prepended for the explicit nonce. */
-  wr->input = p;
-  wr->length = eivlen + len;
-  memcpy(p + eivlen, buf, len);
-
-  /* Encrypt in-place, so the output also goes into |p|. */
-  wr->data = p;
-
-  if (!s->enc_method->enc(s, 1)) {
-    goto err;
-  }
-
-  /* there's only one epoch between handshake and app data */
-  s2n(s->d1->w_epoch, pseq);
-
-  memcpy(pseq, &(s->s3->write_sequence[2]), 6);
-  pseq += 6;
-  s2n(wr->length, pseq);
-
-  if (s->msg_callback) {
-    s->msg_callback(1, 0, SSL3_RT_HEADER, pseq - DTLS1_RT_HEADER_LENGTH,
-                    DTLS1_RT_HEADER_LENGTH, s, s->msg_callback_arg);
-  }
-
-  /* we should now have wr->data pointing to the encrypted data, which is
-   * wr->length long */
-  wr->type = type; /* not needed but helps for debugging */
-  wr->length += DTLS1_RT_HEADER_LENGTH;
-
-  if (!ssl3_record_sequence_update(&s->s3->write_sequence[2], 6)) {
-    goto err;
-  }
 
   /* now let's set up wb */
-  wb->left = prefix_len + wr->length;
-  wb->offset = 0;
+  wb->left = ciphertext_len;
 
   /* memorize arguments so that ssl3_write_pending can detect bad write retries
    * later */
@@ -817,9 +806,6 @@
 
   /* we now just need to write the buffer */
   return ssl3_write_pending(s, type, buf, len);
-
-err:
-  return -1;
 }
 
 static int dtls1_record_replay_check(SSL *s, DTLS1_BITMAP *bitmap) {
diff --git a/ssl/internal.h b/ssl/internal.h
index 0974b07..c4e931d 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -291,6 +291,75 @@
 int ssl_cipher_requires_server_key_exchange(const SSL_CIPHER *cipher);
 
 
+/* Encryption layer. */
+
+/* SSL_AEAD_CTX contains information about an AEAD that is being used to encrypt
+ * an SSL connection. */
+struct ssl_aead_ctx_st {
+  const SSL_CIPHER *cipher;
+  EVP_AEAD_CTX ctx;
+  /* fixed_nonce contains any bytes of the nonce that are fixed for all
+   * records. */
+  uint8_t fixed_nonce[8];
+  uint8_t fixed_nonce_len, variable_nonce_len;
+  /* variable_nonce_included_in_record is non-zero if the variable nonce
+   * for a record is included as a prefix before the ciphertext. */
+  char variable_nonce_included_in_record;
+  /* random_variable_nonce is non-zero if the variable nonce is
+   * randomly generated, rather than derived from the sequence
+   * number. */
+  char random_variable_nonce;
+  /* omit_length_in_ad is non-zero if the length should be omitted in the
+   * AEAD's ad parameter. */
+  char omit_length_in_ad;
+  /* omit_version_in_ad is non-zero if the version should be omitted
+   * in the AEAD's ad parameter. */
+  char omit_version_in_ad;
+} /* SSL_AEAD_CTX */;
+
+/* SSL_AEAD_CTX_new creates a newly-allocated |SSL_AEAD_CTX| using the supplied
+ * key material. It returns NULL on error. Only one of |SSL_AEAD_CTX_open| or
+ * |SSL_AEAD_CTX_seal| may be used with the resulting object, depending on
+ * |direction|. |version| is the normalized protocol version, so DTLS 1.0 is
+ * represented as 0x0301, not 0xffef. */
+SSL_AEAD_CTX *SSL_AEAD_CTX_new(enum evp_aead_direction_t direction,
+                               uint16_t version, const SSL_CIPHER *cipher,
+                               const uint8_t *enc_key, size_t enc_key_len,
+                               const uint8_t *mac_key, size_t mac_key_len,
+                               const uint8_t *fixed_iv, size_t fixed_iv_len);
+
+/* SSL_AEAD_CTX_free frees |ctx|. */
+void SSL_AEAD_CTX_free(SSL_AEAD_CTX *ctx);
+
+/* SSL_AEAD_CTX_explicit_nonce_len returns the length of the explicit nonce for
+ * |ctx|, if any. |ctx| may be NULL to denote the null cipher. */
+size_t SSL_AEAD_CTX_explicit_nonce_len(SSL_AEAD_CTX *ctx);
+
+/* SSL_AEAD_CTX_max_overhead returns the maximum overhead of calling
+ * |SSL_AEAD_CTX_seal|. |ctx| may be NULL to denote the null cipher. */
+size_t SSL_AEAD_CTX_max_overhead(SSL_AEAD_CTX *ctx);
+
+/* SSL_AEAD_CTX_open authenticates and decrypts |in_len| bytes from |in| and
+ * writes the result to |out|. It returns one on success and zero on
+ * error. |ctx| may be NULL to denote the null cipher.
+ *
+ * If |in| and |out| alias then |out| must be <= |in| + |explicit_nonce_len|. */
+int SSL_AEAD_CTX_open(SSL_AEAD_CTX *ctx, uint8_t *out, size_t *out_len,
+                      size_t max_out, uint8_t type, uint16_t wire_version,
+                      const uint8_t seqnum[8], const uint8_t *in,
+                      size_t in_len);
+
+/* SSL_AEAD_CTX_seal encrypts and authenticates |in_len| bytes from |in| and
+ * writes the result to |out|. It returns one on success and zero on
+ * error. |ctx| may be NULL to denote the null cipher.
+ *
+ * If |in| and |out| alias then |out| + |explicit_nonce_len| must be <= |in| */
+int SSL_AEAD_CTX_seal(SSL_AEAD_CTX *ctx, uint8_t *out, size_t *out_len,
+                      size_t max_out, uint8_t type, uint16_t wire_version,
+                      const uint8_t seqnum[8], const uint8_t *in,
+                      size_t in_len);
+
+
 /* Underdocumented functions.
  *
  * Functions below here haven't been touched up and may be underdocumented. */
@@ -596,7 +665,6 @@
 /* This is for the SSLv3/TLSv1.0 differences in crypto/hash stuff It is a bit
  * of a mess of functions, but hell, think of it as an opaque structure. */
 struct ssl3_enc_method {
-  int (*enc)(SSL *, int);
   int (*prf)(SSL *, uint8_t *, size_t, const uint8_t *, size_t, const char *,
              size_t, const uint8_t *, size_t, const uint8_t *, size_t);
   int (*setup_key_block)(SSL *);
@@ -634,30 +702,6 @@
  * may apply to others in future. */
 #define SSL_ENC_FLAG_TLS1_2_CIPHERS 0x8
 
-/* ssl_aead_ctx_st contains information about an AEAD that is being used to
- * encrypt an SSL connection. */
-struct ssl_aead_ctx_st {
-  const SSL_CIPHER *cipher;
-  EVP_AEAD_CTX ctx;
-  /* fixed_nonce contains any bytes of the nonce that are fixed for all
-   * records. */
-  uint8_t fixed_nonce[8];
-  uint8_t fixed_nonce_len, variable_nonce_len, tag_len;
-  /* variable_nonce_included_in_record is non-zero if the variable nonce
-   * for a record is included as a prefix before the ciphertext. */
-  char variable_nonce_included_in_record;
-  /* random_variable_nonce is non-zero if the variable nonce is
-   * randomly generated, rather than derived from the sequence
-   * number. */
-  char random_variable_nonce;
-  /* omit_length_in_ad is non-zero if the length should be omitted in the
-   * AEAD's ad parameter. */
-  char omit_length_in_ad;
-  /* omit_version_in_ad is non-zero if the version should be omitted
-   * in the AEAD's ad parameter. */
-  char omit_version_in_ad;
-};
-
 /* lengths of messages */
 #define DTLS1_COOKIE_LENGTH 256
 
@@ -988,7 +1032,6 @@
 
 int tls1_change_cipher_state(SSL *s, int which);
 int tls1_setup_key_block(SSL *s);
-int tls1_enc(SSL *s, int snd);
 int tls1_handshake_digest(SSL *s, uint8_t *out, size_t out_len);
 int tls1_final_finish_mac(SSL *s, const char *str, int slen, uint8_t *p);
 int tls1_cert_verify_mac(SSL *s, int md_nid, uint8_t *p);
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index 674277f..101ea83 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -478,7 +478,6 @@
 };
 
 const SSL3_ENC_METHOD SSLv3_enc_data = {
-    tls1_enc,
     ssl3_prf,
     tls1_setup_key_block,
     tls1_generate_master_secret,
@@ -533,7 +532,6 @@
   }
   memset(s3, 0, sizeof *s3);
   memset(s3->rrec.seq_num, 0, sizeof(s3->rrec.seq_num));
-  memset(s3->wrec.seq_num, 0, sizeof(s3->wrec.seq_num));
 
   s->s3 = s3;
 
diff --git a/ssl/s3_pkt.c b/ssl/s3_pkt.c
index dded371..18cf47b 100644
--- a/ssl/s3_pkt.c
+++ b/ssl/s3_pkt.c
@@ -262,16 +262,14 @@
  * ssl->s3->rrec.length  - number of bytes */
 /* used only by ssl3_read_bytes */
 static int ssl3_get_record(SSL *s) {
-  int ssl_major, ssl_minor, al;
-  int n, i, ret = -1;
-  SSL3_RECORD *rr;
+  uint8_t ssl_major, ssl_minor;
+  int al, n, i, ret = -1;
+  SSL3_RECORD *rr = &s->s3->rrec;
   uint8_t *p;
-  short version;
+  uint16_t version;
   size_t extra;
   unsigned empty_record_count = 0;
 
-  rr = &s->s3->rrec;
-
 again:
   /* check if we have the header */
   if (s->rstate != SSL_ST_READ_BODY ||
@@ -296,7 +294,7 @@
     rr->type = *(p++);
     ssl_major = *(p++);
     ssl_minor = *(p++);
-    version = (ssl_major << 8) | ssl_minor;
+    version = (((uint16_t)ssl_major) << 8) | ssl_minor;
     n2s(p, rr->length);
 
     if (s->s3->have_version && version != s->version) {
@@ -339,40 +337,40 @@
 
   s->rstate = SSL_ST_READ_HEADER; /* set state for later operations */
 
-  /* At this point, s->packet_length == SSL3_RT_HEADER_LNGTH + rr->length, and
-   * we have that many bytes in s->packet. */
-  rr->input = &s->packet[SSL3_RT_HEADER_LENGTH];
+  /* |rr->data| points to |rr->length| bytes of ciphertext in |s->packet|. */
+  rr->data = &s->packet[SSL3_RT_HEADER_LENGTH];
 
-  /* ok, we can now read from |s->packet| data into |rr|. |rr->input| points at
-   * |rr->length| bytes, which need to be copied into |rr->data| by decryption.
-   * When the data is 'copied' into the |rr->data| buffer, |rr->input| will be
-   * pointed at the new buffer. */
-
-  /* We now have - encrypted [ MAC [ compressed [ plain ] ] ]
-   * rr->length bytes of encrypted compressed stuff. */
-
-  /* decrypt in place in 'rr->input' */
-  rr->data = rr->input;
-
-  if (!s->enc_method->enc(s, 0)) {
+  /* Decrypt the packet in-place.
+   *
+   * TODO(davidben): This assumes |s->version| is the same as the record-layer
+   * version which isn't always true, but it only differs with the NULL cipher
+   * which ignores the parameter. */
+  size_t plaintext_len;
+  if (!SSL_AEAD_CTX_open(s->aead_read_ctx, rr->data, &plaintext_len, rr->length,
+                         rr->type, s->version, s->s3->read_sequence, rr->data,
+                         rr->length)) {
     al = SSL_AD_BAD_RECORD_MAC;
     OPENSSL_PUT_ERROR(SSL, ssl3_get_record,
                       SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC);
     goto f_err;
   }
-
-  if (rr->length > SSL3_RT_MAX_PLAIN_LENGTH + extra) {
+  if (!ssl3_record_sequence_update(s->s3->read_sequence, 8)) {
+    goto err;
+  }
+  if (plaintext_len > SSL3_RT_MAX_PLAIN_LENGTH + extra) {
     al = SSL_AD_RECORD_OVERFLOW;
     OPENSSL_PUT_ERROR(SSL, ssl3_get_record, SSL_R_DATA_LENGTH_TOO_LONG);
     goto f_err;
   }
+  assert(plaintext_len <= (1u << 16));
+  rr->length = plaintext_len;
 
   rr->off = 0;
   /* So at this point the following is true:
    * ssl->s3->rrec.type is the type of record;
    * ssl->s3->rrec.length is the number of bytes in the record;
    * ssl->s3->rrec.off is the offset to first valid byte;
-   * ssl->s3->rrec.data is where to take bytes from (increment after use). */
+   * ssl->s3->rrec.data the first byte of the record body. */
 
   /* we have pulled in a full packet so zero things */
   s->packet_length = 0;
@@ -471,8 +469,8 @@
 
 /* ssl3_seal_record seals a new record of type |type| and plaintext |in| and
  * writes it to |out|. At most |max_out| bytes will be written. It returns one
- * on success and zero on error. On success, |s->s3->wrec| is updated to include
- * the new record. */
+ * on success and zero on error. On success, it updates the write sequence
+ * number. */
 static int ssl3_seal_record(SSL *s, uint8_t *out, size_t *out_len,
                             size_t max_out, uint8_t type, const uint8_t *in,
                             size_t in_len) {
@@ -485,61 +483,30 @@
 
   /* Some servers hang if initial ClientHello is larger than 256 bytes and
    * record version number > TLS 1.0. */
+  uint16_t wire_version = s->version;
   if (!s->s3->have_version && s->version > SSL3_VERSION) {
-    out[1] = TLS1_VERSION >> 8;
-    out[2] = TLS1_VERSION & 0xff;
-  } else {
-    out[1] = s->version >> 8;
-    out[2] = s->version & 0xff;
+    wire_version = TLS1_VERSION;
+  }
+  out[1] = wire_version >> 8;
+  out[2] = wire_version & 0xff;
+
+  size_t ciphertext_len;
+  if (!SSL_AEAD_CTX_seal(s->aead_write_ctx, out + SSL3_RT_HEADER_LENGTH,
+                         &ciphertext_len, max_out - SSL3_RT_HEADER_LENGTH,
+                         type, wire_version, s->s3->write_sequence, in,
+                         in_len) ||
+      !ssl3_record_sequence_update(s->s3->write_sequence, 8)) {
+    return 0;
   }
 
-  size_t explicit_nonce_len = 0;
-  if (s->aead_write_ctx != NULL &&
-      s->aead_write_ctx->variable_nonce_included_in_record) {
-    explicit_nonce_len = s->aead_write_ctx->variable_nonce_len;
-  }
-  size_t max_overhead = 0;
-  if (s->aead_write_ctx != NULL) {
-    max_overhead = s->aead_write_ctx->tag_len;
-  }
-
-  /* Assemble the input for |s->enc_method->enc|. The input is the plaintext
-   * with |explicit_nonce_len| bytes of space prepended for the explicit
-   * nonce. The input is copied into |out| and then encrypted in-place to take
-   * advantage of alignment.
-   *
-   * TODO(davidben): |tls1_enc| should accept its inputs and outputs directly
-   * rather than looking up in |wrec| and friends. The |max_overhead| bounds
-   * check would also be unnecessary if |max_out| were passed down. */
-  SSL3_RECORD *wr = &s->s3->wrec;
-  size_t plaintext_len = in_len + explicit_nonce_len;
-  if (plaintext_len < in_len || plaintext_len > INT_MAX ||
-      plaintext_len + max_overhead < plaintext_len) {
+  if (ciphertext_len >= 1 << 16) {
     OPENSSL_PUT_ERROR(SSL, ssl3_seal_record, ERR_R_OVERFLOW);
     return 0;
   }
-  if (max_out - SSL3_RT_HEADER_LENGTH < plaintext_len + max_overhead) {
-    OPENSSL_PUT_ERROR(SSL, ssl3_seal_record, SSL_R_BUFFER_TOO_SMALL);
-    return 0;
-  }
-  wr->type = type;
-  wr->input = out + SSL3_RT_HEADER_LENGTH;
-  wr->data = wr->input;
-  wr->length = plaintext_len;
-  memcpy(wr->input + explicit_nonce_len, in, in_len);
+  out[3] = ciphertext_len >> 8;
+  out[4] = ciphertext_len & 0xff;
 
-  if (!s->enc_method->enc(s, 1)) {
-    return 0;
-  }
-
-  /* |wr->length| has now been set to the ciphertext length. */
-  if (wr->length >= 1 << 16) {
-    OPENSSL_PUT_ERROR(SSL, ssl3_seal_record, ERR_R_OVERFLOW);
-    return 0;
-  }
-  out[3] = wr->length >> 8;
-  out[4] = wr->length & 0xff;
-  *out_len = SSL3_RT_HEADER_LENGTH + (size_t)wr->length;
+  *out_len = SSL3_RT_HEADER_LENGTH + ciphertext_len;
 
  if (s->msg_callback) {
    s->msg_callback(1 /* write */, 0, SSL3_RT_HEADER, out, SSL3_RT_HEADER_LENGTH,
diff --git a/ssl/ssl_aead_ctx.c b/ssl/ssl_aead_ctx.c
new file mode 100644
index 0000000..c2fba1d
--- /dev/null
+++ b/ssl/ssl_aead_ctx.c
@@ -0,0 +1,257 @@
+/* Copyright (c) 2015, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <assert.h>
+#include <string.h>
+
+#include <openssl/aead.h>
+#include <openssl/err.h>
+#include <openssl/rand.h>
+#include <openssl/type_check.h>
+
+#include "internal.h"
+
+
+OPENSSL_COMPILE_ASSERT(EVP_AEAD_MAX_NONCE_LENGTH < 256,
+                       variable_nonce_len_doesnt_fit_in_uint8_t);
+
+SSL_AEAD_CTX *SSL_AEAD_CTX_new(enum evp_aead_direction_t direction,
+                               uint16_t version, const SSL_CIPHER *cipher,
+                               const uint8_t *enc_key, size_t enc_key_len,
+                               const uint8_t *mac_key, size_t mac_key_len,
+                               const uint8_t *fixed_iv, size_t fixed_iv_len) {
+  const EVP_AEAD *aead;
+  size_t discard;
+  if (!ssl_cipher_get_evp_aead(&aead, &discard, &discard, cipher, version)) {
+    OPENSSL_PUT_ERROR(SSL, SSL_AEAD_CTX_new, ERR_R_INTERNAL_ERROR);
+    return 0;
+  }
+
+  uint8_t merged_key[EVP_AEAD_MAX_KEY_LENGTH];
+  if (mac_key_len > 0) {
+    /* This is a "stateful" AEAD (for compatibility with pre-AEAD cipher
+     * suites). */
+    if (mac_key_len + enc_key_len + fixed_iv_len > sizeof(merged_key)) {
+      OPENSSL_PUT_ERROR(SSL, SSL_AEAD_CTX_new, ERR_R_INTERNAL_ERROR);
+      return 0;
+    }
+    memcpy(merged_key, mac_key, mac_key_len);
+    memcpy(merged_key + mac_key_len, enc_key, enc_key_len);
+    memcpy(merged_key + mac_key_len + enc_key_len, fixed_iv, fixed_iv_len);
+    enc_key = merged_key;
+    enc_key_len += mac_key_len;
+    enc_key_len += fixed_iv_len;
+  }
+
+  SSL_AEAD_CTX *aead_ctx = (SSL_AEAD_CTX *)OPENSSL_malloc(sizeof(SSL_AEAD_CTX));
+  if (aead_ctx == NULL) {
+    OPENSSL_PUT_ERROR(SSL, SSL_AEAD_CTX_new, ERR_R_MALLOC_FAILURE);
+    return NULL;
+  }
+  memset(aead_ctx, 0, sizeof(SSL_AEAD_CTX));
+  aead_ctx->cipher = cipher;
+
+  if (!EVP_AEAD_CTX_init_with_direction(
+          &aead_ctx->ctx, aead, enc_key, enc_key_len,
+          EVP_AEAD_DEFAULT_TAG_LENGTH, direction)) {
+    OPENSSL_free(aead_ctx);
+    return NULL;
+  }
+
+  assert(EVP_AEAD_nonce_length(aead) <= EVP_AEAD_MAX_NONCE_LENGTH);
+  aead_ctx->variable_nonce_len = (uint8_t)EVP_AEAD_nonce_length(aead);
+  if (mac_key_len == 0) {
+    /* For a real AEAD, the IV is the fixed part of the nonce. */
+    if (fixed_iv_len > sizeof(aead_ctx->fixed_nonce) ||
+        fixed_iv_len > aead_ctx->variable_nonce_len) {
+      SSL_AEAD_CTX_free(aead_ctx);
+      OPENSSL_PUT_ERROR(SSL, SSL_AEAD_CTX_new, ERR_R_INTERNAL_ERROR);
+      return 0;
+    }
+    aead_ctx->variable_nonce_len -= fixed_iv_len;
+
+    memcpy(aead_ctx->fixed_nonce, fixed_iv, fixed_iv_len);
+    aead_ctx->fixed_nonce_len = fixed_iv_len;
+    aead_ctx->variable_nonce_included_in_record =
+        (cipher->algorithm2 &
+         SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD) != 0;
+  } else {
+    aead_ctx->variable_nonce_included_in_record = 1;
+    aead_ctx->random_variable_nonce = 1;
+    aead_ctx->omit_length_in_ad = 1;
+    aead_ctx->omit_version_in_ad = (version == SSL3_VERSION);
+  }
+
+  return aead_ctx;
+}
+
+void SSL_AEAD_CTX_free(SSL_AEAD_CTX *aead) {
+  if (aead == NULL) {
+    return;
+  }
+  EVP_AEAD_CTX_cleanup(&aead->ctx);
+  OPENSSL_free(aead);
+}
+
+size_t SSL_AEAD_CTX_explicit_nonce_len(SSL_AEAD_CTX *aead) {
+  if (aead != NULL && aead->variable_nonce_included_in_record) {
+    return aead->variable_nonce_len;
+  }
+  return 0;
+}
+
+size_t SSL_AEAD_CTX_max_overhead(SSL_AEAD_CTX *aead) {
+  if (aead == NULL) {
+    return 0;
+  }
+  return EVP_AEAD_max_overhead(aead->ctx.aead) +
+      SSL_AEAD_CTX_explicit_nonce_len(aead);
+}
+
+/* ssl_aead_ctx_get_ad writes the additional data for |aead| into |out| and
+ * returns the number of bytes written. */
+static size_t ssl_aead_ctx_get_ad(SSL_AEAD_CTX *aead, uint8_t out[13],
+                                  uint8_t type, uint16_t wire_version,
+                                  const uint8_t seqnum[8],
+                                  size_t plaintext_len) {
+  memcpy(out, seqnum, 8);
+  size_t len = 8;
+  out[len++] = type;
+  if (!aead->omit_version_in_ad) {
+    out[len++] = (uint8_t)(wire_version >> 8);
+    out[len++] = (uint8_t)wire_version;
+  }
+  if (!aead->omit_length_in_ad) {
+    out[len++] = (uint8_t)(plaintext_len >> 8);
+    out[len++] = (uint8_t)plaintext_len;
+  }
+  return len;
+}
+
+int SSL_AEAD_CTX_open(SSL_AEAD_CTX *aead, uint8_t *out, size_t *out_len,
+                      size_t max_out, uint8_t type, uint16_t wire_version,
+                      const uint8_t seqnum[8], const uint8_t *in,
+                      size_t in_len) {
+  if (aead == NULL) {
+    /* Handle the initial NULL cipher. */
+    if (in_len > max_out) {
+      OPENSSL_PUT_ERROR(SSL, SSL_AEAD_CTX_open, SSL_R_BUFFER_TOO_SMALL);
+      return 0;
+    }
+    memmove(out, in, in_len);
+    *out_len = in_len;
+    return 1;
+  }
+
+  /* TLS 1.2 AEADs include the length in the AD and are assumed to have fixed
+   * overhead. Otherwise the parameter is unused. */
+  size_t plaintext_len = 0;
+  if (!aead->omit_length_in_ad) {
+    size_t overhead = SSL_AEAD_CTX_max_overhead(aead);
+    if (in_len < overhead) {
+      /* Publicly invalid. */
+      OPENSSL_PUT_ERROR(SSL, SSL_AEAD_CTX_open, SSL_R_BAD_PACKET_LENGTH);
+      return 0;
+    }
+    plaintext_len = in_len - overhead;
+  }
+  uint8_t ad[13];
+  size_t ad_len = ssl_aead_ctx_get_ad(aead, ad, type, wire_version, seqnum,
+                                      plaintext_len);
+
+  /* Assemble the nonce. */
+  uint8_t nonce[EVP_AEAD_MAX_NONCE_LENGTH];
+  size_t nonce_len = 0;
+  memcpy(nonce, aead->fixed_nonce, aead->fixed_nonce_len);
+  nonce_len += aead->fixed_nonce_len;
+  if (aead->variable_nonce_included_in_record) {
+    if (in_len < aead->variable_nonce_len) {
+      /* Publicly invalid. */
+      OPENSSL_PUT_ERROR(SSL, SSL_AEAD_CTX_open, SSL_R_BAD_PACKET_LENGTH);
+      return 0;
+    }
+    memcpy(nonce + nonce_len, in, aead->variable_nonce_len);
+    in += aead->variable_nonce_len;
+    in_len -= aead->variable_nonce_len;
+  } else {
+    assert(aead->variable_nonce_len == 8);
+    memcpy(nonce + nonce_len, seqnum, aead->variable_nonce_len);
+  }
+  nonce_len += aead->variable_nonce_len;
+
+  return EVP_AEAD_CTX_open(&aead->ctx, out, out_len, max_out, nonce, nonce_len,
+                           in, in_len, ad, ad_len);
+}
+
+int SSL_AEAD_CTX_seal(SSL_AEAD_CTX *aead, uint8_t *out, size_t *out_len,
+                      size_t max_out, uint8_t type, uint16_t wire_version,
+                      const uint8_t seqnum[8], const uint8_t *in,
+                      size_t in_len) {
+  if (aead == NULL) {
+    /* Handle the initial NULL cipher. */
+    if (in_len > max_out) {
+      OPENSSL_PUT_ERROR(SSL, SSL_AEAD_CTX_seal, SSL_R_BUFFER_TOO_SMALL);
+      return 0;
+    }
+    memmove(out, in, in_len);
+    *out_len = in_len;
+    return 1;
+  }
+
+  uint8_t ad[13];
+  size_t ad_len = ssl_aead_ctx_get_ad(aead, ad, type, wire_version, seqnum,
+                                      in_len);
+
+  /* Assemble the nonce. */
+  uint8_t nonce[EVP_AEAD_MAX_NONCE_LENGTH];
+  size_t nonce_len = 0;
+  memcpy(nonce, aead->fixed_nonce, aead->fixed_nonce_len);
+  nonce_len += aead->fixed_nonce_len;
+  if (aead->random_variable_nonce) {
+    assert(aead->variable_nonce_included_in_record);
+    if (!RAND_bytes(nonce + nonce_len, aead->variable_nonce_len)) {
+      return 0;
+    }
+  } else {
+    /* When sending we use the sequence number as the variable part of the
+     * nonce. */
+    assert(aead->variable_nonce_len == 8);
+    memcpy(nonce + nonce_len, ad, aead->variable_nonce_len);
+  }
+  nonce_len += aead->variable_nonce_len;
+
+  /* Emit the variable nonce if included in the record. */
+  size_t extra_len = 0;
+  if (aead->variable_nonce_included_in_record) {
+    if (max_out < aead->variable_nonce_len) {
+      OPENSSL_PUT_ERROR(SSL, SSL_AEAD_CTX_seal, SSL_R_BUFFER_TOO_SMALL);
+      return 0;
+    }
+    if (out < in + in_len && in < out + aead->variable_nonce_len) {
+      OPENSSL_PUT_ERROR(SSL, SSL_AEAD_CTX_seal, SSL_R_OUTPUT_ALIASES_INPUT);
+      return 0;
+    }
+    memcpy(out, nonce + aead->fixed_nonce_len, aead->variable_nonce_len);
+    extra_len = aead->variable_nonce_len;
+    out += aead->variable_nonce_len;
+    max_out -= aead->variable_nonce_len;
+  }
+
+  if (!EVP_AEAD_CTX_seal(&aead->ctx, out, out_len, max_out, nonce, nonce_len,
+                         in, in_len, ad, ad_len)) {
+    return 0;
+  }
+  *out_len += extra_len;
+  return 1;
+}
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 79493aa..276d0fd 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -2184,17 +2184,10 @@
 }
 
 void ssl_clear_cipher_ctx(SSL *s) {
-  if (s->aead_read_ctx != NULL) {
-    EVP_AEAD_CTX_cleanup(&s->aead_read_ctx->ctx);
-    OPENSSL_free(s->aead_read_ctx);
-    s->aead_read_ctx = NULL;
-  }
-
-  if (s->aead_write_ctx != NULL) {
-    EVP_AEAD_CTX_cleanup(&s->aead_write_ctx->ctx);
-    OPENSSL_free(s->aead_write_ctx);
-    s->aead_write_ctx = NULL;
-  }
+  SSL_AEAD_CTX_free(s->aead_read_ctx);
+  s->aead_read_ctx = NULL;
+  SSL_AEAD_CTX_free(s->aead_write_ctx);
+  s->aead_write_ctx = NULL;
 }
 
 X509 *SSL_get_certificate(const SSL *s) {
diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c
index ffe16be..63c43b5 100644
--- a/ssl/t1_enc.c
+++ b/ssl/t1_enc.c
@@ -292,116 +292,6 @@
                             SSL3_RANDOM_SIZE);
 }
 
-/* tls1_aead_ctx_init allocates |*aead_ctx|, if needed and returns 1. It
- * returns 0 on malloc error. */
-static int tls1_aead_ctx_init(SSL_AEAD_CTX **aead_ctx) {
-  if (*aead_ctx != NULL) {
-    EVP_AEAD_CTX_cleanup(&(*aead_ctx)->ctx);
-  } else {
-    *aead_ctx = (SSL_AEAD_CTX *)OPENSSL_malloc(sizeof(SSL_AEAD_CTX));
-    if (*aead_ctx == NULL) {
-      OPENSSL_PUT_ERROR(SSL, tls1_aead_ctx_init, ERR_R_MALLOC_FAILURE);
-      return 0;
-    }
-  }
-
-  return 1;
-}
-
-static int tls1_change_cipher_state_aead(SSL *s, char is_read,
-                                         const uint8_t *key, unsigned key_len,
-                                         const uint8_t *iv, unsigned iv_len,
-                                         const uint8_t *mac_secret,
-                                         unsigned mac_secret_len) {
-  const EVP_AEAD *aead = s->s3->tmp.new_aead;
-  SSL_AEAD_CTX *aead_ctx;
-  /* merged_key is used to merge the MAC, cipher, and IV keys for an AEAD which
-   * simulates pre-AEAD cipher suites. */
-  uint8_t merged_key[EVP_AEAD_MAX_KEY_LENGTH];
-
-  if (mac_secret_len > 0) {
-    /* This is a "stateful" AEAD (for compatibility with pre-AEAD cipher
-     * suites). */
-    if (mac_secret_len + key_len + iv_len > sizeof(merged_key)) {
-      OPENSSL_PUT_ERROR(SSL, tls1_change_cipher_state_aead,
-                        ERR_R_INTERNAL_ERROR);
-      return 0;
-    }
-    memcpy(merged_key, mac_secret, mac_secret_len);
-    memcpy(merged_key + mac_secret_len, key, key_len);
-    memcpy(merged_key + mac_secret_len + key_len, iv, iv_len);
-    key = merged_key;
-    key_len += mac_secret_len;
-    key_len += iv_len;
-  }
-
-  if (is_read) {
-    if (!tls1_aead_ctx_init(&s->aead_read_ctx)) {
-      return 0;
-    }
-    aead_ctx = s->aead_read_ctx;
-  } else {
-    if (SSL_IS_DTLS(s) && s->aead_write_ctx != NULL) {
-      /* DTLS renegotiation is unsupported, so a CCS can only switch away from
-       * the NULL cipher. This simplifies renegotiation. */
-      OPENSSL_PUT_ERROR(SSL, tls1_change_cipher_state_aead,
-                        ERR_R_INTERNAL_ERROR);
-      return 0;
-    }
-    if (!tls1_aead_ctx_init(&s->aead_write_ctx)) {
-      return 0;
-    }
-    aead_ctx = s->aead_write_ctx;
-  }
-
-  aead_ctx->cipher = s->session->cipher;
-
-  if (!EVP_AEAD_CTX_init_with_direction(
-          &aead_ctx->ctx, aead, key, key_len, EVP_AEAD_DEFAULT_TAG_LENGTH,
-          is_read ? evp_aead_open : evp_aead_seal)) {
-    OPENSSL_free(aead_ctx);
-    if (is_read) {
-      s->aead_read_ctx = NULL;
-    } else {
-      s->aead_write_ctx = NULL;
-    }
-
-    return 0;
-  }
-
-  if (mac_secret_len == 0) {
-    /* For a real AEAD, the IV is the fixed part of the nonce. */
-    if (iv_len > sizeof(aead_ctx->fixed_nonce)) {
-      OPENSSL_PUT_ERROR(SSL, tls1_change_cipher_state_aead, ERR_R_INTERNAL_ERROR);
-      return 0;
-    }
-
-    memcpy(aead_ctx->fixed_nonce, iv, iv_len);
-    aead_ctx->fixed_nonce_len = iv_len;
-    aead_ctx->variable_nonce_included_in_record =
-      (s->s3->tmp.new_cipher->algorithm2 &
-       SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD) != 0;
-    aead_ctx->random_variable_nonce = 0;
-    aead_ctx->omit_length_in_ad = 0;
-  } else {
-    aead_ctx->fixed_nonce_len = 0;
-    aead_ctx->variable_nonce_included_in_record = 1;
-    aead_ctx->random_variable_nonce = 1;
-    aead_ctx->omit_length_in_ad = 1;
-  }
-  aead_ctx->variable_nonce_len = s->s3->tmp.new_variable_iv_len;
-  aead_ctx->omit_version_in_ad = (s->version == SSL3_VERSION);
-
-  if (aead_ctx->variable_nonce_len + aead_ctx->fixed_nonce_len !=
-      EVP_AEAD_nonce_length(aead)) {
-    OPENSSL_PUT_ERROR(SSL, tls1_change_cipher_state_aead, ERR_R_INTERNAL_ERROR);
-    return 0;
-  }
-  aead_ctx->tag_len = EVP_AEAD_max_overhead(aead);
-
-  return 1;
-}
-
 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. */
@@ -472,8 +362,21 @@
     return 0;
   }
 
-  return tls1_change_cipher_state_aead(s, is_read, key, key_len, iv, iv_len,
-                                       mac_secret, mac_secret_len);
+  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;
+  } else {
+    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);
+    return s->aead_write_ctx != NULL;
+  }
 }
 
 int tls1_setup_key_block(SSL *s) {
@@ -566,153 +469,6 @@
   return 0;
 }
 
-/* tls1_enc encrypts/decrypts the record in |s->wrec| / |s->rrec|,
- * respectively. It returns one on success and zero on failure. */
-int tls1_enc(SSL *s, int send) {
-  SSL3_RECORD *rec;
-  const SSL_AEAD_CTX *aead;
-
-  if (send) {
-    rec = &s->s3->wrec;
-    aead = s->aead_write_ctx;
-  } else {
-    rec = &s->s3->rrec;
-    aead = s->aead_read_ctx;
-  }
-
-  if (aead == NULL) {
-    /* Handle the initial NULL cipher. */
-    memmove(rec->data, rec->input, rec->length);
-    rec->input = rec->data;
-    return 1;
-  }
-
-  uint8_t ad[13], *seq, *in, *out, nonce[EVP_AEAD_MAX_NONCE_LENGTH];
-  unsigned nonce_used;
-  size_t n, ad_len;
-
-  seq = send ? s->s3->write_sequence : s->s3->read_sequence;
-
-  if (SSL_IS_DTLS(s)) {
-    uint8_t dtlsseq[9], *p = dtlsseq;
-
-    s2n(send ? s->d1->w_epoch : s->d1->r_epoch, p);
-    memcpy(p, &seq[2], 6);
-    memcpy(ad, dtlsseq, 8);
-  } else {
-    memcpy(ad, seq, 8);
-    if (!ssl3_record_sequence_update(seq, 8)) {
-      return 0;
-    }
-  }
-
-  ad[8] = rec->type;
-  ad_len = 9;
-  if (!aead->omit_version_in_ad) {
-    ad[ad_len++] = (uint8_t)(s->version >> 8);
-    ad[ad_len++] = (uint8_t)(s->version);
-  }
-
-  if (aead->fixed_nonce_len + aead->variable_nonce_len > sizeof(nonce)) {
-    OPENSSL_PUT_ERROR(SSL, tls1_enc, ERR_R_INTERNAL_ERROR);
-    return 0;
-  }
-
-  memcpy(nonce, aead->fixed_nonce, aead->fixed_nonce_len);
-  nonce_used = aead->fixed_nonce_len;
-
-  if (send) {
-    size_t len = rec->length;
-    size_t eivlen = 0;
-    in = rec->input;
-    out = rec->data;
-
-    uint8_t *variable_nonce = nonce + nonce_used;
-    if (aead->random_variable_nonce) {
-      assert(aead->variable_nonce_included_in_record);
-      if (!RAND_bytes(nonce + nonce_used, aead->variable_nonce_len)) {
-        return 0;
-      }
-    } else {
-      /* When sending we use the sequence number as the variable part of the
-       * nonce. */
-      if (aead->variable_nonce_len != 8) {
-        OPENSSL_PUT_ERROR(SSL, tls1_enc, ERR_R_INTERNAL_ERROR);
-        return 0;
-      }
-      memcpy(nonce + nonce_used, ad, aead->variable_nonce_len);
-    }
-    nonce_used += aead->variable_nonce_len;
-
-    /* in do_ssl3_write, rec->input is moved forward by variable_nonce_len in
-     * order to leave space for the variable nonce. Thus we can copy the
-     * sequence number bytes into place without overwriting any of the
-     * plaintext. */
-    if (aead->variable_nonce_included_in_record) {
-      memcpy(out, variable_nonce, aead->variable_nonce_len);
-      len -= aead->variable_nonce_len;
-      eivlen = aead->variable_nonce_len;
-    }
-
-    if (!aead->omit_length_in_ad) {
-      ad[ad_len++] = len >> 8;
-      ad[ad_len++] = len & 0xff;
-    }
-
-    if (!EVP_AEAD_CTX_seal(&aead->ctx, out + eivlen, &n, len + aead->tag_len,
-                           nonce, nonce_used, in + eivlen, len, ad, ad_len)) {
-      return 0;
-    }
-
-    if (aead->variable_nonce_included_in_record) {
-      n += aead->variable_nonce_len;
-    }
-  } else {
-    /* receive */
-    size_t len = rec->length;
-
-    if (rec->data != rec->input) {
-      OPENSSL_PUT_ERROR(SSL, tls1_enc, ERR_R_INTERNAL_ERROR);
-      return 0;
-    }
-    out = in = rec->input;
-
-    if (len < aead->variable_nonce_len) {
-      return 0;
-    }
-    memcpy(nonce + nonce_used,
-           aead->variable_nonce_included_in_record ? in : ad,
-           aead->variable_nonce_len);
-    nonce_used += aead->variable_nonce_len;
-
-    if (aead->variable_nonce_included_in_record) {
-      in += aead->variable_nonce_len;
-      len -= aead->variable_nonce_len;
-      out += aead->variable_nonce_len;
-    }
-
-    if (!aead->omit_length_in_ad) {
-      if (len < aead->tag_len) {
-        return 0;
-      }
-      size_t plaintext_len = len - aead->tag_len;
-
-      ad[ad_len++] = plaintext_len >> 8;
-      ad[ad_len++] = plaintext_len & 0xff;
-    }
-
-    if (!EVP_AEAD_CTX_open(&aead->ctx, out, &n, rec->length, nonce, nonce_used, in,
-                           len, ad, ad_len)) {
-      return 0;
-    }
-
-    rec->data = rec->input = out;
-  }
-
-  rec->length = n;
-  return 1;
-}
-
 int tls1_cert_verify_mac(SSL *s, int md_nid, uint8_t *out) {
   unsigned int ret;
   EVP_MD_CTX ctx, *d = NULL;
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index 7899561..4b29de5 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -129,7 +129,6 @@
 static int ssl_check_serverhello_tlsext(SSL *s);
 
 const SSL3_ENC_METHOD TLSv1_enc_data = {
-    tls1_enc,
     tls1_prf,
     tls1_setup_key_block,
     tls1_generate_master_secret,
@@ -144,7 +143,6 @@
 };
 
 const SSL3_ENC_METHOD TLSv1_1_enc_data = {
-    tls1_enc,
     tls1_prf,
     tls1_setup_key_block,
     tls1_generate_master_secret,
@@ -159,7 +157,6 @@
 };
 
 const SSL3_ENC_METHOD TLSv1_2_enc_data = {
-    tls1_enc,
     tls1_prf,
     tls1_setup_key_block,
     tls1_generate_master_secret,