external/boringssl: Sync to ba8f1864c15ec938ce0851f416663511c89f454a.

This includes the following changes:

https://boringssl.googlesource.com/boringssl/+log/b1cbe1979008debd0541621584b00e010d9935dd..ba8f1864c15ec938ce0851f416663511c89f454a

Test: BoringSSL CTS Presubmits
Change-Id: I58da2508fd608988d3d14d7219a104da7ed0f4b7
diff --git a/BORINGSSL_REVISION b/BORINGSSL_REVISION
index 7a87d55..a126718 100644
--- a/BORINGSSL_REVISION
+++ b/BORINGSSL_REVISION
@@ -1 +1 @@
-b1cbe1979008debd0541621584b00e010d9935dd
+ba8f1864c15ec938ce0851f416663511c89f454a
diff --git a/ios-arm/crypto/fipsmodule/aes-armv4.S b/ios-arm/crypto/fipsmodule/aes-armv4.S
index 2e6c7ef..516c89b 100644
--- a/ios-arm/crypto/fipsmodule/aes-armv4.S
+++ b/ios-arm/crypto/fipsmodule/aes-armv4.S
@@ -171,7 +171,7 @@
 #ifndef	__thumb2__
 	sub	r3,pc,#8		@ _asm_AES_encrypt
 #else
-	adr	r3,_asm_AES_encrypt
+	adr	r3,.
 #endif
 	stmdb	sp!,{r1,r4-r12,lr}
 #ifdef	__APPLE__
@@ -426,7 +426,7 @@
 #ifndef	__thumb2__
 	sub	r3,pc,#8		@ _asm_AES_set_encrypt_key
 #else
-	adr	r3,_asm_AES_set_encrypt_key
+	adr	r3,.
 #endif
 	teq	r0,#0
 #ifdef	__thumb2__
@@ -956,7 +956,7 @@
 #ifndef	__thumb2__
 	sub	r3,pc,#8		@ _asm_AES_decrypt
 #else
-	adr	r3,_asm_AES_decrypt
+	adr	r3,.
 #endif
 	stmdb	sp!,{r1,r4-r12,lr}
 #ifdef	__APPLE__
diff --git a/ios-arm/crypto/fipsmodule/bsaes-armv7.S b/ios-arm/crypto/fipsmodule/bsaes-armv7.S
index 1cf914c..5e2ebf0 100644
--- a/ios-arm/crypto/fipsmodule/bsaes-armv7.S
+++ b/ios-arm/crypto/fipsmodule/bsaes-armv7.S
@@ -91,7 +91,7 @@
 #endif
 .align	4
 _bsaes_decrypt8:
-	adr	r6,_bsaes_decrypt8
+	adr	r6,.
 	vldmia	r4!, {q9}		@ round 0 key
 #ifdef	__APPLE__
 	adr	r6,LM0ISR
@@ -584,7 +584,7 @@
 #endif
 .align	4
 _bsaes_encrypt8:
-	adr	r6,_bsaes_encrypt8
+	adr	r6,.
 	vldmia	r4!, {q9}		@ round 0 key
 #ifdef	__APPLE__
 	adr	r6,LM0SR
@@ -1021,7 +1021,7 @@
 #endif
 .align	4
 _bsaes_key_convert:
-	adr	r6,_bsaes_key_convert
+	adr	r6,.
 	vld1.8	{q7},  [r4]!		@ load round 0 key
 #ifdef	__APPLE__
 	adr	r6,LM0
diff --git a/linux-arm/crypto/fipsmodule/aes-armv4.S b/linux-arm/crypto/fipsmodule/aes-armv4.S
index f11bc7e..d401fc7 100644
--- a/linux-arm/crypto/fipsmodule/aes-armv4.S
+++ b/linux-arm/crypto/fipsmodule/aes-armv4.S
@@ -170,7 +170,7 @@
 #ifndef	__thumb2__
 	sub	r3,pc,#8		@ asm_AES_encrypt
 #else
-	adr	r3,asm_AES_encrypt
+	adr	r3,.
 #endif
 	stmdb	sp!,{r1,r4-r12,lr}
 #ifdef	__APPLE__
@@ -421,7 +421,7 @@
 #ifndef	__thumb2__
 	sub	r3,pc,#8		@ asm_AES_set_encrypt_key
 #else
-	adr	r3,asm_AES_set_encrypt_key
+	adr	r3,.
 #endif
 	teq	r0,#0
 #ifdef	__thumb2__
@@ -945,7 +945,7 @@
 #ifndef	__thumb2__
 	sub	r3,pc,#8		@ asm_AES_decrypt
 #else
-	adr	r3,asm_AES_decrypt
+	adr	r3,.
 #endif
 	stmdb	sp!,{r1,r4-r12,lr}
 #ifdef	__APPLE__
diff --git a/linux-arm/crypto/fipsmodule/bsaes-armv7.S b/linux-arm/crypto/fipsmodule/bsaes-armv7.S
index 0b1a9f7..f9c6de7 100644
--- a/linux-arm/crypto/fipsmodule/bsaes-armv7.S
+++ b/linux-arm/crypto/fipsmodule/bsaes-armv7.S
@@ -90,7 +90,7 @@
 .type	_bsaes_decrypt8,%function
 .align	4
 _bsaes_decrypt8:
-	adr	r6,_bsaes_decrypt8
+	adr	r6,.
 	vldmia	r4!, {q9}		@ round 0 key
 #ifdef	__APPLE__
 	adr	r6,.LM0ISR
@@ -581,7 +581,7 @@
 .type	_bsaes_encrypt8,%function
 .align	4
 _bsaes_encrypt8:
-	adr	r6,_bsaes_encrypt8
+	adr	r6,.
 	vldmia	r4!, {q9}		@ round 0 key
 #ifdef	__APPLE__
 	adr	r6,.LM0SR
@@ -1016,7 +1016,7 @@
 .type	_bsaes_key_convert,%function
 .align	4
 _bsaes_key_convert:
-	adr	r6,_bsaes_key_convert
+	adr	r6,.
 	vld1.8	{q7},  [r4]!		@ load round 0 key
 #ifdef	__APPLE__
 	adr	r6,.LM0
diff --git a/linux-x86_64/crypto/fipsmodule/aesni-gcm-x86_64.S b/linux-x86_64/crypto/fipsmodule/aesni-gcm-x86_64.S
index 62c6cd6..e7b4c48 100644
--- a/linux-x86_64/crypto/fipsmodule/aesni-gcm-x86_64.S
+++ b/linux-x86_64/crypto/fipsmodule/aesni-gcm-x86_64.S
@@ -4,6 +4,7 @@
 .type	_aesni_ctr32_ghash_6x,@function
 .align	32
 _aesni_ctr32_ghash_6x:
+.cfi_startproc	
 	vmovdqu	32(%r11),%xmm2
 	subq	$6,%rdx
 	vpxor	%xmm4,%xmm4,%xmm4
@@ -328,12 +329,14 @@
 	vpxor	%xmm4,%xmm8,%xmm8
 
 	.byte	0xf3,0xc3
+.cfi_endproc	
 .size	_aesni_ctr32_ghash_6x,.-_aesni_ctr32_ghash_6x
 .globl	aesni_gcm_decrypt
 .hidden aesni_gcm_decrypt
 .type	aesni_gcm_decrypt,@function
 .align	32
 aesni_gcm_decrypt:
+.cfi_startproc	
 	xorq	%r10,%r10
 
 
@@ -342,12 +345,19 @@
 	jb	.Lgcm_dec_abort
 
 	leaq	(%rsp),%rax
+.cfi_def_cfa_register	%rax
 	pushq	%rbx
+.cfi_offset	%rbx,-16
 	pushq	%rbp
+.cfi_offset	%rbp,-24
 	pushq	%r12
+.cfi_offset	%r12,-32
 	pushq	%r13
+.cfi_offset	%r13,-40
 	pushq	%r14
+.cfi_offset	%r14,-48
 	pushq	%r15
+.cfi_offset	%r15,-56
 	vzeroupper
 
 	vmovdqu	(%r8),%xmm1
@@ -417,19 +427,28 @@
 
 	vzeroupper
 	movq	-48(%rax),%r15
+.cfi_restore	%r15
 	movq	-40(%rax),%r14
+.cfi_restore	%r14
 	movq	-32(%rax),%r13
+.cfi_restore	%r13
 	movq	-24(%rax),%r12
+.cfi_restore	%r12
 	movq	-16(%rax),%rbp
+.cfi_restore	%rbp
 	movq	-8(%rax),%rbx
+.cfi_restore	%rbx
 	leaq	(%rax),%rsp
+.cfi_def_cfa_register	%rsp
 .Lgcm_dec_abort:
 	movq	%r10,%rax
 	.byte	0xf3,0xc3
+.cfi_endproc	
 .size	aesni_gcm_decrypt,.-aesni_gcm_decrypt
 .type	_aesni_ctr32_6x,@function
 .align	32
 _aesni_ctr32_6x:
+.cfi_startproc	
 	vmovdqu	0-128(%rcx),%xmm4
 	vmovdqu	32(%r11),%xmm2
 	leaq	-1(%rbp),%r13
@@ -516,6 +535,7 @@
 	vpshufb	%xmm0,%xmm1,%xmm1
 	vpxor	%xmm4,%xmm14,%xmm14
 	jmp	.Loop_ctr32
+.cfi_endproc	
 .size	_aesni_ctr32_6x,.-_aesni_ctr32_6x
 
 .globl	aesni_gcm_encrypt
@@ -523,6 +543,7 @@
 .type	aesni_gcm_encrypt,@function
 .align	32
 aesni_gcm_encrypt:
+.cfi_startproc	
 	xorq	%r10,%r10
 
 
@@ -532,12 +553,19 @@
 	jb	.Lgcm_enc_abort
 
 	leaq	(%rsp),%rax
+.cfi_def_cfa_register	%rax
 	pushq	%rbx
+.cfi_offset	%rbx,-16
 	pushq	%rbp
+.cfi_offset	%rbp,-24
 	pushq	%r12
+.cfi_offset	%r12,-32
 	pushq	%r13
+.cfi_offset	%r13,-40
 	pushq	%r14
+.cfi_offset	%r14,-48
 	pushq	%r15
+.cfi_offset	%r15,-56
 	vzeroupper
 
 	vmovdqu	(%r8),%xmm1
@@ -772,15 +800,23 @@
 
 	vzeroupper
 	movq	-48(%rax),%r15
+.cfi_restore	%r15
 	movq	-40(%rax),%r14
+.cfi_restore	%r14
 	movq	-32(%rax),%r13
+.cfi_restore	%r13
 	movq	-24(%rax),%r12
+.cfi_restore	%r12
 	movq	-16(%rax),%rbp
+.cfi_restore	%rbp
 	movq	-8(%rax),%rbx
+.cfi_restore	%rbx
 	leaq	(%rax),%rsp
+.cfi_def_cfa_register	%rsp
 .Lgcm_enc_abort:
 	movq	%r10,%rax
 	.byte	0xf3,0xc3
+.cfi_endproc	
 .size	aesni_gcm_encrypt,.-aesni_gcm_encrypt
 .align	64
 .Lbswap_mask:
diff --git a/mac-x86_64/crypto/fipsmodule/aesni-gcm-x86_64.S b/mac-x86_64/crypto/fipsmodule/aesni-gcm-x86_64.S
index f185d0c..2513904 100644
--- a/mac-x86_64/crypto/fipsmodule/aesni-gcm-x86_64.S
+++ b/mac-x86_64/crypto/fipsmodule/aesni-gcm-x86_64.S
@@ -4,6 +4,7 @@
 
 .p2align	5
 _aesni_ctr32_ghash_6x:
+
 	vmovdqu	32(%r11),%xmm2
 	subq	$6,%rdx
 	vpxor	%xmm4,%xmm4,%xmm4
@@ -329,11 +330,13 @@
 
 	.byte	0xf3,0xc3
 
+
 .globl	_aesni_gcm_decrypt
 .private_extern _aesni_gcm_decrypt
 
 .p2align	5
 _aesni_gcm_decrypt:
+
 	xorq	%r10,%r10
 
 
@@ -342,12 +345,19 @@
 	jb	L$gcm_dec_abort
 
 	leaq	(%rsp),%rax
+
 	pushq	%rbx
+
 	pushq	%rbp
+
 	pushq	%r12
+
 	pushq	%r13
+
 	pushq	%r14
+
 	pushq	%r15
+
 	vzeroupper
 
 	vmovdqu	(%r8),%xmm1
@@ -417,19 +427,28 @@
 
 	vzeroupper
 	movq	-48(%rax),%r15
+
 	movq	-40(%rax),%r14
+
 	movq	-32(%rax),%r13
+
 	movq	-24(%rax),%r12
+
 	movq	-16(%rax),%rbp
+
 	movq	-8(%rax),%rbx
+
 	leaq	(%rax),%rsp
+
 L$gcm_dec_abort:
 	movq	%r10,%rax
 	.byte	0xf3,0xc3
 
 
+
 .p2align	5
 _aesni_ctr32_6x:
+
 	vmovdqu	0-128(%rcx),%xmm4
 	vmovdqu	32(%r11),%xmm2
 	leaq	-1(%rbp),%r13
@@ -518,11 +537,13 @@
 	jmp	L$oop_ctr32
 
 
+
 .globl	_aesni_gcm_encrypt
 .private_extern _aesni_gcm_encrypt
 
 .p2align	5
 _aesni_gcm_encrypt:
+
 	xorq	%r10,%r10
 
 
@@ -532,12 +553,19 @@
 	jb	L$gcm_enc_abort
 
 	leaq	(%rsp),%rax
+
 	pushq	%rbx
+
 	pushq	%rbp
+
 	pushq	%r12
+
 	pushq	%r13
+
 	pushq	%r14
+
 	pushq	%r15
+
 	vzeroupper
 
 	vmovdqu	(%r8),%xmm1
@@ -772,16 +800,24 @@
 
 	vzeroupper
 	movq	-48(%rax),%r15
+
 	movq	-40(%rax),%r14
+
 	movq	-32(%rax),%r13
+
 	movq	-24(%rax),%r12
+
 	movq	-16(%rax),%rbp
+
 	movq	-8(%rax),%rbx
+
 	leaq	(%rax),%rsp
+
 L$gcm_enc_abort:
 	movq	%r10,%rax
 	.byte	0xf3,0xc3
 
+
 .p2align	6
 L$bswap_mask:
 .byte	15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0
diff --git a/src/crypto/asn1/a_i2d_fp.c b/src/crypto/asn1/a_i2d_fp.c
index 486207e..7b76d0c 100644
--- a/src/crypto/asn1/a_i2d_fp.c
+++ b/src/crypto/asn1/a_i2d_fp.c
@@ -81,6 +81,9 @@
     int i, j = 0, n, ret = 1;
 
     n = i2d(x, NULL);
+    if (n <= 0)
+        return 0;
+
     b = (char *)OPENSSL_malloc(n);
     if (b == NULL) {
         OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
diff --git a/src/crypto/fipsmodule/aes/asm/aes-armv4.pl b/src/crypto/fipsmodule/aes/asm/aes-armv4.pl
index 06f009c..c34d3dc 100644
--- a/src/crypto/fipsmodule/aes/asm/aes-armv4.pl
+++ b/src/crypto/fipsmodule/aes/asm/aes-armv4.pl
@@ -200,7 +200,7 @@
 #ifndef	__thumb2__
 	sub	r3,pc,#8		@ asm_AES_encrypt
 #else
-	adr	r3,asm_AES_encrypt
+	adr	r3,.
 #endif
 	stmdb   sp!,{r1,r4-r12,lr}
 #ifdef	__APPLE__
@@ -450,7 +450,7 @@
 #ifndef	__thumb2__
 	sub	r3,pc,#8		@ asm_AES_set_encrypt_key
 #else
-	adr	r3,asm_AES_set_encrypt_key
+	adr	r3,.
 #endif
 	teq	r0,#0
 #ifdef	__thumb2__
@@ -976,7 +976,7 @@
 #ifndef	__thumb2__
 	sub	r3,pc,#8		@ asm_AES_decrypt
 #else
-	adr	r3,asm_AES_decrypt
+	adr	r3,.
 #endif
 	stmdb   sp!,{r1,r4-r12,lr}
 #ifdef	__APPLE__
diff --git a/src/crypto/fipsmodule/aes/asm/bsaes-armv7.pl b/src/crypto/fipsmodule/aes/asm/bsaes-armv7.pl
index 895a269..1ff890a 100644
--- a/src/crypto/fipsmodule/aes/asm/bsaes-armv7.pl
+++ b/src/crypto/fipsmodule/aes/asm/bsaes-armv7.pl
@@ -744,7 +744,7 @@
 .type	_bsaes_decrypt8,%function
 .align	4
 _bsaes_decrypt8:
-	adr	$const,_bsaes_decrypt8
+	adr	$const,.
 	vldmia	$key!, {@XMM[9]}		@ round 0 key
 #ifdef	__APPLE__
 	adr	$const,.LM0ISR
@@ -843,7 +843,7 @@
 .type	_bsaes_encrypt8,%function
 .align	4
 _bsaes_encrypt8:
-	adr	$const,_bsaes_encrypt8
+	adr	$const,.
 	vldmia	$key!, {@XMM[9]}		@ round 0 key
 #ifdef	__APPLE__
 	adr	$const,.LM0SR
@@ -951,7 +951,7 @@
 .type	_bsaes_key_convert,%function
 .align	4
 _bsaes_key_convert:
-	adr	$const,_bsaes_key_convert
+	adr	$const,.
 	vld1.8	{@XMM[7]},  [$inp]!		@ load round 0 key
 #ifdef	__APPLE__
 	adr	$const,.LM0
diff --git a/src/crypto/fipsmodule/bn/asm/x86_64-gcc.c b/src/crypto/fipsmodule/bn/asm/x86_64-gcc.c
index bfd770f..bcf12eb 100644
--- a/src/crypto/fipsmodule/bn/asm/x86_64-gcc.c
+++ b/src/crypto/fipsmodule/bn/asm/x86_64-gcc.c
@@ -280,7 +280,7 @@
 
 #define sqr_add_c2(a, i, j, c0, c1, c2) mul_add_c2((a)[i], (a)[j], c0, c1, c2)
 
-void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b) {
+void bn_mul_comba8(BN_ULONG r[16], BN_ULONG a[8], BN_ULONG b[8]) {
   BN_ULONG c1, c2, c3;
 
   c1 = 0;
@@ -382,7 +382,7 @@
   r[15] = c1;
 }
 
-void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b) {
+void bn_mul_comba4(BN_ULONG r[8], BN_ULONG a[4], BN_ULONG b[4]) {
   BN_ULONG c1, c2, c3;
 
   c1 = 0;
@@ -420,7 +420,7 @@
   r[7] = c2;
 }
 
-void bn_sqr_comba8(BN_ULONG *r, const BN_ULONG *a) {
+void bn_sqr_comba8(BN_ULONG r[16], const BN_ULONG a[8]) {
   BN_ULONG c1, c2, c3;
 
   c1 = 0;
@@ -494,7 +494,7 @@
   r[15] = c1;
 }
 
-void bn_sqr_comba4(BN_ULONG *r, const BN_ULONG *a) {
+void bn_sqr_comba4(BN_ULONG r[8], const BN_ULONG a[4]) {
   BN_ULONG c1, c2, c3;
 
   c1 = 0;
diff --git a/src/crypto/fipsmodule/bn/div.c b/src/crypto/fipsmodule/bn/div.c
index 0b8b9b9..c92eab3 100644
--- a/src/crypto/fipsmodule/bn/div.c
+++ b/src/crypto/fipsmodule/bn/div.c
@@ -178,28 +178,33 @@
 #endif
 }
 
-// BN_div computes  dv := num / divisor,  rounding towards
-// zero, and sets up rm  such that  dv*divisor + rm = num  holds.
+// BN_div computes "quotient := numerator / divisor", rounding towards zero,
+// and sets up |rem| such that "quotient * divisor + rem = numerator" holds.
+//
 // Thus:
-//     dv->neg == num->neg ^ divisor->neg  (unless the result is zero)
-//     rm->neg == num->neg                 (unless the remainder is zero)
-// If 'dv' or 'rm' is NULL, the respective value is not returned.
+//
+//     quotient->neg == numerator->neg ^ divisor->neg
+//        (unless the result is zero)
+//     rem->neg == numerator->neg
+//        (unless the remainder is zero)
+//
+// If |quotient| or |rem| is NULL, the respective value is not returned.
 //
 // This was specifically designed to contain fewer branches that may leak
 // sensitive information; see "New Branch Prediction Vulnerabilities in OpenSSL
 // and Necessary Software Countermeasures" by Onur Acıçmez, Shay Gueron, and
 // Jean-Pierre Seifert.
-int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor,
-           BN_CTX *ctx) {
-  int norm_shift, i, loop;
-  BIGNUM *tmp, wnum, *snum, *sdiv, *res;
+int BN_div(BIGNUM *quotient, BIGNUM *rem, const BIGNUM *numerator,
+           const BIGNUM *divisor, BN_CTX *ctx) {
+  int norm_shift, loop;
+  BIGNUM wnum;
   BN_ULONG *resp, *wnump;
   BN_ULONG d0, d1;
   int num_n, div_n;
 
   // Invalid zero-padding would have particularly bad consequences
   // so don't just rely on bn_check_top() here
-  if ((num->top > 0 && num->d[num->top - 1] == 0) ||
+  if ((numerator->top > 0 && numerator->d[numerator->top - 1] == 0) ||
       (divisor->top > 0 && divisor->d[divisor->top - 1] == 0)) {
     OPENSSL_PUT_ERROR(BN, BN_R_NOT_INITIALIZED);
     return 0;
@@ -211,26 +216,27 @@
   }
 
   BN_CTX_start(ctx);
-  tmp = BN_CTX_get(ctx);
-  snum = BN_CTX_get(ctx);
-  sdiv = BN_CTX_get(ctx);
-  if (dv == NULL) {
+  BIGNUM *tmp = BN_CTX_get(ctx);
+  BIGNUM *snum = BN_CTX_get(ctx);
+  BIGNUM *sdiv = BN_CTX_get(ctx);
+  BIGNUM *res = NULL;
+  if (quotient == NULL) {
     res = BN_CTX_get(ctx);
   } else {
-    res = dv;
+    res = quotient;
   }
-  if (sdiv == NULL || res == NULL || tmp == NULL || snum == NULL) {
+  if (sdiv == NULL || res == NULL) {
     goto err;
   }
 
   // First we normalise the numbers
-  norm_shift = BN_BITS2 - ((BN_num_bits(divisor)) % BN_BITS2);
-  if (!(BN_lshift(sdiv, divisor, norm_shift))) {
+  norm_shift = BN_BITS2 - (BN_num_bits(divisor) % BN_BITS2);
+  if (!BN_lshift(sdiv, divisor, norm_shift)) {
     goto err;
   }
   sdiv->neg = 0;
   norm_shift += BN_BITS2;
-  if (!(BN_lshift(snum, num, norm_shift))) {
+  if (!BN_lshift(snum, numerator, norm_shift)) {
     goto err;
   }
   snum->neg = 0;
@@ -242,7 +248,7 @@
     if (!bn_wexpand(snum, sdiv->top + 2)) {
       goto err;
     }
-    for (i = snum->top; i < sdiv->top + 2; i++) {
+    for (int i = snum->top; i < sdiv->top + 2; i++) {
       snum->d[i] = 0;
     }
     snum->top = sdiv->top + 2;
@@ -275,15 +281,15 @@
   wnump = &(snum->d[num_n - 1]);
 
   // Setup to 'res'
-  res->neg = (num->neg ^ divisor->neg);
-  if (!bn_wexpand(res, (loop + 1))) {
+  res->neg = (numerator->neg ^ divisor->neg);
+  if (!bn_wexpand(res, loop + 1)) {
     goto err;
   }
   res->top = loop - 1;
   resp = &(res->d[loop - 1]);
 
   // space for temp
-  if (!bn_wexpand(tmp, (div_n + 1))) {
+  if (!bn_wexpand(tmp, div_n + 1)) {
     goto err;
   }
 
@@ -295,11 +301,11 @@
     resp--;
   }
 
-  for (i = 0; i < loop - 1; i++, wnump--, resp--) {
+  for (int i = 0; i < loop - 1; i++, wnump--, resp--) {
     BN_ULONG q, l0;
     // the first part of the loop uses the top two words of snum and sdiv to
     // calculate a BN_ULONG q such that | wnum - sdiv * q | < sdiv
-    BN_ULONG n0, n1, rem = 0;
+    BN_ULONG n0, n1, rm = 0;
 
     n0 = wnump[0];
     n1 = wnump[-1];
@@ -307,18 +313,18 @@
       q = BN_MASK2;
     } else {
       // n0 < d0
-      bn_div_rem_words(&q, &rem, n0, n1, d0);
+      bn_div_rem_words(&q, &rm, n0, n1, d0);
 
 #ifdef BN_ULLONG
       BN_ULLONG t2 = (BN_ULLONG)d1 * q;
       for (;;) {
-        if (t2 <= ((((BN_ULLONG)rem) << BN_BITS2) | wnump[-2])) {
+        if (t2 <= ((((BN_ULLONG)rm) << BN_BITS2) | wnump[-2])) {
           break;
         }
         q--;
-        rem += d0;
-        if (rem < d0) {
-          break;  // don't let rem overflow
+        rm += d0;
+        if (rm < d0) {
+          break;  // don't let rm overflow
         }
         t2 -= d1;
       }
@@ -326,13 +332,14 @@
       BN_ULONG t2l, t2h;
       BN_UMULT_LOHI(t2l, t2h, d1, q);
       for (;;) {
-        if ((t2h < rem) || ((t2h == rem) && (t2l <= wnump[-2]))) {
+        if (t2h < rm ||
+            (t2h == rm && t2l <= wnump[-2])) {
           break;
         }
         q--;
-        rem += d0;
-        if (rem < d0) {
-          break;  // don't let rem overflow
+        rm += d0;
+        if (rm < d0) {
+          break;  // don't let rm overflow
         }
         if (t2l < d1) {
           t2h--;
@@ -363,18 +370,21 @@
     // store part of the result
     *resp = q;
   }
+
   bn_correct_top(snum);
-  if (rm != NULL) {
-    // Keep a copy of the neg flag in num because if rm==num
-    // BN_rshift() will overwrite it.
-    int neg = num->neg;
-    if (!BN_rshift(rm, snum, norm_shift)) {
+
+  if (rem != NULL) {
+    // Keep a copy of the neg flag in numerator because if |rem| == |numerator|
+    // |BN_rshift| will overwrite it.
+    int neg = numerator->neg;
+    if (!BN_rshift(rem, snum, norm_shift)) {
       goto err;
     }
-    if (!BN_is_zero(rm)) {
-      rm->neg = neg;
+    if (!BN_is_zero(rem)) {
+      rem->neg = neg;
     }
   }
+
   bn_correct_top(res);
   BN_CTX_end(ctx);
   return 1;
diff --git a/src/crypto/fipsmodule/bn/exponentiation.c b/src/crypto/fipsmodule/bn/exponentiation.c
index e2dfb34..2d40e8f 100644
--- a/src/crypto/fipsmodule/bn/exponentiation.c
+++ b/src/crypto/fipsmodule/bn/exponentiation.c
@@ -188,9 +188,6 @@
   return ret;
 }
 
-// maximum precomputation table size for *variable* sliding windows
-#define TABLE_SIZE 32
-
 typedef struct bn_recp_ctx_st {
   BIGNUM N;   // the divisor
   BIGNUM Nr;  // the reciprocal
@@ -393,8 +390,8 @@
   return ret;
 }
 
-// BN_window_bits_for_exponent_size -- macro for sliding window mod_exp
-// functions
+// BN_window_bits_for_exponent_size returns sliding window size for mod_exp with
+// a |b| bit exponent.
 //
 // For window size 'w' (w >= 2) and a random 'b' bits exponent, the number of
 // multiplications is a constant plus on average
@@ -416,11 +413,26 @@
 //
 // (with draws in between).  Very small exponents are often selected
 // with low Hamming weight, so we use  w = 1  for b <= 23.
-#define BN_window_bits_for_exponent_size(b) \
-		((b) > 671 ? 6 : \
-		 (b) > 239 ? 5 : \
-		 (b) >  79 ? 4 : \
-		 (b) >  23 ? 3 : 1)
+static int BN_window_bits_for_exponent_size(int b) {
+  if (b > 671) {
+    return 6;
+  }
+  if (b > 239) {
+    return 5;
+  }
+  if (b > 79) {
+    return 4;
+  }
+  if (b > 23) {
+    return 3;
+  }
+  return 1;
+}
+
+// TABLE_SIZE is the maximum precomputation table size for *variable* sliding
+// windows. This must be 2^(max_window - 1), where max_window is the largest
+// value returned from |BN_window_bits_for_exponent_size|.
+#define TABLE_SIZE 32
 
 static int mod_exp_recp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
                         const BIGNUM *m, BN_CTX *ctx) {
@@ -501,7 +513,7 @@
     int wvalue;  // The 'value' of the window
     int wend;  // The bottom bit of the window
 
-    if (BN_is_bit_set(p, wstart) == 0) {
+    if (!BN_is_bit_set(p, wstart)) {
       if (!start) {
         if (!BN_mod_mul_reciprocal(r, r, r, &recp, ctx)) {
           goto err;
@@ -573,19 +585,11 @@
 
 int BN_mod_exp_mont(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
                     const BIGNUM *m, BN_CTX *ctx, const BN_MONT_CTX *mont) {
-  int i, j, bits, ret = 0, wstart, window;
-  int start = 1;
-  BIGNUM *d, *r;
-  const BIGNUM *aa;
-  // Table of variables obtained from 'ctx'
-  BIGNUM *val[TABLE_SIZE];
-  BN_MONT_CTX *new_mont = NULL;
-
   if (!BN_is_odd(m)) {
     OPENSSL_PUT_ERROR(BN, BN_R_CALLED_WITH_EVEN_MODULUS);
     return 0;
   }
-  bits = BN_num_bits(p);
+  int bits = BN_num_bits(p);
   if (bits == 0) {
     // x**0 mod 1 is still zero.
     if (BN_is_one(m)) {
@@ -595,9 +599,13 @@
     return BN_one(rr);
   }
 
+  int ret = 0;
+  BIGNUM *val[TABLE_SIZE];
+  BN_MONT_CTX *new_mont = NULL;
+
   BN_CTX_start(ctx);
-  d = BN_CTX_get(ctx);
-  r = BN_CTX_get(ctx);
+  BIGNUM *d = BN_CTX_get(ctx);
+  BIGNUM *r = BN_CTX_get(ctx);
   val[0] = BN_CTX_get(ctx);
   if (!d || !r || !val[0]) {
     goto err;
@@ -612,6 +620,7 @@
     mont = new_mont;
   }
 
+  const BIGNUM *aa;
   if (a->neg || BN_ucmp(a, m) >= 0) {
     if (!BN_nnmod(val[0], a, m, ctx)) {
       goto err;
@@ -626,53 +635,52 @@
     ret = 1;
     goto err;
   }
-  if (!BN_to_montgomery(val[0], aa, mont, ctx)) {
-    goto err;  // 1
-  }
 
-  window = BN_window_bits_for_exponent_size(bits);
+  // We exponentiate by looking at sliding windows of the exponent and
+  // precomputing powers of |aa|. Windows may be shifted so they always end on a
+  // set bit, so only precompute odd powers. We compute val[i] = aa^(2*i + 1)
+  // for i = 0 to 2^(window-1), all in Montgomery form.
+  int window = BN_window_bits_for_exponent_size(bits);
+  if (!BN_to_montgomery(val[0], aa, mont, ctx)) {
+    goto err;
+  }
   if (window > 1) {
     if (!BN_mod_mul_montgomery(d, val[0], val[0], mont, ctx)) {
-      goto err;  // 2
+      goto err;
     }
-    j = 1 << (window - 1);
-    for (i = 1; i < j; i++) {
-      if (((val[i] = BN_CTX_get(ctx)) == NULL) ||
+    for (int i = 1; i < 1 << (window - 1); i++) {
+      val[i] = BN_CTX_get(ctx);
+      if (val[i] == NULL ||
           !BN_mod_mul_montgomery(val[i], val[i - 1], d, mont, ctx)) {
         goto err;
       }
     }
   }
 
-  start = 1;  // This is used to avoid multiplication etc
-              // when there is only the value '1' in the
-              // buffer.
-  wstart = bits - 1;  // The top bit of the window
-
-  j = m->top;  // borrow j
-  if (m->d[j - 1] & (((BN_ULONG)1) << (BN_BITS2 - 1))) {
-    if (!bn_wexpand(r, j)) {
+  // Set |r| to one in Montgomery form. If the high bit of |m| is set, |m| is
+  // close to R and we subtract rather than perform Montgomery reduction.
+  if (m->d[m->top - 1] & (((BN_ULONG)1) << (BN_BITS2 - 1))) {
+    if (!bn_wexpand(r, m->top)) {
       goto err;
     }
-    // 2^(top*BN_BITS2) - m
+    // r = 2^(top*BN_BITS2) - m
     r->d[0] = 0 - m->d[0];
-    for (i = 1; i < j; i++) {
+    for (int i = 1; i < m->top; i++) {
       r->d[i] = ~m->d[i];
     }
-    r->top = j;
-    // Upper words will be zero if the corresponding words of 'm'
-    // were 0xfff[...], so decrement r->top accordingly.
+    r->top = m->top;
+    // The upper words will be zero if the corresponding words of |m| were
+    // 0xfff[...], so call |bn_correct_top|.
     bn_correct_top(r);
   } else if (!BN_to_montgomery(r, BN_value_one(), mont, ctx)) {
     goto err;
   }
 
+  int r_is_one = 1;
+  int wstart = bits - 1;  // The top bit of the window.
   for (;;) {
-    int wvalue;  // The 'value' of the window
-    int wend;  // The bottom bit of the window
-
-    if (BN_is_bit_set(p, wstart) == 0) {
-      if (!start && !BN_mod_mul_montgomery(r, r, r, mont, ctx)) {
+    if (!BN_is_bit_set(p, wstart)) {
+      if (!r_is_one && !BN_mod_mul_montgomery(r, r, r, mont, ctx)) {
         goto err;
       }
       if (wstart == 0) {
@@ -682,44 +690,37 @@
       continue;
     }
 
-    // We now have wstart on a 'set' bit, we now need to work out how bit a
-    // window to do.  To do this we need to scan forward until the last set bit
-    // before the end of the window
-    wvalue = 1;
-    wend = 0;
-    for (i = 1; i < window; i++) {
-      if (wstart - i < 0) {
-        break;
-      }
+    // We now have wstart on a set bit. Find the largest window we can use.
+    int wvalue = 1;
+    int wsize = 0;
+    for (int i = 1; i < window && i <= wstart; i++) {
       if (BN_is_bit_set(p, wstart - i)) {
-        wvalue <<= (i - wend);
+        wvalue <<= (i - wsize);
         wvalue |= 1;
-        wend = i;
+        wsize = i;
       }
     }
 
-    // wend is the size of the current window
-    j = wend + 1;
-    // add the 'bytes above'
-    if (!start) {
-      for (i = 0; i < j; i++) {
+    // Shift |r| to the end of the window.
+    if (!r_is_one) {
+      for (int i = 0; i < wsize + 1; i++) {
         if (!BN_mod_mul_montgomery(r, r, r, mont, ctx)) {
           goto err;
         }
       }
     }
 
-    // wvalue will be an odd number < 2^window
+    assert(wvalue & 1);
+    assert(wvalue < (1 << window));
     if (!BN_mod_mul_montgomery(r, r, val[wvalue >> 1], mont, ctx)) {
       goto err;
     }
 
-    // move the 'window' down further
-    wstart -= wend + 1;
-    start = 0;
-    if (wstart < 0) {
+    r_is_one = 0;
+    if (wstart == wsize) {
       break;
     }
+    wstart -= wsize + 1;
   }
 
   if (!BN_from_montgomery(rr, r, mont, ctx)) {
diff --git a/src/crypto/fipsmodule/bn/generic.c b/src/crypto/fipsmodule/bn/generic.c
index 11c377c..44e0f2c 100644
--- a/src/crypto/fipsmodule/bn/generic.c
+++ b/src/crypto/fipsmodule/bn/generic.c
@@ -458,7 +458,7 @@
 
 #endif  // !BN_ULLONG
 
-void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b) {
+void bn_mul_comba8(BN_ULONG r[16], BN_ULONG a[8], BN_ULONG b[8]) {
   BN_ULONG c1, c2, c3;
 
   c1 = 0;
@@ -560,7 +560,7 @@
   r[15] = c1;
 }
 
-void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b) {
+void bn_mul_comba4(BN_ULONG r[8], BN_ULONG a[4], BN_ULONG b[4]) {
   BN_ULONG c1, c2, c3;
 
   c1 = 0;
@@ -598,7 +598,7 @@
   r[7] = c2;
 }
 
-void bn_sqr_comba8(BN_ULONG *r, const BN_ULONG *a) {
+void bn_sqr_comba8(BN_ULONG r[16], const BN_ULONG a[8]) {
   BN_ULONG c1, c2, c3;
 
   c1 = 0;
@@ -672,7 +672,7 @@
   r[15] = c1;
 }
 
-void bn_sqr_comba4(BN_ULONG *r, const BN_ULONG *a) {
+void bn_sqr_comba4(BN_ULONG r[8], const BN_ULONG a[4]) {
   BN_ULONG c1, c2, c3;
 
   c1 = 0;
diff --git a/src/crypto/fipsmodule/bn/internal.h b/src/crypto/fipsmodule/bn/internal.h
index b1e0b0d..acc0ac8 100644
--- a/src/crypto/fipsmodule/bn/internal.h
+++ b/src/crypto/fipsmodule/bn/internal.h
@@ -142,41 +142,39 @@
 
 #if !defined(_MSC_VER)
 // MSVC doesn't support two-word integers on 64-bit.
-#define BN_ULLONG	uint128_t
+#define BN_ULLONG uint128_t
 #endif
 
-#define BN_BITS2	64
-#define BN_BYTES	8
-#define BN_BITS4	32
-#define BN_MASK2	(0xffffffffffffffffUL)
-#define BN_MASK2l	(0xffffffffUL)
-#define BN_MASK2h	(0xffffffff00000000UL)
-#define BN_MASK2h1	(0xffffffff80000000UL)
+#define BN_BITS2 64
+#define BN_BYTES 8
+#define BN_BITS4 32
+#define BN_MASK2 (0xffffffffffffffffUL)
+#define BN_MASK2l (0xffffffffUL)
+#define BN_MASK2h (0xffffffff00000000UL)
+#define BN_MASK2h1 (0xffffffff80000000UL)
 #define BN_MONT_CTX_N0_LIMBS 1
-#define BN_TBIT		(0x8000000000000000UL)
-#define BN_DEC_CONV	(10000000000000000000UL)
-#define BN_DEC_NUM	19
+#define BN_DEC_CONV (10000000000000000000UL)
+#define BN_DEC_NUM 19
 #define TOBN(hi, lo) ((BN_ULONG)(hi) << 32 | (lo))
 
 #elif defined(OPENSSL_32_BIT)
 
-#define BN_ULLONG	uint64_t
-#define BN_BITS2	32
-#define BN_BYTES	4
-#define BN_BITS4	16
-#define BN_MASK2	(0xffffffffUL)
-#define BN_MASK2l	(0xffffUL)
-#define BN_MASK2h1	(0xffff8000UL)
-#define BN_MASK2h	(0xffff0000UL)
+#define BN_ULLONG uint64_t
+#define BN_BITS2 32
+#define BN_BYTES 4
+#define BN_BITS4 16
+#define BN_MASK2 (0xffffffffUL)
+#define BN_MASK2l (0xffffUL)
+#define BN_MASK2h1 (0xffff8000UL)
+#define BN_MASK2h (0xffff0000UL)
 // On some 32-bit platforms, Montgomery multiplication is done using 64-bit
 // arithmetic with SIMD instructions. On such platforms, |BN_MONT_CTX::n0|
 // needs to be two words long. Only certain 32-bit platforms actually make use
 // of n0[1] and shorter R value would suffice for the others. However,
 // currently only the assembly files know which is which.
 #define BN_MONT_CTX_N0_LIMBS 2
-#define BN_TBIT		(0x80000000UL)
-#define BN_DEC_CONV	(1000000000UL)
-#define BN_DEC_NUM	9
+#define BN_DEC_CONV (1000000000UL)
+#define BN_DEC_NUM 9
 #define TOBN(hi, lo) (lo), (hi)
 
 #else
@@ -212,16 +210,50 @@
 // least significant word first.
 int bn_set_words(BIGNUM *bn, const BN_ULONG *words, size_t num);
 
-BN_ULONG bn_mul_add_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w);
-BN_ULONG bn_mul_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w);
-void     bn_sqr_words(BN_ULONG *rp, const BN_ULONG *ap, int num);
-BN_ULONG bn_add_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,int num);
-BN_ULONG bn_sub_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,int num);
+// bn_mul_add_words multiples |ap| by |w|, adds the result to |rp|, and places
+// the result in |rp|. |ap| and |rp| must both be |num| words long. It returns
+// the carry word of the operation. |ap| and |rp| may be equal but otherwise may
+// not alias.
+BN_ULONG bn_mul_add_words(BN_ULONG *rp, const BN_ULONG *ap, int num,
+                          BN_ULONG w);
 
-void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b);
-void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b);
-void bn_sqr_comba8(BN_ULONG *r, const BN_ULONG *a);
-void bn_sqr_comba4(BN_ULONG *r, const BN_ULONG *a);
+// bn_mul_words multiples |ap| by |w| and places the result in |rp|. |ap| and
+// |rp| must both be |num| words long. It returns the carry word of the
+// operation. |ap| and |rp| may be equal but otherwise may not alias.
+BN_ULONG bn_mul_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w);
+
+// bn_sqr_words sets |rp[2*i]| and |rp[2*i+1]| to |ap[i]|'s square, for all |i|
+// up to |num|. |ap| is an array of |num| words and |rp| an array of |2*num|
+// words. |ap| and |rp| may not alias.
+//
+// This gives the contribution of the |ap[i]*ap[i]| terms when squaring |ap|.
+void bn_sqr_words(BN_ULONG *rp, const BN_ULONG *ap, int num);
+
+// bn_add_words adds |ap| to |bp| and places the result in |rp|, each of which
+// are |num| words long. It returns the carry bit, which is one if the operation
+// overflowed and zero otherwise. Any pair of |ap|, |bp|, and |rp| may be equal
+// to each other but otherwise may not alias.
+BN_ULONG bn_add_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
+                      int num);
+
+// bn_sub_words subtracts |bp| from |ap| and places the result in |rp|. It
+// returns the borrow bit, which is one if the computation underflowed and zero
+// otherwise. Any pair of |ap|, |bp|, and |rp| may be equal to each other but
+// otherwise may not alias.
+BN_ULONG bn_sub_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
+                      int num);
+
+// bn_mul_comba4 sets |r| to the product of |a| and |b|.
+void bn_mul_comba4(BN_ULONG r[8], BN_ULONG a[4], BN_ULONG b[4]);
+
+// bn_mul_comba8 sets |r| to the product of |a| and |b|.
+void bn_mul_comba8(BN_ULONG r[16], BN_ULONG a[8], BN_ULONG b[8]);
+
+// bn_sqr_comba8 sets |r| to |a|^2.
+void bn_sqr_comba8(BN_ULONG r[16], const BN_ULONG a[4]);
+
+// bn_sqr_comba4 sets |r| to |a|^2.
+void bn_sqr_comba4(BN_ULONG r[8], const BN_ULONG a[4]);
 
 // bn_cmp_words returns a value less than, equal to or greater than zero if
 // the, length |n|, array |a| is less than, equal to or greater than |b|.
diff --git a/src/crypto/fipsmodule/bn/montgomery.c b/src/crypto/fipsmodule/bn/montgomery.c
index 5219187..caa2513 100644
--- a/src/crypto/fipsmodule/bn/montgomery.c
+++ b/src/crypto/fipsmodule/bn/montgomery.c
@@ -207,14 +207,13 @@
   mont->n0[1] = 0;
 #endif
 
-  // Save RR = R**2 (mod N). R is the smallest power of 2**BN_BITS such that R
+  // Save RR = R**2 (mod N). R is the smallest power of 2**BN_BITS2 such that R
   // > mod. Even though the assembly on some 32-bit platforms works with 64-bit
   // values, using |BN_BITS2| here, rather than |BN_MONT_CTX_N0_LIMBS *
   // BN_BITS2|, is correct because R**2 will still be a multiple of the latter
   // as |BN_MONT_CTX_N0_LIMBS| is either one or two.
   //
-  // XXX: This is not constant time with respect to |mont->N|, but it should
-  // be.
+  // XXX: This is not constant time with respect to |mont->N|, but it should be.
   unsigned lgBigR = (BN_num_bits(mod) + (BN_BITS2 - 1)) / BN_BITS2 * BN_BITS2;
   if (!bn_mod_exp_base_2_vartime(&mont->RR, lgBigR * 2, &mont->N)) {
     return 0;
diff --git a/src/crypto/fipsmodule/bn/mul.c b/src/crypto/fipsmodule/bn/mul.c
index b6f3ff1..65f3c2b 100644
--- a/src/crypto/fipsmodule/bn/mul.c
+++ b/src/crypto/fipsmodule/bn/mul.c
@@ -659,37 +659,37 @@
 }
 
 // tmp must have 2*n words
-static void bn_sqr_normal(BN_ULONG *r, const BN_ULONG *a, int n, BN_ULONG *tmp) {
-  int i, j, max;
-  const BN_ULONG *ap;
-  BN_ULONG *rp;
-
-  max = n * 2;
-  ap = a;
-  rp = r;
+static void bn_sqr_normal(BN_ULONG *r, const BN_ULONG *a, int n,
+                          BN_ULONG *tmp) {
+  int max = n * 2;
+  const BN_ULONG *ap = a;
+  BN_ULONG *rp = r;
   rp[0] = rp[max - 1] = 0;
   rp++;
-  j = n;
+  int j = n;
 
+  // Compute the contribution of a[i] * a[j] for all i < j.
   if (--j > 0) {
     ap++;
     rp[j] = bn_mul_words(rp, ap, j, ap[-1]);
     rp += 2;
   }
 
-  for (i = n - 2; i > 0; i--) {
+  for (int i = n - 2; i > 0; i--) {
     j--;
     ap++;
     rp[j] = bn_mul_add_words(rp, ap, j, ap[-1]);
     rp += 2;
   }
 
+  // The final result fits in |max| words, so none of the following operations
+  // will overflow.
+
+  // Double |r|, giving the contribution of a[i] * a[j] for all i != j.
   bn_add_words(r, r, r, max);
 
-  // There will not be a carry
-
+  // Add in the contribution of a[i] * a[i] for all i.
   bn_sqr_words(tmp, a, n);
-
   bn_add_words(r, r, tmp, max);
 }
 
@@ -702,7 +702,8 @@
 // a[0]*b[0]
 // a[0]*b[0]+a[1]*b[1]+(a[0]-a[1])*(b[1]-b[0])
 // a[1]*b[1]
-static void bn_sqr_recursive(BN_ULONG *r, const BN_ULONG *a, int n2, BN_ULONG *t) {
+static void bn_sqr_recursive(BN_ULONG *r, const BN_ULONG *a, int n2,
+                             BN_ULONG *t) {
   int n = n2 / 2;
   int zero, c1;
   BN_ULONG ln, lo, *p;
diff --git a/src/crypto/fipsmodule/bn/shift.c b/src/crypto/fipsmodule/bn/shift.c
index 64afa78..d4528e6 100644
--- a/src/crypto/fipsmodule/bn/shift.c
+++ b/src/crypto/fipsmodule/bn/shift.c
@@ -122,7 +122,7 @@
   for (i = 0; i < a->top; i++) {
     t = *(ap++);
     *(rp++) = (t << 1) | c;
-    c = (t & BN_TBIT) ? 1 : 0;
+    c = t >> (BN_BITS2 - 1);
   }
   if (c) {
     *rp = 1;
@@ -209,14 +209,14 @@
   }
   rp = r->d;
   t = ap[--i];
-  c = (t & 1) ? BN_TBIT : 0;
+  c = t << (BN_BITS2 - 1);
   if (t >>= 1) {
     rp[i] = t;
   }
   while (i > 0) {
     t = ap[--i];
     rp[i] = (t >> 1) | c;
-    c = (t & 1) ? BN_TBIT : 0;
+    c = t << (BN_BITS2 - 1);
   }
   r->top = j;
 
diff --git a/src/crypto/fipsmodule/ecdsa/ecdsa.c b/src/crypto/fipsmodule/ecdsa/ecdsa.c
index dfa3b67..0e2adb6 100644
--- a/src/crypto/fipsmodule/ecdsa/ecdsa.c
+++ b/src/crypto/fipsmodule/ecdsa/ecdsa.c
@@ -160,7 +160,7 @@
     OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_BAD_SIGNATURE);
     goto err;
   }
-  // calculate tmp1 = inv(S) mod order
+  // tmp = inv(s) mod order
   int no_inverse;
   if (!BN_mod_inverse_odd(u2, &no_inverse, sig->s, order, ctx)) {
     OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB);
@@ -174,7 +174,7 @@
     OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB);
     goto err;
   }
-  // u2 = r * w mod q
+  // u2 = r * tmp mod order
   if (!BN_mod_mul(u2, sig->r, u2, order, ctx)) {
     OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB);
     goto err;
@@ -267,13 +267,11 @@
         goto err;
       }
     } else if (digest_len > 0) {
-      do {
-        if (!BN_generate_dsa_nonce(k, order, EC_KEY_get0_private_key(eckey),
-                                   digest, digest_len, ctx)) {
-          OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED);
-          goto err;
-        }
-      } while (BN_is_zero(k));
+      if (!BN_generate_dsa_nonce(k, order, EC_KEY_get0_private_key(eckey),
+                                 digest, digest_len, ctx)) {
+        OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED);
+        goto err;
+      }
     } else if (!BN_rand_range_ex(k, 1, order)) {
       OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED);
       goto err;
diff --git a/src/crypto/fipsmodule/ecdsa/ecdsa_test.cc b/src/crypto/fipsmodule/ecdsa/ecdsa_test.cc
index de4bc48..837b95d 100644
--- a/src/crypto/fipsmodule/ecdsa/ecdsa_test.cc
+++ b/src/crypto/fipsmodule/ecdsa/ecdsa_test.cc
@@ -67,17 +67,17 @@
 #include "../../test/file_test.h"
 
 
-enum Api {
-  kEncodedApi,
-  kRawApi,
+enum API {
+  kEncodedAPI,
+  kRawAPI,
 };
 
 // VerifyECDSASig checks that verifying |ecdsa_sig| gives |expected_result|.
-static void VerifyECDSASig(Api api, const uint8_t *digest, size_t digest_len,
+static void VerifyECDSASig(API api, const uint8_t *digest, size_t digest_len,
                            const ECDSA_SIG *ecdsa_sig, EC_KEY *eckey,
                            int expected_result) {
   switch (api) {
-    case kEncodedApi: {
+    case kEncodedAPI: {
       uint8_t *der;
       size_t der_len;
       ASSERT_TRUE(ECDSA_SIG_to_bytes(&der, &der_len, ecdsa_sig));
@@ -87,7 +87,7 @@
       break;
     }
 
-    case kRawApi:
+    case kRawAPI:
       EXPECT_EQ(expected_result,
                 ECDSA_do_verify(digest, digest_len, ecdsa_sig, eckey));
       break;
@@ -100,7 +100,7 @@
 // TestTamperedSig verifies that signature verification fails when a valid
 // signature is tampered with. |ecdsa_sig| must be a valid signature, which will
 // be modified.
-static void TestTamperedSig(Api api, const uint8_t *digest,
+static void TestTamperedSig(API api, const uint8_t *digest,
                             size_t digest_len, ECDSA_SIG *ecdsa_sig,
                             EC_KEY *eckey, const BIGNUM *order) {
   SCOPED_TRACE(api);
@@ -206,7 +206,7 @@
     bssl::UniquePtr<ECDSA_SIG> ecdsa_sig(
         ECDSA_SIG_from_bytes(signature.data(), signature.size()));
     ASSERT_TRUE(ecdsa_sig);
-    TestTamperedSig(kEncodedApi, digest, 20, ecdsa_sig.get(), eckey.get(),
+    TestTamperedSig(kEncodedAPI, digest, 20, ecdsa_sig.get(), eckey.get(),
                     order);
 
     // Test ECDSA_SIG signing and verification.
@@ -228,7 +228,7 @@
     ERR_clear_error();
 
     // Verify a tampered signature.
-    TestTamperedSig(kRawApi, digest, 20, ecdsa_sig.get(), eckey.get(), order);
+    TestTamperedSig(kRawAPI, digest, 20, ecdsa_sig.get(), eckey.get(), order);
   }
 }
 
diff --git a/src/crypto/fipsmodule/modes/asm/aesni-gcm-x86_64.pl b/src/crypto/fipsmodule/modes/asm/aesni-gcm-x86_64.pl
index dd6657b..3d0600f 100644
--- a/src/crypto/fipsmodule/modes/asm/aesni-gcm-x86_64.pl
+++ b/src/crypto/fipsmodule/modes/asm/aesni-gcm-x86_64.pl
@@ -86,6 +86,7 @@
 .type	_aesni_ctr32_ghash_6x,\@abi-omnipotent
 .align	32
 _aesni_ctr32_ghash_6x:
+.cfi_startproc
 	vmovdqu		0x20($const),$T2	# borrow $T2, .Lone_msb
 	sub		\$6,$len
 	vpxor		$Z0,$Z0,$Z0		# $Z0   = 0
@@ -410,6 +411,7 @@
 	vpxor		$Z0,$Xi,$Xi		# modulo-scheduled
 
 	ret
+.cfi_endproc
 .size	_aesni_ctr32_ghash_6x,.-_aesni_ctr32_ghash_6x
 ___
 ######################################################################
@@ -422,6 +424,7 @@
 .type	aesni_gcm_decrypt,\@function,6
 .align	32
 aesni_gcm_decrypt:
+.cfi_startproc
 	xor	$ret,$ret
 
 	# We call |_aesni_ctr32_ghash_6x|, which requires at least 96 (0x60)
@@ -430,12 +433,19 @@
 	jb	.Lgcm_dec_abort
 
 	lea	(%rsp),%rax			# save stack pointer
+.cfi_def_cfa_register	%rax
 	push	%rbx
+.cfi_push	%rbx
 	push	%rbp
+.cfi_push	%rbp
 	push	%r12
+.cfi_push	%r12
 	push	%r13
+.cfi_push	%r13
 	push	%r14
+.cfi_push	%r14
 	push	%r15
+.cfi_push	%r15
 ___
 $code.=<<___ if ($win64);
 	lea	-0xa8(%rsp),%rsp
@@ -535,15 +545,23 @@
 ___
 $code.=<<___;
 	mov	-48(%rax),%r15
+.cfi_restore	%r15
 	mov	-40(%rax),%r14
+.cfi_restore	%r14
 	mov	-32(%rax),%r13
+.cfi_restore	%r13
 	mov	-24(%rax),%r12
+.cfi_restore	%r12
 	mov	-16(%rax),%rbp
+.cfi_restore	%rbp
 	mov	-8(%rax),%rbx
+.cfi_restore	%rbx
 	lea	(%rax),%rsp		# restore %rsp
+.cfi_def_cfa_register	%rsp
 .Lgcm_dec_abort:
 	mov	$ret,%rax		# return value
 	ret
+.cfi_endproc
 .size	aesni_gcm_decrypt,.-aesni_gcm_decrypt
 ___
 
@@ -551,6 +569,7 @@
 .type	_aesni_ctr32_6x,\@abi-omnipotent
 .align	32
 _aesni_ctr32_6x:
+.cfi_startproc
 	vmovdqu		0x00-0x80($key),$Z0	# borrow $Z0 for $rndkey
 	vmovdqu		0x20($const),$T2	# borrow $T2, .Lone_msb
 	lea		-1($rounds),%r13
@@ -637,12 +656,14 @@
 	vpshufb		$Ii,$T1,$T1		# next counter value
 	vpxor		$Z0,$inout5,$inout5
 	jmp	.Loop_ctr32
+.cfi_endproc
 .size	_aesni_ctr32_6x,.-_aesni_ctr32_6x
 
 .globl	aesni_gcm_encrypt
 .type	aesni_gcm_encrypt,\@function,6
 .align	32
 aesni_gcm_encrypt:
+.cfi_startproc
 	xor	$ret,$ret
 
 	# We call |_aesni_ctr32_6x| twice, each call consuming 96 bytes of
@@ -652,12 +673,19 @@
 	jb	.Lgcm_enc_abort
 
 	lea	(%rsp),%rax			# save stack pointer
+.cfi_def_cfa_register	%rax
 	push	%rbx
+.cfi_push	%rbx
 	push	%rbp
+.cfi_push	%rbp
 	push	%r12
+.cfi_push	%r12
 	push	%r13
+.cfi_push	%r13
 	push	%r14
+.cfi_push	%r14
 	push	%r15
+.cfi_push	%r15
 ___
 $code.=<<___ if ($win64);
 	lea	-0xa8(%rsp),%rsp
@@ -929,15 +957,23 @@
 ___
 $code.=<<___;
 	mov	-48(%rax),%r15
+.cfi_restore	%r15
 	mov	-40(%rax),%r14
+.cfi_restore	%r14
 	mov	-32(%rax),%r13
+.cfi_restore	%r13
 	mov	-24(%rax),%r12
+.cfi_restore	%r12
 	mov	-16(%rax),%rbp
+.cfi_restore	%rbp
 	mov	-8(%rax),%rbx
+.cfi_restore	%rbx
 	lea	(%rax),%rsp		# restore %rsp
+.cfi_def_cfa_register	%rsp
 .Lgcm_enc_abort:
 	mov	$ret,%rax		# return value
 	ret
+.cfi_endproc
 .size	aesni_gcm_encrypt,.-aesni_gcm_encrypt
 ___
 
diff --git a/src/crypto/fipsmodule/modes/cbc.c b/src/crypto/fipsmodule/modes/cbc.c
index 4b3bdb8..db9f024 100644
--- a/src/crypto/fipsmodule/modes/cbc.c
+++ b/src/crypto/fipsmodule/modes/cbc.c
@@ -62,7 +62,8 @@
   assert(len == 0 || (in != NULL && out != NULL));
 
   if (STRICT_ALIGNMENT &&
-      ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) {
+      ((uintptr_t)in | (uintptr_t)out | (uintptr_t)ivec) % sizeof(size_t) !=
+          0) {
     while (len >= 16) {
       for (n = 0; n < 16; ++n) {
         out[n] = in[n] ^ iv[n];
@@ -76,7 +77,7 @@
   } else {
     while (len >= 16) {
       for (n = 0; n < 16; n += sizeof(size_t)) {
-        *(size_t *)(out + n) = *(size_t *)(in + n) ^ *(size_t *)(iv + n);
+        store_word_le(out + n, load_word_le(in + n) ^ load_word_le(iv + n));
       }
       (*block)(out, out, key);
       iv = out;
@@ -129,7 +130,8 @@
     const uint8_t *iv = ivec;
 
     if (STRICT_ALIGNMENT &&
-        ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) {
+        ((uintptr_t)in | (uintptr_t)out | (uintptr_t)ivec) % sizeof(size_t) !=
+            0) {
       while (len >= 16) {
         (*block)(in, out, key);
         for (n = 0; n < 16; ++n) {
@@ -142,11 +144,9 @@
       }
     } else if (16 % sizeof(size_t) == 0) {  // always true
       while (len >= 16) {
-        size_t *out_t = (size_t *)out, *iv_t = (size_t *)iv;
-
         (*block)(in, out, key);
-        for (n = 0; n < 16 / sizeof(size_t); n++) {
-          out_t[n] ^= iv_t[n];
+        for (n = 0; n < 16; n += sizeof(size_t)) {
+          store_word_le(out + n, load_word_le(out + n) ^ load_word_le(iv + n));
         }
         iv = in;
         len -= 16;
@@ -160,7 +160,8 @@
     // directly to |out| would overwrite a ciphertext block before it is used as
     // the next block's IV. Decrypt to a temporary block instead.
     if (STRICT_ALIGNMENT &&
-        ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) {
+        ((uintptr_t)in | (uintptr_t)out | (uintptr_t)ivec) % sizeof(size_t) !=
+            0) {
       uint8_t c;
       while (len >= 16) {
         (*block)(in, tmp.c, key);
@@ -175,14 +176,12 @@
       }
     } else if (16 % sizeof(size_t) == 0) {  // always true
       while (len >= 16) {
-        size_t c, *out_t = (size_t *)out, *ivec_t = (size_t *)ivec;
-        const size_t *in_t = (const size_t *)in;
-
         (*block)(in, tmp.c, key);
-        for (n = 0; n < 16 / sizeof(size_t); n++) {
-          c = in_t[n];
-          out_t[n] = tmp.t[n] ^ ivec_t[n];
-          ivec_t[n] = c;
+        for (n = 0; n < 16; n += sizeof(size_t)) {
+          size_t c = load_word_le(in + n);
+          store_word_le(out + n,
+                        tmp.t[n / sizeof(size_t)] ^ load_word_le(ivec + n));
+          store_word_le(ivec + n, c);
         }
         len -= 16;
         in += 16;
diff --git a/src/crypto/fipsmodule/modes/cfb.c b/src/crypto/fipsmodule/modes/cfb.c
index 2775d19..e1b0a80 100644
--- a/src/crypto/fipsmodule/modes/cfb.c
+++ b/src/crypto/fipsmodule/modes/cfb.c
@@ -72,7 +72,8 @@
       n = (n + 1) % 16;
     }
 #if STRICT_ALIGNMENT
-    if (((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) {
+    if (((uintptr_t)in | (uintptr_t)out | (uintptr_t)ivec) % sizeof(size_t) !=
+        0) {
       while (l < len) {
         if (n == 0) {
           (*block)(ivec, ivec, key);
@@ -88,7 +89,9 @@
     while (len >= 16) {
       (*block)(ivec, ivec, key);
       for (; n < 16; n += sizeof(size_t)) {
-        *(size_t *)(out + n) = *(size_t *)(ivec + n) ^= *(size_t *)(in + n);
+        size_t tmp = load_word_le(ivec + n) ^ load_word_le(in + n);
+        store_word_le(ivec + n, tmp);
+        store_word_le(out + n, tmp);
       }
       len -= 16;
       out += 16;
@@ -112,9 +115,11 @@
       --len;
       n = (n + 1) % 16;
     }
-    if (STRICT_ALIGNMENT && ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) {
+    if (STRICT_ALIGNMENT &&
+        ((uintptr_t)in | (uintptr_t)out | (uintptr_t)ivec) % sizeof(size_t) !=
+            0) {
       while (l < len) {
-        unsigned char c;
+        uint8_t c;
         if (n == 0) {
           (*block)(ivec, ivec, key);
         }
@@ -129,9 +134,9 @@
     while (len >= 16) {
       (*block)(ivec, ivec, key);
       for (; n < 16; n += sizeof(size_t)) {
-        size_t t = *(size_t *)(in + n);
-        *(size_t *)(out + n) = *(size_t *)(ivec + n) ^ t;
-        *(size_t *)(ivec + n) = t;
+        size_t t = load_word_le(in + n);
+        store_word_le(out + n, load_word_le(ivec + n) ^ t);
+        store_word_le(ivec + n, t);
       }
       len -= 16;
       out += 16;
@@ -227,4 +232,3 @@
     cfbr_encrypt_block(&in[n], &out[n], 8, key, ivec, enc, block);
   }
 }
-
diff --git a/src/crypto/fipsmodule/modes/ctr.c b/src/crypto/fipsmodule/modes/ctr.c
index 5a97cf6..63907b4 100644
--- a/src/crypto/fipsmodule/modes/ctr.c
+++ b/src/crypto/fipsmodule/modes/ctr.c
@@ -100,7 +100,8 @@
   }
 
 #if STRICT_ALIGNMENT
-  if (((size_t)in | (size_t)out | (size_t)ecount_buf) % sizeof(size_t) != 0) {
+  if (((uintptr_t)in | (uintptr_t)out |
+        (uintptr_t)ecount_buf) % sizeof(size_t) != 0) {
     size_t l = 0;
     while (l < len) {
       if (n == 0) {
@@ -121,8 +122,8 @@
     (*block)(ivec, ecount_buf, key);
     ctr128_inc(ivec);
     for (n = 0; n < 16; n += sizeof(size_t)) {
-      *(size_t *)(out + n) = *(const size_t *)(in + n) ^
-                             *(const size_t *)(ecount_buf + n);
+      store_word_le(out + n,
+                    load_word_le(in + n) ^ load_word_le(ecount_buf + n));
     }
     len -= 16;
     out += 16;
diff --git a/src/crypto/fipsmodule/modes/gcm.c b/src/crypto/fipsmodule/modes/gcm.c
index bb5be54..05cd18d 100644
--- a/src/crypto/fipsmodule/modes/gcm.c
+++ b/src/crypto/fipsmodule/modes/gcm.c
@@ -550,8 +550,7 @@
 }
 
 int CRYPTO_gcm128_encrypt(GCM128_CONTEXT *ctx, const void *key,
-                          const unsigned char *in, unsigned char *out,
-                          size_t len) {
+                          const uint8_t *in, uint8_t *out, size_t len) {
   unsigned int n, ctr;
   uint64_t mlen = ctx->len.u[1];
   block128_f block = ctx->block;
@@ -592,7 +591,8 @@
       return 1;
     }
   }
-  if (STRICT_ALIGNMENT && ((size_t)in | (size_t)out) % sizeof(size_t) != 0) {
+  if (STRICT_ALIGNMENT &&
+      ((uintptr_t)in | (uintptr_t)out) % sizeof(size_t) != 0) {
     for (size_t i = 0; i < len; ++i) {
       if (n == 0) {
         (*block)(ctx->Yi.c, ctx->EKi.c, key);
@@ -614,14 +614,12 @@
     size_t j = GHASH_CHUNK;
 
     while (j) {
-      size_t *out_t = (size_t *)out;
-      const size_t *in_t = (const size_t *)in;
-
       (*block)(ctx->Yi.c, ctx->EKi.c, key);
       ++ctr;
       ctx->Yi.d[3] = CRYPTO_bswap4(ctr);
-      for (size_t i = 0; i < 16 / sizeof(size_t); ++i) {
-        out_t[i] = in_t[i] ^ ctx->EKi.t[i];
+      for (size_t i = 0; i < 16; i += sizeof(size_t)) {
+        store_word_le(out + i,
+                      load_word_le(in + i) ^ ctx->EKi.t[i / sizeof(size_t)]);
       }
       out += 16;
       in += 16;
@@ -633,14 +631,12 @@
   size_t len_blocks = len & kSizeTWithoutLower4Bits;
   if (len_blocks != 0) {
     while (len >= 16) {
-      size_t *out_t = (size_t *)out;
-      const size_t *in_t = (const size_t *)in;
-
       (*block)(ctx->Yi.c, ctx->EKi.c, key);
       ++ctr;
       ctx->Yi.d[3] = CRYPTO_bswap4(ctr);
-      for (size_t i = 0; i < 16 / sizeof(size_t); ++i) {
-        out_t[i] = in_t[i] ^ ctx->EKi.t[i];
+      for (size_t i = 0; i < 16; i += sizeof(size_t)) {
+        store_word_le(out + i,
+                      load_word_le(in + i) ^ ctx->EKi.t[i / sizeof(size_t)]);
       }
       out += 16;
       in += 16;
@@ -650,14 +646,13 @@
   }
 #else
   while (len >= 16) {
-    size_t *out_t = (size_t *)out;
-    const size_t *in_t = (const size_t *)in;
-
     (*block)(ctx->Yi.c, ctx->EKi.c, key);
     ++ctr;
     ctx->Yi.d[3] = CRYPTO_bswap4(ctr);
-    for (size_t i = 0; i < 16 / sizeof(size_t); ++i) {
-      ctx->Xi.t[i] ^= out_t[i] = in_t[i] ^ ctx->EKi.t[i];
+    for (size_t i = 0; i < 16; i += sizeof(size_t)) {
+      size_t tmp = load_word_le(in + i) ^ ctx->EKi.t[i / sizeof(size_t)];
+      store_word_le(out + i, tmp);
+      ctx->Xi.t[i / sizeof(size_t)] ^= tmp;
     }
     GCM_MUL(ctx, Xi);
     out += 16;
@@ -724,7 +719,8 @@
       return 1;
     }
   }
-  if (STRICT_ALIGNMENT && ((size_t)in | (size_t)out) % sizeof(size_t) != 0) {
+  if (STRICT_ALIGNMENT &&
+      ((uintptr_t)in | (uintptr_t)out) % sizeof(size_t) != 0) {
     for (size_t i = 0; i < len; ++i) {
       uint8_t c;
       if (n == 0) {
@@ -750,14 +746,12 @@
 
     GHASH(ctx, in, GHASH_CHUNK);
     while (j) {
-      size_t *out_t = (size_t *)out;
-      const size_t *in_t = (const size_t *)in;
-
       (*block)(ctx->Yi.c, ctx->EKi.c, key);
       ++ctr;
       ctx->Yi.d[3] = CRYPTO_bswap4(ctr);
-      for (size_t i = 0; i < 16 / sizeof(size_t); ++i) {
-        out_t[i] = in_t[i] ^ ctx->EKi.t[i];
+      for (size_t i = 0; i < 16; i += sizeof(size_t)) {
+        store_word_le(out + i,
+                      load_word_le(in + i) ^ ctx->EKi.t[i / sizeof(size_t)]);
       }
       out += 16;
       in += 16;
@@ -769,14 +763,12 @@
   if (len_blocks != 0) {
     GHASH(ctx, in, len_blocks);
     while (len >= 16) {
-      size_t *out_t = (size_t *)out;
-      const size_t *in_t = (const size_t *)in;
-
       (*block)(ctx->Yi.c, ctx->EKi.c, key);
       ++ctr;
       ctx->Yi.d[3] = CRYPTO_bswap4(ctr);
-      for (size_t i = 0; i < 16 / sizeof(size_t); ++i) {
-        out_t[i] = in_t[i] ^ ctx->EKi.t[i];
+      for (size_t i = 0; i < 16; i += sizeof(size_t)) {
+        store_word_le(out + i,
+                      load_word_le(in + i) ^ ctx->EKi.t[i / sizeof(size_t)]);
       }
       out += 16;
       in += 16;
@@ -785,16 +777,13 @@
   }
 #else
   while (len >= 16) {
-    size_t *out_t = (size_t *)out;
-    const size_t *in_t = (const size_t *)in;
-
     (*block)(ctx->Yi.c, ctx->EKi.c, key);
     ++ctr;
     ctx->Yi.d[3] = CRYPTO_bswap4(ctr);
-    for (size_t i = 0; i < 16 / sizeof(size_t); ++i) {
-      size_t c = in_t[i];
-      out_t[i] = c ^ ctx->EKi.t[i];
-      ctx->Xi.t[i] ^= c;
+    for (size_t i = 0; i < 16; i += sizeof(size_t)) {
+      size_t c = load_word_le(in + i);
+      store_word_le(out + i, c ^ ctx->EKi.t[i / sizeof(size_t)]);
+      ctx->Xi.t[i / sizeof(size_t)] ^= c;
     }
     GCM_MUL(ctx, Xi);
     out += 16;
diff --git a/src/crypto/fipsmodule/modes/internal.h b/src/crypto/fipsmodule/modes/internal.h
index 6a5ff99..f6ee8f4 100644
--- a/src/crypto/fipsmodule/modes/internal.h
+++ b/src/crypto/fipsmodule/modes/internal.h
@@ -109,6 +109,16 @@
   OPENSSL_memcpy(out, &v, sizeof(v));
 }
 
+static inline size_t load_word_le(const void *in) {
+  size_t v;
+  OPENSSL_memcpy(&v, in, sizeof(v));
+  return v;
+}
+
+static inline void store_word_le(void *out, size_t v) {
+  OPENSSL_memcpy(out, &v, sizeof(v));
+}
+
 // block128_f is the type of a 128-bit, block cipher.
 typedef void (*block128_f)(const uint8_t in[16], uint8_t out[16],
                            const void *key);
diff --git a/src/crypto/poly1305/poly1305_vec.c b/src/crypto/poly1305/poly1305_vec.c
index 80eaa36..480d9e5 100644
--- a/src/crypto/poly1305/poly1305_vec.c
+++ b/src/crypto/poly1305/poly1305_vec.c
@@ -85,57 +85,6 @@
   return (poly1305_state_internal *)(((uint64_t)state + 63) & ~63);
 }
 
-// copy 0-63 bytes
-static inline void
-poly1305_block_copy(uint8_t *dst, const uint8_t *src, size_t bytes) {
-  size_t offset = src - dst;
-  if (bytes & 32) {
-    _mm_storeu_si128((xmmi *)(dst + 0),
-                     _mm_loadu_si128((const xmmi *)(dst + offset + 0)));
-    _mm_storeu_si128((xmmi *)(dst + 16),
-                     _mm_loadu_si128((const xmmi *)(dst + offset + 16)));
-    dst += 32;
-  }
-  if (bytes & 16) {
-    _mm_storeu_si128((xmmi *)dst, _mm_loadu_si128((const xmmi *)(dst + offset)));
-    dst += 16;
-  }
-  if (bytes & 8) {
-    *(uint64_t *)dst = *(const uint64_t *)(dst + offset);
-    dst += 8;
-  }
-  if (bytes & 4) {
-    *(uint32_t *)dst = *(const uint32_t *)(dst + offset);
-    dst += 4;
-  }
-  if (bytes & 2) {
-    *(uint16_t *)dst = *(uint16_t *)(dst + offset);
-    dst += 2;
-  }
-  if (bytes & 1) {
-    *(uint8_t *)dst = *(uint8_t *)(dst + offset);
-  }
-}
-
-// zero 0-15 bytes
-static inline void poly1305_block_zero(uint8_t *dst, size_t bytes) {
-  if (bytes & 8) {
-    *(uint64_t *)dst = 0;
-    dst += 8;
-  }
-  if (bytes & 4) {
-    *(uint32_t *)dst = 0;
-    dst += 4;
-  }
-  if (bytes & 2) {
-    *(uint16_t *)dst = 0;
-    dst += 2;
-  }
-  if (bytes & 1) {
-    *(uint8_t *)dst = 0;
-  }
-}
-
 static inline size_t poly1305_min(size_t a, size_t b) {
   return (a < b) ? a : b;
 }
@@ -721,7 +670,7 @@
       bytes -= 32;
     } else {
       want = poly1305_min(32 - st->leftover, bytes);
-      poly1305_block_copy(st->buffer + st->leftover, m, want);
+      OPENSSL_memcpy(st->buffer + st->leftover, m, want);
       bytes -= want;
       m += want;
       st->leftover += want;
@@ -737,7 +686,7 @@
   // handle leftover
   if (st->leftover) {
     want = poly1305_min(64 - st->leftover, bytes);
-    poly1305_block_copy(st->buffer + st->leftover, m, want);
+    OPENSSL_memcpy(st->buffer + st->leftover, m, want);
     bytes -= want;
     m += want;
     st->leftover += want;
@@ -757,7 +706,7 @@
   }
 
   if (bytes) {
-    poly1305_block_copy(st->buffer + st->leftover, m, bytes);
+    OPENSSL_memcpy(st->buffer + st->leftover, m, bytes);
     st->leftover += bytes;
   }
 }
@@ -833,7 +782,7 @@
   }
 
   m[leftover++] = 1;
-  poly1305_block_zero(m + leftover, 16 - leftover);
+  OPENSSL_memset(m + leftover, 0, 16 - leftover);
   leftover = 16;
 
   t0 = U8TO64_LE(m + 0);
diff --git a/src/include/openssl/ssl.h b/src/include/openssl/ssl.h
index 3540a25..8c36ad5 100644
--- a/src/include/openssl/ssl.h
+++ b/src/include/openssl/ssl.h
@@ -593,6 +593,7 @@
 
 #define TLS1_3_DRAFT_VERSION 0x7f12
 #define TLS1_3_DRAFT21_VERSION 0x7f15
+#define TLS1_3_DRAFT22_VERSION 0x7e04
 #define TLS1_3_EXPERIMENT_VERSION 0x7e01
 #define TLS1_3_EXPERIMENT2_VERSION 0x7e02
 #define TLS1_3_EXPERIMENT3_VERSION 0x7e03
@@ -3255,6 +3256,7 @@
   tls13_experiment2 = 2,
   tls13_experiment3 = 3,
   tls13_draft21 = 4,
+  tls13_draft22 = 5,
 };
 
 // SSL_CTX_set_tls13_variant sets which variant of TLS 1.3 we negotiate. On the
diff --git a/src/ssl/handshake.cc b/src/ssl/handshake.cc
index ed11484..3b446a8 100644
--- a/src/ssl/handshake.cc
+++ b/src/ssl/handshake.cc
@@ -127,6 +127,7 @@
       scts_requested(false),
       needs_psk_binder(false),
       received_hello_retry_request(false),
+      sent_hello_retry_request(false),
       received_custom_extension(false),
       handshake_finalized(false),
       accept_psk_mode(false),
diff --git a/src/ssl/handshake_client.cc b/src/ssl/handshake_client.cc
index f907939..583aceb 100644
--- a/src/ssl/handshake_client.cc
+++ b/src/ssl/handshake_client.cc
@@ -500,6 +500,12 @@
     return ssl_hs_ok;
   }
 
+  ssl->s3->aead_write_ctx->SetVersionIfNullCipher(ssl->session->ssl_version);
+  if (ssl_is_draft22(ssl->session->ssl_version) &&
+      !ssl->method->add_change_cipher_spec(ssl)) {
+    return ssl_hs_error;
+  }
+
   if (!tls13_init_early_key_schedule(hs, ssl->session->master_key,
                                      ssl->session->master_key_length) ||
       !tls13_derive_early_secrets(hs) ||
diff --git a/src/ssl/internal.h b/src/ssl/internal.h
index 55bece9..6c14383 100644
--- a/src/ssl/internal.h
+++ b/src/ssl/internal.h
@@ -396,6 +396,10 @@
 // variant.
 bool ssl_is_draft21(uint16_t version);
 
+// ssl_is_draft22 returns whether the version corresponds to a draft22 TLS 1.3
+// variant.
+bool ssl_is_draft22(uint16_t version);
+
 // ssl_is_resumption_experiment returns whether the version corresponds to a
 // TLS 1.3 resumption experiment.
 bool ssl_is_resumption_experiment(uint16_t version);
@@ -1004,6 +1008,8 @@
 // Channel ID, are all enabled.
 #define SSL_MAX_HANDSHAKE_FLIGHT 7
 
+extern const uint8_t kHelloRetryRequest[SSL3_RANDOM_SIZE];
+
 // ssl_max_handshake_message_len returns the maximum number of bytes permitted
 // in a handshake message for |ssl|.
 size_t ssl_max_handshake_message_len(const SSL *ssl);
@@ -1438,6 +1444,7 @@
   bool needs_psk_binder:1;
 
   bool received_hello_retry_request:1;
+  bool sent_hello_retry_request:1;
 
   bool received_custom_extension:1;
 
diff --git a/src/ssl/ssl_versions.cc b/src/ssl/ssl_versions.cc
index 1f30b41..15b0294 100644
--- a/src/ssl/ssl_versions.cc
+++ b/src/ssl/ssl_versions.cc
@@ -36,6 +36,7 @@
 
     case TLS1_3_DRAFT_VERSION:
     case TLS1_3_DRAFT21_VERSION:
+    case TLS1_3_DRAFT22_VERSION:
     case TLS1_3_EXPERIMENT_VERSION:
     case TLS1_3_EXPERIMENT2_VERSION:
     case TLS1_3_EXPERIMENT3_VERSION:
@@ -60,6 +61,7 @@
 // decreasing preference.
 
 static const uint16_t kTLSVersions[] = {
+    TLS1_3_DRAFT22_VERSION,
     TLS1_3_EXPERIMENT3_VERSION,
     TLS1_3_EXPERIMENT2_VERSION,
     TLS1_3_EXPERIMENT_VERSION,
@@ -109,6 +111,7 @@
   switch (version) {
     case TLS1_3_DRAFT_VERSION:
     case TLS1_3_DRAFT21_VERSION:
+    case TLS1_3_DRAFT22_VERSION:
     case TLS1_3_EXPERIMENT_VERSION:
     case TLS1_3_EXPERIMENT2_VERSION:
     case TLS1_3_EXPERIMENT3_VERSION:
@@ -142,6 +145,7 @@
     // Report TLS 1.3 draft versions as TLS 1.3 in the public API.
     case TLS1_3_DRAFT_VERSION:
     case TLS1_3_DRAFT21_VERSION:
+    case TLS1_3_DRAFT22_VERSION:
     case TLS1_3_EXPERIMENT_VERSION:
     case TLS1_3_EXPERIMENT2_VERSION:
     case TLS1_3_EXPERIMENT3_VERSION:
@@ -157,6 +161,7 @@
 static bool api_version_to_wire(uint16_t *out, uint16_t version) {
   if (version == TLS1_3_DRAFT_VERSION ||
       version == TLS1_3_DRAFT21_VERSION ||
+      version == TLS1_3_DRAFT22_VERSION ||
       version == TLS1_3_EXPERIMENT_VERSION ||
       version == TLS1_3_EXPERIMENT2_VERSION ||
       version == TLS1_3_EXPERIMENT3_VERSION) {
@@ -324,6 +329,8 @@
        version == TLS1_3_EXPERIMENT3_VERSION) ||
       (ssl->tls13_variant == tls13_draft21 &&
        version == TLS1_3_DRAFT21_VERSION) ||
+      (ssl->tls13_variant == tls13_draft22 &&
+       version == TLS1_3_DRAFT22_VERSION) ||
       (ssl->tls13_variant == tls13_default &&
        version == TLS1_3_DRAFT_VERSION)) {
     return true;
@@ -331,13 +338,15 @@
 
   // The server, when not configured at |tls13_default|, should additionally
   // enable all variants, except draft-21 which is implemented solely for QUIC
-  // interop testing and will not be deployed. Currently, this is to implement
-  // the draft-18 vs. experiments field trials. In the future, this will be to
-  // transition cleanly to a future draft-22 which hopefully includes the
-  // deployability fixes.
+  // interop testing and will not be deployed, and draft-22 which will be
+  // enabled once the draft is finalized and ready to be deployed in Chrome.
+  // Currently, this is to implement the draft-18 vs. experiments field trials.
+  // In the future, this will be to transition cleanly to a final draft-22
+  // which hopefully includes the deployability fixes.
   if (ssl->server &&
       ssl->tls13_variant != tls13_default &&
-      version != TLS1_3_DRAFT21_VERSION) {
+      version != TLS1_3_DRAFT21_VERSION &&
+      version != TLS1_3_DRAFT22_VERSION) {
     return true;
   }
 
@@ -389,28 +398,35 @@
 }
 
 bool ssl_is_draft21(uint16_t version) {
-  return version == TLS1_3_DRAFT21_VERSION;
+  return version == TLS1_3_DRAFT21_VERSION || version == TLS1_3_DRAFT22_VERSION;
+}
+
+bool ssl_is_draft22(uint16_t version) {
+  return version == TLS1_3_DRAFT22_VERSION;
 }
 
 bool ssl_is_resumption_experiment(uint16_t version) {
   return version == TLS1_3_EXPERIMENT_VERSION ||
          version == TLS1_3_EXPERIMENT2_VERSION ||
-         version == TLS1_3_EXPERIMENT3_VERSION;
+         version == TLS1_3_EXPERIMENT3_VERSION ||
+         version == TLS1_3_DRAFT22_VERSION;
 }
 
 bool ssl_is_resumption_variant(enum tls13_variant_t variant) {
   return variant == tls13_experiment || variant == tls13_experiment2 ||
-         variant == tls13_experiment3;
+         variant == tls13_experiment3 || variant == tls13_draft22;
 }
 
 bool ssl_is_resumption_client_ccs_experiment(uint16_t version) {
   return version == TLS1_3_EXPERIMENT_VERSION ||
-         version == TLS1_3_EXPERIMENT2_VERSION;
+         version == TLS1_3_EXPERIMENT2_VERSION ||
+         version == TLS1_3_DRAFT22_VERSION;
 }
 
 bool ssl_is_resumption_record_version_experiment(uint16_t version) {
   return version == TLS1_3_EXPERIMENT2_VERSION ||
-         version == TLS1_3_EXPERIMENT3_VERSION;
+         version == TLS1_3_EXPERIMENT3_VERSION ||
+         version == TLS1_3_DRAFT22_VERSION;
 }
 
 }  // namespace bssl
diff --git a/src/ssl/test/runner/common.go b/src/ssl/test/runner/common.go
index 9e0deef..4564b0f 100644
--- a/src/ssl/test/runner/common.go
+++ b/src/ssl/test/runner/common.go
@@ -38,6 +38,7 @@
 	tls13ExperimentVersion  = 0x7e01
 	tls13Experiment2Version = 0x7e02
 	tls13Experiment3Version = 0x7e03
+	tls13Draft22Version     = 0x7e04
 )
 
 const (
@@ -46,10 +47,12 @@
 	TLS13Experiment2 = 2
 	TLS13Experiment3 = 3
 	TLS13Draft21     = 4
+	TLS13Draft22     = 5
 )
 
 var allTLSWireVersions = []uint16{
 	tls13DraftVersion,
+	tls13Draft22Version,
 	tls13Draft21Version,
 	tls13Experiment3Version,
 	tls13Experiment2Version,
@@ -148,6 +151,12 @@
 	scsvRenegotiation uint16 = 0x00ff
 )
 
+var tls13HelloRetryRequest = []uint8{
+	0xcf, 0x21, 0xad, 0x74, 0xe5, 0x9a, 0x61, 0x11, 0xbe, 0x1d, 0x8c,
+	0x02, 0x1e, 0x65, 0xb8, 0x91, 0xc2, 0xa2, 0x11, 0x16, 0x7a, 0xbb,
+	0x8c, 0x5e, 0x07, 0x9e, 0x09, 0xe2, 0xc8, 0xa8, 0x33, 0x9c,
+}
+
 // CurveID is the type of a TLS identifier for an elliptic curve. See
 // http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-8
 type CurveID uint16
@@ -619,6 +628,10 @@
 	// messages.
 	FragmentAcrossChangeCipherSpec bool
 
+	// SendExtraChangeCipherSpec causes the implementation to send extra
+	// ChangeCipherSpec messages.
+	SendExtraChangeCipherSpec int
+
 	// SendUnencryptedFinished, if true, causes the Finished message to be
 	// send unencrypted before ChangeCipherSpec rather than after it.
 	SendUnencryptedFinished bool
@@ -1605,7 +1618,7 @@
 		switch vers {
 		case VersionSSL30, VersionTLS10, VersionTLS11, VersionTLS12:
 			return vers, true
-		case tls13DraftVersion, tls13Draft21Version, tls13ExperimentVersion, tls13Experiment2Version, tls13Experiment3Version:
+		case tls13DraftVersion, tls13Draft22Version, tls13Draft21Version, tls13ExperimentVersion, tls13Experiment2Version, tls13Experiment3Version:
 			return VersionTLS13, true
 		}
 	}
@@ -1614,19 +1627,27 @@
 }
 
 func isDraft21(vers uint16) bool {
-	return vers == tls13Draft21Version
+	return vers == tls13Draft21Version || vers == tls13Draft22Version
+}
+
+func isDraft22(vers uint16) bool {
+	return vers == tls13Draft22Version
 }
 
 func isResumptionExperiment(vers uint16) bool {
-	return vers == tls13ExperimentVersion || vers == tls13Experiment2Version || vers == tls13Experiment3Version
+	return vers == tls13ExperimentVersion || vers == tls13Experiment2Version || vers == tls13Experiment3Version || vers == tls13Draft22Version
 }
 
 func isResumptionClientCCSExperiment(vers uint16) bool {
-	return vers == tls13ExperimentVersion || vers == tls13Experiment2Version
+	return vers == tls13ExperimentVersion || vers == tls13Experiment2Version || vers == tls13Draft22Version
 }
 
 func isResumptionRecordVersionExperiment(vers uint16) bool {
-	return vers == tls13Experiment2Version || vers == tls13Experiment3Version
+	return vers == tls13Experiment2Version || vers == tls13Experiment3Version || vers == tls13Draft22Version
+}
+
+func isResumptionRecordVersionVariant(variant int) bool {
+	return variant == TLS13Experiment2 || variant == TLS13Experiment3 || variant == TLS13Draft22
 }
 
 // isSupportedVersion checks if the specified wire version is acceptable. If so,
@@ -1636,6 +1657,7 @@
 	if (c.TLS13Variant != TLS13Experiment && wireVers == tls13ExperimentVersion) ||
 		(c.TLS13Variant != TLS13Experiment2 && wireVers == tls13Experiment2Version) ||
 		(c.TLS13Variant != TLS13Experiment3 && wireVers == tls13Experiment3Version) ||
+		(c.TLS13Variant != TLS13Draft22 && wireVers == tls13Draft22Version) ||
 		(c.TLS13Variant != TLS13Draft21 && wireVers == tls13Draft21Version) ||
 		(c.TLS13Variant != TLS13Default && wireVers == tls13DraftVersion) {
 		return 0, false
diff --git a/src/ssl/test/runner/conn.go b/src/ssl/test/runner/conn.go
index 6a2c59c..5359462 100644
--- a/src/ssl/test/runner/conn.go
+++ b/src/ssl/test/runner/conn.go
@@ -39,6 +39,7 @@
 	vers                 uint16     // TLS version
 	haveVers             bool       // version has been negotiated
 	config               *Config    // configuration passed to constructor
+	hadHelloRetryRequest bool
 	handshakeComplete    bool
 	skipEarlyData        bool // On a server, indicates that the client is sending early data that must be skipped over.
 	didResume            bool // whether this connection was a session resumption
@@ -1152,7 +1153,6 @@
 		}
 		if isResumptionRecordVersionExperiment(c.wireVersion) || isResumptionRecordVersionExperiment(c.out.wireVersion) {
 			vers = VersionTLS12
-		} else {
 		}
 
 		if c.config.Bugs.SendRecordVersion != 0 {
@@ -1322,6 +1322,14 @@
 	// so pass in a fresh copy that won't be overwritten.
 	data = append([]byte(nil), data...)
 
+	if data[0] == typeServerHello && len(data) >= 38 {
+		vers := uint16(data[4])<<8 | uint16(data[5])
+		if vers == VersionTLS12 && bytes.Equal(data[6:38], tls13HelloRetryRequest) {
+			m = new(helloRetryRequestMsg)
+			m.(*helloRetryRequestMsg).isServerHello = true
+		}
+	}
+
 	if !m.unmarshal(data) {
 		return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
 	}
@@ -1936,7 +1944,7 @@
 	payload[0] = byte(recordTypeApplicationData)
 	payload[1] = 3
 	payload[2] = 1
-	if c.config.TLS13Variant == TLS13Experiment2 || c.config.TLS13Variant == TLS13Experiment3 {
+	if isResumptionRecordVersionVariant(c.config.TLS13Variant) {
 		payload[1] = 3
 		payload[2] = 3
 	}
diff --git a/src/ssl/test/runner/handshake_client.go b/src/ssl/test/runner/handshake_client.go
index ba34647..7c8dbb5 100644
--- a/src/ssl/test/runner/handshake_client.go
+++ b/src/ssl/test/runner/handshake_client.go
@@ -419,6 +419,12 @@
 			earlyLabel = earlyTrafficLabelDraft21
 		}
 
+		if !c.config.Bugs.SkipChangeCipherSpec && isDraft22(session.wireVersion) {
+			c.wireVersion = session.wireVersion
+			c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
+			c.wireVersion = 0
+		}
+
 		earlyTrafficSecret := finishedHash.deriveSecret(earlyLabel)
 		c.useOutTrafficSecret(session.wireVersion, pskCipherSuite, earlyTrafficSecret)
 		for _, earlyData := range c.config.Bugs.SendEarlyData {
@@ -482,6 +488,13 @@
 	helloRetryRequest, haveHelloRetryRequest := msg.(*helloRetryRequestMsg)
 	var secondHelloBytes []byte
 	if haveHelloRetryRequest {
+		c.hadHelloRetryRequest = true
+		if isDraft22(c.wireVersion) {
+			if err := c.readRecord(recordTypeChangeCipherSpec); err != nil {
+				return err
+			}
+		}
+
 		c.out.resetCipher()
 		if len(helloRetryRequest.cookie) > 0 {
 			hello.tls13Cookie = helloRetryRequest.cookie
@@ -761,7 +774,7 @@
 		hs.finishedHash.addEntropy(zeroSecret)
 	}
 
-	if isResumptionExperiment(c.wireVersion) {
+	if isResumptionExperiment(c.wireVersion) && !c.hadHelloRetryRequest {
 		if err := c.readRecord(recordTypeChangeCipherSpec); err != nil {
 			return err
 		}
@@ -979,7 +992,11 @@
 		}
 	}
 
-	if isResumptionClientCCSExperiment(c.wireVersion) {
+	if !c.config.Bugs.SkipChangeCipherSpec && isResumptionClientCCSExperiment(c.wireVersion) && !hs.hello.hasEarlyData {
+		c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
+	}
+
+	for i := 0; i < c.config.Bugs.SendExtraChangeCipherSpec; i++ {
 		c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
 	}
 
diff --git a/src/ssl/test/runner/handshake_messages.go b/src/ssl/test/runner/handshake_messages.go
index aa6b463..d5e3951 100644
--- a/src/ssl/test/runner/handshake_messages.go
+++ b/src/ssl/test/runner/handshake_messages.go
@@ -1406,6 +1406,8 @@
 type helloRetryRequestMsg struct {
 	raw                 []byte
 	vers                uint16
+	isServerHello       bool
+	sessionId           []byte
 	cipherSuite         uint16
 	hasSelectedGroup    bool
 	selectedGroup       CurveID
@@ -1420,11 +1422,25 @@
 	}
 
 	retryRequestMsg := newByteBuilder()
-	retryRequestMsg.addU8(typeHelloRetryRequest)
+	if isDraft22(m.vers) {
+		retryRequestMsg.addU8(typeServerHello)
+	} else {
+		retryRequestMsg.addU8(typeHelloRetryRequest)
+	}
 	retryRequest := retryRequestMsg.addU24LengthPrefixed()
-	retryRequest.addU16(m.vers)
-	if isDraft21(m.vers) {
+
+	if isDraft22(m.vers) {
+		retryRequest.addU16(VersionTLS12)
+		retryRequest.addBytes(tls13HelloRetryRequest)
+		sessionId := retryRequest.addU8LengthPrefixed()
+		sessionId.addBytes(m.sessionId)
 		retryRequest.addU16(m.cipherSuite)
+		retryRequest.addU8(0)
+	} else {
+		retryRequest.addU16(m.vers)
+		if isDraft21(m.vers) {
+			retryRequest.addU16(m.cipherSuite)
+		}
 	}
 	extensions := retryRequest.addU16LengthPrefixed()
 
@@ -1434,6 +1450,11 @@
 	}
 
 	for i := 0; i < count; i++ {
+		if isDraft22(m.vers) {
+			extensions.addU16(extensionSupportedVersions)
+			extensions.addU16(2) // Length
+			extensions.addU16(m.vers)
+		}
 		if m.hasSelectedGroup {
 			extensions.addU16(extensionKeyShare)
 			extensions.addU16(2) // length
@@ -1461,9 +1482,25 @@
 	}
 	m.vers = uint16(data[4])<<8 | uint16(data[5])
 	data = data[6:]
-	if isDraft21(m.vers) {
+	if m.isServerHello {
+		if len(data) < 33 {
+			return false
+		}
+		data = data[32:] // Random
+		sessionIdLen := int(data[0])
+		if sessionIdLen > 32 || len(data) < 1+sessionIdLen+3 {
+			return false
+		}
+		m.sessionId = data[1 : 1+sessionIdLen]
+		data = data[1+sessionIdLen:]
 		m.cipherSuite = uint16(data[0])<<8 | uint16(data[1])
 		data = data[2:]
+		data = data[1:] // Compression Method
+	} else {
+		if isDraft21(m.vers) {
+			m.cipherSuite = uint16(data[0])<<8 | uint16(data[1])
+			data = data[2:]
+		}
 	}
 	extLen := int(data[0])<<8 | int(data[1])
 	data = data[2:]
@@ -1482,6 +1519,11 @@
 		}
 
 		switch extension {
+		case extensionSupportedVersions:
+			if length != 2 || !m.isServerHello {
+				return false
+			}
+			m.vers = uint16(data[0])<<8 | uint16(data[1])
 		case extensionKeyShare:
 			if length != 2 {
 				return false
diff --git a/src/ssl/test/runner/handshake_server.go b/src/ssl/test/runner/handshake_server.go
index dd6f48f..2513a00 100644
--- a/src/ssl/test/runner/handshake_server.go
+++ b/src/ssl/test/runner/handshake_server.go
@@ -526,6 +526,7 @@
 	}
 	helloRetryRequest := &helloRetryRequestMsg{
 		vers:                c.wireVersion,
+		sessionId:           hs.clientHello.sessionId,
 		cipherSuite:         cipherSuite,
 		duplicateExtensions: config.Bugs.DuplicateHelloRetryRequestExtensions,
 	}
@@ -587,6 +588,10 @@
 		c.writeRecord(recordTypeHandshake, helloRetryRequest.marshal())
 		c.flushHandshake()
 
+		if !c.config.Bugs.SkipChangeCipherSpec && isDraft22(c.wireVersion) {
+			c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
+		}
+
 		if hs.clientHello.hasEarlyData {
 			c.skipEarlyData = true
 		}
@@ -686,6 +691,12 @@
 				earlyLabel = earlyTrafficLabelDraft21
 			}
 
+			if isDraft22(c.wireVersion) {
+				if err := c.readRecord(recordTypeChangeCipherSpec); err != nil {
+					return err
+				}
+			}
+
 			earlyTrafficSecret := hs.finishedHash.deriveSecret(earlyLabel)
 			if err := c.useInTrafficSecret(c.wireVersion, hs.suite, earlyTrafficSecret); err != nil {
 				return err
@@ -782,7 +793,11 @@
 	}
 	c.flushHandshake()
 
-	if isResumptionExperiment(c.wireVersion) {
+	if !c.config.Bugs.SkipChangeCipherSpec && isResumptionExperiment(c.wireVersion) && !sendHelloRetryRequest {
+		c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
+	}
+
+	for i := 0; i < c.config.Bugs.SendExtraChangeCipherSpec; i++ {
 		c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
 	}
 
@@ -982,7 +997,7 @@
 		}
 	}
 
-	if isResumptionClientCCSExperiment(c.wireVersion) && !c.skipEarlyData {
+	if isResumptionClientCCSExperiment(c.wireVersion) && !c.skipEarlyData && !encryptedExtensions.extensions.hasEarlyData {
 		if err := c.readRecord(recordTypeChangeCipherSpec); err != nil {
 			return err
 		}
diff --git a/src/ssl/test/runner/runner.go b/src/ssl/test/runner/runner.go
index ce50fa8..57bc20c 100644
--- a/src/ssl/test/runner/runner.go
+++ b/src/ssl/test/runner/runner.go
@@ -1312,6 +1312,13 @@
 		tls13Variant: TLS13Draft21,
 	},
 	{
+		name:         "TLS13Draft22",
+		version:      VersionTLS13,
+		excludeFlag:  "-no-tls13",
+		versionWire:  tls13Draft22Version,
+		tls13Variant: TLS13Draft22,
+	},
+	{
 		name:         "TLS13Experiment",
 		version:      VersionTLS13,
 		excludeFlag:  "-no-tls13",
@@ -4160,6 +4167,37 @@
 		})
 
 		tests = append(tests, testCase{
+			name: "TLS13Draft22-HelloRetryRequest-Client",
+			config: Config{
+				MaxVersion: VersionTLS13,
+				MinVersion: VersionTLS13,
+				// P-384 requires a HelloRetryRequest against BoringSSL's default
+				// configuration. Assert this with ExpectMissingKeyShare.
+				CurvePreferences: []CurveID{CurveP384},
+				Bugs: ProtocolBugs{
+					ExpectMissingKeyShare: true,
+				},
+			},
+			tls13Variant: TLS13Draft22,
+			// Cover HelloRetryRequest during an ECDHE-PSK resumption.
+			resumeSession: true,
+		})
+
+		tests = append(tests, testCase{
+			testType: serverTest,
+			name:     "TLS13Draft22-HelloRetryRequest-Server",
+			config: Config{
+				MaxVersion: VersionTLS13,
+				MinVersion: VersionTLS13,
+				// Require a HelloRetryRequest for every curve.
+				DefaultCurves: []CurveID{},
+			},
+			tls13Variant: TLS13Draft22,
+			// Cover HelloRetryRequest during an ECDHE-PSK resumption.
+			resumeSession: true,
+		})
+
+		tests = append(tests, testCase{
 			testType: clientTest,
 			name:     "TLS13-EarlyData-TooMuchData-Client",
 			config: Config{
@@ -5177,7 +5215,7 @@
 				if expectedVersion == VersionTLS13 && runnerVers.tls13Variant != shimVers.tls13Variant {
 					expectedClientVersion = VersionTLS12
 					expectedServerVersion = VersionTLS12
-					if shimVers.tls13Variant != TLS13Default && runnerVers.tls13Variant != TLS13Draft21 {
+					if shimVers.tls13Variant != TLS13Default && runnerVers.tls13Variant != TLS13Draft21 && runnerVers.tls13Variant != TLS13Draft22 {
 						expectedServerVersion = VersionTLS13
 					}
 				}
@@ -5196,7 +5234,7 @@
 				serverVers := expectedServerVersion
 				if expectedServerVersion >= VersionTLS13 {
 					serverVers = VersionTLS10
-					if runnerVers.tls13Variant == TLS13Experiment2 || runnerVers.tls13Variant == TLS13Experiment3 {
+					if runnerVers.tls13Variant == TLS13Experiment2 || runnerVers.tls13Variant == TLS13Experiment3 || runnerVers.tls13Variant == TLS13Draft22 {
 						serverVers = VersionTLS12
 					}
 				}
@@ -11734,6 +11772,58 @@
 		expectedError: ":UNEXPECTED_EXTENSION:",
 	})
 
+	testCases = append(testCases, testCase{
+		testType: clientTest,
+		name: "TLS13Draft22-SkipChangeCipherSpec-Client",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				SkipChangeCipherSpec: true,
+			},
+		},
+		tls13Variant: TLS13Draft22,
+	})
+
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name: "TLS13Draft22-SkipChangeCipherSpec-Server",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				SkipChangeCipherSpec: true,
+			},
+		},
+		tls13Variant: TLS13Draft22,
+	})
+
+	testCases = append(testCases, testCase{
+		testType: clientTest,
+		name: "TLS13Draft22-TooManyChangeCipherSpec-Client",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				SendExtraChangeCipherSpec: 33,
+			},
+		},
+		tls13Variant: TLS13Draft22,
+		shouldFail:       true,
+		expectedError:    ":TOO_MANY_EMPTY_FRAGMENTS:",
+	})
+
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name: "TLS13Draft22-TooManyChangeCipherSpec-Server",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				SendExtraChangeCipherSpec: 33,
+			},
+		},
+		tls13Variant: TLS13Draft22,
+		shouldFail:       true,
+		expectedError:    ":TOO_MANY_EMPTY_FRAGMENTS:",
+	})
+
 	fooString := "foo"
 	barString := "bar"
 
diff --git a/src/ssl/tls13_both.cc b/src/ssl/tls13_both.cc
index 5796bf4..57acbcb 100644
--- a/src/ssl/tls13_both.cc
+++ b/src/ssl/tls13_both.cc
@@ -37,6 +37,12 @@
 // without being able to return application data.
 static const uint8_t kMaxKeyUpdates = 32;
 
+const uint8_t kHelloRetryRequest[SSL3_RANDOM_SIZE] = {
+    0xcf, 0x21, 0xad, 0x74, 0xe5, 0x9a, 0x61, 0x11, 0xbe, 0x1d, 0x8c,
+    0x02, 0x1e, 0x65, 0xb8, 0x91, 0xc2, 0xa2, 0x11, 0x16, 0x7a, 0xbb,
+    0x8c, 0x5e, 0x07, 0x9e, 0x09, 0xe2, 0xc8, 0xa8, 0x33, 0x9c,
+};
+
 bool tls13_get_cert_verify_signature_input(
     SSL_HANDSHAKE *hs, Array<uint8_t> *out,
     enum ssl_cert_verify_context_t cert_verify_context) {
diff --git a/src/ssl/tls13_client.cc b/src/ssl/tls13_client.cc
index 9c09309..0013e61 100644
--- a/src/ssl/tls13_client.cc
+++ b/src/ssl/tls13_client.cc
@@ -36,7 +36,6 @@
   state_read_hello_retry_request = 0,
   state_send_second_client_hello,
   state_read_server_hello,
-  state_process_change_cipher_spec,
   state_read_encrypted_extensions,
   state_read_certificate_request,
   state_read_server_certificate,
@@ -57,23 +56,52 @@
   if (!ssl->method->get_message(ssl, &msg)) {
     return ssl_hs_read_message;
   }
-  if (msg.type != SSL3_MT_HELLO_RETRY_REQUEST) {
-    hs->tls13_state = state_read_server_hello;
-    return ssl_hs_ok;
-  }
 
-  CBS body = msg.body, extensions;
-  uint16_t server_version, cipher_suite = 0;
-  if (!CBS_get_u16(&body, &server_version) ||
-      (ssl_is_draft21(ssl->version) &&
-       !CBS_get_u16(&body, &cipher_suite)) ||
-      !CBS_get_u16_length_prefixed(&body, &extensions) ||
-      // HelloRetryRequest may not be empty.
-      CBS_len(&extensions) == 0 ||
-      CBS_len(&body) != 0) {
-    OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
-    ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
-    return ssl_hs_error;
+  CBS extensions;
+  uint16_t cipher_suite = 0;
+  if (ssl_is_draft22(ssl->version)) {
+    if (!ssl_check_message_type(ssl, msg, SSL3_MT_SERVER_HELLO)) {
+      return ssl_hs_error;
+    }
+
+    CBS body = msg.body, server_random, session_id;
+    uint16_t server_version;
+    if (!CBS_get_u16(&body, &server_version) ||
+        !CBS_get_bytes(&body, &server_random, SSL3_RANDOM_SIZE) ||
+        !CBS_get_u8_length_prefixed(&body, &session_id) ||
+        !CBS_get_u16(&body, &cipher_suite) ||
+        !CBS_skip(&body, 1) ||
+        !CBS_get_u16_length_prefixed(&body, &extensions) ||
+        CBS_len(&extensions) == 0 ||
+        CBS_len(&body) != 0) {
+      OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+      ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+      return ssl_hs_error;
+    }
+
+    if (!CBS_mem_equal(&server_random, kHelloRetryRequest, SSL3_RANDOM_SIZE)) {
+      hs->tls13_state = state_read_server_hello;
+      return ssl_hs_ok;
+    }
+  } else {
+    if (msg.type != SSL3_MT_HELLO_RETRY_REQUEST) {
+      hs->tls13_state = state_read_server_hello;
+      return ssl_hs_ok;
+    }
+
+    CBS body = msg.body;
+    uint16_t server_version;
+    if (!CBS_get_u16(&body, &server_version) ||
+        (ssl_is_draft21(ssl->version) &&
+         !CBS_get_u16(&body, &cipher_suite)) ||
+        !CBS_get_u16_length_prefixed(&body, &extensions) ||
+        // HelloRetryRequest may not be empty.
+        CBS_len(&extensions) == 0 ||
+        CBS_len(&body) != 0) {
+      OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+      ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+      return ssl_hs_error;
+    }
   }
 
   if (ssl_is_draft21(ssl->version)) {
@@ -96,11 +124,13 @@
   }
 
 
-  bool have_cookie, have_key_share;
-  CBS cookie, key_share;
+  bool have_cookie, have_key_share, have_supported_versions;
+  CBS cookie, key_share, supported_versions;
   const SSL_EXTENSION_TYPE ext_types[] = {
       {TLSEXT_TYPE_key_share, &have_key_share, &key_share},
       {TLSEXT_TYPE_cookie, &have_cookie, &cookie},
+      {TLSEXT_TYPE_supported_versions, &have_supported_versions,
+       &supported_versions},
   };
 
   uint8_t alert = SSL_AD_DECODE_ERROR;
@@ -111,6 +141,11 @@
     return ssl_hs_error;
   }
 
+  if (!ssl_is_draft22(ssl->version) && have_supported_versions) {
+    OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
+    ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION);
+    return ssl_hs_error;
+  }
   if (have_cookie) {
     CBS cookie_value;
     if (!CBS_get_u16_length_prefixed(&cookie, &cookie_value) ||
@@ -359,20 +394,8 @@
 
   if (!tls13_advance_key_schedule(hs, dhe_secret.data(), dhe_secret.size()) ||
       !ssl_hash_message(hs, msg) ||
-      !tls13_derive_handshake_secrets(hs)) {
-    return ssl_hs_error;
-  }
-
-  ssl->method->next_message(ssl);
-  hs->tls13_state = state_process_change_cipher_spec;
-  return ssl_is_resumption_experiment(ssl->version)
-             ? ssl_hs_read_change_cipher_spec
-             : ssl_hs_ok;
-}
-
-static enum ssl_hs_wait_t do_process_change_cipher_spec(SSL_HANDSHAKE *hs) {
-  SSL *const ssl = hs->ssl;
-  if (!tls13_set_traffic_key(ssl, evp_aead_open, hs->server_handshake_secret,
+      !tls13_derive_handshake_secrets(hs) ||
+      !tls13_set_traffic_key(ssl, evp_aead_open, hs->server_handshake_secret,
                              hs->hash_len)) {
     return ssl_hs_error;
   }
@@ -388,6 +411,7 @@
     }
   }
 
+  ssl->method->next_message(ssl);
   hs->tls13_state = state_read_encrypted_extensions;
   return ssl_hs_ok;
 }
@@ -642,9 +666,7 @@
   }
 
   if (hs->early_data_offered) {
-    if ((ssl_is_resumption_client_ccs_experiment(ssl->version) &&
-         !ssl->method->add_change_cipher_spec(ssl)) ||
-        !tls13_set_traffic_key(ssl, evp_aead_seal, hs->client_handshake_secret,
+    if (!tls13_set_traffic_key(ssl, evp_aead_seal, hs->client_handshake_secret,
                                hs->hash_len)) {
       return ssl_hs_error;
     }
@@ -767,9 +789,6 @@
       case state_read_server_hello:
         ret = do_read_server_hello(hs);
         break;
-      case state_process_change_cipher_spec:
-        ret = do_process_change_cipher_spec(hs);
-        break;
       case state_read_encrypted_extensions:
         ret = do_read_encrypted_extensions(hs);
         break;
@@ -824,8 +843,6 @@
       return "TLS 1.3 client send_second_client_hello";
     case state_read_server_hello:
       return "TLS 1.3 client read_server_hello";
-    case state_process_change_cipher_spec:
-      return "TLS 1.3 client process_change_cipher_spec";
     case state_read_encrypted_extensions:
       return "TLS 1.3 client read_encrypted_extensions";
     case state_read_certificate_request:
diff --git a/src/ssl/tls13_server.cc b/src/ssl/tls13_server.cc
index 9afd0d4..1040ace 100644
--- a/src/ssl/tls13_server.cc
+++ b/src/ssl/tls13_server.cc
@@ -47,7 +47,6 @@
   state_send_server_certificate_verify,
   state_send_server_finished,
   state_read_second_client_flight,
-  state_process_change_cipher_spec,
   state_process_end_of_early_data,
   state_read_client_certificate,
   state_read_client_certificate_verify,
@@ -490,23 +489,55 @@
 
 static enum ssl_hs_wait_t do_send_hello_retry_request(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
-  ScopedCBB cbb;
-  CBB body, extensions;
-  uint16_t group_id;
-  if (!ssl->method->init_message(ssl, cbb.get(), &body,
-                                 SSL3_MT_HELLO_RETRY_REQUEST) ||
-      !CBB_add_u16(&body, ssl->version) ||
-      (ssl_is_draft21(ssl->version) &&
-       !CBB_add_u16(&body, ssl_cipher_get_value(hs->new_cipher))) ||
-      !tls1_get_shared_group(hs, &group_id) ||
-      !CBB_add_u16_length_prefixed(&body, &extensions) ||
-      !CBB_add_u16(&extensions, TLSEXT_TYPE_key_share) ||
-      !CBB_add_u16(&extensions, 2 /* length */) ||
-      !CBB_add_u16(&extensions, group_id) ||
-      !ssl_add_message_cbb(ssl, cbb.get())) {
-    return ssl_hs_error;
+
+
+  if (ssl_is_draft22(ssl->version)) {
+    ScopedCBB cbb;
+    CBB body, session_id, extensions;
+    uint16_t group_id;
+    if (!ssl->method->init_message(ssl, cbb.get(), &body,
+                                   SSL3_MT_SERVER_HELLO) ||
+        !CBB_add_u16(&body, TLS1_2_VERSION) ||
+        !CBB_add_bytes(&body, kHelloRetryRequest, SSL3_RANDOM_SIZE) ||
+        !CBB_add_u8_length_prefixed(&body, &session_id) ||
+        !CBB_add_bytes(&session_id, hs->session_id, hs->session_id_len) ||
+        !CBB_add_u16(&body, ssl_cipher_get_value(hs->new_cipher)) ||
+        !CBB_add_u8(&body, 0 /* no compression */) ||
+        !tls1_get_shared_group(hs, &group_id) ||
+        !CBB_add_u16_length_prefixed(&body, &extensions) ||
+        !CBB_add_u16(&extensions, TLSEXT_TYPE_supported_versions) ||
+        !CBB_add_u16(&extensions, 2 /* length */) ||
+        !CBB_add_u16(&extensions, ssl->version) ||
+        !CBB_add_u16(&extensions, TLSEXT_TYPE_key_share) ||
+        !CBB_add_u16(&extensions, 2 /* length */) ||
+        !CBB_add_u16(&extensions, group_id) ||
+        !ssl_add_message_cbb(ssl, cbb.get())) {
+      return ssl_hs_error;
+    }
+
+    if (!ssl->method->add_change_cipher_spec(ssl)) {
+      return ssl_hs_error;
+    }
+  } else {
+    ScopedCBB cbb;
+    CBB body, extensions;
+    uint16_t group_id;
+    if (!ssl->method->init_message(ssl, cbb.get(), &body,
+                                   SSL3_MT_HELLO_RETRY_REQUEST) ||
+        !CBB_add_u16(&body, ssl->version) ||
+        (ssl_is_draft21(ssl->version) &&
+         !CBB_add_u16(&body, ssl_cipher_get_value(hs->new_cipher))) ||
+        !tls1_get_shared_group(hs, &group_id) ||
+        !CBB_add_u16_length_prefixed(&body, &extensions) ||
+        !CBB_add_u16(&extensions, TLSEXT_TYPE_key_share) ||
+        !CBB_add_u16(&extensions, 2 /* length */) ||
+        !CBB_add_u16(&extensions, group_id) ||
+        !ssl_add_message_cbb(ssl, cbb.get())) {
+      return ssl_hs_error;
+    }
   }
 
+  hs->sent_hello_retry_request = true;
   hs->tls13_state = state_read_second_client_hello;
   return ssl_hs_flush;
 }
@@ -576,6 +607,7 @@
   }
 
   if (ssl_is_resumption_experiment(ssl->version) &&
+      (!ssl_is_draft22(ssl->version) || !hs->sent_hello_retry_request) &&
       !ssl->method->add_change_cipher_spec(ssl)) {
     return ssl_hs_error;
   }
@@ -756,46 +788,35 @@
     hs->can_early_write = true;
     hs->can_early_read = true;
     hs->in_early_data = true;
-    hs->tls13_state = state_process_end_of_early_data;
-    return ssl_hs_read_end_of_early_data;
   }
   hs->tls13_state = state_process_end_of_early_data;
-  return ssl_hs_ok;
+  return ssl->early_data_accepted ? ssl_hs_read_end_of_early_data : ssl_hs_ok;
 }
 
 static enum ssl_hs_wait_t do_process_end_of_early_data(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
-  hs->tls13_state = state_process_change_cipher_spec;
   if (hs->early_data_offered) {
     // If early data was not accepted, the EndOfEarlyData and ChangeCipherSpec
     // message will be in the discarded early data.
-    if (!hs->ssl->early_data_accepted) {
-      return ssl_hs_ok;
-    }
-    if (ssl_is_draft21(ssl->version)) {
-      SSLMessage msg;
-      if (!ssl->method->get_message(ssl, &msg)) {
-        return ssl_hs_read_message;
-      }
+    if (hs->ssl->early_data_accepted) {
+      if (ssl_is_draft21(ssl->version)) {
+        SSLMessage msg;
+        if (!ssl->method->get_message(ssl, &msg)) {
+          return ssl_hs_read_message;
+        }
 
-      if (!ssl_check_message_type(ssl, msg, SSL3_MT_END_OF_EARLY_DATA)) {
-        return ssl_hs_error;
+        if (!ssl_check_message_type(ssl, msg, SSL3_MT_END_OF_EARLY_DATA)) {
+          return ssl_hs_error;
+        }
+        if (CBS_len(&msg.body) != 0) {
+          ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+          OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+          return ssl_hs_error;
+        }
+        ssl->method->next_message(ssl);
       }
-      if (CBS_len(&msg.body) != 0) {
-        ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
-        OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
-        return ssl_hs_error;
-      }
-      ssl->method->next_message(ssl);
     }
   }
-  return ssl_is_resumption_client_ccs_experiment(hs->ssl->version)
-             ? ssl_hs_read_change_cipher_spec
-             : ssl_hs_ok;
-}
-
-static enum ssl_hs_wait_t do_process_change_cipher_spec(SSL_HANDSHAKE *hs) {
-  SSL *const ssl = hs->ssl;
   if (!tls13_set_traffic_key(ssl, evp_aead_open, hs->client_handshake_secret,
                              hs->hash_len)) {
     return ssl_hs_error;
@@ -973,9 +994,6 @@
       case state_process_end_of_early_data:
         ret = do_process_end_of_early_data(hs);
         break;
-      case state_process_change_cipher_spec:
-        ret = do_process_change_cipher_spec(hs);
-        break;
       case state_read_client_certificate:
         ret = do_read_client_certificate(hs);
         break;
@@ -1028,8 +1046,6 @@
       return "TLS 1.3 server send_server_finished";
     case state_read_second_client_flight:
       return "TLS 1.3 server read_second_client_flight";
-    case state_process_change_cipher_spec:
-      return "TLS 1.3 server process_change_cipher_spec";
     case state_process_end_of_early_data:
       return "TLS 1.3 server process_end_of_early_data";
     case state_read_client_certificate:
diff --git a/src/ssl/tls_record.cc b/src/ssl/tls_record.cc
index a062012..7e8e968 100644
--- a/src/ssl/tls_record.cc
+++ b/src/ssl/tls_record.cc
@@ -247,6 +247,21 @@
 
   *out_consumed = in.size() - CBS_len(&cbs);
 
+  if (ssl->s3->have_version &&
+      ssl_is_resumption_experiment(ssl->version) &&
+      SSL_in_init(ssl) &&
+      type == SSL3_RT_CHANGE_CIPHER_SPEC &&
+      ciphertext_len == 1 &&
+      CBS_data(&body)[0] == 1) {
+    ssl->s3->empty_record_count++;
+    if (ssl->s3->empty_record_count > kMaxEmptyRecords) {
+      OPENSSL_PUT_ERROR(SSL, SSL_R_TOO_MANY_EMPTY_FRAGMENTS);
+      *out_alert = SSL_AD_UNEXPECTED_MESSAGE;
+      return ssl_open_record_error;
+    }
+    return ssl_open_record_discard;
+  }
+
   // Skip early data received when expecting a second ClientHello if we rejected
   // 0RTT.
   if (ssl->s3->skip_early_data &&
diff --git a/src/third_party/android-cmake/METADATA b/src/third_party/android-cmake/METADATA
index 0ba6817..bddb4d3 100644
--- a/src/third_party/android-cmake/METADATA
+++ b/src/third_party/android-cmake/METADATA
@@ -5,7 +5,7 @@
 
 third_party {
   url {
-    type: HOMEPAGE
+    type: GIT
     value: "https://github.com/taka-no-me/android-cmake/"
   }
   version: "556cc14296c226f753a3778d99d8b60778b7df4f"
diff --git a/src/third_party/fiat/METADATA b/src/third_party/fiat/METADATA
index bae0285..8158c30 100644
--- a/src/third_party/fiat/METADATA
+++ b/src/third_party/fiat/METADATA
@@ -1,10 +1,10 @@
 name: "fiat"
 description:
-    "Fiat-Crypto: Synthesizing Correct-by-Construction Code for Cryptographic Primitives".
+    "Fiat-Crypto: Synthesizing Correct-by-Construction Code for Cryptographic Primitives."
 
 third_party {
   url {
-    type: HOMEPAGE
+    type: GIT
     value: "https://github.com/mit-plv/fiat-crypto"
   }
   version: "6c4d4afb26de639718fcac39094353ca7feec365"
diff --git a/src/tool/client.cc b/src/tool/client.cc
index 873cea0..57e1b6e 100644
--- a/src/tool/client.cc
+++ b/src/tool/client.cc
@@ -121,7 +121,8 @@
         "verification is required.",
     },
     {
-        "-early-data", kOptionalArgument, "Allow early data",
+        "-early-data", kOptionalArgument, "Enable early data. The argument to "
+        "this flag is the early data to send.",
     },
     {
         "-tls13-variant", kOptionalArgument,
@@ -339,6 +340,10 @@
     *out = tls13_experiment3;
     return true;
   }
+  if (in == "draft22") {
+    *out = tls13_draft22;
+    return true;
+  }
   return false;
 }
 
diff --git a/src/tool/transport_common.cc b/src/tool/transport_common.cc
index 1a80678..55f2059 100644
--- a/src/tool/transport_common.cc
+++ b/src/tool/transport_common.cc
@@ -284,8 +284,9 @@
     BIO_printf(bio, "  SCT list: %s\n", sct_list_len > 0 ? "yes" : "no");
   }
 
-  BIO_printf(bio, "  Early data: %s\n",
-             SSL_early_data_accepted(ssl) ? "yes" : "no");
+  BIO_printf(
+      bio, "  Early data: %s\n",
+      (SSL_early_data_accepted(ssl) || SSL_in_early_data(ssl)) ? "yes" : "no");
 
   // Print the server cert subject and issuer names.
   bssl::UniquePtr<X509> peer(SSL_get_peer_certificate(ssl));
diff --git a/win-x86_64/crypto/fipsmodule/aesni-gcm-x86_64.asm b/win-x86_64/crypto/fipsmodule/aesni-gcm-x86_64.asm
index 741a9e4..63bcd48 100644
--- a/win-x86_64/crypto/fipsmodule/aesni-gcm-x86_64.asm
+++ b/win-x86_64/crypto/fipsmodule/aesni-gcm-x86_64.asm
@@ -8,6 +8,7 @@
 
 ALIGN	32
 _aesni_ctr32_ghash_6x:
+
 	vmovdqu	xmm2,XMMWORD[32+r11]
 	sub	rdx,6
 	vpxor	xmm4,xmm4,xmm4
@@ -333,6 +334,7 @@
 
 	DB	0F3h,0C3h		;repret
 
+
 global	aesni_gcm_decrypt
 
 ALIGN	32
@@ -349,6 +351,7 @@
 	mov	r9,QWORD[48+rsp]
 
 
+
 	xor	r10,r10
 
 
@@ -357,12 +360,19 @@
 	jb	NEAR $L$gcm_dec_abort
 
 	lea	rax,[rsp]
+
 	push	rbx
+
 	push	rbp
+
 	push	r12
+
 	push	r13
+
 	push	r14
+
 	push	r15
+
 	lea	rsp,[((-168))+rsp]
 	movaps	XMMWORD[(-216)+rax],xmm6
 	movaps	XMMWORD[(-200)+rax],xmm7
@@ -454,21 +464,30 @@
 	movaps	xmm14,XMMWORD[((-88))+rax]
 	movaps	xmm15,XMMWORD[((-72))+rax]
 	mov	r15,QWORD[((-48))+rax]
+
 	mov	r14,QWORD[((-40))+rax]
+
 	mov	r13,QWORD[((-32))+rax]
+
 	mov	r12,QWORD[((-24))+rax]
+
 	mov	rbp,QWORD[((-16))+rax]
+
 	mov	rbx,QWORD[((-8))+rax]
+
 	lea	rsp,[rax]
+
 $L$gcm_dec_abort:
 	mov	rax,r10
 	mov	rdi,QWORD[8+rsp]	;WIN64 epilogue
 	mov	rsi,QWORD[16+rsp]
 	DB	0F3h,0C3h		;repret
+
 $L$SEH_end_aesni_gcm_decrypt:
 
 ALIGN	32
 _aesni_ctr32_6x:
+
 	vmovdqu	xmm4,XMMWORD[((0-128))+rcx]
 	vmovdqu	xmm2,XMMWORD[32+r11]
 	lea	r13,[((-1))+rbp]
@@ -557,6 +576,7 @@
 	jmp	NEAR $L$oop_ctr32
 
 
+
 global	aesni_gcm_encrypt
 
 ALIGN	32
@@ -573,6 +593,7 @@
 	mov	r9,QWORD[48+rsp]
 
 
+
 	xor	r10,r10
 
 
@@ -582,12 +603,19 @@
 	jb	NEAR $L$gcm_enc_abort
 
 	lea	rax,[rsp]
+
 	push	rbx
+
 	push	rbp
+
 	push	r12
+
 	push	r13
+
 	push	r14
+
 	push	r15
+
 	lea	rsp,[((-168))+rsp]
 	movaps	XMMWORD[(-216)+rax],xmm6
 	movaps	XMMWORD[(-200)+rax],xmm7
@@ -844,17 +872,25 @@
 	movaps	xmm14,XMMWORD[((-88))+rax]
 	movaps	xmm15,XMMWORD[((-72))+rax]
 	mov	r15,QWORD[((-48))+rax]
+
 	mov	r14,QWORD[((-40))+rax]
+
 	mov	r13,QWORD[((-32))+rax]
+
 	mov	r12,QWORD[((-24))+rax]
+
 	mov	rbp,QWORD[((-16))+rax]
+
 	mov	rbx,QWORD[((-8))+rax]
+
 	lea	rsp,[rax]
+
 $L$gcm_enc_abort:
 	mov	rax,r10
 	mov	rdi,QWORD[8+rsp]	;WIN64 epilogue
 	mov	rsi,QWORD[16+rsp]
 	DB	0F3h,0C3h		;repret
+
 $L$SEH_end_aesni_gcm_encrypt:
 ALIGN	64
 $L$bswap_mask: