external/boringssl: Sync to 68f37b7a3f451aa1ca8c93669c024d01f6270ae8.

This includes the following changes:

https://boringssl.googlesource.com/boringssl/+log/3ef7697ed30f28367395a5aafb57a12a19906d96..68f37b7a3f451aa1ca8c93669c024d01f6270ae8

Test: cts-tradefed run cts -m CtsLibcoreOkHttpTestCases -a arm64-v8a
Test: cts-tradefed run cts -m CtsLibcoreTestCases -a arm64-v8a

Change-Id: I296d05afab7470335cdda2442414a858df591f6c
diff --git a/BORINGSSL_REVISION b/BORINGSSL_REVISION
index 9fe48a4..aefa36f 100644
--- a/BORINGSSL_REVISION
+++ b/BORINGSSL_REVISION
@@ -1 +1 @@
-3ef7697ed30f28367395a5aafb57a12a19906d96
+68f37b7a3f451aa1ca8c93669c024d01f6270ae8
diff --git a/err_data.c b/err_data.c
index 001145d..90d1962 100644
--- a/err_data.c
+++ b/err_data.c
@@ -178,42 +178,42 @@
     0x28340c19,
     0x283480ac,
     0x283500ea,
-    0x2c322910,
-    0x2c32a91e,
-    0x2c332930,
-    0x2c33a942,
-    0x2c342956,
-    0x2c34a968,
-    0x2c352983,
-    0x2c35a995,
-    0x2c3629a8,
+    0x2c32295b,
+    0x2c32a969,
+    0x2c33297b,
+    0x2c33a98d,
+    0x2c3429a1,
+    0x2c34a9b3,
+    0x2c3529ce,
+    0x2c35a9e0,
+    0x2c3629f3,
     0x2c36832d,
-    0x2c3729b5,
-    0x2c37a9c7,
-    0x2c3829da,
-    0x2c38a9f1,
-    0x2c3929ff,
-    0x2c39aa0f,
-    0x2c3a2a21,
-    0x2c3aaa35,
-    0x2c3b2a46,
-    0x2c3baa65,
-    0x2c3c2a79,
-    0x2c3caa8f,
-    0x2c3d2aa8,
-    0x2c3daac5,
-    0x2c3e2ad6,
-    0x2c3eaae4,
-    0x2c3f2afc,
-    0x2c3fab14,
-    0x2c402b21,
+    0x2c372a00,
+    0x2c37aa12,
+    0x2c382a25,
+    0x2c38aa3c,
+    0x2c392a4a,
+    0x2c39aa5a,
+    0x2c3a2a6c,
+    0x2c3aaa80,
+    0x2c3b2a91,
+    0x2c3baab0,
+    0x2c3c2ac4,
+    0x2c3caada,
+    0x2c3d2af3,
+    0x2c3dab10,
+    0x2c3e2b21,
+    0x2c3eab2f,
+    0x2c3f2b47,
+    0x2c3fab5f,
+    0x2c402b6c,
     0x2c4090e7,
-    0x2c412b32,
-    0x2c41ab45,
+    0x2c412b7d,
+    0x2c41ab90,
     0x2c4210c0,
-    0x2c42ab56,
+    0x2c42aba1,
     0x2c430720,
-    0x2c43aa57,
+    0x2c43aaa2,
     0x30320000,
     0x30328015,
     0x3033001f,
@@ -404,145 +404,148 @@
     0x404e9bf1,
     0x404f1c1e,
     0x404f9c47,
-    0x40501c71,
-    0x40509c85,
-    0x40511ca0,
-    0x40519cb0,
-    0x40521cc7,
-    0x40529ceb,
-    0x40531d03,
-    0x40539d16,
-    0x40541d2b,
-    0x40549d4e,
-    0x40551d5c,
-    0x40559d79,
-    0x40561d86,
-    0x40569d9f,
-    0x40571db7,
-    0x40579dca,
-    0x40581ddf,
-    0x40589e06,
-    0x40591e35,
-    0x40599e62,
-    0x405a1e76,
-    0x405a9e86,
-    0x405b1e9e,
-    0x405b9eaf,
-    0x405c1ec2,
-    0x405c9ee3,
-    0x405d1ef0,
-    0x405d9f07,
-    0x405e1f27,
+    0x40501c82,
+    0x40509c96,
+    0x40511cb1,
+    0x40519cc1,
+    0x40521cd8,
+    0x40529cfc,
+    0x40531d14,
+    0x40539d27,
+    0x40541d3c,
+    0x40549d5f,
+    0x40551d6d,
+    0x40559d8a,
+    0x40561d97,
+    0x40569db0,
+    0x40571dc8,
+    0x40579ddb,
+    0x40581df0,
+    0x40589e17,
+    0x40591e46,
+    0x40599e73,
+    0x405a1e87,
+    0x405a9e97,
+    0x405b1eaf,
+    0x405b9ec0,
+    0x405c1ed3,
+    0x405c9ef4,
+    0x405d1f01,
+    0x405d9f18,
+    0x405e1f56,
     0x405e8a95,
-    0x405f1f48,
-    0x405f9f55,
-    0x40601f63,
-    0x40609f85,
-    0x40611fad,
-    0x40619fc2,
-    0x40621fd9,
-    0x40629fea,
-    0x40631ffb,
-    0x4063a010,
-    0x40642027,
-    0x4064a053,
-    0x4065206e,
-    0x4065a085,
-    0x4066209d,
-    0x4066a0c7,
-    0x406720f2,
-    0x4067a113,
-    0x40682126,
-    0x4068a147,
-    0x40692179,
-    0x4069a1a7,
-    0x406a21c8,
-    0x406aa1e8,
-    0x406b2370,
-    0x406ba393,
-    0x406c23a9,
-    0x406ca60b,
-    0x406d263a,
-    0x406da662,
-    0x406e2690,
-    0x406ea6a8,
-    0x406f26c7,
-    0x406fa6dc,
-    0x407026ef,
-    0x4070a70c,
+    0x405f1f77,
+    0x405f9f84,
+    0x40601f92,
+    0x40609fb4,
+    0x40611ff8,
+    0x4061a00d,
+    0x40622024,
+    0x4062a035,
+    0x40632046,
+    0x4063a05b,
+    0x40642072,
+    0x4064a09e,
+    0x406520b9,
+    0x4065a0d0,
+    0x406620e8,
+    0x4066a112,
+    0x4067213d,
+    0x4067a15e,
+    0x40682171,
+    0x4068a192,
+    0x406921c4,
+    0x4069a1f2,
+    0x406a2213,
+    0x406aa233,
+    0x406b23bb,
+    0x406ba3de,
+    0x406c23f4,
+    0x406ca656,
+    0x406d2685,
+    0x406da6ad,
+    0x406e26db,
+    0x406ea6f3,
+    0x406f2712,
+    0x406fa727,
+    0x4070273a,
+    0x4070a757,
     0x40710800,
-    0x4071a71e,
-    0x40722731,
-    0x4072a74a,
-    0x40732762,
+    0x4071a769,
+    0x4072277c,
+    0x4072a795,
+    0x407327ad,
     0x4073936d,
-    0x40742776,
-    0x4074a790,
-    0x407527a1,
-    0x4075a7b5,
-    0x407627c3,
+    0x407427c1,
+    0x4074a7db,
+    0x407527ec,
+    0x4075a800,
+    0x4076280e,
     0x407691aa,
-    0x407727e8,
-    0x4077a80a,
-    0x40782825,
-    0x4078a85e,
-    0x40792875,
-    0x4079a88b,
-    0x407a2897,
-    0x407aa8aa,
-    0x407b28bf,
-    0x407ba8d1,
-    0x407c28e6,
-    0x407ca8ef,
-    0x407d2162,
+    0x40772833,
+    0x4077a855,
+    0x40782870,
+    0x4078a8a9,
+    0x407928c0,
+    0x4079a8d6,
+    0x407a28e2,
+    0x407aa8f5,
+    0x407b290a,
+    0x407ba91c,
+    0x407c2931,
+    0x407ca93a,
+    0x407d21ad,
     0x407d9c57,
-    0x407e283a,
-    0x407e9e16,
+    0x407e2885,
+    0x407e9e27,
     0x407f1a67,
     0x407f9887,
     0x40801c2e,
     0x40809a8f,
-    0x40811cd9,
+    0x40811cea,
     0x40819c08,
-    0x4082267b,
+    0x408226c6,
     0x4082986d,
-    0x40831df1,
-    0x4083a038,
+    0x40831e02,
+    0x4083a083,
     0x40841aa3,
-    0x40849e4e,
-    0x40851ed3,
-    0x41f4229b,
-    0x41f9232d,
-    0x41fe2220,
-    0x41fea3fc,
-    0x41ff24ed,
-    0x420322b4,
-    0x420822d6,
-    0x4208a312,
-    0x42092204,
-    0x4209a34c,
-    0x420a225b,
-    0x420aa23b,
-    0x420b227b,
-    0x420ba2f4,
-    0x420c2509,
-    0x420ca3c9,
-    0x420d23e3,
-    0x420da41a,
-    0x42122434,
-    0x421724d0,
-    0x4217a476,
-    0x421c2498,
-    0x421f2453,
-    0x42212520,
-    0x422624b3,
-    0x422b25ef,
-    0x422ba59d,
-    0x422c25d7,
-    0x422ca55c,
-    0x422d253b,
-    0x422da5bc,
-    0x422e2582,
+    0x40849e5f,
+    0x40851ee4,
+    0x40859fdc,
+    0x40861f38,
+    0x40869c71,
+    0x41f422e6,
+    0x41f92378,
+    0x41fe226b,
+    0x41fea447,
+    0x41ff2538,
+    0x420322ff,
+    0x42082321,
+    0x4208a35d,
+    0x4209224f,
+    0x4209a397,
+    0x420a22a6,
+    0x420aa286,
+    0x420b22c6,
+    0x420ba33f,
+    0x420c2554,
+    0x420ca414,
+    0x420d242e,
+    0x420da465,
+    0x4212247f,
+    0x4217251b,
+    0x4217a4c1,
+    0x421c24e3,
+    0x421f249e,
+    0x4221256b,
+    0x422624fe,
+    0x422b263a,
+    0x422ba5e8,
+    0x422c2622,
+    0x422ca5a7,
+    0x422d2586,
+    0x422da607,
+    0x422e25cd,
     0x4432072b,
     0x4432873a,
     0x44330746,
@@ -585,69 +588,69 @@
     0x4c3d136d,
     0x4c3d937c,
     0x4c3e1389,
-    0x50322b68,
-    0x5032ab77,
-    0x50332b82,
-    0x5033ab92,
-    0x50342bab,
-    0x5034abc5,
-    0x50352bd3,
-    0x5035abe9,
-    0x50362bfb,
-    0x5036ac11,
-    0x50372c2a,
-    0x5037ac3d,
-    0x50382c55,
-    0x5038ac66,
-    0x50392c7b,
-    0x5039ac8f,
-    0x503a2caf,
-    0x503aacc5,
-    0x503b2cdd,
-    0x503bacef,
-    0x503c2d0b,
-    0x503cad22,
-    0x503d2d3b,
-    0x503dad51,
-    0x503e2d5e,
-    0x503ead74,
-    0x503f2d86,
+    0x50322bb3,
+    0x5032abc2,
+    0x50332bcd,
+    0x5033abdd,
+    0x50342bf6,
+    0x5034ac10,
+    0x50352c1e,
+    0x5035ac34,
+    0x50362c46,
+    0x5036ac5c,
+    0x50372c75,
+    0x5037ac88,
+    0x50382ca0,
+    0x5038acb1,
+    0x50392cc6,
+    0x5039acda,
+    0x503a2cfa,
+    0x503aad10,
+    0x503b2d28,
+    0x503bad3a,
+    0x503c2d56,
+    0x503cad6d,
+    0x503d2d86,
+    0x503dad9c,
+    0x503e2da9,
+    0x503eadbf,
+    0x503f2dd1,
     0x503f8382,
-    0x50402d99,
-    0x5040ada9,
-    0x50412dc3,
-    0x5041add2,
-    0x50422dec,
-    0x5042ae09,
-    0x50432e19,
-    0x5043ae29,
-    0x50442e38,
+    0x50402de4,
+    0x5040adf4,
+    0x50412e0e,
+    0x5041ae1d,
+    0x50422e37,
+    0x5042ae54,
+    0x50432e64,
+    0x5043ae74,
+    0x50442e83,
     0x5044843f,
-    0x50452e4c,
-    0x5045ae6a,
-    0x50462e7d,
-    0x5046ae93,
-    0x50472ea5,
-    0x5047aeba,
-    0x50482ee0,
-    0x5048aeee,
-    0x50492f01,
-    0x5049af16,
-    0x504a2f2c,
-    0x504aaf3c,
-    0x504b2f5c,
-    0x504baf6f,
-    0x504c2f92,
-    0x504cafc0,
-    0x504d2fd2,
-    0x504dafef,
-    0x504e300a,
-    0x504eb026,
-    0x504f3038,
-    0x504fb04f,
-    0x5050305e,
+    0x50452e97,
+    0x5045aeb5,
+    0x50462ec8,
+    0x5046aede,
+    0x50472ef0,
+    0x5047af05,
+    0x50482f2b,
+    0x5048af39,
+    0x50492f4c,
+    0x5049af61,
+    0x504a2f77,
+    0x504aaf87,
+    0x504b2fa7,
+    0x504bafba,
+    0x504c2fdd,
+    0x504cb00b,
+    0x504d301d,
+    0x504db03a,
+    0x504e3055,
+    0x504eb071,
+    0x504f3083,
+    0x504fb09a,
+    0x505030a9,
     0x505086ef,
-    0x50513071,
+    0x505130bc,
     0x58320ec9,
     0x68320e8b,
     0x68328c25,
@@ -1053,6 +1056,7 @@
     "INVALID_COMPRESSION_LIST\0"
     "INVALID_MESSAGE\0"
     "INVALID_OUTER_RECORD_TYPE\0"
+    "INVALID_SCT_LIST\0"
     "INVALID_SSL_SESSION\0"
     "INVALID_TICKET_KEYS_LENGTH\0"
     "LENGTH_MISMATCH\0"
@@ -1086,11 +1090,13 @@
     "NULL_SSL_CTX\0"
     "NULL_SSL_METHOD_PASSED\0"
     "OLD_SESSION_CIPHER_NOT_RETURNED\0"
+    "OLD_SESSION_PRF_HASH_MISMATCH\0"
     "OLD_SESSION_VERSION_NOT_RETURNED\0"
     "PARSE_TLSEXT\0"
     "PATH_TOO_LONG\0"
     "PEER_DID_NOT_RETURN_A_CERTIFICATE\0"
     "PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE\0"
+    "PRE_SHARED_KEY_MUST_BE_LAST\0"
     "PROTOCOL_IS_SHUTDOWN\0"
     "PSK_IDENTITY_NOT_FOUND\0"
     "PSK_NO_CLIENT_CB\0"
diff --git a/linux-x86_64/crypto/ec/p256-x86_64-asm.S b/linux-x86_64/crypto/ec/p256-x86_64-asm.S
index 8a18859..e059dd6 100644
--- a/linux-x86_64/crypto/ec/p256-x86_64-asm.S
+++ b/linux-x86_64/crypto/ec/p256-x86_64-asm.S
@@ -24,6 +24,7 @@
 	pushq	%r13
 
 	movq	0(%rsi),%r8
+	xorq	%r13,%r13
 	movq	8(%rsi),%r9
 	addq	%r8,%r8
 	movq	16(%rsi),%r10
@@ -34,7 +35,7 @@
 	adcq	%r10,%r10
 	adcq	%r11,%r11
 	movq	%r9,%rdx
-	sbbq	%r13,%r13
+	adcq	$0,%r13
 
 	subq	0(%rsi),%r8
 	movq	%r10,%rcx
@@ -42,14 +43,14 @@
 	sbbq	16(%rsi),%r10
 	movq	%r11,%r12
 	sbbq	24(%rsi),%r11
-	testq	%r13,%r13
+	sbbq	$0,%r13
 
-	cmovzq	%rax,%r8
-	cmovzq	%rdx,%r9
+	cmovcq	%rax,%r8
+	cmovcq	%rdx,%r9
 	movq	%r8,0(%rdi)
-	cmovzq	%rcx,%r10
+	cmovcq	%rcx,%r10
 	movq	%r9,8(%rdi)
-	cmovzq	%r12,%r11
+	cmovcq	%r12,%r11
 	movq	%r10,16(%rdi)
 	movq	%r11,24(%rdi)
 
@@ -767,13 +768,14 @@
 .type	__ecp_nistz256_add_toq,@function
 .align	32
 __ecp_nistz256_add_toq:
+	xorq	%r11,%r11
 	addq	0(%rbx),%r12
 	adcq	8(%rbx),%r13
 	movq	%r12,%rax
 	adcq	16(%rbx),%r8
 	adcq	24(%rbx),%r9
 	movq	%r13,%rbp
-	sbbq	%r11,%r11
+	adcq	$0,%r11
 
 	subq	$-1,%r12
 	movq	%r8,%rcx
@@ -781,14 +783,14 @@
 	sbbq	$0,%r8
 	movq	%r9,%r10
 	sbbq	%r15,%r9
-	testq	%r11,%r11
+	sbbq	$0,%r11
 
-	cmovzq	%rax,%r12
-	cmovzq	%rbp,%r13
+	cmovcq	%rax,%r12
+	cmovcq	%rbp,%r13
 	movq	%r12,0(%rdi)
-	cmovzq	%rcx,%r8
+	cmovcq	%rcx,%r8
 	movq	%r13,8(%rdi)
-	cmovzq	%r10,%r9
+	cmovcq	%r10,%r9
 	movq	%r8,16(%rdi)
 	movq	%r9,24(%rdi)
 
@@ -856,13 +858,14 @@
 .type	__ecp_nistz256_mul_by_2q,@function
 .align	32
 __ecp_nistz256_mul_by_2q:
+	xorq	%r11,%r11
 	addq	%r12,%r12
 	adcq	%r13,%r13
 	movq	%r12,%rax
 	adcq	%r8,%r8
 	adcq	%r9,%r9
 	movq	%r13,%rbp
-	sbbq	%r11,%r11
+	adcq	$0,%r11
 
 	subq	$-1,%r12
 	movq	%r8,%rcx
@@ -870,14 +873,14 @@
 	sbbq	$0,%r8
 	movq	%r9,%r10
 	sbbq	%r15,%r9
-	testq	%r11,%r11
+	sbbq	$0,%r11
 
-	cmovzq	%rax,%r12
-	cmovzq	%rbp,%r13
+	cmovcq	%rax,%r12
+	cmovcq	%rbp,%r13
 	movq	%r12,0(%rdi)
-	cmovzq	%rcx,%r8
+	cmovcq	%rcx,%r8
 	movq	%r13,8(%rdi)
-	cmovzq	%r10,%r9
+	cmovcq	%r10,%r9
 	movq	%r8,16(%rdi)
 	movq	%r9,24(%rdi)
 
@@ -1109,16 +1112,14 @@
 	movq	%rdx,%rsi
 	movdqa	%xmm0,384(%rsp)
 	movdqa	%xmm1,384+16(%rsp)
-	por	%xmm0,%xmm1
 	movdqa	%xmm2,416(%rsp)
 	movdqa	%xmm3,416+16(%rsp)
-	por	%xmm2,%xmm3
 	movdqa	%xmm4,448(%rsp)
 	movdqa	%xmm5,448+16(%rsp)
-	por	%xmm1,%xmm3
+	por	%xmm4,%xmm5
 
 	movdqu	0(%rsi),%xmm0
-	pshufd	$0xb1,%xmm3,%xmm5
+	pshufd	$0xb1,%xmm5,%xmm3
 	movdqu	16(%rsi),%xmm1
 	movdqu	32(%rsi),%xmm2
 	por	%xmm3,%xmm5
@@ -1130,14 +1131,14 @@
 	movdqa	%xmm0,480(%rsp)
 	pshufd	$0x1e,%xmm5,%xmm4
 	movdqa	%xmm1,480+16(%rsp)
-	por	%xmm0,%xmm1
-.byte	102,72,15,110,199
+	movdqu	64(%rsi),%xmm0
+	movdqu	80(%rsi),%xmm1
 	movdqa	%xmm2,512(%rsp)
 	movdqa	%xmm3,512+16(%rsp)
-	por	%xmm2,%xmm3
 	por	%xmm4,%xmm5
 	pxor	%xmm4,%xmm4
-	por	%xmm1,%xmm3
+	por	%xmm0,%xmm1
+.byte	102,72,15,110,199
 
 	leaq	64-0(%rsi),%rsi
 	movq	%rax,544+0(%rsp)
@@ -1148,8 +1149,8 @@
 	call	__ecp_nistz256_sqr_montq
 
 	pcmpeqd	%xmm4,%xmm5
-	pshufd	$0xb1,%xmm3,%xmm4
-	por	%xmm3,%xmm4
+	pshufd	$0xb1,%xmm1,%xmm4
+	por	%xmm1,%xmm4
 	pshufd	$0,%xmm5,%xmm5
 	pshufd	$0x1e,%xmm4,%xmm3
 	por	%xmm3,%xmm4
@@ -1332,6 +1333,7 @@
 
 
 
+	xorq	%r11,%r11
 	addq	%r12,%r12
 	leaq	96(%rsp),%rsi
 	adcq	%r13,%r13
@@ -1339,7 +1341,7 @@
 	adcq	%r8,%r8
 	adcq	%r9,%r9
 	movq	%r13,%rbp
-	sbbq	%r11,%r11
+	adcq	$0,%r11
 
 	subq	$-1,%r12
 	movq	%r8,%rcx
@@ -1347,15 +1349,15 @@
 	sbbq	$0,%r8
 	movq	%r9,%r10
 	sbbq	%r15,%r9
-	testq	%r11,%r11
+	sbbq	$0,%r11
 
-	cmovzq	%rax,%r12
+	cmovcq	%rax,%r12
 	movq	0(%rsi),%rax
-	cmovzq	%rbp,%r13
+	cmovcq	%rbp,%r13
 	movq	8(%rsi),%rbp
-	cmovzq	%rcx,%r8
+	cmovcq	%rcx,%r8
 	movq	16(%rsi),%rcx
-	cmovzq	%r10,%r9
+	cmovcq	%r10,%r9
 	movq	24(%rsi),%r10
 
 	call	__ecp_nistz256_subq
@@ -1510,16 +1512,14 @@
 	movq	64+24(%rsi),%r8
 	movdqa	%xmm0,320(%rsp)
 	movdqa	%xmm1,320+16(%rsp)
-	por	%xmm0,%xmm1
 	movdqa	%xmm2,352(%rsp)
 	movdqa	%xmm3,352+16(%rsp)
-	por	%xmm2,%xmm3
 	movdqa	%xmm4,384(%rsp)
 	movdqa	%xmm5,384+16(%rsp)
-	por	%xmm1,%xmm3
+	por	%xmm4,%xmm5
 
 	movdqu	0(%rbx),%xmm0
-	pshufd	$0xb1,%xmm3,%xmm5
+	pshufd	$0xb1,%xmm5,%xmm3
 	movdqu	16(%rbx),%xmm1
 	movdqu	32(%rbx),%xmm2
 	por	%xmm3,%xmm5
@@ -1637,6 +1637,7 @@
 
 
 
+	xorq	%r11,%r11
 	addq	%r12,%r12
 	leaq	192(%rsp),%rsi
 	adcq	%r13,%r13
@@ -1644,7 +1645,7 @@
 	adcq	%r8,%r8
 	adcq	%r9,%r9
 	movq	%r13,%rbp
-	sbbq	%r11,%r11
+	adcq	$0,%r11
 
 	subq	$-1,%r12
 	movq	%r8,%rcx
@@ -1652,15 +1653,15 @@
 	sbbq	$0,%r8
 	movq	%r9,%r10
 	sbbq	%r15,%r9
-	testq	%r11,%r11
+	sbbq	$0,%r11
 
-	cmovzq	%rax,%r12
+	cmovcq	%rax,%r12
 	movq	0(%rsi),%rax
-	cmovzq	%rbp,%r13
+	cmovcq	%rbp,%r13
 	movq	8(%rsi),%rbp
-	cmovzq	%rcx,%r8
+	cmovcq	%rcx,%r8
 	movq	16(%rsi),%rcx
-	cmovzq	%r10,%r9
+	cmovcq	%r10,%r9
 	movq	24(%rsi),%r10
 
 	call	__ecp_nistz256_subq
diff --git a/mac-x86_64/crypto/ec/p256-x86_64-asm.S b/mac-x86_64/crypto/ec/p256-x86_64-asm.S
index 62dc474..97fb75a 100644
--- a/mac-x86_64/crypto/ec/p256-x86_64-asm.S
+++ b/mac-x86_64/crypto/ec/p256-x86_64-asm.S
@@ -23,6 +23,7 @@
 	pushq	%r13
 
 	movq	0(%rsi),%r8
+	xorq	%r13,%r13
 	movq	8(%rsi),%r9
 	addq	%r8,%r8
 	movq	16(%rsi),%r10
@@ -33,7 +34,7 @@
 	adcq	%r10,%r10
 	adcq	%r11,%r11
 	movq	%r9,%rdx
-	sbbq	%r13,%r13
+	adcq	$0,%r13
 
 	subq	0(%rsi),%r8
 	movq	%r10,%rcx
@@ -41,14 +42,14 @@
 	sbbq	16(%rsi),%r10
 	movq	%r11,%r12
 	sbbq	24(%rsi),%r11
-	testq	%r13,%r13
+	sbbq	$0,%r13
 
-	cmovzq	%rax,%r8
-	cmovzq	%rdx,%r9
+	cmovcq	%rax,%r8
+	cmovcq	%rdx,%r9
 	movq	%r8,0(%rdi)
-	cmovzq	%rcx,%r10
+	cmovcq	%rcx,%r10
 	movq	%r9,8(%rdi)
-	cmovzq	%r12,%r11
+	cmovcq	%r12,%r11
 	movq	%r10,16(%rdi)
 	movq	%r11,24(%rdi)
 
@@ -766,13 +767,14 @@
 
 .p2align	5
 __ecp_nistz256_add_toq:
+	xorq	%r11,%r11
 	addq	0(%rbx),%r12
 	adcq	8(%rbx),%r13
 	movq	%r12,%rax
 	adcq	16(%rbx),%r8
 	adcq	24(%rbx),%r9
 	movq	%r13,%rbp
-	sbbq	%r11,%r11
+	adcq	$0,%r11
 
 	subq	$-1,%r12
 	movq	%r8,%rcx
@@ -780,14 +782,14 @@
 	sbbq	$0,%r8
 	movq	%r9,%r10
 	sbbq	%r15,%r9
-	testq	%r11,%r11
+	sbbq	$0,%r11
 
-	cmovzq	%rax,%r12
-	cmovzq	%rbp,%r13
+	cmovcq	%rax,%r12
+	cmovcq	%rbp,%r13
 	movq	%r12,0(%rdi)
-	cmovzq	%rcx,%r8
+	cmovcq	%rcx,%r8
 	movq	%r13,8(%rdi)
-	cmovzq	%r10,%r9
+	cmovcq	%r10,%r9
 	movq	%r8,16(%rdi)
 	movq	%r9,24(%rdi)
 
@@ -855,13 +857,14 @@
 
 .p2align	5
 __ecp_nistz256_mul_by_2q:
+	xorq	%r11,%r11
 	addq	%r12,%r12
 	adcq	%r13,%r13
 	movq	%r12,%rax
 	adcq	%r8,%r8
 	adcq	%r9,%r9
 	movq	%r13,%rbp
-	sbbq	%r11,%r11
+	adcq	$0,%r11
 
 	subq	$-1,%r12
 	movq	%r8,%rcx
@@ -869,14 +872,14 @@
 	sbbq	$0,%r8
 	movq	%r9,%r10
 	sbbq	%r15,%r9
-	testq	%r11,%r11
+	sbbq	$0,%r11
 
-	cmovzq	%rax,%r12
-	cmovzq	%rbp,%r13
+	cmovcq	%rax,%r12
+	cmovcq	%rbp,%r13
 	movq	%r12,0(%rdi)
-	cmovzq	%rcx,%r8
+	cmovcq	%rcx,%r8
 	movq	%r13,8(%rdi)
-	cmovzq	%r10,%r9
+	cmovcq	%r10,%r9
 	movq	%r8,16(%rdi)
 	movq	%r9,24(%rdi)
 
@@ -1108,16 +1111,14 @@
 	movq	%rdx,%rsi
 	movdqa	%xmm0,384(%rsp)
 	movdqa	%xmm1,384+16(%rsp)
-	por	%xmm0,%xmm1
 	movdqa	%xmm2,416(%rsp)
 	movdqa	%xmm3,416+16(%rsp)
-	por	%xmm2,%xmm3
 	movdqa	%xmm4,448(%rsp)
 	movdqa	%xmm5,448+16(%rsp)
-	por	%xmm1,%xmm3
+	por	%xmm4,%xmm5
 
 	movdqu	0(%rsi),%xmm0
-	pshufd	$0xb1,%xmm3,%xmm5
+	pshufd	$0xb1,%xmm5,%xmm3
 	movdqu	16(%rsi),%xmm1
 	movdqu	32(%rsi),%xmm2
 	por	%xmm3,%xmm5
@@ -1129,14 +1130,14 @@
 	movdqa	%xmm0,480(%rsp)
 	pshufd	$0x1e,%xmm5,%xmm4
 	movdqa	%xmm1,480+16(%rsp)
-	por	%xmm0,%xmm1
-.byte	102,72,15,110,199
+	movdqu	64(%rsi),%xmm0
+	movdqu	80(%rsi),%xmm1
 	movdqa	%xmm2,512(%rsp)
 	movdqa	%xmm3,512+16(%rsp)
-	por	%xmm2,%xmm3
 	por	%xmm4,%xmm5
 	pxor	%xmm4,%xmm4
-	por	%xmm1,%xmm3
+	por	%xmm0,%xmm1
+.byte	102,72,15,110,199
 
 	leaq	64-0(%rsi),%rsi
 	movq	%rax,544+0(%rsp)
@@ -1147,8 +1148,8 @@
 	call	__ecp_nistz256_sqr_montq
 
 	pcmpeqd	%xmm4,%xmm5
-	pshufd	$0xb1,%xmm3,%xmm4
-	por	%xmm3,%xmm4
+	pshufd	$0xb1,%xmm1,%xmm4
+	por	%xmm1,%xmm4
 	pshufd	$0,%xmm5,%xmm5
 	pshufd	$0x1e,%xmm4,%xmm3
 	por	%xmm3,%xmm4
@@ -1331,6 +1332,7 @@
 
 
 
+	xorq	%r11,%r11
 	addq	%r12,%r12
 	leaq	96(%rsp),%rsi
 	adcq	%r13,%r13
@@ -1338,7 +1340,7 @@
 	adcq	%r8,%r8
 	adcq	%r9,%r9
 	movq	%r13,%rbp
-	sbbq	%r11,%r11
+	adcq	$0,%r11
 
 	subq	$-1,%r12
 	movq	%r8,%rcx
@@ -1346,15 +1348,15 @@
 	sbbq	$0,%r8
 	movq	%r9,%r10
 	sbbq	%r15,%r9
-	testq	%r11,%r11
+	sbbq	$0,%r11
 
-	cmovzq	%rax,%r12
+	cmovcq	%rax,%r12
 	movq	0(%rsi),%rax
-	cmovzq	%rbp,%r13
+	cmovcq	%rbp,%r13
 	movq	8(%rsi),%rbp
-	cmovzq	%rcx,%r8
+	cmovcq	%rcx,%r8
 	movq	16(%rsi),%rcx
-	cmovzq	%r10,%r9
+	cmovcq	%r10,%r9
 	movq	24(%rsi),%r10
 
 	call	__ecp_nistz256_subq
@@ -1509,16 +1511,14 @@
 	movq	64+24(%rsi),%r8
 	movdqa	%xmm0,320(%rsp)
 	movdqa	%xmm1,320+16(%rsp)
-	por	%xmm0,%xmm1
 	movdqa	%xmm2,352(%rsp)
 	movdqa	%xmm3,352+16(%rsp)
-	por	%xmm2,%xmm3
 	movdqa	%xmm4,384(%rsp)
 	movdqa	%xmm5,384+16(%rsp)
-	por	%xmm1,%xmm3
+	por	%xmm4,%xmm5
 
 	movdqu	0(%rbx),%xmm0
-	pshufd	$0xb1,%xmm3,%xmm5
+	pshufd	$0xb1,%xmm5,%xmm3
 	movdqu	16(%rbx),%xmm1
 	movdqu	32(%rbx),%xmm2
 	por	%xmm3,%xmm5
@@ -1636,6 +1636,7 @@
 
 
 
+	xorq	%r11,%r11
 	addq	%r12,%r12
 	leaq	192(%rsp),%rsi
 	adcq	%r13,%r13
@@ -1643,7 +1644,7 @@
 	adcq	%r8,%r8
 	adcq	%r9,%r9
 	movq	%r13,%rbp
-	sbbq	%r11,%r11
+	adcq	$0,%r11
 
 	subq	$-1,%r12
 	movq	%r8,%rcx
@@ -1651,15 +1652,15 @@
 	sbbq	$0,%r8
 	movq	%r9,%r10
 	sbbq	%r15,%r9
-	testq	%r11,%r11
+	sbbq	$0,%r11
 
-	cmovzq	%rax,%r12
+	cmovcq	%rax,%r12
 	movq	0(%rsi),%rax
-	cmovzq	%rbp,%r13
+	cmovcq	%rbp,%r13
 	movq	8(%rsi),%rbp
-	cmovzq	%rcx,%r8
+	cmovcq	%rcx,%r8
 	movq	16(%rsi),%rcx
-	cmovzq	%r10,%r9
+	cmovcq	%r10,%r9
 	movq	24(%rsi),%r10
 
 	call	__ecp_nistz256_subq
diff --git a/sources.bp b/sources.bp
index fa6c61d..8ae4dc9 100644
--- a/sources.bp
+++ b/sources.bp
@@ -186,6 +186,7 @@
         "src/crypto/poly1305/poly1305.c",
         "src/crypto/poly1305/poly1305_arm.c",
         "src/crypto/poly1305/poly1305_vec.c",
+        "src/crypto/pool/pool.c",
         "src/crypto/rand/deterministic.c",
         "src/crypto/rand/rand.c",
         "src/crypto/rand/urandom.c",
@@ -198,6 +199,7 @@
         "src/crypto/rsa/rsa.c",
         "src/crypto/rsa/rsa_asn1.c",
         "src/crypto/rsa/rsa_impl.c",
+        "src/crypto/sha/sha1-altivec.c",
         "src/crypto/sha/sha1.c",
         "src/crypto/sha/sha256.c",
         "src/crypto/sha/sha512.c",
@@ -486,6 +488,7 @@
         "src/crypto/dsa/dsa_test.c",
         "src/crypto/ec/ec_test.cc",
         "src/crypto/ec/example_mul.c",
+        "src/crypto/ec/p256-x86_64_test.cc",
         "src/crypto/ecdh/ecdh_test.cc",
         "src/crypto/ecdsa/ecdsa_sign_test.cc",
         "src/crypto/ecdsa/ecdsa_test.cc",
@@ -505,6 +508,7 @@
         "src/crypto/pkcs8/pkcs12_test.cc",
         "src/crypto/pkcs8/pkcs8_test.cc",
         "src/crypto/poly1305/poly1305_test.cc",
+        "src/crypto/pool/pool_test.cc",
         "src/crypto/refcount_test.c",
         "src/crypto/rsa/rsa_test.cc",
         "src/crypto/thread_test.c",
diff --git a/sources.mk b/sources.mk
index e8697cb..deafdc9 100644
--- a/sources.mk
+++ b/sources.mk
@@ -184,6 +184,7 @@
   src/crypto/poly1305/poly1305.c\
   src/crypto/poly1305/poly1305_arm.c\
   src/crypto/poly1305/poly1305_vec.c\
+  src/crypto/pool/pool.c\
   src/crypto/rand/deterministic.c\
   src/crypto/rand/rand.c\
   src/crypto/rand/urandom.c\
@@ -196,6 +197,7 @@
   src/crypto/rsa/rsa.c\
   src/crypto/rsa/rsa_asn1.c\
   src/crypto/rsa/rsa_impl.c\
+  src/crypto/sha/sha1-altivec.c\
   src/crypto/sha/sha1.c\
   src/crypto/sha/sha256.c\
   src/crypto/sha/sha512.c\
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 8ab4066..cb8bb53 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -47,6 +47,9 @@
       "C4127" # conditional expression is constant
       "C4200" # nonstandard extension used : zero-sized array in
               # struct/union.
+      "C4204" # nonstandard extension used: non-constant aggregate initializer
+      "C4221" # nonstandard extension used : 'identifier' : cannot be
+              # initialized using address of automatic variable
       "C4242" # 'function' : conversion from 'int' to 'uint8_t',
               # possible loss of data
       "C4244" # 'function' : conversion from 'int' to 'uint8_t',
@@ -125,8 +128,13 @@
     message(FATAL_ERROR "You need to build with Clang for fuzzing to work")
   endif()
 
-  add_definitions(-DBORINGSSL_UNSAFE_FUZZER_MODE)
-  set(RUNNER_ARGS "-fuzzer" "-deterministic" "-shim-config" "fuzzer_mode.json")
+  add_definitions(-DBORINGSSL_UNSAFE_DETERMINISTIC_MODE)
+  set(RUNNER_ARGS "-deterministic")
+
+  if(NOT NO_FUZZER_MODE)
+    add_definitions(-DBORINGSSL_UNSAFE_FUZZER_MODE)
+    set(RUNNER_ARGS ${RUNNER_ARGS} "-fuzzer" "-shim-config" "fuzzer_mode.json")
+  endif()
 
   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fsanitize-coverage=edge,indirect-calls,8bit-counters")
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fsanitize-coverage=edge,indirect-calls,8bit-counters")
@@ -160,14 +168,14 @@
   set(ARCH "x86")
 elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "i686")
   set(ARCH "x86")
-elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "arm")
-  set(ARCH "arm")
-elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "armv6")
-  set(ARCH "arm")
-elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "armv7-a")
+elseif (${CMAKE_SYSTEM_PROCESSOR} MATCHES "^arm*")
   set(ARCH "arm")
 elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "aarch64")
   set(ARCH "aarch64")
+elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "mips")
+  # Just to avoid the “unknown processor” error.
+elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "ppc64le")
+  set(ARCH "ppc64le")
 else()
   message(FATAL_ERROR "Unknown processor:" ${CMAKE_SYSTEM_PROCESSOR})
 endif()
diff --git a/src/FUZZING.md b/src/FUZZING.md
index 1a21403..f004c27 100644
--- a/src/FUZZING.md
+++ b/src/FUZZING.md
@@ -53,39 +53,31 @@
 
 ## Fuzzer mode
 
-When `-DFUZZ=1` is passed into CMake, BoringSSL builds with `BORINGSSL_UNSAFE_FUZZER_MODE` defined. This modifies the library, particularly the TLS stack, to be more friendly to fuzzers. It will:
+When `-DFUZZ=1` is passed into CMake, BoringSSL builds with `BORINGSSL_UNSAFE_FUZZER_MODE` and `BORINGSSL_UNSAFE_DETERMINISTIC_MODE` defined. This modifies the library to be more friendly to fuzzers. If `BORINGSSL_UNSAFE_DETERMINISTIC_MODE` is set, BoringSSL will:
 
 * Replace `RAND_bytes` with a deterministic PRNG. Call `RAND_reset_for_fuzzing()` at the start of fuzzers which use `RAND_bytes` to reset the PRNG state.
 
+* Use a hard-coded time instead of the actual time.
+
+Additionally, if `BORINGSSL_UNSAFE_FUZZER_MODE` is set, BoringSSL will:
+
 * Modify the TLS stack to perform all signature checks (CertificateVerify and ServerKeyExchange) and the Finished check, but always act as if the check succeeded.
 
 * Treat every cipher as the NULL cipher.
 
-* Use a hard-coded time instead of the actual time.
-
 * Tickets are unencrypted and the MAC check is performed but ignored.
 
 This is to prevent the fuzzer from getting stuck at a cryptographic invariant in the protocol.
 
 ## TLS transcripts
 
-The `client` and `server` corpora are seeded from the test suite. The test suite has a `-fuzzer` flag which mirrors the fuzzer mode changes above and a `-deterministic` flag which removes all non-determinism on the Go side. Not all tests pass, so `ssl/test/runner/fuzzer_mode.json` contains the necessary suppressions. To run the tests against a fuzzer-mode `bssl_shim`, run:
+The `client` and `server` corpora are seeded from the test suite. The test suite has a `-fuzzer` flag which mirrors the fuzzer mode changes above and a `-deterministic` flag which removes all non-determinism on the Go side. Not all tests pass, so `ssl/test/runner/fuzzer_mode.json` contains the necessary suppressions. The `run_tests` target will pass appropriate command-line flags.
+
+There are separate corpora, `client_corpus_no_fuzzer_mode` and `server_corpus_no_fuzzer_mode`. These are transcripts for fuzzers with only `BORINGSSL_UNSAFE_DETERMINISTIC_MODE` defined. To build in this mode, pass `-DNO_FUZZER_MODE=1` into CMake. This configuration is run in the same way but without `-fuzzer` and `-shim-path` flags.
+
+If both sets of tests pass, refresh the fuzzer corpora with `refresh_ssl_corpora.sh`:
 
 ```
-cd ssl/test/runner
-go test -fuzzer -deterministic -shim-config fuzzer_mode.json
-```
-
-For a different build directory from `build/`, pass the appropriate `-shim-path` flag. If those tests pass, record a set of transcripts with:
-
-```
-go test -fuzzer -deterministic -transcript-dir /tmp/transcripts/
-```
-
-Note the suppressions file is ignored so disabled tests record transcripts too. Then merge into the existing corpora:
-
-```
-cd build/
-./fuzz/client -max_len=50000 -merge=1 ../fuzz/client_corpus /tmp/transcripts/tls/client
-./fuzz/server -max_len=50000 -merge=1 ../fuzz/server_corpus /tmp/transcripts/tls/server
+cd fuzz
+./refresh_fuzzer_corpora.sh /path/to/fuzzer/mode/build /path/to/non/fuzzer/mode/build
 ```
diff --git a/src/INCORPORATING.md b/src/INCORPORATING.md
index 38e9d79..6dc7fa9 100644
--- a/src/INCORPORATING.md
+++ b/src/INCORPORATING.md
@@ -5,7 +5,7 @@
 
 ## Bazel
 
-If you are using [Bazel](http://www.bazel.io) then you can incorporate
+If you are using [Bazel](https://bazel.build) then you can incorporate
 BoringSSL as an external repository by using a commit from the
 `master-with-bazel` branch. That branch is maintained by a bot from `master`
 and includes the needed generated files and a top-level BUILD file.
@@ -38,7 +38,7 @@
 BoringSSL is designed to work with many different build systems. Currently,
 different projects use [GYP](https://gyp.gsrc.io/),
 [GN](https://chromium.googlesource.com/chromium/src/+/master/tools/gn/docs/quick_start.md),
-[Bazel](http://bazel.io/) and [Make](https://www.gnu.org/software/make/)  to
+[Bazel](https://bazel.build/) and [Make](https://www.gnu.org/software/make/)  to
 build BoringSSL, without too much pain.
 
 The development build system is CMake and the CMake build knows how to
diff --git a/src/crypto/CMakeLists.txt b/src/crypto/CMakeLists.txt
index 4cc5ae2..20a38dc 100644
--- a/src/crypto/CMakeLists.txt
+++ b/src/crypto/CMakeLists.txt
@@ -64,6 +64,7 @@
 add_subdirectory(buf)
 add_subdirectory(base64)
 add_subdirectory(bytestring)
+add_subdirectory(pool)
 
 # Level 0.2 - depends on nothing but itself
 add_subdirectory(sha)
@@ -136,6 +137,7 @@
   $<TARGET_OBJECTS:err>
   $<TARGET_OBJECTS:base64>
   $<TARGET_OBJECTS:bytestring>
+  $<TARGET_OBJECTS:pool>
   $<TARGET_OBJECTS:sha>
   $<TARGET_OBJECTS:md4>
   $<TARGET_OBJECTS:md5>
diff --git a/src/crypto/aes/asm/aesp8-ppc.pl b/src/crypto/aes/asm/aesp8-ppc.pl
index 4bdcff7..ca3a150 100644
--- a/src/crypto/aes/asm/aesp8-ppc.pl
+++ b/src/crypto/aes/asm/aesp8-ppc.pl
@@ -3011,7 +3011,7 @@
 	 vxor		$twk0,$twk0,v31
 
 	vcipher		$out0,$out0,v26
-	lvsr		$inpperm,r0,$taillen	# $in5 is no more
+	lvsr		$inpperm,0,$taillen	# $in5 is no more
 	vcipher		$out1,$out1,v26
 	vcipher		$out2,$out2,v26
 	vcipher		$out3,$out3,v26
@@ -3773,7 +3773,7 @@
 	    if ($flavour =~ /le$/o) {
 		SWITCH: for($conv)  {
 		    /\?inv/ && do   { @bytes=map($_^0xf,@bytes); last; };
-		    /\?rev/ && do   { @bytes=reverse(@bytes);    last; }; 
+		    /\?rev/ && do   { @bytes=reverse(@bytes);    last; };
 		}
 	    }
 
diff --git a/src/crypto/aes/key_wrap.c b/src/crypto/aes/key_wrap.c
index e955c47..c8b6a03 100644
--- a/src/crypto/aes/key_wrap.c
+++ b/src/crypto/aes/key_wrap.c
@@ -59,6 +59,8 @@
     0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6,
 };
 
+static const unsigned kBound = 6;
+
 int AES_wrap_key(const AES_KEY *key, const uint8_t *iv, uint8_t *out,
                  const uint8_t *in, size_t in_len) {
   /* See RFC 3394, section 2.2.1. */
@@ -77,7 +79,7 @@
 
   size_t n = in_len / 8;
 
-  for (unsigned j = 0; j < 6; j++) {
+  for (unsigned j = 0; j < kBound; j++) {
     for (size_t i = 1; i <= n; i++) {
       memcpy(A + 8, out + 8 * i, 8);
       AES_encrypt(A, A, key);
@@ -113,7 +115,7 @@
 
   size_t n = (in_len / 8) - 1;
 
-  for (unsigned j = 5; j < 6; j--) {
+  for (unsigned j = kBound - 1; j < kBound; j--) {
     for (size_t i = n; i > 0; i--) {
       uint32_t t = (uint32_t)(n * j + i);
       A[7] ^= t & 0xff;
diff --git a/src/crypto/asn1/a_gentm.c b/src/crypto/asn1/a_gentm.c
index ee6b3db..2f29868 100644
--- a/src/crypto/asn1/a_gentm.c
+++ b/src/crypto/asn1/a_gentm.c
@@ -220,37 +220,43 @@
     struct tm *ts;
     struct tm data;
     size_t len = 20;
+    ASN1_GENERALIZEDTIME *tmps = NULL;
 
     if (s == NULL)
-        s = M_ASN1_GENERALIZEDTIME_new();
-    if (s == NULL)
-        return (NULL);
+        tmps = ASN1_GENERALIZEDTIME_new();
+    else
+        tmps = s;
+    if (tmps == NULL)
+        return NULL;
 
     ts = OPENSSL_gmtime(&t, &data);
     if (ts == NULL)
-        return (NULL);
+        goto err;
 
     if (offset_day || offset_sec) {
         if (!OPENSSL_gmtime_adj(ts, offset_day, offset_sec))
-            return NULL;
+            goto err;
     }
 
-    p = (char *)s->data;
-    if ((p == NULL) || ((size_t)s->length < len)) {
+    p = (char *)tmps->data;
+    if ((p == NULL) || ((size_t)tmps->length < len)) {
         p = OPENSSL_malloc(len);
         if (p == NULL) {
             OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
-            return (NULL);
+            goto err;
         }
-        if (s->data != NULL)
-            OPENSSL_free(s->data);
-        s->data = (unsigned char *)p;
+        OPENSSL_free(tmps->data);
+        tmps->data = (unsigned char *)p;
     }
 
     BIO_snprintf(p, len, "%04d%02d%02d%02d%02d%02dZ", ts->tm_year + 1900,
                  ts->tm_mon + 1, ts->tm_mday, ts->tm_hour, ts->tm_min,
                  ts->tm_sec);
-    s->length = strlen(p);
-    s->type = V_ASN1_GENERALIZEDTIME;
-    return (s);
+    tmps->length = strlen(p);
+    tmps->type = V_ASN1_GENERALIZEDTIME;
+    return tmps;
+ err:
+    if (s == NULL)
+        ASN1_GENERALIZEDTIME_free(tmps);
+    return NULL;
 }
diff --git a/src/crypto/asn1/tasn_utl.c b/src/crypto/asn1/tasn_utl.c
index d409cfa..3f53072 100644
--- a/src/crypto/asn1/tasn_utl.c
+++ b/src/crypto/asn1/tasn_utl.c
@@ -56,6 +56,7 @@
 
 #include <openssl/asn1.h>
 
+#include <assert.h>
 #include <string.h>
 
 #include <openssl/asn1t.h>
@@ -134,6 +135,8 @@
   if (enc) {
     enc->enc = NULL;
     enc->len = 0;
+    enc->alias_only = 0;
+    enc->alias_only_on_next_parse = 0;
     enc->modified = 1;
   }
 }
@@ -142,11 +145,13 @@
   ASN1_ENCODING *enc;
   enc = asn1_get_enc_ptr(pval, it);
   if (enc) {
-    if (enc->enc) {
+    if (enc->enc && !enc->alias_only) {
       OPENSSL_free(enc->enc);
     }
     enc->enc = NULL;
     enc->len = 0;
+    enc->alias_only = 0;
+    enc->alias_only_on_next_parse = 0;
     enc->modified = 1;
   }
 }
@@ -159,14 +164,23 @@
     return 1;
   }
 
-  if (enc->enc) {
+  if (!enc->alias_only) {
     OPENSSL_free(enc->enc);
   }
-  enc->enc = OPENSSL_malloc(inlen);
-  if (!enc->enc) {
-    return 0;
+
+  enc->alias_only = enc->alias_only_on_next_parse;
+  enc->alias_only_on_next_parse = 0;
+
+  if (enc->alias_only) {
+    enc->enc = (uint8_t *) in;
+  } else {
+    enc->enc = OPENSSL_malloc(inlen);
+    if (!enc->enc) {
+      return 0;
+    }
+    memcpy(enc->enc, in, inlen);
   }
-  memcpy(enc->enc, in, inlen);
+
   enc->len = inlen;
   enc->modified = 0;
 
diff --git a/src/crypto/bio/bio.c b/src/crypto/bio/bio.c
index 8f8a196..675e903 100644
--- a/src/crypto/bio/bio.c
+++ b/src/crypto/bio/bio.c
@@ -336,7 +336,13 @@
 }
 
 size_t BIO_pending(const BIO *bio) {
-  return BIO_ctrl((BIO *) bio, BIO_CTRL_PENDING, 0, NULL);
+  const long r = BIO_ctrl((BIO *) bio, BIO_CTRL_PENDING, 0, NULL);
+  assert(r >= 0);
+
+  if (r < 0) {
+    return 0;
+  }
+  return r;
 }
 
 size_t BIO_ctrl_pending(const BIO *bio) {
@@ -344,7 +350,13 @@
 }
 
 size_t BIO_wpending(const BIO *bio) {
-  return BIO_ctrl((BIO *) bio, BIO_CTRL_WPENDING, 0, NULL);
+  const long r = BIO_ctrl((BIO *) bio, BIO_CTRL_WPENDING, 0, NULL);
+  assert(r >= 0);
+
+  if (r < 0) {
+    return 0;
+  }
+  return r;
 }
 
 int BIO_set_close(BIO *bio, int close_flag) {
@@ -448,12 +460,8 @@
   return BIO_write((BIO *)bio, str, len);
 }
 
-void BIO_print_errors(BIO *bio) {
-  ERR_print_errors_cb(print_bio, bio);
-}
-
 void ERR_print_errors(BIO *bio) {
-  BIO_print_errors(bio);
+  ERR_print_errors_cb(print_bio, bio);
 }
 
 /* bio_read_all reads everything from |bio| and prepends |prefix| to it. On
diff --git a/src/crypto/bio/bio_test.cc b/src/crypto/bio/bio_test.cc
index cbc4fde..01b93f6 100644
--- a/src/crypto/bio/bio_test.cc
+++ b/src/crypto/bio/bio_test.cc
@@ -59,7 +59,7 @@
 
 class ScopedSocket {
  public:
-  ScopedSocket(int sock) : sock_(sock) {}
+  explicit ScopedSocket(int sock) : sock_(sock) {}
   ~ScopedSocket() {
     closesocket(sock_);
   }
diff --git a/src/crypto/bn/asm/x86_64-mont.pl b/src/crypto/bn/asm/x86_64-mont.pl
index 92933d4..60e0111 100755
--- a/src/crypto/bn/asm/x86_64-mont.pl
+++ b/src/crypto/bn/asm/x86_64-mont.pl
@@ -1059,18 +1059,17 @@
 	mulx	2*8($aptr),%r15,%r13	# ...
 	adox	-3*8($tptr),%r11
 	adcx	%r15,%r12
-	adox	$zero,%r12
+	adox	-2*8($tptr),%r12
 	adcx	$zero,%r13
+	adox	$zero,%r13
 
 	mov	$bptr,8(%rsp)		# off-load &b[i]
-	.byte	0x67
 	mov	$mi,%r15
 	imulq	24(%rsp),$mi		# "t[0]"*n0
 	xor	%ebp,%ebp		# xor	$zero,$zero	# cf=0, of=0
 
 	mulx	3*8($aptr),%rax,%r14
 	 mov	$mi,%rdx
-	adox	-2*8($tptr),%r12
 	adcx	%rax,%r13
 	adox	-1*8($tptr),%r13
 	adcx	$zero,%r14
diff --git a/src/crypto/bn/bn_test.cc b/src/crypto/bn/bn_test.cc
index 0488810..672d83f 100644
--- a/src/crypto/bn/bn_test.cc
+++ b/src/crypto/bn/bn_test.cc
@@ -1024,14 +1024,12 @@
     }
 
     // Test the value serializes correctly.
-    CBB cbb;
+    bssl::ScopedCBB cbb;
     uint8_t *der;
     size_t der_len;
-    CBB_zero(&cbb);
-    if (!CBB_init(&cbb, 0) ||
-        !BN_marshal_asn1(&cbb, bn.get()) ||
-        !CBB_finish(&cbb, &der, &der_len)) {
-      CBB_cleanup(&cbb);
+    if (!CBB_init(cbb.get(), 0) ||
+        !BN_marshal_asn1(cbb.get(), bn.get()) ||
+        !CBB_finish(cbb.get(), &der, &der_len)) {
       return false;
     }
     bssl::UniquePtr<uint8_t> delete_der(der);
@@ -1114,16 +1112,13 @@
   if (!bn) {
     return false;
   }
-  CBB cbb;
-  CBB_zero(&cbb);
-  if (!CBB_init(&cbb, 0) ||
-      BN_marshal_asn1(&cbb, bn.get())) {
+  bssl::ScopedCBB cbb;
+  if (!CBB_init(cbb.get(), 0) ||
+      BN_marshal_asn1(cbb.get(), bn.get())) {
     fprintf(stderr, "Serialized negative number.\n");
-    CBB_cleanup(&cbb);
     return false;
   }
   ERR_clear_error();
-  CBB_cleanup(&cbb);
 
   return true;
 }
@@ -1208,6 +1203,37 @@
     return false;
   }
 
+  // Test that |BN_rshift| and |BN_rshift1| will not produce a negative zero.
+  if (!BN_set_word(a.get(), 1)) {
+    return false;
+  }
+
+  BN_set_negative(a.get(), 1);
+  if (!BN_rshift(b.get(), a.get(), 1) ||
+      !BN_rshift1(c.get(), a.get())) {
+    return false;
+  }
+
+  if (!BN_is_zero(b.get()) || BN_is_negative(b.get())) {
+    fprintf(stderr, "BN_rshift(-1, 1) produced the wrong result.\n");
+    return false;
+  }
+
+  if (!BN_is_zero(c.get()) || BN_is_negative(c.get())) {
+    fprintf(stderr, "BN_rshift1(-1) produced the wrong result.\n");
+    return false;
+  }
+
+  // Test that |BN_div_word| will not produce a negative zero.
+  if (BN_div_word(a.get(), 2) == (BN_ULONG)-1) {
+    return false;
+  }
+
+  if (!BN_is_zero(a.get()) || BN_is_negative(a.get())) {
+    fprintf(stderr, "BN_div_word(-1, 2) produced the wrong result.\n");
+    return false;
+  }
+
   return true;
 }
 
diff --git a/src/crypto/bn/bn_tests.txt b/src/crypto/bn/bn_tests.txt
index 8451fcf..692a642 100644
--- a/src/crypto/bn/bn_tests.txt
+++ b/src/crypto/bn/bn_tests.txt
@@ -9875,6 +9875,18 @@
 B = a8b4bc9647d8df9b7c76cc6d0f2248cdbc41f5da9c061f9864aa8415c9557582cada456cf23cc32d47d1fc1caf19d36b398019aac4734e10f55ce3cad419e5e7
 M = 7eacffe21f88413af94155a2a8e37f70a431a59653738afda04a1bec72d0d9ed
 
+# Regression tests for CVE-2016-7055.
+
+ModMul = ccd6f75b5f24b7c5ce2ce755fa89c2450c6a7d96ce8c8791e659eab84577a7695e3b2caa7c980fb23f60634233e9798499c28b0338c1f1a326d0ca89fd41f2fd88b759f317889832966b551a950043ec7a4b6152d3e2cbfb40e88458e70ab783b96f12d271f828d5b39e198ccaf8665411d85026282dbead5d24cd01b6c8a8e9
+A = 7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878
+B = 095d72c08c097ba488c5e439c655a192eafb6380073d8c2664668eddb4060744e16e57fb4edb9ae10a0cefcdc28a894f689a128379db279d48a2e20849d685939b7803bcf46cebf5c533fb0dd35b080593de5472e3fe5db951b8bff9b4cb8f039cc638a5ee8cdd703719f8000e6a9f63beed5f2fcd52ff293ea05a251bb4ab81
+M = d78af684e71db0c39cff4e64fb9db567132cb9c50cc98009feb820b26f2ded9b91b9b5e2b83ae0ae4eb4e0523ca726bfbe969b89fd754f674ce99118c3f2d1c5d81fdc7c54e02b60262b241d53c040e99e45826eca37a804668e690e1afc1ca42c9a15d84d4954425f0b7642fc0bd9d7b24e2618d2dcc9b729d944badacfddaf
+
+ModMul = ccd6f75b5f24b7c5ce2ce755fa89c2450c6a7d96ce8c8791e659eab84577a7695e3b2caa7c980fb23f60634233e9798499c28b0338c1f1a326d0ca89fd41f2fd88b759f317889832966b551a950043ec7a4b6152d3e2cbfb40e88458e70ab783b96f12d271f828d5b39e198ccaf8665411d85026282dbead5d24cd01b6c8a8e9
+A = 095d72c08c097ba488c5e439c655a192eafb6380073d8c2664668eddb4060744e16e57fb4edb9ae10a0cefcdc28a894f689a128379db279d48a2e20849d685939b7803bcf46cebf5c533fb0dd35b080593de5472e3fe5db951b8bff9b4cb8f039cc638a5ee8cdd703719f8000e6a9f63beed5f2fcd52ff293ea05a251bb4ab81
+B = 7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878
+M = d78af684e71db0c39cff4e64fb9db567132cb9c50cc98009feb820b26f2ded9b91b9b5e2b83ae0ae4eb4e0523ca726bfbe969b89fd754f674ce99118c3f2d1c5d81fdc7c54e02b60262b241d53c040e99e45826eca37a804668e690e1afc1ca42c9a15d84d4954425f0b7642fc0bd9d7b24e2618d2dcc9b729d944badacfddaf
+
 
 # ModExp tests.
 #
diff --git a/src/crypto/bn/div.c b/src/crypto/bn/div.c
index 03577f2..ab49281 100644
--- a/src/crypto/bn/div.c
+++ b/src/crypto/bn/div.c
@@ -628,6 +628,10 @@
     a->top--;
   }
 
+  if (a->top == 0) {
+    a->neg = 0;
+  }
+
   ret >>= j;
   return ret;
 }
diff --git a/src/crypto/bn/internal.h b/src/crypto/bn/internal.h
index 99fc306..aeed88f 100644
--- a/src/crypto/bn/internal.h
+++ b/src/crypto/bn/internal.h
@@ -160,7 +160,7 @@
 #define BN_TBIT		(0x8000000000000000UL)
 #define BN_DEC_CONV	(10000000000000000000UL)
 #define BN_DEC_NUM	19
-#define TOBN(hi, lo) ((BN_ULONG)hi << 32 | lo)
+#define TOBN(hi, lo) ((BN_ULONG)(hi) << 32 | (lo))
 
 #elif defined(OPENSSL_32_BIT)
 
@@ -181,7 +181,7 @@
 #define BN_TBIT		(0x80000000UL)
 #define BN_DEC_CONV	(1000000000UL)
 #define BN_DEC_NUM	9
-#define TOBN(hi, lo) lo, hi
+#define TOBN(hi, lo) (lo), (hi)
 
 #else
 #error "Must define either OPENSSL_32_BIT or OPENSSL_64_BIT"
diff --git a/src/crypto/bn/shift.c b/src/crypto/bn/shift.c
index defec92..22006d1 100644
--- a/src/crypto/bn/shift.c
+++ b/src/crypto/bn/shift.c
@@ -182,6 +182,10 @@
     }
   }
 
+  if (r->top == 0) {
+    r->neg = 0;
+  }
+
   return 1;
 }
 
@@ -215,6 +219,10 @@
   }
   r->top = j;
 
+  if (r->top == 0) {
+    r->neg = 0;
+  }
+
   return 1;
 }
 
diff --git a/src/crypto/cipher/e_tls.c b/src/crypto/cipher/e_tls.c
index 95483e7..c0d18fd 100644
--- a/src/crypto/cipher/e_tls.c
+++ b/src/crypto/cipher/e_tls.c
@@ -262,7 +262,7 @@
 
   /* Remove CBC padding. Code from here on is timing-sensitive with respect to
    * |padding_ok| and |data_plus_mac_len| for CBC ciphers. */
-  unsigned padding_ok, data_plus_mac_len, data_len;
+  unsigned padding_ok, data_plus_mac_len;
   if (EVP_CIPHER_CTX_mode(&tls_ctx->cipher_ctx) == EVP_CIPH_CBC_MODE) {
     if (!EVP_tls_cbc_remove_padding(
             &padding_ok, &data_plus_mac_len, out, total,
@@ -279,7 +279,7 @@
      * already been checked against the MAC size at the top of the function. */
     assert(data_plus_mac_len >= HMAC_size(&tls_ctx->hmac_ctx));
   }
-  data_len = data_plus_mac_len - HMAC_size(&tls_ctx->hmac_ctx);
+  unsigned data_len = data_plus_mac_len - HMAC_size(&tls_ctx->hmac_ctx);
 
   /* At this point, if the padding is valid, the first |data_plus_mac_len| bytes
    * after |out| are the plaintext and MAC. Otherwise, |data_plus_mac_len| is
diff --git a/src/crypto/conf/conf.c b/src/crypto/conf/conf.c
index e4fc428..96a534a 100644
--- a/src/crypto/conf/conf.c
+++ b/src/crypto/conf/conf.c
@@ -786,3 +786,5 @@
 void CONF_modules_free(void) {}
 
 void OPENSSL_config(CONF_MUST_BE_NULL *config_name) {}
+
+void OPENSSL_no_config(void) {}
diff --git a/src/crypto/curve25519/curve25519.c b/src/crypto/curve25519/curve25519.c
index 93ef7dc..d660b6c 100644
--- a/src/crypto/curve25519/curve25519.c
+++ b/src/crypto/curve25519/curve25519.c
@@ -640,9 +640,6 @@
   int i;
 
   fe_sq(t0, z);
-  for (i = 1; i < 1; ++i) {
-    fe_sq(t0, t0);
-  }
   fe_sq(t1, t0);
   for (i = 1; i < 2; ++i) {
     fe_sq(t1, t1);
@@ -650,9 +647,6 @@
   fe_mul(t1, z, t1);
   fe_mul(t0, t0, t1);
   fe_sq(t2, t0);
-  for (i = 1; i < 1; ++i) {
-    fe_sq(t2, t2);
-  }
   fe_mul(t1, t1, t2);
   fe_sq(t2, t1);
   for (i = 1; i < 5; ++i) {
@@ -907,9 +901,6 @@
   int i;
 
   fe_sq(t0, z);
-  for (i = 1; i < 1; ++i) {
-    fe_sq(t0, t0);
-  }
   fe_sq(t1, t0);
   for (i = 1; i < 2; ++i) {
     fe_sq(t1, t1);
@@ -917,9 +908,6 @@
   fe_mul(t1, z, t1);
   fe_mul(t0, t0, t1);
   fe_sq(t0, t0);
-  for (i = 1; i < 1; ++i) {
-    fe_sq(t0, t0);
-  }
   fe_mul(t0, t1, t0);
   fe_sq(t1, t0);
   for (i = 1; i < 5; ++i) {
@@ -4625,20 +4613,7 @@
 void ED25519_keypair(uint8_t out_public_key[32], uint8_t out_private_key[64]) {
   uint8_t seed[32];
   RAND_bytes(seed, 32);
-
-  uint8_t az[SHA512_DIGEST_LENGTH];
-  SHA512(seed, 32, az);
-
-  az[0] &= 248;
-  az[31] &= 63;
-  az[31] |= 64;
-
-  ge_p3 A;
-  x25519_ge_scalarmult_base(&A, az);
-  ge_p3_tobytes(out_public_key, &A);
-
-  memcpy(out_private_key, seed, 32);
-  memmove(out_private_key + 32, out_public_key, 32);
+  ED25519_keypair_from_seed(out_public_key, out_private_key, seed);
 }
 
 int ED25519_sign(uint8_t *out_sig, const uint8_t *message, size_t message_len,
@@ -4712,6 +4687,24 @@
   return CRYPTO_memcmp(rcheck, rcopy, sizeof(rcheck)) == 0;
 }
 
+void ED25519_keypair_from_seed(uint8_t out_public_key[32],
+                               uint8_t out_private_key[64],
+                               const uint8_t seed[32]) {
+  uint8_t az[SHA512_DIGEST_LENGTH];
+  SHA512(seed, 32, az);
+
+  az[0] &= 248;
+  az[31] &= 63;
+  az[31] |= 64;
+
+  ge_p3 A;
+  x25519_ge_scalarmult_base(&A, az);
+  ge_p3_tobytes(out_public_key, &A);
+
+  memcpy(out_private_key, seed, 32);
+  memcpy(out_private_key + 32, out_public_key, 32);
+}
+
 
 #if defined(BORINGSSL_X25519_X86_64)
 
diff --git a/src/crypto/curve25519/ed25519_test.cc b/src/crypto/curve25519/ed25519_test.cc
index 1b6a0b6..5af8ba7 100644
--- a/src/crypto/curve25519/ed25519_test.cc
+++ b/src/crypto/curve25519/ed25519_test.cc
@@ -53,11 +53,30 @@
   return true;
 }
 
+static bool TestKeypairFromSeed() {
+  uint8_t public_key1[32], private_key1[64];
+  ED25519_keypair(public_key1, private_key1);
+
+  uint8_t seed[32];
+  memcpy(seed, private_key1, sizeof(seed));
+
+  uint8_t public_key2[32], private_key2[64];
+  ED25519_keypair_from_seed(public_key2, private_key2, seed);
+
+  if (memcmp(public_key1, public_key2, sizeof(public_key1)) != 0 ||
+      memcmp(private_key1, private_key2, sizeof(private_key1)) != 0) {
+    fprintf(stderr, "TestKeypairFromSeed: resulting keypairs did not match.\n");
+    return false;
+  }
+
+  return true;
+}
+
 int main(int argc, char **argv) {
   if (argc != 2) {
     fprintf(stderr, "%s <test input.txt>\n", argv[0]);
     return 1;
   }
 
-  return FileTestMain(TestSignature, nullptr, argv[1]);
+  return TestKeypairFromSeed() && FileTestMain(TestSignature, nullptr, argv[1]);
 }
diff --git a/src/crypto/ec/CMakeLists.txt b/src/crypto/ec/CMakeLists.txt
index 4749484..a54075c 100644
--- a/src/crypto/ec/CMakeLists.txt
+++ b/src/crypto/ec/CMakeLists.txt
@@ -46,6 +46,15 @@
   $<TARGET_OBJECTS:test_support>
 )
 
+add_executable(
+  p256-x86_64_test
+
+  p256-x86_64_test.cc
+
+  $<TARGET_OBJECTS:test_support>
+)
+
 target_link_libraries(example_mul crypto)
 target_link_libraries(ec_test crypto)
-add_dependencies(all_tests example_mul ec_test)
+target_link_libraries(p256-x86_64_test crypto)
+add_dependencies(all_tests example_mul ec_test p256-x86_64_test)
diff --git a/src/crypto/ec/asm/p256-x86_64-asm.pl b/src/crypto/ec/asm/p256-x86_64-asm.pl
index 0a7d640..a0b4b18 100755
--- a/src/crypto/ec/asm/p256-x86_64-asm.pl
+++ b/src/crypto/ec/asm/p256-x86_64-asm.pl
@@ -94,6 +94,7 @@
 	push	%r13
 
 	mov	8*0($a_ptr), $a0
+	xor	$t4,$t4
 	mov	8*1($a_ptr), $a1
 	add	$a0, $a0		# a0:a3+a0:a3
 	mov	8*2($a_ptr), $a2
@@ -104,7 +105,7 @@
 	adc	$a2, $a2
 	adc	$a3, $a3
 	 mov	$a1, $t1
-	sbb	$t4, $t4
+	adc	\$0, $t4
 
 	sub	8*0($a_ptr), $a0
 	 mov	$a2, $t2
@@ -112,14 +113,14 @@
 	sbb	8*2($a_ptr), $a2
 	 mov	$a3, $t3
 	sbb	8*3($a_ptr), $a3
-	test	$t4, $t4
+	sbb	\$0, $t4
 
-	cmovz	$t0, $a0
-	cmovz	$t1, $a1
+	cmovc	$t0, $a0
+	cmovc	$t1, $a1
 	mov	$a0, 8*0($r_ptr)
-	cmovz	$t2, $a2
+	cmovc	$t2, $a2
 	mov	$a1, 8*1($r_ptr)
-	cmovz	$t3, $a3
+	cmovc	$t3, $a3
 	mov	$a2, 8*2($r_ptr)
 	mov	$a3, 8*3($r_ptr)
 
@@ -1570,13 +1571,14 @@
 .type	__ecp_nistz256_add_toq,\@abi-omnipotent
 .align	32
 __ecp_nistz256_add_toq:
+	xor	$t4,$t4
 	add	8*0($b_ptr), $a0
 	adc	8*1($b_ptr), $a1
 	 mov	$a0, $t0
 	adc	8*2($b_ptr), $a2
 	adc	8*3($b_ptr), $a3
 	 mov	$a1, $t1
-	sbb	$t4, $t4
+	adc	\$0, $t4
 
 	sub	\$-1, $a0
 	 mov	$a2, $t2
@@ -1584,14 +1586,14 @@
 	sbb	\$0, $a2
 	 mov	$a3, $t3
 	sbb	$poly3, $a3
-	test	$t4, $t4
+	sbb	\$0, $t4
 
-	cmovz	$t0, $a0
-	cmovz	$t1, $a1
+	cmovc	$t0, $a0
+	cmovc	$t1, $a1
 	mov	$a0, 8*0($r_ptr)
-	cmovz	$t2, $a2
+	cmovc	$t2, $a2
 	mov	$a1, 8*1($r_ptr)
-	cmovz	$t3, $a3
+	cmovc	$t3, $a3
 	mov	$a2, 8*2($r_ptr)
 	mov	$a3, 8*3($r_ptr)
 
@@ -1659,13 +1661,14 @@
 .type	__ecp_nistz256_mul_by_2q,\@abi-omnipotent
 .align	32
 __ecp_nistz256_mul_by_2q:
+	xor	$t4, $t4
 	add	$a0, $a0		# a0:a3+a0:a3
 	adc	$a1, $a1
 	 mov	$a0, $t0
 	adc	$a2, $a2
 	adc	$a3, $a3
 	 mov	$a1, $t1
-	sbb	$t4, $t4
+	adc	\$0, $t4
 
 	sub	\$-1, $a0
 	 mov	$a2, $t2
@@ -1673,14 +1676,14 @@
 	sbb	\$0, $a2
 	 mov	$a3, $t3
 	sbb	$poly3, $a3
-	test	$t4, $t4
+	sbb	\$0, $t4
 
-	cmovz	$t0, $a0
-	cmovz	$t1, $a1
+	cmovc	$t0, $a0
+	cmovc	$t1, $a1
 	mov	$a0, 8*0($r_ptr)
-	cmovz	$t2, $a2
+	cmovc	$t2, $a2
 	mov	$a1, 8*1($r_ptr)
-	cmovz	$t3, $a3
+	cmovc	$t3, $a3
 	mov	$a2, 8*2($r_ptr)
 	mov	$a3, 8*3($r_ptr)
 
@@ -1971,16 +1974,14 @@
 	mov	$b_org, $a_ptr			# reassign
 	movdqa	%xmm0, $in1_x(%rsp)
 	movdqa	%xmm1, $in1_x+0x10(%rsp)
-	por	%xmm0, %xmm1
 	movdqa	%xmm2, $in1_y(%rsp)
 	movdqa	%xmm3, $in1_y+0x10(%rsp)
-	por	%xmm2, %xmm3
 	movdqa	%xmm4, $in1_z(%rsp)
 	movdqa	%xmm5, $in1_z+0x10(%rsp)
-	por	%xmm1, %xmm3
+	por	%xmm4, %xmm5
 
 	movdqu	0x00($a_ptr), %xmm0		# copy	*(P256_POINT *)$b_ptr
-	 pshufd	\$0xb1, %xmm3, %xmm5
+	 pshufd	\$0xb1, %xmm5, %xmm3
 	movdqu	0x10($a_ptr), %xmm1
 	movdqu	0x20($a_ptr), %xmm2
 	 por	%xmm3, %xmm5
@@ -1992,14 +1993,14 @@
 	movdqa	%xmm0, $in2_x(%rsp)
 	 pshufd	\$0x1e, %xmm5, %xmm4
 	movdqa	%xmm1, $in2_x+0x10(%rsp)
-	por	%xmm0, %xmm1
-	 movq	$r_ptr, %xmm0			# save $r_ptr
+	movdqu	0x40($a_ptr),%xmm0		# in2_z again
+	movdqu	0x50($a_ptr),%xmm1
 	movdqa	%xmm2, $in2_y(%rsp)
 	movdqa	%xmm3, $in2_y+0x10(%rsp)
-	por	%xmm2, %xmm3
 	 por	%xmm4, %xmm5
 	 pxor	%xmm4, %xmm4
-	por	%xmm1, %xmm3
+	por	%xmm0, %xmm1
+	 movq	$r_ptr, %xmm0			# save $r_ptr
 
 	lea	0x40-$bias($a_ptr), $a_ptr	# $a_ptr is still valid
 	 mov	$src0, $in2_z+8*0(%rsp)		# make in2_z copy
@@ -2010,8 +2011,8 @@
 	call	__ecp_nistz256_sqr_mont$x	# p256_sqr_mont(Z2sqr, in2_z);
 
 	pcmpeqd	%xmm4, %xmm5
-	pshufd	\$0xb1, %xmm3, %xmm4
-	por	%xmm3, %xmm4
+	pshufd	\$0xb1, %xmm1, %xmm4
+	por	%xmm1, %xmm4
 	pshufd	\$0, %xmm5, %xmm5		# in1infty
 	pshufd	\$0x1e, %xmm4, %xmm3
 	por	%xmm3, %xmm4
@@ -2135,6 +2136,7 @@
 	#lea	$Hsqr(%rsp), $r_ptr	# 2*U1*H^2
 	#call	__ecp_nistz256_mul_by_2	# ecp_nistz256_mul_by_2(Hsqr, U2);
 
+	xor	$t4, $t4
 	add	$acc0, $acc0		# a0:a3+a0:a3
 	lea	$Rsqr(%rsp), $a_ptr
 	adc	$acc1, $acc1
@@ -2142,7 +2144,7 @@
 	adc	$acc2, $acc2
 	adc	$acc3, $acc3
 	 mov	$acc1, $t1
-	sbb	$t4, $t4
+	adc	\$0, $t4
 
 	sub	\$-1, $acc0
 	 mov	$acc2, $t2
@@ -2150,15 +2152,15 @@
 	sbb	\$0, $acc2
 	 mov	$acc3, $t3
 	sbb	$poly3, $acc3
-	test	$t4, $t4
+	sbb	\$0, $t4
 
-	cmovz	$t0, $acc0
+	cmovc	$t0, $acc0
 	mov	8*0($a_ptr), $t0
-	cmovz	$t1, $acc1
+	cmovc	$t1, $acc1
 	mov	8*1($a_ptr), $t1
-	cmovz	$t2, $acc2
+	cmovc	$t2, $acc2
 	mov	8*2($a_ptr), $t2
-	cmovz	$t3, $acc3
+	cmovc	$t3, $acc3
 	mov	8*3($a_ptr), $t3
 
 	call	__ecp_nistz256_sub$x		# p256_sub(res_x, Rsqr, Hsqr);
@@ -2342,16 +2344,14 @@
 	 mov	0x40+8*3($a_ptr), $acc0
 	movdqa	%xmm0, $in1_x(%rsp)
 	movdqa	%xmm1, $in1_x+0x10(%rsp)
-	por	%xmm0, %xmm1
 	movdqa	%xmm2, $in1_y(%rsp)
 	movdqa	%xmm3, $in1_y+0x10(%rsp)
-	por	%xmm2, %xmm3
 	movdqa	%xmm4, $in1_z(%rsp)
 	movdqa	%xmm5, $in1_z+0x10(%rsp)
-	por	%xmm1, %xmm3
+	por	%xmm4, %xmm5
 
 	movdqu	0x00($b_ptr), %xmm0	# copy	*(P256_POINT_AFFINE *)$b_ptr
-	 pshufd	\$0xb1, %xmm3, %xmm5
+	 pshufd	\$0xb1, %xmm5, %xmm3
 	movdqu	0x10($b_ptr), %xmm1
 	movdqu	0x20($b_ptr), %xmm2
 	 por	%xmm3, %xmm5
@@ -2440,6 +2440,7 @@
 	#lea	$Hsqr(%rsp), $r_ptr	# 2*U1*H^2
 	#call	__ecp_nistz256_mul_by_2	# ecp_nistz256_mul_by_2(Hsqr, U2);
 
+	xor	$t4, $t4
 	add	$acc0, $acc0		# a0:a3+a0:a3
 	lea	$Rsqr(%rsp), $a_ptr
 	adc	$acc1, $acc1
@@ -2447,7 +2448,7 @@
 	adc	$acc2, $acc2
 	adc	$acc3, $acc3
 	 mov	$acc1, $t1
-	sbb	$t4, $t4
+	adc	\$0, $t4
 
 	sub	\$-1, $acc0
 	 mov	$acc2, $t2
@@ -2455,15 +2456,15 @@
 	sbb	\$0, $acc2
 	 mov	$acc3, $t3
 	sbb	$poly3, $acc3
-	test	$t4, $t4
+	sbb	\$0, $t4
 
-	cmovz	$t0, $acc0
+	cmovc	$t0, $acc0
 	mov	8*0($a_ptr), $t0
-	cmovz	$t1, $acc1
+	cmovc	$t1, $acc1
 	mov	8*1($a_ptr), $t1
-	cmovz	$t2, $acc2
+	cmovc	$t2, $acc2
 	mov	8*2($a_ptr), $t2
-	cmovz	$t3, $acc3
+	cmovc	$t3, $acc3
 	mov	8*3($a_ptr), $t3
 
 	call	__ecp_nistz256_sub$x		# p256_sub(res_x, Rsqr, Hsqr);
@@ -2615,14 +2616,14 @@
 	sbb	\$0, $a2
 	 mov	$a3, $t3
 	sbb	$poly3, $a3
+	sbb	\$0, $t4
 
-	bt	\$0, $t4
-	cmovnc	$t0, $a0
-	cmovnc	$t1, $a1
+	cmovc	$t0, $a0
+	cmovc	$t1, $a1
 	mov	$a0, 8*0($r_ptr)
-	cmovnc	$t2, $a2
+	cmovc	$t2, $a2
 	mov	$a1, 8*1($r_ptr)
-	cmovnc	$t3, $a3
+	cmovc	$t3, $a3
 	mov	$a2, 8*2($r_ptr)
 	mov	$a3, 8*3($r_ptr)
 
@@ -2710,14 +2711,14 @@
 	sbb	\$0, $a2
 	 mov	$a3, $t3
 	sbb	$poly3, $a3
+	sbb	\$0, $t4
 
-	bt	\$0, $t4
-	cmovnc	$t0, $a0
-	cmovnc	$t1, $a1
+	cmovc	$t0, $a0
+	cmovc	$t1, $a1
 	mov	$a0, 8*0($r_ptr)
-	cmovnc	$t2, $a2
+	cmovc	$t2, $a2
 	mov	$a1, 8*1($r_ptr)
-	cmovnc	$t3, $a3
+	cmovc	$t3, $a3
 	mov	$a2, 8*2($r_ptr)
 	mov	$a3, 8*3($r_ptr)
 
diff --git a/src/crypto/ec/ec_test.cc b/src/crypto/ec/ec_test.cc
index 839acfe..31619b1 100644
--- a/src/crypto/ec/ec_test.cc
+++ b/src/crypto/ec/ec_test.cc
@@ -26,8 +26,6 @@
 #include <openssl/nid.h>
 
 
-namespace bssl {
-
 // kECKeyWithoutPublic is an ECPrivateKey with the optional publicKey field
 // omitted.
 static const uint8_t kECKeyWithoutPublic[] = {
@@ -112,7 +110,7 @@
 // EncodeECPrivateKey encodes |key| as an ECPrivateKey structure into |*out|. It
 // returns true on success or false on error.
 static bool EncodeECPrivateKey(std::vector<uint8_t> *out, const EC_KEY *key) {
-  ScopedCBB cbb;
+  bssl::ScopedCBB cbb;
   uint8_t *der;
   size_t der_len;
   if (!CBB_init(cbb.get(), 0) ||
@@ -459,6 +457,51 @@
   return true;
 }
 
+static bool TestMulZero(int nid) {
+  bssl::UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(nid));
+  if (!group) {
+    return false;
+  }
+
+  bssl::UniquePtr<EC_POINT> point(EC_POINT_new(group.get()));
+  bssl::UniquePtr<BIGNUM> zero(BN_new());
+  if (!point || !zero) {
+    return false;
+  }
+
+  BN_zero(zero.get());
+  if (!EC_POINT_mul(group.get(), point.get(), zero.get(), nullptr, nullptr,
+                    nullptr)) {
+    return false;
+  }
+
+  if (!EC_POINT_is_at_infinity(group.get(), point.get())) {
+    fprintf(stderr, "g * 0 did not return point at infinity.\n");
+    return false;
+  }
+
+  // Test that zero times an arbitrary point is also infinity. The generator is
+  // used as the arbitrary point.
+  bssl::UniquePtr<EC_POINT> generator(EC_POINT_new(group.get()));
+  bssl::UniquePtr<BIGNUM> one(BN_new());
+  if (!generator ||
+      !one ||
+      !BN_one(one.get()) ||
+      !EC_POINT_mul(group.get(), generator.get(), one.get(), nullptr, nullptr,
+                    nullptr) ||
+      !EC_POINT_mul(group.get(), point.get(), nullptr, generator.get(),
+                    zero.get(), nullptr)) {
+    return false;
+  }
+
+  if (!EC_POINT_is_at_infinity(group.get(), point.get())) {
+    fprintf(stderr, "p * 0 did not return point at infinity.\n");
+    return false;
+  }
+
+  return true;
+}
+
 static bool ForEachCurve(bool (*test_func)(int nid)) {
   const size_t num_curves = EC_get_builtin_curves(nullptr, 0);
   std::vector<EC_builtin_curve> curves(num_curves);
@@ -474,7 +517,7 @@
   return true;
 }
 
-static int Main() {
+int main() {
   CRYPTO_library_init();
 
   if (!Testd2i_ECPrivateKey() ||
@@ -482,6 +525,7 @@
       !TestSpecifiedCurve() ||
       !ForEachCurve(TestSetAffine) ||
       !ForEachCurve(TestAddingEqualPoints) ||
+      !ForEachCurve(TestMulZero) ||
       !TestArbitraryCurve()) {
     fprintf(stderr, "failed\n");
     return 1;
@@ -490,9 +534,3 @@
   printf("PASS\n");
   return 0;
 }
-
-}  // namespace bssl
-
-int main() {
-  return bssl::Main();
-}
diff --git a/src/crypto/ec/p256-x86_64.c b/src/crypto/ec/p256-x86_64.c
index a5906e4..0a3be92 100644
--- a/src/crypto/ec/p256-x86_64.c
+++ b/src/crypto/ec/p256-x86_64.c
@@ -31,56 +31,16 @@
 #include <openssl/err.h>
 
 #include "../bn/internal.h"
-#include "../ec/internal.h"
 #include "../internal.h"
+#include "internal.h"
+#include "p256-x86_64.h"
 
 
 #if !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86_64) && \
     !defined(OPENSSL_SMALL)
 
-
-#define P256_LIMBS (256 / BN_BITS2)
-
-typedef struct {
-  BN_ULONG X[P256_LIMBS];
-  BN_ULONG Y[P256_LIMBS];
-  BN_ULONG Z[P256_LIMBS];
-} P256_POINT;
-
-typedef struct {
-  BN_ULONG X[P256_LIMBS];
-  BN_ULONG Y[P256_LIMBS];
-} P256_POINT_AFFINE;
-
 typedef P256_POINT_AFFINE PRECOMP256_ROW[64];
 
-/* Arithmetic on field elements using Almost Montgomery Multiplication. The
- * "almost" means, in particular, that the inputs and outputs of these
- * functions are in the range [0, 2**BN_BITS2), not [0, P). Only
- * |ecp_nistz256_from_mont| outputs a fully reduced value in [0, P). Almost
- * Montgomery Arithmetic is described clearly in "Efficient Software
- * Implementations of Modular Exponentiation" by Shay Gueron. */
-
-/* Modular neg: res = -a mod P, where res is not fully reduced. */
-void ecp_nistz256_neg(BN_ULONG res[P256_LIMBS], const BN_ULONG a[P256_LIMBS]);
-/* Montgomery mul: res = a*b*2^-256 mod P, where res is not fully reduced. */
-void ecp_nistz256_mul_mont(BN_ULONG res[P256_LIMBS],
-                           const BN_ULONG a[P256_LIMBS],
-                           const BN_ULONG b[P256_LIMBS]);
-/* Montgomery sqr: res = a*a*2^-256 mod P, where res is not fully reduced. */
-void ecp_nistz256_sqr_mont(BN_ULONG res[P256_LIMBS],
-                           const BN_ULONG a[P256_LIMBS]);
-/* Convert a number from Montgomery domain, by multiplying with 1, where res
- * will be fully reduced mod P. */
-void ecp_nistz256_from_mont(BN_ULONG res[P256_LIMBS],
-                            const BN_ULONG in[P256_LIMBS]);
-
-
-/* Functions that perform constant time access to the precomputed tables */
-void ecp_nistz256_select_w5(P256_POINT *val, const P256_POINT *in_t, int index);
-void ecp_nistz256_select_w7(P256_POINT_AFFINE *val,
-                            const P256_POINT_AFFINE *in_t, int index);
-
 /* One converted into the Montgomery domain */
 static const BN_ULONG ONE[P256_LIMBS] = {
     TOBN(0x00000000, 0x00000001), TOBN(0xffffffff, 0x00000000),
@@ -90,7 +50,7 @@
 /* Precomputed tables for the default generator */
 #include "p256-x86_64-table.h"
 
-/* Recode window to a signed digit, see ecp_nistputil.c for details */
+/* Recode window to a signed digit, see util-64.c for details */
 static unsigned booth_recode_w5(unsigned in) {
   unsigned s, d;
 
@@ -113,6 +73,11 @@
   return (d << 1) + (s & 1);
 }
 
+/* copy_conditional copies |src| to |dst| if |move| is one and leaves it as-is
+ * if |move| is zero.
+ *
+ * WARNING: this breaks the usual convention of constant-time functions
+ * returning masks. */
 static void copy_conditional(BN_ULONG dst[P256_LIMBS],
                              const BN_ULONG src[P256_LIMBS], BN_ULONG move) {
   BN_ULONG mask1 = ((BN_ULONG)0) - move;
@@ -130,15 +95,34 @@
   }
 }
 
-void ecp_nistz256_point_double(P256_POINT *r, const P256_POINT *a);
-void ecp_nistz256_point_add(P256_POINT *r, const P256_POINT *a,
-                            const P256_POINT *b);
-void ecp_nistz256_point_add_affine(P256_POINT *r, const P256_POINT *a,
-                                   const P256_POINT_AFFINE *b);
+/* is_not_zero returns one iff in != 0 and zero otherwise.
+ *
+ * WARNING: this breaks the usual convention of constant-time functions
+ * returning masks.
+ *
+ * (define-fun is_not_zero ((in (_ BitVec 64))) (_ BitVec 64)
+ *   (bvlshr (bvor in (bvsub #x0000000000000000 in)) #x000000000000003f)
+ * )
+ *
+ * (declare-fun x () (_ BitVec 64))
+ *
+ * (assert (and (= x #x0000000000000000) (= (is_not_zero x) #x0000000000000001)))
+ * (check-sat)
+ *
+ * (assert (and (not (= x #x0000000000000000)) (= (is_not_zero x) #x0000000000000000)))
+ * (check-sat)
+ * */
+static BN_ULONG is_not_zero(BN_ULONG in) {
+  in |= (0 - in);
+  in >>= BN_BITS2 - 1;
+  return in;
+}
 
-/* r = in^-1 mod p */
-static void ecp_nistz256_mod_inverse(BN_ULONG r[P256_LIMBS],
-                                     const BN_ULONG in[P256_LIMBS]) {
+/* ecp_nistz256_mod_inverse_mont sets |r| to (|in| * 2^-256)^-1 * 2^256 mod p.
+ * That is, |r| is the modular inverse of |in| for input and output in the
+ * Montgomery domain. */
+static void ecp_nistz256_mod_inverse_mont(BN_ULONG r[P256_LIMBS],
+                                          const BN_ULONG in[P256_LIMBS]) {
   /* The poly is ffffffff 00000001 00000000 00000000 00000000 ffffffff ffffffff
      ffffffff
      We use FLT and used poly-2 as exponent */
@@ -454,7 +438,11 @@
     ecp_nistz256_neg(p.p.Z, p.p.Y);
     copy_conditional(p.p.Y, p.p.Z, wvalue & 1);
 
-    memcpy(p.p.Z, ONE, sizeof(ONE));
+    /* Convert |p| from affine to Jacobian coordinates. We set Z to zero if |p|
+     * is infinity and |ONE| otherwise. |p| was computed from the table, so it
+     * is infinity iff |wvalue >> 1| is zero.  */
+    memset(p.p.Z, 0, sizeof(p.p.Z));
+    copy_conditional(p.p.Z, ONE, is_not_zero(wvalue >> 1));
 
     for (i = 1; i < 37; i++) {
       unsigned off = (index - 1) / 8;
@@ -524,13 +512,11 @@
     return 0;
   }
 
-  ecp_nistz256_mod_inverse(z_inv3, point_z);
+  ecp_nistz256_mod_inverse_mont(z_inv3, point_z);
   ecp_nistz256_sqr_mont(z_inv2, z_inv3);
 
-  /* Unlike the |BN_mod_mul_montgomery|-based implementation, we cannot factor
-   * out the two calls to |ecp_nistz256_from_mont| into one call, because
-   * |ecp_nistz256_from_mont| must be the last operation to ensure that the
-   * result is fully reduced mod P. */
+  /* TODO(davidben): The two calls to |ecp_nistz256_from_mont| may be factored
+   * into one call now that other operations also reduce mod P. */
 
   if (x != NULL) {
     BN_ULONG x_aff[P256_LIMBS];
diff --git a/src/crypto/ec/p256-x86_64.h b/src/crypto/ec/p256-x86_64.h
new file mode 100644
index 0000000..9897699
--- /dev/null
+++ b/src/crypto/ec/p256-x86_64.h
@@ -0,0 +1,110 @@
+/* Copyright (c) 2014, Intel Corporation.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#ifndef OPENSSL_HEADER_EC_P256_X86_64_H
+#define OPENSSL_HEADER_EC_P256_X86_64_H
+
+#include <openssl/base.h>
+
+#include <openssl/bn.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+#if !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86_64) && \
+    !defined(OPENSSL_SMALL)
+
+/* P-256 field operations.
+ *
+ * An element mod P in P-256 is represented as a little-endian array of
+ * |P256_LIMBS| |BN_ULONG|s, spanning the full range of values.
+ *
+ * The following functions take fully-reduced inputs mod P and give
+ * fully-reduced outputs. They may be used in-place. */
+
+#define P256_LIMBS (256 / BN_BITS2)
+
+/* ecp_nistz256_neg sets |res| to -|a| mod P. */
+void ecp_nistz256_neg(BN_ULONG res[P256_LIMBS], const BN_ULONG a[P256_LIMBS]);
+
+/* ecp_nistz256_mul_mont sets |res| to |a| * |b| * 2^-256 mod P. */
+void ecp_nistz256_mul_mont(BN_ULONG res[P256_LIMBS],
+                           const BN_ULONG a[P256_LIMBS],
+                           const BN_ULONG b[P256_LIMBS]);
+
+/* ecp_nistz256_sqr_mont sets |res| to |a| * |a| * 2^-256 mod P. */
+void ecp_nistz256_sqr_mont(BN_ULONG res[P256_LIMBS],
+                           const BN_ULONG a[P256_LIMBS]);
+
+/* ecp_nistz256_from_mont sets |res| to |in|, converted from Montgomery domain
+ * by multiplying with 1. */
+void ecp_nistz256_from_mont(BN_ULONG res[P256_LIMBS],
+                            const BN_ULONG in[P256_LIMBS]);
+
+
+/* P-256 point operations.
+ *
+ * The following functions may be used in-place. All coordinates are in the
+ * Montgomery domain. */
+
+/* A P256_POINT represents a P-256 point in Jacobian coordinates. */
+typedef struct {
+  BN_ULONG X[P256_LIMBS];
+  BN_ULONG Y[P256_LIMBS];
+  BN_ULONG Z[P256_LIMBS];
+} P256_POINT;
+
+/* A P256_POINT_AFFINE represents a P-256 point in affine coordinates. Infinity
+ * is encoded as (0, 0). */
+typedef struct {
+  BN_ULONG X[P256_LIMBS];
+  BN_ULONG Y[P256_LIMBS];
+} P256_POINT_AFFINE;
+
+/* ecp_nistz256_select_w5 sets |*val| to |in_t[index-1]| if 1 <= |index| <= 16
+ * and all zeros (the point at infinity) if |index| is 0. This is done in
+ * constant time. */
+void ecp_nistz256_select_w5(P256_POINT *val, const P256_POINT in_t[16],
+                            int index);
+
+/* ecp_nistz256_select_w7 sets |*val| to |in_t[index-1]| if 1 <= |index| <= 64
+ * and all zeros (the point at infinity) if |index| is 0. This is done in
+ * constant time. */
+void ecp_nistz256_select_w7(P256_POINT_AFFINE *val,
+                            const P256_POINT_AFFINE in_t[64], int index);
+
+/* ecp_nistz256_point_double sets |r| to |a| doubled. */
+void ecp_nistz256_point_double(P256_POINT *r, const P256_POINT *a);
+
+/* ecp_nistz256_point_add adds |a| to |b| and places the result in |r|. */
+void ecp_nistz256_point_add(P256_POINT *r, const P256_POINT *a,
+                            const P256_POINT *b);
+
+/* ecp_nistz256_point_add_affine adds |a| to |b| and places the result in
+ * |r|. |a| and |b| must not represent the same point unless they are both
+ * infinity. */
+void ecp_nistz256_point_add_affine(P256_POINT *r, const P256_POINT *a,
+                                   const P256_POINT_AFFINE *b);
+
+#endif /* !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86_64) && \
+           !defined(OPENSSL_SMALL) */
+
+
+#if defined(__cplusplus)
+}  /* extern C++ */
+#endif
+
+#endif  /* OPENSSL_HEADER_EC_P256_X86_64_H */
diff --git a/src/crypto/ec/p256-x86_64_test.cc b/src/crypto/ec/p256-x86_64_test.cc
new file mode 100644
index 0000000..531edcf
--- /dev/null
+++ b/src/crypto/ec/p256-x86_64_test.cc
@@ -0,0 +1,508 @@
+/* Copyright (c) 2016, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#if !defined(__STDC_FORMAT_MACROS)
+#define __STDC_FORMAT_MACROS
+#endif
+
+#include <openssl/base.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include <openssl/bn.h>
+#include <openssl/mem.h>
+
+#include "../bn/internal.h"
+#include "../test/file_test.h"
+#include "p256-x86_64.h"
+
+
+// Disable tests if BORINGSSL_SHARED_LIBRARY is defined. These tests need access
+// to internal functions.
+#if !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86_64) && \
+    !defined(OPENSSL_SMALL) && !defined(BORINGSSL_SHARED_LIBRARY)
+
+static bool TestSelectW5() {
+  // Fill a table with some garbage input.
+  P256_POINT table[16];
+  for (size_t i = 0; i < 16; i++) {
+    memset(table[i].X, 3 * i, sizeof(table[i].X));
+    memset(table[i].Y, 3 * i + 1, sizeof(table[i].Y));
+    memset(table[i].Z, 3 * i + 2, sizeof(table[i].Z));
+  }
+
+  for (int i = 0; i <= 16; i++) {
+    P256_POINT val;
+    ecp_nistz256_select_w5(&val, table, i);
+
+    P256_POINT expected;
+    if (i == 0) {
+      memset(&expected, 0, sizeof(expected));
+    } else {
+      expected = table[i-1];
+    }
+
+    if (memcmp(&val, &expected, sizeof(P256_POINT)) != 0) {
+      fprintf(stderr, "ecp_nistz256_select_w5(%d) gave the wrong value.\n", i);
+      return false;
+    }
+  }
+
+  return true;
+}
+
+static bool TestSelectW7() {
+  // Fill a table with some garbage input.
+  P256_POINT_AFFINE table[64];
+  for (size_t i = 0; i < 64; i++) {
+    memset(table[i].X, 2 * i, sizeof(table[i].X));
+    memset(table[i].Y, 2 * i + 1, sizeof(table[i].Y));
+  }
+
+  for (int i = 0; i <= 64; i++) {
+    P256_POINT_AFFINE val;
+    ecp_nistz256_select_w7(&val, table, i);
+
+    P256_POINT_AFFINE expected;
+    if (i == 0) {
+      memset(&expected, 0, sizeof(expected));
+    } else {
+      expected = table[i-1];
+    }
+
+    if (memcmp(&val, &expected, sizeof(P256_POINT_AFFINE)) != 0) {
+      fprintf(stderr, "ecp_nistz256_select_w7(%d) gave the wrong value.\n", i);
+      return false;
+    }
+  }
+
+  return true;
+}
+
+static bool GetFieldElement(FileTest *t, BN_ULONG out[P256_LIMBS],
+                            const char *name) {
+  std::vector<uint8_t> bytes;
+  if (!t->GetBytes(&bytes, name)) {
+    return false;
+  }
+
+  if (bytes.size() != BN_BYTES * P256_LIMBS) {
+    t->PrintLine("Invalid length: %s", name);
+    return false;
+  }
+
+  // |byte| contains bytes in big-endian while |out| should contain |BN_ULONG|s
+  // in little-endian.
+  memset(out, 0, P256_LIMBS * sizeof(BN_ULONG));
+  for (size_t i = 0; i < bytes.size(); i++) {
+    out[P256_LIMBS - 1 - (i / BN_BYTES)] <<= 8;
+    out[P256_LIMBS - 1 - (i / BN_BYTES)] |= bytes[i];
+  }
+
+  return true;
+}
+
+static std::string FieldElementToString(const BN_ULONG a[P256_LIMBS]) {
+  std::string ret;
+  for (size_t i = P256_LIMBS-1; i < P256_LIMBS; i--) {
+    char buf[2 * BN_BYTES + 1];
+    BIO_snprintf(buf, sizeof(buf), BN_HEX_FMT2, a[i]);
+    ret += buf;
+  }
+  return ret;
+}
+
+static bool ExpectFieldElementsEqual(FileTest *t, const char *message,
+                                     const BN_ULONG expected[P256_LIMBS],
+                                     const BN_ULONG actual[P256_LIMBS]) {
+  if (memcmp(expected, actual, sizeof(BN_ULONG) * P256_LIMBS) == 0) {
+    return true;
+  }
+
+  t->PrintLine("%s", message);
+  t->PrintLine("Expected: %s", FieldElementToString(expected).c_str());
+  t->PrintLine("Actual:   %s", FieldElementToString(actual).c_str());
+  return false;
+}
+
+static bool PointToAffine(P256_POINT_AFFINE *out, const P256_POINT *in) {
+  static const uint8_t kP[] = {
+      0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  };
+
+  bssl::UniquePtr<BIGNUM> x(BN_new()), y(BN_new()), z(BN_new());
+  bssl::UniquePtr<BIGNUM> p(BN_bin2bn(kP, sizeof(kP), nullptr));
+  if (!x || !y || !z || !p ||
+      !bn_set_words(x.get(), in->X, P256_LIMBS) ||
+      !bn_set_words(y.get(), in->Y, P256_LIMBS) ||
+      !bn_set_words(z.get(), in->Z, P256_LIMBS)) {
+    return false;
+  }
+
+  // Coordinates must be fully-reduced.
+  if (BN_cmp(x.get(), p.get()) >= 0 ||
+      BN_cmp(y.get(), p.get()) >= 0 ||
+      BN_cmp(z.get(), p.get()) >= 0) {
+    return false;
+  }
+
+  memset(out, 0, sizeof(P256_POINT_AFFINE));
+
+  if (BN_is_zero(z.get())) {
+    // The point at infinity is represented as (0, 0).
+    return true;
+  }
+
+  bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
+  bssl::UniquePtr<BN_MONT_CTX> mont(BN_MONT_CTX_new());
+  if (!ctx || !mont ||
+      !BN_MONT_CTX_set(mont.get(), p.get(), ctx.get()) ||
+      // Invert Z.
+      !BN_from_montgomery(z.get(), z.get(), mont.get(), ctx.get()) ||
+      !BN_mod_inverse(z.get(), z.get(), p.get(), ctx.get()) ||
+      !BN_to_montgomery(z.get(), z.get(), mont.get(), ctx.get()) ||
+      // Convert (X, Y, Z) to (X/Z^2, Y/Z^3).
+      !BN_mod_mul_montgomery(x.get(), x.get(), z.get(), mont.get(),
+                             ctx.get()) ||
+      !BN_mod_mul_montgomery(x.get(), x.get(), z.get(), mont.get(),
+                             ctx.get()) ||
+      !BN_mod_mul_montgomery(y.get(), y.get(), z.get(), mont.get(),
+                             ctx.get()) ||
+      !BN_mod_mul_montgomery(y.get(), y.get(), z.get(), mont.get(),
+                             ctx.get()) ||
+      !BN_mod_mul_montgomery(y.get(), y.get(), z.get(), mont.get(),
+                             ctx.get())) {
+    return false;
+  }
+
+  memcpy(out->X, x->d, sizeof(BN_ULONG) * x->top);
+  memcpy(out->Y, y->d, sizeof(BN_ULONG) * y->top);
+  return true;
+}
+
+static bool ExpectPointsEqual(FileTest *t, const char *message,
+                              const P256_POINT_AFFINE *expected,
+                              const P256_POINT *point) {
+  // There are multiple representations of the same |P256_POINT|, so convert to
+  // |P256_POINT_AFFINE| and compare.
+  P256_POINT_AFFINE affine;
+  if (!PointToAffine(&affine, point)) {
+    t->PrintLine("%s", message);
+    t->PrintLine("Could not convert to affine: (%s, %s, %s)",
+                 FieldElementToString(point->X).c_str(),
+                 FieldElementToString(point->Y).c_str(),
+                 FieldElementToString(point->Z).c_str());
+    return false;
+  }
+
+  if (memcmp(expected, &affine, sizeof(P256_POINT_AFFINE)) != 0) {
+    t->PrintLine("%s", message);
+    t->PrintLine("Expected: (%s, %s)",
+                 FieldElementToString(expected->X).c_str(),
+                 FieldElementToString(expected->Y).c_str());
+    t->PrintLine("Actual:   (%s, %s)", FieldElementToString(affine.X).c_str(),
+                 FieldElementToString(affine.Y).c_str());
+    return false;
+  }
+
+  return true;
+}
+
+static bool TestNegate(FileTest *t) {
+  BN_ULONG a[P256_LIMBS], b[P256_LIMBS];
+  if (!GetFieldElement(t, a, "A") ||
+      !GetFieldElement(t, b, "B")) {
+    return false;
+  }
+
+  // Test that -A = B.
+  BN_ULONG ret[P256_LIMBS];
+  ecp_nistz256_neg(ret, a);
+  if (!ExpectFieldElementsEqual(t, "ecp_nistz256_neg(A) was incorrect.", b,
+                                ret)) {
+    return false;
+  }
+
+  memcpy(ret, a, sizeof(ret));
+  ecp_nistz256_neg(ret, ret);
+  if (!ExpectFieldElementsEqual(
+          t, "In-place ecp_nistz256_neg(A) was incorrect.", b, ret)) {
+    return false;
+  }
+
+  // Test that -B = A.
+  ecp_nistz256_neg(ret, b);
+  if (!ExpectFieldElementsEqual(t, "ecp_nistz256_neg(B) was incorrect.", a,
+                                ret)) {
+    return false;
+  }
+
+  memcpy(ret, b, sizeof(ret));
+  ecp_nistz256_neg(ret, ret);
+  if (!ExpectFieldElementsEqual(
+          t, "In-place ecp_nistz256_neg(B) was incorrect.", a, ret)) {
+    return false;
+  }
+
+  return true;
+}
+
+static bool TestMulMont(FileTest *t) {
+  BN_ULONG a[P256_LIMBS], b[P256_LIMBS], result[P256_LIMBS];
+  if (!GetFieldElement(t, a, "A") ||
+      !GetFieldElement(t, b, "B") ||
+      !GetFieldElement(t, result, "Result")) {
+    return false;
+  }
+
+  BN_ULONG ret[P256_LIMBS];
+  ecp_nistz256_mul_mont(ret, a, b);
+  if (!ExpectFieldElementsEqual(t, "ecp_nistz256_mul_mont(A, B) was incorrect.",
+                                result, ret)) {
+    return false;
+  }
+
+  ecp_nistz256_mul_mont(ret, b, a);
+  if (!ExpectFieldElementsEqual(t, "ecp_nistz256_mul_mont(B, A) was incorrect.",
+                                result, ret)) {
+    return false;
+  }
+
+  memcpy(ret, a, sizeof(ret));
+  ecp_nistz256_mul_mont(ret, ret, b);
+  if (!ExpectFieldElementsEqual(
+          t, "ecp_nistz256_mul_mont(ret = A, B) was incorrect.", result, ret)) {
+    return false;
+  }
+
+  memcpy(ret, a, sizeof(ret));
+  ecp_nistz256_mul_mont(ret, b, ret);
+  if (!ExpectFieldElementsEqual(
+          t, "ecp_nistz256_mul_mont(B, ret = A) was incorrect.", result, ret)) {
+    return false;
+  }
+
+  memcpy(ret, b, sizeof(ret));
+  ecp_nistz256_mul_mont(ret, a, ret);
+  if (!ExpectFieldElementsEqual(
+          t, "ecp_nistz256_mul_mont(A, ret = B) was incorrect.", result, ret)) {
+    return false;
+  }
+
+  memcpy(ret, b, sizeof(ret));
+  ecp_nistz256_mul_mont(ret, ret, a);
+  if (!ExpectFieldElementsEqual(
+          t, "ecp_nistz256_mul_mont(ret = B, A) was incorrect.", result, ret)) {
+    return false;
+  }
+
+  if (memcmp(a, b, sizeof(a)) == 0) {
+    ecp_nistz256_sqr_mont(ret, a);
+    if (!ExpectFieldElementsEqual(t, "ecp_nistz256_sqr_mont(A) was incorrect.",
+                                  result, ret)) {
+      return false;
+    }
+
+    memcpy(ret, a, sizeof(ret));
+    ecp_nistz256_sqr_mont(ret, ret);
+    if (!ExpectFieldElementsEqual(
+            t, "ecp_nistz256_sqr_mont(ret = A) was incorrect.", result, ret)) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+static bool TestFromMont(FileTest *t) {
+  BN_ULONG a[P256_LIMBS], result[P256_LIMBS];
+  if (!GetFieldElement(t, a, "A") ||
+      !GetFieldElement(t, result, "Result")) {
+    return false;
+  }
+
+  BN_ULONG ret[P256_LIMBS];
+  ecp_nistz256_from_mont(ret, a);
+  if (!ExpectFieldElementsEqual(t, "ecp_nistz256_from_mont(A) was incorrect.",
+                                result, ret)) {
+    return false;
+  }
+
+  memcpy(ret, a, sizeof(ret));
+  ecp_nistz256_from_mont(ret, ret);
+  if (!ExpectFieldElementsEqual(
+          t, "ecp_nistz256_from_mont(ret = A) was incorrect.", result, ret)) {
+    return false;
+  }
+
+  return true;
+}
+
+static bool TestPointAdd(FileTest *t) {
+  P256_POINT a, b;
+  P256_POINT_AFFINE result;
+  if (!GetFieldElement(t, a.X, "A.X") ||
+      !GetFieldElement(t, a.Y, "A.Y") ||
+      !GetFieldElement(t, a.Z, "A.Z") ||
+      !GetFieldElement(t, b.X, "B.X") ||
+      !GetFieldElement(t, b.Y, "B.Y") ||
+      !GetFieldElement(t, b.Z, "B.Z") ||
+      !GetFieldElement(t, result.X, "Result.X") ||
+      !GetFieldElement(t, result.Y, "Result.Y")) {
+    return false;
+  }
+
+  P256_POINT ret;
+  ecp_nistz256_point_add(&ret, &a, &b);
+  if (!ExpectPointsEqual(t, "ecp_nistz256_point_add(A, B) was incorrect.",
+                         &result, &ret)) {
+    return false;
+  }
+
+  ecp_nistz256_point_add(&ret, &b, &a);
+  if (!ExpectPointsEqual(t, "ecp_nistz256_point_add(B, A) was incorrect.",
+                         &result, &ret)) {
+    return false;
+  }
+
+  memcpy(&ret, &a, sizeof(ret));
+  ecp_nistz256_point_add(&ret, &ret, &b);
+  if (!ExpectPointsEqual(t, "ecp_nistz256_point_add(ret = A, B) was incorrect.",
+                         &result, &ret)) {
+    return false;
+  }
+
+  memcpy(&ret, &a, sizeof(ret));
+  ecp_nistz256_point_add(&ret, &b, &ret);
+  if (!ExpectPointsEqual(t, "ecp_nistz256_point_add(B, ret = A) was incorrect.",
+                         &result, &ret)) {
+    return false;
+  }
+
+  memcpy(&ret, &b, sizeof(ret));
+  ecp_nistz256_point_add(&ret, &a, &ret);
+  if (!ExpectPointsEqual(t, "ecp_nistz256_point_add(ret = A, B) was incorrect.",
+                         &result, &ret)) {
+    return false;
+  }
+
+  memcpy(&ret, &b, sizeof(ret));
+  ecp_nistz256_point_add(&ret, &ret, &a);
+  if (!ExpectPointsEqual(t, "ecp_nistz256_point_add(ret = B, A) was incorrect.",
+                         &result, &ret)) {
+    return false;
+  }
+
+  P256_POINT_AFFINE a_affine, b_affine, infinity;
+  memset(&infinity, 0, sizeof(infinity));
+  if (!PointToAffine(&a_affine, &a) ||
+      !PointToAffine(&b_affine, &b)) {
+    return false;
+  }
+
+  // ecp_nistz256_point_add_affine does not work when a == b unless doubling the
+  // point at infinity.
+  if (memcmp(&a_affine, &b_affine, sizeof(a_affine)) != 0 ||
+      memcmp(&a_affine, &infinity, sizeof(a_affine)) == 0) {
+    ecp_nistz256_point_add_affine(&ret, &a, &b_affine);
+    if (!ExpectPointsEqual(t,
+                           "ecp_nistz256_point_add_affine(A, B) was incorrect.",
+                           &result, &ret)) {
+      return false;
+    }
+
+    memcpy(&ret, &a, sizeof(ret));
+    ecp_nistz256_point_add_affine(&ret, &ret, &b_affine);
+    if (!ExpectPointsEqual(
+            t, "ecp_nistz256_point_add_affine(ret = A, B) was incorrect.",
+            &result, &ret)) {
+      return false;
+    }
+
+    ecp_nistz256_point_add_affine(&ret, &b, &a_affine);
+    if (!ExpectPointsEqual(t,
+                           "ecp_nistz256_point_add_affine(B, A) was incorrect.",
+                           &result, &ret)) {
+      return false;
+    }
+
+    memcpy(&ret, &b, sizeof(ret));
+    ecp_nistz256_point_add_affine(&ret, &ret, &a_affine);
+    if (!ExpectPointsEqual(
+            t, "ecp_nistz256_point_add_affine(ret = B, A) was incorrect.",
+            &result, &ret)) {
+      return false;
+    }
+  }
+
+  if (memcmp(&a, &b, sizeof(a)) == 0) {
+    ecp_nistz256_point_double(&ret, &a);
+    if (!ExpectPointsEqual(t, "ecp_nistz256_point_double(A) was incorrect.",
+                           &result, &ret)) {
+      return false;
+    }
+
+    ret = a;
+    ecp_nistz256_point_double(&ret, &ret);
+    if (!ExpectPointsEqual(
+            t, "In-place ecp_nistz256_point_double(A) was incorrect.", &result,
+            &ret)) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+int main(int argc, char **argv) {
+  if (argc != 2) {
+    fprintf(stderr, "%s TEST_FILE\n", argv[0]);
+    return 1;
+  }
+
+  if (!TestSelectW5() ||
+      !TestSelectW7()) {
+    return 1;
+  }
+
+  return FileTestMain([](FileTest *t, void *) -> bool {
+    if (t->GetParameter() == "Negate") {
+      return TestNegate(t);
+    }
+    if (t->GetParameter() == "MulMont") {
+      return TestMulMont(t);
+    }
+    if (t->GetParameter() == "FromMont") {
+      return TestFromMont(t);
+    }
+    if (t->GetParameter() == "PointAdd") {
+      return TestPointAdd(t);
+    }
+
+    t->PrintLine("Unknown test type: %s", t->GetParameter().c_str());
+    return false;
+  }, nullptr, argv[1]);
+}
+
+#else
+
+int main() {
+  printf("PASS\n");
+  return 0;
+}
+
+#endif
diff --git a/src/crypto/ec/p256-x86_64_tests.txt b/src/crypto/ec/p256-x86_64_tests.txt
new file mode 100644
index 0000000..a680850
--- /dev/null
+++ b/src/crypto/ec/p256-x86_64_tests.txt
@@ -0,0 +1,1405 @@
+# Negation tests.
+#
+# The following tests satisfy A = -B (mod P).
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000000000000000000000
+B = 0000000000000000000000000000000000000000000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000000000000000000001
+B = ffffffff00000001000000000000000000000000fffffffffffffffffffffffe
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000000000000000000003
+B = ffffffff00000001000000000000000000000000fffffffffffffffffffffffc
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000000000000000000007
+B = ffffffff00000001000000000000000000000000fffffffffffffffffffffff8
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000000000000000000000f
+B = ffffffff00000001000000000000000000000000fffffffffffffffffffffff0
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000000000000000000001f
+B = ffffffff00000001000000000000000000000000ffffffffffffffffffffffe0
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000000000000000000003f
+B = ffffffff00000001000000000000000000000000ffffffffffffffffffffffc0
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000000000000000000007f
+B = ffffffff00000001000000000000000000000000ffffffffffffffffffffff80
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000000000000000000000ff
+B = ffffffff00000001000000000000000000000000ffffffffffffffffffffff00
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000000000000000000001ff
+B = ffffffff00000001000000000000000000000000fffffffffffffffffffffe00
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000000000000000000003ff
+B = ffffffff00000001000000000000000000000000fffffffffffffffffffffc00
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000000000000000000007ff
+B = ffffffff00000001000000000000000000000000fffffffffffffffffffff800
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000000000000000000fff
+B = ffffffff00000001000000000000000000000000fffffffffffffffffffff000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000000000000000001fff
+B = ffffffff00000001000000000000000000000000ffffffffffffffffffffe000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000000000000000003fff
+B = ffffffff00000001000000000000000000000000ffffffffffffffffffffc000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000000000000000007fff
+B = ffffffff00000001000000000000000000000000ffffffffffffffffffff8000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000000000000000000ffff
+B = ffffffff00000001000000000000000000000000ffffffffffffffffffff0000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000000000000000001ffff
+B = ffffffff00000001000000000000000000000000fffffffffffffffffffe0000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000000000000000003ffff
+B = ffffffff00000001000000000000000000000000fffffffffffffffffffc0000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000000000000000007ffff
+B = ffffffff00000001000000000000000000000000fffffffffffffffffff80000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000000000000000000fffff
+B = ffffffff00000001000000000000000000000000fffffffffffffffffff00000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000000000000000001fffff
+B = ffffffff00000001000000000000000000000000ffffffffffffffffffe00000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000000000000000003fffff
+B = ffffffff00000001000000000000000000000000ffffffffffffffffffc00000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000000000000000007fffff
+B = ffffffff00000001000000000000000000000000ffffffffffffffffff800000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000000000000000ffffff
+B = ffffffff00000001000000000000000000000000ffffffffffffffffff000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000000000000001ffffff
+B = ffffffff00000001000000000000000000000000fffffffffffffffffe000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000000000000003ffffff
+B = ffffffff00000001000000000000000000000000fffffffffffffffffc000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000000000000007ffffff
+B = ffffffff00000001000000000000000000000000fffffffffffffffff8000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000000000000000fffffff
+B = ffffffff00000001000000000000000000000000fffffffffffffffff0000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000000000000001fffffff
+B = ffffffff00000001000000000000000000000000ffffffffffffffffe0000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000000000000003fffffff
+B = ffffffff00000001000000000000000000000000ffffffffffffffffc0000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000000000000007fffffff
+B = ffffffff00000001000000000000000000000000ffffffffffffffff80000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000000000000000ffffffff
+B = ffffffff00000001000000000000000000000000ffffffffffffffff00000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000000000000001ffffffff
+B = ffffffff00000001000000000000000000000000fffffffffffffffe00000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000000000000003ffffffff
+B = ffffffff00000001000000000000000000000000fffffffffffffffc00000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000000000000007ffffffff
+B = ffffffff00000001000000000000000000000000fffffffffffffff800000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000000000000fffffffff
+B = ffffffff00000001000000000000000000000000fffffffffffffff000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000000000001fffffffff
+B = ffffffff00000001000000000000000000000000ffffffffffffffe000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000000000003fffffffff
+B = ffffffff00000001000000000000000000000000ffffffffffffffc000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000000000007fffffffff
+B = ffffffff00000001000000000000000000000000ffffffffffffff8000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000000000000ffffffffff
+B = ffffffff00000001000000000000000000000000ffffffffffffff0000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000000000001ffffffffff
+B = ffffffff00000001000000000000000000000000fffffffffffffe0000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000000000003ffffffffff
+B = ffffffff00000001000000000000000000000000fffffffffffffc0000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000000000007ffffffffff
+B = ffffffff00000001000000000000000000000000fffffffffffff80000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000000000000fffffffffff
+B = ffffffff00000001000000000000000000000000fffffffffffff00000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000000000001fffffffffff
+B = ffffffff00000001000000000000000000000000ffffffffffffe00000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000000000003fffffffffff
+B = ffffffff00000001000000000000000000000000ffffffffffffc00000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000000000007fffffffffff
+B = ffffffff00000001000000000000000000000000ffffffffffff800000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000000000ffffffffffff
+B = ffffffff00000001000000000000000000000000ffffffffffff000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000000001ffffffffffff
+B = ffffffff00000001000000000000000000000000fffffffffffe000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000000003ffffffffffff
+B = ffffffff00000001000000000000000000000000fffffffffffc000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000000007ffffffffffff
+B = ffffffff00000001000000000000000000000000fffffffffff8000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000000000fffffffffffff
+B = ffffffff00000001000000000000000000000000fffffffffff0000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000000001fffffffffffff
+B = ffffffff00000001000000000000000000000000ffffffffffe0000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000000003fffffffffffff
+B = ffffffff00000001000000000000000000000000ffffffffffc0000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000000007fffffffffffff
+B = ffffffff00000001000000000000000000000000ffffffffff80000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000000000ffffffffffffff
+B = ffffffff00000001000000000000000000000000ffffffffff00000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000000001ffffffffffffff
+B = ffffffff00000001000000000000000000000000fffffffffe00000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000000003ffffffffffffff
+B = ffffffff00000001000000000000000000000000fffffffffc00000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000000007ffffffffffffff
+B = ffffffff00000001000000000000000000000000fffffffff800000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000000fffffffffffffff
+B = ffffffff00000001000000000000000000000000fffffffff000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000001fffffffffffffff
+B = ffffffff00000001000000000000000000000000ffffffffe000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000003fffffffffffffff
+B = ffffffff00000001000000000000000000000000ffffffffc000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000007fffffffffffffff
+B = ffffffff00000001000000000000000000000000ffffffff8000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000000ffffffffffffffff
+B = ffffffff00000001000000000000000000000000ffffffff0000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000001ffffffffffffffff
+B = ffffffff00000001000000000000000000000000fffffffe0000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000003ffffffffffffffff
+B = ffffffff00000001000000000000000000000000fffffffc0000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000007ffffffffffffffff
+B = ffffffff00000001000000000000000000000000fffffff80000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000000fffffffffffffffff
+B = ffffffff00000001000000000000000000000000fffffff00000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000001fffffffffffffffff
+B = ffffffff00000001000000000000000000000000ffffffe00000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000003fffffffffffffffff
+B = ffffffff00000001000000000000000000000000ffffffc00000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000007fffffffffffffffff
+B = ffffffff00000001000000000000000000000000ffffff800000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000ffffffffffffffffff
+B = ffffffff00000001000000000000000000000000ffffff000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000001ffffffffffffffffff
+B = ffffffff00000001000000000000000000000000fffffe000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000003ffffffffffffffffff
+B = ffffffff00000001000000000000000000000000fffffc000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000007ffffffffffffffffff
+B = ffffffff00000001000000000000000000000000fffff8000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000fffffffffffffffffff
+B = ffffffff00000001000000000000000000000000fffff0000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000001fffffffffffffffffff
+B = ffffffff00000001000000000000000000000000ffffe0000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000003fffffffffffffffffff
+B = ffffffff00000001000000000000000000000000ffffc0000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000007fffffffffffffffffff
+B = ffffffff00000001000000000000000000000000ffff80000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000ffffffffffffffffffff
+B = ffffffff00000001000000000000000000000000ffff00000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000001ffffffffffffffffffff
+B = ffffffff00000001000000000000000000000000fffe00000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000003ffffffffffffffffffff
+B = ffffffff00000001000000000000000000000000fffc00000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000007ffffffffffffffffffff
+B = ffffffff00000001000000000000000000000000fff800000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000fffffffffffffffffffff
+B = ffffffff00000001000000000000000000000000fff000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000001fffffffffffffffffffff
+B = ffffffff00000001000000000000000000000000ffe000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000003fffffffffffffffffffff
+B = ffffffff00000001000000000000000000000000ffc000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000007fffffffffffffffffffff
+B = ffffffff00000001000000000000000000000000ff8000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000ffffffffffffffffffffff
+B = ffffffff00000001000000000000000000000000ff0000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000001ffffffffffffffffffffff
+B = ffffffff00000001000000000000000000000000fe0000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000003ffffffffffffffffffffff
+B = ffffffff00000001000000000000000000000000fc0000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000007ffffffffffffffffffffff
+B = ffffffff00000001000000000000000000000000f80000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000fffffffffffffffffffffff
+B = ffffffff00000001000000000000000000000000f00000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000001fffffffffffffffffffffff
+B = ffffffff00000001000000000000000000000000e00000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000003fffffffffffffffffffffff
+B = ffffffff00000001000000000000000000000000c00000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000007fffffffffffffffffffffff
+B = ffffffff00000001000000000000000000000000800000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000ffffffffffffffffffffffff
+B = ffffffff00000001000000000000000000000000000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000001ffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffffffffffffffff000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000003ffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffffffffffffffd000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000007ffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffffffffffffff9000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000fffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffffffffffffff1000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000001fffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffffffffffffffe1000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000003fffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffffffffffffffc1000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000007fffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffffffffffffff81000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000ffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffffffffffffff01000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000001ffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffffffffffffe01000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000003ffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffffffffffffc01000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000007ffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffffffffffff801000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000fffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffffffffffff001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000001fffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffffffffffffe001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000003fffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffffffffffffc001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000007fffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffffffffffff8001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000ffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffffffffffff0001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000001ffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffffffffffe0001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000003ffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffffffffffc0001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000007ffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffffffffff80001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000fffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffffffffff00001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000001fffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffffffffffe00001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000003fffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffffffffffc00001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000007fffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffffffffff800001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000ffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffffffffff000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000001ffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffffffffe000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000003ffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffffffffc000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000007ffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffffffff8000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000fffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffffffff0000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000001fffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffffffffe0000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000003fffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffffffffc0000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000007fffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffffffff80000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000ffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffffffff00000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000001ffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffffffe00000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000003ffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffffffc00000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000007ffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffffff800000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000fffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffffff000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000001fffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffffffe000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000003fffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffffffc000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000007fffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffffff8000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000ffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffffff0000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000001ffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffffe0000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000003ffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffffc0000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000007ffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffff80000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000fffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffff00000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000001fffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffffe00000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000003fffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffffc00000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000007fffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffff800000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000ffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffff000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000001ffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffe000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000003ffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffc000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000007ffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffff8000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000fffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffff0000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000001fffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffe0000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000003fffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffc0000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000007fffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffff80000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000ffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffff00000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000001ffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffe00000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000003ffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffc00000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000007ffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffff800000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000fffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffff000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000001fffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffe000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000003fffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffc000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000007fffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffff8000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000ffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffff0000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000001ffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffe0000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000003ffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffc0000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000007ffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffff80000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000fffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffff00000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000001fffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffe00000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000003fffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffc00000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000007fffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffff800000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000ffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffff000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000001ffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffe000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000003ffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffc000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000007ffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffff8000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000fffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffff0000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000001fffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffe0000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000003fffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffc0000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000007fffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffff80000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000ffffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffff00000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000001ffffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffe00000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000003ffffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffc00000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000007ffffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fff800000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000fffffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fff000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000001fffffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffe000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000003fffffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffc000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000007fffffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ff8000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000ffffffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ff0000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000001ffffffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fe0000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000003ffffffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fc0000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000007ffffffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000f80000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000fffffffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000f00000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000001fffffffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000e00000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000003fffffffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000c00000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000007fffffffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000800000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000001ffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffeffffffff000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000003ffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffefffffffd000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000007ffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffefffffff9000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000fffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffefffffff1000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000001fffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffeffffffe1000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000003fffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffeffffffc1000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000007fffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffeffffff81000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000ffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffeffffff01000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000001ffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffefffffe01000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000003ffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffefffffc01000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000007ffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffefffff801000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000fffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffefffff001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000001fffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffeffffe001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000003fffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffeffffc001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000007fffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffeffff8001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffeffff0001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000001ffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffefffe0001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000003ffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffefffc0001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000007ffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffefff80001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000fffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffefff00001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000001fffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffeffe00001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000003fffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffeffc00001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000007fffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffeff800001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffeff000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000001ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffefe000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000003ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffefc000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000007ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffef8000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000fffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffef0000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000001fffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffee0000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000003fffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffec0000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000007fffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffe80000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffe00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffd00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000003ffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffb00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000007ffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffff700000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = ffffffef00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000001fffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = ffffffdf00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000003fffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = ffffffbf00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000007fffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = ffffff7f00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffeff00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffdff00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000003ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffbff00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffff7ff00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = ffffefff00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00001fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = ffffdfff00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00003fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = ffffbfff00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = ffff7fff00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffeffff00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffdffff00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0003ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffbffff00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fff7ffff00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = ffefffff00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 001fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = ffdfffff00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 003fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = ffbfffff00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = ff7fffff00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = feffffff00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fdffffff00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fbffffff00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = f7ffffff00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = efffffff00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = dfffffff00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = bfffffff00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = 7fffffff00000001000000000000000000000001000000000000000000000000
+
+
+# Montgomery multiplication tests.
+#
+# The following tests satisfy A * B * 2^-256 = Result (mod P).
+
+Test = MulMont
+A = e762f095431b732ce33c4f4a6f41068ff7f78e37aad940166667d193bfc58039
+B = a43df383dd5df14d7c16737b781261473f9ffb76ee29562fbb5e5d390b882fb5
+Result = cf637a47dc5fb82aed80ed4c66b682a94bf0b76a2878acf483aad86c0db7cc19
+
+Test = MulMont
+A = 2e519e860cb3f8f32fc351861b022e9fc7bb073ca8767efb3d1027dd32a38bcb
+B = 466d035e4238d6a30613dd227b0daeacd6a8634fa60f5150d42dd20601794be4
+Result = 486e1abe0f79e107f8beca6e4653872f63a24dedb005def6aae75a2a51e73c76
+
+Test = MulMont
+A = 1763859541b5e2edee019c66699d0e12e349e6ee586d618ac20c679d2fa8cadd
+B = 56125872de888c5656dec17fbf9678d915ff9815da897df81f03fd9aa4f93654
+Result = 71ce584135a0aba8222ca0021bcefac5811d19100627f96726cf195ff2ac4aad
+
+Test = MulMont
+A = ea3be6295098e4995b93267dbd58f24fd9c18f7e89e9e5aeafdc34ca54e8ec4e
+B = 2735658978d620a4f76bffe94d9cd7d683b3bfd533aa6bb2b94f52122e83f7fc
+Result = 362f7ab3a12effe9bad069b84a7df5f108503c2457f83ddb05b57f19e6457989
+
+Test = MulMont
+A = f607f087ec5015b533df8802771dc60ef1487d86ce405e5bb18f8f06ca483f13
+B = 73ac532eb3f2356a96e668f167a1626a0f7b1fd2cd84ba6deeebd01af1d3897d
+Result = ce7045e69da157e62fb42508880f5734531c36948c704aedec42afa75cb9c2eb
+
+Test = MulMont
+A = 80ce8eb07601fd8e19ba08a9d21081b0324fd459f9c489ac7c871d406133c813
+B = 7ad28cef45b137ecc5426a44b6bce6d4329f5bd2b5e55d46edd5fbb295678a1b
+Result = 04068f8461d17b34c8d9c3eecf61dbaef9cd5a952bbcd9f84bb2044f2439da60
+
+Test = MulMont
+A = 17429caf63689e143c8ca77df69a11cbc02c272daadd75a66f3fa5f88828367e
+B = 5725bedc56a4b16e0f0ae55fa0beb1fdf3ff132ccb9803bab678d4ac7915d88c
+Result = a1da0fa68947e906287ea164b213bc7e80649b2ac3f97f203549d3b270de05a1
+
+Test = MulMont
+A = e7da43c0e0fa7adeb972901bef3160c848e9651bfc810968afdb0cd598830370
+B = 08f03060cac1d3c15eea69623d5fb01da465b209e3e5e90fbb51053a1c5700eb
+Result = cda4ffaf8b1c3ac0d44bae6ea5154de11e14931747a65396531302c0cb1ed537
+
+Test = MulMont
+A = c7375c2b6666713cb33cfb741268fd3ccf703bcaa0b9b27f84a8cb970655da9c
+B = b0796ee4bb88b9bad895d9c25c34f43a3941e9585bda8e86ff4fa0bbb391ac61
+Result = fd1d557a9fb0031e462121bf7ca31804acfcfce822bb6ee6631b54c575380617
+
+Test = MulMont
+A = 72a87b13eb4a2e248214aa591c586df65790f9f750a1641b47581a4ee09be7e9
+B = 38e602844b9aaf737e8b1261110b86ba22806ccbbbfdc5305075429d7ce4f002
+Result = cb2d63ee829de8801759f0229d4c07139bacd804f0c815d35004747c65bffdf2
+
+# Test cases where A == B to test squaring.
+
+Test = MulMont
+A = 0000000000000000000000000000000000000000000000000000000000000000
+B = 0000000000000000000000000000000000000000000000000000000000000000
+Result = 0000000000000000000000000000000000000000000000000000000000000000
+
+Test = MulMont
+A = 579e9ce1ad00639b8b64d49546ff4f9c30ad12eaebe9e2ed91e97d55c3c5d847
+B = 579e9ce1ad00639b8b64d49546ff4f9c30ad12eaebe9e2ed91e97d55c3c5d847
+Result = 10c5e60c2d480d5d53f50c24fb771fd2dec208db04624dfd05d2847ca173a9aa
+
+Test = MulMont
+A = 501947209b121bcdedce8c895ee2ba310f2e561e97998eb8f3b99d1f924f36c1
+B = 501947209b121bcdedce8c895ee2ba310f2e561e97998eb8f3b99d1f924f36c1
+Result = 54d6d64566619b215910f1b9e467b22ef205ca3aaad37a00fcbd906357f9c179
+
+Test = MulMont
+A = e84ab9202722498baa2c9158f40d47b1f03df4d13976b0aec916a937e99f3a89
+B = e84ab9202722498baa2c9158f40d47b1f03df4d13976b0aec916a937e99f3a89
+Result = 9af01fa6947a60679b6f87efe9b6fba97baf5d55a19d5e91dd5da1da10caeebf
+
+Test = MulMont
+A = add67c61d8479570f45a59e9b04974f970b0c4c6c046056fea1bdf3f0e7d3152
+B = add67c61d8479570f45a59e9b04974f970b0c4c6c046056fea1bdf3f0e7d3152
+Result = c0c68b4327e3fe7e0522167a54b25aaa6f76085ce4f6550479c89f3f1c39dd18
+
+Test = MulMont
+A = 434ef0db5640a3ea63125f815bc3cb3c92d06dbc3b5cb484e01b5247b3b4bfe5
+B = 434ef0db5640a3ea63125f815bc3cb3c92d06dbc3b5cb484e01b5247b3b4bfe5
+Result = b5105d16b858279247ed31362a90260978d64e0492e84bffa7a0e13ee1541544
+
+Test = MulMont
+A = b1db42aa4b259d9c6104599aff622114f10c327d02c5640b74cf1742adff332d
+B = b1db42aa4b259d9c6104599aff622114f10c327d02c5640b74cf1742adff332d
+Result = 0c175e7f96fc62059864c561d99a8d90978c72757ba305cd8862ed6a5fadad59
+
+Test = MulMont
+A = 7610271796be25416b652badd3119938974b20d4fc92244aea76d23b80d178f0
+B = 7610271796be25416b652badd3119938974b20d4fc92244aea76d23b80d178f0
+Result = 67d76e4a7c8355bb362481a76a63b365ad79767cc672b174130e833d41ca5709
+
+Test = MulMont
+A = 3480d60b0ccafca89c86f22f78380cead81310241f27a815e6fd21c2060caed8
+B = 3480d60b0ccafca89c86f22f78380cead81310241f27a815e6fd21c2060caed8
+Result = 68bfb2652d3bf03d17b20b2c52c68e847b0006047ba4ea81d4b85af2e0a21f72
+
+Test = MulMont
+A = 8ad6fa8bf3fe56ece1d0970636c1429ed5dfc2441c3194928a6348b69490b537
+B = 8ad6fa8bf3fe56ece1d0970636c1429ed5dfc2441c3194928a6348b69490b537
+Result = f5cdccf29e09928722137fb5a5ec035d7f39580838e19b892a7a972866330318
+
+Test = MulMont
+A = 71c328ce472ae74b5028b21f9d1997e0f7dbcee979a8f9fdecfa5d37d359c835
+B = 71c328ce472ae74b5028b21f9d1997e0f7dbcee979a8f9fdecfa5d37d359c835
+Result = c3472fafd01fc3ed93a91ab65411cb852bd5839603a02ca6cdfbadcb9ac474a0
+
+
+# Montgomery conversion tests.
+#
+# The following tests satisfy A * 2^-256 = Result (mod P).
+
+Test = FromMont
+A = 0585a3dada9bb283fd8db4fc46c106d28f95b8cf159a405891196dbb9ce0b5cf
+Result = d198d054d25a069c40cdeeb968a5562a67c3ef659297169e4be872f234897dc0
+
+Test = FromMont
+A = 9ff49a4a3f810fd34ca6f37fb1b3c40e61bc0492227e91e41cbe06bd58ba65b8
+Result = 326a061b2047d9ba4eddaba9b1fe253d5b2a24e268e3f8810767bef8cda07643
+
+Test = FromMont
+A = 05a69f8f646494be65affbd44d0536ca098d6f3640e80b5e48764ab78928cf58
+Result = 5a6f9c7025d4063480c400fe6f271cf3a3d2c43f9e1ceac21a88208c28329731
+
+Test = FromMont
+A = 256481a9e52d692719330a6f1208d9eca4ddd919aee06e234cbbde77d245501b
+Result = fe9fc86a2ff61a0c981d5e86c5472248e071e9639521c5be43947bfffc7d5858
+
+Test = FromMont
+A = 2062ef333cadefc36ced52a2ea7e4215b1fca29283baa1e3be76e321f1b213f0
+Result = 961ce39c3bf1d699b4b61ded8a5beae6eb6185d21f1df435b079b1f6a79dc738
+
+Test = FromMont
+A = 97241c3651a8f9d2fc02730f15c3e09e48d2e645cfe927385cb81d3f454414fb
+Result = 2114225803efe7b6c7fbb290cb946da4e78697aad5624c2d3fe9fb568460b93c
+
+Test = FromMont
+A = 1aae0ad2c8ac988e11beda32ca7257f4d4de41f4b74452fa46f0a3bafb39262a
+Result = 77c884131c34a2c3acce8a69dc5cf55987b7999c70586a9ef3c0dfb634900296
+
+Test = FromMont
+A = 034de033e2d38cf8bec8a994414b64a2fce7c83c5d81efc3d21448225071e85d
+Result = 984fecbde84f393133fb602777b4395c56449d2cbbd7d8ae428b2ee6f82a2956
+
+Test = FromMont
+A = d2b296c2004b2761b6781311c924cbf5ff56dcc0900ed5cd24f5dd2e07f32633
+Result = ddcff6e031b859a814ce8f37b71c10cd5fb642af54af72deabb95adcb99307b1
+
+Test = FromMont
+A = 8f525e6af50a62fc176dec75bdf48f70ba8ab97323ba78c643ef07f6457ba070
+Result = 8fa95d57aae2fff79045654501478f7a394b27b8b54113a25ac74662606f767c
+
+
+# Point adding tests.
+#
+# The following tests satisfy Result = A + B, where Result is in affine
+# coordinates and A and B are in Jacobian coordinates in the Montgomery domain.
+
+# ∞ + ∞ = ∞.
+Test = PointAdd
+A.X = 0000000000000000000000000000000000000000000000000000000000000000
+A.Y = 0000000000000000000000000000000000000000000000000000000000000000
+A.Z = 0000000000000000000000000000000000000000000000000000000000000000
+B.X = 0000000000000000000000000000000000000000000000000000000000000000
+B.Y = 0000000000000000000000000000000000000000000000000000000000000000
+B.Z = 0000000000000000000000000000000000000000000000000000000000000000
+Result.X = 0000000000000000000000000000000000000000000000000000000000000000
+Result.Y = 0000000000000000000000000000000000000000000000000000000000000000
+
+# ∞ + ∞ = ∞, with an alternate representation of ∞.
+Test = PointAdd
+A.X = 2b11cb945c8cf152ffa4c9c2b1c965b019b35d0b7626919ef0ae6cb9d232f8af
+A.Y = 6d333da42e30f7011245b6281015ded14e0f100968e758a1b6c3c083afc14ea0
+A.Z = 0000000000000000000000000000000000000000000000000000000000000000
+B.X = 2b11cb945c8cf152ffa4c9c2b1c965b019b35d0b7626919ef0ae6cb9d232f8af
+B.Y = 6d333da42e30f7011245b6281015ded14e0f100968e758a1b6c3c083afc14ea0
+B.Z = 0000000000000000000000000000000000000000000000000000000000000000
+Result.X = 0000000000000000000000000000000000000000000000000000000000000000
+Result.Y = 0000000000000000000000000000000000000000000000000000000000000000
+
+# g + ∞ = g.
+Test = PointAdd
+A.X = 18905f76a53755c679fb732b7762251075ba95fc5fedb60179e730d418a9143c
+A.Y = 8571ff1825885d85d2e88688dd21f3258b4ab8e4ba19e45cddf25357ce95560a
+A.Z = 00000000fffffffeffffffffffffffffffffffff000000000000000000000001
+B.X = 0000000000000000000000000000000000000000000000000000000000000000
+B.Y = 0000000000000000000000000000000000000000000000000000000000000000
+B.Z = 0000000000000000000000000000000000000000000000000000000000000000
+Result.X = 18905f76a53755c679fb732b7762251075ba95fc5fedb60179e730d418a9143c
+Result.Y = 8571ff1825885d85d2e88688dd21f3258b4ab8e4ba19e45cddf25357ce95560a
+
+# g + ∞ = g, with an alternate representation of ∞.
+Test = PointAdd
+A.X = 18905f76a53755c679fb732b7762251075ba95fc5fedb60179e730d418a9143c
+A.Y = 8571ff1825885d85d2e88688dd21f3258b4ab8e4ba19e45cddf25357ce95560a
+A.Z = 00000000fffffffeffffffffffffffffffffffff000000000000000000000001
+B.X = 2b11cb945c8cf152ffa4c9c2b1c965b019b35d0b7626919ef0ae6cb9d232f8af
+B.Y = 6d333da42e30f7011245b6281015ded14e0f100968e758a1b6c3c083afc14ea0
+B.Z = 0000000000000000000000000000000000000000000000000000000000000000
+Result.X = 18905f76a53755c679fb732b7762251075ba95fc5fedb60179e730d418a9143c
+Result.Y = 8571ff1825885d85d2e88688dd21f3258b4ab8e4ba19e45cddf25357ce95560a
+
+# g + -g = ∞.
+Test = PointAdd
+A.X = 18905f76a53755c679fb732b7762251075ba95fc5fedb60179e730d418a9143c
+A.Y = 8571ff1825885d85d2e88688dd21f3258b4ab8e4ba19e45cddf25357ce95560a
+A.Z = 00000000fffffffeffffffffffffffffffffffff000000000000000000000001
+B.X = 18905f76a53755c679fb732b7762251075ba95fc5fedb60179e730d418a9143c
+B.Y = 7a8e00e6da77a27b2d17797722de0cda74b5471c45e61ba3220daca8316aa9f5
+B.Z = 00000000fffffffeffffffffffffffffffffffff000000000000000000000001
+Result.X = 0000000000000000000000000000000000000000000000000000000000000000
+Result.Y = 0000000000000000000000000000000000000000000000000000000000000000
+
+Test = PointAdd
+A.X = bcba3eebf2b0af1174a4b874b155b4dc74bd5fb57c70214561aaabb105635580
+A.Y = 1dc33ce74f651305dd89263c1d314edd2773ef6dd043742a6f47f29542b9eb07
+A.Z = 00000000fffffffeffffffffffffffffffffffff000000000000000000000001
+B.X = f9e0b98b1a87b6c49c4cc5fc47efd157e5f12cf5543d71cfa38187a3793d6791
+B.Y = 3b2de94df438554381037c9f9d2c21991c6975d83c0acd42ef1a8419a040436f
+B.Z = 00000000fffffffeffffffffffffffffffffffff000000000000000000000001
+Result.X = 6bd7b4e06d7862f749901a398417e941618c11c48dffcce719e4026220b77477
+Result.Y = 1e2ffd71e8c206acc19032d26a53ea275fefea51a2c90e4dd3c8b7c6acc51ab6
+
+Test = PointAdd
+A.X = d71c6da129f6e867bf525563e1d8bdbd2f90a9bac7de867a6ea2317a5d6cb507
+A.Y = 125e0cc1ba0c93caa19edb419a764f88d955289c4c6e77d02d90e4e31d47c9a2
+A.Z = 00000000fffffffeffffffffffffffffffffffff000000000000000000000001
+B.X = 334c2200ec08896808ab12a76820ff674fcdccff6d85afa2e586b31fc944de33
+B.Y = b5ee8cfa25896d4075588c60926a2582a099c7a5acbcfec78fba457c4886301c
+B.Z = 00000000fffffffeffffffffffffffffffffffff000000000000000000000001
+Result.X = 93e9d4e6f7736f80da1b00d221024ccfd17f2927d6b505a5bcefe0801fe6f0a9
+Result.Y = 4824eeb2d5da27d57e1d50c2dae000acdcddcbaf534d8b7e7d97854ed3dc939e
+
+Test = PointAdd
+A.X = 0daba41be2b418e7d160a363e6cbdcbff5d433f96b0d5be3812c0a7adfab8ed4
+A.Y = 3ae4dd97c4d2987a63df16c5fb8c494164e14b93eeebd5585d74bd26e2201499
+A.Z = 00000000fffffffeffffffffffffffffffffffff000000000000000000000001
+B.X = 87135fb06383ec8b282fdc028eb38fd447ac1ecc76922e37f0cc454febb11aee
+B.Y = 98ab966087531eb3eea1e5e36189271a02f7ee8e381f9c78d6f346a301f96f81
+B.Z = 00000000fffffffeffffffffffffffffffffffff000000000000000000000001
+Result.X = 2e096c2fabf06a5b838c7e07fda436d068dd1c4e3ff4f5704f89ab9df6b4be5b
+Result.Y = 59ca6304321ae1e41bfa30f52e7ef27fceeade8507f20837654383d70e8a41df
+
+Test = PointAdd
+A.X = 356db98c21c2169899b9b296edcacb7d531524f2572913b75edb7b73196f5682
+A.Y = 47a26c52b1b2f229109e8aca7f5b4af768baf053a15ff8f58051c7e4e1b7f818
+A.Z = 00000000fffffffeffffffffffffffffffffffff000000000000000000000001
+B.X = 56956f6d3bbbd4aece299f29bb4c537355f312f391c207c6ec6efe646362b288
+B.Y = a69fc73c0636c9928764cc9d6e1482577b6ca06f277c098f571108356a858cab
+B.Z = 00000000fffffffeffffffffffffffffffffffff000000000000000000000001
+Result.X = ca0ddd995a77173a1438473bf82734cb3a09fafe7050bda9bd592a1cf078fa38
+Result.Y = 379da87952d36c5396b934a2ce8b003ee8fc4155b3b488f2f550734e2a82ce7d
+
+Test = PointAdd
+A.X = 13764cccab4addf5cf4ef5fb4af60a93e08fa3a0a72653abf013e3427abbf82c
+A.Y = c3dc524745368a0dc4948f897402f4b5a280acbf74f5ea9180d038a483d4090a
+A.Z = 2903a04d6615ec23cd63ba46287be2e7a8eeee030bed49e7a94769386a46f209
+B.X = a5c5921f9a8c569f661693bfae1b167937987c2fe951956ef0e34c426965c648
+B.Y = f8a299605e690a78e583371e59cf2b848d475afc35bb1448981c53ad8c0a6581
+B.Z = 9c3fde73f1899a76eb40f055fce02ab9c1b1ce7d43b54c54f93ffe56830e3f83
+Result.X = 4073318e85bc2d7637fd0129fa8eb86b6ca20334542795f3bb1de54b90a16b69
+Result.Y = 9a1b1e7435d98287b244d2337f8bf0e9c87b40677bf1ea2a9dedbd07c5241ee0
+
+Test = PointAdd
+A.X = f72706b81fca2b1530238bdc2c0c454b5116ee54fdf156bc62bffea73f0645af
+A.Y = c6e66d9ae8fc5e164e6a985f866aae41f3c4e4281a0eea9173e4e77cb29e4bc7
+A.Z = 6a84f9c37634b8aefdae477e9efec66f20d2f6159575f40c7b21a1e0732e8c49
+B.X = bcf21b020cb8fb4b2ef7f639240d221dd96fc08d7fa575c2e7037fc84d8f03b2
+B.Y = abc500f82f06f0d69a920c8d80eef9dd2310cd09e0d89d80fc7397aa4e361dd1
+B.Z = 5031c46be15f9d4fa9a347be998c07f9cc7f754999fe0f9c3c8b38e0d85dda9f
+Result.X = 401b010df4dd21ed96f7c8babb401db74b3b6ee7f55c498803203855b5911de9
+Result.Y = 05e585cca569bc22855f7df32b20a4a45315a1ca5d98d2b94792eb748ec8744b
+
+Test = PointAdd
+A.X = 7b44b52e9fb1bc58c81a2adc9bfedcc42bba3cb34ec666e51cba8050d48fdb37
+A.Y = 2b7e629fef7b4e175f5eb30c421e60f26fefdf5f9fed743cad4a8e638c18696a
+A.Z = 68f31acd92bed56a4556e954b0c51f9f8f3b797bc853d1b2b01b228657bd317f
+B.X = 3d293c36fd065d1f054eb218932d60feb00d1bd4bee0236cb9788d9723df9571
+B.Y = c8b893b8e9ff935f2e060227334e32ba144f4046b1bd4961f4479ad3fef1c7d2
+B.Z = 9c072deacfe5c025c763efebb4feab79e954c47d3e86ef4abfbd1901f50d8495
+Result.X = 245582d32415c77a2e3abbf844cf1a40c31466c1418cd279747e5394744509be
+Result.Y = 5c2f80f947d2df7fb1f829d05c6175f6fce7cd2d7f79fd7aa865f930e910e9fd
+
+Test = PointAdd
+A.X = 75ab91b8a46a5a1abf827cb209373b28cbb8f83a06adf6a9b10ac76e22493ecc
+A.Y = abd989a78d1bcee7e63920d7e637f9763901da408a9d8c731e4e65a6fc52e1a1
+A.Z = 188a24145243ca066c35870e5a8835532ad512fbdcf5f5ae4033b262fa9aa6b8
+B.X = 5d6e885ec19069b2aa51a2723c98da1f03e8dbc344fe1de0bdb42910ba8bfe96
+B.Y = a1f86e66eacc38db7e47154a324a16031705b4803addf074037d3320b50dbef8
+B.Z = 5cff900a783687049a7d497b1f8cd837c479a61f3fef4b7ced180ea82770bc75
+Result.X = a4029333b9b9db434eea002bd6d4e0d9f3e5317c685511a30ecae351fc60d164
+Result.Y = 8e9302c77bc6f560c9bec473ef1ffb76b357c0d4794192696bda8e99651798ee
+
+Test = PointAdd
+A.X = 8d1867f890abaa26b634d5d5cdeb0f4abc7ebd16d807479f837fcece592dc0eb
+A.Y = fc68c801999c12070eddeb3169219c491f9e8fe29cdc4e3cb698ee8471934076
+A.Z = 00000000fffffffeffffffffffffffffffffffff000000000000000000000001
+B.X = 8d1867f890abaa26b634d5d5cdeb0f4abc7ebd16d807479f837fcece592dc0eb
+B.Y = fc68c801999c12070eddeb3169219c491f9e8fe29cdc4e3cb698ee8471934076
+B.Z = 00000000fffffffeffffffffffffffffffffffff000000000000000000000001
+Result.X = 8da53dc540c1450c73082ad3b799d0d18a69a747fcd81f847e9e60484dcf579a
+Result.Y = c20c398e99e0513a452b5e9b6331863d1ac3eee6fcf73021f505a0b62daf6f80
+
+Test = PointAdd
+A.X = 328b983f6490312e37e8eeb2121cd622cf85dbcf78af93df74fbca961ce3bfa2
+A.Y = 1c8a0aea2f2e540770644f48c41810bf7f9e1a782b2f6397712b17c88109fbce
+A.Z = 00000000fffffffeffffffffffffffffffffffff000000000000000000000001
+B.X = 328b983f6490312e37e8eeb2121cd622cf85dbcf78af93df74fbca961ce3bfa2
+B.Y = 1c8a0aea2f2e540770644f48c41810bf7f9e1a782b2f6397712b17c88109fbce
+B.Z = 00000000fffffffeffffffffffffffffffffffff000000000000000000000001
+Result.X = b6f3c548944862dfdea2314ca6d6a88780b08da41becf58384af80544aca4966
+Result.Y = 95afecb4ad3195485a2aad3cd14008c9a7c1e0c02656c3c2b7cd5f2e7f3a4474
+
+Test = PointAdd
+A.X = 3ae6b24cadd6a14612d24a1c094a35c6be56db8f53a6d526e0ede03923918443
+A.Y = de8a23105c5f5c88b77dbde74e30a56f8865d78a5ce9060cff9f2927dbd196b6
+A.Z = 00000000fffffffeffffffffffffffffffffffff000000000000000000000001
+B.X = 3ae6b24cadd6a14612d24a1c094a35c6be56db8f53a6d526e0ede03923918443
+B.Y = de8a23105c5f5c88b77dbde74e30a56f8865d78a5ce9060cff9f2927dbd196b6
+B.Z = 00000000fffffffeffffffffffffffffffffffff000000000000000000000001
+Result.X = 6f125b512c3c736f39781fcd89adb653e515b4ce1e1204505f08d0a8480052ef
+Result.Y = e1acfccf1b9950067adf0f06e0d9703a8b1ac1bbdbb35b08df28cd56c24ae5a0
+
+Test = PointAdd
+A.X = f317c6c02d9a6ff0799b3b4a22f83c95324831baad336ecd0c631ea04a5e11c8
+A.Y = b624e8057d411031f41b30cd02f56c24e89262e885007b7a1ed1861feb7ffcda
+A.Z = 00000000fffffffeffffffffffffffffffffffff000000000000000000000001
+B.X = f317c6c02d9a6ff0799b3b4a22f83c95324831baad336ecd0c631ea04a5e11c8
+B.Y = b624e8057d411031f41b30cd02f56c24e89262e885007b7a1ed1861feb7ffcda
+B.Z = 00000000fffffffeffffffffffffffffffffffff000000000000000000000001
+Result.X = e805208c74602e54482d113f16fcf6e4600436f8af49705cdd05ecfb0e6d45fd
+Result.Y = baded898bfead1b4eb3ab3bbd0129837efc85823dabe82718a975bd603f96d9e
+
+Test = PointAdd
+A.X = 3a6802aeaebc67046a1e75152822fa8bab04c11ae2b816f42c073daee3f13274
+A.Y = d6522c882d18e32bc5ea1fa59efbce8ce2369f2154dcc00e6fb17500f50f8ebf
+A.Z = bea747d5bb1c6ee865249d7a22378f3c760916e163497f4b6ef4da8adcb5dfab
+B.X = 3a6802aeaebc67046a1e75152822fa8bab04c11ae2b816f42c073daee3f13274
+B.Y = d6522c882d18e32bc5ea1fa59efbce8ce2369f2154dcc00e6fb17500f50f8ebf
+B.Z = bea747d5bb1c6ee865249d7a22378f3c760916e163497f4b6ef4da8adcb5dfab
+Result.X = 5a2891dca746889d413d8dc1a69b715954baf692689fc32d9aa10b7431a5c149
+Result.Y = 91db7288536b4f6d78e5a787ecbb5094f6834515038cb070a7fa4870af8045f0
+
+Test = PointAdd
+A.X = c76ddbcb15bc63f82807804536a0d25fd7a639c71adf953ad6cc8f68d915f485
+A.Y = e3a4f830809f5e91b68699c05fa9faa7c3d1f9d1b1c982c282508fa18d695537
+A.Z = eb372f19c7b9466a116363ad9114a89ad287523da318d915f59ed5e558bd824e
+B.X = c76ddbcb15bc63f82807804536a0d25fd7a639c71adf953ad6cc8f68d915f485
+B.Y = e3a4f830809f5e91b68699c05fa9faa7c3d1f9d1b1c982c282508fa18d695537
+B.Z = eb372f19c7b9466a116363ad9114a89ad287523da318d915f59ed5e558bd824e
+Result.X = c5485a3509f55c7cc33d098fb0bfe1b198a9f26ce0ebc29bec5baa29ef6f74a2
+Result.Y = 60e949a551aa94afc9a3efe411a3c63ecb851ef1738ed24c88f86cf85ec01020
+
+Test = PointAdd
+A.X = ca72936509631f09d2a3ac14fb786daabb15520ef01de4298c7fd71653e89194
+A.Y = 02aeb6b6f04cd8125887baa18e6e79ba2b0acfa9a2443e9eea36ca7715eb8eb3
+A.Z = 8b4ef1a52fa42c711445e0463003f2ed38ace6583bf08198e9a0b938b4589479
+B.X = ca72936509631f09d2a3ac14fb786daabb15520ef01de4298c7fd71653e89194
+B.Y = 02aeb6b6f04cd8125887baa18e6e79ba2b0acfa9a2443e9eea36ca7715eb8eb3
+B.Z = 8b4ef1a52fa42c711445e0463003f2ed38ace6583bf08198e9a0b938b4589479
+Result.X = 8d3b35c5661faafa83510ab9b3f1642bb121e7686ed4ae61323ddee2c7247f93
+Result.Y = 1a22ef5df156ca80235fe3cd1ca3152e21a3e17b2a34dd93b2003e3274a8a2fb
+
+Test = PointAdd
+A.X = db7b023fbe056819027fa09c5a2a0d777a53fb78c00bf4f31f46b63a7494bbfe
+A.Y = 59affcbf4628d572ee56b95087d30e765bb518b123e879b25df9960dab706a32
+A.Z = 1f7c7226d78e51478c683bbb6afe01abc2225dbfc773d0806d30ff5f827b76c8
+B.X = db7b023fbe056819027fa09c5a2a0d777a53fb78c00bf4f31f46b63a7494bbfe
+B.Y = 59affcbf4628d572ee56b95087d30e765bb518b123e879b25df9960dab706a32
+B.Z = 1f7c7226d78e51478c683bbb6afe01abc2225dbfc773d0806d30ff5f827b76c8
+Result.X = fba400ae656ec3103c5c5f531d2a0f7368031e01a48a91f1a4f3138d294b13be
+Result.Y = 160e358ad1f059eb62722df01a7440048a1db21ecaea8698efa9677db6e9ff97
diff --git a/src/crypto/err/ssl.errordata b/src/crypto/err/ssl.errordata
index c25683e..b50f9ab 100644
--- a/src/crypto/err/ssl.errordata
+++ b/src/crypto/err/ssl.errordata
@@ -66,6 +66,7 @@
 SSL,256,INVALID_COMPRESSION_LIST
 SSL,159,INVALID_MESSAGE
 SSL,251,INVALID_OUTER_RECORD_TYPE
+SSL,269,INVALID_SCT_LIST
 SSL,160,INVALID_SSL_SESSION
 SSL,161,INVALID_TICKET_KEYS_LENGTH
 SSL,162,LENGTH_MISMATCH
@@ -99,12 +100,14 @@
 SSL,185,NULL_SSL_CTX
 SSL,186,NULL_SSL_METHOD_PASSED
 SSL,187,OLD_SESSION_CIPHER_NOT_RETURNED
+SSL,268,OLD_SESSION_PRF_HASH_MISMATCH
 SSL,188,OLD_SESSION_VERSION_NOT_RETURNED
 SSL,189,OUTPUT_ALIASES_INPUT
 SSL,190,PARSE_TLSEXT
 SSL,191,PATH_TOO_LONG
 SSL,192,PEER_DID_NOT_RETURN_A_CERTIFICATE
 SSL,193,PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE
+SSL,267,PRE_SHARED_KEY_MUST_BE_LAST
 SSL,194,PROTOCOL_IS_SHUTDOWN
 SSL,195,PSK_IDENTITY_NOT_FOUND
 SSL,196,PSK_NO_CLIENT_CB
diff --git a/src/crypto/mem.c b/src/crypto/mem.c
index 4596472..ee34767 100644
--- a/src/crypto/mem.c
+++ b/src/crypto/mem.c
@@ -68,14 +68,6 @@
 #if defined(OPENSSL_WINDOWS)
 OPENSSL_MSVC_PRAGMA(warning(push, 3))
 #include <windows.h>
-
-/* Work around a clang-cl bug: SecureZeroMemory() below uses __stosb() but
- * windows.h only declares that intrinsic and then uses `#pragma intrinsic` for
- * it.  clang-cl doesn't implement `#pragma intrinsic` yet; it instead defines
- * the function as an always-inline symbol in its intrin.h.
- * TODO(thakis): Remove this once http://llvm.org/PR19898 is fixed.
- */
-#include <intrin.h>
 OPENSSL_MSVC_PRAGMA(warning(pop))
 #else
 #include <strings.h>
diff --git a/src/crypto/poly1305/poly1305.c b/src/crypto/poly1305/poly1305.c
index 5e36802..4c5d11f 100644
--- a/src/crypto/poly1305/poly1305.c
+++ b/src/crypto/poly1305/poly1305.c
@@ -27,7 +27,6 @@
 
 #if defined(OPENSSL_WINDOWS) || !defined(OPENSSL_X86_64)
 
-#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || defined(OPENSSL_ARM)
 /* We can assume little-endian. */
 static uint32_t U8TO32_LE(const uint8_t *m) {
   uint32_t r;
@@ -36,19 +35,6 @@
 }
 
 static void U32TO8_LE(uint8_t *m, uint32_t v) { memcpy(m, &v, sizeof(v)); }
-#else
-static uint32_t U8TO32_LE(const uint8_t *m) {
-  return (uint32_t)m[0] | (uint32_t)m[1] << 8 | (uint32_t)m[2] << 16 |
-         (uint32_t)m[3] << 24;
-}
-
-static void U32TO8_LE(uint8_t *m, uint32_t v) {
-  m[0] = v;
-  m[1] = v >> 8;
-  m[2] = v >> 16;
-  m[3] = v >> 24;
-}
-#endif
 
 static uint64_t mul32x32_64(uint32_t a, uint32_t b) { return (uint64_t)a * b; }
 
@@ -61,6 +47,11 @@
   uint8_t key[16];
 };
 
+static inline struct poly1305_state_st *poly1305_aligned_state(
+    poly1305_state *state) {
+  return (struct poly1305_state_st *)(((uintptr_t)state + 63) & ~63);
+}
+
 /* poly1305_blocks updates |state| given some amount of input data. This
  * function may only be called with a |len| that is not a multiple of 16 at the
  * end of the data. Otherwise the input must be buffered into 16 byte blocks. */
@@ -159,7 +150,7 @@
 }
 
 void CRYPTO_poly1305_init(poly1305_state *statep, const uint8_t key[32]) {
-  struct poly1305_state_st *state = (struct poly1305_state_st *)statep;
+  struct poly1305_state_st *state = poly1305_aligned_state(statep);
   uint32_t t0, t1, t2, t3;
 
 #if defined(OPENSSL_ARM) && !defined(OPENSSL_NO_ASM)
@@ -207,7 +198,7 @@
 void CRYPTO_poly1305_update(poly1305_state *statep, const uint8_t *in,
                             size_t in_len) {
   unsigned int i;
-  struct poly1305_state_st *state = (struct poly1305_state_st *)statep;
+  struct poly1305_state_st *state = poly1305_aligned_state(statep);
 
 #if defined(OPENSSL_ARM) && !defined(OPENSSL_NO_ASM)
   if (CRYPTO_is_NEON_capable()) {
@@ -250,7 +241,7 @@
 }
 
 void CRYPTO_poly1305_finish(poly1305_state *statep, uint8_t mac[16]) {
-  struct poly1305_state_st *state = (struct poly1305_state_st *)statep;
+  struct poly1305_state_st *state = poly1305_aligned_state(statep);
   uint64_t f0, f1, f2, f3;
   uint32_t g0, g1, g2, g3, g4;
   uint32_t b, nb;
diff --git a/src/crypto/pool/CMakeLists.txt b/src/crypto/pool/CMakeLists.txt
new file mode 100644
index 0000000..fe55af2
--- /dev/null
+++ b/src/crypto/pool/CMakeLists.txt
@@ -0,0 +1,20 @@
+include_directories(../../include)
+
+add_library(
+  pool
+
+  OBJECT
+
+  pool.c
+)
+
+add_executable(
+  pool_test
+
+  pool_test.cc
+
+  $<TARGET_OBJECTS:test_support>
+)
+
+target_link_libraries(pool_test crypto)
+add_dependencies(all_tests pool_test)
diff --git a/src/crypto/pool/internal.h b/src/crypto/pool/internal.h
new file mode 100644
index 0000000..3ec2ec2
--- /dev/null
+++ b/src/crypto/pool/internal.h
@@ -0,0 +1,45 @@
+/* Copyright (c) 2016, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#ifndef OPENSSL_HEADER_POOL_INTERNAL_H
+#define OPENSSL_HEADER_POOL_INTERNAL_H
+
+#include <openssl/lhash.h>
+#include <openssl/thread.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+DECLARE_LHASH_OF(CRYPTO_BUFFER);
+
+struct crypto_buffer_st {
+  CRYPTO_BUFFER_POOL *pool;
+  uint8_t *data;
+  size_t len;
+  CRYPTO_refcount_t references;
+};
+
+struct crypto_buffer_pool_st {
+  LHASH_OF(CRYPTO_BUFFER) *bufs;
+  CRYPTO_MUTEX lock;
+};
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#endif /* OPENSSL_HEADER_POOL_INTERNAL_H */
diff --git a/src/crypto/pool/pool.c b/src/crypto/pool/pool.c
new file mode 100644
index 0000000..ca058fc
--- /dev/null
+++ b/src/crypto/pool/pool.c
@@ -0,0 +1,200 @@
+/* Copyright (c) 2016, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/pool.h>
+
+#include <assert.h>
+#include <string.h>
+
+#include <openssl/buf.h>
+#include <openssl/bytestring.h>
+#include <openssl/mem.h>
+#include <openssl/thread.h>
+
+#include "../internal.h"
+#include "internal.h"
+
+
+static uint32_t CRYPTO_BUFFER_hash(const CRYPTO_BUFFER *buf) {
+  return OPENSSL_hash32(buf->data, buf->len);
+}
+
+static int CRYPTO_BUFFER_cmp(const CRYPTO_BUFFER *a, const CRYPTO_BUFFER *b) {
+  if (a->len != b->len) {
+    return 1;
+  }
+  return memcmp(a->data, b->data, a->len);
+}
+
+CRYPTO_BUFFER_POOL* CRYPTO_BUFFER_POOL_new(void) {
+  CRYPTO_BUFFER_POOL *pool = OPENSSL_malloc(sizeof(CRYPTO_BUFFER_POOL));
+  if (pool == NULL) {
+    return NULL;
+  }
+
+  memset(pool, 0, sizeof(CRYPTO_BUFFER_POOL));
+  pool->bufs = lh_CRYPTO_BUFFER_new(CRYPTO_BUFFER_hash, CRYPTO_BUFFER_cmp);
+  if (pool->bufs == NULL) {
+    OPENSSL_free(pool);
+    return NULL;
+  }
+
+  CRYPTO_MUTEX_init(&pool->lock);
+
+  return pool;
+}
+
+void CRYPTO_BUFFER_POOL_free(CRYPTO_BUFFER_POOL *pool) {
+  if (pool == NULL) {
+    return;
+  }
+
+#if !defined(NDEBUG)
+  CRYPTO_MUTEX_lock_write(&pool->lock);
+  assert(lh_CRYPTO_BUFFER_num_items(pool->bufs) == 0);
+  CRYPTO_MUTEX_unlock_write(&pool->lock);
+#endif
+
+  lh_CRYPTO_BUFFER_free(pool->bufs);
+  CRYPTO_MUTEX_cleanup(&pool->lock);
+  OPENSSL_free(pool);
+}
+
+CRYPTO_BUFFER *CRYPTO_BUFFER_new(const uint8_t *data, size_t len,
+                                 CRYPTO_BUFFER_POOL *pool) {
+  if (pool != NULL) {
+    CRYPTO_BUFFER tmp;
+    tmp.data = (uint8_t *) data;
+    tmp.len = len;
+
+    CRYPTO_MUTEX_lock_read(&pool->lock);
+    CRYPTO_BUFFER *const duplicate =
+        lh_CRYPTO_BUFFER_retrieve(pool->bufs, &tmp);
+    if (duplicate != NULL) {
+      CRYPTO_refcount_inc(&duplicate->references);
+    }
+    CRYPTO_MUTEX_unlock_read(&pool->lock);
+
+    if (duplicate != NULL) {
+      return duplicate;
+    }
+  }
+
+  CRYPTO_BUFFER *const buf = OPENSSL_malloc(sizeof(CRYPTO_BUFFER));
+  if (buf == NULL) {
+    return NULL;
+  }
+  memset(buf, 0, sizeof(CRYPTO_BUFFER));
+
+  buf->data = BUF_memdup(data, len);
+  if (len != 0 && buf->data == NULL) {
+    OPENSSL_free(buf);
+    return NULL;
+  }
+
+  buf->len = len;
+  buf->references = 1;
+
+  if (pool == NULL) {
+    return buf;
+  }
+
+  buf->pool = pool;
+
+  CRYPTO_MUTEX_lock_write(&pool->lock);
+  CRYPTO_BUFFER *duplicate = lh_CRYPTO_BUFFER_retrieve(pool->bufs, buf);
+  int inserted = 0;
+  if (duplicate == NULL) {
+    CRYPTO_BUFFER *old = NULL;
+    inserted = lh_CRYPTO_BUFFER_insert(pool->bufs, &old, buf);
+    assert(old == NULL);
+  } else {
+    CRYPTO_refcount_inc(&duplicate->references);
+  }
+  CRYPTO_MUTEX_unlock_write(&pool->lock);
+
+  if (!inserted) {
+    /* We raced to insert |buf| into the pool and lost, or else there was an
+     * error inserting. */
+    OPENSSL_free(buf->data);
+    OPENSSL_free(buf);
+    return duplicate;
+  }
+
+  return buf;
+}
+
+CRYPTO_BUFFER* CRYPTO_BUFFER_new_from_CBS(CBS *cbs, CRYPTO_BUFFER_POOL *pool) {
+  return CRYPTO_BUFFER_new(CBS_data(cbs), CBS_len(cbs), pool);
+}
+
+void CRYPTO_BUFFER_free(CRYPTO_BUFFER *buf) {
+  if (buf == NULL) {
+    return;
+  }
+
+  CRYPTO_BUFFER_POOL *const pool = buf->pool;
+  if (pool == NULL) {
+    if (CRYPTO_refcount_dec_and_test_zero(&buf->references)) {
+      /* If a reference count of zero is observed, there cannot be a reference
+       * from any pool to this buffer and thus we are able to free this
+       * buffer. */
+      OPENSSL_free(buf->data);
+      OPENSSL_free(buf);
+    }
+
+    return;
+  }
+
+  CRYPTO_MUTEX_lock_write(&pool->lock);
+  if (!CRYPTO_refcount_dec_and_test_zero(&buf->references)) {
+    CRYPTO_MUTEX_unlock_write(&buf->pool->lock);
+    return;
+  }
+
+  /* We have an exclusive lock on the pool, therefore no concurrent lookups can
+   * find this buffer and increment the reference count. Thus, if the count is
+   * zero there are and can never be any more references and thus we can free
+   * this buffer. */
+  void *found = lh_CRYPTO_BUFFER_delete(pool->bufs, buf);
+  assert(found != NULL);
+  assert(found == buf);
+  (void)found;
+  CRYPTO_MUTEX_unlock_write(&buf->pool->lock);
+  OPENSSL_free(buf->data);
+  OPENSSL_free(buf);
+}
+
+int CRYPTO_BUFFER_up_ref(CRYPTO_BUFFER *buf) {
+  /* This is safe in the case that |buf->pool| is NULL because it's just
+   * standard reference counting in that case.
+   *
+   * This is also safe if |buf->pool| is non-NULL because, if it were racing
+   * with |CRYPTO_BUFFER_free| then the two callers must have independent
+   * references already and so the reference count will never hit zero. */
+  CRYPTO_refcount_inc(&buf->references);
+  return 1;
+}
+
+const uint8_t *CRYPTO_BUFFER_data(const CRYPTO_BUFFER *buf) {
+  return buf->data;
+}
+
+size_t CRYPTO_BUFFER_len(const CRYPTO_BUFFER *buf) {
+  return buf->len;
+}
+
+void CRYPTO_BUFFER_init_CBS(const CRYPTO_BUFFER *buf, CBS *out) {
+  CBS_init(out, buf->data, buf->len);
+}
diff --git a/src/crypto/pool/pool_test.cc b/src/crypto/pool/pool_test.cc
new file mode 100644
index 0000000..0b5338f
--- /dev/null
+++ b/src/crypto/pool/pool_test.cc
@@ -0,0 +1,86 @@
+/* Copyright (c) 2016, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <openssl/pool.h>
+
+
+static bool TestUnpooled() {
+  static const uint8_t kData[4] = {1, 2, 3, 4};
+  bssl::UniquePtr<CRYPTO_BUFFER> buf(
+      CRYPTO_BUFFER_new(kData, sizeof(kData), nullptr));
+  if (!buf) {
+    return false;
+  }
+
+  if (CRYPTO_BUFFER_len(buf.get()) != sizeof(kData) ||
+      memcmp(kData, CRYPTO_BUFFER_data(buf.get()), sizeof(kData)) != 0) {
+    fprintf(stderr, "CRYPTO_BUFFER corrupted data.\n");
+    return false;
+  }
+
+  CRYPTO_BUFFER_up_ref(buf.get());
+  bssl::UniquePtr<CRYPTO_BUFFER> buf2(buf.get());
+
+  return true;
+}
+
+static bool TestEmpty() {
+  bssl::UniquePtr<CRYPTO_BUFFER> buf(CRYPTO_BUFFER_new(nullptr, 0, nullptr));
+  if (!buf) {
+    return false;
+  }
+
+  return true;
+}
+
+static bool TestPool() {
+  bssl::UniquePtr<CRYPTO_BUFFER_POOL> pool(CRYPTO_BUFFER_POOL_new());
+  if (!pool) {
+    return false;
+  }
+
+  static const uint8_t kData[4] = {1, 2, 3, 4};
+  bssl::UniquePtr<CRYPTO_BUFFER> buf(
+      CRYPTO_BUFFER_new(kData, sizeof(kData), pool.get()));
+  if (!buf) {
+    return false;
+  }
+
+  bssl::UniquePtr<CRYPTO_BUFFER> buf2(
+      CRYPTO_BUFFER_new(kData, sizeof(kData), pool.get()));
+  if (!buf2) {
+    return false;
+  }
+
+  if (buf.get() != buf2.get()) {
+    fprintf(stderr, "CRYPTO_BUFFER_POOL did not dedup data.\n");
+    return false;
+  }
+
+  return true;
+}
+
+int main(int argc, char **argv) {
+  if (!TestUnpooled() ||
+      !TestEmpty() ||
+      !TestPool()) {
+    return 1;
+  }
+
+  printf("PASS\n");
+  return 0;
+}
diff --git a/src/crypto/rand/deterministic.c b/src/crypto/rand/deterministic.c
index 628fd22..c0a347c 100644
--- a/src/crypto/rand/deterministic.c
+++ b/src/crypto/rand/deterministic.c
@@ -14,7 +14,7 @@
 
 #include <openssl/rand.h>
 
-#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+#if defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE)
 
 #include <string.h>
 
@@ -44,4 +44,4 @@
   g_num_calls++;
 }
 
-#endif  /* BORINGSSL_UNSAFE_FUZZER_MODE */
+#endif  /* BORINGSSL_UNSAFE_DETERMINISTIC_MODE */
diff --git a/src/crypto/rand/rand.c b/src/crypto/rand/rand.c
index b73bc3c..ec78a2e 100644
--- a/src/crypto/rand/rand.c
+++ b/src/crypto/rand/rand.c
@@ -73,7 +73,7 @@
 }
 
 #if defined(OPENSSL_X86_64) && !defined(OPENSSL_NO_ASM) && \
-    !defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+    !defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE)
 
 /* These functions are defined in asm/rdrand-x86_64.pl */
 extern int CRYPTO_rdrand(uint8_t out[8]);
diff --git a/src/crypto/rand/urandom.c b/src/crypto/rand/urandom.c
index 4c8a5f7..2572625 100644
--- a/src/crypto/rand/urandom.c
+++ b/src/crypto/rand/urandom.c
@@ -12,9 +12,11 @@
  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
 
+#define _GNU_SOURCE  /* needed for syscall() on Linux. */
+
 #include <openssl/rand.h>
 
-#if !defined(OPENSSL_WINDOWS) && !defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+#if !defined(OPENSSL_WINDOWS) && !defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE)
 
 #include <assert.h>
 #include <errno.h>
@@ -22,6 +24,10 @@
 #include <string.h>
 #include <unistd.h>
 
+#if defined(OPENSSL_LINUX)
+#include <sys/syscall.h>
+#endif
+
 #include <openssl/thread.h>
 #include <openssl/mem.h>
 
@@ -29,6 +35,43 @@
 #include "../internal.h"
 
 
+#if defined(OPENSSL_LINUX)
+
+#if defined(OPENSSL_X86_64)
+#define EXPECTED_SYS_getrandom 318
+#elif defined(OPENSSL_X86)
+#define EXPECTED_SYS_getrandom 355
+#elif defined(OPENSSL_AARCH64)
+#define EXPECTED_SYS_getrandom 278
+#elif defined(OPENSSL_ARM)
+#define EXPECTED_SYS_getrandom 384
+#elif defined(OPENSSL_PPC64LE)
+#define EXPECTED_SYS_getrandom 359
+#endif
+
+#if defined(EXPECTED_SYS_getrandom)
+#define USE_SYS_getrandom
+
+#if defined(SYS_getrandom)
+
+#if SYS_getrandom != EXPECTED_SYS_getrandom
+#error "system call number for getrandom is not the expected value"
+#endif
+
+#else  /* SYS_getrandom */
+
+#define SYS_getrandom EXPECTED_SYS_getrandom
+
+#endif  /* SYS_getrandom */
+
+#endif /* EXPECTED_SYS_getrandom */
+
+#if !defined(GRND_NONBLOCK)
+#define GRND_NONBLOCK 1
+#endif
+
+#endif  /* OPENSSL_LINUX */
+
 /* This file implements a PRNG by reading from /dev/urandom, optionally with a
  * buffer, which is unsafe across |fork|. */
 
@@ -71,6 +114,12 @@
   int fd = urandom_fd_requested;
   CRYPTO_STATIC_MUTEX_unlock_read(&requested_lock);
 
+#if defined(USE_SYS_getrandom)
+  /* Initial test of getrandom to find any unexpected behavior. */
+  uint8_t dummy;
+  syscall(SYS_getrandom, &dummy, sizeof(dummy), GRND_NONBLOCK);
+#endif
+
   if (fd == -2) {
     do {
       fd = open("/dev/urandom", O_RDONLY);
@@ -144,7 +193,7 @@
   if (buf == NULL) {
     return NULL;
   }
-  buf->used = BUF_SIZE;  /* To trigger a |read_full| on first use. */
+  buf->used = BUF_SIZE;  /* To trigger a |fill_with_entropy| on first use. */
   if (!CRYPTO_set_thread_local(OPENSSL_THREAD_LOCAL_URANDOM_BUF, buf,
                                OPENSSL_free)) {
     OPENSSL_free(buf);
@@ -154,14 +203,14 @@
   return buf;
 }
 
-/* read_full reads exactly |len| bytes from |fd| into |out| and returns 1. In
- * the case of an error it returns 0. */
-static char read_full(int fd, uint8_t *out, size_t len) {
+/* fill_with_entropy writes |len| bytes of entropy into |out|. It returns one
+ * on success and zero on error. */
+static char fill_with_entropy(uint8_t *out, size_t len) {
   ssize_t r;
 
   while (len > 0) {
     do {
-      r = read(fd, out, len);
+      r = read(urandom_fd, out, len);
     } while (r == -1 && errno == EINTR);
 
     if (r <= 0) {
@@ -186,7 +235,7 @@
     out += remaining;
     requested -= remaining;
 
-    if (!read_full(urandom_fd, buf->rand, BUF_SIZE)) {
+    if (!fill_with_entropy(buf->rand, BUF_SIZE)) {
       abort();
       return;
     }
@@ -213,9 +262,9 @@
     }
   }
 
-  if (!read_full(urandom_fd, out, requested)) {
+  if (!fill_with_entropy(out, requested)) {
     abort();
   }
 }
 
-#endif  /* !OPENSSL_WINDOWS && !BORINGSSL_UNSAFE_FUZZER_MODE */
+#endif  /* !OPENSSL_WINDOWS && !BORINGSSL_UNSAFE_DETERMINISTIC_MODE */
diff --git a/src/crypto/rand/windows.c b/src/crypto/rand/windows.c
index 07e7dd8..f47182d 100644
--- a/src/crypto/rand/windows.c
+++ b/src/crypto/rand/windows.c
@@ -14,7 +14,7 @@
 
 #include <openssl/rand.h>
 
-#if defined(OPENSSL_WINDOWS) && !defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+#if defined(OPENSSL_WINDOWS) && !defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE)
 
 #include <limits.h>
 #include <stdlib.h>
@@ -50,4 +50,4 @@
   return;
 }
 
-#endif  /* OPENSSL_WINDOWS && !BORINGSSL_UNSAFE_FUZZER_MODE */
+#endif  /* OPENSSL_WINDOWS && !BORINGSSL_UNSAFE_DETERMINISTIC_MODE */
diff --git a/src/crypto/sha/CMakeLists.txt b/src/crypto/sha/CMakeLists.txt
index 49147d3..64c77db 100644
--- a/src/crypto/sha/CMakeLists.txt
+++ b/src/crypto/sha/CMakeLists.txt
@@ -45,6 +45,7 @@
 
   OBJECT
 
+  sha1-altivec.c
   sha1.c
   sha256.c
   sha512.c
diff --git a/src/crypto/sha/sha1-altivec.c b/src/crypto/sha/sha1-altivec.c
new file mode 100644
index 0000000..500986e
--- /dev/null
+++ b/src/crypto/sha/sha1-altivec.c
@@ -0,0 +1,346 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+/* Altivec-optimized SHA1 in C. This is tested on ppc64le only.
+ *
+ * References:
+ * https://software.intel.com/en-us/articles/improving-the-performance-of-the-secure-hash-algorithm-1
+ * http://arctic.org/~dean/crypto/sha1.html
+ *
+ * This code used the generic SHA-1 from OpenSSL as a basis and AltiVec
+ * optimisations were added on top. */
+
+#include <openssl/sha.h>
+
+#if defined(OPENSSL_PPC64LE)
+
+#include <altivec.h>
+
+void sha1_block_data_order(uint32_t *state, const uint8_t *data, size_t num);
+
+static uint32_t rotate(uint32_t a, int n) { return (a << n) | (a >> (32 - n)); }
+
+typedef vector unsigned int vec_uint32_t;
+typedef vector unsigned char vec_uint8_t;
+
+/* Vector constants */
+static const vec_uint8_t k_swap_endianness = {3,  2,  1, 0, 7,  6,  5,  4,
+                                              11, 10, 9, 8, 15, 14, 13, 12};
+
+/* Shift amounts for byte and bit shifts and rotations */
+static const vec_uint8_t k_4_bytes = {32, 32, 32, 32, 32, 32, 32, 32,
+                                      32, 32, 32, 32, 32, 32, 32, 32};
+static const vec_uint8_t k_12_bytes = {96, 96, 96, 96, 96, 96, 96, 96,
+                                       96, 96, 96, 96, 96, 96, 96, 96};
+
+#define K_00_19 0x5a827999UL
+#define K_20_39 0x6ed9eba1UL
+#define K_40_59 0x8f1bbcdcUL
+#define K_60_79 0xca62c1d6UL
+
+/* Vector versions of the above. */
+static const vec_uint32_t K_00_19_x_4 = {K_00_19, K_00_19, K_00_19, K_00_19};
+static const vec_uint32_t K_20_39_x_4 = {K_20_39, K_20_39, K_20_39, K_20_39};
+static const vec_uint32_t K_40_59_x_4 = {K_40_59, K_40_59, K_40_59, K_40_59};
+static const vec_uint32_t K_60_79_x_4 = {K_60_79, K_60_79, K_60_79, K_60_79};
+
+/* vector message scheduling: compute message schedule for round i..i+3 where i
+ * is divisible by 4. We return the schedule w[i..i+3] as a vector. In
+ * addition, we also precompute sum w[i..+3] and an additive constant K. This
+ * is done to offload some computation of f() in the integer execution units.
+ *
+ * Byte shifting code below may not be correct for big-endian systems. */
+static vec_uint32_t sched_00_15(vec_uint32_t *pre_added, const void *data,
+                                vec_uint32_t k) {
+  const vec_uint32_t v = *((const vec_uint32_t *)data);
+  const vec_uint32_t w = vec_perm(v, v, k_swap_endianness);
+  vec_st(w + k, 0, pre_added);
+  return w;
+}
+
+/* Compute w[i..i+3] using these steps for i in [16, 20, 24, 28]
+ *
+ * w'[i  ]  = (w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16]) <<< 1
+ * w'[i+1]  = (w[i-2] ^ w[i-7] ^ w[i-13] ^ w[i-15]) <<< 1
+ * w'[i+2]  = (w[i-1] ^ w[i-6] ^ w[i-12] ^ w[i-14]) <<< 1
+ * w'[i+3]  = (     0 ^ w[i-5] ^ w[i-11] ^ w[i-13]) <<< 1
+ *
+ * w[  i] = w'[  i]
+ * w[i+1] = w'[i+1]
+ * w[i+2] = w'[i+2]
+ * w[i+3] = w'[i+3] ^ (w'[i] <<< 1) */
+static vec_uint32_t sched_16_31(vec_uint32_t *pre_added, vec_uint32_t minus_4,
+                                vec_uint32_t minus_8, vec_uint32_t minus_12,
+                                vec_uint32_t minus_16, vec_uint32_t k) {
+  const vec_uint32_t minus_3 = vec_sro(minus_4, k_4_bytes);
+  const vec_uint32_t minus_14 = vec_sld((minus_12), (minus_16), 8);
+  const vec_uint32_t k_1_bit = vec_splat_u32(1);
+  const vec_uint32_t w_prime =
+      vec_rl(minus_3 ^ minus_8 ^ minus_14 ^ minus_16, k_1_bit);
+  const vec_uint32_t w =
+      w_prime ^ vec_rl(vec_slo(w_prime, k_12_bytes), k_1_bit);
+  vec_st(w + k, 0, pre_added);
+  return w;
+}
+
+/* Compute w[i..i+3] using this relation for i in [32, 36, 40 ... 76]
+ * w[i] = (w[i-6] ^ w[i-16] ^ w[i-28] ^ w[i-32]), 2) <<< 2 */
+static vec_uint32_t sched_32_79(vec_uint32_t *pre_added, vec_uint32_t minus_4,
+                                vec_uint32_t minus_8, vec_uint32_t minus_16,
+                                vec_uint32_t minus_28, vec_uint32_t minus_32,
+                                vec_uint32_t k) {
+  const vec_uint32_t minus_6 = vec_sld(minus_4, minus_8, 8);
+  const vec_uint32_t k_2_bits = vec_splat_u32(2);
+  const vec_uint32_t w =
+      vec_rl(minus_6 ^ minus_16 ^ minus_28 ^ minus_32, k_2_bits);
+  vec_st(w + k, 0, pre_added);
+  return w;
+}
+
+/* As pointed out by Wei Dai <weidai@eskimo.com>, F() below can be simplified
+ * to the code in F_00_19. Wei attributes these optimisations to Peter
+ * Gutmann's SHS code, and he attributes it to Rich Schroeppel. #define
+ * F(x,y,z) (((x) & (y))  |  ((~(x)) & (z))) I've just become aware of another
+ * tweak to be made, again from Wei Dai, in F_40_59, (x&a)|(y&a) -> (x|y)&a */
+#define F_00_19(b, c, d) ((((c) ^ (d)) & (b)) ^ (d))
+#define F_20_39(b, c, d) ((b) ^ (c) ^ (d))
+#define F_40_59(b, c, d) (((b) & (c)) | (((b) | (c)) & (d)))
+#define F_60_79(b, c, d) F_20_39(b, c, d)
+
+/* We pre-added the K constants during message scheduling. */
+#define BODY_00_19(i, a, b, c, d, e, f)                         \
+  do {                                                          \
+    (f) = w[i] + (e) + rotate((a), 5) + F_00_19((b), (c), (d)); \
+    (b) = rotate((b), 30);                                      \
+  } while (0)
+
+#define BODY_20_39(i, a, b, c, d, e, f)                         \
+  do {                                                          \
+    (f) = w[i] + (e) + rotate((a), 5) + F_20_39((b), (c), (d)); \
+    (b) = rotate((b), 30);                                      \
+  } while (0)
+
+#define BODY_40_59(i, a, b, c, d, e, f)                         \
+  do {                                                          \
+    (f) = w[i] + (e) + rotate((a), 5) + F_40_59((b), (c), (d)); \
+    (b) = rotate((b), 30);                                      \
+  } while (0)
+
+#define BODY_60_79(i, a, b, c, d, e, f)                         \
+  do {                                                          \
+    (f) = w[i] + (e) + rotate((a), 5) + F_60_79((b), (c), (d)); \
+    (b) = rotate((b), 30);                                      \
+  } while (0)
+
+void sha1_block_data_order(uint32_t *state, const uint8_t *data, size_t num) {
+  uint32_t A, B, C, D, E, T;
+
+  A = state[0];
+  B = state[1];
+  C = state[2];
+  D = state[3];
+  E = state[4];
+
+  for (;;) {
+    vec_uint32_t vw[20];
+    const uint32_t *w = (const uint32_t *)&vw;
+
+    vec_uint32_t k = K_00_19_x_4;
+    const vec_uint32_t w0 = sched_00_15(vw + 0, data + 0, k);
+    BODY_00_19(0, A, B, C, D, E, T);
+    BODY_00_19(1, T, A, B, C, D, E);
+    BODY_00_19(2, E, T, A, B, C, D);
+    BODY_00_19(3, D, E, T, A, B, C);
+
+    const vec_uint32_t w4 = sched_00_15(vw + 1, data + 16, k);
+    BODY_00_19(4, C, D, E, T, A, B);
+    BODY_00_19(5, B, C, D, E, T, A);
+    BODY_00_19(6, A, B, C, D, E, T);
+    BODY_00_19(7, T, A, B, C, D, E);
+
+    const vec_uint32_t w8 = sched_00_15(vw + 2, data + 32, k);
+    BODY_00_19(8, E, T, A, B, C, D);
+    BODY_00_19(9, D, E, T, A, B, C);
+    BODY_00_19(10, C, D, E, T, A, B);
+    BODY_00_19(11, B, C, D, E, T, A);
+
+    const vec_uint32_t w12 = sched_00_15(vw + 3, data + 48, k);
+    BODY_00_19(12, A, B, C, D, E, T);
+    BODY_00_19(13, T, A, B, C, D, E);
+    BODY_00_19(14, E, T, A, B, C, D);
+    BODY_00_19(15, D, E, T, A, B, C);
+
+    const vec_uint32_t w16 = sched_16_31(vw + 4, w12, w8, w4, w0, k);
+    BODY_00_19(16, C, D, E, T, A, B);
+    BODY_00_19(17, B, C, D, E, T, A);
+    BODY_00_19(18, A, B, C, D, E, T);
+    BODY_00_19(19, T, A, B, C, D, E);
+
+    k = K_20_39_x_4;
+    const vec_uint32_t w20 = sched_16_31(vw + 5, w16, w12, w8, w4, k);
+    BODY_20_39(20, E, T, A, B, C, D);
+    BODY_20_39(21, D, E, T, A, B, C);
+    BODY_20_39(22, C, D, E, T, A, B);
+    BODY_20_39(23, B, C, D, E, T, A);
+
+    const vec_uint32_t w24 = sched_16_31(vw + 6, w20, w16, w12, w8, k);
+    BODY_20_39(24, A, B, C, D, E, T);
+    BODY_20_39(25, T, A, B, C, D, E);
+    BODY_20_39(26, E, T, A, B, C, D);
+    BODY_20_39(27, D, E, T, A, B, C);
+
+    const vec_uint32_t w28 = sched_16_31(vw + 7, w24, w20, w16, w12, k);
+    BODY_20_39(28, C, D, E, T, A, B);
+    BODY_20_39(29, B, C, D, E, T, A);
+    BODY_20_39(30, A, B, C, D, E, T);
+    BODY_20_39(31, T, A, B, C, D, E);
+
+    const vec_uint32_t w32 = sched_32_79(vw + 8, w28, w24, w16, w4, w0, k);
+    BODY_20_39(32, E, T, A, B, C, D);
+    BODY_20_39(33, D, E, T, A, B, C);
+    BODY_20_39(34, C, D, E, T, A, B);
+    BODY_20_39(35, B, C, D, E, T, A);
+
+    const vec_uint32_t w36 = sched_32_79(vw + 9, w32, w28, w20, w8, w4, k);
+    BODY_20_39(36, A, B, C, D, E, T);
+    BODY_20_39(37, T, A, B, C, D, E);
+    BODY_20_39(38, E, T, A, B, C, D);
+    BODY_20_39(39, D, E, T, A, B, C);
+
+    k = K_40_59_x_4;
+    const vec_uint32_t w40 = sched_32_79(vw + 10, w36, w32, w24, w12, w8, k);
+    BODY_40_59(40, C, D, E, T, A, B);
+    BODY_40_59(41, B, C, D, E, T, A);
+    BODY_40_59(42, A, B, C, D, E, T);
+    BODY_40_59(43, T, A, B, C, D, E);
+
+    const vec_uint32_t w44 = sched_32_79(vw + 11, w40, w36, w28, w16, w12, k);
+    BODY_40_59(44, E, T, A, B, C, D);
+    BODY_40_59(45, D, E, T, A, B, C);
+    BODY_40_59(46, C, D, E, T, A, B);
+    BODY_40_59(47, B, C, D, E, T, A);
+
+    const vec_uint32_t w48 = sched_32_79(vw + 12, w44, w40, w32, w20, w16, k);
+    BODY_40_59(48, A, B, C, D, E, T);
+    BODY_40_59(49, T, A, B, C, D, E);
+    BODY_40_59(50, E, T, A, B, C, D);
+    BODY_40_59(51, D, E, T, A, B, C);
+
+    const vec_uint32_t w52 = sched_32_79(vw + 13, w48, w44, w36, w24, w20, k);
+    BODY_40_59(52, C, D, E, T, A, B);
+    BODY_40_59(53, B, C, D, E, T, A);
+    BODY_40_59(54, A, B, C, D, E, T);
+    BODY_40_59(55, T, A, B, C, D, E);
+
+    const vec_uint32_t w56 = sched_32_79(vw + 14, w52, w48, w40, w28, w24, k);
+    BODY_40_59(56, E, T, A, B, C, D);
+    BODY_40_59(57, D, E, T, A, B, C);
+    BODY_40_59(58, C, D, E, T, A, B);
+    BODY_40_59(59, B, C, D, E, T, A);
+
+    k = K_60_79_x_4;
+    const vec_uint32_t w60 = sched_32_79(vw + 15, w56, w52, w44, w32, w28, k);
+    BODY_60_79(60, A, B, C, D, E, T);
+    BODY_60_79(61, T, A, B, C, D, E);
+    BODY_60_79(62, E, T, A, B, C, D);
+    BODY_60_79(63, D, E, T, A, B, C);
+
+    const vec_uint32_t w64 = sched_32_79(vw + 16, w60, w56, w48, w36, w32, k);
+    BODY_60_79(64, C, D, E, T, A, B);
+    BODY_60_79(65, B, C, D, E, T, A);
+    BODY_60_79(66, A, B, C, D, E, T);
+    BODY_60_79(67, T, A, B, C, D, E);
+
+    const vec_uint32_t w68 = sched_32_79(vw + 17, w64, w60, w52, w40, w36, k);
+    BODY_60_79(68, E, T, A, B, C, D);
+    BODY_60_79(69, D, E, T, A, B, C);
+    BODY_60_79(70, C, D, E, T, A, B);
+    BODY_60_79(71, B, C, D, E, T, A);
+
+    const vec_uint32_t w72 = sched_32_79(vw + 18, w68, w64, w56, w44, w40, k);
+    BODY_60_79(72, A, B, C, D, E, T);
+    BODY_60_79(73, T, A, B, C, D, E);
+    BODY_60_79(74, E, T, A, B, C, D);
+    BODY_60_79(75, D, E, T, A, B, C);
+
+    /* We don't use the last value */
+    (void)sched_32_79(vw + 19, w72, w68, w60, w48, w44, k);
+    BODY_60_79(76, C, D, E, T, A, B);
+    BODY_60_79(77, B, C, D, E, T, A);
+    BODY_60_79(78, A, B, C, D, E, T);
+    BODY_60_79(79, T, A, B, C, D, E);
+
+    const uint32_t mask = 0xffffffffUL;
+    state[0] = (state[0] + E) & mask;
+    state[1] = (state[1] + T) & mask;
+    state[2] = (state[2] + A) & mask;
+    state[3] = (state[3] + B) & mask;
+    state[4] = (state[4] + C) & mask;
+
+    data += 64;
+    if (--num == 0) {
+      break;
+    }
+
+    A = state[0];
+    B = state[1];
+    C = state[2];
+    D = state[3];
+    E = state[4];
+  }
+}
+
+#endif  /* OPENSSL_PPC64LE */
diff --git a/src/crypto/sha/sha1.c b/src/crypto/sha/sha1.c
index 0ebed99..12fb457 100644
--- a/src/crypto/sha/sha1.c
+++ b/src/crypto/sha/sha1.c
@@ -63,7 +63,8 @@
 
 #if !defined(OPENSSL_NO_ASM) &&                         \
     (defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || \
-     defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64))
+     defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64) || \
+     defined(OPENSSL_PPC64LE))
 #define SHA1_ASM
 #endif
 
diff --git a/src/crypto/x509/t_x509.c b/src/crypto/x509/t_x509.c
index 1fba9b4..d5d48ba 100644
--- a/src/crypto/x509/t_x509.c
+++ b/src/crypto/x509/t_x509.c
@@ -207,7 +207,7 @@
         pkey = X509_get_pubkey(x);
         if (pkey == NULL) {
             BIO_printf(bp, "%12sUnable to load Public Key\n", "");
-            BIO_print_errors(bp);
+            ERR_print_errors(bp);
         } else {
             EVP_PKEY_print_public(bp, pkey, 16, NULL);
             EVP_PKEY_free(pkey);
diff --git a/src/crypto/x509/x509_test.cc b/src/crypto/x509/x509_test.cc
index dc5af13..c39d98d 100644
--- a/src/crypto/x509/x509_test.cc
+++ b/src/crypto/x509/x509_test.cc
@@ -17,298 +17,375 @@
 #include <assert.h>
 #include <string.h>
 
+#include <openssl/bytestring.h>
 #include <openssl/crypto.h>
 #include <openssl/digest.h>
 #include <openssl/err.h>
 #include <openssl/pem.h>
+#include <openssl/pool.h>
 #include <openssl/x509.h>
 
 namespace bssl {
 
 static const char kCrossSigningRootPEM[] =
-"-----BEGIN CERTIFICATE-----\n"
-"MIICcTCCAdqgAwIBAgIIagJHiPvE0MowDQYJKoZIhvcNAQELBQAwPDEaMBgGA1UE\n"
-"ChMRQm9yaW5nU1NMIFRFU1RJTkcxHjAcBgNVBAMTFUNyb3NzLXNpZ25pbmcgUm9v\n"
-"dCBDQTAgFw0xNTAxMDEwMDAwMDBaGA8yMTAwMDEwMTAwMDAwMFowPDEaMBgGA1UE\n"
-"ChMRQm9yaW5nU1NMIFRFU1RJTkcxHjAcBgNVBAMTFUNyb3NzLXNpZ25pbmcgUm9v\n"
-"dCBDQTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwo3qFvSB9Zmlbpzn9wJp\n"
-"ikI75Rxkatez8VkLqyxbOhPYl2Haz8F5p1gDG96dCI6jcLGgu3AKT9uhEQyyUko5\n"
-"EKYasazSeA9CQrdyhPg0mkTYVETnPM1W/ebid1YtqQbq1CMWlq2aTDoSGAReGFKP\n"
-"RTdXAbuAXzpCfi/d8LqV13UCAwEAAaN6MHgwDgYDVR0PAQH/BAQDAgIEMB0GA1Ud\n"
-"JQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAPBgNVHRMBAf8EBTADAQH/MBkGA1Ud\n"
-"DgQSBBBHKHC7V3Z/3oLvEZx0RZRwMBsGA1UdIwQUMBKAEEcocLtXdn/egu8RnHRF\n"
-"lHAwDQYJKoZIhvcNAQELBQADgYEAnglibsy6mGtpIXivtlcz4zIEnHw/lNW+r/eC\n"
-"CY7evZTmOoOuC/x9SS3MF9vawt1HFUummWM6ZgErqVBOXIB4//ykrcCgf5ZbF5Hr\n"
-"+3EFprKhBqYiXdD8hpBkrBoXwn85LPYWNd2TceCrx0YtLIprE2R5MB2RIq8y4Jk3\n"
-"YFXvkME=\n"
-"-----END CERTIFICATE-----\n";
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIICcTCCAdqgAwIBAgIIagJHiPvE0MowDQYJKoZIhvcNAQELBQAwPDEaMBgGA1UE\n"
+    "ChMRQm9yaW5nU1NMIFRFU1RJTkcxHjAcBgNVBAMTFUNyb3NzLXNpZ25pbmcgUm9v\n"
+    "dCBDQTAgFw0xNTAxMDEwMDAwMDBaGA8yMTAwMDEwMTAwMDAwMFowPDEaMBgGA1UE\n"
+    "ChMRQm9yaW5nU1NMIFRFU1RJTkcxHjAcBgNVBAMTFUNyb3NzLXNpZ25pbmcgUm9v\n"
+    "dCBDQTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwo3qFvSB9Zmlbpzn9wJp\n"
+    "ikI75Rxkatez8VkLqyxbOhPYl2Haz8F5p1gDG96dCI6jcLGgu3AKT9uhEQyyUko5\n"
+    "EKYasazSeA9CQrdyhPg0mkTYVETnPM1W/ebid1YtqQbq1CMWlq2aTDoSGAReGFKP\n"
+    "RTdXAbuAXzpCfi/d8LqV13UCAwEAAaN6MHgwDgYDVR0PAQH/BAQDAgIEMB0GA1Ud\n"
+    "JQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAPBgNVHRMBAf8EBTADAQH/MBkGA1Ud\n"
+    "DgQSBBBHKHC7V3Z/3oLvEZx0RZRwMBsGA1UdIwQUMBKAEEcocLtXdn/egu8RnHRF\n"
+    "lHAwDQYJKoZIhvcNAQELBQADgYEAnglibsy6mGtpIXivtlcz4zIEnHw/lNW+r/eC\n"
+    "CY7evZTmOoOuC/x9SS3MF9vawt1HFUummWM6ZgErqVBOXIB4//ykrcCgf5ZbF5Hr\n"
+    "+3EFprKhBqYiXdD8hpBkrBoXwn85LPYWNd2TceCrx0YtLIprE2R5MB2RIq8y4Jk3\n"
+    "YFXvkME=\n"
+    "-----END CERTIFICATE-----\n";
 
 static const char kRootCAPEM[] =
-"-----BEGIN CERTIFICATE-----\n"
-"MIICVTCCAb6gAwIBAgIIAj5CwoHlWuYwDQYJKoZIhvcNAQELBQAwLjEaMBgGA1UE\n"
-"ChMRQm9yaW5nU1NMIFRFU1RJTkcxEDAOBgNVBAMTB1Jvb3QgQ0EwIBcNMTUwMTAx\n"
-"MDAwMDAwWhgPMjEwMDAxMDEwMDAwMDBaMC4xGjAYBgNVBAoTEUJvcmluZ1NTTCBU\n"
-"RVNUSU5HMRAwDgYDVQQDEwdSb290IENBMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB\n"
-"iQKBgQDpDn8RDOZa5oaDcPZRBy4CeBH1siSSOO4mYgLHlPE+oXdqwI/VImi2XeJM\n"
-"2uCFETXCknJJjYG0iJdrt/yyRFvZTQZw+QzGj+mz36NqhGxDWb6dstB2m8PX+plZ\n"
-"w7jl81MDvUnWs8yiQ/6twgu5AbhWKZQDJKcNKCEpqa6UW0r5nwIDAQABo3oweDAO\n"
-"BgNVHQ8BAf8EBAMCAgQwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMA8G\n"
-"A1UdEwEB/wQFMAMBAf8wGQYDVR0OBBIEEEA31wH7QC+4HH5UBCeMWQEwGwYDVR0j\n"
-"BBQwEoAQQDfXAftAL7gcflQEJ4xZATANBgkqhkiG9w0BAQsFAAOBgQDXylEK77Za\n"
-"kKeY6ZerrScWyZhrjIGtHFu09qVpdJEzrk87k2G7iHHR9CAvSofCgEExKtWNS9dN\n"
-"+9WiZp/U48iHLk7qaYXdEuO07No4BYtXn+lkOykE+FUxmA4wvOF1cTd2tdj3MzX2\n"
-"kfGIBAYhzGZWhY3JbhIfTEfY1PNM1pWChQ==\n"
-"-----END CERTIFICATE-----\n";
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIICVTCCAb6gAwIBAgIIAj5CwoHlWuYwDQYJKoZIhvcNAQELBQAwLjEaMBgGA1UE\n"
+    "ChMRQm9yaW5nU1NMIFRFU1RJTkcxEDAOBgNVBAMTB1Jvb3QgQ0EwIBcNMTUwMTAx\n"
+    "MDAwMDAwWhgPMjEwMDAxMDEwMDAwMDBaMC4xGjAYBgNVBAoTEUJvcmluZ1NTTCBU\n"
+    "RVNUSU5HMRAwDgYDVQQDEwdSb290IENBMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB\n"
+    "iQKBgQDpDn8RDOZa5oaDcPZRBy4CeBH1siSSOO4mYgLHlPE+oXdqwI/VImi2XeJM\n"
+    "2uCFETXCknJJjYG0iJdrt/yyRFvZTQZw+QzGj+mz36NqhGxDWb6dstB2m8PX+plZ\n"
+    "w7jl81MDvUnWs8yiQ/6twgu5AbhWKZQDJKcNKCEpqa6UW0r5nwIDAQABo3oweDAO\n"
+    "BgNVHQ8BAf8EBAMCAgQwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMA8G\n"
+    "A1UdEwEB/wQFMAMBAf8wGQYDVR0OBBIEEEA31wH7QC+4HH5UBCeMWQEwGwYDVR0j\n"
+    "BBQwEoAQQDfXAftAL7gcflQEJ4xZATANBgkqhkiG9w0BAQsFAAOBgQDXylEK77Za\n"
+    "kKeY6ZerrScWyZhrjIGtHFu09qVpdJEzrk87k2G7iHHR9CAvSofCgEExKtWNS9dN\n"
+    "+9WiZp/U48iHLk7qaYXdEuO07No4BYtXn+lkOykE+FUxmA4wvOF1cTd2tdj3MzX2\n"
+    "kfGIBAYhzGZWhY3JbhIfTEfY1PNM1pWChQ==\n"
+    "-----END CERTIFICATE-----\n";
 
 static const char kRootCrossSignedPEM[] =
-"-----BEGIN CERTIFICATE-----\n"
-"MIICYzCCAcygAwIBAgIIAj5CwoHlWuYwDQYJKoZIhvcNAQELBQAwPDEaMBgGA1UE\n"
-"ChMRQm9yaW5nU1NMIFRFU1RJTkcxHjAcBgNVBAMTFUNyb3NzLXNpZ25pbmcgUm9v\n"
-"dCBDQTAgFw0xNTAxMDEwMDAwMDBaGA8yMTAwMDEwMTAwMDAwMFowLjEaMBgGA1UE\n"
-"ChMRQm9yaW5nU1NMIFRFU1RJTkcxEDAOBgNVBAMTB1Jvb3QgQ0EwgZ8wDQYJKoZI\n"
-"hvcNAQEBBQADgY0AMIGJAoGBAOkOfxEM5lrmhoNw9lEHLgJ4EfWyJJI47iZiAseU\n"
-"8T6hd2rAj9UiaLZd4kza4IURNcKSckmNgbSIl2u3/LJEW9lNBnD5DMaP6bPfo2qE\n"
-"bENZvp2y0Habw9f6mVnDuOXzUwO9SdazzKJD/q3CC7kBuFYplAMkpw0oISmprpRb\n"
-"SvmfAgMBAAGjejB4MA4GA1UdDwEB/wQEAwICBDAdBgNVHSUEFjAUBggrBgEFBQcD\n"
-"AQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAZBgNVHQ4EEgQQQDfXAftAL7gc\n"
-"flQEJ4xZATAbBgNVHSMEFDASgBBHKHC7V3Z/3oLvEZx0RZRwMA0GCSqGSIb3DQEB\n"
-"CwUAA4GBAErTxYJ0en9HVRHAAr5OO5wuk5Iq3VMc79TMyQLCXVL8YH8Uk7KEwv+q\n"
-"9MEKZv2eR/Vfm4HlXlUuIqfgUXbwrAYC/YVVX86Wnbpy/jc73NYVCq8FEZeO+0XU\n"
-"90SWAPDdp+iL7aZdimnMtG1qlM1edmz8AKbrhN/R3IbA2CL0nCWV\n"
-"-----END CERTIFICATE-----\n";
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIICYzCCAcygAwIBAgIIAj5CwoHlWuYwDQYJKoZIhvcNAQELBQAwPDEaMBgGA1UE\n"
+    "ChMRQm9yaW5nU1NMIFRFU1RJTkcxHjAcBgNVBAMTFUNyb3NzLXNpZ25pbmcgUm9v\n"
+    "dCBDQTAgFw0xNTAxMDEwMDAwMDBaGA8yMTAwMDEwMTAwMDAwMFowLjEaMBgGA1UE\n"
+    "ChMRQm9yaW5nU1NMIFRFU1RJTkcxEDAOBgNVBAMTB1Jvb3QgQ0EwgZ8wDQYJKoZI\n"
+    "hvcNAQEBBQADgY0AMIGJAoGBAOkOfxEM5lrmhoNw9lEHLgJ4EfWyJJI47iZiAseU\n"
+    "8T6hd2rAj9UiaLZd4kza4IURNcKSckmNgbSIl2u3/LJEW9lNBnD5DMaP6bPfo2qE\n"
+    "bENZvp2y0Habw9f6mVnDuOXzUwO9SdazzKJD/q3CC7kBuFYplAMkpw0oISmprpRb\n"
+    "SvmfAgMBAAGjejB4MA4GA1UdDwEB/wQEAwICBDAdBgNVHSUEFjAUBggrBgEFBQcD\n"
+    "AQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAZBgNVHQ4EEgQQQDfXAftAL7gc\n"
+    "flQEJ4xZATAbBgNVHSMEFDASgBBHKHC7V3Z/3oLvEZx0RZRwMA0GCSqGSIb3DQEB\n"
+    "CwUAA4GBAErTxYJ0en9HVRHAAr5OO5wuk5Iq3VMc79TMyQLCXVL8YH8Uk7KEwv+q\n"
+    "9MEKZv2eR/Vfm4HlXlUuIqfgUXbwrAYC/YVVX86Wnbpy/jc73NYVCq8FEZeO+0XU\n"
+    "90SWAPDdp+iL7aZdimnMtG1qlM1edmz8AKbrhN/R3IbA2CL0nCWV\n"
+    "-----END CERTIFICATE-----\n";
 
 static const char kIntermediatePEM[] =
-"-----BEGIN CERTIFICATE-----\n"
-"MIICXjCCAcegAwIBAgIJAKJMH+7rscPcMA0GCSqGSIb3DQEBCwUAMC4xGjAYBgNV\n"
-"BAoTEUJvcmluZ1NTTCBURVNUSU5HMRAwDgYDVQQDEwdSb290IENBMCAXDTE1MDEw\n"
-"MTAwMDAwMFoYDzIxMDAwMTAxMDAwMDAwWjA2MRowGAYDVQQKExFCb3JpbmdTU0wg\n"
-"VEVTVElORzEYMBYGA1UEAxMPSW50ZXJtZWRpYXRlIENBMIGfMA0GCSqGSIb3DQEB\n"
-"AQUAA4GNADCBiQKBgQC7YtI0l8ocTYJ0gKyXTtPL4iMJCNY4OcxXl48jkncVG1Hl\n"
-"blicgNUa1r9m9YFtVkxvBinb8dXiUpEGhVg4awRPDcatlsBSEBuJkiZGYbRcAmSu\n"
-"CmZYnf6u3aYQ18SU8WqVERPpE4cwVVs+6kwlzRw0+XDoZAczu8ZezVhCUc6NbQID\n"
-"AQABo3oweDAOBgNVHQ8BAf8EBAMCAgQwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsG\n"
-"AQUFBwMCMA8GA1UdEwEB/wQFMAMBAf8wGQYDVR0OBBIEEIwaaKi1dttdV3sfjRSy\n"
-"BqMwGwYDVR0jBBQwEoAQQDfXAftAL7gcflQEJ4xZATANBgkqhkiG9w0BAQsFAAOB\n"
-"gQCvnolNWEHuQS8PFVVyuLR+FKBeUUdrVbSfHSzTqNAqQGp0C9fk5oCzDq6ZgTfY\n"
-"ESXM4cJhb3IAnW0UM0NFsYSKQJ50JZL2L3z5ZLQhHdbs4RmODGoC40BVdnJ4/qgB\n"
-"aGSh09eQRvAVmbVCviDK2ipkWNegdyI19jFfNP5uIkGlYg==\n"
-"-----END CERTIFICATE-----\n";
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIICXjCCAcegAwIBAgIJAKJMH+7rscPcMA0GCSqGSIb3DQEBCwUAMC4xGjAYBgNV\n"
+    "BAoTEUJvcmluZ1NTTCBURVNUSU5HMRAwDgYDVQQDEwdSb290IENBMCAXDTE1MDEw\n"
+    "MTAwMDAwMFoYDzIxMDAwMTAxMDAwMDAwWjA2MRowGAYDVQQKExFCb3JpbmdTU0wg\n"
+    "VEVTVElORzEYMBYGA1UEAxMPSW50ZXJtZWRpYXRlIENBMIGfMA0GCSqGSIb3DQEB\n"
+    "AQUAA4GNADCBiQKBgQC7YtI0l8ocTYJ0gKyXTtPL4iMJCNY4OcxXl48jkncVG1Hl\n"
+    "blicgNUa1r9m9YFtVkxvBinb8dXiUpEGhVg4awRPDcatlsBSEBuJkiZGYbRcAmSu\n"
+    "CmZYnf6u3aYQ18SU8WqVERPpE4cwVVs+6kwlzRw0+XDoZAczu8ZezVhCUc6NbQID\n"
+    "AQABo3oweDAOBgNVHQ8BAf8EBAMCAgQwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsG\n"
+    "AQUFBwMCMA8GA1UdEwEB/wQFMAMBAf8wGQYDVR0OBBIEEIwaaKi1dttdV3sfjRSy\n"
+    "BqMwGwYDVR0jBBQwEoAQQDfXAftAL7gcflQEJ4xZATANBgkqhkiG9w0BAQsFAAOB\n"
+    "gQCvnolNWEHuQS8PFVVyuLR+FKBeUUdrVbSfHSzTqNAqQGp0C9fk5oCzDq6ZgTfY\n"
+    "ESXM4cJhb3IAnW0UM0NFsYSKQJ50JZL2L3z5ZLQhHdbs4RmODGoC40BVdnJ4/qgB\n"
+    "aGSh09eQRvAVmbVCviDK2ipkWNegdyI19jFfNP5uIkGlYg==\n"
+    "-----END CERTIFICATE-----\n";
 
 static const char kIntermediateSelfSignedPEM[] =
-"-----BEGIN CERTIFICATE-----\n"
-"MIICZjCCAc+gAwIBAgIJAKJMH+7rscPcMA0GCSqGSIb3DQEBCwUAMDYxGjAYBgNV\n"
-"BAoTEUJvcmluZ1NTTCBURVNUSU5HMRgwFgYDVQQDEw9JbnRlcm1lZGlhdGUgQ0Ew\n"
-"IBcNMTUwMTAxMDAwMDAwWhgPMjEwMDAxMDEwMDAwMDBaMDYxGjAYBgNVBAoTEUJv\n"
-"cmluZ1NTTCBURVNUSU5HMRgwFgYDVQQDEw9JbnRlcm1lZGlhdGUgQ0EwgZ8wDQYJ\n"
-"KoZIhvcNAQEBBQADgY0AMIGJAoGBALti0jSXyhxNgnSArJdO08viIwkI1jg5zFeX\n"
-"jyOSdxUbUeVuWJyA1RrWv2b1gW1WTG8GKdvx1eJSkQaFWDhrBE8Nxq2WwFIQG4mS\n"
-"JkZhtFwCZK4KZlid/q7dphDXxJTxapURE+kThzBVWz7qTCXNHDT5cOhkBzO7xl7N\n"
-"WEJRzo1tAgMBAAGjejB4MA4GA1UdDwEB/wQEAwICBDAdBgNVHSUEFjAUBggrBgEF\n"
-"BQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAZBgNVHQ4EEgQQjBpoqLV2\n"
-"211Xex+NFLIGozAbBgNVHSMEFDASgBCMGmiotXbbXVd7H40UsgajMA0GCSqGSIb3\n"
-"DQEBCwUAA4GBALcccSrAQ0/EqQBsx0ZDTUydHXXNP2DrUkpUKmAXIe8McqIVSlkT\n"
-"6H4xz7z8VRKBo9j+drjjtCw2i0CQc8aOLxRb5WJ8eVLnaW2XRlUqAzhF0CrulfVI\n"
-"E4Vs6ZLU+fra1WAuIj6qFiigRja+3YkZArG8tMA9vtlhTX/g7YBZIkqH\n"
-"-----END CERTIFICATE-----\n";
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIICZjCCAc+gAwIBAgIJAKJMH+7rscPcMA0GCSqGSIb3DQEBCwUAMDYxGjAYBgNV\n"
+    "BAoTEUJvcmluZ1NTTCBURVNUSU5HMRgwFgYDVQQDEw9JbnRlcm1lZGlhdGUgQ0Ew\n"
+    "IBcNMTUwMTAxMDAwMDAwWhgPMjEwMDAxMDEwMDAwMDBaMDYxGjAYBgNVBAoTEUJv\n"
+    "cmluZ1NTTCBURVNUSU5HMRgwFgYDVQQDEw9JbnRlcm1lZGlhdGUgQ0EwgZ8wDQYJ\n"
+    "KoZIhvcNAQEBBQADgY0AMIGJAoGBALti0jSXyhxNgnSArJdO08viIwkI1jg5zFeX\n"
+    "jyOSdxUbUeVuWJyA1RrWv2b1gW1WTG8GKdvx1eJSkQaFWDhrBE8Nxq2WwFIQG4mS\n"
+    "JkZhtFwCZK4KZlid/q7dphDXxJTxapURE+kThzBVWz7qTCXNHDT5cOhkBzO7xl7N\n"
+    "WEJRzo1tAgMBAAGjejB4MA4GA1UdDwEB/wQEAwICBDAdBgNVHSUEFjAUBggrBgEF\n"
+    "BQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAZBgNVHQ4EEgQQjBpoqLV2\n"
+    "211Xex+NFLIGozAbBgNVHSMEFDASgBCMGmiotXbbXVd7H40UsgajMA0GCSqGSIb3\n"
+    "DQEBCwUAA4GBALcccSrAQ0/EqQBsx0ZDTUydHXXNP2DrUkpUKmAXIe8McqIVSlkT\n"
+    "6H4xz7z8VRKBo9j+drjjtCw2i0CQc8aOLxRb5WJ8eVLnaW2XRlUqAzhF0CrulfVI\n"
+    "E4Vs6ZLU+fra1WAuIj6qFiigRja+3YkZArG8tMA9vtlhTX/g7YBZIkqH\n"
+    "-----END CERTIFICATE-----\n";
 
 static const char kLeafPEM[] =
-"-----BEGIN CERTIFICATE-----\n"
-"MIICXjCCAcegAwIBAgIIWjO48ufpunYwDQYJKoZIhvcNAQELBQAwNjEaMBgGA1UE\n"
-"ChMRQm9yaW5nU1NMIFRFU1RJTkcxGDAWBgNVBAMTD0ludGVybWVkaWF0ZSBDQTAg\n"
-"Fw0xNTAxMDEwMDAwMDBaGA8yMTAwMDEwMTAwMDAwMFowMjEaMBgGA1UEChMRQm9y\n"
-"aW5nU1NMIFRFU1RJTkcxFDASBgNVBAMTC2V4YW1wbGUuY29tMIGfMA0GCSqGSIb3\n"
-"DQEBAQUAA4GNADCBiQKBgQDD0U0ZYgqShJ7oOjsyNKyVXEHqeafmk/bAoPqY/h1c\n"
-"oPw2E8KmeqiUSoTPjG5IXSblOxcqpbAXgnjPzo8DI3GNMhAf8SYNYsoH7gc7Uy7j\n"
-"5x8bUrisGnuTHqkqH6d4/e7ETJ7i3CpR8bvK16DggEvQTudLipz8FBHtYhFakfdh\n"
-"TwIDAQABo3cwdTAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEG\n"
-"CCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwGQYDVR0OBBIEEKN5pvbur7mlXjeMEYA0\n"
-"4nUwGwYDVR0jBBQwEoAQjBpoqLV2211Xex+NFLIGozANBgkqhkiG9w0BAQsFAAOB\n"
-"gQBj/p+JChp//LnXWC1k121LM/ii7hFzQzMrt70bny406SGz9jAjaPOX4S3gt38y\n"
-"rhjpPukBlSzgQXFg66y6q5qp1nQTD1Cw6NkKBe9WuBlY3iYfmsf7WT8nhlT1CttU\n"
-"xNCwyMX9mtdXdQicOfNjIGUCD5OLV5PgHFPRKiHHioBAhg==\n"
-"-----END CERTIFICATE-----\n";
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIICXjCCAcegAwIBAgIIWjO48ufpunYwDQYJKoZIhvcNAQELBQAwNjEaMBgGA1UE\n"
+    "ChMRQm9yaW5nU1NMIFRFU1RJTkcxGDAWBgNVBAMTD0ludGVybWVkaWF0ZSBDQTAg\n"
+    "Fw0xNTAxMDEwMDAwMDBaGA8yMTAwMDEwMTAwMDAwMFowMjEaMBgGA1UEChMRQm9y\n"
+    "aW5nU1NMIFRFU1RJTkcxFDASBgNVBAMTC2V4YW1wbGUuY29tMIGfMA0GCSqGSIb3\n"
+    "DQEBAQUAA4GNADCBiQKBgQDD0U0ZYgqShJ7oOjsyNKyVXEHqeafmk/bAoPqY/h1c\n"
+    "oPw2E8KmeqiUSoTPjG5IXSblOxcqpbAXgnjPzo8DI3GNMhAf8SYNYsoH7gc7Uy7j\n"
+    "5x8bUrisGnuTHqkqH6d4/e7ETJ7i3CpR8bvK16DggEvQTudLipz8FBHtYhFakfdh\n"
+    "TwIDAQABo3cwdTAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEG\n"
+    "CCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwGQYDVR0OBBIEEKN5pvbur7mlXjeMEYA0\n"
+    "4nUwGwYDVR0jBBQwEoAQjBpoqLV2211Xex+NFLIGozANBgkqhkiG9w0BAQsFAAOB\n"
+    "gQBj/p+JChp//LnXWC1k121LM/ii7hFzQzMrt70bny406SGz9jAjaPOX4S3gt38y\n"
+    "rhjpPukBlSzgQXFg66y6q5qp1nQTD1Cw6NkKBe9WuBlY3iYfmsf7WT8nhlT1CttU\n"
+    "xNCwyMX9mtdXdQicOfNjIGUCD5OLV5PgHFPRKiHHioBAhg==\n"
+    "-----END CERTIFICATE-----\n";
 
 static const char kLeafNoKeyUsagePEM[] =
-"-----BEGIN CERTIFICATE-----\n"
-"MIICNTCCAZ6gAwIBAgIJAIFQGaLQ0G2mMA0GCSqGSIb3DQEBCwUAMDYxGjAYBgNV\n"
-"BAoTEUJvcmluZ1NTTCBURVNUSU5HMRgwFgYDVQQDEw9JbnRlcm1lZGlhdGUgQ0Ew\n"
-"IBcNMTUwMTAxMDAwMDAwWhgPMjEwMDAxMDEwMDAwMDBaMDcxGjAYBgNVBAoTEUJv\n"
-"cmluZ1NTTCBURVNUSU5HMRkwFwYDVQQDExBldmlsLmV4YW1wbGUuY29tMIGfMA0G\n"
-"CSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOKoZe75NPz77EOaMMl4/0s3PyQw++zJvp\n"
-"ejHAxZiTPCJgMbEHLrSzNoHdopg+CLUH5bE4wTXM8w9Inv5P8OAFJt7gJuPUunmk\n"
-"j+NoU3QfzOR6BroePcz1vXX9jyVHRs087M/sLqWRHu9IR+/A+UTcBaWaFiDVUxtJ\n"
-"YOwFMwjNPQIDAQABo0gwRjAMBgNVHRMBAf8EAjAAMBkGA1UdDgQSBBBJfLEUWHq1\n"
-"27rZ1AVx2J5GMBsGA1UdIwQUMBKAEIwaaKi1dttdV3sfjRSyBqMwDQYJKoZIhvcN\n"
-"AQELBQADgYEALVKN2Y3LZJOtu6SxFIYKxbLaXhTGTdIjxipZhmbBRDFjbZjZZOTe\n"
-"6Oo+VDNPYco4rBexK7umYXJyfTqoY0E8dbiImhTcGTEj7OAB3DbBomgU1AYe+t2D\n"
-"uwBqh4Y3Eto+Zn4pMVsxGEfUpjzjZDel7bN1/oU/9KWPpDfywfUmjgk=\n"
-"-----END CERTIFICATE-----\n";
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIICNTCCAZ6gAwIBAgIJAIFQGaLQ0G2mMA0GCSqGSIb3DQEBCwUAMDYxGjAYBgNV\n"
+    "BAoTEUJvcmluZ1NTTCBURVNUSU5HMRgwFgYDVQQDEw9JbnRlcm1lZGlhdGUgQ0Ew\n"
+    "IBcNMTUwMTAxMDAwMDAwWhgPMjEwMDAxMDEwMDAwMDBaMDcxGjAYBgNVBAoTEUJv\n"
+    "cmluZ1NTTCBURVNUSU5HMRkwFwYDVQQDExBldmlsLmV4YW1wbGUuY29tMIGfMA0G\n"
+    "CSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOKoZe75NPz77EOaMMl4/0s3PyQw++zJvp\n"
+    "ejHAxZiTPCJgMbEHLrSzNoHdopg+CLUH5bE4wTXM8w9Inv5P8OAFJt7gJuPUunmk\n"
+    "j+NoU3QfzOR6BroePcz1vXX9jyVHRs087M/sLqWRHu9IR+/A+UTcBaWaFiDVUxtJ\n"
+    "YOwFMwjNPQIDAQABo0gwRjAMBgNVHRMBAf8EAjAAMBkGA1UdDgQSBBBJfLEUWHq1\n"
+    "27rZ1AVx2J5GMBsGA1UdIwQUMBKAEIwaaKi1dttdV3sfjRSyBqMwDQYJKoZIhvcN\n"
+    "AQELBQADgYEALVKN2Y3LZJOtu6SxFIYKxbLaXhTGTdIjxipZhmbBRDFjbZjZZOTe\n"
+    "6Oo+VDNPYco4rBexK7umYXJyfTqoY0E8dbiImhTcGTEj7OAB3DbBomgU1AYe+t2D\n"
+    "uwBqh4Y3Eto+Zn4pMVsxGEfUpjzjZDel7bN1/oU/9KWPpDfywfUmjgk=\n"
+    "-----END CERTIFICATE-----\n";
 
 static const char kForgeryPEM[] =
-"-----BEGIN CERTIFICATE-----\n"
-"MIICZzCCAdCgAwIBAgIIdTlMzQoKkeMwDQYJKoZIhvcNAQELBQAwNzEaMBgGA1UE\n"
-"ChMRQm9yaW5nU1NMIFRFU1RJTkcxGTAXBgNVBAMTEGV2aWwuZXhhbXBsZS5jb20w\n"
-"IBcNMTUwMTAxMDAwMDAwWhgPMjEwMDAxMDEwMDAwMDBaMDoxGjAYBgNVBAoTEUJv\n"
-"cmluZ1NTTCBURVNUSU5HMRwwGgYDVQQDExNmb3JnZXJ5LmV4YW1wbGUuY29tMIGf\n"
-"MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDADTwruBQZGb7Ay6s9HiYv5d1lwtEy\n"
-"xQdA2Sy8Rn8uA20Q4KgqwVY7wzIZ+z5Butrsmwb70gdG1XU+yRaDeE7XVoW6jSpm\n"
-"0sw35/5vJbTcL4THEFbnX0OPZnvpuZDFUkvVtq5kxpDWsVyM24G8EEq7kPih3Sa3\n"
-"OMhXVXF8kso6UQIDAQABo3cwdTAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYI\n"
-"KwYBBQUHAwEGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwGQYDVR0OBBIEEEYJ/WHM\n"
-"8p64erPWIg4/liwwGwYDVR0jBBQwEoAQSXyxFFh6tdu62dQFcdieRjANBgkqhkiG\n"
-"9w0BAQsFAAOBgQA+zH7bHPElWRWJvjxDqRexmYLn+D3Aivs8XgXQJsM94W0EzSUf\n"
-"DSLfRgaQwcb2gg2xpDFoG+W0vc6O651uF23WGt5JaFFJJxqjII05IexfCNhuPmp4\n"
-"4UZAXPttuJXpn74IY1tuouaM06B3vXKZR+/ityKmfJvSwxacmFcK+2ziAg==\n"
-"-----END CERTIFICATE-----\n";
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIICZzCCAdCgAwIBAgIIdTlMzQoKkeMwDQYJKoZIhvcNAQELBQAwNzEaMBgGA1UE\n"
+    "ChMRQm9yaW5nU1NMIFRFU1RJTkcxGTAXBgNVBAMTEGV2aWwuZXhhbXBsZS5jb20w\n"
+    "IBcNMTUwMTAxMDAwMDAwWhgPMjEwMDAxMDEwMDAwMDBaMDoxGjAYBgNVBAoTEUJv\n"
+    "cmluZ1NTTCBURVNUSU5HMRwwGgYDVQQDExNmb3JnZXJ5LmV4YW1wbGUuY29tMIGf\n"
+    "MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDADTwruBQZGb7Ay6s9HiYv5d1lwtEy\n"
+    "xQdA2Sy8Rn8uA20Q4KgqwVY7wzIZ+z5Butrsmwb70gdG1XU+yRaDeE7XVoW6jSpm\n"
+    "0sw35/5vJbTcL4THEFbnX0OPZnvpuZDFUkvVtq5kxpDWsVyM24G8EEq7kPih3Sa3\n"
+    "OMhXVXF8kso6UQIDAQABo3cwdTAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYI\n"
+    "KwYBBQUHAwEGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwGQYDVR0OBBIEEEYJ/WHM\n"
+    "8p64erPWIg4/liwwGwYDVR0jBBQwEoAQSXyxFFh6tdu62dQFcdieRjANBgkqhkiG\n"
+    "9w0BAQsFAAOBgQA+zH7bHPElWRWJvjxDqRexmYLn+D3Aivs8XgXQJsM94W0EzSUf\n"
+    "DSLfRgaQwcb2gg2xpDFoG+W0vc6O651uF23WGt5JaFFJJxqjII05IexfCNhuPmp4\n"
+    "4UZAXPttuJXpn74IY1tuouaM06B3vXKZR+/ityKmfJvSwxacmFcK+2ziAg==\n"
+    "-----END CERTIFICATE-----\n";
 
 // kExamplePSSCert is an example RSA-PSS self-signed certificate, signed with
 // the default hash functions.
 static const char kExamplePSSCert[] =
-"-----BEGIN CERTIFICATE-----\n"
-"MIICYjCCAcagAwIBAgIJAI3qUyT6SIfzMBIGCSqGSIb3DQEBCjAFogMCAWowRTEL\n"
-"MAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVy\n"
-"bmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0xNDEwMDkxOTA5NTVaFw0xNTEwMDkxOTA5\n"
-"NTVaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQK\n"
-"DBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwgZ8wDQYJKoZIhvcNAQEBBQADgY0A\n"
-"MIGJAoGBAPi4bIO0vNmoV8CltFl2jFQdeesiUgR+0zfrQf2D+fCmhRU0dXFahKg8\n"
-"0u9aTtPel4rd/7vPCqqGkr64UOTNb4AzMHYTj8p73OxaymPHAyXvqIqDWHYg+hZ3\n"
-"13mSYwFIGth7Z/FSVUlO1m5KXNd6NzYM3t2PROjCpywrta9kS2EHAgMBAAGjUDBO\n"
-"MB0GA1UdDgQWBBTQQfuJQR6nrVrsNF1JEflVgXgfEzAfBgNVHSMEGDAWgBTQQfuJ\n"
-"QR6nrVrsNF1JEflVgXgfEzAMBgNVHRMEBTADAQH/MBIGCSqGSIb3DQEBCjAFogMC\n"
-"AWoDgYEASUy2RZcgNbNQZA0/7F+V1YTLEXwD16bm+iSVnzGwtexmQVEYIZG74K/w\n"
-"xbdZQdTbpNJkp1QPjPfh0zsatw6dmt5QoZ8K8No0DjR9dgf+Wvv5WJvJUIQBoAVN\n"
-"Z0IL+OQFz6+LcTHxD27JJCebrATXZA0wThGTQDm7crL+a+SujBY=\n"
-"-----END CERTIFICATE-----\n";
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIICYjCCAcagAwIBAgIJAI3qUyT6SIfzMBIGCSqGSIb3DQEBCjAFogMCAWowRTEL\n"
+    "MAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVy\n"
+    "bmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0xNDEwMDkxOTA5NTVaFw0xNTEwMDkxOTA5\n"
+    "NTVaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQK\n"
+    "DBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwgZ8wDQYJKoZIhvcNAQEBBQADgY0A\n"
+    "MIGJAoGBAPi4bIO0vNmoV8CltFl2jFQdeesiUgR+0zfrQf2D+fCmhRU0dXFahKg8\n"
+    "0u9aTtPel4rd/7vPCqqGkr64UOTNb4AzMHYTj8p73OxaymPHAyXvqIqDWHYg+hZ3\n"
+    "13mSYwFIGth7Z/FSVUlO1m5KXNd6NzYM3t2PROjCpywrta9kS2EHAgMBAAGjUDBO\n"
+    "MB0GA1UdDgQWBBTQQfuJQR6nrVrsNF1JEflVgXgfEzAfBgNVHSMEGDAWgBTQQfuJ\n"
+    "QR6nrVrsNF1JEflVgXgfEzAMBgNVHRMEBTADAQH/MBIGCSqGSIb3DQEBCjAFogMC\n"
+    "AWoDgYEASUy2RZcgNbNQZA0/7F+V1YTLEXwD16bm+iSVnzGwtexmQVEYIZG74K/w\n"
+    "xbdZQdTbpNJkp1QPjPfh0zsatw6dmt5QoZ8K8No0DjR9dgf+Wvv5WJvJUIQBoAVN\n"
+    "Z0IL+OQFz6+LcTHxD27JJCebrATXZA0wThGTQDm7crL+a+SujBY=\n"
+    "-----END CERTIFICATE-----\n";
 
 // kBadPSSCertPEM is a self-signed RSA-PSS certificate with bad parameters.
 static const char kBadPSSCertPEM[] =
-"-----BEGIN CERTIFICATE-----\n"
-"MIIDdjCCAjqgAwIBAgIJANcwZLyfEv7DMD4GCSqGSIb3DQEBCjAxoA0wCwYJYIZI\n"
-"AWUDBAIBoRowGAYJKoZIhvcNAQEIMAsGCWCGSAFlAwQCAaIEAgIA3jAnMSUwIwYD\n"
-"VQQDDBxUZXN0IEludmFsaWQgUFNTIGNlcnRpZmljYXRlMB4XDTE1MTEwNDE2MDIz\n"
-"NVoXDTE1MTIwNDE2MDIzNVowJzElMCMGA1UEAwwcVGVzdCBJbnZhbGlkIFBTUyBj\n"
-"ZXJ0aWZpY2F0ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMTaM7WH\n"
-"qVCAGAIA+zL1KWvvASTrhlq+1ePdO7wsrWX2KiYoTYrJYTnxhLnn0wrHqApt79nL\n"
-"IBG7cfShyZqFHOY/IzlYPMVt+gPo293gw96Fds5JBsjhjkyGnOyr9OUntFqvxDbT\n"
-"IIFU7o9IdxD4edaqjRv+fegVE+B79pDk4s0ujsk6dULtCg9Rst0ucGFo19mr+b7k\n"
-"dbfn8pZ72ZNDJPueVdrUAWw9oll61UcYfk75XdrLk6JlL41GrYHc8KlfXf43gGQq\n"
-"QfrpHkg4Ih2cI6Wt2nhFGAzrlcorzLliQIUJRIhM8h4IgDfpBpaPdVQLqS2pFbXa\n"
-"5eQjqiyJwak2vJ8CAwEAAaNQME4wHQYDVR0OBBYEFCt180N4oGUt5LbzBwQ4Ia+2\n"
-"4V97MB8GA1UdIwQYMBaAFCt180N4oGUt5LbzBwQ4Ia+24V97MAwGA1UdEwQFMAMB\n"
-"Af8wMQYJKoZIhvcNAQEKMCSgDTALBglghkgBZQMEAgGhDTALBgkqhkiG9w0BAQii\n"
-"BAICAN4DggEBAAjBtm90lGxgddjc4Xu/nbXXFHVs2zVcHv/mqOZoQkGB9r/BVgLb\n"
-"xhHrFZ2pHGElbUYPfifdS9ztB73e1d4J+P29o0yBqfd4/wGAc/JA8qgn6AAEO/Xn\n"
-"plhFeTRJQtLZVl75CkHXgUGUd3h+ADvKtcBuW9dSUncaUrgNKR8u/h/2sMG38RWY\n"
-"DzBddC/66YTa3r7KkVUfW7yqRQfELiGKdcm+bjlTEMsvS+EhHup9CzbpoCx2Fx9p\n"
-"NPtFY3yEObQhmL1JyoCRWqBE75GzFPbRaiux5UpEkns+i3trkGssZzsOuVqHNTNZ\n"
-"lC9+9hPHIoc9UMmAQNo1vGIW3NWVoeGbaJ8=\n"
-"-----END CERTIFICATE-----\n";
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIIDdjCCAjqgAwIBAgIJANcwZLyfEv7DMD4GCSqGSIb3DQEBCjAxoA0wCwYJYIZI\n"
+    "AWUDBAIBoRowGAYJKoZIhvcNAQEIMAsGCWCGSAFlAwQCAaIEAgIA3jAnMSUwIwYD\n"
+    "VQQDDBxUZXN0IEludmFsaWQgUFNTIGNlcnRpZmljYXRlMB4XDTE1MTEwNDE2MDIz\n"
+    "NVoXDTE1MTIwNDE2MDIzNVowJzElMCMGA1UEAwwcVGVzdCBJbnZhbGlkIFBTUyBj\n"
+    "ZXJ0aWZpY2F0ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMTaM7WH\n"
+    "qVCAGAIA+zL1KWvvASTrhlq+1ePdO7wsrWX2KiYoTYrJYTnxhLnn0wrHqApt79nL\n"
+    "IBG7cfShyZqFHOY/IzlYPMVt+gPo293gw96Fds5JBsjhjkyGnOyr9OUntFqvxDbT\n"
+    "IIFU7o9IdxD4edaqjRv+fegVE+B79pDk4s0ujsk6dULtCg9Rst0ucGFo19mr+b7k\n"
+    "dbfn8pZ72ZNDJPueVdrUAWw9oll61UcYfk75XdrLk6JlL41GrYHc8KlfXf43gGQq\n"
+    "QfrpHkg4Ih2cI6Wt2nhFGAzrlcorzLliQIUJRIhM8h4IgDfpBpaPdVQLqS2pFbXa\n"
+    "5eQjqiyJwak2vJ8CAwEAAaNQME4wHQYDVR0OBBYEFCt180N4oGUt5LbzBwQ4Ia+2\n"
+    "4V97MB8GA1UdIwQYMBaAFCt180N4oGUt5LbzBwQ4Ia+24V97MAwGA1UdEwQFMAMB\n"
+    "Af8wMQYJKoZIhvcNAQEKMCSgDTALBglghkgBZQMEAgGhDTALBgkqhkiG9w0BAQii\n"
+    "BAICAN4DggEBAAjBtm90lGxgddjc4Xu/nbXXFHVs2zVcHv/mqOZoQkGB9r/BVgLb\n"
+    "xhHrFZ2pHGElbUYPfifdS9ztB73e1d4J+P29o0yBqfd4/wGAc/JA8qgn6AAEO/Xn\n"
+    "plhFeTRJQtLZVl75CkHXgUGUd3h+ADvKtcBuW9dSUncaUrgNKR8u/h/2sMG38RWY\n"
+    "DzBddC/66YTa3r7KkVUfW7yqRQfELiGKdcm+bjlTEMsvS+EhHup9CzbpoCx2Fx9p\n"
+    "NPtFY3yEObQhmL1JyoCRWqBE75GzFPbRaiux5UpEkns+i3trkGssZzsOuVqHNTNZ\n"
+    "lC9+9hPHIoc9UMmAQNo1vGIW3NWVoeGbaJ8=\n"
+    "-----END CERTIFICATE-----\n";
 
 static const char kRSAKey[] =
-"-----BEGIN RSA PRIVATE KEY-----\n"
-"MIICXgIBAAKBgQDYK8imMuRi/03z0K1Zi0WnvfFHvwlYeyK9Na6XJYaUoIDAtB92\n"
-"kWdGMdAQhLciHnAjkXLI6W15OoV3gA/ElRZ1xUpxTMhjP6PyY5wqT5r6y8FxbiiF\n"
-"KKAnHmUcrgfVW28tQ+0rkLGMryRtrukXOgXBv7gcrmU7G1jC2a7WqmeI8QIDAQAB\n"
-"AoGBAIBy09Fd4DOq/Ijp8HeKuCMKTHqTW1xGHshLQ6jwVV2vWZIn9aIgmDsvkjCe\n"
-"i6ssZvnbjVcwzSoByhjN8ZCf/i15HECWDFFh6gt0P5z0MnChwzZmvatV/FXCT0j+\n"
-"WmGNB/gkehKjGXLLcjTb6dRYVJSCZhVuOLLcbWIV10gggJQBAkEA8S8sGe4ezyyZ\n"
-"m4e9r95g6s43kPqtj5rewTsUxt+2n4eVodD+ZUlCULWVNAFLkYRTBCASlSrm9Xhj\n"
-"QpmWAHJUkQJBAOVzQdFUaewLtdOJoPCtpYoY1zd22eae8TQEmpGOR11L6kbxLQsk\n"
-"aMly/DOnOaa82tqAGTdqDEZgSNmCeKKknmECQAvpnY8GUOVAubGR6c+W90iBuQLj\n"
-"LtFp/9ihd2w/PoDwrHZaoUYVcT4VSfJQog/k7kjE4MYXYWL8eEKg3WTWQNECQQDk\n"
-"104Wi91Umd1PzF0ijd2jXOERJU1wEKe6XLkYYNHWQAe5l4J4MWj9OdxFXAxIuuR/\n"
-"tfDwbqkta4xcux67//khAkEAvvRXLHTaa6VFzTaiiO8SaFsHV3lQyXOtMrBpB5jd\n"
-"moZWgjHvB2W9Ckn7sDqsPB+U2tyX0joDdQEyuiMECDY8oQ==\n"
-"-----END RSA PRIVATE KEY-----\n";
+    "-----BEGIN RSA PRIVATE KEY-----\n"
+    "MIICXgIBAAKBgQDYK8imMuRi/03z0K1Zi0WnvfFHvwlYeyK9Na6XJYaUoIDAtB92\n"
+    "kWdGMdAQhLciHnAjkXLI6W15OoV3gA/ElRZ1xUpxTMhjP6PyY5wqT5r6y8FxbiiF\n"
+    "KKAnHmUcrgfVW28tQ+0rkLGMryRtrukXOgXBv7gcrmU7G1jC2a7WqmeI8QIDAQAB\n"
+    "AoGBAIBy09Fd4DOq/Ijp8HeKuCMKTHqTW1xGHshLQ6jwVV2vWZIn9aIgmDsvkjCe\n"
+    "i6ssZvnbjVcwzSoByhjN8ZCf/i15HECWDFFh6gt0P5z0MnChwzZmvatV/FXCT0j+\n"
+    "WmGNB/gkehKjGXLLcjTb6dRYVJSCZhVuOLLcbWIV10gggJQBAkEA8S8sGe4ezyyZ\n"
+    "m4e9r95g6s43kPqtj5rewTsUxt+2n4eVodD+ZUlCULWVNAFLkYRTBCASlSrm9Xhj\n"
+    "QpmWAHJUkQJBAOVzQdFUaewLtdOJoPCtpYoY1zd22eae8TQEmpGOR11L6kbxLQsk\n"
+    "aMly/DOnOaa82tqAGTdqDEZgSNmCeKKknmECQAvpnY8GUOVAubGR6c+W90iBuQLj\n"
+    "LtFp/9ihd2w/PoDwrHZaoUYVcT4VSfJQog/k7kjE4MYXYWL8eEKg3WTWQNECQQDk\n"
+    "104Wi91Umd1PzF0ijd2jXOERJU1wEKe6XLkYYNHWQAe5l4J4MWj9OdxFXAxIuuR/\n"
+    "tfDwbqkta4xcux67//khAkEAvvRXLHTaa6VFzTaiiO8SaFsHV3lQyXOtMrBpB5jd\n"
+    "moZWgjHvB2W9Ckn7sDqsPB+U2tyX0joDdQEyuiMECDY8oQ==\n"
+    "-----END RSA PRIVATE KEY-----\n";
 
-
+// kCRLTestRoot is a test root certificate. It has private key:
+//
+//     -----BEGIN RSA PRIVATE KEY-----
+//     MIIEpAIBAAKCAQEAo16WiLWZuaymsD8n5SKPmxV1y6jjgr3BS/dUBpbrzd1aeFzN
+//     lI8l2jfAnzUyp+I21RQ+nh/MhqjGElkTtK9xMn1Y+S9GMRh+5R/Du0iCb1tCZIPY
+//     07Tgrb0KMNWe0v2QKVVruuYSgxIWodBfxlKO64Z8AJ5IbnWpuRqO6rctN9qUoMlT
+//     IAB6dL4G0tDJ/PGFWOJYwOMEIX54bly2wgyYJVBKiRRt4f7n8H922qmvPNA9idmX
+//     9G1VAtgV6x97XXi7ULORIQvn9lVQF6nTYDBJhyuPB+mLThbLP2o9orxGx7aCtnnB
+//     ZUIxUvHNOI0FaSaZH7Fi0xsZ/GkG2HZe7ImPJwIDAQABAoIBAQCJF9MTHfHGkk+/
+//     DwCXlA0Wg0e6hBuHl10iNobYkMWIl/xXjOknhYiqOqb181py76472SVC5ERprC+r
+//     Lf0PXzqKuA117mnkwT2bYLCL9Skf8WEhoFLQNbVlloF6wYjqXcYgKYKh8HgQbZl4
+//     aLg2YQl2NADTNABsUWj/4H2WEelsODVviqfFs725lFg9KHDI8zxAZXLzDt/M9uVL
+//     GxJiX12tr0AwaeAFZ1oPM/y+LznM3N3+Ht3jHHw3jZ/u8Z1RdAmdpu3bZ6tbwGBr
+//     9edsH5rKkm9aBvMrY7eX5VHqaqyRNFyG152ZOJh4XiiFG7EmgTPCpaHo50Y018Re
+//     grVtk+FBAoGBANY3lY+V8ZOwMxSHes+kTnoimHO5Ob7nxrOC71i27x+4HHsYUeAr
+//     /zOOghiDIn+oNkuiX5CIOWZKx159Bp65CPpCbTb/fh+HYnSgXFgCw7XptycO7LXM
+//     5GwR5jSfpfzBFdYxjxoUzDMFBwTEYRTm0HkUHkH+s+ajjw5wqqbcGLcfAoGBAMM8
+//     DKW6Tb66xsf708f0jonAjKYTLZ+WOcwsBEWSFHoY8dUjvW5gqx5acHTEsc5ZTeh4
+//     BCFLa+Mn9cuJWVJNs09k7Xb2PNl92HQ4GN2vbdkJhExbkT6oLDHg1hVD0w8KLfz1
+//     lTAW6pS+6CdOHMEJpvqx89EgU/1GgIQ1fXYczE75AoGAKeJoXdDFkUjsU+FBhAPu
+//     TDcjc80Nm2QaF9NMFR5/lsYa236f06MGnQAKM9zADBHJu/Qdl1brUjLg1HrBppsr
+//     RDNkw1IlSOjhuUf5hkPUHGd8Jijm440SRIcjabqla8wdBupdvo2+d2NOQgJbsQiI
+//     ToQ+fkzcxAXK3Nnuo/1436UCgYBjLH7UNOZHS8OsVM0I1r8NVKVdu4JCfeJQR8/H
+//     s2P5ffBir+wLRMnH+nMDreMQiibcPxMCArkERAlE4jlgaJ38Z62E76KLbLTmnJRt
+//     EC9Bv+bXjvAiHvWMRMUbOj/ddPNVez7Uld+FvdBaHwDWQlvzHzBWfBCOKSEhh7Z6
+//     qDhUqQKBgQDPMDx2i5rfmQp3imV9xUcCkIRsyYQVf8Eo7NV07IdUy/otmksgn4Zt
+//     Lbf3v2dvxOpTNTONWjp2c+iUQo8QxJCZr5Sfb21oQ9Ktcrmc/CY7LeBVDibXwxdM
+//     vRG8kBzvslFWh7REzC3u06GSVhyKDfW93kN2cKVwGoahRlhj7oHuZQ==
+//     -----END RSA PRIVATE KEY-----
 static const char kCRLTestRoot[] =
-"-----BEGIN CERTIFICATE-----\n"
-"MIIDbzCCAlegAwIBAgIJAODri7v0dDUFMA0GCSqGSIb3DQEBCwUAME4xCzAJBgNV\n"
-"BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBW\n"
-"aWV3MRIwEAYDVQQKDAlCb3JpbmdTU0wwHhcNMTYwOTI2MTUwNjI2WhcNMjYwOTI0\n"
-"MTUwNjI2WjBOMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQG\n"
-"A1UEBwwNTW91bnRhaW4gVmlldzESMBAGA1UECgwJQm9yaW5nU1NMMIIBIjANBgkq\n"
-"hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAo16WiLWZuaymsD8n5SKPmxV1y6jjgr3B\n"
-"S/dUBpbrzd1aeFzNlI8l2jfAnzUyp+I21RQ+nh/MhqjGElkTtK9xMn1Y+S9GMRh+\n"
-"5R/Du0iCb1tCZIPY07Tgrb0KMNWe0v2QKVVruuYSgxIWodBfxlKO64Z8AJ5IbnWp\n"
-"uRqO6rctN9qUoMlTIAB6dL4G0tDJ/PGFWOJYwOMEIX54bly2wgyYJVBKiRRt4f7n\n"
-"8H922qmvPNA9idmX9G1VAtgV6x97XXi7ULORIQvn9lVQF6nTYDBJhyuPB+mLThbL\n"
-"P2o9orxGx7aCtnnBZUIxUvHNOI0FaSaZH7Fi0xsZ/GkG2HZe7ImPJwIDAQABo1Aw\n"
-"TjAdBgNVHQ4EFgQUWPt3N5cZ/CRvubbrkqfBnAqhq94wHwYDVR0jBBgwFoAUWPt3\n"
-"N5cZ/CRvubbrkqfBnAqhq94wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC\n"
-"AQEAORu6M0MOwXy+3VEBwNilfTxyqDfruQsc1jA4PT8Oe8zora1WxE1JB4q2FJOz\n"
-"EAuM3H/NXvEnBuN+ITvKZAJUfm4NKX97qmjMJwLKWe1gVv+VQTr63aR7mgWJReQN\n"
-"XdMztlVeZs2dppV6uEg3ia1X0G7LARxGpA9ETbMyCpb39XxlYuTClcbA5ftDN99B\n"
-"3Xg9KNdd++Ew22O3HWRDvdDpTO/JkzQfzi3sYwUtzMEonENhczJhGf7bQMmvL/w5\n"
-"24Wxj4Z7KzzWIHsNqE/RIs6RV3fcW61j/mRgW2XyoWnMVeBzvcJr9NXp4VQYmFPw\n"
-"amd8GKMZQvP0ufGnUn7D7uartA==\n"
-"-----END CERTIFICATE-----\n";
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIIDbzCCAlegAwIBAgIJAODri7v0dDUFMA0GCSqGSIb3DQEBCwUAME4xCzAJBgNV\n"
+    "BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBW\n"
+    "aWV3MRIwEAYDVQQKDAlCb3JpbmdTU0wwHhcNMTYwOTI2MTUwNjI2WhcNMjYwOTI0\n"
+    "MTUwNjI2WjBOMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQG\n"
+    "A1UEBwwNTW91bnRhaW4gVmlldzESMBAGA1UECgwJQm9yaW5nU1NMMIIBIjANBgkq\n"
+    "hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAo16WiLWZuaymsD8n5SKPmxV1y6jjgr3B\n"
+    "S/dUBpbrzd1aeFzNlI8l2jfAnzUyp+I21RQ+nh/MhqjGElkTtK9xMn1Y+S9GMRh+\n"
+    "5R/Du0iCb1tCZIPY07Tgrb0KMNWe0v2QKVVruuYSgxIWodBfxlKO64Z8AJ5IbnWp\n"
+    "uRqO6rctN9qUoMlTIAB6dL4G0tDJ/PGFWOJYwOMEIX54bly2wgyYJVBKiRRt4f7n\n"
+    "8H922qmvPNA9idmX9G1VAtgV6x97XXi7ULORIQvn9lVQF6nTYDBJhyuPB+mLThbL\n"
+    "P2o9orxGx7aCtnnBZUIxUvHNOI0FaSaZH7Fi0xsZ/GkG2HZe7ImPJwIDAQABo1Aw\n"
+    "TjAdBgNVHQ4EFgQUWPt3N5cZ/CRvubbrkqfBnAqhq94wHwYDVR0jBBgwFoAUWPt3\n"
+    "N5cZ/CRvubbrkqfBnAqhq94wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC\n"
+    "AQEAORu6M0MOwXy+3VEBwNilfTxyqDfruQsc1jA4PT8Oe8zora1WxE1JB4q2FJOz\n"
+    "EAuM3H/NXvEnBuN+ITvKZAJUfm4NKX97qmjMJwLKWe1gVv+VQTr63aR7mgWJReQN\n"
+    "XdMztlVeZs2dppV6uEg3ia1X0G7LARxGpA9ETbMyCpb39XxlYuTClcbA5ftDN99B\n"
+    "3Xg9KNdd++Ew22O3HWRDvdDpTO/JkzQfzi3sYwUtzMEonENhczJhGf7bQMmvL/w5\n"
+    "24Wxj4Z7KzzWIHsNqE/RIs6RV3fcW61j/mRgW2XyoWnMVeBzvcJr9NXp4VQYmFPw\n"
+    "amd8GKMZQvP0ufGnUn7D7uartA==\n"
+    "-----END CERTIFICATE-----\n";
 
 static const char kCRLTestLeaf[] =
-"-----BEGIN CERTIFICATE-----\n"
-"MIIDkDCCAnigAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwTjELMAkGA1UEBhMCVVMx\n"
-"EzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxEjAQ\n"
-"BgNVBAoMCUJvcmluZ1NTTDAeFw0xNjA5MjYxNTA4MzFaFw0xNzA5MjYxNTA4MzFa\n"
-"MEsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQKDAlC\n"
-"b3JpbmdTU0wxEzARBgNVBAMMCmJvcmluZy5zc2wwggEiMA0GCSqGSIb3DQEBAQUA\n"
-"A4IBDwAwggEKAoIBAQDc5v1S1M0W+QWM+raWfO0LH8uvqEwuJQgODqMaGnSlWUx9\n"
-"8iQcnWfjyPja3lWg9K62hSOFDuSyEkysKHDxijz5R93CfLcfnVXjWQDJe7EJTTDP\n"
-"ozEvxN6RjAeYv7CF000euYr3QT5iyBjg76+bon1p0jHZBJeNPP1KqGYgyxp+hzpx\n"
-"e0gZmTlGAXd8JQK4v8kpdYwD6PPifFL/jpmQpqOtQmH/6zcLjY4ojmqpEdBqIKIX\n"
-"+saA29hMq0+NK3K+wgg31RU+cVWxu3tLOIiesETkeDgArjWRS1Vkzbi4v9SJxtNu\n"
-"OZuAxWiynRJw3JwH/OFHYZIvQqz68ZBoj96cepjPAgMBAAGjezB5MAkGA1UdEwQC\n"
-"MAAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRl\n"
-"MB0GA1UdDgQWBBTGn0OVVh/aoYt0bvEKG+PIERqnDzAfBgNVHSMEGDAWgBRY+3c3\n"
-"lxn8JG+5tuuSp8GcCqGr3jANBgkqhkiG9w0BAQsFAAOCAQEAd2nM8gCQN2Dc8QJw\n"
-"XSZXyuI3DBGGCHcay/3iXu0JvTC3EiQo8J6Djv7WLI0N5KH8mkm40u89fJAB2lLZ\n"
-"ShuHVtcC182bOKnePgwp9CNwQ21p0rDEu/P3X46ZvFgdxx82E9xLa0tBB8PiPDWh\n"
-"lV16jbaKTgX5AZqjnsyjR5o9/mbZVupZJXx5Syq+XA8qiJfstSYJs4KyKK9UOjql\n"
-"ICkJVKpi2ahDBqX4MOH4SLfzVk8pqSpviS6yaA1RXqjpkxiN45WWaXDldVHMSkhC\n"
-"5CNXsXi4b1nAntu89crwSLA3rEwzCWeYj+BX7e1T9rr3oJdwOU/2KQtW1js1yQUG\n"
-"tjJMFw==\n"
-"-----END CERTIFICATE-----\n";
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIIDkDCCAnigAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwTjELMAkGA1UEBhMCVVMx\n"
+    "EzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxEjAQ\n"
+    "BgNVBAoMCUJvcmluZ1NTTDAeFw0xNjA5MjYxNTA4MzFaFw0xNzA5MjYxNTA4MzFa\n"
+    "MEsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQKDAlC\n"
+    "b3JpbmdTU0wxEzARBgNVBAMMCmJvcmluZy5zc2wwggEiMA0GCSqGSIb3DQEBAQUA\n"
+    "A4IBDwAwggEKAoIBAQDc5v1S1M0W+QWM+raWfO0LH8uvqEwuJQgODqMaGnSlWUx9\n"
+    "8iQcnWfjyPja3lWg9K62hSOFDuSyEkysKHDxijz5R93CfLcfnVXjWQDJe7EJTTDP\n"
+    "ozEvxN6RjAeYv7CF000euYr3QT5iyBjg76+bon1p0jHZBJeNPP1KqGYgyxp+hzpx\n"
+    "e0gZmTlGAXd8JQK4v8kpdYwD6PPifFL/jpmQpqOtQmH/6zcLjY4ojmqpEdBqIKIX\n"
+    "+saA29hMq0+NK3K+wgg31RU+cVWxu3tLOIiesETkeDgArjWRS1Vkzbi4v9SJxtNu\n"
+    "OZuAxWiynRJw3JwH/OFHYZIvQqz68ZBoj96cepjPAgMBAAGjezB5MAkGA1UdEwQC\n"
+    "MAAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRl\n"
+    "MB0GA1UdDgQWBBTGn0OVVh/aoYt0bvEKG+PIERqnDzAfBgNVHSMEGDAWgBRY+3c3\n"
+    "lxn8JG+5tuuSp8GcCqGr3jANBgkqhkiG9w0BAQsFAAOCAQEAd2nM8gCQN2Dc8QJw\n"
+    "XSZXyuI3DBGGCHcay/3iXu0JvTC3EiQo8J6Djv7WLI0N5KH8mkm40u89fJAB2lLZ\n"
+    "ShuHVtcC182bOKnePgwp9CNwQ21p0rDEu/P3X46ZvFgdxx82E9xLa0tBB8PiPDWh\n"
+    "lV16jbaKTgX5AZqjnsyjR5o9/mbZVupZJXx5Syq+XA8qiJfstSYJs4KyKK9UOjql\n"
+    "ICkJVKpi2ahDBqX4MOH4SLfzVk8pqSpviS6yaA1RXqjpkxiN45WWaXDldVHMSkhC\n"
+    "5CNXsXi4b1nAntu89crwSLA3rEwzCWeYj+BX7e1T9rr3oJdwOU/2KQtW1js1yQUG\n"
+    "tjJMFw==\n"
+    "-----END CERTIFICATE-----\n";
 
 static const char kBasicCRL[] =
-"-----BEGIN X509 CRL-----\n"
-"MIIBpzCBkAIBATANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJVUzETMBEGA1UE\n"
-"CAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzESMBAGA1UECgwJ\n"
-"Qm9yaW5nU1NMFw0xNjA5MjYxNTEwNTVaFw0xNjEwMjYxNTEwNTVaoA4wDDAKBgNV\n"
-"HRQEAwIBATANBgkqhkiG9w0BAQsFAAOCAQEAnrBKKgvd9x9zwK9rtUvVeFeJ7+LN\n"
-"ZEAc+a5oxpPNEsJx6hXoApYEbzXMxuWBQoCs5iEBycSGudct21L+MVf27M38KrWo\n"
-"eOkq0a2siqViQZO2Fb/SUFR0k9zb8xl86Zf65lgPplALun0bV/HT7MJcl04Tc4os\n"
-"dsAReBs5nqTGNEd5AlC1iKHvQZkM//MD51DspKnDpsDiUVi54h9C1SpfZmX8H2Vv\n"
-"diyu0fZ/bPAM3VAGawatf/SyWfBMyKpoPXEG39oAzmjjOj8en82psn7m474IGaho\n"
-"/vBbhl1ms5qQiLYPjm4YELtnXQoFyC72tBjbdFd/ZE9k4CNKDbxFUXFbkw==\n"
-"-----END X509 CRL-----\n";
+    "-----BEGIN X509 CRL-----\n"
+    "MIIBpzCBkAIBATANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJVUzETMBEGA1UE\n"
+    "CAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzESMBAGA1UECgwJ\n"
+    "Qm9yaW5nU1NMFw0xNjA5MjYxNTEwNTVaFw0xNjEwMjYxNTEwNTVaoA4wDDAKBgNV\n"
+    "HRQEAwIBATANBgkqhkiG9w0BAQsFAAOCAQEAnrBKKgvd9x9zwK9rtUvVeFeJ7+LN\n"
+    "ZEAc+a5oxpPNEsJx6hXoApYEbzXMxuWBQoCs5iEBycSGudct21L+MVf27M38KrWo\n"
+    "eOkq0a2siqViQZO2Fb/SUFR0k9zb8xl86Zf65lgPplALun0bV/HT7MJcl04Tc4os\n"
+    "dsAReBs5nqTGNEd5AlC1iKHvQZkM//MD51DspKnDpsDiUVi54h9C1SpfZmX8H2Vv\n"
+    "diyu0fZ/bPAM3VAGawatf/SyWfBMyKpoPXEG39oAzmjjOj8en82psn7m474IGaho\n"
+    "/vBbhl1ms5qQiLYPjm4YELtnXQoFyC72tBjbdFd/ZE9k4CNKDbxFUXFbkw==\n"
+    "-----END X509 CRL-----\n";
 
 static const char kRevokedCRL[] =
-"-----BEGIN X509 CRL-----\n"
-"MIIBvjCBpwIBATANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJVUzETMBEGA1UE\n"
-"CAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzESMBAGA1UECgwJ\n"
-"Qm9yaW5nU1NMFw0xNjA5MjYxNTEyNDRaFw0xNjEwMjYxNTEyNDRaMBUwEwICEAAX\n"
-"DTE2MDkyNjE1MTIyNlqgDjAMMAoGA1UdFAQDAgECMA0GCSqGSIb3DQEBCwUAA4IB\n"
-"AQCUGaM4DcWzlQKrcZvI8TMeR8BpsvQeo5BoI/XZu2a8h//PyRyMwYeaOM+3zl0d\n"
-"sjgCT8b3C1FPgT+P2Lkowv7rJ+FHJRNQkogr+RuqCSPTq65ha4WKlRGWkMFybzVH\n"
-"NloxC+aU3lgp/NlX9yUtfqYmJek1CDrOOGPrAEAwj1l/BUeYKNGqfBWYJQtPJu+5\n"
-"OaSvIYGpETCZJscUWODmLEb/O3DM438vLvxonwGqXqS0KX37+CHpUlyhnSovxXxp\n"
-"Pz4aF+L7OtczxL0GYtD2fR9B7TDMqsNmHXgQrixvvOY7MUdLGbd4RfJL3yA53hyO\n"
-"xzfKY2TzxLiOmctG0hXFkH5J\n"
-"-----END X509 CRL-----\n";
+    "-----BEGIN X509 CRL-----\n"
+    "MIIBvjCBpwIBATANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJVUzETMBEGA1UE\n"
+    "CAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzESMBAGA1UECgwJ\n"
+    "Qm9yaW5nU1NMFw0xNjA5MjYxNTEyNDRaFw0xNjEwMjYxNTEyNDRaMBUwEwICEAAX\n"
+    "DTE2MDkyNjE1MTIyNlqgDjAMMAoGA1UdFAQDAgECMA0GCSqGSIb3DQEBCwUAA4IB\n"
+    "AQCUGaM4DcWzlQKrcZvI8TMeR8BpsvQeo5BoI/XZu2a8h//PyRyMwYeaOM+3zl0d\n"
+    "sjgCT8b3C1FPgT+P2Lkowv7rJ+FHJRNQkogr+RuqCSPTq65ha4WKlRGWkMFybzVH\n"
+    "NloxC+aU3lgp/NlX9yUtfqYmJek1CDrOOGPrAEAwj1l/BUeYKNGqfBWYJQtPJu+5\n"
+    "OaSvIYGpETCZJscUWODmLEb/O3DM438vLvxonwGqXqS0KX37+CHpUlyhnSovxXxp\n"
+    "Pz4aF+L7OtczxL0GYtD2fR9B7TDMqsNmHXgQrixvvOY7MUdLGbd4RfJL3yA53hyO\n"
+    "xzfKY2TzxLiOmctG0hXFkH5J\n"
+    "-----END X509 CRL-----\n";
 
 static const char kBadIssuerCRL[] =
-"-----BEGIN X509 CRL-----\n"
-"MIIBwjCBqwIBATANBgkqhkiG9w0BAQsFADBSMQswCQYDVQQGEwJVUzETMBEGA1UE\n"
-"CAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEWMBQGA1UECgwN\n"
-"Tm90IEJvcmluZ1NTTBcNMTYwOTI2MTUxMjQ0WhcNMTYxMDI2MTUxMjQ0WjAVMBMC\n"
-"AhAAFw0xNjA5MjYxNTEyMjZaoA4wDDAKBgNVHRQEAwIBAjANBgkqhkiG9w0BAQsF\n"
-"AAOCAQEAlBmjOA3Fs5UCq3GbyPEzHkfAabL0HqOQaCP12btmvIf/z8kcjMGHmjjP\n"
-"t85dHbI4Ak/G9wtRT4E/j9i5KML+6yfhRyUTUJKIK/kbqgkj06uuYWuFipURlpDB\n"
-"cm81RzZaMQvmlN5YKfzZV/clLX6mJiXpNQg6zjhj6wBAMI9ZfwVHmCjRqnwVmCUL\n"
-"TybvuTmkryGBqREwmSbHFFjg5ixG/ztwzON/Ly78aJ8Bql6ktCl9+/gh6VJcoZ0q\n"
-"L8V8aT8+Ghfi+zrXM8S9BmLQ9n0fQe0wzKrDZh14EK4sb7zmOzFHSxm3eEXyS98g\n"
-"Od4cjsc3ymNk88S4jpnLRtIVxZB+SQ==\n"
-"-----END X509 CRL-----\n";
+    "-----BEGIN X509 CRL-----\n"
+    "MIIBwjCBqwIBATANBgkqhkiG9w0BAQsFADBSMQswCQYDVQQGEwJVUzETMBEGA1UE\n"
+    "CAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEWMBQGA1UECgwN\n"
+    "Tm90IEJvcmluZ1NTTBcNMTYwOTI2MTUxMjQ0WhcNMTYxMDI2MTUxMjQ0WjAVMBMC\n"
+    "AhAAFw0xNjA5MjYxNTEyMjZaoA4wDDAKBgNVHRQEAwIBAjANBgkqhkiG9w0BAQsF\n"
+    "AAOCAQEAlBmjOA3Fs5UCq3GbyPEzHkfAabL0HqOQaCP12btmvIf/z8kcjMGHmjjP\n"
+    "t85dHbI4Ak/G9wtRT4E/j9i5KML+6yfhRyUTUJKIK/kbqgkj06uuYWuFipURlpDB\n"
+    "cm81RzZaMQvmlN5YKfzZV/clLX6mJiXpNQg6zjhj6wBAMI9ZfwVHmCjRqnwVmCUL\n"
+    "TybvuTmkryGBqREwmSbHFFjg5ixG/ztwzON/Ly78aJ8Bql6ktCl9+/gh6VJcoZ0q\n"
+    "L8V8aT8+Ghfi+zrXM8S9BmLQ9n0fQe0wzKrDZh14EK4sb7zmOzFHSxm3eEXyS98g\n"
+    "Od4cjsc3ymNk88S4jpnLRtIVxZB+SQ==\n"
+    "-----END X509 CRL-----\n";
+
+// kKnownCriticalCRL is kBasicCRL but with a critical issuing distribution point
+// extension.
+static const char kKnownCriticalCRL[] =
+    "-----BEGIN X509 CRL-----\n"
+    "MIIBujCBowIBATANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJVUzETMBEGA1UE\n"
+    "CAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzESMBAGA1UECgwJ\n"
+    "Qm9yaW5nU1NMFw0xNjA5MjYxNTEwNTVaFw0xNjEwMjYxNTEwNTVaoCEwHzAKBgNV\n"
+    "HRQEAwIBATARBgNVHRwBAf8EBzAFoQMBAf8wDQYJKoZIhvcNAQELBQADggEBAA+3\n"
+    "i+5e5Ub8sccfgOBs6WVJFI9c8gvJjrJ8/dYfFIAuCyeocs7DFXn1n13CRZ+URR/Q\n"
+    "mVWgU28+xeusuSPYFpd9cyYTcVyNUGNTI3lwgcE/yVjPaOmzSZKdPakApRxtpKKQ\n"
+    "NN/56aQz3bnT/ZSHQNciRB8U6jiD9V30t0w+FDTpGaG+7bzzUH3UVF9xf9Ctp60A\n"
+    "3mfLe0scas7owSt4AEFuj2SPvcE7yvdOXbu+IEv21cEJUVExJAbhvIweHXh6yRW+\n"
+    "7VVeiNzdIjkZjyTmAzoXGha4+wbxXyBRbfH+XWcO/H+8nwyG8Gktdu2QB9S9nnIp\n"
+    "o/1TpfOMSGhMyMoyPrk=\n"
+    "-----END X509 CRL-----\n";
+
+// kUnknownCriticalCRL is kBasicCRL but with an unknown critical extension.
+static const char kUnknownCriticalCRL[] =
+    "-----BEGIN X509 CRL-----\n"
+    "MIIBvDCBpQIBATANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJVUzETMBEGA1UE\n"
+    "CAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzESMBAGA1UECgwJ\n"
+    "Qm9yaW5nU1NMFw0xNjA5MjYxNTEwNTVaFw0xNjEwMjYxNTEwNTVaoCMwITAKBgNV\n"
+    "HRQEAwIBATATBgwqhkiG9xIEAYS3CQABAf8EADANBgkqhkiG9w0BAQsFAAOCAQEA\n"
+    "GvBP0xqL509InMj/3493YVRV+ldTpBv5uTD6jewzf5XdaxEQ/VjTNe5zKnxbpAib\n"
+    "Kf7cwX0PMSkZjx7k7kKdDlEucwVvDoqC+O9aJcqVmM6GDyNb9xENxd0XCXja6MZC\n"
+    "yVgP4AwLauB2vSiEprYJyI1APph3iAEeDm60lTXX/wBM/tupQDDujKh2GPyvBRfJ\n"
+    "+wEDwGg3ICwvu4gO4zeC5qnFR+bpL9t5tOMAQnVZ0NWv+k7mkd2LbHdD44dxrfXC\n"
+    "nhtfERx99SDmC/jtUAJrGhtCO8acr7exCeYcduN7KKCm91OeCJKK6OzWst0Og1DB\n"
+    "kwzzU2rL3G65CrZ7H0SZsQ==\n"
+    "-----END X509 CRL-----\n";
+
+// kUnknownCriticalCRL2 is kBasicCRL but with a critical issuing distribution
+// point extension followed by an unknown critical extension
+static const char kUnknownCriticalCRL2[] =
+    "-----BEGIN X509 CRL-----\n"
+    "MIIBzzCBuAIBATANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJVUzETMBEGA1UE\n"
+    "CAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzESMBAGA1UECgwJ\n"
+    "Qm9yaW5nU1NMFw0xNjA5MjYxNTEwNTVaFw0xNjEwMjYxNTEwNTVaoDYwNDAKBgNV\n"
+    "HRQEAwIBATARBgNVHRwBAf8EBzAFoQMBAf8wEwYMKoZIhvcSBAGEtwkAAQH/BAAw\n"
+    "DQYJKoZIhvcNAQELBQADggEBACTcpQC8jXL12JN5YzOcQ64ubQIe0XxRAd30p7qB\n"
+    "BTXGpgqBjrjxRfLms7EBYodEXB2oXMsDq3km0vT1MfYdsDD05S+SQ9CDsq/pUfaC\n"
+    "E2WNI5p8WircRnroYvbN2vkjlRbMd1+yNITohXYXCJwjEOAWOx3XIM10bwPYBv4R\n"
+    "rDobuLHoMgL3yHgMHmAkP7YpkBucNqeBV8cCdeAZLuhXFWi6yfr3r/X18yWbC/r2\n"
+    "2xXdkrSqXLFo7ToyP8YKTgiXpya4x6m53biEYwa2ULlas0igL6DK7wjYZX95Uy7H\n"
+    "GKljn9weIYiMPV/BzGymwfv2EW0preLwtyJNJPaxbdin6Jc=\n"
+    "-----END X509 CRL-----\n";
 
 // CertFromPEM parses the given, NUL-terminated pem block and returns an
 // |X509*|.
@@ -335,9 +412,10 @@
       PEM_read_bio_PrivateKey(bio.get(), nullptr, nullptr, nullptr));
 }
 
-// CertsToStack converts a vector of |X509*| to an OpenSSL STACK_OF(X509*),
+// CertsToStack converts a vector of |X509*| to an OpenSSL STACK_OF(X509),
 // bumping the reference counts for each certificate in question.
-static STACK_OF(X509)* CertsToStack(const std::vector<X509*> &certs) {
+static bssl::UniquePtr<STACK_OF(X509)> CertsToStack(
+    const std::vector<X509 *> &certs) {
   bssl::UniquePtr<STACK_OF(X509)> stack(sk_X509_new_null());
   if (!stack) {
     return nullptr;
@@ -349,12 +427,13 @@
     X509_up_ref(cert);
   }
 
-  return stack.release();
+  return stack;
 }
 
-// CRLsToStack converts a vector of |X509_CRL*| to an OpenSSL STACK_OF(X509_CRL*),
-// bumping the reference counts for each CRL in question.
-static STACK_OF(X509_CRL)* CRLsToStack(const std::vector<X509_CRL*> &crls) {
+// CRLsToStack converts a vector of |X509_CRL*| to an OpenSSL
+// STACK_OF(X509_CRL), bumping the reference counts for each CRL in question.
+static bssl::UniquePtr<STACK_OF(X509_CRL)> CRLsToStack(
+    const std::vector<X509_CRL *> &crls) {
   bssl::UniquePtr<STACK_OF(X509_CRL)> stack(sk_X509_CRL_new_null());
   if (!stack) {
     return nullptr;
@@ -366,7 +445,7 @@
     X509_CRL_up_ref(crl);
   }
 
-  return stack.release();
+  return stack;
 }
 
 static int Verify(X509 *leaf, const std::vector<X509 *> &roots,
@@ -522,13 +601,21 @@
   bssl::UniquePtr<X509_CRL> basic_crl(CRLFromPEM(kBasicCRL));
   bssl::UniquePtr<X509_CRL> revoked_crl(CRLFromPEM(kRevokedCRL));
   bssl::UniquePtr<X509_CRL> bad_issuer_crl(CRLFromPEM(kBadIssuerCRL));
+  bssl::UniquePtr<X509_CRL> known_critical_crl(CRLFromPEM(kKnownCriticalCRL));
+  bssl::UniquePtr<X509_CRL> unknown_critical_crl(
+      CRLFromPEM(kUnknownCriticalCRL));
+  bssl::UniquePtr<X509_CRL> unknown_critical_crl2(
+      CRLFromPEM(kUnknownCriticalCRL2));
 
   if (!root ||
       !leaf ||
       !basic_crl ||
       !revoked_crl ||
-      !bad_issuer_crl) {
-    fprintf(stderr, "Failed to parse certificates\n");
+      !bad_issuer_crl ||
+      !known_critical_crl ||
+      !unknown_critical_crl ||
+      !unknown_critical_crl2) {
+    fprintf(stderr, "Failed to parse certificates and CRLs.\n");
     return false;
   }
 
@@ -558,6 +645,26 @@
     return false;
   }
 
+  if (Verify(leaf.get(), {root.get()}, {root.get()}, {known_critical_crl.get()},
+             X509_V_FLAG_CRL_CHECK) != X509_V_OK) {
+    fprintf(stderr, "CRL with known critical extension was rejected.\n");
+    return false;
+  }
+
+  if (Verify(leaf.get(), {root.get()}, {root.get()},
+             {unknown_critical_crl.get()}, X509_V_FLAG_CRL_CHECK) !=
+      X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION) {
+    fprintf(stderr, "CRL with unknown critical extension was accepted.\n");
+    return false;
+  }
+
+  if (Verify(leaf.get(), {root.get()}, {root.get()},
+             {unknown_critical_crl2.get()}, X509_V_FLAG_CRL_CHECK) !=
+      X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION) {
+    fprintf(stderr, "CRL with unknown critical extension (2) was accepted.\n");
+    return false;
+  }
+
   return true;
 }
 
@@ -639,6 +746,201 @@
   return true;
 }
 
+static bool PEMToDER(bssl::UniquePtr<uint8_t> *out, size_t *out_len,
+                     const char *pem) {
+  bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(pem, strlen(pem)));
+  if (!bio) {
+    return false;
+  }
+
+  char *name, *header;
+  uint8_t *data;
+  long data_len;
+  if (!PEM_read_bio(bio.get(), &name, &header, &data, &data_len)) {
+    fprintf(stderr, "failed to read PEM data.\n");
+    return false;
+  }
+  OPENSSL_free(name);
+  OPENSSL_free(header);
+
+  out->reset(data);
+  *out_len = data_len;
+
+  return true;
+}
+
+static bool TestFromBuffer() {
+  size_t data_len;
+  bssl::UniquePtr<uint8_t> data;
+  if (!PEMToDER(&data, &data_len, kRootCAPEM)) {
+    return false;
+  }
+
+  bssl::UniquePtr<CRYPTO_BUFFER> buf(
+      CRYPTO_BUFFER_new(data.get(), data_len, nullptr));
+  if (!buf) {
+    return false;
+  }
+
+  bssl::UniquePtr<X509> root(X509_parse_from_buffer(buf.get()));
+  if (!root) {
+    return false;
+  }
+
+  const uint8_t *enc_pointer = root->cert_info->enc.enc;
+  const uint8_t *buf_pointer = CRYPTO_BUFFER_data(buf.get());
+  if (enc_pointer < buf_pointer ||
+      enc_pointer >= buf_pointer + CRYPTO_BUFFER_len(buf.get())) {
+    fprintf(stderr, "TestFromBuffer: enc does not alias the buffer.\n");
+    return false;
+  }
+
+  buf.reset();
+
+  /* This ensures the X509 took a reference to |buf|, otherwise this will be a
+   * reference to free memory and ASAN should notice. */
+  if (enc_pointer[0] != CBS_ASN1_SEQUENCE) {
+    fprintf(stderr, "TestFromBuffer: enc data is not a SEQUENCE.\n");
+    return false;
+  }
+
+  return true;
+}
+
+static bool TestFromBufferTrailingData() {
+  size_t data_len;
+  bssl::UniquePtr<uint8_t> data;
+  if (!PEMToDER(&data, &data_len, kRootCAPEM)) {
+    return false;
+  }
+
+  std::unique_ptr<uint8_t[]> trailing_data(new uint8_t[data_len + 1]);
+  memcpy(trailing_data.get(), data.get(), data_len);
+
+  bssl::UniquePtr<CRYPTO_BUFFER> buf_trailing_data(
+      CRYPTO_BUFFER_new(trailing_data.get(), data_len + 1, nullptr));
+  if (!buf_trailing_data) {
+    return false;
+  }
+
+  bssl::UniquePtr<X509> root_trailing_data(
+      X509_parse_from_buffer(buf_trailing_data.get()));
+  if (root_trailing_data) {
+    fprintf(stderr, "TestFromBuffer: trailing data was not rejected.\n");
+    return false;
+  }
+
+  return true;
+}
+
+static bool TestFromBufferModified() {
+  size_t data_len;
+  bssl::UniquePtr<uint8_t> data;
+  if (!PEMToDER(&data, &data_len, kRootCAPEM)) {
+    return false;
+  }
+
+  bssl::UniquePtr<CRYPTO_BUFFER> buf(
+      CRYPTO_BUFFER_new(data.get(), data_len, nullptr));
+  if (!buf) {
+    return false;
+  }
+
+  bssl::UniquePtr<X509> root(X509_parse_from_buffer(buf.get()));
+  if (!root) {
+    return false;
+  }
+
+  bssl::UniquePtr<ASN1_INTEGER> fourty_two(ASN1_INTEGER_new());
+  ASN1_INTEGER_set(fourty_two.get(), 42);
+  X509_set_serialNumber(root.get(), fourty_two.get());
+
+  if (i2d_X509(root.get(), nullptr) != static_cast<long>(data_len)) {
+    fprintf(stderr,
+            "TestFromBufferModified: i2d_X509 gives different answer before "
+            "marking as modified.\n");
+    return false;
+  }
+
+  X509_CINF_set_modified(root->cert_info);
+
+  if (i2d_X509(root.get(), nullptr) == static_cast<long>(data_len)) {
+    fprintf(stderr,
+            "TestFromBufferModified: i2d_X509 gives same answer after marking "
+            "as modified.\n");
+    return false;
+  }
+
+  return true;
+}
+
+static bool TestFromBufferReused() {
+  size_t data_len;
+  bssl::UniquePtr<uint8_t> data;
+  if (!PEMToDER(&data, &data_len, kRootCAPEM)) {
+    return false;
+  }
+
+  bssl::UniquePtr<CRYPTO_BUFFER> buf(
+      CRYPTO_BUFFER_new(data.get(), data_len, nullptr));
+  if (!buf) {
+    return false;
+  }
+
+  bssl::UniquePtr<X509> root(X509_parse_from_buffer(buf.get()));
+  if (!root) {
+    return false;
+  }
+
+  size_t data2_len;
+  bssl::UniquePtr<uint8_t> data2;
+  if (!PEMToDER(&data2, &data2_len, kLeafPEM)) {
+    return false;
+  }
+
+  X509 *x509p = root.get();
+  const uint8_t *inp = data2.get();
+  X509 *ret = d2i_X509(&x509p, &inp, data2_len);
+  if (ret != root.get()) {
+    fprintf(stderr,
+            "TestFromBufferReused: d2i_X509 parsed into a different object.\n");
+    return false;
+  }
+
+  if (root->buf != nullptr) {
+    fprintf(stderr,
+            "TestFromBufferReused: d2i_X509 didn't clear |buf| pointer.\n");
+    return false;
+  }
+
+  // Free |data2| and ensure that |root| took its own copy. Otherwise the
+  // following will trigger a use-after-free.
+  data2.reset();
+
+  uint8_t *i2d = nullptr;
+  int i2d_len = i2d_X509(root.get(), &i2d);
+  if (i2d_len < 0) {
+    return false;
+  }
+  bssl::UniquePtr<uint8_t> i2d_storage(i2d);
+
+  if (!PEMToDER(&data2, &data2_len, kLeafPEM)) {
+    return false;
+  }
+  if (i2d_len != static_cast<long>(data2_len) ||
+      memcmp(data2.get(), i2d, i2d_len) != 0) {
+    fprintf(stderr, "TestFromBufferReused: i2d gave wrong result.\n");
+    return false;
+  }
+
+  if (root->buf != NULL) {
+    fprintf(stderr, "TestFromBufferReused: X509.buf was not cleared.\n");
+    return false;
+  }
+
+  return true;
+}
+
 static int Main() {
   CRYPTO_library_init();
 
@@ -646,7 +948,11 @@
       !TestCRL() ||
       !TestPSS() ||
       !TestBadPSSParameters() ||
-      !TestSignCtx()) {
+      !TestSignCtx() ||
+      !TestFromBuffer() ||
+      !TestFromBufferTrailingData() ||
+      !TestFromBufferModified() ||
+      !TestFromBufferReused()) {
     return 1;
   }
 
diff --git a/src/crypto/x509/x_crl.c b/src/crypto/x509/x_crl.c
index 89cd5d1..6450e84 100644
--- a/src/crypto/x509/x_crl.c
+++ b/src/crypto/x509/x_crl.c
@@ -283,7 +283,7 @@
                 if ((nid == NID_issuing_distribution_point)
                     || (nid == NID_authority_key_identifier)
                     || (nid == NID_delta_crl))
-                    break;;
+                    continue;
                 crl->flags |= EXFLAG_CRITICAL;
                 break;
             }
diff --git a/src/crypto/x509/x_name.c b/src/crypto/x509/x_name.c
index d7dbf80..19f536c 100644
--- a/src/crypto/x509/x_name.c
+++ b/src/crypto/x509/x_name.c
@@ -346,7 +346,7 @@
     STACK_OF(STACK_OF_X509_NAME_ENTRY) *intname = NULL;
     STACK_OF(X509_NAME_ENTRY) *entries = NULL;
     X509_NAME_ENTRY *entry, *tmpentry = NULL;
-    int set = -1, ret = 0;
+    int set = -1, ret = 0, len;
     size_t i;
 
     if (a->canon_enc) {
@@ -386,7 +386,11 @@
 
     /* Finally generate encoding */
 
-    a->canon_enclen = i2d_name_canon(intname, NULL);
+    len = i2d_name_canon(intname, NULL);
+    if (len < 0) {
+        goto err;
+    }
+    a->canon_enclen = len;
 
     p = OPENSSL_malloc(a->canon_enclen);
 
diff --git a/src/crypto/x509/x_x509.c b/src/crypto/x509/x_x509.c
index 9fdda82..845d4b2 100644
--- a/src/crypto/x509/x_x509.c
+++ b/src/crypto/x509/x_x509.c
@@ -62,6 +62,7 @@
 #include <openssl/evp.h>
 #include <openssl/mem.h>
 #include <openssl/obj.h>
+#include <openssl/pool.h>
 #include <openssl/thread.h>
 #include <openssl/x509.h>
 #include <openssl/x509v3.h>
@@ -103,9 +104,15 @@
         ret->akid = NULL;
         ret->aux = NULL;
         ret->crldp = NULL;
+        ret->buf = NULL;
         CRYPTO_new_ex_data(&ret->ex_data);
         break;
 
+    case ASN1_OP_D2I_PRE:
+        CRYPTO_BUFFER_free(ret->buf);
+        ret->buf = NULL;
+        break;
+
     case ASN1_OP_D2I_POST:
         if (ret->name != NULL)
             OPENSSL_free(ret->name);
@@ -121,6 +128,7 @@
         policy_cache_free(ret->policy_cache);
         GENERAL_NAMES_free(ret->altname);
         NAME_CONSTRAINTS_free(ret->nc);
+        CRYPTO_BUFFER_free(ret->buf);
 
         if (ret->name != NULL)
             OPENSSL_free(ret->name);
@@ -142,6 +150,31 @@
 
 IMPLEMENT_ASN1_DUP_FUNCTION(X509)
 
+X509 *X509_parse_from_buffer(CRYPTO_BUFFER *buf) {
+  X509 *x509 = X509_new();
+  if (x509 == NULL) {
+    return NULL;
+  }
+
+  x509->cert_info->enc.alias_only_on_next_parse = 1;
+
+  const uint8_t *inp = CRYPTO_BUFFER_data(buf);
+  X509 *x509p = x509;
+  X509 *ret = d2i_X509(&x509p, &inp, CRYPTO_BUFFER_len(buf));
+  if (ret == NULL ||
+      (inp - CRYPTO_BUFFER_data(buf)) != (ptrdiff_t) CRYPTO_BUFFER_len(buf)) {
+    X509_free(x509);
+    return NULL;
+  }
+  assert(x509p == x509);
+  assert(ret == x509);
+
+  CRYPTO_BUFFER_up_ref(buf);
+  ret->buf = buf;
+
+  return ret;
+}
+
 int X509_up_ref(X509 *x)
 {
     CRYPTO_refcount_inc(&x->references);
diff --git a/src/include/openssl/asn1.h b/src/include/openssl/asn1.h
index c8b32e7..42386e0 100644
--- a/src/include/openssl/asn1.h
+++ b/src/include/openssl/asn1.h
@@ -246,7 +246,15 @@
 	{
 	unsigned char *enc;	/* DER encoding */
 	long len;		/* Length of encoding */
-	int modified;		 /* set to 1 if 'enc' is invalid */
+	int modified;		/* set to 1 if 'enc' is invalid */
+	/* alias_only is zero if |enc| owns the buffer that it points to
+	 * (although |enc| may still be NULL). If one, |enc| points into a
+	 * buffer that is owned elsewhere. */
+	unsigned alias_only:1;
+	/* alias_only_on_next_parse is one iff the next parsing operation
+	 * should avoid taking a copy of the input and rather set
+	 * |alias_only|. */
+	unsigned alias_only_on_next_parse:1;
 	} ASN1_ENCODING;
 
 /* Used with ASN1 LONG type: if a long is set to this it is omitted */
diff --git a/src/include/openssl/base.h b/src/include/openssl/base.h
index 10a22ce..14c243b 100644
--- a/src/include/openssl/base.h
+++ b/src/include/openssl/base.h
@@ -114,6 +114,10 @@
 #define OPENSSL_WINDOWS
 #endif
 
+#if defined(__linux__)
+#define OPENSSL_LINUX
+#endif
+
 #if defined(TRUSTY)
 #define OPENSSL_TRUSTY
 #define OPENSSL_NO_THREADS
@@ -185,6 +189,10 @@
 #define OPENSSL_MSVC_PRAGMA(arg)
 #endif
 
+#if defined(BORINGSSL_UNSAFE_FUZZER_MODE) && \
+    !defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE)
+#define BORINGSSL_UNSAFE_DETERMINISTIC_MODE
+#endif
 
 /* CRYPTO_THREADID is a dummy value. */
 typedef int CRYPTO_THREADID;
@@ -255,6 +263,8 @@
 typedef struct cmac_ctx_st CMAC_CTX;
 typedef struct conf_st CONF;
 typedef struct conf_value_st CONF_VALUE;
+typedef struct crypto_buffer_pool_st CRYPTO_BUFFER_POOL;
+typedef struct crypto_buffer_st CRYPTO_BUFFER;
 typedef struct dh_st DH;
 typedef struct dsa_st DSA;
 typedef struct ec_group_st EC_GROUP;
diff --git a/src/include/openssl/bio.h b/src/include/openssl/bio.h
index 18f9f2a..3c8b97d 100644
--- a/src/include/openssl/bio.h
+++ b/src/include/openssl/bio.h
@@ -333,9 +333,9 @@
 OPENSSL_EXPORT int BIO_hexdump(BIO *bio, const uint8_t *data, size_t len,
                                unsigned indent);
 
-/* BIO_print_errors prints the current contents of the error stack to |bio|
+/* ERR_print_errors prints the current contents of the error stack to |bio|
  * using human readable strings where possible. */
-OPENSSL_EXPORT void BIO_print_errors(BIO *bio);
+OPENSSL_EXPORT void ERR_print_errors(BIO *bio);
 
 /* BIO_read_asn1 reads a single ASN.1 object from |bio|. If successful it sets
  * |*out| to be an allocated buffer (that should be freed with |OPENSSL_free|),
@@ -748,9 +748,6 @@
  * on one line. */
 OPENSSL_EXPORT const BIO_METHOD *BIO_f_base64(void);
 
-/* ERR_print_errors is an alias for |BIO_print_errors|. */
-OPENSSL_EXPORT void ERR_print_errors(BIO *bio);
-
 
 /* Private functions */
 
diff --git a/src/include/openssl/bn.h b/src/include/openssl/bn.h
index 66945cb..764d8c5 100644
--- a/src/include/openssl/bn.h
+++ b/src/include/openssl/bn.h
@@ -148,15 +148,17 @@
 #if defined(OPENSSL_64_BIT)
 #define BN_ULONG uint64_t
 #define BN_BITS2 64
-#define BN_DEC_FMT1	"%" PRIu64
-#define BN_DEC_FMT2	"%019" PRIu64
-#define BN_HEX_FMT1	"%" PRIx64
+#define BN_DEC_FMT1 "%" PRIu64
+#define BN_DEC_FMT2 "%019" PRIu64
+#define BN_HEX_FMT1 "%" PRIx64
+#define BN_HEX_FMT2 "%016" PRIx64
 #elif defined(OPENSSL_32_BIT)
 #define BN_ULONG uint32_t
 #define BN_BITS2 32
-#define BN_DEC_FMT1	"%" PRIu32
-#define BN_DEC_FMT2	"%09" PRIu32
-#define BN_HEX_FMT1	"%" PRIx32
+#define BN_DEC_FMT1 "%" PRIu32
+#define BN_DEC_FMT2 "%09" PRIu32
+#define BN_HEX_FMT1 "%" PRIx32
+#define BN_HEX_FMT2 "%08" PRIx64
 #else
 #error "Must define either OPENSSL_32_BIT or OPENSSL_64_BIT"
 #endif
@@ -582,7 +584,7 @@
 /* Random and prime number generation. */
 
 /* The following are values for the |top| parameter of |BN_rand|. */
-#define BN_RAND_TOP_ANY    -1
+#define BN_RAND_TOP_ANY    (-1)
 #define BN_RAND_TOP_ONE     0
 #define BN_RAND_TOP_TWO     1
 
diff --git a/src/include/openssl/conf.h b/src/include/openssl/conf.h
index 6e6364f..0a09e24 100644
--- a/src/include/openssl/conf.h
+++ b/src/include/openssl/conf.h
@@ -155,6 +155,9 @@
 /* OPENSSL_config does nothing. */
 OPENSSL_EXPORT void OPENSSL_config(CONF_MUST_BE_NULL *config_name);
 
+/* OPENSSL_no_config does nothing. */
+OPENSSL_EXPORT void OPENSSL_no_config(void);
+
 
 #if defined(__cplusplus)
 }  /* extern C */
diff --git a/src/include/openssl/curve25519.h b/src/include/openssl/curve25519.h
index e9ba04d..19f9daa 100644
--- a/src/include/openssl/curve25519.h
+++ b/src/include/openssl/curve25519.h
@@ -33,6 +33,9 @@
  * sometimes referred to as “curve25519”, but “X25519” is a more precise name.
  * See http://cr.yp.to/ecdh.html and https://tools.ietf.org/html/rfc7748. */
 
+#define X25519_PRIVATE_KEY_LEN 32
+#define X25519_PUBLIC_VALUE_LEN 32
+
 /* X25519_keypair sets |out_public_value| and |out_private_key| to a freshly
  * generated, public–private key pair. */
 OPENSSL_EXPORT void X25519_keypair(uint8_t out_public_value[32],
@@ -82,6 +85,15 @@
                                   const uint8_t signature[64],
                                   const uint8_t public_key[32]);
 
+/* ED25519_keypair_from_seed calculates a public and private key from an
+ * Ed25519 “seed”. Seed values are not exposed by this API (although they
+ * happen to be the first 32 bytes of a private key) so this function is for
+ * interoperating with systems that may store just a seed instead of a full
+ * private key. */
+OPENSSL_EXPORT void ED25519_keypair_from_seed(uint8_t out_public_key[32],
+                                              uint8_t out_private_key[64],
+                                              const uint8_t seed[32]);
+
 
 /* SPAKE2.
  *
diff --git a/src/include/openssl/lhash.h b/src/include/openssl/lhash.h
index 0d6d3ae..130ffb1 100644
--- a/src/include/openssl/lhash.h
+++ b/src/include/openssl/lhash.h
@@ -97,6 +97,7 @@
  *
  * LHASH_OF:ASN1_OBJECT
  * LHASH_OF:CONF_VALUE
+ * LHASH_OF:CRYPTO_BUFFER
  * LHASH_OF:SSL_SESSION */
 
 #define IN_LHASH_H
diff --git a/src/include/openssl/lhash_macros.h b/src/include/openssl/lhash_macros.h
index 1d98107..ca349a9 100644
--- a/src/include/openssl/lhash_macros.h
+++ b/src/include/openssl/lhash_macros.h
@@ -17,11 +17,11 @@
 #endif
 
 /* ASN1_OBJECT */
-#define lh_ASN1_OBJECT_new(hash, comp)                                        \
-  ((LHASH_OF(ASN1_OBJECT) *)lh_new(                                           \
-      CHECKED_CAST(lhash_hash_func, uint32_t (*)(const ASN1_OBJECT *), hash), \
-      CHECKED_CAST(lhash_cmp_func,                                            \
-                   int (*)(const ASN1_OBJECT *a, const ASN1_OBJECT *b),       \
+#define lh_ASN1_OBJECT_new(hash, comp)                                       \
+  ((LHASH_OF(ASN1_OBJECT) *)lh_new(                                          \
+      CHECKED_CAST(lhash_hash_func, uint32_t(*)(const ASN1_OBJECT *), hash), \
+      CHECKED_CAST(lhash_cmp_func,                                           \
+                   int (*)(const ASN1_OBJECT *a, const ASN1_OBJECT *b),      \
                    comp)))
 
 #define lh_ASN1_OBJECT_free(lh) \
@@ -55,11 +55,12 @@
                             void (*)(ASN1_OBJECT *, void *), func), \
                arg);
 
+
 /* CONF_VALUE */
-#define lh_CONF_VALUE_new(hash, comp)                                        \
-  ((LHASH_OF(CONF_VALUE) *)lh_new(                                           \
-      CHECKED_CAST(lhash_hash_func, uint32_t (*)(const CONF_VALUE *), hash), \
-      CHECKED_CAST(lhash_cmp_func,                                           \
+#define lh_CONF_VALUE_new(hash, comp)                                       \
+  ((LHASH_OF(CONF_VALUE) *)lh_new(                                          \
+      CHECKED_CAST(lhash_hash_func, uint32_t(*)(const CONF_VALUE *), hash), \
+      CHECKED_CAST(lhash_cmp_func,                                          \
                    int (*)(const CONF_VALUE *a, const CONF_VALUE *b), comp)))
 
 #define lh_CONF_VALUE_free(lh) \
@@ -92,12 +93,53 @@
                             void (*)(CONF_VALUE *, void *), func), \
                arg);
 
+
+/* CRYPTO_BUFFER */
+#define lh_CRYPTO_BUFFER_new(hash, comp)                                       \
+  ((LHASH_OF(CRYPTO_BUFFER) *)lh_new(                                          \
+      CHECKED_CAST(lhash_hash_func, uint32_t(*)(const CRYPTO_BUFFER *), hash), \
+      CHECKED_CAST(lhash_cmp_func,                                             \
+                   int (*)(const CRYPTO_BUFFER *a, const CRYPTO_BUFFER *b),    \
+                   comp)))
+
+#define lh_CRYPTO_BUFFER_free(lh) \
+  lh_free(CHECKED_CAST(_LHASH *, LHASH_OF(CRYPTO_BUFFER) *, lh));
+
+#define lh_CRYPTO_BUFFER_num_items(lh) \
+  lh_num_items(CHECKED_CAST(_LHASH *, LHASH_OF(CRYPTO_BUFFER) *, lh))
+
+#define lh_CRYPTO_BUFFER_retrieve(lh, data)                  \
+  ((CRYPTO_BUFFER *)lh_retrieve(                             \
+      CHECKED_CAST(_LHASH *, LHASH_OF(CRYPTO_BUFFER) *, lh), \
+      CHECKED_CAST(void *, CRYPTO_BUFFER *, data)))
+
+#define lh_CRYPTO_BUFFER_insert(lh, old_data, data)                \
+  lh_insert(CHECKED_CAST(_LHASH *, LHASH_OF(CRYPTO_BUFFER) *, lh), \
+            CHECKED_CAST(void **, CRYPTO_BUFFER **, old_data),     \
+            CHECKED_CAST(void *, CRYPTO_BUFFER *, data))
+
+#define lh_CRYPTO_BUFFER_delete(lh, data)                    \
+  ((CRYPTO_BUFFER *)lh_delete(                               \
+      CHECKED_CAST(_LHASH *, LHASH_OF(CRYPTO_BUFFER) *, lh), \
+      CHECKED_CAST(void *, CRYPTO_BUFFER *, data)))
+
+#define lh_CRYPTO_BUFFER_doall(lh, func)                          \
+  lh_doall(CHECKED_CAST(_LHASH *, LHASH_OF(CRYPTO_BUFFER) *, lh), \
+           CHECKED_CAST(void (*)(void *), void (*)(CRYPTO_BUFFER *), func));
+
+#define lh_CRYPTO_BUFFER_doall_arg(lh, func, arg)                     \
+  lh_doall_arg(CHECKED_CAST(_LHASH *, LHASH_OF(CRYPTO_BUFFER) *, lh), \
+               CHECKED_CAST(void (*)(void *, void *),                 \
+                            void (*)(CRYPTO_BUFFER *, void *), func), \
+               arg);
+
+
 /* SSL_SESSION */
-#define lh_SSL_SESSION_new(hash, comp)                                        \
-  ((LHASH_OF(SSL_SESSION) *)lh_new(                                           \
-      CHECKED_CAST(lhash_hash_func, uint32_t (*)(const SSL_SESSION *), hash), \
-      CHECKED_CAST(lhash_cmp_func,                                            \
-                   int (*)(const SSL_SESSION *a, const SSL_SESSION *b),       \
+#define lh_SSL_SESSION_new(hash, comp)                                       \
+  ((LHASH_OF(SSL_SESSION) *)lh_new(                                          \
+      CHECKED_CAST(lhash_hash_func, uint32_t(*)(const SSL_SESSION *), hash), \
+      CHECKED_CAST(lhash_cmp_func,                                           \
+                   int (*)(const SSL_SESSION *a, const SSL_SESSION *b),      \
                    comp)))
 
 #define lh_SSL_SESSION_free(lh) \
diff --git a/src/include/openssl/pool.h b/src/include/openssl/pool.h
new file mode 100644
index 0000000..a6dee9f
--- /dev/null
+++ b/src/include/openssl/pool.h
@@ -0,0 +1,87 @@
+/* Copyright (c) 2016, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#ifndef OPENSSL_HEADER_POOL_H
+#define OPENSSL_HEADER_POOL_H
+
+#include <openssl/base.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* Buffers and buffer pools.
+ *
+ * |CRYPTO_BUFFER|s are simply reference-counted blobs. A |CRYPTO_BUFFER_POOL| is
+ * an intern table for |CRYPTO_BUFFER|s. This allows for a single copy of a given
+ * blob to be kept in memory and referenced from multiple places. */
+
+
+/* CRYPTO_BUFFER_POOL_new returns a freshly allocated |CRYPTO_BUFFER_POOL| or
+ * NULL on error. */
+OPENSSL_EXPORT CRYPTO_BUFFER_POOL* CRYPTO_BUFFER_POOL_new(void);
+
+/* CRYPTO_BUFFER_POOL_free frees |pool|, which must be empty. */
+OPENSSL_EXPORT void CRYPTO_BUFFER_POOL_free(CRYPTO_BUFFER_POOL *pool);
+
+/* CRYPTO_BUFFER_new returns a |CRYPTO_BUFFER| containing a copy of |data|, or
+ * else NULL on error. If |pool| is not NULL then the returned value may be a
+ * reference to a previously existing |CRYPTO_BUFFER| that contained the same
+ * data. Otherwise, the returned, fresh |CRYPTO_BUFFER| will be added to the
+ * pool. */
+OPENSSL_EXPORT CRYPTO_BUFFER *CRYPTO_BUFFER_new(const uint8_t *data, size_t len,
+                                                CRYPTO_BUFFER_POOL *pool);
+
+/* CRYPTO_BUFFER_new_from_CBS acts the same as |CRYPTO_BUFFER_new|. */
+OPENSSL_EXPORT CRYPTO_BUFFER *CRYPTO_BUFFER_new_from_CBS(
+    CBS *cbs, CRYPTO_BUFFER_POOL *pool);
+
+/* CRYPTO_BUFFER_free decrements the reference count of |buf|. If there are no
+ * other references, or if the only remaining reference is from a pool, then
+ * |buf| will be freed. */
+OPENSSL_EXPORT void CRYPTO_BUFFER_free(CRYPTO_BUFFER *buf);
+
+/* CRYPTO_BUFFER_up_ref increments the reference count of |buf| and returns
+ * one. */
+OPENSSL_EXPORT int CRYPTO_BUFFER_up_ref(CRYPTO_BUFFER *buf);
+
+/* CRYPTO_BUFFER_data returns a pointer to the data contained in |buf|. */
+OPENSSL_EXPORT const uint8_t *CRYPTO_BUFFER_data(const CRYPTO_BUFFER *buf);
+
+/* CRYPTO_BUFFER_len returns the length, in bytes, of the data contained in
+ * |buf|. */
+OPENSSL_EXPORT size_t CRYPTO_BUFFER_len(const CRYPTO_BUFFER *buf);
+
+/* CRYPTO_BUFFER_init_CBS initialises |out| to point at the data from |buf|. */
+OPENSSL_EXPORT void CRYPTO_BUFFER_init_CBS(const CRYPTO_BUFFER *buf, CBS *out);
+
+
+#if defined(__cplusplus)
+}  /* extern C */
+
+extern "C++" {
+
+namespace bssl {
+
+BORINGSSL_MAKE_DELETER(CRYPTO_BUFFER_POOL, CRYPTO_BUFFER_POOL_free)
+BORINGSSL_MAKE_DELETER(CRYPTO_BUFFER, CRYPTO_BUFFER_free)
+
+}  // namespace bssl
+
+}  /* extern C++ */
+
+#endif
+
+#endif  // OPENSSL_HEADER_POOL_H
diff --git a/src/include/openssl/rand.h b/src/include/openssl/rand.h
index 322249c..0e9a8cd 100644
--- a/src/include/openssl/rand.h
+++ b/src/include/openssl/rand.h
@@ -62,7 +62,7 @@
 OPENSSL_EXPORT void RAND_enable_fork_unsafe_buffering(int fd);
 #endif
 
-#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+#if defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE)
 /* RAND_reset_for_fuzzing resets the fuzzer-only deterministic RNG. This
  * function is only defined in the fuzzer-only build configuration. */
 OPENSSL_EXPORT void RAND_reset_for_fuzzing(void);
diff --git a/src/include/openssl/ssl.h b/src/include/openssl/ssl.h
index 0d78754..f5b9f9d 100644
--- a/src/include/openssl/ssl.h
+++ b/src/include/openssl/ssl.h
@@ -562,7 +562,7 @@
 #define DTLS1_VERSION 0xfeff
 #define DTLS1_2_VERSION 0xfefd
 
-#define TLS1_3_DRAFT_VERSION 0x7f10
+#define TLS1_3_DRAFT_VERSION 0x7f12
 
 /* SSL_CTX_set_min_proto_version sets the minimum protocol version for |ctx| to
  * |version|. If |version| is zero, the default minimum version is used. It
@@ -670,8 +670,9 @@
 #define SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER 0x00000002L
 
 /* SSL_MODE_NO_AUTO_CHAIN disables automatically building a certificate chain
- * before sending certificates to the peer.
- * TODO(davidben): Remove this behavior. https://crbug.com/486295. */
+ * before sending certificates to the peer. This flag is set (and the feature
+ * disabled) by default.
+ * TODO(davidben): Remove this behavior. https://crbug.com/boringssl/42. */
 #define SSL_MODE_NO_AUTO_CHAIN 0x00000008L
 
 /* SSL_MODE_ENABLE_FALSE_START allows clients to send application data before
@@ -1306,7 +1307,12 @@
  *   [ECDHE-ECDSA-CHACHA20-POLY1305|ECDHE-ECDSA-AES128-GCM-SHA256]
  *
  * Once an equal-preference group is used, future directives must be
- * opcode-less. */
+ * opcode-less.
+ *
+ * TLS 1.3 ciphers do not participate in this mechanism and instead have a
+ * built-in preference order. Functions to set cipher lists do not affect TLS
+ * 1.3, and functions to query the cipher list do not include TLS 1.3
+ * ciphers. */
 
 /* SSL_DEFAULT_CIPHER_LIST is the default cipher suite configuration. It is
  * substituted when a cipher string starts with 'DEFAULT'. */
@@ -2331,9 +2337,9 @@
 
 /* SSL_CTX_set_tlsext_servername_callback configures |callback| to be called on
  * the server after ClientHello extensions have been parsed and returns one.
- * The callback may use |SSL_get_servername| to examine the server_name extension
- * and returns a |SSL_TLSEXT_ERR_*| value. The value of |arg| may be set by
- * calling |SSL_CTX_set_tlsext_servername_arg|.
+ * The callback may use |SSL_get_servername| to examine the server_name
+ * extension and returns a |SSL_TLSEXT_ERR_*| value. The value of |arg| may be
+ * set by calling |SSL_CTX_set_tlsext_servername_arg|.
  *
  * If the callback returns |SSL_TLSEXT_ERR_NOACK|, the server_name extension is
  * not acknowledged in the ServerHello. If the return value is
@@ -2389,7 +2395,10 @@
  * |*out_len| to the selected protocol and return |SSL_TLSEXT_ERR_OK| on
  * success. It does not pass ownership of the buffer. Otherwise, it should
  * return |SSL_TLSEXT_ERR_NOACK|. Other |SSL_TLSEXT_ERR_*| values are
- * unimplemented and will be treated as |SSL_TLSEXT_ERR_NOACK|. */
+ * unimplemented and will be treated as |SSL_TLSEXT_ERR_NOACK|.
+ *
+ * The cipher suite is selected before negotiating ALPN. The callback may use
+ * |SSL_get_pending_cipher| to query the cipher suite. */
 OPENSSL_EXPORT void SSL_CTX_set_alpn_select_cb(
     SSL_CTX *ctx, int (*cb)(SSL *ssl, const uint8_t **out, uint8_t *out_len,
                             const uint8_t *in, unsigned in_len, void *arg),
@@ -3107,6 +3116,14 @@
  * NULL if one has not been negotiated yet or there is no pending handshake. */
 OPENSSL_EXPORT const SSL_CIPHER *SSL_get_pending_cipher(const SSL *ssl);
 
+/* SSL_set_retain_only_sha256_of_client_certs, on a server, sets whether only
+ * the SHA-256 hash of peer's certificate should be saved in memory and in the
+ * session. This can save memory, ticket size and session cache space. If
+ * enabled, |SSL_get_peer_certificate| will return NULL after the handshake
+ * completes. See the |peer_sha256| field of |SSL_SESSION| for the hash. */
+OPENSSL_EXPORT void SSL_set_retain_only_sha256_of_client_certs(SSL *ssl,
+                                                               int enable);
+
 /* SSL_CTX_set_retain_only_sha256_of_client_certs, on a server, sets whether
  * only the SHA-256 hash of peer's certificate should be saved in memory and in
  * the session. This can save memory, ticket size and session cache space. If
@@ -3119,6 +3136,10 @@
  * GREASE. See draft-davidben-tls-grease-01. */
 OPENSSL_EXPORT void SSL_CTX_set_grease_enabled(SSL_CTX *ctx, int enabled);
 
+/* SSL_max_seal_overhead returns the maximum overhead, in bytes, of sealing a
+ * record with |ssl|. */
+OPENSSL_EXPORT size_t SSL_max_seal_overhead(const SSL *ssl);
+
 
 /* Deprecated functions. */
 
@@ -3613,9 +3634,6 @@
  * deprecated. */
 
 typedef struct ssl_protocol_method_st SSL_PROTOCOL_METHOD;
-typedef struct ssl3_enc_method SSL3_ENC_METHOD;
-typedef struct ssl_aead_ctx_st SSL_AEAD_CTX;
-typedef struct ssl_handshake_st SSL_HANDSHAKE;
 
 struct ssl_cipher_st {
   /* name is the OpenSSL name for the cipher. */
@@ -3631,12 +3649,6 @@
   uint32_t algorithm_prf;
 };
 
-typedef struct ssl_ecdh_method_st SSL_ECDH_METHOD;
-typedef struct ssl_ecdh_ctx_st {
-  const SSL_ECDH_METHOD *method;
-  void *data;
-} SSL_ECDH_CTX;
-
 #define SSL_MAX_SSL_SESSION_ID_LENGTH 32
 #define SSL_MAX_SID_CTX_LENGTH 32
 #define SSL_MAX_MASTER_KEY_LENGTH 48
@@ -3671,19 +3683,23 @@
   uint8_t sid_ctx[SSL_MAX_SID_CTX_LENGTH];
 
   char *psk_identity;
-  /* peer is the peer's certificate. */
-  X509 *peer;
+  /* x509_peer is the peer's certificate. */
+  X509 *x509_peer;
 
-  /* cert_chain is the certificate chain sent by the peer. NOTE: for historical
+  /* x509_chain is the certificate chain sent by the peer. NOTE: for historical
    * reasons, when a client (so the peer is a server), the chain includes
    * |peer|, but when a server it does not. */
-  STACK_OF(X509) *cert_chain;
+  STACK_OF(X509) *x509_chain;
 
   /* verify_result is the result of certificate verification in the case of
    * non-fatal certificate errors. */
   long verify_result;
 
+  /* timeout is the lifetime of the session in seconds, measured from |time|. */
   long timeout;
+
+  /* time is the time the session was issued, measured in seconds from the UNIX
+   * epoch. */
   long time;
 
   const SSL_CIPHER *cipher;
@@ -3788,8 +3804,6 @@
   uint16_t min_version;
 
   struct ssl_cipher_preference_list_st *cipher_list;
-  /* same as above but sorted for lookup */
-  STACK_OF(SSL_CIPHER) *cipher_list_by_id;
 
   /* cipher_list_tls10 is the list of ciphers when TLS 1.0 or greater is in
    * use. This only applies to server connections as, for clients, the version
@@ -4091,7 +4105,6 @@
 
   /* crypto */
   struct ssl_cipher_preference_list_st *cipher_list;
-  STACK_OF(SSL_CIPHER) *cipher_list_by_id;
 
   /* session info */
 
@@ -4195,8 +4208,10 @@
    * we'll advertise support. */
   unsigned tlsext_channel_id_enabled:1;
 
-  /* RFC4507 session ticket expected to be received or sent */
-  unsigned tlsext_ticket_expected:1;
+  /* retain_only_sha256_of_client_certs is true if we should compute the SHA256
+   * hash of the peer's certificate and then discard it to save memory and
+   * session space. Only effective on the server side. */
+  unsigned retain_only_sha256_of_client_certs:1;
 
   /* TODO(agl): remove once node.js not longer references this. */
   int tlsext_status_type;
@@ -4534,6 +4549,9 @@
 #define SSL_R_DUPLICATE_KEY_SHARE 264
 #define SSL_R_NO_GROUPS_SPECIFIED 265
 #define SSL_R_NO_SHARED_GROUP 266
+#define SSL_R_PRE_SHARED_KEY_MUST_BE_LAST 267
+#define SSL_R_OLD_SESSION_PRF_HASH_MISMATCH 268
+#define SSL_R_INVALID_SCT_LIST 269
 #define SSL_R_SSLV3_ALERT_CLOSE_NOTIFY 1000
 #define SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE 1010
 #define SSL_R_SSLV3_ALERT_BAD_RECORD_MAC 1020
diff --git a/src/include/openssl/ssl3.h b/src/include/openssl/ssl3.h
index 4a99196..4cf51e1 100644
--- a/src/include/openssl/ssl3.h
+++ b/src/include/openssl/ssl3.h
@@ -352,6 +352,7 @@
 #define SSL3_ST_SR_CLNT_HELLO_B (0x111 | SSL_ST_ACCEPT)
 #define SSL3_ST_SR_CLNT_HELLO_C (0x112 | SSL_ST_ACCEPT)
 #define SSL3_ST_SR_CLNT_HELLO_D (0x113 | SSL_ST_ACCEPT)
+#define SSL3_ST_SR_CLNT_HELLO_E (0x114 | SSL_ST_ACCEPT)
 /* write to client */
 #define SSL3_ST_SW_HELLO_REQ_A (0x120 | SSL_ST_ACCEPT)
 #define SSL3_ST_SW_HELLO_REQ_B (0x121 | SSL_ST_ACCEPT)
diff --git a/src/include/openssl/stack.h b/src/include/openssl/stack.h
index c6e0de3..c0cd0f6 100644
--- a/src/include/openssl/stack.h
+++ b/src/include/openssl/stack.h
@@ -129,6 +129,7 @@
  * STACK_OF:BY_DIR_ENTRY
  * STACK_OF:BY_DIR_HASH
  * STACK_OF:CONF_VALUE
+ * STACK_OF:CRYPTO_BUFFER
  * STACK_OF:CRYPTO_EX_DATA_FUNCS
  * STACK_OF:DIST_POINT
  * STACK_OF:GENERAL_NAME
diff --git a/src/include/openssl/stack_macros.h b/src/include/openssl/stack_macros.h
index d5f47f7..a5f36fb 100644
--- a/src/include/openssl/stack_macros.h
+++ b/src/include/openssl/stack_macros.h
@@ -1014,6 +1014,91 @@
                    copy_func),                                        \
       CHECKED_CAST(void (*)(void *), void (*)(CONF_VALUE *), free_func)))
 
+/* CRYPTO_BUFFER */
+#define sk_CRYPTO_BUFFER_new(comp)                 \
+  ((STACK_OF(CRYPTO_BUFFER) *)sk_new(CHECKED_CAST( \
+      stack_cmp_func,                              \
+      int (*)(const CRYPTO_BUFFER **a, const CRYPTO_BUFFER **b), comp)))
+
+#define sk_CRYPTO_BUFFER_new_null() ((STACK_OF(CRYPTO_BUFFER) *)sk_new_null())
+
+#define sk_CRYPTO_BUFFER_num(sk) \
+  sk_num(CHECKED_CAST(const _STACK *, const STACK_OF(CRYPTO_BUFFER) *, sk))
+
+#define sk_CRYPTO_BUFFER_zero(sk) \
+  sk_zero(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_BUFFER) *, sk));
+
+#define sk_CRYPTO_BUFFER_value(sk, i) \
+  ((CRYPTO_BUFFER *)sk_value(         \
+      CHECKED_CAST(const _STACK *, const STACK_OF(CRYPTO_BUFFER) *, sk), (i)))
+
+#define sk_CRYPTO_BUFFER_set(sk, i, p)                            \
+  ((CRYPTO_BUFFER *)sk_set(                                       \
+      CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_BUFFER) *, sk), (i), \
+      CHECKED_CAST(void *, CRYPTO_BUFFER *, p)))
+
+#define sk_CRYPTO_BUFFER_free(sk) \
+  sk_free(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_BUFFER) *, sk))
+
+#define sk_CRYPTO_BUFFER_pop_free(sk, free_func)             \
+  sk_pop_free(                                               \
+      CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_BUFFER) *, sk), \
+      CHECKED_CAST(void (*)(void *), void (*)(CRYPTO_BUFFER *), free_func))
+
+#define sk_CRYPTO_BUFFER_insert(sk, p, where)                      \
+  sk_insert(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_BUFFER) *, sk), \
+            CHECKED_CAST(void *, CRYPTO_BUFFER *, p), (where))
+
+#define sk_CRYPTO_BUFFER_delete(sk, where) \
+  ((CRYPTO_BUFFER *)sk_delete(             \
+      CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_BUFFER) *, sk), (where)))
+
+#define sk_CRYPTO_BUFFER_delete_ptr(sk, p)                   \
+  ((CRYPTO_BUFFER *)sk_delete_ptr(                           \
+      CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_BUFFER) *, sk), \
+      CHECKED_CAST(void *, CRYPTO_BUFFER *, p)))
+
+#define sk_CRYPTO_BUFFER_find(sk, out_index, p)                               \
+  sk_find(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_BUFFER) *, sk), (out_index), \
+          CHECKED_CAST(void *, CRYPTO_BUFFER *, p))
+
+#define sk_CRYPTO_BUFFER_shift(sk) \
+  ((CRYPTO_BUFFER *)sk_shift(      \
+      CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_BUFFER) *, sk)))
+
+#define sk_CRYPTO_BUFFER_push(sk, p)                             \
+  sk_push(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_BUFFER) *, sk), \
+          CHECKED_CAST(void *, CRYPTO_BUFFER *, p))
+
+#define sk_CRYPTO_BUFFER_pop(sk) \
+  ((CRYPTO_BUFFER *)sk_pop(      \
+      CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_BUFFER) *, sk)))
+
+#define sk_CRYPTO_BUFFER_dup(sk)      \
+  ((STACK_OF(CRYPTO_BUFFER) *)sk_dup( \
+      CHECKED_CAST(const _STACK *, const STACK_OF(CRYPTO_BUFFER) *, sk)))
+
+#define sk_CRYPTO_BUFFER_sort(sk) \
+  sk_sort(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_BUFFER) *, sk))
+
+#define sk_CRYPTO_BUFFER_is_sorted(sk) \
+  sk_is_sorted(                        \
+      CHECKED_CAST(const _STACK *, const STACK_OF(CRYPTO_BUFFER) *, sk))
+
+#define sk_CRYPTO_BUFFER_set_cmp_func(sk, comp)                                \
+  ((int (*)(const CRYPTO_BUFFER **a, const CRYPTO_BUFFER **b))sk_set_cmp_func( \
+      CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_BUFFER) *, sk),                   \
+      CHECKED_CAST(stack_cmp_func,                                             \
+                   int (*)(const CRYPTO_BUFFER **a, const CRYPTO_BUFFER **b),  \
+                   comp)))
+
+#define sk_CRYPTO_BUFFER_deep_copy(sk, copy_func, free_func)               \
+  ((STACK_OF(CRYPTO_BUFFER) *)sk_deep_copy(                                \
+      CHECKED_CAST(const _STACK *, const STACK_OF(CRYPTO_BUFFER) *, sk),   \
+      CHECKED_CAST(void *(*)(void *), CRYPTO_BUFFER *(*)(CRYPTO_BUFFER *), \
+                   copy_func),                                             \
+      CHECKED_CAST(void (*)(void *), void (*)(CRYPTO_BUFFER *), free_func)))
+
 /* CRYPTO_EX_DATA_FUNCS */
 #define sk_CRYPTO_EX_DATA_FUNCS_new(comp)                                      \
   ((STACK_OF(CRYPTO_EX_DATA_FUNCS) *)sk_new(CHECKED_CAST(                      \
diff --git a/src/include/openssl/tls1.h b/src/include/openssl/tls1.h
index 35d3145..dfaf78a 100644
--- a/src/include/openssl/tls1.h
+++ b/src/include/openssl/tls1.h
@@ -205,13 +205,14 @@
 /* ExtensionType value from RFC4507 */
 #define TLSEXT_TYPE_session_ticket 35
 
-/* ExtensionType values from draft-ietf-tls-tls13-16 */
+/* ExtensionType values from draft-ietf-tls-tls13-18 */
 #define TLSEXT_TYPE_supported_groups 10
 #define TLSEXT_TYPE_key_share 40
 #define TLSEXT_TYPE_pre_shared_key 41
 #define TLSEXT_TYPE_early_data 42
 #define TLSEXT_TYPE_supported_versions 43
 #define TLSEXT_TYPE_cookie 44
+#define TLSEXT_TYPE_psk_key_exchange_modes 45
 
 /* ExtensionType value from RFC5746 */
 #define TLSEXT_TYPE_renegotiate 0xff01
diff --git a/src/include/openssl/x509.h b/src/include/openssl/x509.h
index 8204486..8f2e1c3 100644
--- a/src/include/openssl/x509.h
+++ b/src/include/openssl/x509.h
@@ -77,6 +77,7 @@
 #include <openssl/ec.h>
 #include <openssl/evp.h>
 #include <openssl/obj.h>
+#include <openssl/pool.h>
 #include <openssl/rsa.h>
 #include <openssl/sha.h>
 #include <openssl/stack.h>
@@ -261,6 +262,7 @@
 	NAME_CONSTRAINTS *nc;
 	unsigned char sha1_hash[SHA_DIGEST_LENGTH];
 	X509_CERT_AUX *aux;
+	CRYPTO_BUFFER *buf;
 	} /* X509 */;
 
 DECLARE_STACK_OF(X509)
@@ -636,6 +638,12 @@
 		unsigned char *md, unsigned int *len);
 #endif
 
+/* X509_parse_from_buffer parses an X.509 structure from |buf| and returns a
+ * fresh X509 or NULL on error. There must not be any trailing data in |buf|.
+ * The returned structure (if any) holds a reference to |buf| rather than
+ * copying parts of it as a normal |d2i_X509| call would do. */
+OPENSSL_EXPORT X509 *X509_parse_from_buffer(CRYPTO_BUFFER *buf);
+
 #ifndef OPENSSL_NO_FP_API
 OPENSSL_EXPORT X509 *d2i_X509_fp(FILE *fp, X509 **x509);
 OPENSSL_EXPORT int i2d_X509_fp(FILE *fp,X509 *x509);
@@ -1074,24 +1082,6 @@
 OPENSSL_EXPORT ASN1_OBJECT *X509_ATTRIBUTE_get0_object(X509_ATTRIBUTE *attr);
 OPENSSL_EXPORT ASN1_TYPE *X509_ATTRIBUTE_get0_type(X509_ATTRIBUTE *attr, int idx);
 
-OPENSSL_EXPORT int EVP_PKEY_get_attr_count(const EVP_PKEY *key);
-OPENSSL_EXPORT int EVP_PKEY_get_attr_by_NID(const EVP_PKEY *key, int nid,
-			  int lastpos);
-OPENSSL_EXPORT int EVP_PKEY_get_attr_by_OBJ(const EVP_PKEY *key, ASN1_OBJECT *obj,
-			  int lastpos);
-OPENSSL_EXPORT X509_ATTRIBUTE *EVP_PKEY_get_attr(const EVP_PKEY *key, int loc);
-OPENSSL_EXPORT X509_ATTRIBUTE *EVP_PKEY_delete_attr(EVP_PKEY *key, int loc);
-OPENSSL_EXPORT int EVP_PKEY_add1_attr(EVP_PKEY *key, X509_ATTRIBUTE *attr);
-OPENSSL_EXPORT int EVP_PKEY_add1_attr_by_OBJ(EVP_PKEY *key,
-			const ASN1_OBJECT *obj, int type,
-			const unsigned char *bytes, int len);
-OPENSSL_EXPORT int EVP_PKEY_add1_attr_by_NID(EVP_PKEY *key,
-			int nid, int type,
-			const unsigned char *bytes, int len);
-OPENSSL_EXPORT int EVP_PKEY_add1_attr_by_txt(EVP_PKEY *key,
-			const char *attrname, int type,
-			const unsigned char *bytes, int len);
-
 OPENSSL_EXPORT int		X509_verify_cert(X509_STORE_CTX *ctx);
 
 /* lookup a cert from a X509 STACK */
diff --git a/src/ssl/custom_extensions.c b/src/ssl/custom_extensions.c
index 780cdc6..46b5efb 100644
--- a/src/ssl/custom_extensions.c
+++ b/src/ssl/custom_extensions.c
@@ -90,7 +90,7 @@
             !CBB_add_bytes(&contents_cbb, contents, contents_len) ||
             !CBB_flush(extensions)) {
           OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
-          ERR_add_error_dataf("extension: %u", (unsigned) ext->value);
+          ERR_add_error_dataf("extension %u", (unsigned) ext->value);
           if (ext->free_callback && 0 < contents_len) {
             ext->free_callback(ssl, ext->value, contents, ext->add_arg);
           }
@@ -113,7 +113,7 @@
       default:
         ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
         OPENSSL_PUT_ERROR(SSL, SSL_R_CUSTOM_EXTENSION_ERROR);
-        ERR_add_error_dataf("extension: %u", (unsigned) ext->value);
+        ERR_add_error_dataf("extension %u", (unsigned) ext->value);
         return 0;
     }
   }
@@ -136,7 +136,7 @@
       /* Also, if we didn't send the extension, that's also unacceptable. */
       !(ssl->s3->hs->custom_extensions.sent & (1u << index))) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
-    ERR_add_error_dataf("extension: %u", (unsigned)value);
+    ERR_add_error_dataf("extension %u", (unsigned)value);
     *out_alert = SSL_AD_UNSUPPORTED_EXTENSION;
     return 0;
   }
@@ -145,7 +145,7 @@
       !ext->parse_callback(ssl, value, CBS_data(extension), CBS_len(extension),
                            out_alert, ext->parse_arg)) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_CUSTOM_EXTENSION_ERROR);
-    ERR_add_error_dataf("extension: %u", (unsigned)ext->value);
+    ERR_add_error_dataf("extension %u", (unsigned)ext->value);
     return 0;
   }
 
@@ -169,7 +169,7 @@
       !ext->parse_callback(ssl, value, CBS_data(extension), CBS_len(extension),
                            out_alert, ext->parse_arg)) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_CUSTOM_EXTENSION_ERROR);
-    ERR_add_error_dataf("extension: %u", (unsigned)ext->value);
+    ERR_add_error_dataf("extension %u", (unsigned)ext->value);
     return 0;
   }
 
diff --git a/src/ssl/d1_both.c b/src/ssl/d1_both.c
index 7bb2de2..f9bb8f4 100644
--- a/src/ssl/d1_both.c
+++ b/src/ssl/d1_both.c
@@ -433,7 +433,7 @@
     OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE);
     return -1;
   }
-  if (hash_message == ssl_hash_message && !dtls1_hash_current_message(ssl)) {
+  if (hash_message == ssl_hash_message && !ssl_hash_current_message(ssl)) {
     return -1;
   }
 
@@ -442,13 +442,12 @@
   return 1;
 }
 
-int dtls1_hash_current_message(SSL *ssl) {
+void dtls1_get_current_message(const SSL *ssl, CBS *out) {
   assert(dtls1_is_current_message_complete(ssl));
 
   hm_fragment *frag = ssl->d1->incoming_messages[ssl->d1->handshake_read_seq %
                                                  SSL_MAX_HANDSHAKE_FLIGHT];
-  return ssl3_update_handshake_hash(ssl, frag->data,
-                                    DTLS1_HM_HEADER_LENGTH + frag->msg_len);
+  CBS_init(out, frag->data, DTLS1_HM_HEADER_LENGTH + frag->msg_len);
 }
 
 void dtls1_release_current_message(SSL *ssl, int free_buffer) {
@@ -527,10 +526,10 @@
 /* dtls1_max_record_size returns the maximum record body length that may be
  * written without exceeding the MTU. It accounts for any buffering installed on
  * the write BIO. If no record may be written, it returns zero. */
-static size_t dtls1_max_record_size(SSL *ssl) {
+static size_t dtls1_max_record_size(const SSL *ssl) {
   size_t ret = ssl->d1->mtu;
 
-  size_t overhead = ssl_max_seal_overhead(ssl);
+  size_t overhead = SSL_max_seal_overhead(ssl);
   if (ret <= overhead) {
     return 0;
   }
@@ -736,21 +735,23 @@
   return 1;
 }
 
-int dtls1_finish_message(SSL *ssl, CBB *cbb) {
-  uint8_t *msg = NULL;
-  size_t len;
-  if (!CBB_finish(cbb, &msg, &len) ||
-      len > 0xffffffffu ||
-      len < DTLS1_HM_HEADER_LENGTH) {
+int dtls1_finish_message(SSL *ssl, CBB *cbb, uint8_t **out_msg,
+                         size_t *out_len) {
+  *out_msg = NULL;
+  if (!CBB_finish(cbb, out_msg, out_len) ||
+      *out_len < DTLS1_HM_HEADER_LENGTH) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
-    OPENSSL_free(msg);
+    OPENSSL_free(*out_msg);
     return 0;
   }
 
   /* Fix up the header. Copy the fragment length into the total message
    * length. */
-  memcpy(msg + 1, msg + DTLS1_HM_HEADER_LENGTH - 3, 3);
+  memcpy(*out_msg + 1, *out_msg + DTLS1_HM_HEADER_LENGTH - 3, 3);
+  return 1;
+}
 
+int dtls1_queue_message(SSL *ssl, uint8_t *msg, size_t len) {
   ssl3_update_handshake_hash(ssl, msg, len);
 
   ssl->d1->handshake_write_seq++;
diff --git a/src/ssl/d1_pkt.c b/src/ssl/d1_pkt.c
index 099de5d..155359c 100644
--- a/src/ssl/d1_pkt.c
+++ b/src/ssl/d1_pkt.c
@@ -377,7 +377,7 @@
     return -1;
   }
 
-  size_t max_out = len + ssl_max_seal_overhead(ssl);
+  size_t max_out = len + SSL_max_seal_overhead(ssl);
   uint8_t *out;
   size_t ciphertext_len;
   if (!ssl_write_buffer_init(ssl, &out, max_out) ||
diff --git a/src/ssl/dtls_method.c b/src/ssl/dtls_method.c
index 9d791b5..8e92cc9 100644
--- a/src/ssl/dtls_method.c
+++ b/src/ssl/dtls_method.c
@@ -132,7 +132,7 @@
     dtls1_new,
     dtls1_free,
     dtls1_get_message,
-    dtls1_hash_current_message,
+    dtls1_get_current_message,
     dtls1_release_current_message,
     dtls1_read_app_data,
     dtls1_read_change_cipher_spec,
@@ -142,6 +142,7 @@
     dtls1_supports_cipher,
     dtls1_init_message,
     dtls1_finish_message,
+    dtls1_queue_message,
     dtls1_write_message,
     dtls1_send_change_cipher_spec,
     dtls1_expect_flight,
diff --git a/src/ssl/handshake_client.c b/src/ssl/handshake_client.c
index a917e02..70d8d96 100644
--- a/src/ssl/handshake_client.c
+++ b/src/ssl/handshake_client.c
@@ -152,6 +152,7 @@
 #include <assert.h>
 #include <string.h>
 
+#include <openssl/aead.h>
 #include <openssl/bn.h>
 #include <openssl/buf.h>
 #include <openssl/bytestring.h>
@@ -447,7 +448,7 @@
         goto end;
 
       case SSL3_ST_CR_SESSION_TICKET_A:
-        if (ssl->tlsext_ticket_expected) {
+        if (ssl->s3->hs->ticket_expected) {
           ret = ssl3_get_new_session_ticket(ssl);
           if (ret <= 0) {
             goto end;
@@ -506,8 +507,6 @@
         break;
 
       case SSL_ST_OK:
-        /* Clean a few things up. */
-        ssl3_cleanup_key_block(ssl);
         ssl->method->release_current_message(ssl, 1 /* free_buffer */);
 
         SSL_SESSION_free(ssl->s3->established_session);
@@ -537,9 +536,6 @@
         /* Remove write buffering now. */
         ssl_free_wbio_buffer(ssl);
 
-        ssl_handshake_free(ssl->s3->hs);
-        ssl->s3->hs = NULL;
-
         const int is_initial_handshake = !ssl->s3->initial_handshake_complete;
         ssl->s3->initial_handshake_complete = 1;
         if (is_initial_handshake) {
@@ -547,6 +543,9 @@
           ssl_update_cache(ssl, SSL_SESS_CACHE_CLIENT);
         }
 
+        ssl_handshake_free(ssl->s3->hs);
+        ssl->s3->hs = NULL;
+
         ret = 1;
         ssl_do_info_callback(ssl, SSL_CB_HANDSHAKE_DONE, 1);
         goto end;
@@ -605,30 +604,48 @@
     return 0;
   }
 
-  STACK_OF(SSL_CIPHER) *ciphers = SSL_get_ciphers(ssl);
-
-  int any_enabled = 0;
-  for (size_t i = 0; i < sk_SSL_CIPHER_num(ciphers); i++) {
-    const SSL_CIPHER *cipher = sk_SSL_CIPHER_value(ciphers, i);
-    /* Skip disabled ciphers */
-    if ((cipher->algorithm_mkey & ssl->cert->mask_k) ||
-        (cipher->algorithm_auth & ssl->cert->mask_a)) {
-      continue;
+  /* Add TLS 1.3 ciphers. Order ChaCha20-Poly1305 relative to AES-GCM based on
+   * hardware support. */
+  if (max_version >= TLS1_3_VERSION) {
+    if (!EVP_has_aes_hardware() &&
+        !CBB_add_u16(&child, TLS1_CK_CHACHA20_POLY1305_SHA256 & 0xffff)) {
+      return 0;
     }
-    if (SSL_CIPHER_get_min_version(cipher) > max_version ||
-        SSL_CIPHER_get_max_version(cipher) < min_version) {
-      continue;
+    if (!CBB_add_u16(&child, TLS1_CK_AES_128_GCM_SHA256 & 0xffff) ||
+        !CBB_add_u16(&child, TLS1_CK_AES_256_GCM_SHA384 & 0xffff)) {
+      return 0;
     }
-    any_enabled = 1;
-    if (!CBB_add_u16(&child, ssl_cipher_get_value(cipher))) {
+    if (EVP_has_aes_hardware() &&
+        !CBB_add_u16(&child, TLS1_CK_CHACHA20_POLY1305_SHA256 & 0xffff)) {
       return 0;
     }
   }
 
-  /* If all ciphers were disabled, return the error to the caller. */
-  if (!any_enabled) {
-    OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CIPHERS_AVAILABLE);
-    return 0;
+  if (min_version < TLS1_3_VERSION) {
+    STACK_OF(SSL_CIPHER) *ciphers = SSL_get_ciphers(ssl);
+    int any_enabled = 0;
+    for (size_t i = 0; i < sk_SSL_CIPHER_num(ciphers); i++) {
+      const SSL_CIPHER *cipher = sk_SSL_CIPHER_value(ciphers, i);
+      /* Skip disabled ciphers */
+      if ((cipher->algorithm_mkey & ssl->cert->mask_k) ||
+          (cipher->algorithm_auth & ssl->cert->mask_a)) {
+        continue;
+      }
+      if (SSL_CIPHER_get_min_version(cipher) > max_version ||
+          SSL_CIPHER_get_max_version(cipher) < min_version) {
+        continue;
+      }
+      any_enabled = 1;
+      if (!CBB_add_u16(&child, ssl_cipher_get_value(cipher))) {
+        return 0;
+      }
+    }
+
+    /* If all ciphers were disabled, return the error to the caller. */
+    if (!any_enabled && max_version < TLS1_3_VERSION) {
+      OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CIPHERS_AVAILABLE);
+      return 0;
+    }
   }
 
   /* For SSLv3, the SCSV is added. Otherwise the renegotiation extension is
@@ -649,43 +666,66 @@
   return CBB_flush(out);
 }
 
-int ssl_add_client_hello_body(SSL *ssl, CBB *body) {
+int ssl_write_client_hello(SSL *ssl) {
   uint16_t min_version, max_version;
   if (!ssl_get_version_range(ssl, &min_version, &max_version)) {
     return 0;
   }
 
+  CBB cbb, body;
+  if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_CLIENT_HELLO)) {
+    goto err;
+  }
+
   /* Renegotiations do not participate in session resumption. */
   int has_session = ssl->session != NULL &&
                     !ssl->s3->initial_handshake_complete;
 
   CBB child;
-  if (!CBB_add_u16(body, ssl->client_version) ||
-      !CBB_add_bytes(body, ssl->s3->client_random, SSL3_RANDOM_SIZE) ||
-      !CBB_add_u8_length_prefixed(body, &child) ||
+  if (!CBB_add_u16(&body, ssl->client_version) ||
+      !CBB_add_bytes(&body, ssl->s3->client_random, SSL3_RANDOM_SIZE) ||
+      !CBB_add_u8_length_prefixed(&body, &child) ||
       (has_session &&
        !CBB_add_bytes(&child, ssl->session->session_id,
                       ssl->session->session_id_length))) {
-    return 0;
+    goto err;
   }
 
   if (SSL_is_dtls(ssl)) {
-    if (!CBB_add_u8_length_prefixed(body, &child) ||
+    if (!CBB_add_u8_length_prefixed(&body, &child) ||
         !CBB_add_bytes(&child, ssl->d1->cookie, ssl->d1->cookie_len)) {
-      return 0;
+      goto err;
     }
   }
 
   size_t header_len =
       SSL_is_dtls(ssl) ? DTLS1_HM_HEADER_LENGTH : SSL3_HM_HEADER_LENGTH;
-  if (!ssl_write_client_cipher_list(ssl, body, min_version, max_version) ||
-      !CBB_add_u8(body, 1 /* one compression method */) ||
-      !CBB_add_u8(body, 0 /* null compression */) ||
-      !ssl_add_clienthello_tlsext(ssl, body, header_len + CBB_len(body))) {
-    return 0;
+  if (!ssl_write_client_cipher_list(ssl, &body, min_version, max_version) ||
+      !CBB_add_u8(&body, 1 /* one compression method */) ||
+      !CBB_add_u8(&body, 0 /* null compression */) ||
+      !ssl_add_clienthello_tlsext(ssl, &body, header_len + CBB_len(&body))) {
+    goto err;
   }
 
-  return 1;
+  uint8_t *msg = NULL;
+  size_t len;
+  if (!ssl->method->finish_message(ssl, &cbb, &msg, &len)) {
+    goto err;
+  }
+
+  /* Now that the length prefixes have been computed, fill in the placeholder
+   * PSK binder. */
+  if (ssl->s3->hs->needs_psk_binder &&
+      !tls13_write_psk_binder(ssl, msg, len)) {
+    OPENSSL_free(msg);
+    goto err;
+  }
+
+  return ssl->method->queue_message(ssl, msg, len);
+
+ err:
+  CBB_cleanup(&cbb);
+  return 0;
 }
 
 static int ssl3_send_client_hello(SSL *ssl) {
@@ -700,12 +740,9 @@
     return -1;
   }
 
-  CBB cbb;
-  CBB_zero(&cbb);
-
   uint16_t min_version, max_version;
   if (!ssl_get_version_range(ssl, &min_version, &max_version)) {
-    goto err;
+    return -1;
   }
 
   assert(ssl->state == SSL3_ST_CW_CLNT_HELLO_A);
@@ -741,22 +778,15 @@
    * renegerate the client_random. The random must be reused. */
   if ((!SSL_is_dtls(ssl) || !ssl->d1->send_cookie) &&
       !RAND_bytes(ssl->s3->client_random, sizeof(ssl->s3->client_random))) {
-    goto err;
+    return -1;
   }
 
-  CBB body;
-  if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_CLIENT_HELLO) ||
-      !ssl_add_client_hello_body(ssl, &body) ||
-      !ssl->method->finish_message(ssl, &cbb)) {
-    goto err;
+  if (!ssl_write_client_hello(ssl)) {
+    return -1;
   }
 
   ssl->state = SSL3_ST_CW_CLNT_HELLO_B;
   return ssl->method->write_message(ssl);
-
-err:
-  CBB_cleanup(&cbb);
-  return -1;
 }
 
 static int dtls1_get_hello_verify(SSL *ssl) {
@@ -802,8 +832,6 @@
 }
 
 static int ssl3_get_server_hello(SSL *ssl) {
-  STACK_OF(SSL_CIPHER) *sk;
-  const SSL_CIPHER *c;
   CERT *ct = ssl->cert;
   int al = SSL_AD_INTERNAL_ERROR;
   CBS server_hello, server_random, session_id;
@@ -911,26 +939,19 @@
            CBS_len(&session_id));
   }
 
-  c = SSL_get_cipher_by_value(cipher_suite);
+  const SSL_CIPHER *c = SSL_get_cipher_by_value(cipher_suite);
   if (c == NULL) {
     /* unknown cipher */
     al = SSL_AD_ILLEGAL_PARAMETER;
     OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CIPHER_RETURNED);
     goto f_err;
   }
-  /* If the cipher is disabled then we didn't sent it in the ClientHello, so if
-   * the server selected it, it's an error. */
+
+  /* The cipher must be allowed in the selected version and enabled. */
   if ((c->algorithm_mkey & ct->mask_k) || (c->algorithm_auth & ct->mask_a) ||
       SSL_CIPHER_get_min_version(c) > ssl3_protocol_version(ssl) ||
-      SSL_CIPHER_get_max_version(c) < ssl3_protocol_version(ssl)) {
-    al = SSL_AD_ILLEGAL_PARAMETER;
-    OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CIPHER_RETURNED);
-    goto f_err;
-  }
-
-  sk = ssl_get_ciphers_by_id(ssl);
-  if (!sk_SSL_CIPHER_find(sk, NULL, c)) {
-    /* we did not say we would use this cipher */
+      SSL_CIPHER_get_max_version(c) < ssl3_protocol_version(ssl) ||
+      !sk_SSL_CIPHER_find(SSL_get_ciphers(ssl), NULL, c)) {
     al = SSL_AD_ILLEGAL_PARAMETER;
     OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CIPHER_RETURNED);
     goto f_err;
@@ -1041,14 +1062,14 @@
     goto err;
   }
 
-  /* NOTE: Unlike the server half, the client's copy of |cert_chain| includes
+  /* NOTE: Unlike the server half, the client's copy of |x509_chain| includes
    * the leaf. */
-  sk_X509_pop_free(ssl->s3->new_session->cert_chain, X509_free);
-  ssl->s3->new_session->cert_chain = chain;
+  sk_X509_pop_free(ssl->s3->new_session->x509_chain, X509_free);
+  ssl->s3->new_session->x509_chain = chain;
 
-  X509_free(ssl->s3->new_session->peer);
+  X509_free(ssl->s3->new_session->x509_peer);
   X509_up_ref(leaf);
-  ssl->s3->new_session->peer = leaf;
+  ssl->s3->new_session->x509_peer = leaf;
 
   return 1;
 
@@ -1100,7 +1121,7 @@
 
 static int ssl3_verify_server_cert(SSL *ssl) {
   if (!ssl_verify_cert_chain(ssl, &ssl->s3->new_session->verify_result,
-                             ssl->s3->new_session->cert_chain)) {
+                             ssl->s3->new_session->x509_chain)) {
     return -1;
   }
 
@@ -1274,7 +1295,7 @@
 
   /* ServerKeyExchange should be signed by the server's public key. */
   if (ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher)) {
-    pkey = X509_get_pubkey(ssl->s3->new_session->peer);
+    pkey = X509_get_pubkey(ssl->s3->new_session->x509_peer);
     if (pkey == NULL) {
       goto err;
     }
@@ -1455,6 +1476,7 @@
         return -1;
       }
       if (ret == 0) {
+        OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_CB_ERROR);
         ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
         return -1;
       }
@@ -1562,7 +1584,7 @@
       goto err;
     }
 
-    EVP_PKEY *pkey = X509_get_pubkey(ssl->s3->new_session->peer);
+    EVP_PKEY *pkey = X509_get_pubkey(ssl->s3->new_session->x509_peer);
     if (pkey == NULL) {
       goto err;
     }
@@ -1668,7 +1690,7 @@
 
   /* The message must be added to the finished hash before calculating the
    * master secret. */
-  if (!ssl->method->finish_message(ssl, &cbb)) {
+  if (!ssl_complete_message(ssl, &cbb)) {
     goto err;
   }
   ssl->state = SSL3_ST_CW_KEY_EXCH_B;
@@ -1785,7 +1807,7 @@
   }
 
   if (!CBB_did_write(&child, sig_len) ||
-      !ssl->method->finish_message(ssl, &cbb)) {
+      !ssl_complete_message(ssl, &cbb)) {
     goto err;
   }
 
@@ -1814,7 +1836,7 @@
                      ssl->s3->next_proto_negotiated_len) ||
       !CBB_add_u8_length_prefixed(&body, &child) ||
       !CBB_add_bytes(&child, kZero, padding_len) ||
-      !ssl->method->finish_message(ssl, &cbb)) {
+      !ssl_complete_message(ssl, &cbb)) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
     CBB_cleanup(&cbb);
     return -1;
@@ -1831,16 +1853,8 @@
 
   assert(ssl->state == SSL3_ST_CW_CHANNEL_ID_A);
 
-  if (ssl->tlsext_channel_id_private == NULL &&
-      ssl->ctx->channel_id_cb != NULL) {
-    EVP_PKEY *key = NULL;
-    ssl->ctx->channel_id_cb(ssl, &key);
-    if (key != NULL &&
-        !SSL_set1_tls_channel_id(ssl, key)) {
-      EVP_PKEY_free(key);
-      return -1;
-    }
-    EVP_PKEY_free(key);
+  if (!ssl_do_channel_id_callback(ssl)) {
+    return -1;
   }
 
   if (ssl->tlsext_channel_id_private == NULL) {
@@ -1848,55 +1862,17 @@
     return -1;
   }
 
-  EC_KEY *ec_key = EVP_PKEY_get0_EC_KEY(ssl->tlsext_channel_id_private);
-  if (ec_key == NULL) {
+  CBB cbb, body;
+  if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_CHANNEL_ID) ||
+      !tls1_write_channel_id(ssl, &body) ||
+      !ssl_complete_message(ssl, &cbb)) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+    CBB_cleanup(&cbb);
     return -1;
   }
 
-  int ret = -1;
-  BIGNUM *x = BN_new();
-  BIGNUM *y = BN_new();
-  ECDSA_SIG *sig = NULL;
-  if (x == NULL || y == NULL ||
-      !EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(ec_key),
-                                           EC_KEY_get0_public_key(ec_key),
-                                           x, y, NULL)) {
-    goto err;
-  }
-
-  uint8_t digest[EVP_MAX_MD_SIZE];
-  size_t digest_len;
-  if (!tls1_channel_id_hash(ssl, digest, &digest_len)) {
-    goto err;
-  }
-
-  sig = ECDSA_do_sign(digest, digest_len, ec_key);
-  if (sig == NULL) {
-    goto err;
-  }
-
-  CBB cbb, body, child;
-  if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_CHANNEL_ID) ||
-      !CBB_add_u16(&body, TLSEXT_TYPE_channel_id) ||
-      !CBB_add_u16_length_prefixed(&body, &child) ||
-      !BN_bn2cbb_padded(&child, 32, x) || !BN_bn2cbb_padded(&child, 32, y) ||
-      !BN_bn2cbb_padded(&child, 32, sig->r) ||
-      !BN_bn2cbb_padded(&child, 32, sig->s) ||
-      !ssl->method->finish_message(ssl, &cbb)) {
-    OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
-    CBB_cleanup(&cbb);
-    goto err;
-  }
-
   ssl->state = SSL3_ST_CW_CHANNEL_ID_B;
-  ret = ssl->method->write_message(ssl);
-
-err:
-  BN_free(x);
-  BN_free(y);
-  ECDSA_SIG_free(sig);
-  return ret;
+  return ssl->method->write_message(ssl);
 }
 
 static int ssl3_get_new_session_ticket(SSL *ssl) {
@@ -1919,10 +1895,9 @@
 
   if (CBS_len(&ticket) == 0) {
     /* RFC 5077 allows a server to change its mind and send no ticket after
-     * negotiating the extension. The value of |tlsext_ticket_expected| is
-     * checked in |ssl_update_cache| so is cleared here to avoid an unnecessary
-     * update. */
-    ssl->tlsext_ticket_expected = 0;
+     * negotiating the extension. The value of |ticket_expected| is checked in
+     * |ssl_update_cache| so is cleared here to avoid an unnecessary update. */
+    ssl->s3->hs->ticket_expected = 0;
     return 1;
   }
 
@@ -1940,6 +1915,9 @@
     }
   }
 
+  /* |tlsext_tick_lifetime_hint| is measured from when the ticket was issued. */
+  ssl_session_refresh_time(ssl, session);
+
   if (!CBS_stow(&ticket, &session->tlsext_tick, &session->tlsext_ticklen)) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
     goto err;
diff --git a/src/ssl/handshake_server.c b/src/ssl/handshake_server.c
index e018680..3b66ab7 100644
--- a/src/ssl/handshake_server.c
+++ b/src/ssl/handshake_server.c
@@ -231,6 +231,7 @@
       case SSL3_ST_SR_CLNT_HELLO_B:
       case SSL3_ST_SR_CLNT_HELLO_C:
       case SSL3_ST_SR_CLNT_HELLO_D:
+      case SSL3_ST_SR_CLNT_HELLO_E:
         ret = ssl3_get_client_hello(ssl);
         if (ssl->state == SSL_ST_TLS13) {
           break;
@@ -415,7 +416,7 @@
 
       case SSL3_ST_SW_SESSION_TICKET_A:
       case SSL3_ST_SW_SESSION_TICKET_B:
-        if (ssl->tlsext_ticket_expected) {
+        if (ssl->s3->hs->ticket_expected) {
           ret = ssl3_send_new_session_ticket(ssl);
           if (ret <= 0) {
             goto end;
@@ -476,18 +477,16 @@
         break;
 
       case SSL_ST_OK:
-        /* Clean a few things up. */
-        ssl3_cleanup_key_block(ssl);
         ssl->method->release_current_message(ssl, 1 /* free_buffer */);
 
         /* If we aren't retaining peer certificates then we can discard it
          * now. */
         if (ssl->s3->new_session != NULL &&
-            ssl->ctx->retain_only_sha256_of_client_certs) {
-          X509_free(ssl->s3->new_session->peer);
-          ssl->s3->new_session->peer = NULL;
-          sk_X509_pop_free(ssl->s3->new_session->cert_chain, X509_free);
-          ssl->s3->new_session->cert_chain = NULL;
+            ssl->retain_only_sha256_of_client_certs) {
+          X509_free(ssl->s3->new_session->x509_peer);
+          ssl->s3->new_session->x509_peer = NULL;
+          sk_X509_pop_free(ssl->s3->new_session->x509_chain, X509_free);
+          ssl->s3->new_session->x509_chain = NULL;
         }
 
         SSL_SESSION_free(ssl->s3->established_session);
@@ -503,15 +502,13 @@
         /* remove buffering on output */
         ssl_free_wbio_buffer(ssl);
 
+        ssl->s3->initial_handshake_complete = 1;
+        ssl_update_cache(ssl, SSL_SESS_CACHE_SERVER);
+
         ssl_handshake_free(ssl->s3->hs);
         ssl->s3->hs = NULL;
 
-        ssl->s3->initial_handshake_complete = 1;
-
-        ssl_update_cache(ssl, SSL_SESS_CACHE_SERVER);
-
         ssl_do_info_callback(ssl, SSL_CB_HANDSHAKE_DONE, 1);
-
         ret = 1;
         goto end;
 
@@ -556,7 +553,7 @@
 }
 
 static int negotiate_version(
-    SSL *ssl, int *out_alert,
+    SSL *ssl, uint8_t *out_alert,
     const struct ssl_early_callback_ctx *client_hello) {
   uint16_t min_version, max_version;
   if (!ssl_get_version_range(ssl, &min_version, &max_version)) {
@@ -578,6 +575,9 @@
       return 0;
     }
 
+    /* Choose the newest commonly-supported version advertised by the client.
+     * The client orders the versions according to its preferences, but we're
+     * not required to honor the client's preferences. */
     int found_version = 0;
     while (CBS_len(&versions) != 0) {
       uint16_t ext_version;
@@ -590,10 +590,10 @@
         continue;
       }
       if (min_version <= ext_version &&
-          ext_version <= max_version) {
+          ext_version <= max_version &&
+          (!found_version || version < ext_version)) {
         version = ext_version;
         found_version = 1;
-        break;
       }
     }
 
@@ -662,7 +662,8 @@
 }
 
 static int ssl3_get_client_hello(SSL *ssl) {
-  int al = SSL_AD_INTERNAL_ERROR, ret = -1;
+  uint8_t al = SSL_AD_INTERNAL_ERROR;
+  int ret = -1;
   SSL_SESSION *session = NULL;
 
   if (ssl->state == SSL3_ST_SR_CLNT_HELLO_A) {
@@ -729,76 +730,6 @@
     memcpy(ssl->s3->client_random, client_hello.random,
            client_hello.random_len);
 
-    /* Determine whether we are doing session resumption. */
-    int send_new_ticket = 0;
-    switch (
-        ssl_get_prev_session(ssl, &session, &send_new_ticket, &client_hello)) {
-      case ssl_session_success:
-        break;
-      case ssl_session_error:
-        goto err;
-      case ssl_session_retry:
-        ssl->rwstate = SSL_PENDING_SESSION;
-        goto err;
-    }
-    ssl->tlsext_ticket_expected = send_new_ticket;
-
-    /* The EMS state is needed when making the resumption decision, but
-     * extensions are not normally parsed until later. This detects the EMS
-     * extension for the resumption decision and it's checked against the result
-     * of the normal parse later in this function. */
-    CBS ems;
-    int have_extended_master_secret =
-        ssl->version != SSL3_VERSION &&
-        ssl_early_callback_get_extension(&client_hello, &ems,
-                                         TLSEXT_TYPE_extended_master_secret) &&
-        CBS_len(&ems) == 0;
-
-    int has_session = 0;
-    if (session != NULL) {
-      if (session->extended_master_secret &&
-          !have_extended_master_secret) {
-        /* A ClientHello without EMS that attempts to resume a session with EMS
-         * is fatal to the connection. */
-        al = SSL_AD_HANDSHAKE_FAILURE;
-        OPENSSL_PUT_ERROR(SSL, SSL_R_RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION);
-        goto f_err;
-      }
-
-      has_session =
-          /* Only resume if the session's version matches the negotiated
-           * version: most clients do not accept a mismatch. */
-          ssl->version == session->ssl_version &&
-          /* If the client offers the EMS extension, but the previous session
-           * didn't use it, then negotiate a new session. */
-          have_extended_master_secret == session->extended_master_secret;
-    }
-
-    if (has_session) {
-      /* Use the old session. */
-      ssl->session = session;
-      session = NULL;
-      ssl->s3->session_reused = 1;
-    } else {
-      ssl_set_session(ssl, NULL);
-      if (!ssl_get_new_session(ssl, 1 /* server */)) {
-        goto err;
-      }
-
-      /* Clear the session ID if we want the session to be single-use. */
-      if (!(ssl->ctx->session_cache_mode & SSL_SESS_CACHE_SERVER)) {
-        ssl->s3->new_session->session_id_length = 0;
-      }
-    }
-
-    if (ssl->ctx->dos_protection_cb != NULL &&
-        ssl->ctx->dos_protection_cb(&client_hello) == 0) {
-      /* Connection rejected for DOS reasons. */
-      al = SSL_AD_INTERNAL_ERROR;
-      OPENSSL_PUT_ERROR(SSL, SSL_R_CONNECTION_REJECTED);
-      goto f_err;
-    }
-
     /* Only null compression is supported. */
     if (memchr(client_hello.compression_methods, 0,
                client_hello.compression_methods_len) == NULL) {
@@ -813,30 +744,10 @@
       goto err;
     }
 
-    if (have_extended_master_secret != ssl->s3->tmp.extended_master_secret) {
-      al = SSL_AD_INTERNAL_ERROR;
-      OPENSSL_PUT_ERROR(SSL, SSL_R_EMS_STATE_INCONSISTENT);
-      goto f_err;
-    }
-
     ssl->state = SSL3_ST_SR_CLNT_HELLO_D;
   }
 
-  /* Determine the remaining connection parameters. This is a separate state so
-   * |cert_cb| does not cause earlier logic to run multiple times. */
-  assert(ssl->state == SSL3_ST_SR_CLNT_HELLO_D);
-
-  if (ssl->session != NULL) {
-    /* Check that the cipher is in the list. */
-    if (!ssl_client_cipher_list_contains_cipher(
-            &client_hello, (uint16_t)ssl->session->cipher->id)) {
-      al = SSL_AD_ILLEGAL_PARAMETER;
-      OPENSSL_PUT_ERROR(SSL, SSL_R_REQUIRED_CIPHER_MISSING);
-      goto f_err;
-    }
-
-    ssl->s3->tmp.new_cipher = ssl->session->cipher;
-  } else {
+  if (ssl->state == SSL3_ST_SR_CLNT_HELLO_D) {
     /* Call |cert_cb| to update server certificates if required. */
     if (ssl->cert->cert_cb != NULL) {
       int rv = ssl->cert->cert_cb(ssl, ssl->cert->cert_cb_arg);
@@ -851,16 +762,92 @@
       }
     }
 
-    const SSL_CIPHER *c =
+    /* Negotiate the cipher suite. This must be done after |cert_cb| so the
+     * certificate is finalized. */
+    ssl->s3->tmp.new_cipher =
         ssl3_choose_cipher(ssl, &client_hello, ssl_get_cipher_preferences(ssl));
-    if (c == NULL) {
+    if (ssl->s3->tmp.new_cipher == NULL) {
       al = SSL_AD_HANDSHAKE_FAILURE;
       OPENSSL_PUT_ERROR(SSL, SSL_R_NO_SHARED_CIPHER);
       goto f_err;
     }
 
-    ssl->s3->new_session->cipher = c;
-    ssl->s3->tmp.new_cipher = c;
+    ssl->state = SSL3_ST_SR_CLNT_HELLO_E;
+  }
+
+  assert(ssl->state == SSL3_ST_SR_CLNT_HELLO_E);
+
+  /* Determine whether we are doing session resumption. */
+  int tickets_supported = 0, renew_ticket = 0;
+  switch (ssl_get_prev_session(ssl, &session, &tickets_supported, &renew_ticket,
+                               &client_hello)) {
+    case ssl_session_success:
+      break;
+    case ssl_session_error:
+      goto err;
+    case ssl_session_retry:
+      ssl->rwstate = SSL_PENDING_SESSION;
+      goto err;
+  }
+
+  if (session != NULL) {
+    if (session->extended_master_secret &&
+        !ssl->s3->tmp.extended_master_secret) {
+      /* A ClientHello without EMS that attempts to resume a session with EMS
+       * is fatal to the connection. */
+      al = SSL_AD_HANDSHAKE_FAILURE;
+      OPENSSL_PUT_ERROR(SSL, SSL_R_RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION);
+      goto f_err;
+    }
+
+    if (!ssl_session_is_resumable(ssl, session) ||
+        /* If the client offers the EMS extension, but the previous session
+         * didn't use it, then negotiate a new session. */
+        ssl->s3->tmp.extended_master_secret !=
+            session->extended_master_secret) {
+      SSL_SESSION_free(session);
+      session = NULL;
+    }
+  }
+
+  if (session != NULL) {
+    /* Use the old session. */
+    ssl->s3->hs->ticket_expected = renew_ticket;
+    ssl->session = session;
+    session = NULL;
+    ssl->s3->session_reused = 1;
+  } else {
+    ssl->s3->hs->ticket_expected = tickets_supported;
+    ssl_set_session(ssl, NULL);
+    if (!ssl_get_new_session(ssl, 1 /* server */)) {
+      goto err;
+    }
+
+    /* Clear the session ID if we want the session to be single-use. */
+    if (!(ssl->ctx->session_cache_mode & SSL_SESS_CACHE_SERVER)) {
+      ssl->s3->new_session->session_id_length = 0;
+    }
+  }
+
+  if (ssl->ctx->dos_protection_cb != NULL &&
+      ssl->ctx->dos_protection_cb(&client_hello) == 0) {
+    /* Connection rejected for DOS reasons. */
+    al = SSL_AD_INTERNAL_ERROR;
+    OPENSSL_PUT_ERROR(SSL, SSL_R_CONNECTION_REJECTED);
+    goto f_err;
+  }
+
+  if (ssl->session == NULL) {
+    ssl->s3->new_session->cipher = ssl->s3->tmp.new_cipher;
+
+    /* On new sessions, stash the SNI value in the session. */
+    if (ssl->s3->hs->hostname != NULL) {
+      ssl->s3->new_session->tlsext_hostname = BUF_strdup(ssl->s3->hs->hostname);
+      if (ssl->s3->new_session->tlsext_hostname == NULL) {
+        al = SSL_AD_INTERNAL_ERROR;
+        goto f_err;
+      }
+    }
 
     /* Determine whether to request a client certificate. */
     ssl->s3->hs->cert_request = !!(ssl->verify_mode & SSL_VERIFY_PEER);
@@ -881,7 +868,13 @@
     }
   }
 
-  /* Now that the cipher is known, initialize the handshake hash. */
+  /* HTTP/2 negotiation depends on the cipher suite, so ALPN negotiation was
+   * deferred. Complete it now. */
+  if (!ssl_negotiate_alpn(ssl, &al, &client_hello)) {
+    goto f_err;
+  }
+
+  /* Now that all parameters are known, initialize the handshake hash. */
   if (!ssl3_init_handshake_hash(ssl)) {
     goto f_err;
   }
@@ -953,7 +946,7 @@
       !CBB_add_u16(&body, ssl_cipher_get_value(ssl->s3->tmp.new_cipher)) ||
       !CBB_add_u8(&body, 0 /* no compression */) ||
       !ssl_add_serverhello_tlsext(ssl, &body) ||
-      !ssl->method->finish_message(ssl, &cbb)) {
+      !ssl_complete_message(ssl, &cbb)) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
     CBB_cleanup(&cbb);
     return -1;
@@ -992,7 +985,7 @@
       !CBB_add_u24_length_prefixed(&body, &ocsp_response) ||
       !CBB_add_bytes(&ocsp_response, ssl->ctx->ocsp_response,
                      ssl->ctx->ocsp_response_length) ||
-      !ssl->method->finish_message(ssl, &cbb)) {
+      !ssl_complete_message(ssl, &cbb)) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
     CBB_cleanup(&cbb);
     return -1;
@@ -1173,7 +1166,7 @@
     }
   }
 
-  if (!ssl->method->finish_message(ssl, &cbb)) {
+  if (!ssl_complete_message(ssl, &cbb)) {
     goto err;
   }
 
@@ -1255,7 +1248,7 @@
   }
 
   if (!ssl_add_client_CA_list(ssl, &body) ||
-      !ssl->method->finish_message(ssl, &cbb)) {
+      !ssl_complete_message(ssl, &cbb)) {
     goto err;
   }
 
@@ -1275,7 +1268,7 @@
 
   CBB cbb, body;
   if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_SERVER_HELLO_DONE) ||
-      !ssl->method->finish_message(ssl, &cbb)) {
+      !ssl_complete_message(ssl, &cbb)) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
     CBB_cleanup(&cbb);
     return -1;
@@ -1320,7 +1313,7 @@
   CBS_init(&certificate_msg, ssl->init_msg, ssl->init_num);
   uint8_t alert;
   STACK_OF(X509) *chain = ssl_parse_cert_chain(
-      ssl, &alert, ssl->ctx->retain_only_sha256_of_client_certs
+      ssl, &alert, ssl->retain_only_sha256_of_client_certs
                        ? ssl->s3->new_session->peer_sha256
                        : NULL,
       &certificate_msg);
@@ -1359,7 +1352,7 @@
     ssl->s3->new_session->verify_result = X509_V_OK;
   } else {
     /* The hash would have been filled in. */
-    if (ssl->ctx->retain_only_sha256_of_client_certs) {
+    if (ssl->retain_only_sha256_of_client_certs) {
       ssl->s3->new_session->peer_sha256_valid = 1;
     }
 
@@ -1369,12 +1362,12 @@
     }
   }
 
-  X509_free(ssl->s3->new_session->peer);
-  ssl->s3->new_session->peer = sk_X509_shift(chain);
+  X509_free(ssl->s3->new_session->x509_peer);
+  ssl->s3->new_session->x509_peer = sk_X509_shift(chain);
 
-  sk_X509_pop_free(ssl->s3->new_session->cert_chain, X509_free);
-  ssl->s3->new_session->cert_chain = chain;
-  /* Inconsistency alert: cert_chain does *not* include the peer's own
+  sk_X509_pop_free(ssl->s3->new_session->x509_chain, X509_free);
+  ssl->s3->new_session->x509_chain = chain;
+  /* Inconsistency alert: x509_chain does *not* include the peer's own
    * certificate, while we do include it in s3_clnt.c */
 
   return 1;
@@ -1656,7 +1649,7 @@
 static int ssl3_get_cert_verify(SSL *ssl) {
   int al, ret = 0;
   CBS certificate_verify, signature;
-  X509 *peer = ssl->s3->new_session->peer;
+  X509 *peer = ssl->s3->new_session->x509_peer;
   EVP_PKEY *pkey = NULL;
 
   /* Only RSA and ECDSA client certificates are supported, so a
@@ -1750,7 +1743,7 @@
   /* The handshake buffer is no longer necessary, and we may hash the current
    * message.*/
   ssl3_free_handshake_buffer(ssl);
-  if (!ssl->method->hash_current_message(ssl)) {
+  if (!ssl_hash_current_message(ssl)) {
     goto err;
   }
 
@@ -1796,109 +1789,17 @@
 
 /* ssl3_get_channel_id reads and verifies a ClientID handshake message. */
 static int ssl3_get_channel_id(SSL *ssl) {
-  int ret = -1;
-  uint8_t channel_id_hash[EVP_MAX_MD_SIZE];
-  size_t channel_id_hash_len;
-  const uint8_t *p;
-  uint16_t extension_type;
-  EC_GROUP *p256 = NULL;
-  EC_KEY *key = NULL;
-  EC_POINT *point = NULL;
-  ECDSA_SIG sig;
-  BIGNUM x, y;
-  CBS encrypted_extensions, extension;
-
   int msg_ret = ssl->method->ssl_get_message(ssl, SSL3_MT_CHANNEL_ID,
                                              ssl_dont_hash_message);
   if (msg_ret <= 0) {
     return msg_ret;
   }
 
-  /* Before incorporating the EncryptedExtensions message to the handshake
-   * hash, compute the hash that should have been signed. */
-  if (!tls1_channel_id_hash(ssl, channel_id_hash, &channel_id_hash_len)) {
+  if (!tls1_verify_channel_id(ssl) ||
+      !ssl_hash_current_message(ssl)) {
     return -1;
   }
-  assert(channel_id_hash_len == SHA256_DIGEST_LENGTH);
-
-  if (!ssl->method->hash_current_message(ssl)) {
-    return -1;
-  }
-
-  CBS_init(&encrypted_extensions, ssl->init_msg, ssl->init_num);
-
-  /* EncryptedExtensions could include multiple extensions, but the only
-   * extension that could be negotiated is Channel ID, so there can only be one
-   * entry. */
-  if (!CBS_get_u16(&encrypted_extensions, &extension_type) ||
-      !CBS_get_u16_length_prefixed(&encrypted_extensions, &extension) ||
-      CBS_len(&encrypted_extensions) != 0 ||
-      extension_type != TLSEXT_TYPE_channel_id ||
-      CBS_len(&extension) != TLSEXT_CHANNEL_ID_SIZE) {
-    OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
-    ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
-    return -1;
-  }
-
-  p256 = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
-  if (!p256) {
-    OPENSSL_PUT_ERROR(SSL, SSL_R_NO_P256_SUPPORT);
-    return -1;
-  }
-
-  BN_init(&x);
-  BN_init(&y);
-  sig.r = BN_new();
-  sig.s = BN_new();
-  if (sig.r == NULL || sig.s == NULL) {
-    goto err;
-  }
-
-  p = CBS_data(&extension);
-  if (BN_bin2bn(p + 0, 32, &x) == NULL ||
-      BN_bin2bn(p + 32, 32, &y) == NULL ||
-      BN_bin2bn(p + 64, 32, sig.r) == NULL ||
-      BN_bin2bn(p + 96, 32, sig.s) == NULL) {
-    goto err;
-  }
-
-  point = EC_POINT_new(p256);
-  if (!point ||
-      !EC_POINT_set_affine_coordinates_GFp(p256, point, &x, &y, NULL)) {
-    goto err;
-  }
-
-  key = EC_KEY_new();
-  if (!key || !EC_KEY_set_group(key, p256) ||
-      !EC_KEY_set_public_key(key, point)) {
-    goto err;
-  }
-
-  /* We stored the handshake hash in |tlsext_channel_id| the first time that we
-   * were called. */
-  int sig_ok = ECDSA_do_verify(channel_id_hash, channel_id_hash_len, &sig, key);
-#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
-  sig_ok = 1;
-#endif
-  if (!sig_ok) {
-    OPENSSL_PUT_ERROR(SSL, SSL_R_CHANNEL_ID_SIGNATURE_INVALID);
-    ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECRYPT_ERROR);
-    ssl->s3->tlsext_channel_id_valid = 0;
-    goto err;
-  }
-
-  memcpy(ssl->s3->tlsext_channel_id, p, 64);
-  ret = 1;
-
-err:
-  BN_free(&x);
-  BN_free(&y);
-  BN_free(sig.r);
-  BN_free(sig.s);
-  EC_KEY_free(key);
-  EC_POINT_free(point);
-  EC_GROUP_free(p256);
-  return ret;
+  return 1;
 }
 
 static int ssl3_send_new_session_ticket(SSL *ssl) {
@@ -1906,20 +1807,37 @@
     return ssl->method->write_message(ssl);
   }
 
+  const SSL_SESSION *session;
+  SSL_SESSION *session_copy = NULL;
+  if (ssl->session == NULL) {
+    /* Fix the timeout to measure from the ticket issuance time. */
+    ssl_session_refresh_time(ssl, ssl->s3->new_session);
+    session = ssl->s3->new_session;
+  } else {
+    /* We are renewing an existing session. Duplicate the session to adjust the
+     * timeout. */
+    session_copy = SSL_SESSION_dup(ssl->session, SSL_SESSION_INCLUDE_NONAUTH);
+    if (session_copy == NULL) {
+      return -1;
+    }
+
+    ssl_session_refresh_time(ssl, session_copy);
+    session = session_copy;
+  }
+
   CBB cbb, body, ticket;
-  if (!ssl->method->init_message(ssl, &cbb, &body,
-                                 SSL3_MT_NEW_SESSION_TICKET) ||
-      /* Ticket lifetime hint (advisory only): We leave this unspecified for
-       * resumed session (for simplicity), and guess that tickets for new
-       * sessions will live as long as their sessions. */
-      !CBB_add_u32(&body,
-                   ssl->session != NULL ? 0 : ssl->s3->new_session->timeout) ||
-      !CBB_add_u16_length_prefixed(&body, &ticket) ||
-      !ssl_encrypt_ticket(ssl, &ticket, ssl->session != NULL
-                                            ? ssl->session
-                                            : ssl->s3->new_session) ||
-      !ssl->method->finish_message(ssl, &cbb)) {
-    return 0;
+  int ok =
+      ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_NEW_SESSION_TICKET) &&
+      CBB_add_u32(&body, session->timeout) &&
+      CBB_add_u16_length_prefixed(&body, &ticket) &&
+      ssl_encrypt_ticket(ssl, &ticket, session) &&
+      ssl_complete_message(ssl, &cbb);
+
+  SSL_SESSION_free(session_copy);
+  CBB_cleanup(&cbb);
+
+  if (!ok) {
+    return -1;
   }
 
   ssl->state = SSL3_ST_SW_SESSION_TICKET_B;
diff --git a/src/ssl/internal.h b/src/ssl/internal.h
index 7e9954d..1d78ec1 100644
--- a/src/ssl/internal.h
+++ b/src/ssl/internal.h
@@ -230,14 +230,12 @@
 
 /* ssl_create_cipher_list evaluates |rule_str| according to the ciphers in
  * |ssl_method|. It sets |*out_cipher_list| to a newly-allocated
- * |ssl_cipher_preference_list_st| containing the result.
- * |*out_cipher_list_by_id| is set to a list of selected ciphers sorted by
- * id. It returns |(*out_cipher_list)->ciphers| on success and NULL on
+ * |ssl_cipher_preference_list_st| containing the result. It returns
+ * |(*out_cipher_list)->ciphers| on success and NULL on
  * failure. */
 STACK_OF(SSL_CIPHER) *
 ssl_create_cipher_list(const SSL_PROTOCOL_METHOD *ssl_method,
                        struct ssl_cipher_preference_list_st **out_cipher_list,
-                       STACK_OF(SSL_CIPHER) **out_cipher_list_by_id,
                        const char *rule_str);
 
 /* ssl_cipher_get_value returns the cipher suite id of |cipher|. */
@@ -269,7 +267,7 @@
 
 /* SSL_AEAD_CTX contains information about an AEAD that is being used to encrypt
  * an SSL connection. */
-struct ssl_aead_ctx_st {
+typedef struct ssl_aead_ctx_st {
   const SSL_CIPHER *cipher;
   EVP_AEAD_CTX ctx;
   /* fixed_nonce contains any bytes of the nonce that are fixed for all
@@ -294,7 +292,7 @@
   /* xor_fixed_nonce is non-zero if the fixed nonce should be XOR'd into the
    * variable nonce rather than prepended. */
   char xor_fixed_nonce;
-} /* SSL_AEAD_CTX */;
+} SSL_AEAD_CTX;
 
 /* SSL_AEAD_CTX_new creates a newly-allocated |SSL_AEAD_CTX| using the supplied
  * key material. It returns NULL on error. Only one of |SSL_AEAD_CTX_open| or
@@ -420,13 +418,6 @@
  * buffer-free APIs are available. */
 size_t ssl_seal_align_prefix_len(const SSL *ssl);
 
-/* ssl_max_seal_overhead returns the maximum overhead of sealing a record with
- * |ssl|.
- *
- * TODO(davidben): Expose this as part of public API once the high-level
- * buffer-free APIs are available. */
-size_t ssl_max_seal_overhead(const SSL *ssl);
-
 /* tls_seal_record seals a new record of type |type| and body |in| and writes it
  * to |out|. At most |max_out| bytes will be written. It returns one on success
  * and zero on error. If enabled, |tls_seal_record| implements TLS 1.0 CBC 1/n-1
@@ -434,7 +425,7 @@
  *
  * For a large record, the bulk of the ciphertext will begin
  * |ssl_seal_align_prefix_len| bytes into out. Aligning |out| appropriately may
- * improve performance. It writes at most |in_len| + |ssl_max_seal_overhead|
+ * improve performance. It writes at most |in_len| + |SSL_max_seal_overhead|
  * bytes to |out|.
  *
  * |in| and |out| may not alias. */
@@ -557,9 +548,11 @@
 
 /* ECDH groups. */
 
+typedef struct ssl_ecdh_ctx_st SSL_ECDH_CTX;
+
 /* An SSL_ECDH_METHOD is an implementation of ECDH-like key exchanges for
  * TLS. */
-struct ssl_ecdh_method_st {
+typedef struct ssl_ecdh_method_st {
   int nid;
   uint16_t group_id;
   const char name[8];
@@ -599,7 +592,12 @@
    * be passed to |offer| or |accept|. It returns one on success and zero on
    * error. */
   int (*add_key)(CBB *cbb, CBB *out_contents);
-} /* SSL_ECDH_METHOD */;
+} SSL_ECDH_METHOD;
+
+struct ssl_ecdh_ctx_st {
+  const SSL_ECDH_METHOD *method;
+  void *data;
+};
 
 /* ssl_nid_to_group_id looks up the group corresponding to |nid|. On success, it
  * sets |*out_group_id| to the group ID and returns one. Otherwise, it returns
@@ -750,6 +748,10 @@
  * configured and zero otherwise. */
 int ssl_has_certificate(const SSL *ssl);
 
+/* ssl_parse_x509 parses a X509 certificate from |cbs|. It returns NULL
+ * on error. */
+X509 *ssl_parse_x509(CBS *cbs);
+
 /* ssl_parse_cert_chain parses a certificate list from |cbs| in the format used
  * by a TLS Certificate message. On success, it returns a newly-allocated
  * |X509| list and advances |cbs|. Otherwise, it returns NULL and sets
@@ -794,21 +796,19 @@
 /* TLS 1.3 key derivation. */
 
 /* tls13_init_key_schedule initializes the handshake hash and key derivation
- * state with the given resumption context. The cipher suite and PRF hash must
- * have been selected at this point. It returns one on success and zero on
- * error. */
-int tls13_init_key_schedule(SSL *ssl, const uint8_t *resumption_ctx,
-                            size_t resumption_ctx_len);
+ * state. The cipher suite and PRF hash must have been selected at this point.
+ * It returns one on success and zero on error. */
+int tls13_init_key_schedule(SSL *ssl);
 
 /* tls13_advance_key_schedule incorporates |in| into the key schedule with
  * HKDF-Extract. It returns one on success and zero on error. */
 int tls13_advance_key_schedule(SSL *ssl, const uint8_t *in, size_t len);
 
-/* tls13_get_context_hashes writes Hash(Handshake Context) +
- * Hash(resumption_context) to |out| which much have room for at least 2 *
- * |EVP_MAX_MD_SIZE| bytes. On success, it returns one and sets |*out_len| to
- * the number of bytes written. Otherwise, it returns zero. */
-int tls13_get_context_hashes(SSL *ssl, uint8_t *out, size_t *out_len);
+/* tls13_get_context_hash writes Hash(Handshake Context) to |out| which must
+ * have room for at least |EVP_MAX_MD_SIZE| bytes. On success, it returns one
+ * and sets |*out_len| to the number of bytes written. Otherwise, it returns
+ * zero. */
+int tls13_get_context_hash(SSL *ssl, uint8_t *out, size_t *out_len);
 
 enum tls_record_type_t {
   type_early_handshake,
@@ -817,11 +817,9 @@
   type_data,
 };
 
-/* tls13_set_traffic_key sets the read or write traffic keys to |traffic_secret|
- * for the given traffic phase |type|. It returns one on success and zero on
- * error. */
-int tls13_set_traffic_key(SSL *ssl, enum tls_record_type_t type,
-                          enum evp_aead_direction_t direction,
+/* tls13_set_traffic_key sets the read or write traffic keys to
+ * |traffic_secret|. It returns one on success and zero on error. */
+int tls13_set_traffic_key(SSL *ssl, enum evp_aead_direction_t direction,
                           const uint8_t *traffic_secret,
                           size_t traffic_secret_len);
 
@@ -834,15 +832,15 @@
  * returns one on success and zero on error. */
 int tls13_rotate_traffic_key(SSL *ssl, enum evp_aead_direction_t direction);
 
-/* tls13_derive_traffic_secret_0 derives the initial application data traffic
- * secret based on the handshake transcripts and |master_secret|. It returns one
- * on success and zero on error. */
-int tls13_derive_traffic_secret_0(SSL *ssl);
+/* tls13_derive_application_secrets derives the initial application data traffic
+ * and exporter secrets based on the handshake transcripts and |master_secret|.
+ * It returns one on success and zero on error. */
+int tls13_derive_application_secrets(SSL *ssl);
 
-/* tls13_finalize_keys derives the |exporter_secret| and |resumption_secret|. */
-int tls13_finalize_keys(SSL *ssl);
+/* tls13_derive_resumption_secret derives the |resumption_secret|. */
+int tls13_derive_resumption_secret(SSL *ssl);
 
-/* tls13_export_keying_material provides and exporter interface to use the
+/* tls13_export_keying_material provides an exporter interface to use the
  * |exporter_secret|. */
 int tls13_export_keying_material(SSL *ssl, uint8_t *out, size_t out_len,
                                  const char *label, size_t label_len,
@@ -855,17 +853,15 @@
  * 0 for the Client Finished. */
 int tls13_finished_mac(SSL *ssl, uint8_t *out, size_t *out_len, int is_server);
 
-/* tls13_resumption_psk calculates the PSK to use for the resumption of
- * |session| and stores the result in |out|. It returns one on success, and
- * zero on failure. */
-int tls13_resumption_psk(SSL *ssl, uint8_t *out, size_t out_len,
-                         const SSL_SESSION *session);
+/* tls13_write_psk_binder calculates the PSK binder value and replaces the last
+ * bytes of |msg| with the resulting value. It returns 1 on success, and 0 on
+ * failure. */
+int tls13_write_psk_binder(SSL *ssl, uint8_t *msg, size_t len);
 
-/* tls13_resumption_context derives the context to be used for the handshake
- * transcript on the resumption of |session|. It returns one on success, and
- * zero on failure. */
-int tls13_resumption_context(SSL *ssl, uint8_t *out, size_t out_len,
-                             const SSL_SESSION *session);
+/* tls13_verify_psk_binder verifies that the handshake transcript, truncated
+ * up to the binders has a valid signature using the value of |session|'s
+ * resumption secret. It returns 1 on success, and 0 on failure. */
+int tls13_verify_psk_binder(SSL *ssl, SSL_SESSION *session, CBS *binders);
 
 
 /* Handshake functions. */
@@ -878,10 +874,11 @@
   ssl_hs_flush,
   ssl_hs_flush_and_read_message,
   ssl_hs_x509_lookup,
+  ssl_hs_channel_id_lookup,
   ssl_hs_private_key_operation,
 };
 
-struct ssl_handshake_st {
+typedef struct ssl_handshake_st {
   /* wait contains the operation |do_handshake| is currently blocking on or
    * |ssl_hs_ok| if none. */
   enum ssl_hs_wait_t wait;
@@ -894,7 +891,6 @@
   int state;
 
   size_t hash_len;
-  uint8_t resumption_hash[EVP_MAX_MD_SIZE];
   uint8_t secret[EVP_MAX_MD_SIZE];
   uint8_t client_traffic_secret_0[EVP_MAX_MD_SIZE];
   uint8_t server_traffic_secret_0[EVP_MAX_MD_SIZE];
@@ -923,8 +919,19 @@
   /* ecdh_ctx is the current ECDH instance. */
   SSL_ECDH_CTX ecdh_ctx;
 
+  /* scts_requested is one if the SCT extension is in the ClientHello. */
+  unsigned scts_requested:1;
+
+  /* needs_psk_binder if the ClientHello has a placeholder PSK binder to be
+   * filled in. */
+  unsigned needs_psk_binder:1;
+
   unsigned received_hello_retry_request:1;
 
+  /* accept_psk_mode stores whether the client's PSK mode is compatible with our
+   * preferences. */
+  unsigned accept_psk_mode:1;
+
   /* retry_group is the group ID selected by the server in HelloRetryRequest in
    * TLS 1.3. */
   uint16_t retry_group;
@@ -992,6 +999,10 @@
   /* next_proto_neg_seen is one of NPN was negotiated. */
   unsigned next_proto_neg_seen:1;
 
+  /* ticket_expected is one if a TLS 1.2 NewSessionTicket message is to be sent
+   * or received. */
+  unsigned ticket_expected:1;
+
   /* peer_psk_identity_hint, on the client, is the psk_identity_hint sent by the
    * server when using a TLS 1.2 PSK key exchange. */
   char *peer_psk_identity_hint;
@@ -1004,7 +1015,14 @@
    * received in a CertificateRequest message. */
   uint8_t *certificate_types;
   size_t num_certificate_types;
-} /* SSL_HANDSHAKE */;
+
+  /* key_block is the record-layer key block for TLS 1.2 and earlier. */
+  uint8_t *key_block;
+  uint8_t key_block_len;
+
+  /* hostname, on the server, is the value of the SNI extension. */
+  char *hostname;
+} SSL_HANDSHAKE;
 
 SSL_HANDSHAKE *ssl_handshake_new(enum ssl_hs_wait_t (*do_handshake)(SSL *ssl));
 
@@ -1051,15 +1069,56 @@
                                              CBS *contents);
 int ssl_ext_pre_shared_key_parse_clienthello(SSL *ssl,
                                              SSL_SESSION **out_session,
+                                             CBS *out_binders,
                                              uint8_t *out_alert, CBS *contents);
 int ssl_ext_pre_shared_key_add_serverhello(SSL *ssl, CBB *out);
 
-int ssl_add_client_hello_body(SSL *ssl, CBB *body);
+/* ssl_is_sct_list_valid does a shallow parse of the SCT list in |contents| and
+ * returns one iff it's valid. */
+int ssl_is_sct_list_valid(const CBS *contents);
+
+int ssl_write_client_hello(SSL *ssl);
 
 /* ssl_clear_tls13_state releases client state only needed for TLS 1.3. It
  * should be called once the version is known to be TLS 1.2 or earlier. */
 void ssl_clear_tls13_state(SSL *ssl);
 
+enum ssl_cert_verify_context_t {
+  ssl_cert_verify_server,
+  ssl_cert_verify_client,
+  ssl_cert_verify_channel_id,
+};
+
+/* tls13_get_cert_verify_signature_input generates the message to be signed for
+ * TLS 1.3's CertificateVerify message. |cert_verify_context| determines the
+ * type of signature. It sets |*out| and |*out_len| to a newly allocated buffer
+ * containing the result. The caller must free it with |OPENSSL_free| to release
+ * it. This function returns one on success and zero on failure. */
+int tls13_get_cert_verify_signature_input(
+    SSL *ssl, uint8_t **out, size_t *out_len,
+    enum ssl_cert_verify_context_t cert_verify_context);
+
+/* ssl_negotiate_alpn negotiates the ALPN extension, if applicable. It returns
+ * one on successful negotiation or if nothing was negotiated. It returns zero
+ * and sets |*out_alert| to an alert on error. */
+int ssl_negotiate_alpn(SSL *ssl, uint8_t *out_alert,
+                       const struct ssl_early_callback_ctx *client_hello);
+
+typedef struct {
+  uint16_t type;
+  int *out_present;
+  CBS *out_data;
+} SSL_EXTENSION_TYPE;
+
+/* ssl_parse_extensions parses a TLS extensions block out of |cbs| and advances
+ * it. It writes the parsed extensions to pointers denoted by |ext_types|. On
+ * success, it fills in the |out_present| and |out_data| fields and returns one.
+ * Otherwise, it sets |*out_alert| to an alert to send and returns zero. Unknown
+ * extensions are rejected. */
+int ssl_parse_extensions(const CBS *cbs, uint8_t *out_alert,
+                         const SSL_EXTENSION_TYPE *ext_types,
+                         size_t num_ext_types);
+
 
 /* SSLKEYLOGFILE functions. */
 
@@ -1147,10 +1206,9 @@
 };
 
 typedef struct cert_st {
-  X509 *x509;
   EVP_PKEY *privatekey;
-  /* Chain for this certificate */
-  STACK_OF(X509) *chain;
+  X509 *x509_leaf;
+  STACK_OF(X509) *x509_chain;
 
   /* key_method, if non-NULL, is a set of callbacks to call for private key
    * operations. */
@@ -1220,10 +1278,9 @@
    * Otherwise, it returns <= 0. */
   int (*ssl_get_message)(SSL *ssl, int msg_type,
                          enum ssl_hash_message_t hash_message);
-  /* hash_current_message incorporates the current handshake message into the
-   * handshake hash. It returns one on success and zero on allocation
-   * failure. */
-  int (*hash_current_message)(SSL *ssl);
+  /* get_current_message sets |*out| to the current handshake message. This
+   * includes the protocol-specific message header. */
+  void (*get_current_message)(const SSL *ssl, CBS *out);
   /* release_current_message is called to release the current handshake message.
    * If |free_buffer| is one, buffers will also be released. */
   void (*release_current_message)(SSL *ssl, int free_buffer);
@@ -1245,9 +1302,15 @@
    * root CBB to be passed into |finish_message|. |*body| is set to a child CBB
    * the caller should write to. It returns one on success and zero on error. */
   int (*init_message)(SSL *ssl, CBB *cbb, CBB *body, uint8_t type);
-  /* finish_message finishes a handshake message and prepares it to be
-   * written. It returns one on success and zero on error. */
-  int (*finish_message)(SSL *ssl, CBB *cbb);
+  /* finish_message finishes a handshake message. It sets |*out_msg| to a
+   * newly-allocated buffer with the serialized message. The caller must
+   * release it with |OPENSSL_free| when done. It returns one on success and
+   * zero on error. */
+  int (*finish_message)(SSL *ssl, CBB *cbb, uint8_t **out_msg, size_t *out_len);
+  /* queue_message queues a handshake message and prepares it to be written. It
+   * takes ownership of |msg| and releases it with |OPENSSL_free| when done. It
+   * returns one on success and zero on error. */
+  int (*queue_message)(SSL *ssl, uint8_t *msg, size_t len);
   /* write_message writes the next message to the transport. It returns one on
    * success and <= 0 on error. */
   int (*write_message)(SSL *ssl);
@@ -1271,7 +1334,7 @@
 
 /* This is for the SSLv3/TLSv1.0 differences in crypto/hash stuff It is a bit
  * of a mess of functions, but hell, think of it as an opaque structure. */
-struct ssl3_enc_method {
+typedef struct ssl3_enc_method {
   /* prf computes the PRF function for |ssl|. It writes |out_len| bytes to
    * |out|, using |secret| as the secret and |label| as the label. |seed1| and
    * |seed2| are concatenated to form the seed parameter. It returns one on
@@ -1281,7 +1344,7 @@
              size_t label_len, const uint8_t *seed1, size_t seed1_len,
              const uint8_t *seed2, size_t seed2_len);
   int (*final_finish_mac)(SSL *ssl, int from_server, uint8_t *out);
-};
+} SSL3_ENC_METHOD;
 
 typedef struct ssl3_record_st {
   /* type is the record type. */
@@ -1415,9 +1478,6 @@
 
     int reuse_message;
 
-    uint8_t *key_block;
-    uint8_t key_block_length;
-
     uint8_t new_mac_secret_len;
     uint8_t new_key_len;
     uint8_t new_fixed_iv_len;
@@ -1569,12 +1629,9 @@
 extern const SSL3_ENC_METHOD TLSv1_enc_data;
 extern const SSL3_ENC_METHOD SSLv3_enc_data;
 
-/* From draft-ietf-tls-tls13-16, used in determining PSK modes. */
-#define SSL_PSK_KE        0x0
-#define SSL_PSK_DHE_KE    0x1
-
-#define SSL_PSK_AUTH      0x0
-#define SSL_PSK_SIGN_AUTH 0x1
+/* From draft-ietf-tls-tls13-18, used in determining PSK modes. */
+#define SSL_PSK_KE     0x0
+#define SSL_PSK_DHE_KE 0x1
 
 /* From draft-ietf-tls-tls13-16, used in determining whether to respond with a
  * KeyUpdate. */
@@ -1596,6 +1653,10 @@
  * it has expired. */
 int ssl_session_is_time_valid(const SSL *ssl, const SSL_SESSION *session);
 
+/* ssl_session_is_resumable returns one if |session| is resumable for |ssl| and
+ * zero otherwise. */
+int ssl_session_is_resumable(const SSL *ssl, const SSL_SESSION *session);
+
 void ssl_set_session(SSL *ssl, SSL_SESSION *session);
 
 enum ssl_session_result_t {
@@ -1605,14 +1666,13 @@
 };
 
 /* ssl_get_prev_session looks up the previous session based on |ctx|. On
- * success, it sets |*out_session| to the session or NULL if none was found. It
- * sets |*out_send_ticket| to whether a ticket should be sent at the end of the
- * handshake. If the session could not be looked up synchronously, it returns
+ * success, it sets |*out_session| to the session or NULL if none was found. If
+ * the session could not be looked up synchronously, it returns
  * |ssl_session_retry| and should be called again. Otherwise, it returns
  * |ssl_session_error|.  */
 enum ssl_session_result_t ssl_get_prev_session(
-    SSL *ssl, SSL_SESSION **out_session, int *out_send_ticket,
-    const struct ssl_early_callback_ctx *ctx);
+    SSL *ssl, SSL_SESSION **out_session, int *out_tickets_supported,
+    int *out_renew_ticket, const struct ssl_early_callback_ctx *ctx);
 
 /* The following flags determine which parts of the session are duplicated. */
 #define SSL_SESSION_DUP_AUTH_ONLY 0x0
@@ -1627,9 +1687,17 @@
 OPENSSL_EXPORT SSL_SESSION *SSL_SESSION_dup(SSL_SESSION *session,
                                             int dup_flags);
 
+/* ssl_session_refresh_time updates |session|'s start time to the current time,
+ * adjusting the timeout so the expiration time is unchanged. */
+void ssl_session_refresh_time(SSL *ssl, SSL_SESSION *session);
+
 void ssl_cipher_preference_list_free(
     struct ssl_cipher_preference_list_st *cipher_list);
-struct ssl_cipher_preference_list_st *ssl_get_cipher_preferences(SSL *ssl);
+
+/* ssl_get_cipher_preferences returns the cipher preference list for TLS 1.2 and
+ * below. */
+const struct ssl_cipher_preference_list_st *ssl_get_cipher_preferences(
+    const SSL *ssl);
 
 int ssl_cert_set0_chain(CERT *cert, STACK_OF(X509) *chain);
 int ssl_cert_set1_chain(CERT *cert, STACK_OF(X509) *chain);
@@ -1649,16 +1717,14 @@
 void ssl_get_compatible_server_ciphers(SSL *ssl, uint32_t *out_mask_k,
                                        uint32_t *out_mask_a);
 
-STACK_OF(SSL_CIPHER) *ssl_get_ciphers_by_id(SSL *ssl);
 int ssl_verify_alarm_type(long type);
 
 int ssl3_get_finished(SSL *ssl);
 int ssl3_send_change_cipher_spec(SSL *ssl);
-void ssl3_cleanup_key_block(SSL *ssl);
 int ssl3_send_alert(SSL *ssl, int level, int desc);
 int ssl3_get_message(SSL *ssl, int msg_type,
                      enum ssl_hash_message_t hash_message);
-int ssl3_hash_current_message(SSL *ssl);
+void ssl3_get_current_message(const SSL *ssl, CBS *out);
 void ssl3_release_current_message(SSL *ssl, int free_buffer);
 
 /* ssl3_cert_verify_hash writes the SSL 3.0 CertificateVerify hash into the
@@ -1679,6 +1745,7 @@
 int ssl3_write_app_data(SSL *ssl, const void *buf, int len);
 int ssl3_write_bytes(SSL *ssl, int type, const void *buf, int len);
 int ssl3_output_cert_chain(SSL *ssl);
+
 const SSL_CIPHER *ssl3_choose_cipher(
     SSL *ssl, const struct ssl_early_callback_ctx *client_hello,
     const struct ssl_cipher_preference_list_st *srvr);
@@ -1689,16 +1756,27 @@
 int ssl3_connect(SSL *ssl);
 
 int ssl3_init_message(SSL *ssl, CBB *cbb, CBB *body, uint8_t type);
-int ssl3_finish_message(SSL *ssl, CBB *cbb);
+int ssl3_finish_message(SSL *ssl, CBB *cbb, uint8_t **out_msg, size_t *out_len);
+int ssl3_queue_message(SSL *ssl, uint8_t *msg, size_t len);
 int ssl3_write_message(SSL *ssl);
 
 void ssl3_expect_flight(SSL *ssl);
 void ssl3_received_flight(SSL *ssl);
 
 int dtls1_init_message(SSL *ssl, CBB *cbb, CBB *body, uint8_t type);
-int dtls1_finish_message(SSL *ssl, CBB *cbb);
+int dtls1_finish_message(SSL *ssl, CBB *cbb, uint8_t **out_msg,
+                         size_t *out_len);
+int dtls1_queue_message(SSL *ssl, uint8_t *msg, size_t len);
 int dtls1_write_message(SSL *ssl);
 
+/* ssl_complete_message calls |finish_message| and |queue_message| on |cbb| to
+ * queue the message for writing. */
+int ssl_complete_message(SSL *ssl, CBB *cbb);
+
+/* ssl_hash_current_message incorporates the current handshake message into the
+ * handshake hash. It returns one on success and zero on allocation failure. */
+int ssl_hash_current_message(SSL *ssl);
+
 /* dtls1_get_record reads a new input record. On success, it places it in
  * |ssl->s3->rrec| and returns one. Otherwise it returns <= 0 on error or if
  * more data is needed. */
@@ -1740,7 +1818,7 @@
 void dtls1_free(SSL *ssl);
 
 int dtls1_get_message(SSL *ssl, int mt, enum ssl_hash_message_t hash_message);
-int dtls1_hash_current_message(SSL *ssl);
+void dtls1_get_current_message(const SSL *ssl, CBS *out);
 void dtls1_release_current_message(SSL *ssl, int free_buffer);
 int dtls1_dispatch_alert(SSL *ssl);
 
@@ -1752,7 +1830,6 @@
 void ssl_free_wbio_buffer(SSL *ssl);
 
 int tls1_change_cipher_state(SSL *ssl, int which);
-int tls1_setup_key_block(SSL *ssl);
 int tls1_handshake_digest(SSL *ssl, uint8_t *out, size_t out_len);
 int tls1_generate_master_secret(SSL *ssl, uint8_t *out, const uint8_t *premaster,
                                 size_t premaster_len);
@@ -1808,6 +1885,16 @@
                        size_t ticket_len, const uint8_t *session_id,
                        size_t session_id_len);
 
+/* tls1_verify_channel_id processes the current message as a Channel ID message,
+ * and verifies the signature. If the key is valid, it saves the Channel ID and
+ * returns one. Otherwise, it returns zero. */
+int tls1_verify_channel_id(SSL *ssl);
+
+/* tls1_write_channel_id generates a Channel ID message and puts the output in
+ * |cbb|. |ssl->tlsext_channel_id_private| must already be set before calling.
+ * This function returns one on success and zero on error. */
+int tls1_write_channel_id(SSL *ssl, CBB *cbb);
+
 /* tls1_channel_id_hash computes the hash to be signed by Channel ID and writes
  * it to |out|, which must contain at least |EVP_MAX_MD_SIZE| bytes. It returns
  * one on success and zero on failure. */
@@ -1815,6 +1902,12 @@
 
 int tls1_record_handshake_hashes_for_channel_id(SSL *ssl);
 
+/* ssl_do_channel_id_callback checks runs |ssl->ctx->channel_id_cb| if
+ * necessary. It returns one on success and zero on fatal error. Note that, on
+ * success, |ssl->tlsext_channel_id_private| may be unset, in which case the
+ * operation should be retried later. */
+int ssl_do_channel_id_callback(SSL *ssl);
+
 /* ssl3_can_false_start returns one if |ssl| is allowed to False Start and zero
  * otherwise. */
 int ssl3_can_false_start(const SSL *ssl);
diff --git a/src/ssl/s3_both.c b/src/ssl/s3_both.c
index 1e7e4e1..d872020 100644
--- a/src/ssl/s3_both.c
+++ b/src/ssl/s3_both.c
@@ -163,6 +163,13 @@
   OPENSSL_free(hs->peer_psk_identity_hint);
   sk_X509_NAME_pop_free(hs->ca_names, X509_NAME_free);
   OPENSSL_free(hs->certificate_types);
+
+  if (hs->key_block != NULL) {
+    OPENSSL_cleanse(hs->key_block, hs->key_block_len);
+    OPENSSL_free(hs->key_block);
+  }
+
+  OPENSSL_free(hs->hostname);
   OPENSSL_free(hs);
 }
 
@@ -199,18 +206,21 @@
   return 1;
 }
 
-int ssl3_finish_message(SSL *ssl, CBB *cbb) {
-  if (ssl->s3->pending_message != NULL) {
+int ssl3_finish_message(SSL *ssl, CBB *cbb, uint8_t **out_msg,
+                        size_t *out_len) {
+  if (!CBB_finish(cbb, out_msg, out_len)) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
     return 0;
   }
 
-  uint8_t *msg = NULL;
-  size_t len;
-  if (!CBB_finish(cbb, &msg, &len) ||
+  return 1;
+}
+
+int ssl3_queue_message(SSL *ssl, uint8_t *msg, size_t len) {
+  if (ssl->s3->pending_message != NULL ||
       len > 0xffffffffu) {
-    OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
     OPENSSL_free(msg);
+    OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
     return 0;
   }
 
@@ -221,6 +231,17 @@
   return 1;
 }
 
+int ssl_complete_message(SSL *ssl, CBB *cbb) {
+  uint8_t *msg;
+  size_t len;
+  if (!ssl->method->finish_message(ssl, cbb, &msg, &len) ||
+      !ssl->method->queue_message(ssl, msg, len)) {
+    return 0;
+  }
+
+  return 1;
+}
+
 int ssl3_write_message(SSL *ssl) {
   if (ssl->s3->pending_message == NULL) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
@@ -278,7 +299,7 @@
   CBB cbb, body;
   if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_FINISHED) ||
       !CBB_add_bytes(&body, finished, finished_len) ||
-      !ssl->method->finish_message(ssl, &cbb)) {
+      !ssl_complete_message(ssl, &cbb)) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
     CBB_cleanup(&cbb);
     return -1;
@@ -300,7 +321,7 @@
   size_t finished_len =
       ssl->s3->enc_method->final_finish_mac(ssl, !ssl->server, finished);
   if (finished_len == 0 ||
-      !ssl->method->hash_current_message(ssl)) {
+      !ssl_hash_current_message(ssl)) {
     return -1;
   }
 
@@ -346,7 +367,7 @@
   CBB cbb, body;
   if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_CERTIFICATE) ||
       !ssl_add_cert_chain(ssl, &body) ||
-      !ssl->method->finish_message(ssl, &cbb)) {
+      !ssl_complete_message(ssl, &cbb)) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
     CBB_cleanup(&cbb);
     return 0;
@@ -640,16 +661,21 @@
   }
 
   /* Feed this message into MAC computation. */
-  if (hash_message == ssl_hash_message && !ssl3_hash_current_message(ssl)) {
+  if (hash_message == ssl_hash_message && !ssl_hash_current_message(ssl)) {
     return -1;
   }
 
   return 1;
 }
 
-int ssl3_hash_current_message(SSL *ssl) {
-  return ssl3_update_handshake_hash(ssl, (uint8_t *)ssl->init_buf->data,
-                                    ssl->init_buf->length);
+void ssl3_get_current_message(const SSL *ssl, CBS *out) {
+  CBS_init(out, (uint8_t *)ssl->init_buf->data, ssl->init_buf->length);
+}
+
+int ssl_hash_current_message(SSL *ssl) {
+  CBS cbs;
+  ssl->method->get_current_message(ssl, &cbs);
+  return ssl3_update_handshake_hash(ssl, CBS_data(&cbs), CBS_len(&cbs));
 }
 
 void ssl3_release_current_message(SSL *ssl, int free_buffer) {
@@ -742,3 +768,51 @@
 
   return al;
 }
+
+int ssl_parse_extensions(const CBS *cbs, uint8_t *out_alert,
+                         const SSL_EXTENSION_TYPE *ext_types,
+                         size_t num_ext_types) {
+  /* Reset everything. */
+  for (size_t i = 0; i < num_ext_types; i++) {
+    *ext_types[i].out_present = 0;
+    CBS_init(ext_types[i].out_data, NULL, 0);
+  }
+
+  CBS copy = *cbs;
+  while (CBS_len(&copy) != 0) {
+    uint16_t type;
+    CBS data;
+    if (!CBS_get_u16(&copy, &type) ||
+        !CBS_get_u16_length_prefixed(&copy, &data)) {
+      OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT);
+      *out_alert = SSL_AD_DECODE_ERROR;
+      return 0;
+    }
+
+    const SSL_EXTENSION_TYPE *ext_type = NULL;
+    for (size_t i = 0; i < num_ext_types; i++) {
+      if (type == ext_types[i].type) {
+        ext_type = &ext_types[i];
+        break;
+      }
+    }
+
+    if (ext_type == NULL) {
+      OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
+      *out_alert = SSL_AD_UNSUPPORTED_EXTENSION;
+      return 0;
+    }
+
+    /* Duplicate ext_types are forbidden. */
+    if (*ext_type->out_present) {
+      OPENSSL_PUT_ERROR(SSL, SSL_R_DUPLICATE_EXTENSION);
+      *out_alert = SSL_AD_ILLEGAL_PARAMETER;
+      return 0;
+    }
+
+    *ext_type->out_present = 1;
+    *ext_type->out_data = data;
+  }
+
+  return 1;
+}
diff --git a/src/ssl/s3_enc.c b/src/ssl/s3_enc.c
index 2209e80..7cdc294 100644
--- a/src/ssl/s3_enc.c
+++ b/src/ssl/s3_enc.c
@@ -209,15 +209,6 @@
   return 1;
 }
 
-void ssl3_cleanup_key_block(SSL *ssl) {
-  if (ssl->s3->tmp.key_block != NULL) {
-    OPENSSL_cleanse(ssl->s3->tmp.key_block, ssl->s3->tmp.key_block_length);
-    OPENSSL_free(ssl->s3->tmp.key_block);
-    ssl->s3->tmp.key_block = NULL;
-  }
-  ssl->s3->tmp.key_block_length = 0;
-}
-
 int ssl3_init_handshake_buffer(SSL *ssl) {
   ssl3_free_handshake_buffer(ssl);
   ssl3_free_handshake_hash(ssl);
diff --git a/src/ssl/s3_lib.c b/src/ssl/s3_lib.c
index 69d3a9d..901b8af 100644
--- a/src/ssl/s3_lib.c
+++ b/src/ssl/s3_lib.c
@@ -200,7 +200,6 @@
     return;
   }
 
-  ssl3_cleanup_key_block(ssl);
   ssl_read_buffer_clear(ssl);
   ssl_write_buffer_clear(ssl);
 
@@ -220,7 +219,8 @@
   ssl->s3 = NULL;
 }
 
-struct ssl_cipher_preference_list_st *ssl_get_cipher_preferences(SSL *ssl) {
+const struct ssl_cipher_preference_list_st *ssl_get_cipher_preferences(
+    const SSL *ssl) {
   if (ssl->cipher_list != NULL) {
     return ssl->cipher_list;
   }
diff --git a/src/ssl/s3_pkt.c b/src/ssl/s3_pkt.c
index fda9a25..e4116fb 100644
--- a/src/ssl/s3_pkt.c
+++ b/src/ssl/s3_pkt.c
@@ -245,8 +245,8 @@
 static int ssl3_write_pending(SSL *ssl, int type, const uint8_t *buf,
                               unsigned int len) {
   if (ssl->s3->wpend_tot > (int)len ||
-      (ssl->s3->wpend_buf != buf &&
-       !(ssl->mode & SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER)) ||
+      (!(ssl->mode & SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER) &&
+       ssl->s3->wpend_buf != buf) ||
       ssl->s3->wpend_type != type) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_WRITE_RETRY);
     return -1;
@@ -284,7 +284,7 @@
     return 0;
   }
 
-  size_t max_out = len + ssl_max_seal_overhead(ssl);
+  size_t max_out = len + SSL_max_seal_overhead(ssl);
   if (max_out < len) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
     return -1;
diff --git a/src/ssl/ssl_aead_ctx.c b/src/ssl/ssl_aead_ctx.c
index 0f6f64f..b05df0b 100644
--- a/src/ssl/ssl_aead_ctx.c
+++ b/src/ssl/ssl_aead_ctx.c
@@ -34,8 +34,12 @@
                                const uint8_t *mac_key, size_t mac_key_len,
                                const uint8_t *fixed_iv, size_t fixed_iv_len) {
   const EVP_AEAD *aead;
-  size_t discard;
-  if (!ssl_cipher_get_evp_aead(&aead, &discard, &discard, cipher, version)) {
+  size_t expected_mac_key_len, expected_fixed_iv_len;
+  if (!ssl_cipher_get_evp_aead(&aead, &expected_mac_key_len,
+                               &expected_fixed_iv_len, cipher, version) ||
+      /* Ensure the caller returned correct key sizes. */
+      expected_fixed_iv_len != fixed_iv_len ||
+      expected_mac_key_len != mac_key_len) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
     return 0;
   }
diff --git a/src/ssl/ssl_asn1.c b/src/ssl/ssl_asn1.c
index eeea826..2a7b7d4 100644
--- a/src/ssl/ssl_asn1.c
+++ b/src/ssl/ssl_asn1.c
@@ -97,13 +97,13 @@
 /* An SSL_SESSION is serialized as the following ASN.1 structure:
  *
  * SSLSession ::= SEQUENCE {
- *     version                     INTEGER (1),  -- ignored
+ *     version                     INTEGER (1),  -- session structure version
  *     sslVersion                  INTEGER,      -- protocol version number
  *     cipher                      OCTET STRING, -- two bytes long
  *     sessionID                   OCTET STRING,
  *     masterKey                   OCTET STRING,
- *     time                    [1] INTEGER OPTIONAL, -- seconds since UNIX epoch
- *     timeout                 [2] INTEGER OPTIONAL, -- in seconds
+ *     time                    [1] INTEGER, -- seconds since UNIX epoch
+ *     timeout                 [2] INTEGER, -- in seconds
  *     peer                    [3] Certificate OPTIONAL,
  *     sessionIDContext        [4] OCTET STRING OPTIONAL,
  *     verifyResult            [5] INTEGER OPTIONAL,  -- one of X509_V_* codes
@@ -196,30 +196,36 @@
     goto err;
   }
 
-  if (in->time != 0) {
-    if (!CBB_add_asn1(&session, &child, kTimeTag) ||
-        !CBB_add_asn1_uint64(&child, in->time)) {
-      OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
-      goto err;
-    }
+  if (in->time < 0) {
+    OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
+    goto err;
   }
 
-  if (in->timeout != 0) {
-    if (!CBB_add_asn1(&session, &child, kTimeoutTag) ||
-        !CBB_add_asn1_uint64(&child, in->timeout)) {
-      OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
-      goto err;
-    }
+  if (!CBB_add_asn1(&session, &child, kTimeTag) ||
+      !CBB_add_asn1_uint64(&child, in->time)) {
+    OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+    goto err;
+  }
+
+  if (in->timeout < 0) {
+    OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
+    goto err;
+  }
+
+  if (!CBB_add_asn1(&session, &child, kTimeoutTag) ||
+      !CBB_add_asn1_uint64(&child, in->timeout)) {
+    OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+    goto err;
   }
 
   /* The peer certificate is only serialized if the SHA-256 isn't
    * serialized instead. */
-  if (in->peer && !in->peer_sha256_valid) {
+  if (in->x509_peer && !in->peer_sha256_valid) {
     if (!CBB_add_asn1(&session, &child, kPeerTag)) {
       OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
       goto err;
     }
-    if (!ssl_add_cert_to_cbb(&child, in->peer)) {
+    if (!ssl_add_cert_to_cbb(&child, in->x509_peer)) {
       goto err;
     }
   }
@@ -334,13 +340,13 @@
 
   /* The certificate chain is only serialized if the leaf's SHA-256 isn't
    * serialized instead. */
-  if (in->cert_chain != NULL && !in->peer_sha256_valid) {
+  if (in->x509_chain != NULL && !in->peer_sha256_valid) {
     if (!CBB_add_asn1(&session, &child, kCertChainTag)) {
       OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
       goto err;
     }
-    for (size_t i = 0; i < sk_X509_num(in->cert_chain); i++) {
-      if (!ssl_add_cert_to_cbb(&child, sk_X509_value(in->cert_chain, i))) {
+    for (size_t i = 0; i < sk_X509_num(in->x509_chain); i++) {
+      if (!ssl_add_cert_to_cbb(&child, sk_X509_value(in->x509_chain, i))) {
         goto err;
       }
     }
@@ -505,20 +511,6 @@
   return 1;
 }
 
-static X509 *parse_x509(CBS *cbs) {
-  if (CBS_len(cbs) > LONG_MAX) {
-    OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
-    return NULL;
-  }
-  const uint8_t *ptr = CBS_data(cbs);
-  X509 *ret = d2i_X509(NULL, &ptr, (long)CBS_len(cbs));
-  if (ret == NULL) {
-    return NULL;
-  }
-  CBS_skip(cbs, ptr - CBS_data(cbs));
-  return ret;
-}
-
 static SSL_SESSION *SSL_SESSION_parse(CBS *cbs) {
   SSL_SESSION *ret = SSL_SESSION_new();
   if (ret == NULL) {
@@ -563,23 +555,32 @@
   memcpy(ret->master_key, CBS_data(&master_key), CBS_len(&master_key));
   ret->master_key_length = CBS_len(&master_key);
 
-  if (!SSL_SESSION_parse_long(&session, &ret->time, kTimeTag, time(NULL)) ||
-      !SSL_SESSION_parse_long(&session, &ret->timeout, kTimeoutTag, 3)) {
+  CBS child;
+  uint64_t time, timeout;
+  if (!CBS_get_asn1(&session, &child, kTimeTag) ||
+      !CBS_get_asn1_uint64(&child, &time) ||
+      time > LONG_MAX ||
+      !CBS_get_asn1(&session, &child, kTimeoutTag) ||
+      !CBS_get_asn1_uint64(&child, &timeout) ||
+      timeout > LONG_MAX) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
     goto err;
   }
 
+  ret->time = (long)time;
+  ret->timeout = (long)timeout;
+
   CBS peer;
   int has_peer;
   if (!CBS_get_optional_asn1(&session, &peer, &has_peer, kPeerTag)) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
     goto err;
   }
-  X509_free(ret->peer);
-  ret->peer = NULL;
+  X509_free(ret->x509_peer);
+  ret->x509_peer = NULL;
   if (has_peer) {
-    ret->peer = parse_x509(&peer);
-    if (ret->peer == NULL) {
+    ret->x509_peer = ssl_parse_x509(&peer);
+    if (ret->x509_peer == NULL) {
       goto err;
     }
     if (CBS_len(&peer) != 0) {
@@ -605,7 +606,7 @@
   }
 
   if (CBS_peek_asn1_tag(&session, kPeerSHA256Tag)) {
-    CBS child, peer_sha256;
+    CBS peer_sha256;
     if (!CBS_get_asn1(&session, &child, kPeerSHA256Tag) ||
         !CBS_get_asn1(&child, &peer_sha256, CBS_ASN1_OCTETSTRING) ||
         CBS_len(&peer_sha256) != sizeof(ret->peer_sha256) ||
@@ -655,20 +656,20 @@
     OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
     goto err;
   }
-  sk_X509_pop_free(ret->cert_chain, X509_free);
-  ret->cert_chain = NULL;
+  sk_X509_pop_free(ret->x509_chain, X509_free);
+  ret->x509_chain = NULL;
   if (has_cert_chain) {
-    ret->cert_chain = sk_X509_new_null();
-    if (ret->cert_chain == NULL) {
+    ret->x509_chain = sk_X509_new_null();
+    if (ret->x509_chain == NULL) {
       OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
       goto err;
     }
     while (CBS_len(&cert_chain) > 0) {
-      X509 *x509 = parse_x509(&cert_chain);
+      X509 *x509 = ssl_parse_x509(&cert_chain);
       if (x509 == NULL) {
         goto err;
       }
-      if (!sk_X509_push(ret->cert_chain, x509)) {
+      if (!sk_X509_push(ret->x509_chain, x509)) {
         OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
         X509_free(x509);
         goto err;
diff --git a/src/ssl/ssl_cert.c b/src/ssl/ssl_cert.c
index 55b464f..7f6cf63 100644
--- a/src/ssl/ssl_cert.c
+++ b/src/ssl/ssl_cert.c
@@ -115,6 +115,7 @@
 #include <openssl/ssl.h>
 
 #include <assert.h>
+#include <limits.h>
 #include <string.h>
 
 #include <openssl/bn.h>
@@ -158,9 +159,9 @@
   }
   memset(ret, 0, sizeof(CERT));
 
-  if (cert->x509 != NULL) {
-    X509_up_ref(cert->x509);
-    ret->x509 = cert->x509;
+  if (cert->x509_leaf != NULL) {
+    X509_up_ref(cert->x509_leaf);
+    ret->x509_leaf = cert->x509_leaf;
   }
 
   if (cert->privatekey != NULL) {
@@ -168,9 +169,9 @@
     ret->privatekey = cert->privatekey;
   }
 
-  if (cert->chain) {
-    ret->chain = X509_chain_up_ref(cert->chain);
-    if (!ret->chain) {
+  if (cert->x509_chain) {
+    ret->x509_chain = X509_chain_up_ref(cert->x509_chain);
+    if (!ret->x509_chain) {
       OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
       goto err;
     }
@@ -220,12 +221,12 @@
     return;
   }
 
-  X509_free(cert->x509);
-  cert->x509 = NULL;
+  X509_free(cert->x509_leaf);
+  cert->x509_leaf = NULL;
   EVP_PKEY_free(cert->privatekey);
   cert->privatekey = NULL;
-  sk_X509_pop_free(cert->chain, X509_free);
-  cert->chain = NULL;
+  sk_X509_pop_free(cert->x509_chain, X509_free);
+  cert->x509_chain = NULL;
   cert->key_method = NULL;
 }
 
@@ -244,8 +245,8 @@
 }
 
 int ssl_cert_set0_chain(CERT *cert, STACK_OF(X509) *chain) {
-  sk_X509_pop_free(cert->chain, X509_free);
-  cert->chain = chain;
+  sk_X509_pop_free(cert->x509_chain, X509_free);
+  cert->x509_chain = chain;
   return 1;
 }
 
@@ -269,10 +270,10 @@
 }
 
 int ssl_cert_add0_chain_cert(CERT *cert, X509 *x509) {
-  if (cert->chain == NULL) {
-    cert->chain = sk_X509_new_null();
+  if (cert->x509_chain == NULL) {
+    cert->x509_chain = sk_X509_new_null();
   }
-  if (cert->chain == NULL || !sk_X509_push(cert->chain, x509)) {
+  if (cert->x509_chain == NULL || !sk_X509_push(cert->x509_chain, x509)) {
     return 0;
   }
 
@@ -443,7 +444,21 @@
 }
 
 int ssl_has_certificate(const SSL *ssl) {
-  return ssl->cert->x509 != NULL && ssl_has_private_key(ssl);
+  return ssl->cert->x509_leaf != NULL && ssl_has_private_key(ssl);
+}
+
+X509 *ssl_parse_x509(CBS *cbs) {
+  if (CBS_len(cbs) > LONG_MAX) {
+    OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+    return NULL;
+  }
+  const uint8_t *ptr = CBS_data(cbs);
+  X509 *ret = d2i_X509(NULL, &ptr, (long)CBS_len(cbs));
+  if (ret == NULL) {
+    return NULL;
+  }
+  CBS_skip(cbs, ptr - CBS_data(cbs));
+  return ret;
 }
 
 STACK_OF(X509) *ssl_parse_cert_chain(SSL *ssl, uint8_t *out_alert,
@@ -476,10 +491,8 @@
       SHA256(CBS_data(&certificate), CBS_len(&certificate), out_leaf_sha256);
     }
 
-    /* A u24 length cannot overflow a long. */
-    const uint8_t *data = CBS_data(&certificate);
-    x = d2i_X509(NULL, &data, (long)CBS_len(&certificate));
-    if (x == NULL || data != CBS_data(&certificate) + CBS_len(&certificate)) {
+    x = ssl_parse_x509(&certificate);
+    if (x == NULL || CBS_len(&certificate) != 0) {
       *out_alert = SSL_AD_DECODE_ERROR;
       goto err;
     }
@@ -528,7 +541,7 @@
   }
 
   CERT *cert = ssl->cert;
-  X509 *x = cert->x509;
+  X509 *x = cert->x509_leaf;
 
   CBB child;
   if (!CBB_add_u24_length_prefixed(cbb, &child)) {
@@ -537,7 +550,7 @@
   }
 
   int no_chain = 0;
-  STACK_OF(X509) *chain = cert->chain;
+  STACK_OF(X509) *chain = cert->x509_chain;
   if ((ssl->mode & SSL_MODE_NO_AUTO_CHAIN) || chain != NULL) {
     no_chain = 1;
   }
@@ -763,7 +776,7 @@
 }
 
 int SSL_CTX_get0_chain_certs(const SSL_CTX *ctx, STACK_OF(X509) **out_chain) {
-  *out_chain = ctx->cert->chain;
+  *out_chain = ctx->cert->x509_chain;
   return 1;
 }
 
@@ -773,7 +786,7 @@
 }
 
 int SSL_get0_chain_certs(const SSL *ssl, STACK_OF(X509) **out_chain) {
-  *out_chain = ssl->cert->chain;
+  *out_chain = ssl->cert->x509_chain;
   return 1;
 }
 
diff --git a/src/ssl/ssl_cipher.c b/src/ssl/ssl_cipher.c
index 6d48c89..99aba72 100644
--- a/src/ssl/ssl_cipher.c
+++ b/src/ssl/ssl_cipher.c
@@ -738,9 +738,6 @@
     {"TLSv1", ~SSL_kCECPQ1, ~0u, ~SSL_eNULL, ~0u, SSL3_VERSION},
     {"TLSv1.2", ~SSL_kCECPQ1, ~0u, ~SSL_eNULL, ~0u, TLS1_2_VERSION},
 
-    /* AEAD-only ciphers for TLS 1.3. */
-    {"GENERIC", SSL_kGENERIC, SSL_aGENERIC, ~0u, ~0u, 0},
-
     /* Legacy strength classes. */
     {"HIGH", ~SSL_kCECPQ1, ~0u, ~SSL_eNULL, ~0u, 0},
     {"FIPS", ~SSL_kCECPQ1, ~0u, ~SSL_eNULL, ~0u, 0},
@@ -761,10 +758,6 @@
   }
 }
 
-static int ssl_cipher_ptr_id_cmp(const SSL_CIPHER **a, const SSL_CIPHER **b) {
-  return ssl_cipher_id_cmp(*a, *b);
-}
-
 const SSL_CIPHER *SSL_get_cipher_by_value(uint16_t value) {
   SSL_CIPHER c;
 
@@ -781,125 +774,93 @@
   *out_mac_secret_len = 0;
   *out_fixed_iv_len = 0;
 
-  switch (cipher->algorithm_enc) {
-    case SSL_AES128GCM:
+  if (cipher->algorithm_mac == SSL_AEAD) {
+    if (cipher->algorithm_enc == SSL_AES128GCM) {
       *out_aead = EVP_aead_aes_128_gcm();
       *out_fixed_iv_len = 4;
-      break;
-
-    case SSL_AES256GCM:
+    } else if (cipher->algorithm_enc == SSL_AES256GCM) {
       *out_aead = EVP_aead_aes_256_gcm();
       *out_fixed_iv_len = 4;
-      break;
-
 #if !defined(BORINGSSL_ANDROID_SYSTEM)
-    case SSL_CHACHA20POLY1305_OLD:
+    } else if (cipher->algorithm_enc == SSL_CHACHA20POLY1305_OLD) {
       *out_aead = EVP_aead_chacha20_poly1305_old();
       *out_fixed_iv_len = 0;
-      break;
 #endif
-
-    case SSL_CHACHA20POLY1305:
+    } else if (cipher->algorithm_enc == SSL_CHACHA20POLY1305) {
       *out_aead = EVP_aead_chacha20_poly1305();
       *out_fixed_iv_len = 12;
-      break;
-
-    case SSL_AES128:
-      switch (cipher->algorithm_mac) {
-        case SSL_SHA1:
-          if (version == SSL3_VERSION) {
-            *out_aead = EVP_aead_aes_128_cbc_sha1_ssl3();
-            *out_fixed_iv_len = 16;
-          } else if (version == TLS1_VERSION) {
-            *out_aead = EVP_aead_aes_128_cbc_sha1_tls_implicit_iv();
-            *out_fixed_iv_len = 16;
-          } else {
-            *out_aead = EVP_aead_aes_128_cbc_sha1_tls();
-          }
-          *out_mac_secret_len = SHA_DIGEST_LENGTH;
-          break;
-        case SSL_SHA256:
-          *out_aead = EVP_aead_aes_128_cbc_sha256_tls();
-          *out_mac_secret_len = SHA256_DIGEST_LENGTH;
-          break;
-        default:
-          return 0;
-      }
-      break;
-
-    case SSL_AES256:
-      switch (cipher->algorithm_mac) {
-        case SSL_SHA1:
-          if (version == SSL3_VERSION) {
-            *out_aead = EVP_aead_aes_256_cbc_sha1_ssl3();
-            *out_fixed_iv_len = 16;
-          } else if (version == TLS1_VERSION) {
-            *out_aead = EVP_aead_aes_256_cbc_sha1_tls_implicit_iv();
-            *out_fixed_iv_len = 16;
-          } else {
-            *out_aead = EVP_aead_aes_256_cbc_sha1_tls();
-          }
-          *out_mac_secret_len = SHA_DIGEST_LENGTH;
-          break;
-        case SSL_SHA256:
-          *out_aead = EVP_aead_aes_256_cbc_sha256_tls();
-          *out_mac_secret_len = SHA256_DIGEST_LENGTH;
-          break;
-        case SSL_SHA384:
-          *out_aead = EVP_aead_aes_256_cbc_sha384_tls();
-          *out_mac_secret_len = SHA384_DIGEST_LENGTH;
-          break;
-        default:
-          return 0;
-      }
-      break;
-
-    case SSL_3DES:
-      switch (cipher->algorithm_mac) {
-        case SSL_SHA1:
-          if (version == SSL3_VERSION) {
-            *out_aead = EVP_aead_des_ede3_cbc_sha1_ssl3();
-            *out_fixed_iv_len = 8;
-          } else if (version == TLS1_VERSION) {
-            *out_aead = EVP_aead_des_ede3_cbc_sha1_tls_implicit_iv();
-            *out_fixed_iv_len = 8;
-          } else {
-            *out_aead = EVP_aead_des_ede3_cbc_sha1_tls();
-          }
-          *out_mac_secret_len = SHA_DIGEST_LENGTH;
-          break;
-        default:
-          return 0;
-      }
-      break;
-
-    case SSL_eNULL:
-      switch (cipher->algorithm_mac) {
-        case SSL_SHA1:
-          if (version == SSL3_VERSION) {
-            *out_aead = EVP_aead_null_sha1_ssl3();
-          } else {
-            *out_aead = EVP_aead_null_sha1_tls();
-          }
-          *out_mac_secret_len = SHA_DIGEST_LENGTH;
-          break;
-        default:
-          return 0;
-      }
-      break;
-
-    default:
+    } else {
       return 0;
+    }
+
+    /* In TLS 1.3, the iv_len is equal to the AEAD nonce length whereas the code
+     * above computes the TLS 1.2 construction. */
+    if (version >= TLS1_3_VERSION) {
+      *out_fixed_iv_len = EVP_AEAD_nonce_length(*out_aead);
+    }
+  } else if (cipher->algorithm_mac == SSL_SHA1) {
+    if (cipher->algorithm_enc == SSL_eNULL) {
+      if (version == SSL3_VERSION) {
+        *out_aead = EVP_aead_null_sha1_ssl3();
+      } else {
+        *out_aead = EVP_aead_null_sha1_tls();
+      }
+    } else if (cipher->algorithm_enc == SSL_3DES) {
+      if (version == SSL3_VERSION) {
+        *out_aead = EVP_aead_des_ede3_cbc_sha1_ssl3();
+        *out_fixed_iv_len = 8;
+      } else if (version == TLS1_VERSION) {
+        *out_aead = EVP_aead_des_ede3_cbc_sha1_tls_implicit_iv();
+        *out_fixed_iv_len = 8;
+      } else {
+        *out_aead = EVP_aead_des_ede3_cbc_sha1_tls();
+      }
+    } else if (cipher->algorithm_enc == SSL_AES128) {
+      if (version == SSL3_VERSION) {
+        *out_aead = EVP_aead_aes_128_cbc_sha1_ssl3();
+        *out_fixed_iv_len = 16;
+      } else if (version == TLS1_VERSION) {
+        *out_aead = EVP_aead_aes_128_cbc_sha1_tls_implicit_iv();
+        *out_fixed_iv_len = 16;
+      } else {
+        *out_aead = EVP_aead_aes_128_cbc_sha1_tls();
+      }
+    } else if (cipher->algorithm_enc == SSL_AES256) {
+      if (version == SSL3_VERSION) {
+        *out_aead = EVP_aead_aes_256_cbc_sha1_ssl3();
+        *out_fixed_iv_len = 16;
+      } else if (version == TLS1_VERSION) {
+        *out_aead = EVP_aead_aes_256_cbc_sha1_tls_implicit_iv();
+        *out_fixed_iv_len = 16;
+      } else {
+        *out_aead = EVP_aead_aes_256_cbc_sha1_tls();
+      }
+    } else {
+      return 0;
+    }
+
+    *out_mac_secret_len = SHA_DIGEST_LENGTH;
+  } else if (cipher->algorithm_mac == SSL_SHA256) {
+    if (cipher->algorithm_enc == SSL_AES128) {
+      *out_aead = EVP_aead_aes_128_cbc_sha256_tls();
+    } else if (cipher->algorithm_enc == SSL_AES256) {
+      *out_aead = EVP_aead_aes_256_cbc_sha256_tls();
+    } else {
+      return 0;
+    }
+
+    *out_mac_secret_len = SHA256_DIGEST_LENGTH;
+  } else if (cipher->algorithm_mac == SSL_SHA384) {
+      if (cipher->algorithm_enc != SSL_AES256) {
+        return 0;
+      }
+
+      *out_aead = EVP_aead_aes_256_cbc_sha384_tls();
+      *out_mac_secret_len = SHA384_DIGEST_LENGTH;
+  } else {
+    return 0;
   }
 
-  /* In TLS 1.3, the iv_len is equal to the AEAD nonce length whereas the code
-   * above computes the TLS 1.2 construction.
-   *
-   * TODO(davidben,svaldez): Avoid computing the wrong value and fixing it. */
-  if (version >= TLS1_3_VERSION) {
-    *out_fixed_iv_len = EVP_AEAD_nonce_length(*out_aead);
-    assert(*out_fixed_iv_len >= 8);
-  }
   return 1;
 }
 
@@ -975,7 +936,9 @@
   size_t co_list_num = 0;
   for (size_t i = 0; i < kCiphersLen; i++) {
     const SSL_CIPHER *cipher = &kCiphers[i];
-    if (ssl_method->supports_cipher(cipher)) {
+    if (ssl_method->supports_cipher(cipher) &&
+        /* TLS 1.3 ciphers do not participate in this mechanism. */
+        cipher->algorithm_mkey != SSL_kGENERIC) {
       co_list[co_list_num].cipher = cipher;
       co_list[co_list_num].next = NULL;
       co_list[co_list_num].prev = NULL;
@@ -1389,11 +1352,8 @@
 STACK_OF(SSL_CIPHER) *
 ssl_create_cipher_list(const SSL_PROTOCOL_METHOD *ssl_method,
                        struct ssl_cipher_preference_list_st **out_cipher_list,
-                       STACK_OF(SSL_CIPHER) **out_cipher_list_by_id,
                        const char *rule_str) {
-  int ok;
-  STACK_OF(SSL_CIPHER) *cipherstack = NULL, *tmp_cipher_list = NULL;
-  const char *rule_p;
+  STACK_OF(SSL_CIPHER) *cipherstack = NULL;
   CIPHER_ORDER *co_list = NULL, *head = NULL, *tail = NULL, *curr;
   uint8_t *in_group_flags = NULL;
   unsigned int num_in_group_flags = 0;
@@ -1418,11 +1378,8 @@
   /* Now arrange all ciphers by preference:
    * TODO(davidben): Compute this order once and copy it. */
 
-  /* Everything else being equal, prefer TLS 1.3 ciphers then ECDHE_ECDSA then
-   * ECDHE_RSA over other key exchange mechanisms */
-
-  ssl_cipher_apply_rule(0, SSL_kGENERIC, SSL_aGENERIC, ~0u, ~0u, 0, CIPHER_ADD,
-                        -1, 0, &head, &tail);
+  /* Everything else being equal, prefer ECDHE_ECDSA and ECDHE_RSA over other
+   * key exchange mechanisms */
   ssl_cipher_apply_rule(0, SSL_kECDHE, SSL_aECDSA, ~0u, ~0u, 0, CIPHER_ADD, -1,
                         0, &head, &tail);
   ssl_cipher_apply_rule(0, SSL_kECDHE, ~0u, ~0u, ~0u, 0, CIPHER_ADD, -1, 0,
@@ -1477,22 +1434,20 @@
 
   /* If the rule_string begins with DEFAULT, apply the default rule before
    * using the (possibly available) additional rules. */
-  ok = 1;
-  rule_p = rule_str;
+  const char *rule_p = rule_str;
   if (strncmp(rule_str, "DEFAULT", 7) == 0) {
-    ok = ssl_cipher_process_rulestr(ssl_method, SSL_DEFAULT_CIPHER_LIST, &head,
-                                    &tail);
+    if (!ssl_cipher_process_rulestr(ssl_method, SSL_DEFAULT_CIPHER_LIST, &head,
+                                    &tail)) {
+      goto err;
+    }
     rule_p += 7;
     if (*rule_p == ':') {
       rule_p++;
     }
   }
 
-  if (ok && strlen(rule_p) > 0) {
-    ok = ssl_cipher_process_rulestr(ssl_method, rule_p, &head, &tail);
-  }
-
-  if (!ok) {
+  if (*rule_p != '\0' &&
+      !ssl_cipher_process_rulestr(ssl_method, rule_p, &head, &tail)) {
     goto err;
   }
 
@@ -1521,10 +1476,6 @@
   OPENSSL_free(co_list); /* Not needed any longer */
   co_list = NULL;
 
-  tmp_cipher_list = sk_SSL_CIPHER_dup(cipherstack);
-  if (tmp_cipher_list == NULL) {
-    goto err;
-  }
   pref_list = OPENSSL_malloc(sizeof(struct ssl_cipher_preference_list_st));
   if (!pref_list) {
     goto err;
@@ -1543,26 +1494,12 @@
   *out_cipher_list = pref_list;
   pref_list = NULL;
 
-  if (out_cipher_list_by_id != NULL) {
-    sk_SSL_CIPHER_free(*out_cipher_list_by_id);
-    *out_cipher_list_by_id = tmp_cipher_list;
-    tmp_cipher_list = NULL;
-    (void) sk_SSL_CIPHER_set_cmp_func(*out_cipher_list_by_id,
-                                      ssl_cipher_ptr_id_cmp);
-
-    sk_SSL_CIPHER_sort(*out_cipher_list_by_id);
-  } else {
-    sk_SSL_CIPHER_free(tmp_cipher_list);
-    tmp_cipher_list = NULL;
-  }
-
   return cipherstack;
 
 err:
   OPENSSL_free(co_list);
   OPENSSL_free(in_group_flags);
   sk_SSL_CIPHER_free(cipherstack);
-  sk_SSL_CIPHER_free(tmp_cipher_list);
   if (pref_list) {
     OPENSSL_free(pref_list->in_group_flags);
   }
diff --git a/src/ssl/ssl_lib.c b/src/ssl/ssl_lib.c
index 491c408..70a39ea 100644
--- a/src/ssl/ssl_lib.c
+++ b/src/ssl/ssl_lib.c
@@ -276,7 +276,7 @@
   }
 
   ssl_create_cipher_list(ret->method, &ret->cipher_list,
-                         &ret->cipher_list_by_id, SSL_DEFAULT_CIPHER_LIST);
+                         SSL_DEFAULT_CIPHER_LIST);
   if (ret->cipher_list == NULL ||
       sk_SSL_CIPHER_num(ret->cipher_list->ciphers) <= 0) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_LIBRARY_HAS_NO_CIPHERS);
@@ -304,6 +304,10 @@
     ret->options |= SSL_OP_NO_TICKET;
   }
 
+  /* Disable the auto-chaining feature by default. Once this has stuck without
+   * problems, the feature will be removed entirely. */
+  ret->mode = SSL_MODE_NO_AUTO_CHAIN;
+
   /* Lock the SSL_CTX to the specified version, for compatibility with legacy
    * uses of SSL_METHOD. */
   if (!SSL_CTX_set_max_proto_version(ret, method->version) ||
@@ -348,7 +352,6 @@
   lh_SSL_SESSION_free(ctx->sessions);
   X509_STORE_free(ctx->cert_store);
   ssl_cipher_preference_list_free(ctx->cipher_list);
-  sk_SSL_CIPHER_free(ctx->cipher_list_by_id);
   ssl_cipher_preference_list_free(ctx->cipher_list_tls10);
   ssl_cipher_preference_list_free(ctx->cipher_list_tls11);
   ssl_cert_free(ctx->cert);
@@ -409,6 +412,8 @@
   assert(ssl->sid_ctx_length <= sizeof ssl->sid_ctx);
   memcpy(&ssl->sid_ctx, &ctx->sid_ctx, sizeof(ssl->sid_ctx));
   ssl->verify_callback = ctx->default_verify_callback;
+  ssl->retain_only_sha256_of_client_certs =
+      ctx->retain_only_sha256_of_client_certs;
 
   ssl->param = X509_VERIFY_PARAM_new();
   if (!ssl->param) {
@@ -500,7 +505,6 @@
 
   /* add extra stuff */
   ssl_cipher_preference_list_free(ssl->cipher_list);
-  sk_SSL_CIPHER_free(ssl->cipher_list_by_id);
 
   SSL_SESSION_free(ssl->session);
 
@@ -1046,11 +1050,11 @@
     return NULL;
   }
   SSL_SESSION *session = SSL_get_session(ssl);
-  if (session == NULL || session->peer == NULL) {
+  if (session == NULL || session->x509_peer == NULL) {
     return NULL;
   }
-  X509_up_ref(session->peer);
-  return session->peer;
+  X509_up_ref(session->x509_peer);
+  return session->x509_peer;
 }
 
 STACK_OF(X509) *SSL_get_peer_cert_chain(const SSL *ssl) {
@@ -1061,7 +1065,7 @@
   if (session == NULL) {
     return NULL;
   }
-  return session->cert_chain;
+  return session->x509_chain;
 }
 
 int SSL_get_tls_unique(const SSL *ssl, uint8_t *out, size_t *out_len,
@@ -1334,32 +1338,34 @@
 
 /* Fix this so it checks all the valid key/cert options */
 int SSL_CTX_check_private_key(const SSL_CTX *ctx) {
-  if (ctx->cert->x509 == NULL) {
-    OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATE_ASSIGNED);
-    return 0;
-  }
-
   if (ctx->cert->privatekey == NULL) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_NO_PRIVATE_KEY_ASSIGNED);
     return 0;
   }
 
-  return X509_check_private_key(ctx->cert->x509, ctx->cert->privatekey);
-}
-
-/* Fix this function so that it takes an optional type parameter */
-int SSL_check_private_key(const SSL *ssl) {
-  if (ssl->cert->x509 == NULL) {
+  X509 *x509 = ctx->cert->x509_leaf;
+  if (x509 == NULL) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATE_ASSIGNED);
     return 0;
   }
 
+  return X509_check_private_key(x509, ctx->cert->privatekey);
+}
+
+/* Fix this function so that it takes an optional type parameter */
+int SSL_check_private_key(const SSL *ssl) {
   if (ssl->cert->privatekey == NULL) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_NO_PRIVATE_KEY_ASSIGNED);
     return 0;
   }
 
-  return X509_check_private_key(ssl->cert->x509, ssl->cert->privatekey);
+  X509 *x509 = ssl->cert->x509_leaf;
+  if (x509 == NULL) {
+    OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATE_ASSIGNED);
+    return 0;
+  }
+
+  return X509_check_private_key(x509, ssl->cert->privatekey);
 }
 
 long SSL_get_default_timeout(const SSL *ssl) {
@@ -1564,41 +1570,13 @@
     return NULL;
   }
 
-  if (ssl->cipher_list != NULL) {
-    return ssl->cipher_list->ciphers;
-  }
-
-  if (ssl->version >= TLS1_1_VERSION && ssl->ctx->cipher_list_tls11 != NULL) {
-    return ssl->ctx->cipher_list_tls11->ciphers;
-  }
-
-  if (ssl->version >= TLS1_VERSION && ssl->ctx->cipher_list_tls10 != NULL) {
-    return ssl->ctx->cipher_list_tls10->ciphers;
-  }
-
-  if (ssl->ctx->cipher_list != NULL) {
-    return ssl->ctx->cipher_list->ciphers;
-  }
-
-  return NULL;
-}
-
-/* return a STACK of the ciphers available for the SSL and in order of
- * algorithm id */
-STACK_OF(SSL_CIPHER) *ssl_get_ciphers_by_id(SSL *ssl) {
-  if (ssl == NULL) {
+  const struct ssl_cipher_preference_list_st *prefs =
+      ssl_get_cipher_preferences(ssl);
+  if (prefs == NULL) {
     return NULL;
   }
 
-  if (ssl->cipher_list_by_id != NULL) {
-    return ssl->cipher_list_by_id;
-  }
-
-  if (ssl->ctx->cipher_list_by_id != NULL) {
-    return ssl->ctx->cipher_list_by_id;
-  }
-
-  return NULL;
+  return prefs->ciphers;
 }
 
 const char *SSL_get_cipher_list(const SSL *ssl, int n) {
@@ -1623,8 +1601,8 @@
 }
 
 int SSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str) {
-  STACK_OF(SSL_CIPHER) *cipher_list = ssl_create_cipher_list(
-      ctx->method, &ctx->cipher_list, &ctx->cipher_list_by_id, str);
+  STACK_OF(SSL_CIPHER) *cipher_list =
+      ssl_create_cipher_list(ctx->method, &ctx->cipher_list, str);
   if (cipher_list == NULL) {
     return 0;
   }
@@ -1639,8 +1617,8 @@
 }
 
 int SSL_CTX_set_cipher_list_tls10(SSL_CTX *ctx, const char *str) {
-  STACK_OF(SSL_CIPHER) *cipher_list = ssl_create_cipher_list(
-      ctx->method, &ctx->cipher_list_tls10, NULL, str);
+  STACK_OF(SSL_CIPHER) *cipher_list =
+      ssl_create_cipher_list(ctx->method, &ctx->cipher_list_tls10, str);
   if (cipher_list == NULL) {
     return 0;
   }
@@ -1655,8 +1633,8 @@
 }
 
 int SSL_CTX_set_cipher_list_tls11(SSL_CTX *ctx, const char *str) {
-  STACK_OF(SSL_CIPHER) *cipher_list = ssl_create_cipher_list(
-      ctx->method, &ctx->cipher_list_tls11, NULL, str);
+  STACK_OF(SSL_CIPHER) *cipher_list =
+      ssl_create_cipher_list(ctx->method, &ctx->cipher_list_tls11, str);
   if (cipher_list == NULL) {
     return 0;
   }
@@ -1671,8 +1649,8 @@
 }
 
 int SSL_set_cipher_list(SSL *ssl, const char *str) {
-  STACK_OF(SSL_CIPHER) *cipher_list = ssl_create_cipher_list(
-      ssl->ctx->method, &ssl->cipher_list, &ssl->cipher_list_by_id, str);
+  STACK_OF(SSL_CIPHER) *cipher_list =
+      ssl_create_cipher_list(ssl->ctx->method, &ssl->cipher_list, str);
   if (cipher_list == NULL) {
     return 0;
   }
@@ -1730,6 +1708,15 @@
     return ssl->tlsext_hostname;
   }
 
+  /* During the handshake, report the handshake value. */
+  if (ssl->s3->hs != NULL) {
+    return ssl->s3->hs->hostname;
+  }
+
+  /* SSL_get_servername may also be called after the handshake to look up the
+   * SNI value.
+   *
+   * TODO(davidben): This is almost unused. Can we remove it? */
   SSL_SESSION *session = SSL_get_session(ssl);
   if (session == NULL) {
     return NULL;
@@ -1792,16 +1779,15 @@
 
 int SSL_CTX_set_signed_cert_timestamp_list(SSL_CTX *ctx, const uint8_t *list,
                                            size_t list_len) {
-  OPENSSL_free(ctx->signed_cert_timestamp_list);
-  ctx->signed_cert_timestamp_list_length = 0;
-
-  ctx->signed_cert_timestamp_list = BUF_memdup(list, list_len);
-  if (ctx->signed_cert_timestamp_list == NULL) {
+  CBS sct_list;
+  CBS_init(&sct_list, list, list_len);
+  if (!ssl_is_sct_list_valid(&sct_list)) {
+    OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SCT_LIST);
     return 0;
   }
-  ctx->signed_cert_timestamp_list_length = list_len;
 
-  return 1;
+  return CBS_stow(&sct_list, &ctx->signed_cert_timestamp_list,
+                  &ctx->signed_cert_timestamp_list_length);
 }
 
 int SSL_CTX_set_ocsp_response(SSL_CTX *ctx, const uint8_t *response,
@@ -2056,7 +2042,7 @@
   uint32_t mask_k = 0;
   uint32_t mask_a = 0;
 
-  if (ssl->cert->x509 != NULL && ssl_has_private_key(ssl)) {
+  if (ssl->cert->x509_leaf != NULL && ssl_has_private_key(ssl)) {
     int type = ssl_private_key_type(ssl);
     if (type == NID_rsaEncryption) {
       mask_k |= SSL_kRSA;
@@ -2105,7 +2091,7 @@
    * decides to renew the ticket. Once the handshake is completed, it should be
    * inserted into the cache. */
   if (ssl->s3->established_session != ssl->session ||
-      (!ssl->server && ssl->tlsext_ticket_expected)) {
+      (!ssl->server && ssl->s3->hs->ticket_expected)) {
     if (use_internal_cache) {
       SSL_CTX_add_session(ctx, ssl->s3->established_session);
     }
@@ -2177,7 +2163,7 @@
 
 X509 *SSL_get_certificate(const SSL *ssl) {
   if (ssl->cert != NULL) {
-    return ssl->cert->x509;
+    return ssl->cert->x509_leaf;
   }
 
   return NULL;
@@ -2193,7 +2179,7 @@
 
 X509 *SSL_CTX_get0_certificate(const SSL_CTX *ctx) {
   if (ctx->cert != NULL) {
-    return ctx->cert->x509;
+    return ctx->cert->x509_leaf;
   }
 
   return NULL;
@@ -2923,6 +2909,10 @@
   return ssl->s3->tmp.new_cipher;
 }
 
+void SSL_set_retain_only_sha256_of_client_certs(SSL *ssl, int enabled) {
+  ssl->retain_only_sha256_of_client_certs = !!enabled;
+}
+
 void SSL_CTX_set_retain_only_sha256_of_client_certs(SSL_CTX *ctx, int enabled) {
   ctx->retain_only_sha256_of_client_certs = !!enabled;
 }
@@ -3060,7 +3050,7 @@
     return;
   }
 
-#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+#if defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE)
   out_clock->tv_sec = 1234;
   out_clock->tv_usec = 1234;
 #elif defined(OPENSSL_WINDOWS)
diff --git a/src/ssl/ssl_rsa.c b/src/ssl/ssl_rsa.c
index 29e5f19..e984012 100644
--- a/src/ssl/ssl_rsa.c
+++ b/src/ssl/ssl_rsa.c
@@ -134,13 +134,14 @@
     return 0;
   }
 
-  if (c->x509 != NULL) {
+  X509 *x509_leaf = c->x509_leaf;
+  if (x509_leaf != NULL) {
     /* Sanity-check that the private key and the certificate match, unless the
      * key is opaque (in case of, say, a smartcard). */
     if (!EVP_PKEY_is_opaque(pkey) &&
-        !X509_check_private_key(c->x509, pkey)) {
-      X509_free(c->x509);
-      c->x509 = NULL;
+        !X509_check_private_key(x509_leaf, pkey)) {
+      X509_free(c->x509_leaf);
+      c->x509_leaf = NULL;
       return 0;
     }
   }
@@ -248,9 +249,9 @@
 
   EVP_PKEY_free(pkey);
 
-  X509_free(c->x509);
+  X509_free(c->x509_leaf);
   X509_up_ref(x);
-  c->x509 = x;
+  c->x509_leaf = x;
 
   return 1;
 }
diff --git a/src/ssl/ssl_session.c b/src/ssl/ssl_session.c
index c2396b1..a6b669d 100644
--- a/src/ssl/ssl_session.c
+++ b/src/ssl/ssl_session.c
@@ -199,13 +199,13 @@
       goto err;
     }
   }
-  if (session->peer != NULL) {
-    X509_up_ref(session->peer);
-    new_session->peer = session->peer;
+  if (session->x509_peer != NULL) {
+    X509_up_ref(session->x509_peer);
+    new_session->x509_peer = session->x509_peer;
   }
-  if (session->cert_chain != NULL) {
-    new_session->cert_chain = X509_chain_up_ref(session->cert_chain);
-    if (new_session->cert_chain == NULL) {
+  if (session->x509_chain != NULL) {
+    new_session->x509_chain = X509_chain_up_ref(session->x509_chain);
+    if (new_session->x509_chain == NULL) {
       goto err;
     }
   }
@@ -234,6 +234,13 @@
   memcpy(new_session->peer_sha256, session->peer_sha256, SHA256_DIGEST_LENGTH);
   new_session->peer_sha256_valid = session->peer_sha256_valid;
 
+  if (session->tlsext_hostname != NULL) {
+    new_session->tlsext_hostname = BUF_strdup(session->tlsext_hostname);
+    if (new_session->tlsext_hostname == NULL) {
+      goto err;
+    }
+  }
+
   new_session->timeout = session->timeout;
   new_session->time = session->time;
 
@@ -245,13 +252,6 @@
 
     new_session->key_exchange_info = session->key_exchange_info;
 
-    if (session->tlsext_hostname != NULL) {
-      new_session->tlsext_hostname = BUF_strdup(session->tlsext_hostname);
-      if (new_session->tlsext_hostname == NULL) {
-        goto err;
-      }
-    }
-
     memcpy(new_session->original_handshake_hash,
            session->original_handshake_hash,
            session->original_handshake_hash_len);
@@ -285,6 +285,31 @@
   return 0;
 }
 
+void ssl_session_refresh_time(SSL *ssl, SSL_SESSION *session) {
+  struct timeval now;
+  ssl_get_current_time(ssl, &now);
+
+  /* To avoid overflows and underflows, if we've gone back in time or any value
+   * is negative, update the time, but mark the session expired. */
+  if (session->time > now.tv_sec ||
+      session->time < 0 ||
+      now.tv_sec < 0) {
+    session->time = now.tv_sec;
+    session->timeout = 0;
+    return;
+  }
+
+  /* Adjust the session time and timeout. If the session has already expired,
+   * clamp the timeout at zero. */
+  long delta = now.tv_sec - session->time;
+  session->time = now.tv_sec;
+  if (session->timeout < delta) {
+    session->timeout = 0;
+  } else {
+    session->timeout -= delta;
+  }
+}
+
 int SSL_SESSION_up_ref(SSL_SESSION *session) {
   CRYPTO_refcount_inc(&session->references);
   return 1;
@@ -300,8 +325,8 @@
 
   OPENSSL_cleanse(session->master_key, sizeof(session->master_key));
   OPENSSL_cleanse(session->session_id, sizeof(session->session_id));
-  X509_free(session->peer);
-  sk_X509_pop_free(session->cert_chain, X509_free);
+  X509_free(session->x509_peer);
+  sk_X509_pop_free(session->x509_chain, X509_free);
   OPENSSL_free(session->tlsext_hostname);
   OPENSSL_free(session->tlsext_tick);
   OPENSSL_free(session->tlsext_signed_cert_timestamp_list);
@@ -332,7 +357,7 @@
 }
 
 X509 *SSL_SESSION_get0_peer(const SSL_SESSION *session) {
-  return session->peer;
+  return session->x509_peer;
 }
 
 size_t SSL_SESSION_get_master_key(const SSL_SESSION *session, uint8_t *out,
@@ -448,7 +473,7 @@
   session->ssl_version = ssl->version;
 
   if (is_server) {
-    if (ssl->tlsext_ticket_expected) {
+    if (ssl->s3->hs->ticket_expected) {
       /* Don't set session IDs for sessions resumed with tickets. This will keep
        * them out of the session cache. */
       session->session_id_length = 0;
@@ -599,7 +624,30 @@
 
   struct timeval now;
   ssl_get_current_time(ssl, &now);
-  return session->timeout >= (long)now.tv_sec - session->time;
+
+  /* Reject tickets from the future to avoid underflow. */
+  if ((long)now.tv_sec < session->time) {
+    return 0;
+  }
+
+  return session->timeout > (long)now.tv_sec - session->time;
+}
+
+int ssl_session_is_resumable(const SSL *ssl, const SSL_SESSION *session) {
+  return ssl_session_is_context_valid(ssl, session) &&
+         /* The session must not be expired. */
+         ssl_session_is_time_valid(ssl, session) &&
+         /* Only resume if the session's version matches the negotiated
+           * version. */
+         ssl->version == session->ssl_version &&
+         /* Only resume if the session's cipher matches the negotiated one. */
+         ssl->s3->tmp.new_cipher == session->cipher &&
+         /* If the session contains a client certificate (either the full
+          * certificate or just the hash) then require that the form of the
+          * certificate matches the current configuration. */
+         ((session->x509_peer == NULL && !session->peer_sha256_valid) ||
+          session->peer_sha256_valid ==
+              ssl->retain_only_sha256_of_client_certs);
 }
 
 /* ssl_lookup_session looks up |session_id| in the session cache and sets
@@ -662,15 +710,8 @@
     }
   }
 
-  if (session == NULL) {
-    return ssl_session_success;
-  }
-
-  if (!ssl_session_is_context_valid(ssl, session)) {
-    /* The client did not offer a suitable ticket or session ID. */
-    SSL_SESSION_free(session);
-    session = NULL;
-  } else if (!ssl_session_is_time_valid(ssl, session)) {
+  if (session != NULL &&
+      !ssl_session_is_time_valid(ssl, session)) {
     /* The session was from the cache, so remove it. */
     SSL_CTX_remove_session(ssl->initial_ctx, session);
     SSL_SESSION_free(session);
@@ -682,8 +723,8 @@
 }
 
 enum ssl_session_result_t ssl_get_prev_session(
-    SSL *ssl, SSL_SESSION **out_session, int *out_send_ticket,
-    const struct ssl_early_callback_ctx *ctx) {
+    SSL *ssl, SSL_SESSION **out_session, int *out_tickets_supported,
+    int *out_renew_ticket, const struct ssl_early_callback_ctx *ctx) {
   /* This is used only by servers. */
   assert(ssl->server);
   SSL_SESSION *session = NULL;
@@ -712,11 +753,8 @@
   }
 
   *out_session = session;
-  if (session != NULL) {
-    *out_send_ticket = renew_ticket;
-  } else {
-    *out_send_ticket = tickets_supported;
-  }
+  *out_tickets_supported = tickets_supported;
+  *out_renew_ticket = renew_ticket;
   return ssl_session_success;
 }
 
diff --git a/src/ssl/ssl_test.cc b/src/ssl/ssl_test.cc
index cfce2d0..ae9d5ca 100644
--- a/src/ssl/ssl_test.cc
+++ b/src/ssl/ssl_test.cc
@@ -23,11 +23,14 @@
 
 #include <openssl/base64.h>
 #include <openssl/bio.h>
+#include <openssl/cipher.h>
 #include <openssl/crypto.h>
 #include <openssl/err.h>
+#include <openssl/hmac.h>
 #include <openssl/pem.h>
 #include <openssl/sha.h>
 #include <openssl/ssl.h>
+#include <openssl/rand.h>
 #include <openssl/x509.h>
 
 #include "internal.h"
@@ -269,7 +272,6 @@
   "SSLv3",
   "TLSv1",
   "TLSv1.2",
-  "GENERIC",
 };
 
 static const char *kMustNotIncludeCECPQ1[] = {
@@ -294,7 +296,6 @@
   "AES256",
   "AESGCM",
   "CHACHA20",
-  "GENERIC",
 };
 
 static const CurveTest kCurveTests[] = {
@@ -864,18 +865,22 @@
   return true;
 }
 
-// CreateSessionWithTicket returns a sample |SSL_SESSION| with the ticket
-// replaced for one of length |ticket_len| or nullptr on failure.
-static bssl::UniquePtr<SSL_SESSION> CreateSessionWithTicket(size_t ticket_len) {
+// CreateSessionWithTicket returns a sample |SSL_SESSION| with the specified
+// version and ticket length or nullptr on failure.
+static bssl::UniquePtr<SSL_SESSION> CreateSessionWithTicket(uint16_t version,
+                                                            size_t ticket_len) {
   std::vector<uint8_t> der;
   if (!DecodeBase64(&der, kOpenSSLSession)) {
     return nullptr;
   }
-  bssl::UniquePtr<SSL_SESSION> session(SSL_SESSION_from_bytes(der.data(), der.size()));
+  bssl::UniquePtr<SSL_SESSION> session(
+      SSL_SESSION_from_bytes(der.data(), der.size()));
   if (!session) {
     return nullptr;
   }
 
+  session->ssl_version = version;
+
   // Swap out the ticket for a garbage one.
   OPENSSL_free(session->tlsext_tick);
   session->tlsext_tick = reinterpret_cast<uint8_t*>(OPENSSL_malloc(ticket_len));
@@ -886,7 +891,11 @@
   session->tlsext_ticklen = ticket_len;
 
   // Fix up the timeout.
+#if defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE)
+  session->time = 1234;
+#else
   session->time = time(NULL);
+#endif
   return session;
 }
 
@@ -914,27 +923,32 @@
   return true;
 }
 
-// GetClientHelloLen creates a client SSL connection with a ticket of length
-// |ticket_len| and records the ClientHello. It returns the length of the
-// ClientHello, not including the record header, on success and zero on error.
-static size_t GetClientHelloLen(size_t ticket_len) {
+// GetClientHelloLen creates a client SSL connection with the specified version
+// and ticket length. It returns the length of the ClientHello, not including
+// the record header, on success and zero on error.
+static size_t GetClientHelloLen(uint16_t max_version, uint16_t session_version,
+                                size_t ticket_len) {
   bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
-  bssl::UniquePtr<SSL_SESSION> session = CreateSessionWithTicket(ticket_len);
+  bssl::UniquePtr<SSL_SESSION> session =
+      CreateSessionWithTicket(session_version, ticket_len);
   if (!ctx || !session) {
     return 0;
   }
+
+  // Set a one-element cipher list so the baseline ClientHello is unpadded.
   bssl::UniquePtr<SSL> ssl(SSL_new(ctx.get()));
-  // Test at TLS 1.2. TLS 1.3 adds enough extensions that the ClientHello is
-  // longer than our test vectors.
   if (!ssl || !SSL_set_session(ssl.get(), session.get()) ||
-      !SSL_set_max_proto_version(ssl.get(), TLS1_2_VERSION)) {
+      !SSL_set_cipher_list(ssl.get(), "ECDHE-RSA-AES128-GCM-SHA256") ||
+      !SSL_set_max_proto_version(ssl.get(), max_version)) {
     return 0;
   }
+
   std::vector<uint8_t> client_hello;
   if (!GetClientHello(ssl.get(), &client_hello) ||
       client_hello.size() <= SSL3_RT_HEADER_LENGTH) {
     return 0;
   }
+
   return client_hello.size() - SSL3_RT_HEADER_LENGTH;
 }
 
@@ -963,28 +977,37 @@
     {0x201, 0x201},
 };
 
-static bool TestPaddingExtension() {
+static bool TestPaddingExtension(uint16_t max_version,
+                                 uint16_t session_version) {
   // Sample a baseline length.
-  size_t base_len = GetClientHelloLen(1);
+  size_t base_len = GetClientHelloLen(max_version, session_version, 1);
   if (base_len == 0) {
     return false;
   }
 
   for (const PaddingTest &test : kPaddingTests) {
     if (base_len > test.input_len) {
-      fprintf(stderr, "Baseline ClientHello too long.\n");
+      fprintf(stderr,
+              "Baseline ClientHello too long (max_version = %04x, "
+              "session_version = %04x).\n",
+              max_version, session_version);
       return false;
     }
 
-    size_t padded_len = GetClientHelloLen(1 + test.input_len - base_len);
+    size_t padded_len = GetClientHelloLen(max_version, session_version,
+                                          1 + test.input_len - base_len);
     if (padded_len != test.padded_len) {
-      fprintf(stderr, "%u-byte ClientHello padded to %u bytes, not %u.\n",
+      fprintf(stderr,
+              "%u-byte ClientHello padded to %u bytes, not %u (max_version = "
+              "%04x, session_version = %04x).\n",
               static_cast<unsigned>(test.input_len),
               static_cast<unsigned>(padded_len),
-              static_cast<unsigned>(test.padded_len));
+              static_cast<unsigned>(test.padded_len), max_version,
+              session_version);
       return false;
     }
   }
+
   return true;
 }
 
@@ -1273,115 +1296,104 @@
   return true;
 }
 
-static uint16_t kTLSVersions[] = {
-    SSL3_VERSION, TLS1_VERSION, TLS1_1_VERSION, TLS1_2_VERSION, TLS1_3_VERSION,
-};
-
-static uint16_t kDTLSVersions[] = {
-    DTLS1_VERSION, DTLS1_2_VERSION,
-};
-
-static bool TestSequenceNumber() {
-  for (bool is_dtls : std::vector<bool>{false, true}) {
-    const SSL_METHOD *method = is_dtls ? DTLS_method() : TLS_method();
-    const uint16_t *versions = is_dtls ? kDTLSVersions : kTLSVersions;
-    size_t num_versions = is_dtls ? OPENSSL_ARRAY_SIZE(kDTLSVersions)
-                                  : OPENSSL_ARRAY_SIZE(kTLSVersions);
-    for (size_t i = 0; i < num_versions; i++) {
-      uint16_t version = versions[i];
-      bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(method));
-      bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(method));
-      if (!server_ctx || !client_ctx ||
-          !SSL_CTX_set_min_proto_version(client_ctx.get(), version) ||
-          !SSL_CTX_set_max_proto_version(client_ctx.get(), version) ||
-          !SSL_CTX_set_min_proto_version(server_ctx.get(), version) ||
-          !SSL_CTX_set_max_proto_version(server_ctx.get(), version)) {
-        return false;
-      }
-
-      bssl::UniquePtr<X509> cert = GetTestCertificate();
-      bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
-      if (!cert || !key ||
-          !SSL_CTX_use_certificate(server_ctx.get(), cert.get()) ||
-          !SSL_CTX_use_PrivateKey(server_ctx.get(), key.get())) {
-        return false;
-      }
-
-      bssl::UniquePtr<SSL> client, server;
-      if (!ConnectClientAndServer(&client, &server, client_ctx.get(),
-                                  server_ctx.get(), nullptr /* no session */)) {
-        return false;
-      }
-
-      // Drain any post-handshake messages to ensure there are no unread records
-      // on either end.
-      uint8_t byte = 0;
-      if (SSL_read(client.get(), &byte, 1) > 0 ||
-          SSL_read(server.get(), &byte, 1) > 0) {
-        fprintf(stderr, "Received unexpected data.\n");
-        return false;
-      }
-
-      uint64_t client_read_seq = SSL_get_read_sequence(client.get());
-      uint64_t client_write_seq = SSL_get_write_sequence(client.get());
-      uint64_t server_read_seq = SSL_get_read_sequence(server.get());
-      uint64_t server_write_seq = SSL_get_write_sequence(server.get());
-
-      if (is_dtls) {
-        // Both client and server must be at epoch 1.
-        if (EpochFromSequence(client_read_seq) != 1 ||
-            EpochFromSequence(client_write_seq) != 1 ||
-            EpochFromSequence(server_read_seq) != 1 ||
-            EpochFromSequence(server_write_seq) != 1) {
-          fprintf(stderr, "Bad epochs.\n");
-          return false;
-        }
-
-        // The next record to be written should exceed the largest received.
-        if (client_write_seq <= server_read_seq ||
-            server_write_seq <= client_read_seq) {
-          fprintf(stderr, "Inconsistent sequence numbers.\n");
-          return false;
-        }
-      } else {
-        // The next record to be written should equal the next to be received.
-        if (client_write_seq != server_read_seq ||
-            server_write_seq != client_read_seq) {
-          fprintf(stderr, "Inconsistent sequence numbers.\n");
-          return false;
-        }
-      }
-
-      // Send a record from client to server.
-      if (SSL_write(client.get(), &byte, 1) != 1 ||
-          SSL_read(server.get(), &byte, 1) != 1) {
-        fprintf(stderr, "Could not send byte.\n");
-        return false;
-      }
-
-      // The client write and server read sequence numbers should have
-      // incremented.
-      if (client_write_seq + 1 != SSL_get_write_sequence(client.get()) ||
-          server_read_seq + 1 != SSL_get_read_sequence(server.get())) {
-        fprintf(stderr, "Sequence numbers did not increment.\n");
-        return false;
-      }
-    }
-  }
-
-  return true;
-}
-
-static bool TestOneSidedShutdown() {
-  bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
-  bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(TLS_method()));
-  if (!client_ctx || !server_ctx) {
+static bool TestSequenceNumber(bool is_dtls, const SSL_METHOD *method,
+                               uint16_t version) {
+  bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(method));
+  bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(method));
+  if (!server_ctx || !client_ctx ||
+      !SSL_CTX_set_min_proto_version(client_ctx.get(), version) ||
+      !SSL_CTX_set_max_proto_version(client_ctx.get(), version) ||
+      !SSL_CTX_set_min_proto_version(server_ctx.get(), version) ||
+      !SSL_CTX_set_max_proto_version(server_ctx.get(), version)) {
     return false;
   }
 
   bssl::UniquePtr<X509> cert = GetTestCertificate();
   bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
-  if (!cert || !key ||
+  if (!cert || !key || !SSL_CTX_use_certificate(server_ctx.get(), cert.get()) ||
+      !SSL_CTX_use_PrivateKey(server_ctx.get(), key.get())) {
+    return false;
+  }
+
+  bssl::UniquePtr<SSL> client, server;
+  if (!ConnectClientAndServer(&client, &server, client_ctx.get(),
+                              server_ctx.get(), nullptr /* no session */)) {
+    return false;
+  }
+
+  // Drain any post-handshake messages to ensure there are no unread records
+  // on either end.
+  uint8_t byte = 0;
+  if (SSL_read(client.get(), &byte, 1) > 0 ||
+      SSL_read(server.get(), &byte, 1) > 0) {
+    fprintf(stderr, "Received unexpected data.\n");
+    return false;
+  }
+
+  uint64_t client_read_seq = SSL_get_read_sequence(client.get());
+  uint64_t client_write_seq = SSL_get_write_sequence(client.get());
+  uint64_t server_read_seq = SSL_get_read_sequence(server.get());
+  uint64_t server_write_seq = SSL_get_write_sequence(server.get());
+
+  if (is_dtls) {
+    // Both client and server must be at epoch 1.
+    if (EpochFromSequence(client_read_seq) != 1 ||
+        EpochFromSequence(client_write_seq) != 1 ||
+        EpochFromSequence(server_read_seq) != 1 ||
+        EpochFromSequence(server_write_seq) != 1) {
+      fprintf(stderr, "Bad epochs.\n");
+      return false;
+    }
+
+    // The next record to be written should exceed the largest received.
+    if (client_write_seq <= server_read_seq ||
+        server_write_seq <= client_read_seq) {
+      fprintf(stderr, "Inconsistent sequence numbers.\n");
+      return false;
+    }
+  } else {
+    // The next record to be written should equal the next to be received.
+    if (client_write_seq != server_read_seq ||
+        server_write_seq != client_read_seq) {
+      fprintf(stderr, "Inconsistent sequence numbers.\n");
+      return false;
+    }
+  }
+
+  // Send a record from client to server.
+  if (SSL_write(client.get(), &byte, 1) != 1 ||
+      SSL_read(server.get(), &byte, 1) != 1) {
+    fprintf(stderr, "Could not send byte.\n");
+    return false;
+  }
+
+  // The client write and server read sequence numbers should have
+  // incremented.
+  if (client_write_seq + 1 != SSL_get_write_sequence(client.get()) ||
+      server_read_seq + 1 != SSL_get_read_sequence(server.get())) {
+    fprintf(stderr, "Sequence numbers did not increment.\n");
+    return false;
+  }
+
+  return true;
+}
+
+static bool TestOneSidedShutdown(bool is_dtls, const SSL_METHOD *method,
+                                 uint16_t version) {
+  // SSL_shutdown is a no-op in DTLS.
+  if (is_dtls) {
+    return true;
+  }
+
+  bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(method));
+  bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(method));
+  bssl::UniquePtr<X509> cert = GetTestCertificate();
+  bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
+  if (!client_ctx || !server_ctx || !cert || !key ||
+      !SSL_CTX_set_min_proto_version(server_ctx.get(), version) ||
+      !SSL_CTX_set_max_proto_version(server_ctx.get(), version) ||
+      !SSL_CTX_set_min_proto_version(client_ctx.get(), version) ||
+      !SSL_CTX_set_max_proto_version(client_ctx.get(), version) ||
       !SSL_CTX_use_certificate(server_ctx.get(), cert.get()) ||
       !SSL_CTX_use_PrivateKey(server_ctx.get(), key.get())) {
     return false;
@@ -1427,6 +1439,7 @@
 
   return true;
 }
+
 static bool TestSessionDuplication() {
   bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
   bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(TLS_method()));
@@ -1631,63 +1644,63 @@
 
 static int VerifySucceed(X509_STORE_CTX *store_ctx, void *arg) { return 1; }
 
-static bool TestGetPeerCertificate() {
+static bool TestGetPeerCertificate(bool is_dtls, const SSL_METHOD *method,
+                                   uint16_t version) {
   bssl::UniquePtr<X509> cert = GetTestCertificate();
   bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
   if (!cert || !key) {
     return false;
   }
 
-  for (uint16_t version : kTLSVersions) {
-    // Configure both client and server to accept any certificate.
-    bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
-    if (!ctx ||
-        !SSL_CTX_use_certificate(ctx.get(), cert.get()) ||
-        !SSL_CTX_use_PrivateKey(ctx.get(), key.get()) ||
-        !SSL_CTX_set_min_proto_version(ctx.get(), version) ||
-        !SSL_CTX_set_max_proto_version(ctx.get(), version)) {
-      return false;
-    }
-    SSL_CTX_set_verify(
-        ctx.get(), SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr);
-    SSL_CTX_set_cert_verify_callback(ctx.get(), VerifySucceed, NULL);
+  // Configure both client and server to accept any certificate.
+  bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(method));
+  if (!ctx ||
+      !SSL_CTX_use_certificate(ctx.get(), cert.get()) ||
+      !SSL_CTX_use_PrivateKey(ctx.get(), key.get()) ||
+      !SSL_CTX_set_min_proto_version(ctx.get(), version) ||
+      !SSL_CTX_set_max_proto_version(ctx.get(), version)) {
+    return false;
+  }
+  SSL_CTX_set_verify(
+      ctx.get(), SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr);
+  SSL_CTX_set_cert_verify_callback(ctx.get(), VerifySucceed, NULL);
 
-    bssl::UniquePtr<SSL> client, server;
-    if (!ConnectClientAndServer(&client, &server, ctx.get(), ctx.get(),
-                                nullptr /* no session */)) {
-      return false;
-    }
+  bssl::UniquePtr<SSL> client, server;
+  if (!ConnectClientAndServer(&client, &server, ctx.get(), ctx.get(),
+                              nullptr /* no session */)) {
+    return false;
+  }
 
-    // Client and server should both see the leaf certificate.
-    bssl::UniquePtr<X509> peer(SSL_get_peer_certificate(server.get()));
-    if (!peer || X509_cmp(cert.get(), peer.get()) != 0) {
-      fprintf(stderr, "%x: Server peer certificate did not match.\n", version);
-      return false;
-    }
+  // Client and server should both see the leaf certificate.
+  bssl::UniquePtr<X509> peer(SSL_get_peer_certificate(server.get()));
+  if (!peer || X509_cmp(cert.get(), peer.get()) != 0) {
+    fprintf(stderr, "Server peer certificate did not match.\n");
+    return false;
+  }
 
-    peer.reset(SSL_get_peer_certificate(client.get()));
-    if (!peer || X509_cmp(cert.get(), peer.get()) != 0) {
-      fprintf(stderr, "%x: Client peer certificate did not match.\n", version);
-      return false;
-    }
+  peer.reset(SSL_get_peer_certificate(client.get()));
+  if (!peer || X509_cmp(cert.get(), peer.get()) != 0) {
+    fprintf(stderr, "Client peer certificate did not match.\n");
+    return false;
+  }
 
-    // However, for historical reasons, the chain includes the leaf on the
-    // client, but does not on the server.
-    if (sk_X509_num(SSL_get_peer_cert_chain(client.get())) != 1) {
-      fprintf(stderr, "%x: Client peer chain was incorrect.\n", version);
-      return false;
-    }
+  // However, for historical reasons, the chain includes the leaf on the
+  // client, but does not on the server.
+  if (sk_X509_num(SSL_get_peer_cert_chain(client.get())) != 1) {
+    fprintf(stderr, "Client peer chain was incorrect.\n");
+    return false;
+  }
 
-    if (sk_X509_num(SSL_get_peer_cert_chain(server.get())) != 0) {
-      fprintf(stderr, "%x: Server peer chain was incorrect.\n", version);
-      return false;
-    }
+  if (sk_X509_num(SSL_get_peer_cert_chain(server.get())) != 0) {
+    fprintf(stderr, "Server peer chain was incorrect.\n");
+    return false;
   }
 
   return true;
 }
 
-static bool TestRetainOnlySHA256OfCerts() {
+static bool TestRetainOnlySHA256OfCerts(bool is_dtls, const SSL_METHOD *method,
+                                        uint16_t version) {
   bssl::UniquePtr<X509> cert = GetTestCertificate();
   bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
   if (!cert || !key) {
@@ -1704,45 +1717,43 @@
   uint8_t cert_sha256[SHA256_DIGEST_LENGTH];
   SHA256(cert_der, cert_der_len, cert_sha256);
 
-  for (uint16_t version : kTLSVersions) {
-    // Configure both client and server to accept any certificate, but the
-    // server must retain only the SHA-256 of the peer.
-    bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
-    if (!ctx ||
-        !SSL_CTX_use_certificate(ctx.get(), cert.get()) ||
-        !SSL_CTX_use_PrivateKey(ctx.get(), key.get()) ||
-        !SSL_CTX_set_min_proto_version(ctx.get(), version) ||
-        !SSL_CTX_set_max_proto_version(ctx.get(), version)) {
-      return false;
-    }
-    SSL_CTX_set_verify(
-        ctx.get(), SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr);
-    SSL_CTX_set_cert_verify_callback(ctx.get(), VerifySucceed, NULL);
-    SSL_CTX_set_retain_only_sha256_of_client_certs(ctx.get(), 1);
+  // Configure both client and server to accept any certificate, but the
+  // server must retain only the SHA-256 of the peer.
+  bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(method));
+  if (!ctx ||
+      !SSL_CTX_use_certificate(ctx.get(), cert.get()) ||
+      !SSL_CTX_use_PrivateKey(ctx.get(), key.get()) ||
+      !SSL_CTX_set_min_proto_version(ctx.get(), version) ||
+      !SSL_CTX_set_max_proto_version(ctx.get(), version)) {
+    return false;
+  }
+  SSL_CTX_set_verify(
+      ctx.get(), SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr);
+  SSL_CTX_set_cert_verify_callback(ctx.get(), VerifySucceed, NULL);
+  SSL_CTX_set_retain_only_sha256_of_client_certs(ctx.get(), 1);
 
-    bssl::UniquePtr<SSL> client, server;
-    if (!ConnectClientAndServer(&client, &server, ctx.get(), ctx.get(),
-                                nullptr /* no session */)) {
-      return false;
-    }
+  bssl::UniquePtr<SSL> client, server;
+  if (!ConnectClientAndServer(&client, &server, ctx.get(), ctx.get(),
+                              nullptr /* no session */)) {
+    return false;
+  }
 
-    // The peer certificate has been dropped.
-    bssl::UniquePtr<X509> peer(SSL_get_peer_certificate(server.get()));
-    if (peer) {
-      fprintf(stderr, "%x: Peer certificate was retained.\n", version);
-      return false;
-    }
+  // The peer certificate has been dropped.
+  bssl::UniquePtr<X509> peer(SSL_get_peer_certificate(server.get()));
+  if (peer) {
+    fprintf(stderr, "Peer certificate was retained.\n");
+    return false;
+  }
 
-    SSL_SESSION *session = SSL_get_session(server.get());
-    if (!session->peer_sha256_valid) {
-      fprintf(stderr, "%x: peer_sha256_valid was not set.\n", version);
-      return false;
-    }
+  SSL_SESSION *session = SSL_get_session(server.get());
+  if (!session->peer_sha256_valid) {
+    fprintf(stderr, "peer_sha256_valid was not set.\n");
+    return false;
+  }
 
-    if (memcmp(cert_sha256, session->peer_sha256, SHA256_DIGEST_LENGTH) != 0) {
-      fprintf(stderr, "%x: peer_sha256 did not match.\n", version);
-      return false;
-    }
+  if (memcmp(cert_sha256, session->peer_sha256, SHA256_DIGEST_LENGTH) != 0) {
+    fprintf(stderr, "peer_sha256 did not match.\n");
+    return false;
   }
 
   return true;
@@ -1900,8 +1911,8 @@
       0xc0, 0x28, 0x00, 0x39, 0x00, 0x6b, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x2f,
       0x00, 0x3c, 0x00, 0x35, 0x00, 0x3d, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x37,
       0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x23, 0x00,
-      0x00, 0x00, 0x0d, 0x00, 0x14, 0x00, 0x12, 0x08, 0x06, 0x06, 0x01, 0x08,
-      0x05, 0x05, 0x01, 0x05, 0x03, 0x08, 0x04, 0x04, 0x01, 0x04, 0x03, 0x02,
+      0x00, 0x00, 0x0d, 0x00, 0x14, 0x00, 0x12, 0x04, 0x03, 0x08, 0x04, 0x04,
+      0x01, 0x05, 0x03, 0x08, 0x05, 0x05, 0x01, 0x08, 0x06, 0x06, 0x01, 0x02,
       0x01, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x08, 0x00,
       0x06, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18,
   };
@@ -1974,7 +1985,64 @@
   return true;
 }
 
-static bool TestSessionIDContext() {
+static bssl::UniquePtr<SSL_SESSION> ExpectSessionRenewed(SSL_CTX *client_ctx,
+                                                         SSL_CTX *server_ctx,
+                                                         SSL_SESSION *session) {
+  g_last_session = nullptr;
+  SSL_CTX_sess_set_new_cb(client_ctx, SaveLastSession);
+
+  bssl::UniquePtr<SSL> client, server;
+  if (!ConnectClientAndServer(&client, &server, client_ctx,
+                              server_ctx, session)) {
+    fprintf(stderr, "Failed to connect client and server.\n");
+    return nullptr;
+  }
+
+  if (SSL_session_reused(client.get()) != SSL_session_reused(server.get())) {
+    fprintf(stderr, "Client and server were inconsistent.\n");
+    return nullptr;
+  }
+
+  if (!SSL_session_reused(client.get())) {
+    fprintf(stderr, "Session was not reused.\n");
+    return nullptr;
+  }
+
+  // Run the read loop to account for post-handshake tickets in TLS 1.3.
+  SSL_read(client.get(), nullptr, 0);
+
+  SSL_CTX_sess_set_new_cb(client_ctx, nullptr);
+
+  if (!g_last_session) {
+    fprintf(stderr, "Client did not receive a renewed session.\n");
+    return nullptr;
+  }
+  return std::move(g_last_session);
+}
+
+static int SwitchSessionIDContextSNI(SSL *ssl, int *out_alert, void *arg) {
+  static const uint8_t kContext[] = {3};
+
+  if (!SSL_set_session_id_context(ssl, kContext, sizeof(kContext))) {
+    return SSL_TLSEXT_ERR_ALERT_FATAL;
+  }
+
+  return SSL_TLSEXT_ERR_OK;
+}
+
+static int SwitchSessionIDContextEarly(
+    const struct ssl_early_callback_ctx *ctx) {
+  static const uint8_t kContext[] = {3};
+
+  if (!SSL_set_session_id_context(ctx->ssl, kContext, sizeof(kContext))) {
+    return -1;
+  }
+
+  return 1;
+}
+
+static bool TestSessionIDContext(bool is_dtls, const SSL_METHOD *method,
+                                 uint16_t version) {
   bssl::UniquePtr<X509> cert = GetTestCertificate();
   bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
   if (!cert || !key) {
@@ -1984,50 +2052,74 @@
   static const uint8_t kContext1[] = {1};
   static const uint8_t kContext2[] = {2};
 
-  for (uint16_t version : kTLSVersions) {
-    bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(TLS_method()));
-    bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
-    if (!server_ctx || !client_ctx ||
-        !SSL_CTX_use_certificate(server_ctx.get(), cert.get()) ||
-        !SSL_CTX_use_PrivateKey(server_ctx.get(), key.get()) ||
-        !SSL_CTX_set_session_id_context(server_ctx.get(), kContext1,
-                                        sizeof(kContext1)) ||
-        !SSL_CTX_set_min_proto_version(client_ctx.get(), version) ||
-        !SSL_CTX_set_max_proto_version(client_ctx.get(), version) ||
-        !SSL_CTX_set_min_proto_version(server_ctx.get(), version) ||
-        !SSL_CTX_set_max_proto_version(server_ctx.get(), version)) {
-      return false;
-    }
+  bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(method));
+  bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(method));
+  if (!server_ctx || !client_ctx ||
+      !SSL_CTX_use_certificate(server_ctx.get(), cert.get()) ||
+      !SSL_CTX_use_PrivateKey(server_ctx.get(), key.get()) ||
+      !SSL_CTX_set_session_id_context(server_ctx.get(), kContext1,
+                                      sizeof(kContext1)) ||
+      !SSL_CTX_set_min_proto_version(client_ctx.get(), version) ||
+      !SSL_CTX_set_max_proto_version(client_ctx.get(), version) ||
+      !SSL_CTX_set_min_proto_version(server_ctx.get(), version) ||
+      !SSL_CTX_set_max_proto_version(server_ctx.get(), version)) {
+    return false;
+  }
 
-    SSL_CTX_set_session_cache_mode(client_ctx.get(), SSL_SESS_CACHE_BOTH);
-    SSL_CTX_set_session_cache_mode(server_ctx.get(), SSL_SESS_CACHE_BOTH);
+  SSL_CTX_set_session_cache_mode(client_ctx.get(), SSL_SESS_CACHE_BOTH);
+  SSL_CTX_set_session_cache_mode(server_ctx.get(), SSL_SESS_CACHE_BOTH);
 
-    bssl::UniquePtr<SSL_SESSION> session =
-        CreateClientSession(client_ctx.get(), server_ctx.get());
-    if (!session) {
-      fprintf(stderr, "Error getting session (version = %04x).\n", version);
-      return false;
-    }
+  bssl::UniquePtr<SSL_SESSION> session =
+      CreateClientSession(client_ctx.get(), server_ctx.get());
+  if (!session) {
+    fprintf(stderr, "Error getting session.\n");
+    return false;
+  }
 
-    if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(), session.get(),
-                             true /* expect session reused */)) {
-      fprintf(stderr, "Error resuming session (version = %04x).\n", version);
-      return false;
-    }
+  if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(), session.get(),
+                           true /* expect session reused */)) {
+    fprintf(stderr, "Error resuming session.\n");
+    return false;
+  }
 
-    // Change the session ID context.
-    if (!SSL_CTX_set_session_id_context(server_ctx.get(), kContext2,
-                                        sizeof(kContext2))) {
-      return false;
-    }
+  // Change the session ID context.
+  if (!SSL_CTX_set_session_id_context(server_ctx.get(), kContext2,
+                                      sizeof(kContext2))) {
+    return false;
+  }
 
-    if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(), session.get(),
-                             false /* expect session not reused */)) {
-      fprintf(stderr,
-              "Error connection with different context (version = %04x).\n",
-              version);
-      return false;
-    }
+  if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(), session.get(),
+                           false /* expect session not reused */)) {
+    fprintf(stderr, "Error connecting with a different context.\n");
+    return false;
+  }
+
+  // Change the session ID context back and install an SNI callback to switch
+  // it.
+  if (!SSL_CTX_set_session_id_context(server_ctx.get(), kContext1,
+                                      sizeof(kContext1))) {
+    return false;
+  }
+
+  SSL_CTX_set_tlsext_servername_callback(server_ctx.get(),
+                                         SwitchSessionIDContextSNI);
+
+  if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(), session.get(),
+                           false /* expect session not reused */)) {
+    fprintf(stderr, "Error connecting with a context switch on SNI callback.\n");
+    return false;
+  }
+
+  // Switch the session ID context with the early callback instead.
+  SSL_CTX_set_tlsext_servername_callback(server_ctx.get(), nullptr);
+  SSL_CTX_set_select_certificate_cb(server_ctx.get(),
+                                    SwitchSessionIDContextEarly);
+
+  if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(), session.get(),
+                           false /* expect session not reused */)) {
+    fprintf(stderr,
+            "Error connecting with a context switch on early callback.\n");
+    return false;
   }
 
   return true;
@@ -2039,16 +2131,78 @@
   *out_clock = g_current_time;
 }
 
-static bool TestSessionTimeout() {
+static int RenewTicketCallback(SSL *ssl, uint8_t *key_name, uint8_t *iv,
+                               EVP_CIPHER_CTX *ctx, HMAC_CTX *hmac_ctx,
+                               int encrypt) {
+  static const uint8_t kZeros[16] = {0};
+
+  if (encrypt) {
+    memcpy(key_name, kZeros, sizeof(kZeros));
+    RAND_bytes(iv, 16);
+  } else if (memcmp(key_name, kZeros, 16) != 0) {
+    return 0;
+  }
+
+  if (!HMAC_Init_ex(hmac_ctx, kZeros, sizeof(kZeros), EVP_sha256(), NULL) ||
+      !EVP_CipherInit_ex(ctx, EVP_aes_128_cbc(), NULL, kZeros, iv, encrypt)) {
+    return -1;
+  }
+
+  // Returning two from the callback in decrypt mode renews the
+  // session in TLS 1.2 and below.
+  return encrypt ? 1 : 2;
+}
+
+static bool GetServerTicketTime(long *out, const SSL_SESSION *session) {
+  if (session->tlsext_ticklen < 16 + 16 + SHA256_DIGEST_LENGTH) {
+    return false;
+  }
+
+  const uint8_t *ciphertext = session->tlsext_tick + 16 + 16;
+  size_t len = session->tlsext_ticklen - 16 - 16 - SHA256_DIGEST_LENGTH;
+  std::unique_ptr<uint8_t[]> plaintext(new uint8_t[len]);
+
+#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+  // Fuzzer-mode tickets are unencrypted.
+  memcpy(plaintext.get(), ciphertext, len);
+#else
+  static const uint8_t kZeros[16] = {0};
+  const uint8_t *iv = session->tlsext_tick + 16;
+  bssl::ScopedEVP_CIPHER_CTX ctx;
+  int len1, len2;
+  if (!EVP_DecryptInit_ex(ctx.get(), EVP_aes_128_cbc(), nullptr, kZeros, iv) ||
+      !EVP_DecryptUpdate(ctx.get(), plaintext.get(), &len1, ciphertext, len) ||
+      !EVP_DecryptFinal_ex(ctx.get(), plaintext.get() + len1, &len2)) {
+    return false;
+  }
+
+  len = static_cast<size_t>(len1 + len2);
+#endif
+
+  bssl::UniquePtr<SSL_SESSION> server_session(
+      SSL_SESSION_from_bytes(plaintext.get(), len));
+  if (!server_session) {
+    return false;
+  }
+
+  *out = server_session->time;
+  return true;
+}
+
+static bool TestSessionTimeout(bool is_dtls, const SSL_METHOD *method,
+                               uint16_t version) {
   bssl::UniquePtr<X509> cert = GetTestCertificate();
   bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
   if (!cert || !key) {
     return false;
   }
 
-  for (uint16_t version : kTLSVersions) {
-    bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(TLS_method()));
-    bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
+  for (bool server_test : std::vector<bool>{false, true}) {
+    static const int kStartTime = 1000;
+    g_current_time.tv_sec = kStartTime;
+
+    bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(method));
+    bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(method));
     if (!server_ctx || !client_ctx ||
         !SSL_CTX_use_certificate(server_ctx.get(), cert.get()) ||
         !SSL_CTX_use_PrivateKey(server_ctx.get(), key.get()) ||
@@ -2060,23 +2214,31 @@
     }
 
     SSL_CTX_set_session_cache_mode(client_ctx.get(), SSL_SESS_CACHE_BOTH);
-
     SSL_CTX_set_session_cache_mode(server_ctx.get(), SSL_SESS_CACHE_BOTH);
-    SSL_CTX_set_current_time_cb(server_ctx.get(), CurrentTimeCallback);
+
+    // Both client and server must enforce session timeouts.
+    if (server_test) {
+      SSL_CTX_set_current_time_cb(server_ctx.get(), CurrentTimeCallback);
+    } else {
+      SSL_CTX_set_current_time_cb(client_ctx.get(), CurrentTimeCallback);
+    }
+
+    // Configure a ticket callback which renews tickets.
+    SSL_CTX_set_tlsext_ticket_key_cb(server_ctx.get(), RenewTicketCallback);
 
     bssl::UniquePtr<SSL_SESSION> session =
         CreateClientSession(client_ctx.get(), server_ctx.get());
     if (!session) {
-      fprintf(stderr, "Error getting session (version = %04x).\n", version);
+      fprintf(stderr, "Error getting session.\n");
       return false;
     }
 
     // Advance the clock just behind the timeout.
-    g_current_time.tv_sec += SSL_DEFAULT_SESSION_TIMEOUT;
+    g_current_time.tv_sec += SSL_DEFAULT_SESSION_TIMEOUT - 1;
 
     if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(), session.get(),
                              true /* expect session reused */)) {
-      fprintf(stderr, "Error resuming session (version = %04x).\n", version);
+      fprintf(stderr, "Error resuming session.\n");
       return false;
     }
 
@@ -2085,7 +2247,71 @@
 
     if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(), session.get(),
                              false /* expect session not reused */)) {
-      fprintf(stderr, "Error resuming session (version = %04x).\n", version);
+      fprintf(stderr, "Error resuming session.\n");
+      return false;
+    }
+
+    // Rewind the clock to before the session was minted.
+    g_current_time.tv_sec = kStartTime - 1;
+
+    if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(), session.get(),
+                             false /* expect session not reused */)) {
+      fprintf(stderr, "Error resuming session.\n");
+      return false;
+    }
+
+    // SSL 3.0 cannot renew sessions.
+    if (version == SSL3_VERSION) {
+      continue;
+    }
+
+    // Renew the session 10 seconds before expiration.
+    g_current_time.tv_sec = kStartTime + SSL_DEFAULT_SESSION_TIMEOUT - 10;
+    bssl::UniquePtr<SSL_SESSION> new_session =
+        ExpectSessionRenewed(client_ctx.get(), server_ctx.get(), session.get());
+    if (!new_session) {
+      fprintf(stderr, "Error renewing session.\n");
+      return false;
+    }
+
+    // This new session is not the same object as before.
+    if (session.get() == new_session.get()) {
+      fprintf(stderr, "New and old sessions alias.\n");
+      return false;
+    }
+
+    // Check the sessions have timestamps measured from issuance.
+    long session_time = 0;
+    if (server_test) {
+      if (!GetServerTicketTime(&session_time, new_session.get())) {
+        fprintf(stderr, "Failed to decode session ticket.\n");
+        return false;
+      }
+    } else {
+      session_time = new_session->time;
+    }
+
+    if (session_time != g_current_time.tv_sec) {
+      fprintf(stderr, "New session is not measured from issuance.\n");
+      return false;
+    }
+
+    // The new session is usable just before the old expiration.
+    g_current_time.tv_sec = kStartTime + SSL_DEFAULT_SESSION_TIMEOUT - 1;
+    if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(),
+                             new_session.get(),
+                             true /* expect session reused */)) {
+      fprintf(stderr, "Error resuming renewed session.\n");
+      return false;
+    }
+
+    // Renewal does not extend the lifetime, so it is not usable beyond the
+    // old expiration.
+    g_current_time.tv_sec = kStartTime + SSL_DEFAULT_SESSION_TIMEOUT + 1;
+    if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(),
+                             new_session.get(),
+                             false /* expect session not reused */)) {
+      fprintf(stderr, "Renewed session's lifetime is too long.\n");
       return false;
     }
   }
@@ -2099,7 +2325,13 @@
   return SSL_TLSEXT_ERR_OK;
 }
 
-static bool TestSNICallback() {
+static bool TestSNICallback(bool is_dtls, const SSL_METHOD *method,
+                            uint16_t version) {
+  // SSL 3.0 lacks extensions.
+  if (version == SSL3_VERSION) {
+    return true;
+  }
+
   bssl::UniquePtr<X509> cert = GetTestCertificate();
   bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
   bssl::UniquePtr<X509> cert2 = GetECDSATestCertificate();
@@ -2108,56 +2340,47 @@
     return false;
   }
 
-  // At each version, test that switching the |SSL_CTX| at the SNI callback
-  // behaves correctly.
-  for (uint16_t version : kTLSVersions) {
-    if (version == SSL3_VERSION) {
-      continue;
-    }
+  // Test that switching the |SSL_CTX| at the SNI callback behaves correctly.
+  static const uint16_t kECDSAWithSHA256 = SSL_SIGN_ECDSA_SECP256R1_SHA256;
 
-    static const uint16_t kECDSAWithSHA256 = SSL_SIGN_ECDSA_SECP256R1_SHA256;
+  bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(method));
+  bssl::UniquePtr<SSL_CTX> server_ctx2(SSL_CTX_new(method));
+  bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(method));
+  if (!server_ctx || !server_ctx2 || !client_ctx ||
+      !SSL_CTX_use_certificate(server_ctx.get(), cert.get()) ||
+      !SSL_CTX_use_PrivateKey(server_ctx.get(), key.get()) ||
+      !SSL_CTX_use_certificate(server_ctx2.get(), cert2.get()) ||
+      !SSL_CTX_use_PrivateKey(server_ctx2.get(), key2.get()) ||
+      // Historically signing preferences would be lost in some cases with the
+      // SNI callback, which triggers the TLS 1.2 SHA-1 default. To ensure
+      // this doesn't happen when |version| is TLS 1.2, configure the private
+      // key to only sign SHA-256.
+      !SSL_CTX_set_signing_algorithm_prefs(server_ctx2.get(), &kECDSAWithSHA256,
+                                           1) ||
+      !SSL_CTX_set_min_proto_version(client_ctx.get(), version) ||
+      !SSL_CTX_set_max_proto_version(client_ctx.get(), version) ||
+      !SSL_CTX_set_min_proto_version(server_ctx.get(), version) ||
+      !SSL_CTX_set_max_proto_version(server_ctx.get(), version) ||
+      !SSL_CTX_set_min_proto_version(server_ctx2.get(), version) ||
+      !SSL_CTX_set_max_proto_version(server_ctx2.get(), version)) {
+    return false;
+  }
 
-    bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(TLS_method()));
-    bssl::UniquePtr<SSL_CTX> server_ctx2(SSL_CTX_new(TLS_method()));
-    bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
-    if (!server_ctx || !server_ctx2 || !client_ctx ||
-        !SSL_CTX_use_certificate(server_ctx.get(), cert.get()) ||
-        !SSL_CTX_use_PrivateKey(server_ctx.get(), key.get()) ||
-        !SSL_CTX_use_certificate(server_ctx2.get(), cert2.get()) ||
-        !SSL_CTX_use_PrivateKey(server_ctx2.get(), key2.get()) ||
-        // Historically signing preferences would be lost in some cases with the
-        // SNI callback, which triggers the TLS 1.2 SHA-1 default. To ensure
-        // this doesn't happen when |version| is TLS 1.2, configure the private
-        // key to only sign SHA-256.
-        !SSL_CTX_set_signing_algorithm_prefs(server_ctx2.get(),
-                                             &kECDSAWithSHA256, 1) ||
-        !SSL_CTX_set_min_proto_version(client_ctx.get(), version) ||
-        !SSL_CTX_set_max_proto_version(client_ctx.get(), version) ||
-        !SSL_CTX_set_min_proto_version(server_ctx.get(), version) ||
-        !SSL_CTX_set_max_proto_version(server_ctx.get(), version) ||
-        !SSL_CTX_set_min_proto_version(server_ctx2.get(), version) ||
-        !SSL_CTX_set_max_proto_version(server_ctx2.get(), version)) {
-      return false;
-    }
+  SSL_CTX_set_tlsext_servername_callback(server_ctx.get(), SwitchContext);
+  SSL_CTX_set_tlsext_servername_arg(server_ctx.get(), server_ctx2.get());
 
-    SSL_CTX_set_tlsext_servername_callback(server_ctx.get(), SwitchContext);
-    SSL_CTX_set_tlsext_servername_arg(server_ctx.get(), server_ctx2.get());
+  bssl::UniquePtr<SSL> client, server;
+  if (!ConnectClientAndServer(&client, &server, client_ctx.get(),
+                              server_ctx.get(), nullptr)) {
+    fprintf(stderr, "Handshake failed.\n");
+    return false;
+  }
 
-    bssl::UniquePtr<SSL> client, server;
-    if (!ConnectClientAndServer(&client, &server, client_ctx.get(),
-                                server_ctx.get(), nullptr)) {
-      fprintf(stderr, "Handshake failed at version %04x.\n", version);
-      return false;
-    }
-
-    // The client should have received |cert2|.
-    bssl::UniquePtr<X509> peer(SSL_get_peer_certificate(client.get()));
-    if (!peer ||
-        X509_cmp(peer.get(), cert2.get()) != 0) {
-      fprintf(stderr, "Incorrect certificate received at version %04x.\n",
-              version);
-      return false;
-    }
+  // The client should have received |cert2|.
+  bssl::UniquePtr<X509> peer(SSL_get_peer_certificate(client.get()));
+  if (!peer || X509_cmp(peer.get(), cert2.get()) != 0) {
+    fprintf(stderr, "Incorrect certificate received.\n");
+    return false;
   }
 
   return true;
@@ -2280,45 +2503,120 @@
   return true;
 }
 
-static bool TestVersions() {
+static bool TestVersion(bool is_dtls, const SSL_METHOD *method,
+                        uint16_t version) {
   bssl::UniquePtr<X509> cert = GetTestCertificate();
   bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
   if (!cert || !key) {
     return false;
   }
 
-  for (bool is_dtls : std::vector<bool>{false, true}) {
-    const SSL_METHOD *method = is_dtls ? DTLS_method() : TLS_method();
-    const char *name = is_dtls ? "DTLS" : "TLS";
-    const uint16_t *versions = is_dtls ? kDTLSVersions : kTLSVersions;
-    size_t num_versions = is_dtls ? OPENSSL_ARRAY_SIZE(kDTLSVersions)
-                                  : OPENSSL_ARRAY_SIZE(kTLSVersions);
-    for (size_t i = 0; i < num_versions; i++) {
-      uint16_t version = versions[i];
-      bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(method));
-      bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(method));
-      bssl::UniquePtr<SSL> client, server;
-      if (!server_ctx || !client_ctx ||
-          !SSL_CTX_use_certificate(server_ctx.get(), cert.get()) ||
-          !SSL_CTX_use_PrivateKey(server_ctx.get(), key.get()) ||
-          !SSL_CTX_set_min_proto_version(client_ctx.get(), version) ||
-          !SSL_CTX_set_max_proto_version(client_ctx.get(), version) ||
-          !SSL_CTX_set_min_proto_version(server_ctx.get(), version) ||
-          !SSL_CTX_set_max_proto_version(server_ctx.get(), version) ||
-          !ConnectClientAndServer(&client, &server, client_ctx.get(),
-                                  server_ctx.get(), nullptr /* no session */)) {
-        fprintf(stderr, "Failed to connect %s at version %04x.\n", name,
-                version);
-        return false;
-      }
+  bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(method));
+  bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(method));
+  bssl::UniquePtr<SSL> client, server;
+  if (!server_ctx || !client_ctx ||
+      !SSL_CTX_use_certificate(server_ctx.get(), cert.get()) ||
+      !SSL_CTX_use_PrivateKey(server_ctx.get(), key.get()) ||
+      !SSL_CTX_set_min_proto_version(client_ctx.get(), version) ||
+      !SSL_CTX_set_max_proto_version(client_ctx.get(), version) ||
+      !SSL_CTX_set_min_proto_version(server_ctx.get(), version) ||
+      !SSL_CTX_set_max_proto_version(server_ctx.get(), version) ||
+      !ConnectClientAndServer(&client, &server, client_ctx.get(),
+                              server_ctx.get(), nullptr /* no session */)) {
+    fprintf(stderr, "Failed to connect.\n");
+    return false;
+  }
 
-      if (SSL_version(client.get()) != version ||
-          SSL_version(server.get()) != version) {
-        fprintf(stderr,
-                "%s version mismatch. Got %04x and %04x, wanted %04x.\n", name,
-                SSL_version(client.get()), SSL_version(server.get()), version);
-        return false;
-      }
+  if (SSL_version(client.get()) != version ||
+      SSL_version(server.get()) != version) {
+    fprintf(stderr, "Version mismatch. Got %04x and %04x, wanted %04x.\n",
+            SSL_version(client.get()), SSL_version(server.get()), version);
+    return false;
+  }
+
+  return true;
+}
+
+// Tests that that |SSL_get_pending_cipher| is available during the ALPN
+// selection callback.
+static bool TestALPNCipherAvailable(bool is_dtls, const SSL_METHOD *method,
+                                    uint16_t version) {
+  // SSL 3.0 lacks extensions.
+  if (version == SSL3_VERSION) {
+    return true;
+  }
+
+  static const uint8_t kALPNProtos[] = {0x03, 'f', 'o', 'o'};
+
+  bssl::UniquePtr<X509> cert = GetTestCertificate();
+  bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
+  if (!cert || !key) {
+    return false;
+  }
+
+  bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(method));
+  if (!ctx || !SSL_CTX_use_certificate(ctx.get(), cert.get()) ||
+      !SSL_CTX_use_PrivateKey(ctx.get(), key.get()) ||
+      !SSL_CTX_set_min_proto_version(ctx.get(), version) ||
+      !SSL_CTX_set_max_proto_version(ctx.get(), version) ||
+      SSL_CTX_set_alpn_protos(ctx.get(), kALPNProtos, sizeof(kALPNProtos)) !=
+          0) {
+    return false;
+  }
+
+  // The ALPN callback does not fail the handshake on error, so have the
+  // callback write a boolean.
+  std::pair<uint16_t, bool> callback_state(version, false);
+  SSL_CTX_set_alpn_select_cb(
+      ctx.get(),
+      [](SSL *ssl, const uint8_t **out, uint8_t *out_len, const uint8_t *in,
+         unsigned in_len, void *arg) -> int {
+        auto state = reinterpret_cast<std::pair<uint16_t, bool> *>(arg);
+        if (SSL_get_pending_cipher(ssl) != nullptr &&
+            SSL_version(ssl) == state->first) {
+          state->second = true;
+        }
+        return SSL_TLSEXT_ERR_NOACK;
+      },
+      &callback_state);
+
+  bssl::UniquePtr<SSL> client, server;
+  if (!ConnectClientAndServer(&client, &server, ctx.get(), ctx.get(),
+                              nullptr /* no session */)) {
+    return false;
+  }
+
+  if (!callback_state.second) {
+    fprintf(stderr, "The pending cipher was not known in the ALPN callback.\n");
+    return false;
+  }
+
+  return true;
+}
+
+static bool ForEachVersion(bool (*test_func)(bool is_dtls,
+                                             const SSL_METHOD *method,
+                                             uint16_t version)) {
+  static uint16_t kTLSVersions[] = {
+      SSL3_VERSION,   TLS1_VERSION,   TLS1_1_VERSION,
+      TLS1_2_VERSION, TLS1_3_VERSION,
+  };
+
+  static uint16_t kDTLSVersions[] = {
+      DTLS1_VERSION, DTLS1_2_VERSION,
+  };
+
+  for (uint16_t version : kTLSVersions) {
+    if (!test_func(false, TLS_method(), version)) {
+      fprintf(stderr, "Test failed at TLS version %04x.\n", version);
+      return false;
+    }
+  }
+
+  for (uint16_t version : kDTLSVersions) {
+    if (!test_func(true, DTLS_method(), version)) {
+      fprintf(stderr, "Test failed at DTLS version %04x.\n", version);
+      return false;
     }
   }
 
@@ -2346,23 +2644,31 @@
       !TestDefaultVersion(TLS1_1_VERSION, TLS1_1_VERSION, &DTLSv1_method) ||
       !TestDefaultVersion(TLS1_2_VERSION, TLS1_2_VERSION, &DTLSv1_2_method) ||
       !TestCipherGetRFCName() ||
-      !TestPaddingExtension() ||
+      // Test the padding extension at TLS 1.2.
+      !TestPaddingExtension(TLS1_2_VERSION, TLS1_2_VERSION) ||
+      // Test the padding extension at TLS 1.3 with a TLS 1.2 session, so there
+      // will be no PSK binder after the padding extension.
+      !TestPaddingExtension(TLS1_3_VERSION, TLS1_2_VERSION) ||
+      // Test the padding extension at TLS 1.3 with a TLS 1.3 session, so there
+      // will be a PSK binder after the padding extension.
+      !TestPaddingExtension(TLS1_3_VERSION, TLS1_3_DRAFT_VERSION) ||
       !TestClientCAList() ||
       !TestInternalSessionCache() ||
-      !TestSequenceNumber() ||
-      !TestOneSidedShutdown() ||
+      !ForEachVersion(TestSequenceNumber) ||
+      !ForEachVersion(TestOneSidedShutdown) ||
       !TestSessionDuplication() ||
       !TestSetFD() ||
       !TestSetBIO() ||
-      !TestGetPeerCertificate() ||
-      !TestRetainOnlySHA256OfCerts() ||
+      !ForEachVersion(TestGetPeerCertificate) ||
+      !ForEachVersion(TestRetainOnlySHA256OfCerts) ||
       !TestClientHello() ||
-      !TestSessionIDContext() ||
-      !TestSessionTimeout() ||
-      !TestSNICallback() ||
+      !ForEachVersion(TestSessionIDContext) ||
+      !ForEachVersion(TestSessionTimeout) ||
+      !ForEachVersion(TestSNICallback) ||
       !TestEarlyCallbackVersionSwitch() ||
       !TestSetVersion() ||
-      !TestVersions()) {
+      !ForEachVersion(TestVersion) ||
+      !ForEachVersion(TestALPNCipherAvailable)) {
     ERR_print_errors_fp(stderr);
     return 1;
   }
diff --git a/src/ssl/t1_enc.c b/src/ssl/t1_enc.c
index 4b8fe45..4c7d3ee 100644
--- a/src/ssl/t1_enc.c
+++ b/src/ssl/t1_enc.c
@@ -258,6 +258,63 @@
   return 1;
 }
 
+static int tls1_setup_key_block(SSL *ssl) {
+  if (ssl->s3->hs->key_block_len != 0) {
+    return 1;
+  }
+
+  SSL_SESSION *session = ssl->session;
+  if (ssl->s3->new_session != NULL) {
+    session = ssl->s3->new_session;
+  }
+
+  const EVP_AEAD *aead = NULL;
+  size_t mac_secret_len, fixed_iv_len;
+  if (session->cipher == NULL ||
+      !ssl_cipher_get_evp_aead(&aead, &mac_secret_len, &fixed_iv_len,
+                               session->cipher, ssl3_protocol_version(ssl))) {
+    OPENSSL_PUT_ERROR(SSL, SSL_R_CIPHER_OR_HASH_UNAVAILABLE);
+    return 0;
+  }
+  size_t key_len = EVP_AEAD_key_length(aead);
+  if (mac_secret_len > 0) {
+    /* For "stateful" AEADs (i.e. compatibility with pre-AEAD cipher suites) the
+     * key length reported by |EVP_AEAD_key_length| will include the MAC key
+     * bytes and initial implicit IV. */
+    if (key_len < mac_secret_len + fixed_iv_len) {
+      OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+      return 0;
+    }
+    key_len -= mac_secret_len + fixed_iv_len;
+  }
+
+  assert(mac_secret_len < 256);
+  assert(key_len < 256);
+  assert(fixed_iv_len < 256);
+
+  ssl->s3->tmp.new_mac_secret_len = (uint8_t)mac_secret_len;
+  ssl->s3->tmp.new_key_len = (uint8_t)key_len;
+  ssl->s3->tmp.new_fixed_iv_len = (uint8_t)fixed_iv_len;
+
+  size_t key_block_len = SSL_get_key_block_len(ssl);
+
+  uint8_t *keyblock = OPENSSL_malloc(key_block_len);
+  if (keyblock == NULL) {
+    OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+    return 0;
+  }
+
+  if (!SSL_generate_key_block(ssl, keyblock, key_block_len)) {
+    OPENSSL_free(keyblock);
+    return 0;
+  }
+
+  assert(key_block_len < 256);
+  ssl->s3->hs->key_block_len = (uint8_t)key_block_len;
+  ssl->s3->hs->key_block = keyblock;
+  return 1;
+}
+
 int tls1_change_cipher_state(SSL *ssl, int which) {
   /* Ensure the key block is set up. */
   if (!tls1_setup_key_block(ssl)) {
@@ -276,10 +333,9 @@
   size_t mac_secret_len = ssl->s3->tmp.new_mac_secret_len;
   size_t key_len = ssl->s3->tmp.new_key_len;
   size_t iv_len = ssl->s3->tmp.new_fixed_iv_len;
-  assert((mac_secret_len + key_len + iv_len) * 2 ==
-         ssl->s3->tmp.key_block_length);
+  assert((mac_secret_len + key_len + iv_len) * 2 == ssl->s3->hs->key_block_len);
 
-  const uint8_t *key_data = ssl->s3->tmp.key_block;
+  const uint8_t *key_data = ssl->s3->hs->key_block;
   const uint8_t *client_write_mac_secret = key_data;
   key_data += mac_secret_len;
   const uint8_t *server_write_mac_secret = key_data;
@@ -333,65 +389,6 @@
       ssl->s3->client_random, SSL3_RANDOM_SIZE);
 }
 
-int tls1_setup_key_block(SSL *ssl) {
-  if (ssl->s3->tmp.key_block_length != 0) {
-    return 1;
-  }
-
-  SSL_SESSION *session = ssl->session;
-  if (ssl->s3->new_session != NULL) {
-    session = ssl->s3->new_session;
-  }
-
-  const EVP_AEAD *aead = NULL;
-  size_t mac_secret_len, fixed_iv_len;
-  if (session->cipher == NULL ||
-      !ssl_cipher_get_evp_aead(&aead, &mac_secret_len, &fixed_iv_len,
-                               session->cipher, ssl3_protocol_version(ssl))) {
-    OPENSSL_PUT_ERROR(SSL, SSL_R_CIPHER_OR_HASH_UNAVAILABLE);
-    return 0;
-  }
-  size_t key_len = EVP_AEAD_key_length(aead);
-  if (mac_secret_len > 0) {
-    /* For "stateful" AEADs (i.e. compatibility with pre-AEAD cipher suites) the
-     * key length reported by |EVP_AEAD_key_length| will include the MAC key
-     * bytes and initial implicit IV. */
-    if (key_len < mac_secret_len + fixed_iv_len) {
-      OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
-      return 0;
-    }
-    key_len -= mac_secret_len + fixed_iv_len;
-  }
-
-  assert(mac_secret_len < 256);
-  assert(key_len < 256);
-  assert(fixed_iv_len < 256);
-
-  ssl->s3->tmp.new_mac_secret_len = (uint8_t)mac_secret_len;
-  ssl->s3->tmp.new_key_len = (uint8_t)key_len;
-  ssl->s3->tmp.new_fixed_iv_len = (uint8_t)fixed_iv_len;
-
-  size_t key_block_len = SSL_get_key_block_len(ssl);
-
-  ssl3_cleanup_key_block(ssl);
-
-  uint8_t *keyblock = OPENSSL_malloc(key_block_len);
-  if (keyblock == NULL) {
-    OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
-    return 0;
-  }
-
-  if (!SSL_generate_key_block(ssl, keyblock, key_block_len)) {
-    OPENSSL_free(keyblock);
-    return 0;
-  }
-
-  assert(key_block_len < 256);
-  ssl->s3->tmp.key_block_length = (uint8_t)key_block_len;
-  ssl->s3->tmp.key_block = keyblock;
-  return 1;
-}
-
 static int append_digest(const EVP_MD_CTX *ctx, uint8_t *out, size_t *out_len,
                          size_t max_out) {
   int ret = 0;
@@ -505,6 +502,11 @@
     return 0;
   }
 
+  /* Exporters may not be used in the middle of a renegotiation. */
+  if (SSL_in_init(ssl) && !SSL_in_false_start(ssl)) {
+    return 0;
+  }
+
   if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) {
     return tls13_export_keying_material(ssl, out, out_len, label, label_len,
                                         context, context_len, use_context);
diff --git a/src/ssl/t1_lib.c b/src/ssl/t1_lib.c
index 9655b83..421232f 100644
--- a/src/ssl/t1_lib.c
+++ b/src/ssl/t1_lib.c
@@ -442,62 +442,73 @@
 }
 
 /* kVerifySignatureAlgorithms is the default list of accepted signature
- * algorithms for verifying. */
+ * algorithms for verifying.
+ *
+ * For now, RSA-PSS signature algorithms are not enabled on Android's system
+ * BoringSSL. Once the change in Chrome has stuck and the values are finalized,
+ * restore them. */
 static const uint16_t kVerifySignatureAlgorithms[] = {
-    /* For now, do not enable RSA-PSS signature algorithms on Android's system
-     * BoringSSL. Once TLS 1.3 is finalized and the change in Chrome has stuck,
-     * restore them. */
+    /* Prefer SHA-256 algorithms. */
+    SSL_SIGN_ECDSA_SECP256R1_SHA256,
 #if !defined(BORINGSSL_ANDROID_SYSTEM)
-    SSL_SIGN_RSA_PSS_SHA512,
+    SSL_SIGN_RSA_PSS_SHA256,
 #endif
-    SSL_SIGN_RSA_PKCS1_SHA512,
+    SSL_SIGN_RSA_PKCS1_SHA256,
+
+    /* Larger hashes are acceptable. */
+    SSL_SIGN_ECDSA_SECP384R1_SHA384,
+#if !defined(BORINGSSL_ANDROID_SYSTEM)
+    SSL_SIGN_RSA_PSS_SHA384,
+#endif
+    SSL_SIGN_RSA_PKCS1_SHA384,
+
     /* TODO(davidben): Remove this entry and SSL_CURVE_SECP521R1 from
      * kDefaultGroups. */
 #if defined(BORINGSSL_ANDROID_SYSTEM)
     SSL_SIGN_ECDSA_SECP521R1_SHA512,
 #endif
-
-#if !defined(BORINGSSL_ANDROID_SYSTEM)
-    SSL_SIGN_RSA_PSS_SHA384,
-#endif
-    SSL_SIGN_RSA_PKCS1_SHA384,
-    SSL_SIGN_ECDSA_SECP384R1_SHA384,
-
-#if !defined(BORINGSSL_ANDROID_SYSTEM)
-    SSL_SIGN_RSA_PSS_SHA256,
-#endif
-    SSL_SIGN_RSA_PKCS1_SHA256,
-    SSL_SIGN_ECDSA_SECP256R1_SHA256,
-
-    SSL_SIGN_RSA_PKCS1_SHA1,
-};
-
-/* kSignSignatureAlgorithms is the default list of supported signature
- * algorithms for signing. */
-static const uint16_t kSignSignatureAlgorithms[] = {
-    /* For now, do not enable RSA-PSS signature algorithms on Android's system
-     * BoringSSL. Once TLS 1.3 is finalized and the change in Chrome has stuck,
-     * restore them. */
 #if !defined(BORINGSSL_ANDROID_SYSTEM)
     SSL_SIGN_RSA_PSS_SHA512,
 #endif
     SSL_SIGN_RSA_PKCS1_SHA512,
-    SSL_SIGN_ECDSA_SECP521R1_SHA512,
 
-#if !defined(BORINGSSL_ANDROID_SYSTEM)
-    SSL_SIGN_RSA_PSS_SHA384,
-#endif
-    SSL_SIGN_RSA_PKCS1_SHA384,
-    SSL_SIGN_ECDSA_SECP384R1_SHA384,
+    /* For now, SHA-1 is still accepted but least preferable. */
+    SSL_SIGN_RSA_PKCS1_SHA1,
 
+};
+
+/* kSignSignatureAlgorithms is the default list of supported signature
+ * algorithms for signing.
+ *
+ * For now, RSA-PSS signature algorithms are not enabled on Android's system
+ * BoringSSL. Once the change in Chrome has stuck and the values are finalized,
+ * restore them. */
+static const uint16_t kSignSignatureAlgorithms[] = {
+    /* Prefer SHA-256 algorithms. */
+    SSL_SIGN_ECDSA_SECP256R1_SHA256,
 #if !defined(BORINGSSL_ANDROID_SYSTEM)
     SSL_SIGN_RSA_PSS_SHA256,
 #endif
     SSL_SIGN_RSA_PKCS1_SHA256,
-    SSL_SIGN_ECDSA_SECP256R1_SHA256,
 
-    SSL_SIGN_RSA_PKCS1_SHA1,
+    /* If needed, sign larger hashes.
+     *
+     * TODO(davidben): Determine which of these may be pruned. */
+    SSL_SIGN_ECDSA_SECP384R1_SHA384,
+#if !defined(BORINGSSL_ANDROID_SYSTEM)
+    SSL_SIGN_RSA_PSS_SHA384,
+#endif
+    SSL_SIGN_RSA_PKCS1_SHA384,
+
+    SSL_SIGN_ECDSA_SECP521R1_SHA512,
+#if !defined(BORINGSSL_ANDROID_SYSTEM)
+    SSL_SIGN_RSA_PSS_SHA512,
+#endif
+    SSL_SIGN_RSA_PKCS1_SHA512,
+
+    /* If the peer supports nothing else, sign with SHA-1. */
     SSL_SIGN_ECDSA_SHA1,
+    SSL_SIGN_RSA_PKCS1_SHA1,
 };
 
 size_t tls12_get_verify_sigalgs(const SSL *ssl, const uint16_t **out) {
@@ -694,28 +705,19 @@
     return 0;
   }
 
-  /* TODO(davidben): SNI should be resolved before resumption. We have the
-   * early callback as a replacement, but we should fix the current callback
-   * and avoid the need for |SSL_CTX_set_session_id_context|. */
-  if (ssl->session == NULL) {
-    assert(ssl->s3->new_session->tlsext_hostname == NULL);
-
-    /* Copy the hostname as a string. */
-    if (!CBS_strdup(&host_name, &ssl->s3->new_session->tlsext_hostname)) {
-      *out_alert = SSL_AD_INTERNAL_ERROR;
-      return 0;
-    }
-
-    ssl->s3->hs->should_ack_sni = 1;
+  /* Copy the hostname as a string. */
+  if (!CBS_strdup(&host_name, &ssl->s3->hs->hostname)) {
+    *out_alert = SSL_AD_INTERNAL_ERROR;
+    return 0;
   }
 
+  ssl->s3->hs->should_ack_sni = 1;
   return 1;
 }
 
 static int ext_sni_add_serverhello(SSL *ssl, CBB *out) {
-  if (ssl->session != NULL ||
-      !ssl->s3->hs->should_ack_sni ||
-      ssl->s3->new_session->tlsext_hostname == NULL) {
+  if (ssl->s3->session_reused ||
+      !ssl->s3->hs->should_ack_sni) {
     return 1;
   }
 
@@ -1019,8 +1021,6 @@
 
 static int ext_ticket_parse_serverhello(SSL *ssl, uint8_t *out_alert,
                                         CBS *contents) {
-  ssl->tlsext_ticket_expected = 0;
-
   if (contents == NULL) {
     return 1;
   }
@@ -1038,17 +1038,16 @@
     return 0;
   }
 
-  ssl->tlsext_ticket_expected = 1;
+  ssl->s3->hs->ticket_expected = 1;
   return 1;
 }
 
 static int ext_ticket_add_serverhello(SSL *ssl, CBB *out) {
-  if (!ssl->tlsext_ticket_expected) {
+  if (!ssl->s3->hs->ticket_expected) {
     return 1;
   }
 
-  /* If |SSL_OP_NO_TICKET| is set, |tlsext_ticket_expected| should never be
-   * true. */
+  /* If |SSL_OP_NO_TICKET| is set, |ticket_expected| should never be true. */
   assert((SSL_get_options(ssl) & SSL_OP_NO_TICKET) == 0);
 
   if (!CBB_add_u16(out, TLSEXT_TYPE_session_ticket) ||
@@ -1152,42 +1151,22 @@
     return 1;
   }
 
-  if (ssl3_protocol_version(ssl) < TLS1_3_VERSION) {
-    /* OCSP stapling is forbidden on non-certificate ciphers. */
-    if (CBS_len(contents) != 0 ||
-        !ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher)) {
-      return 0;
-    }
-
-    /* Note this does not check for resumption in TLS 1.2. Sending
-     * status_request here does not make sense, but OpenSSL does so and the
-     * specification does not say anything. Tolerate it but ignore it. */
-
-    ssl->s3->hs->certificate_status_expected = 1;
-    return 1;
-  }
-
-  /* In TLS 1.3, OCSP stapling is forbidden on resumption. */
-  if (ssl->s3->session_reused) {
+  /* TLS 1.3 OCSP responses are included in the Certificate extensions. */
+  if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) {
     return 0;
   }
 
-  uint8_t status_type;
-  CBS ocsp_response;
-  if (!CBS_get_u8(contents, &status_type) ||
-      status_type != TLSEXT_STATUSTYPE_ocsp ||
-      !CBS_get_u24_length_prefixed(contents, &ocsp_response) ||
-      CBS_len(&ocsp_response) == 0 ||
-      CBS_len(contents) != 0) {
+  /* OCSP stapling is forbidden on non-certificate ciphers. */
+  if (CBS_len(contents) != 0 ||
+      !ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher)) {
     return 0;
   }
 
-  if (!CBS_stow(&ocsp_response, &ssl->s3->new_session->ocsp_response,
-                &ssl->s3->new_session->ocsp_response_length)) {
-    *out_alert = SSL_AD_INTERNAL_ERROR;
-    return 0;
-  }
+  /* Note this does not check for resumption in TLS 1.2. Sending
+   * status_request here does not make sense, but OpenSSL does so and the
+   * specification does not say anything. Tolerate it but ignore it. */
 
+  ssl->s3->hs->certificate_status_expected = 1;
   return 1;
 }
 
@@ -1210,34 +1189,18 @@
 }
 
 static int ext_ocsp_add_serverhello(SSL *ssl, CBB *out) {
-  if (!ssl->s3->hs->ocsp_stapling_requested ||
+  if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION ||
+      !ssl->s3->hs->ocsp_stapling_requested ||
       ssl->ctx->ocsp_response_length == 0 ||
       ssl->s3->session_reused ||
-      (ssl3_protocol_version(ssl) < TLS1_3_VERSION &&
-       !ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher))) {
+      !ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher)) {
     return 1;
   }
 
-  if (ssl3_protocol_version(ssl) < TLS1_3_VERSION) {
-    /* The extension shouldn't be sent when resuming sessions. */
-    if (ssl->session != NULL) {
-      return 1;
-    }
+  ssl->s3->hs->certificate_status_expected = 1;
 
-    ssl->s3->hs->certificate_status_expected = 1;
-
-    return CBB_add_u16(out, TLSEXT_TYPE_status_request) &&
-           CBB_add_u16(out, 0 /* length */);
-  }
-
-  CBB body, ocsp_response;
   return CBB_add_u16(out, TLSEXT_TYPE_status_request) &&
-         CBB_add_u16_length_prefixed(out, &body) &&
-         CBB_add_u8(&body, TLSEXT_STATUSTYPE_ocsp) &&
-         CBB_add_u24_length_prefixed(&body, &ocsp_response) &&
-         CBB_add_bytes(&ocsp_response, ssl->ctx->ocsp_response,
-                       ssl->ctx->ocsp_response_length) &&
-         CBB_flush(out);
+         CBB_add_u16(out, 0 /* length */);
 }
 
 
@@ -1331,10 +1294,6 @@
 
   if (contents == NULL ||
       ssl->s3->initial_handshake_complete ||
-      /* If the ALPN extension is seen before NPN, ignore it. (If ALPN is seen
-       * afterwards, parsing the ALPN extension will clear
-       * |next_proto_neg_seen|. */
-      ssl->s3->alpn_selected != NULL ||
       ssl->ctx->next_protos_advertised_cb == NULL ||
       SSL_is_dtls(ssl)) {
     return 1;
@@ -1396,11 +1355,17 @@
     return 1;
   }
 
+  /* TLS 1.3 SCTs are included in the Certificate extensions. */
+  if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) {
+    *out_alert = SSL_AD_DECODE_ERROR;
+    return 0;
+  }
+
   /* If this is false then we should never have sent the SCT extension in the
    * ClientHello and thus this function should never have been called. */
   assert(ssl->signed_cert_timestamps_enabled);
 
-  if (CBS_len(contents) == 0) {
+  if (!ssl_is_sct_list_valid(contents)) {
     *out_alert = SSL_AD_DECODE_ERROR;
     return 0;
   }
@@ -1424,12 +1389,22 @@
 
 static int ext_sct_parse_clienthello(SSL *ssl, uint8_t *out_alert,
                                      CBS *contents) {
-  return contents == NULL || CBS_len(contents) == 0;
+  if (contents == NULL) {
+    return 1;
+  }
+
+  if (CBS_len(contents) != 0) {
+    return 0;
+  }
+
+  ssl->s3->hs->scts_requested = 1;
+  return 1;
 }
 
 static int ext_sct_add_serverhello(SSL *ssl, CBB *out) {
   /* The extension shouldn't be sent when resuming sessions. */
-  if (ssl->s3->session_reused ||
+  if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION ||
+      ssl->s3->session_reused ||
       ssl->ctx->signed_cert_timestamp_list_length == 0) {
     return 1;
   }
@@ -1447,11 +1422,6 @@
  *
  * https://tools.ietf.org/html/rfc7301 */
 
-static void ext_alpn_init(SSL *ssl) {
-  OPENSSL_free(ssl->s3->alpn_selected);
-  ssl->s3->alpn_selected = NULL;
-}
-
 static int ext_alpn_add_clienthello(SSL *ssl, CBB *out) {
   if (ssl->alpn_client_proto_list == NULL ||
       ssl->s3->initial_handshake_complete) {
@@ -1534,14 +1504,14 @@
   return 1;
 }
 
-static int ext_alpn_parse_clienthello(SSL *ssl, uint8_t *out_alert,
-                                      CBS *contents) {
-  if (contents == NULL) {
-    return 1;
-  }
-
+int ssl_negotiate_alpn(SSL *ssl, uint8_t *out_alert,
+                       const struct ssl_early_callback_ctx *client_hello) {
+  CBS contents;
   if (ssl->ctx->alpn_select_cb == NULL ||
-      ssl->s3->initial_handshake_complete) {
+      !ssl_early_callback_get_extension(
+          client_hello, &contents,
+          TLSEXT_TYPE_application_layer_protocol_negotiation)) {
+    /* Ignore ALPN if not configured or no extension was supplied. */
     return 1;
   }
 
@@ -1549,9 +1519,11 @@
   ssl->s3->hs->next_proto_neg_seen = 0;
 
   CBS protocol_name_list;
-  if (!CBS_get_u16_length_prefixed(contents, &protocol_name_list) ||
-      CBS_len(contents) != 0 ||
+  if (!CBS_get_u16_length_prefixed(&contents, &protocol_name_list) ||
+      CBS_len(&contents) != 0 ||
       CBS_len(&protocol_name_list) < 2) {
+    OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT);
+    *out_alert = SSL_AD_DECODE_ERROR;
     return 0;
   }
 
@@ -1563,6 +1535,8 @@
     if (!CBS_get_u8_length_prefixed(&protocol_name_list_copy, &protocol_name) ||
         /* Empty protocol names are forbidden. */
         CBS_len(&protocol_name) == 0) {
+      OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT);
+      *out_alert = SSL_AD_DECODE_ERROR;
       return 0;
     }
   }
@@ -1633,10 +1607,6 @@
     return 1;
   }
 
-  if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) {
-    return 0;
-  }
-
   assert(!SSL_is_dtls(ssl));
   assert(ssl->tlsext_channel_id_enabled);
 
@@ -1665,10 +1635,6 @@
 }
 
 static int ext_channel_id_add_serverhello(SSL *ssl, CBB *out) {
-  if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) {
-    return 1;
-  }
-
   if (!ssl->s3->tlsext_channel_id_valid) {
     return 1;
   }
@@ -1836,26 +1802,6 @@
  *
  * https://tools.ietf.org/html/rfc4492#section-5.1.2 */
 
-static int ssl_any_ec_cipher_suites_enabled(const SSL *ssl) {
-  if (ssl->version < TLS1_VERSION && !SSL_is_dtls(ssl)) {
-    return 0;
-  }
-
-  const STACK_OF(SSL_CIPHER) *cipher_stack = SSL_get_ciphers(ssl);
-
-  for (size_t i = 0; i < sk_SSL_CIPHER_num(cipher_stack); i++) {
-    const SSL_CIPHER *cipher = sk_SSL_CIPHER_value(cipher_stack, i);
-
-    const uint32_t alg_k = cipher->algorithm_mkey;
-    const uint32_t alg_a = cipher->algorithm_auth;
-    if ((alg_k & SSL_kECDHE) || (alg_a & SSL_aECDSA)) {
-      return 1;
-    }
-  }
-
-  return 0;
-}
-
 static int ext_ec_point_add_extension(SSL *ssl, CBB *out) {
   CBB contents, formats;
   if (!CBB_add_u16(out, TLSEXT_TYPE_ec_point_formats) ||
@@ -1870,7 +1816,13 @@
 }
 
 static int ext_ec_point_add_clienthello(SSL *ssl, CBB *out) {
-  if (!ssl_any_ec_cipher_suites_enabled(ssl)) {
+  uint16_t min_version, max_version;
+  if (!ssl_get_version_range(ssl, &min_version, &max_version)) {
+    return 0;
+  }
+
+  /* The point format extension is unneccessary in TLS 1.3. */
+  if (min_version >= TLS1_3_VERSION) {
     return 1;
   }
 
@@ -1929,9 +1881,30 @@
   return ext_ec_point_add_extension(ssl, out);
 }
 
+
 /* Pre Shared Key
  *
- * https://tools.ietf.org/html/draft-ietf-tls-tls13-16#section-4.2.6 */
+ * https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.6 */
+
+static size_t ext_pre_shared_key_clienthello_length(SSL *ssl) {
+  uint16_t min_version, max_version;
+  if (!ssl_get_version_range(ssl, &min_version, &max_version)) {
+    return 0;
+  }
+
+  uint16_t session_version;
+  if (max_version < TLS1_3_VERSION || ssl->session == NULL ||
+      !ssl->method->version_from_wire(&session_version,
+                                      ssl->session->ssl_version) ||
+      session_version < TLS1_3_VERSION) {
+    return 0;
+  }
+
+  const EVP_MD *digest =
+      ssl_get_handshake_digest(ssl->session->cipher->algorithm_prf);
+  size_t binder_len = EVP_MD_size(digest);
+  return 15 + ssl->session->tlsext_ticklen + binder_len;
+}
 
 static int ext_pre_shared_key_add_clienthello(SSL *ssl, CBB *out) {
   uint16_t min_version, max_version;
@@ -1947,20 +1920,33 @@
     return 1;
   }
 
-  CBB contents, identity, ke_modes, auth_modes, ticket;
+  struct timeval now;
+  ssl_get_current_time(ssl, &now);
+  uint32_t ticket_age = 1000 * (now.tv_sec - ssl->session->time);
+  uint32_t obfuscated_ticket_age = ticket_age + ssl->session->ticket_age_add;
+
+  /* Fill in a placeholder zero binder of the appropriate length. It will be
+   * computed and filled in later after length prefixes are computed. */
+  uint8_t zero_binder[EVP_MAX_MD_SIZE] = {0};
+  const EVP_MD *digest =
+      ssl_get_handshake_digest(ssl->session->cipher->algorithm_prf);
+  size_t binder_len = EVP_MD_size(digest);
+
+  CBB contents, identity, ticket, binders, binder;
   if (!CBB_add_u16(out, TLSEXT_TYPE_pre_shared_key) ||
       !CBB_add_u16_length_prefixed(out, &contents) ||
       !CBB_add_u16_length_prefixed(&contents, &identity) ||
-      !CBB_add_u8_length_prefixed(&identity, &ke_modes) ||
-      !CBB_add_u8(&ke_modes, SSL_PSK_DHE_KE) ||
-      !CBB_add_u8_length_prefixed(&identity, &auth_modes) ||
-      !CBB_add_u8(&auth_modes, SSL_PSK_AUTH) ||
       !CBB_add_u16_length_prefixed(&identity, &ticket) ||
       !CBB_add_bytes(&ticket, ssl->session->tlsext_tick,
-                     ssl->session->tlsext_ticklen)) {
+                     ssl->session->tlsext_ticklen) ||
+      !CBB_add_u32(&identity, obfuscated_ticket_age) ||
+      !CBB_add_u16_length_prefixed(&contents, &binders) ||
+      !CBB_add_u8_length_prefixed(&binders, &binder) ||
+      !CBB_add_bytes(&binder, zero_binder, binder_len)) {
     return 0;
   }
 
+  ssl->s3->hs->needs_psk_binder = 1;
   return CBB_flush(out);
 }
 
@@ -1974,6 +1960,7 @@
     return 0;
   }
 
+  /* We only advertise one PSK identity, so the only legal index is zero. */
   if (psk_id != 0) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_PSK_IDENTITY_NOT_FOUND);
     *out_alert = SSL_AD_UNKNOWN_PSK_IDENTITY;
@@ -1985,32 +1972,45 @@
 
 int ssl_ext_pre_shared_key_parse_clienthello(SSL *ssl,
                                              SSL_SESSION **out_session,
+                                             CBS *out_binders,
                                              uint8_t *out_alert,
                                              CBS *contents) {
   /* We only process the first PSK identity since we don't support pure PSK. */
-  CBS identity, ke_modes, auth_modes, ticket;
+  uint32_t obfuscated_ticket_age;
+  CBS identity, ticket, binders;
   if (!CBS_get_u16_length_prefixed(contents, &identity) ||
-      !CBS_get_u8_length_prefixed(&identity, &ke_modes) ||
-      !CBS_get_u8_length_prefixed(&identity, &auth_modes) ||
       !CBS_get_u16_length_prefixed(&identity, &ticket) ||
-      CBS_len(&identity) != 0) {
+      !CBS_get_u32(&identity, &obfuscated_ticket_age) ||
+      !CBS_get_u16_length_prefixed(contents, &binders) ||
+      CBS_len(contents) != 0) {
+    OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
     *out_alert = SSL_AD_DECODE_ERROR;
     return 0;
   }
 
-  /* We only support tickets with PSK_DHE_KE and PSK_AUTH. */
-  if (memchr(CBS_data(&ke_modes), SSL_PSK_DHE_KE, CBS_len(&ke_modes)) == NULL ||
-      memchr(CBS_data(&auth_modes), SSL_PSK_AUTH, CBS_len(&auth_modes)) ==
-          NULL) {
-    *out_session = NULL;
-    return 1;
+  *out_binders = binders;
+
+  /* The PSK identity must have a corresponding binder. */
+  CBS binder;
+  if (!CBS_get_u8_length_prefixed(&binders, &binder)) {
+    OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+    *out_alert = SSL_AD_DECODE_ERROR;
+    return 0;
   }
 
+  /* TODO(svaldez): Check that the ticket_age is valid when attempting to use
+   * the PSK for 0-RTT. http://crbug.com/boringssl/113 */
+
   /* TLS 1.3 session tickets are renewed separately as part of the
    * NewSessionTicket. */
-  int renew;
-  return tls_process_ticket(ssl, out_session, &renew, CBS_data(&ticket),
-                            CBS_len(&ticket), NULL, 0);
+  int unused_renew;
+  if (!tls_process_ticket(ssl, out_session, &unused_renew, CBS_data(&ticket),
+                          CBS_len(&ticket), NULL, 0)) {
+    *out_alert = SSL_AD_INTERNAL_ERROR;
+    return 0;
+  }
+
+  return 1;
 }
 
 int ssl_ext_pre_shared_key_add_serverhello(SSL *ssl, CBB *out) {
@@ -2031,6 +2031,53 @@
 }
 
 
+/* Pre-Shared Key Exchange Modes
+ *
+ * https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.7 */
+static int ext_psk_key_exchange_modes_add_clienthello(SSL *ssl, CBB *out) {
+  uint16_t min_version, max_version;
+  if (!ssl_get_version_range(ssl, &min_version, &max_version)) {
+    return 0;
+  }
+
+  if (max_version < TLS1_3_VERSION) {
+    return 1;
+  }
+
+  CBB contents, ke_modes;
+  if (!CBB_add_u16(out, TLSEXT_TYPE_psk_key_exchange_modes) ||
+      !CBB_add_u16_length_prefixed(out, &contents) ||
+      !CBB_add_u8_length_prefixed(&contents, &ke_modes) ||
+      !CBB_add_u8(&ke_modes, SSL_PSK_DHE_KE)) {
+    return 0;
+  }
+
+  return CBB_flush(out);
+}
+
+static int ext_psk_key_exchange_modes_parse_clienthello(SSL *ssl,
+                                                        uint8_t *out_alert,
+                                                        CBS *contents) {
+  if (contents == NULL) {
+    return 1;
+  }
+
+  CBS ke_modes;
+  if (!CBS_get_u8_length_prefixed(contents, &ke_modes) ||
+      CBS_len(&ke_modes) == 0 ||
+      CBS_len(contents) != 0) {
+    *out_alert = SSL_AD_DECODE_ERROR;
+    return 0;
+  }
+
+  /* We only support tickets with PSK_DHE_KE. */
+  ssl->s3->hs->accept_psk_mode =
+      memchr(CBS_data(&ke_modes), SSL_PSK_DHE_KE, CBS_len(&ke_modes)) != NULL;
+
+  return 1;
+}
+
+
 /* Key Share
  *
  * https://tools.ietf.org/html/draft-ietf-tls-tls13-16#section-4.2.5 */
@@ -2052,21 +2099,18 @@
     return 0;
   }
 
-  uint16_t group_id;
+  uint16_t group_id = ssl->s3->hs->retry_group;
   if (ssl->s3->hs->received_hello_retry_request) {
-    /* Replay the old key shares. */
-    if (!CBB_add_bytes(&kse_bytes, ssl->s3->hs->key_share_bytes,
+    /* We received a HelloRetryRequest without a new curve, so there is no new
+     * share to append. Leave |ecdh_ctx| as-is. */
+    if (group_id == 0 &&
+        !CBB_add_bytes(&kse_bytes, ssl->s3->hs->key_share_bytes,
                        ssl->s3->hs->key_share_bytes_len)) {
       return 0;
     }
     OPENSSL_free(ssl->s3->hs->key_share_bytes);
     ssl->s3->hs->key_share_bytes = NULL;
     ssl->s3->hs->key_share_bytes_len = 0;
-
-    group_id = ssl->s3->hs->retry_group;
-
-    /* We received a HelloRetryRequest without a new curve, so there is no new
-     * share to append. Leave |ecdh_ctx| as-is. */
     if (group_id == 0) {
       return CBB_flush(out);
     }
@@ -2319,10 +2363,6 @@
  * https://tools.ietf.org/html/draft-ietf-tls-tls13-16#section-4.2.4 */
 
 static int ext_supported_groups_add_clienthello(SSL *ssl, CBB *out) {
-  if (!ssl_any_ec_cipher_suites_enabled(ssl)) {
-    return 1;
-  }
-
   CBB contents, groups_bytes;
   if (!CBB_add_u16(out, TLSEXT_TYPE_supported_groups) ||
       !CBB_add_u16_length_prefixed(out, &contents) ||
@@ -2473,10 +2513,11 @@
   },
   {
     TLSEXT_TYPE_application_layer_protocol_negotiation,
-    ext_alpn_init,
+    NULL,
     ext_alpn_add_clienthello,
     ext_alpn_parse_serverhello,
-    ext_alpn_parse_clienthello,
+    /* ALPN is negotiated late in |ssl_negotiate_alpn|. */
+    ignore_parse_clienthello,
     ext_alpn_add_serverhello,
   },
   {
@@ -2512,11 +2553,11 @@
     dont_add_serverhello,
   },
   {
-    TLSEXT_TYPE_pre_shared_key,
+    TLSEXT_TYPE_psk_key_exchange_modes,
     NULL,
-    ext_pre_shared_key_add_clienthello,
+    ext_psk_key_exchange_modes_add_clienthello,
     forbid_parse_serverhello,
-    ignore_parse_clienthello,
+    ext_psk_key_exchange_modes_parse_clienthello,
     dont_add_serverhello,
   },
   {
@@ -2611,7 +2652,7 @@
     const size_t len_before = CBB_len(&extensions);
     if (!kExtensions[i].add_clienthello(ssl, &extensions)) {
       OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_ADDING_EXTENSION);
-      ERR_add_error_dataf("extension: %u", (unsigned)kExtensions[i].value);
+      ERR_add_error_dataf("extension %u", (unsigned)kExtensions[i].value);
       goto err;
     }
 
@@ -2643,7 +2684,8 @@
   }
 
   if (!SSL_is_dtls(ssl)) {
-    header_len += 2 + CBB_len(&extensions);
+    size_t psk_extension_len = ext_pre_shared_key_clienthello_length(ssl);
+    header_len += 2 + CBB_len(&extensions) + psk_extension_len;
     if (header_len > 0xff && header_len < 0x200) {
       /* Add padding to workaround bugs in F5 terminators. See RFC 7685.
        *
@@ -2671,6 +2713,11 @@
     }
   }
 
+  /* The PSK extension must be last, including after the padding. */
+  if (!ext_pre_shared_key_add_clienthello(ssl, &extensions)) {
+    goto err;
+  }
+
   /* Discard empty extensions blocks. */
   if (CBB_len(&extensions) == 0) {
     CBB_discard_child(out);
@@ -2698,7 +2745,7 @@
 
     if (!kExtensions[i].add_serverhello(ssl, &extensions)) {
       OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_ADDING_EXTENSION);
-      ERR_add_error_dataf("extension: %u", (unsigned)kExtensions[i].value);
+      ERR_add_error_dataf("extension %u", (unsigned)kExtensions[i].value);
       goto err;
     }
   }
@@ -2768,7 +2815,7 @@
     if (!ext->parse_clienthello(ssl, &alert, &extension)) {
       *out_alert = alert;
       OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_PARSING_EXTENSION);
-      ERR_add_error_dataf("extension: %u", (unsigned)type);
+      ERR_add_error_dataf("extension %u", (unsigned)type);
       return 0;
     }
   }
@@ -2796,7 +2843,7 @@
     uint8_t alert = SSL_AD_DECODE_ERROR;
     if (!kExtensions[i].parse_clienthello(ssl, &alert, contents)) {
       OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_EXTENSION);
-      ERR_add_error_dataf("extension: %u", (unsigned)kExtensions[i].value);
+      ERR_add_error_dataf("extension %u", (unsigned)kExtensions[i].value);
       *out_alert = alert;
       return 0;
     }
@@ -2875,7 +2922,7 @@
     uint8_t alert = SSL_AD_DECODE_ERROR;
     if (!ext->parse_serverhello(ssl, &alert, &extension)) {
       OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_PARSING_EXTENSION);
-      ERR_add_error_dataf("extension: %u", (unsigned)type);
+      ERR_add_error_dataf("extension %u", (unsigned)type);
       *out_alert = alert;
       return 0;
     }
@@ -2888,7 +2935,7 @@
       uint8_t alert = SSL_AD_DECODE_ERROR;
       if (!kExtensions[i].parse_serverhello(ssl, &alert, NULL)) {
         OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_EXTENSION);
-        ERR_add_error_dataf("extension: %u", (unsigned)kExtensions[i].value);
+        ERR_add_error_dataf("extension %u", (unsigned)kExtensions[i].value);
         *out_alert = alert;
         return 0;
       }
@@ -3090,12 +3137,6 @@
   memcpy(session->session_id, session_id, session_id_len);
   session->session_id_length = session_id_len;
 
-  if (!ssl_session_is_context_valid(ssl, session) ||
-      !ssl_session_is_time_valid(ssl, session)) {
-    SSL_SESSION_free(session);
-    session = NULL;
-  }
-
   *out_session = session;
 
 done:
@@ -3207,45 +3248,184 @@
   return 0;
 }
 
-int tls1_channel_id_hash(SSL *ssl, uint8_t *out, size_t *out_len) {
+int tls1_verify_channel_id(SSL *ssl) {
   int ret = 0;
-  EVP_MD_CTX ctx;
+  uint16_t extension_type;
+  CBS extension, channel_id;
 
-  EVP_MD_CTX_init(&ctx);
-  if (!EVP_DigestInit_ex(&ctx, EVP_sha256(), NULL)) {
+  /* A Channel ID handshake message is structured to contain multiple
+   * extensions, but the only one that can be present is Channel ID. */
+  CBS_init(&channel_id, ssl->init_msg, ssl->init_num);
+  if (!CBS_get_u16(&channel_id, &extension_type) ||
+      !CBS_get_u16_length_prefixed(&channel_id, &extension) ||
+      CBS_len(&channel_id) != 0 ||
+      extension_type != TLSEXT_TYPE_channel_id ||
+      CBS_len(&extension) != TLSEXT_CHANNEL_ID_SIZE) {
+    OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+    ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+    return 0;
+  }
+
+  EC_GROUP *p256 = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
+  if (!p256) {
+    OPENSSL_PUT_ERROR(SSL, SSL_R_NO_P256_SUPPORT);
+    return 0;
+  }
+
+  EC_KEY *key = NULL;
+  EC_POINT *point = NULL;
+  BIGNUM x, y;
+  ECDSA_SIG sig;
+  BN_init(&x);
+  BN_init(&y);
+  sig.r = BN_new();
+  sig.s = BN_new();
+  if (sig.r == NULL || sig.s == NULL) {
     goto err;
   }
 
+  const uint8_t *p = CBS_data(&extension);
+  if (BN_bin2bn(p + 0, 32, &x) == NULL ||
+      BN_bin2bn(p + 32, 32, &y) == NULL ||
+      BN_bin2bn(p + 64, 32, sig.r) == NULL ||
+      BN_bin2bn(p + 96, 32, sig.s) == NULL) {
+    goto err;
+  }
+
+  point = EC_POINT_new(p256);
+  if (point == NULL ||
+      !EC_POINT_set_affine_coordinates_GFp(p256, point, &x, &y, NULL)) {
+    goto err;
+  }
+
+  key = EC_KEY_new();
+  if (key == NULL ||
+      !EC_KEY_set_group(key, p256) ||
+      !EC_KEY_set_public_key(key, point)) {
+    goto err;
+  }
+
+  uint8_t digest[EVP_MAX_MD_SIZE];
+  size_t digest_len;
+  if (!tls1_channel_id_hash(ssl, digest, &digest_len)) {
+    goto err;
+  }
+
+  int sig_ok = ECDSA_do_verify(digest, digest_len, &sig, key);
+#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+  sig_ok = 1;
+#endif
+  if (!sig_ok) {
+    OPENSSL_PUT_ERROR(SSL, SSL_R_CHANNEL_ID_SIGNATURE_INVALID);
+    ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECRYPT_ERROR);
+    ssl->s3->tlsext_channel_id_valid = 0;
+    goto err;
+  }
+
+  memcpy(ssl->s3->tlsext_channel_id, p, 64);
+  ret = 1;
+
+err:
+  BN_free(&x);
+  BN_free(&y);
+  BN_free(sig.r);
+  BN_free(sig.s);
+  EC_KEY_free(key);
+  EC_POINT_free(point);
+  EC_GROUP_free(p256);
+  return ret;
+}
+
+int tls1_write_channel_id(SSL *ssl, CBB *cbb) {
+  uint8_t digest[EVP_MAX_MD_SIZE];
+  size_t digest_len;
+  if (!tls1_channel_id_hash(ssl, digest, &digest_len)) {
+    return 0;
+  }
+
+  EC_KEY *ec_key = EVP_PKEY_get0_EC_KEY(ssl->tlsext_channel_id_private);
+  if (ec_key == NULL) {
+    OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+    return 0;
+  }
+
+  int ret = 0;
+  BIGNUM *x = BN_new();
+  BIGNUM *y = BN_new();
+  ECDSA_SIG *sig = NULL;
+  if (x == NULL || y == NULL ||
+      !EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(ec_key),
+                                           EC_KEY_get0_public_key(ec_key),
+                                           x, y, NULL)) {
+    goto err;
+  }
+
+  sig = ECDSA_do_sign(digest, digest_len, ec_key);
+  if (sig == NULL) {
+    goto err;
+  }
+
+  CBB child;
+  if (!CBB_add_u16(cbb, TLSEXT_TYPE_channel_id) ||
+      !CBB_add_u16_length_prefixed(cbb, &child) ||
+      !BN_bn2cbb_padded(&child, 32, x) ||
+      !BN_bn2cbb_padded(&child, 32, y) ||
+      !BN_bn2cbb_padded(&child, 32, sig->r) ||
+      !BN_bn2cbb_padded(&child, 32, sig->s) ||
+      !CBB_flush(cbb)) {
+    goto err;
+  }
+
+  ret = 1;
+
+err:
+  BN_free(x);
+  BN_free(y);
+  ECDSA_SIG_free(sig);
+  return ret;
+}
+
+int tls1_channel_id_hash(SSL *ssl, uint8_t *out, size_t *out_len) {
+  if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) {
+    uint8_t *msg;
+    size_t msg_len;
+    if (!tls13_get_cert_verify_signature_input(ssl, &msg, &msg_len,
+                                               ssl_cert_verify_channel_id)) {
+      return 0;
+    }
+    SHA256(msg, msg_len, out);
+    *out_len = SHA256_DIGEST_LENGTH;
+    OPENSSL_free(msg);
+    return 1;
+  }
+
+  SHA256_CTX ctx;
+
+  SHA256_Init(&ctx);
   static const char kClientIDMagic[] = "TLS Channel ID signature";
-  EVP_DigestUpdate(&ctx, kClientIDMagic, sizeof(kClientIDMagic));
+  SHA256_Update(&ctx, kClientIDMagic, sizeof(kClientIDMagic));
 
   if (ssl->session != NULL) {
     static const char kResumptionMagic[] = "Resumption";
-    EVP_DigestUpdate(&ctx, kResumptionMagic, sizeof(kResumptionMagic));
+    SHA256_Update(&ctx, kResumptionMagic, sizeof(kResumptionMagic));
     if (ssl->session->original_handshake_hash_len == 0) {
       OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
-      goto err;
+      return 0;
     }
-    EVP_DigestUpdate(&ctx, ssl->session->original_handshake_hash,
-                     ssl->session->original_handshake_hash_len);
+    SHA256_Update(&ctx, ssl->session->original_handshake_hash,
+                  ssl->session->original_handshake_hash_len);
   }
 
   uint8_t handshake_hash[EVP_MAX_MD_SIZE];
   int handshake_hash_len = tls1_handshake_digest(ssl, handshake_hash,
                                                  sizeof(handshake_hash));
   if (handshake_hash_len < 0) {
-    goto err;
+    return 0;
   }
-  EVP_DigestUpdate(&ctx, handshake_hash, (size_t)handshake_hash_len);
-  unsigned len_u;
-  EVP_DigestFinal_ex(&ctx, out, &len_u);
-  *out_len = len_u;
-
-  ret = 1;
-
-err:
-  EVP_MD_CTX_cleanup(&ctx);
-  return ret;
+  SHA256_Update(&ctx, handshake_hash, (size_t)handshake_hash_len);
+  SHA256_Final(out, &ctx);
+  *out_len = SHA256_DIGEST_LENGTH;
+  return 1;
 }
 
 /* tls1_record_handshake_hashes_for_channel_id records the current handshake
@@ -3272,3 +3452,44 @@
 
   return 1;
 }
+
+int ssl_do_channel_id_callback(SSL *ssl) {
+  if (ssl->tlsext_channel_id_private != NULL ||
+      ssl->ctx->channel_id_cb == NULL) {
+    return 1;
+  }
+
+  EVP_PKEY *key = NULL;
+  ssl->ctx->channel_id_cb(ssl, &key);
+  if (key == NULL) {
+    /* The caller should try again later. */
+    return 1;
+  }
+
+  int ret = SSL_set1_tls_channel_id(ssl, key);
+  EVP_PKEY_free(key);
+  return ret;
+}
+
+int ssl_is_sct_list_valid(const CBS *contents) {
+  /* Shallow parse the SCT list for sanity. By the RFC
+   * (https://tools.ietf.org/html/rfc6962#section-3.3) neither the list nor any
+   * of the SCTs may be empty. */
+  CBS copy = *contents;
+  CBS sct_list;
+  if (!CBS_get_u16_length_prefixed(&copy, &sct_list) ||
+      CBS_len(&copy) != 0 ||
+      CBS_len(&sct_list) == 0) {
+    return 0;
+  }
+
+  while (CBS_len(&sct_list) > 0) {
+    CBS sct;
+    if (!CBS_get_u16_length_prefixed(&sct_list, &sct) ||
+        CBS_len(&sct) == 0) {
+      return 0;
+    }
+  }
+
+  return 1;
+}
diff --git a/src/ssl/test/bssl_shim.cc b/src/ssl/test/bssl_shim.cc
index 76caa4e..97860c4 100644
--- a/src/ssl/test/bssl_shim.cc
+++ b/src/ssl/test/bssl_shim.cc
@@ -40,6 +40,7 @@
 #include <inttypes.h>
 #include <string.h>
 
+#include <openssl/aead.h>
 #include <openssl/bio.h>
 #include <openssl/buf.h>
 #include <openssl/bytestring.h>
@@ -137,12 +138,46 @@
   return (TestState *)SSL_get_ex_data(ssl, g_state_index);
 }
 
-static bssl::UniquePtr<X509> LoadCertificate(const std::string &file) {
+static bool LoadCertificate(bssl::UniquePtr<X509> *out_x509,
+                            bssl::UniquePtr<STACK_OF(X509)> *out_chain,
+                            const std::string &file) {
   bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_file()));
   if (!bio || !BIO_read_filename(bio.get(), file.c_str())) {
-    return nullptr;
+    return false;
   }
-  return bssl::UniquePtr<X509>(PEM_read_bio_X509(bio.get(), NULL, NULL, NULL));
+
+  out_x509->reset(PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr));
+  if (!*out_x509) {
+    return false;
+  }
+
+  out_chain->reset(sk_X509_new_null());
+  if (!*out_chain) {
+    return false;
+  }
+
+  // Keep reading the certificate chain.
+  for (;;) {
+    bssl::UniquePtr<X509> cert(
+        PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr));
+    if (!cert) {
+      break;
+    }
+
+    if (!sk_X509_push(out_chain->get(), cert.get())) {
+      return false;
+    }
+    cert.release();  // sk_X509_push takes ownership.
+  }
+
+  uint32_t err = ERR_peek_last_error();
+  if (ERR_GET_LIB(err) != ERR_LIB_PEM ||
+      ERR_GET_REASON(err) != PEM_R_NO_START_LINE) {
+    return false;
+}
+
+  ERR_clear_error();
+  return true;
 }
 
 static bssl::UniquePtr<EVP_PKEY> LoadPrivateKey(const std::string &file) {
@@ -320,6 +355,7 @@
 };
 
 static bool GetCertificate(SSL *ssl, bssl::UniquePtr<X509> *out_x509,
+                           bssl::UniquePtr<STACK_OF(X509)> *out_chain,
                            bssl::UniquePtr<EVP_PKEY> *out_pkey) {
   const TestConfig *config = GetTestConfig(ssl);
 
@@ -358,14 +394,12 @@
       return false;
     }
   }
-  if (!config->cert_file.empty()) {
-    *out_x509 = LoadCertificate(config->cert_file.c_str());
-    if (!*out_x509) {
-      return false;
-    }
+  if (!config->cert_file.empty() &&
+      !LoadCertificate(out_x509, out_chain, config->cert_file.c_str())) {
+    return false;
   }
   if (!config->ocsp_response.empty() &&
-      !SSL_CTX_set_ocsp_response(ssl->ctx,
+      !SSL_CTX_set_ocsp_response(SSL_get_SSL_CTX(ssl),
                                  (const uint8_t *)config->ocsp_response.data(),
                                  config->ocsp_response.size())) {
     return false;
@@ -375,8 +409,9 @@
 
 static bool InstallCertificate(SSL *ssl) {
   bssl::UniquePtr<X509> x509;
+  bssl::UniquePtr<STACK_OF(X509)> chain;
   bssl::UniquePtr<EVP_PKEY> pkey;
-  if (!GetCertificate(ssl, &x509, &pkey)) {
+  if (!GetCertificate(ssl, &x509, &chain, &pkey)) {
     return false;
   }
 
@@ -395,6 +430,11 @@
     return false;
   }
 
+  if (sk_X509_num(chain.get()) > 0 &&
+      !SSL_set1_chain(ssl, chain.get())) {
+    return false;
+  }
+
   return true;
 }
 
@@ -456,8 +496,9 @@
   }
 
   bssl::UniquePtr<X509> x509;
+  bssl::UniquePtr<STACK_OF(X509)> chain;
   bssl::UniquePtr<EVP_PKEY> pkey;
-  if (!GetCertificate(ssl, &x509, &pkey)) {
+  if (!GetCertificate(ssl, &x509, &chain, &pkey)) {
     return -1;
   }
 
@@ -466,7 +507,7 @@
     return 0;
   }
 
-  // Asynchronous private keys are not supported with client_cert_cb.
+  // Chains and asynchronous private keys are not supported with client_cert_cb.
   *out_x509 = x509.release();
   *out_pkey = pkey.release();
   return 1;
@@ -594,8 +635,10 @@
   return config->psk.size();
 }
 
+static timeval g_clock;
+
 static void CurrentTimeCallback(const SSL *ssl, timeval *out_clock) {
-  *out_clock = PacketedBioGetClock(GetTestState(ssl)->packeted_bio);
+  *out_clock = g_clock;
 }
 
 static void ChannelIdCallback(SSL *ssl, EVP_PKEY **out_pkey) {
@@ -622,6 +665,10 @@
     }
   }
 
+  if (config->fail_cert_callback) {
+    return 0;
+  }
+
   // The certificate will be installed via other means.
   if (!config->async || config->use_early_callback ||
       config->use_old_client_cert_callback) {
@@ -774,6 +821,20 @@
   return 1;
 }
 
+static int ServerNameCallback(SSL *ssl, int *out_alert, void *arg) {
+  // SNI must be accessible from the SNI callback.
+  const TestConfig *config = GetTestConfig(ssl);
+  const char *server_name = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
+  if (server_name == nullptr ||
+      std::string(server_name) != config->expected_server_name) {
+    fprintf(stderr, "servername mismatch (got %s; want %s)\n", server_name,
+            config->expected_server_name.c_str());
+    return SSL_TLSEXT_ERR_ALERT_FATAL;
+  }
+
+  return SSL_TLSEXT_ERR_OK;
+}
+
 // Connect returns a new socket connected to localhost on |port| or -1 on
 // error.
 static int Connect(uint16_t port) {
@@ -923,9 +984,7 @@
   SSL_CTX_enable_tls_channel_id(ssl_ctx.get());
   SSL_CTX_set_channel_id_cb(ssl_ctx.get(), ChannelIdCallback);
 
-  if (config->is_dtls) {
-    SSL_CTX_set_current_time_cb(ssl_ctx.get(), CurrentTimeCallback);
-  }
+  SSL_CTX_set_current_time_cb(ssl_ctx.get(), CurrentTimeCallback);
 
   SSL_CTX_set_info_callback(ssl_ctx.get(), InfoCallback);
   SSL_CTX_sess_set_new_cb(ssl_ctx.get(), NewSessionCallback);
@@ -971,6 +1030,16 @@
     SSL_CTX_set_grease_enabled(ssl_ctx.get(), 1);
   }
 
+  if (!config->expected_server_name.empty()) {
+    SSL_CTX_set_tlsext_servername_callback(ssl_ctx.get(), ServerNameCallback);
+  }
+
+  if (!config->ticket_key.empty() &&
+      !SSL_CTX_set_tlsext_ticket_keys(ssl_ctx.get(), config->ticket_key.data(),
+                                      config->ticket_key.size())) {
+    return nullptr;
+  }
+
   return ssl_ctx;
 }
 
@@ -1054,6 +1123,16 @@
     if (config->async) {
       AsyncBioEnforceWriteQuota(test_state->async_bio, true);
     }
+
+    // Run the exporter after each read. This is to test that the exporter fails
+    // during a renegotiation.
+    if (config->use_exporter_between_reads) {
+      uint8_t buf;
+      if (!SSL_export_keying_material(ssl, &buf, 1, NULL, 0, NULL, 0, 0)) {
+        fprintf(stderr, "failed to export keying material\n");
+        return -1;
+      }
+    }
   } while (config->async && RetryAsync(ssl, ret));
 
   if (config->peek_then_read && ret > 0) {
@@ -1171,7 +1250,8 @@
   if (!config->expected_server_name.empty()) {
     const char *server_name =
         SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
-    if (server_name != config->expected_server_name) {
+    if (server_name == nullptr ||
+        server_name != config->expected_server_name) {
       fprintf(stderr, "servername mismatch (got %s; want %s)\n",
               server_name, config->expected_server_name.c_str());
       return false;
@@ -1285,6 +1365,25 @@
     }
   }
 
+  uint16_t cipher_id =
+      static_cast<uint16_t>(SSL_CIPHER_get_id(SSL_get_current_cipher(ssl)));
+  if (config->expect_cipher_aes != 0 &&
+      EVP_has_aes_hardware() &&
+      static_cast<uint16_t>(config->expect_cipher_aes) != cipher_id) {
+    fprintf(stderr, "Cipher ID was %04x, wanted %04x (has AES hardware)\n",
+            cipher_id, static_cast<uint16_t>(config->expect_cipher_aes));
+    return false;
+  }
+
+  if (config->expect_cipher_no_aes != 0 &&
+      !EVP_has_aes_hardware() &&
+      static_cast<uint16_t>(config->expect_cipher_no_aes) != cipher_id) {
+    fprintf(stderr, "Cipher ID was %04x, wanted %04x (no AES hardware)\n",
+            cipher_id, static_cast<uint16_t>(config->expect_cipher_no_aes));
+    return false;
+  }
+
+
   if (!config->psk.empty()) {
     if (SSL_get_peer_cert_chain(ssl) != nullptr) {
       fprintf(stderr, "Received peer certificate on a PSK cipher.\n");
@@ -1297,6 +1396,65 @@
     }
   }
 
+  if (!config->expect_peer_cert_file.empty()) {
+    bssl::UniquePtr<X509> expect_leaf;
+    bssl::UniquePtr<STACK_OF(X509)> expect_chain;
+    if (!LoadCertificate(&expect_leaf, &expect_chain,
+                         config->expect_peer_cert_file)) {
+      return false;
+    }
+
+    // For historical reasons, clients report a chain with a leaf and servers
+    // without.
+    if (!config->is_server) {
+      if (!sk_X509_insert(expect_chain.get(), expect_leaf.get(), 0)) {
+        return false;
+      }
+      X509_up_ref(expect_leaf.get());  // sk_X509_push takes ownership.
+    }
+
+    bssl::UniquePtr<X509> leaf(SSL_get_peer_certificate(ssl));
+    STACK_OF(X509) *chain = SSL_get_peer_cert_chain(ssl);
+    if (X509_cmp(leaf.get(), expect_leaf.get()) != 0) {
+      fprintf(stderr, "Received a different leaf certificate than expected.\n");
+      return false;
+    }
+
+    if (sk_X509_num(chain) != sk_X509_num(expect_chain.get())) {
+      fprintf(stderr, "Received a chain of length %zu instead of %zu.\n",
+              sk_X509_num(chain), sk_X509_num(expect_chain.get()));
+      return false;
+    }
+
+    for (size_t i = 0; i < sk_X509_num(chain); i++) {
+      if (X509_cmp(sk_X509_value(chain, i),
+                   sk_X509_value(expect_chain.get(), i)) != 0) {
+        fprintf(stderr, "Chain certificate %zu did not match.\n",
+                i + 1);
+        return false;
+      }
+    }
+  }
+
+  bool expected_sha256_client_cert = config->expect_sha256_client_cert_initial;
+  if (is_resume) {
+    expected_sha256_client_cert = config->expect_sha256_client_cert_resume;
+  }
+
+  if (SSL_get_session(ssl)->peer_sha256_valid != expected_sha256_client_cert) {
+    fprintf(stderr,
+            "Unexpected SHA-256 client cert state: expected:%d is_resume:%d.\n",
+            expected_sha256_client_cert, is_resume);
+    return false;
+  }
+
+  if (expected_sha256_client_cert &&
+      SSL_get_session(ssl)->x509_peer != nullptr) {
+    fprintf(stderr, "Have both client cert and SHA-256 hash: is_resume:%d.\n",
+            is_resume);
+    return false;
+  }
+
   return true;
 }
 
@@ -1456,6 +1614,12 @@
   if (config->max_cert_list > 0) {
     SSL_set_max_cert_list(ssl.get(), config->max_cert_list);
   }
+  if (!is_resume && config->retain_only_sha256_client_cert_initial) {
+    SSL_set_retain_only_sha256_of_client_certs(ssl.get(), 1);
+  }
+  if (is_resume && config->retain_only_sha256_client_cert_resume) {
+    SSL_set_retain_only_sha256_of_client_certs(ssl.get(), 1);
+  }
 
   int sock = Connect(config->port);
   if (sock == -1) {
@@ -1468,7 +1632,7 @@
     return false;
   }
   if (config->is_dtls) {
-    bssl::UniquePtr<BIO> packeted = PacketedBioCreate(!config->async);
+    bssl::UniquePtr<BIO> packeted = PacketedBioCreate(&g_clock, !config->async);
     if (!packeted) {
       return false;
     }
@@ -1743,6 +1907,11 @@
     return Usage(argv[0]);
   }
 
+  // Some code treats the zero time special, so initialize the clock to a
+  // non-zero time.
+  g_clock.tv_sec = 1234;
+  g_clock.tv_usec = 1234;
+
   bssl::UniquePtr<SSL_CTX> ssl_ctx = SetupCtx(&config);
   if (!ssl_ctx) {
     ERR_print_errors_fp(stderr);
@@ -1764,6 +1933,10 @@
       ERR_print_errors_fp(stderr);
       return 1;
     }
+
+    if (config.resumption_delay != 0) {
+      g_clock.tv_sec += config.resumption_delay;
+    }
   }
 
   return 0;
diff --git a/src/ssl/test/packeted_bio.cc b/src/ssl/test/packeted_bio.cc
index f7267fc..8331b4b 100644
--- a/src/ssl/test/packeted_bio.cc
+++ b/src/ssl/test/packeted_bio.cc
@@ -31,10 +31,9 @@
 const uint8_t kOpcodeTimeoutAck = 't';
 
 struct PacketedBio {
-  explicit PacketedBio(bool advance_clock_arg)
-      : advance_clock(advance_clock_arg) {
+  PacketedBio(timeval *clock_arg, bool advance_clock_arg)
+      : clock(clock_arg), advance_clock(advance_clock_arg) {
     memset(&timeout, 0, sizeof(timeout));
-    memset(&clock, 0, sizeof(clock));
     memset(&read_deadline, 0, sizeof(read_deadline));
   }
 
@@ -47,14 +46,14 @@
       return true;
     }
 
-    if (clock.tv_sec == read_deadline.tv_sec) {
-      return clock.tv_usec < read_deadline.tv_usec;
+    if (clock->tv_sec == read_deadline.tv_sec) {
+      return clock->tv_usec < read_deadline.tv_usec;
     }
-    return clock.tv_sec < read_deadline.tv_sec;
+    return clock->tv_sec < read_deadline.tv_sec;
   }
 
   timeval timeout;
-  timeval clock;
+  timeval *clock;
   timeval read_deadline;
   bool advance_clock;
 };
@@ -66,10 +65,6 @@
   return (PacketedBio *)bio->ptr;
 }
 
-const PacketedBio *GetData(const BIO *bio) {
-  return GetData(const_cast<BIO*>(bio));
-}
-
 // ReadAll reads |len| bytes from |bio| into |out|. It returns 1 on success and
 // 0 or -1 on error.
 static int ReadAll(BIO *bio, uint8_t *out, size_t len) {
@@ -272,19 +267,15 @@
 
 }  // namespace
 
-bssl::UniquePtr<BIO> PacketedBioCreate(bool advance_clock) {
+bssl::UniquePtr<BIO> PacketedBioCreate(timeval *clock, bool advance_clock) {
   bssl::UniquePtr<BIO> bio(BIO_new(&g_packeted_bio_method));
   if (!bio) {
     return nullptr;
   }
-  bio->ptr = new PacketedBio(advance_clock);
+  bio->ptr = new PacketedBio(clock, advance_clock);
   return bio;
 }
 
-timeval PacketedBioGetClock(const BIO *bio) {
-  return GetData(bio)->clock;
-}
-
 bool PacketedBioAdvanceClock(BIO *bio) {
   PacketedBio *data = GetData(bio);
   if (data == nullptr) {
@@ -295,10 +286,10 @@
     return false;
   }
 
-  data->clock.tv_usec += data->timeout.tv_usec;
-  data->clock.tv_sec += data->clock.tv_usec / 1000000;
-  data->clock.tv_usec %= 1000000;
-  data->clock.tv_sec += data->timeout.tv_sec;
+  data->clock->tv_usec += data->timeout.tv_usec;
+  data->clock->tv_sec += data->clock->tv_usec / 1000000;
+  data->clock->tv_usec %= 1000000;
+  data->clock->tv_sec += data->timeout.tv_sec;
   memset(&data->timeout, 0, sizeof(data->timeout));
   return true;
 }
diff --git a/src/ssl/test/packeted_bio.h b/src/ssl/test/packeted_bio.h
index 07930d4..9d4cdcb 100644
--- a/src/ssl/test/packeted_bio.h
+++ b/src/ssl/test/packeted_bio.h
@@ -28,21 +28,18 @@
 
 
 // PacketedBioCreate creates a filter BIO which implements a reliable in-order
-// blocking datagram socket. It internally maintains a clock and honors
-// |BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT| based on it.
+// blocking datagram socket. It uses the value of |*clock| as the clock and
+// honors |BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT| based on it.
 //
 // During a |BIO_read|, the peer may signal the filter BIO to simulate a
 // timeout. If |advance_clock| is true, it automatically advances the clock and
 // continues reading, subject to the read deadline. Otherwise, it fails
 // immediately. The caller must then call |PacketedBioAdvanceClock| before
 // retrying |BIO_read|.
-bssl::UniquePtr<BIO> PacketedBioCreate(bool advance_clock);
+bssl::UniquePtr<BIO> PacketedBioCreate(timeval *clock, bool advance_clock);
 
-// PacketedBioGetClock returns the current time for |bio|.
-timeval PacketedBioGetClock(const BIO *bio);
-
-// PacketedBioAdvanceClock advances |bio|'s internal clock and returns true if
-// there is a pending timeout. Otherwise, it returns false.
+// PacketedBioAdvanceClock advances |bio|'s clock and returns true if there is a
+// pending timeout. Otherwise, it returns false.
 bool PacketedBioAdvanceClock(BIO *bio);
 
 
diff --git a/src/ssl/test/runner/cipher_suites.go b/src/ssl/test/runner/cipher_suites.go
index 656a3d0..a997016 100644
--- a/src/ssl/test/runner/cipher_suites.go
+++ b/src/ssl/test/runner/cipher_suites.go
@@ -480,12 +480,16 @@
 func mutualCipherSuite(have []uint16, want uint16) *cipherSuite {
 	for _, id := range have {
 		if id == want {
-			for _, suite := range cipherSuites {
-				if suite.id == want {
-					return suite
-				}
-			}
-			return nil
+			return cipherSuiteFromID(id)
+		}
+	}
+	return nil
+}
+
+func cipherSuiteFromID(id uint16) *cipherSuite {
+	for _, suite := range cipherSuites {
+		if suite.id == id {
+			return suite
 		}
 	}
 	return nil
diff --git a/src/ssl/test/runner/common.go b/src/ssl/test/runner/common.go
index 62c8dd3..a6496fd 100644
--- a/src/ssl/test/runner/common.go
+++ b/src/ssl/test/runner/common.go
@@ -27,7 +27,7 @@
 )
 
 // A draft version of TLS 1.3 that is sent over the wire for the current draft.
-const tls13DraftVersion = 0x7f10
+const tls13DraftVersion = 0x7f12
 
 const (
 	maxPlaintext        = 16384        // maximum plaintext payload length
@@ -94,6 +94,7 @@
 	extensionEarlyData                  uint16 = 42    // draft-ietf-tls-tls13-16
 	extensionSupportedVersions          uint16 = 43    // draft-ietf-tls-tls13-16
 	extensionCookie                     uint16 = 44    // draft-ietf-tls-tls13-16
+	extensionPSKKeyExchangeModes        uint16 = 45    // draft-ietf-tls-tls13-18
 	extensionCustom                     uint16 = 1234  // not IANA assigned
 	extensionNextProtoNeg               uint16 = 13172 // not IANA assigned
 	extensionRenegotiationInfo          uint16 = 0xff01
@@ -200,12 +201,6 @@
 	pskDHEKEMode = 1
 )
 
-// PskAuthenticationMode values (see draft-ietf-tls-tls13-16)
-const (
-	pskAuthMode     = 0
-	pskSignAuthMode = 1
-)
-
 // KeyUpdateRequest values (see draft-ietf-tls-tls13-16, section 4.5.3)
 const (
 	keyUpdateNotRequested = 0
@@ -259,6 +254,7 @@
 	ocspResponse         []byte
 	ticketCreationTime   time.Time
 	ticketExpiration     time.Time
+	ticketAgeAdd         uint32
 }
 
 // ClientSessionCache is a cache of ClientSessionState objects that can be used
@@ -661,9 +657,9 @@
 	// TLS 1.2 and 1.3 extensions.
 	SendBothTickets bool
 
-	// CorruptTicket causes a client to corrupt a session ticket before
-	// sending it in a resume handshake.
-	CorruptTicket bool
+	// FilterTicket, if not nil, causes the client to modify a session
+	// ticket before sending it in a resume handshake.
+	FilterTicket func([]byte) ([]byte, error)
 
 	// OversizedSessionId causes the session id that is sent with a ticket
 	// resumption attempt to be too large (33 bytes).
@@ -753,9 +749,17 @@
 	RequireSameRenegoClientVersion bool
 
 	// ExpectInitialRecordVersion, if non-zero, is the expected value of
-	// record-layer version field before the version is determined.
+	// record-layer version field before the protocol version is determined.
 	ExpectInitialRecordVersion uint16
 
+	// SendRecordVersion, if non-zero, is the value to send as the
+	// record-layer version.
+	SendRecordVersion uint16
+
+	// SendInitialRecordVersion, if non-zero, is the value to send as the
+	// record-layer version before the protocol version is determined.
+	SendInitialRecordVersion uint16
+
 	// MaxPacketLength, if non-zero, is the maximum acceptable size for a
 	// packet.
 	MaxPacketLength int
@@ -765,6 +769,11 @@
 	// the server believes it has actually negotiated.
 	SendCipherSuite uint16
 
+	// SendCipherSuites, if not nil, is the cipher suite list that the
+	// client will send in the ClientHello. This does not affect the cipher
+	// the client believes it has actually offered.
+	SendCipherSuites []uint16
+
 	// AppDataBeforeHandshake, if not nil, causes application data to be
 	// sent immediately before the first handshake message.
 	AppDataBeforeHandshake []byte
@@ -939,12 +948,17 @@
 	// session ticket.
 	SendEmptySessionTicket bool
 
-	// SnedPSKKeyExchangeModes, if present, determines the PSK key exchange modes
+	// SendPSKKeyExchangeModes, if present, determines the PSK key exchange modes
 	// to send.
 	SendPSKKeyExchangeModes []byte
 
-	// SendPSKAuthModes, if present, determines the PSK auth modes to send.
-	SendPSKAuthModes []byte
+	// ExpectNoNewSessionTicket, if present, means that the client will fail upon
+	// receipt of a NewSessionTicket message.
+	ExpectNoNewSessionTicket bool
+
+	// ExpectTicketAge, if non-zero, is the expected age of the ticket that the
+	// server receives from the client.
+	ExpectTicketAge time.Duration
 
 	// FailIfSessionOffered, if true, causes the server to fail any
 	// connections where the client offers a non-empty session ID or session
@@ -991,6 +1005,26 @@
 	// supplied stapled response.
 	SendOCSPResponseOnResume []byte
 
+	// SendExtensionOnCertificate, if not nil, causes the runner to send the
+	// supplied bytes in the extensions on the Certificate message.
+	SendExtensionOnCertificate []byte
+
+	// SendOCSPOnIntermediates, if not nil, causes the server to send the
+	// supplied OCSP on intermediate certificates in the Certificate message.
+	SendOCSPOnIntermediates []byte
+
+	// SendSCTOnIntermediates, if not nil, causes the server to send the
+	// supplied SCT on intermediate certificates in the Certificate message.
+	SendSCTOnIntermediates []byte
+
+	// SendDuplicateCertExtensions, if true, causes the server to send an extra
+	// copy of the OCSP/SCT extensions in the Certificate message.
+	SendDuplicateCertExtensions bool
+
+	// ExpectNoExtensionsOnIntermediate, if true, causes the client to
+	// reject extensions on intermediate certificates.
+	ExpectNoExtensionsOnIntermediate bool
+
 	// CECPQ1BadX25519Part corrupts the X25519 part of a CECPQ1 key exchange, as
 	// a trivial proof that it is actually used.
 	CECPQ1BadX25519Part bool
@@ -1028,10 +1062,6 @@
 	// Renegotiation Info to be negotiated at all versions.
 	NegotiateRenegotiationInfoAtAllVersions bool
 
-	// NegotiateChannelIDAtAllVersions, if true, causes Channel ID to be
-	// negotiated at all versions.
-	NegotiateChannelIDAtAllVersions bool
-
 	// NegotiateNPNAtAllVersions, if true, causes NPN to be negotiated at
 	// all versions.
 	NegotiateNPNAtAllVersions bool
@@ -1056,13 +1086,9 @@
 	// the specified PSK identity index rather than the actual value.
 	SelectPSKIdentityOnResume uint16
 
-	// OmitServerHelloSignatureAlgorithms, if true, causes the server to omit the
-	// signature_algorithms extension in the ServerHello.
-	OmitServerHelloSignatureAlgorithms bool
-
-	// IncludeServerHelloSignatureAlgorithms, if true, causes the server to
-	// include the signature_algorithms extension in all ServerHellos.
-	IncludeServerHelloSignatureAlgorithms bool
+	// ExtraPSKIdentity, if true, causes the client to send an extra PSK
+	// identity.
+	ExtraPSKIdentity bool
 
 	// MissingKeyShare, if true, causes the TLS 1.3 implementation to skip
 	// sending a key_share extension and use the zero ECDHE secret
@@ -1160,6 +1186,29 @@
 	// ExpectGREASE, if true, causes messages without GREASE values to be
 	// rejected. See draft-davidben-tls-grease-01.
 	ExpectGREASE bool
+
+	// SendShortPSKBinder, if true, causes the client to send a PSK binder
+	// that is one byte shorter than it should be.
+	SendShortPSKBinder bool
+
+	// SendInvalidPSKBinder, if true, causes the client to send an invalid
+	// PSK binder.
+	SendInvalidPSKBinder bool
+
+	// SendNoPSKBinder, if true, causes the client to send no PSK binders.
+	SendNoPSKBinder bool
+
+	// PSKBinderFirst, if true, causes the client to send the PSK Binder
+	// extension as the first extension instead of the last extension.
+	PSKBinderFirst bool
+
+	// NoOCSPStapling, if true, causes the client to not request OCSP
+	// stapling.
+	NoOCSPStapling bool
+
+	// NoSignedCertificateTimestamps, if true, causes the client to not
+	// request signed certificate timestamps.
+	NoSignedCertificateTimestamps bool
 }
 
 func (c *Config) serverInit() {
diff --git a/src/ssl/test/runner/conn.go b/src/ssl/test/runner/conn.go
index f5014d4..39c2785 100644
--- a/src/ssl/test/runner/conn.go
+++ b/src/ssl/test/runner/conn.go
@@ -208,9 +208,9 @@
 }
 
 // useTrafficSecret sets the current cipher state for TLS 1.3.
-func (hc *halfConn) useTrafficSecret(version uint16, suite *cipherSuite, secret, phase []byte, side trafficDirection) {
+func (hc *halfConn) useTrafficSecret(version uint16, suite *cipherSuite, secret []byte, side trafficDirection) {
 	hc.version = version
-	hc.cipher = deriveTrafficAEAD(version, suite, secret, phase, side)
+	hc.cipher = deriveTrafficAEAD(version, suite, secret, side)
 	if hc.config.Bugs.NullAllCiphers {
 		hc.cipher = nullCipher{}
 	}
@@ -223,7 +223,7 @@
 	if c.isClient == isOutgoing {
 		side = clientWrite
 	}
-	hc.useTrafficSecret(hc.version, c.cipherSuite, updateTrafficSecret(c.cipherSuite.hash(), hc.trafficSecret), applicationPhase, side)
+	hc.useTrafficSecret(hc.version, c.cipherSuite, updateTrafficSecret(c.cipherSuite.hash(), hc.trafficSecret), side)
 }
 
 // incSeq increments the sequence number.
@@ -753,16 +753,18 @@
 	// record-layer version prior to TLS 1.3. (In TLS 1.3, the record-layer
 	// version is irrelevant.)
 	if typ != recordTypeAlert {
+		var expect uint16
 		if c.haveVers {
-			if vers != c.vers && c.vers < VersionTLS13 {
-				c.sendAlert(alertProtocolVersion)
-				return 0, nil, c.in.setErrorLocked(fmt.Errorf("tls: received record with version %x when expecting version %x", vers, c.vers))
+			expect = c.vers
+			if c.vers >= VersionTLS13 {
+				expect = VersionTLS10
 			}
 		} else {
-			if expect := c.config.Bugs.ExpectInitialRecordVersion; expect != 0 && vers != expect {
-				c.sendAlert(alertProtocolVersion)
-				return 0, nil, c.in.setErrorLocked(fmt.Errorf("tls: received record with version %x when expecting version %x", vers, expect))
-			}
+			expect = c.config.Bugs.ExpectInitialRecordVersion
+		}
+		if expect != 0 && vers != expect {
+			c.sendAlert(alertProtocolVersion)
+			return 0, nil, c.in.setErrorLocked(fmt.Errorf("tls: received record with version %x when expecting version %x", vers, expect))
 		}
 	}
 	if n > maxCiphertext {
@@ -1063,6 +1065,12 @@
 			// layer to {3, 1}.
 			vers = VersionTLS10
 		}
+		if c.config.Bugs.SendRecordVersion != 0 {
+			vers = c.config.Bugs.SendRecordVersion
+		}
+		if c.vers == 0 && c.config.Bugs.SendInitialRecordVersion != 0 {
+			vers = c.config.Bugs.SendInitialRecordVersion
+		}
 		b.data[1] = byte(vers >> 8)
 		b.data[2] = byte(vers)
 		b.data[3] = byte(m >> 8)
@@ -1396,27 +1404,14 @@
 				return errors.New("tls: no GREASE ticket extension found")
 			}
 
+			if c.config.Bugs.ExpectNoNewSessionTicket {
+				return errors.New("tls: received unexpected NewSessionTicket")
+			}
+
 			if c.config.ClientSessionCache == nil || newSessionTicket.ticketLifetime == 0 {
 				return nil
 			}
 
-			var foundKE, foundAuth bool
-			for _, mode := range newSessionTicket.keModes {
-				if mode == pskDHEKEMode {
-					foundKE = true
-				}
-			}
-			for _, mode := range newSessionTicket.authModes {
-				if mode == pskAuthMode {
-					foundAuth = true
-				}
-			}
-
-			// Ignore the ticket if the server preferences do not match a mode we implement.
-			if !foundKE || !foundAuth {
-				return nil
-			}
-
 			session := &ClientSessionState{
 				sessionTicket:      newSessionTicket.ticket,
 				vers:               c.vers,
@@ -1427,6 +1422,7 @@
 				ocspResponse:       c.ocspResponse,
 				ticketCreationTime: c.config.time(),
 				ticketExpiration:   c.config.time().Add(time.Duration(newSessionTicket.ticketLifetime) * time.Second),
+				ticketAgeAdd:       newSessionTicket.ticketAgeAdd,
 			}
 
 			cacheKey := clientSessionCacheKey(c.conn.RemoteAddr(), c.config)
@@ -1709,20 +1705,20 @@
 		peerCertificatesRaw = append(peerCertificatesRaw, cert.Raw)
 	}
 
+	addBuffer := make([]byte, 4)
+	_, err := io.ReadFull(c.config.rand(), addBuffer)
+	if err != nil {
+		c.sendAlert(alertInternalError)
+		return errors.New("tls: short read from Rand: " + err.Error())
+	}
+	ticketAgeAdd := uint32(addBuffer[3])<<24 | uint32(addBuffer[2])<<16 | uint32(addBuffer[1])<<8 | uint32(addBuffer[0])
+
 	// TODO(davidben): Allow configuring these values.
 	m := &newSessionTicketMsg{
 		version:         c.vers,
 		ticketLifetime:  uint32(24 * time.Hour / time.Second),
-		keModes:         []byte{pskDHEKEMode},
-		authModes:       []byte{pskAuthMode},
 		customExtension: c.config.Bugs.CustomTicketExtension,
-	}
-
-	if len(c.config.Bugs.SendPSKKeyExchangeModes) != 0 {
-		m.keModes = c.config.Bugs.SendPSKKeyExchangeModes
-	}
-	if len(c.config.Bugs.SendPSKAuthModes) != 0 {
-		m.authModes = c.config.Bugs.SendPSKAuthModes
+		ticketAgeAdd:    ticketAgeAdd,
 	}
 
 	state := sessionState{
@@ -1732,6 +1728,7 @@
 		certificates:       peerCertificatesRaw,
 		ticketCreationTime: c.config.time(),
 		ticketExpiration:   c.config.time().Add(time.Duration(m.ticketLifetime) * time.Second),
+		ticketAgeAdd:       uint32(addBuffer[3])<<24 | uint32(addBuffer[2])<<16 | uint32(addBuffer[1])<<8 | uint32(addBuffer[0]),
 	}
 
 	if !c.config.Bugs.SendEmptySessionTicket {
@@ -1744,7 +1741,7 @@
 
 	c.out.Lock()
 	defer c.out.Unlock()
-	_, err := c.writeRecord(recordTypeHandshake, m.marshal())
+	_, err = c.writeRecord(recordTypeHandshake, m.marshal())
 	return err
 }
 
diff --git a/src/ssl/test/runner/fuzzer_mode.json b/src/ssl/test/runner/fuzzer_mode.json
index 8fc1a56..24f3bd6 100644
--- a/src/ssl/test/runner/fuzzer_mode.json
+++ b/src/ssl/test/runner/fuzzer_mode.json
@@ -1,14 +1,14 @@
 {
   "DisabledTests": {
     "BadCBCPadding*": "Fuzzer mode has no CBC padding.",
-    "BadECDSA-*": "Fuzzer mode ignores invalid signatures.",
-    "*-InvalidSignature-*": "Fuzzer mode ignores invalid signatures.",
+
     "BadFinished-*": "Fuzzer mode ignores Finished checks.",
     "FalseStart-BadFinished": "Fuzzer mode ignores Finished checks.",
     "TrailingMessageData-*Finished*": "Fuzzer mode ignores Finished checks.",
 
     "DTLSIgnoreBadPackets*": "Fuzzer mode has no bad packets.",
     "TLSFatalBadPackets": "Fuzzer mode has no bad packets.",
+    "*-BadRecord": "Fuzzer mode has no bad packets.",
 
     "BadRSAClientKeyExchange*": "Fuzzer mode does not notice a bad premaster secret.",
     "CECPQ1-*-BadNewhopePart": "Fuzzer mode does not notice a bad premaster secret.",
@@ -19,10 +19,20 @@
     "UnknownUnencryptedExtension-Client-TLS13": "Fuzzer mode will not read the peer's alert as a MAC error",
     "WrongMessageType-TLS13-ServerHello": "Fuzzer mode will not read the peer's alert as a MAC error",
 
+    "BadECDSA-*": "Fuzzer mode always accepts a signature.",
+    "*-InvalidSignature-*": "Fuzzer mode always accepts a signature.",
     "*Auth-Verify-RSA-PKCS1-*-TLS13": "Fuzzer mode always accepts a signature.",
     "*Auth-Verify-ECDSA-SHA1-TLS13": "Fuzzer mode always accepts a signature.",
     "Verify-*Auth-SignatureType*": "Fuzzer mode always accepts a signature.",
     "ECDSACurveMismatch-Verify-TLS13": "Fuzzer mode always accepts a signature.",
-    "InvalidChannelIDSignature": "Fuzzer mode always accepts a signature."
+    "InvalidChannelIDSignature-*": "Fuzzer mode always accepts a signature.",
+
+    "Resume-Server-DeclineBadCipher*": "Fuzzer mode does not encrypt tickets.",
+    "Resume-Server-DeclineCrossVersion*": "Fuzzer mode does not encrypt tickets.",
+    "TicketCallback-SingleCall-*": "Fuzzer mode does not encrypt tickets.",
+    "CorruptTicket-*": "Fuzzer mode does not encrypt tickets.",
+    "ShimTicketRewritable": "Fuzzer mode does not encrypt tickets.",
+
+    "Resume-Server-*Binder*": "Fuzzer mode does not check binders."
   }
 }
diff --git a/src/ssl/test/runner/handshake_client.go b/src/ssl/test/runner/handshake_client.go
index ae3228a..d074778 100644
--- a/src/ssl/test/runner/handshake_client.go
+++ b/src/ssl/test/runner/handshake_client.go
@@ -64,21 +64,23 @@
 		vers:                    versionToWire(maxVersion, c.isDTLS),
 		compressionMethods:      []uint8{compressionNone},
 		random:                  make([]byte, 32),
-		ocspStapling:            true,
-		sctListSupported:        true,
+		ocspStapling:            !c.config.Bugs.NoOCSPStapling,
+		sctListSupported:        !c.config.Bugs.NoSignedCertificateTimestamps,
 		serverName:              c.config.ServerName,
 		supportedCurves:         c.config.curvePreferences(),
+		pskKEModes:              []byte{pskDHEKEMode},
 		supportedPoints:         []uint8{pointFormatUncompressed},
 		nextProtoNeg:            len(c.config.NextProtos) > 0,
 		secureRenegotiation:     []byte{},
 		alpnProtocols:           c.config.NextProtos,
 		duplicateExtension:      c.config.Bugs.DuplicateExtension,
 		channelIDSupported:      c.config.ChannelID != nil,
-		npnLast:                 c.config.Bugs.SwapNPNAndALPN,
+		npnAfterAlpn:            c.config.Bugs.SwapNPNAndALPN,
 		extendedMasterSecret:    maxVersion >= VersionTLS10,
 		srtpProtectionProfiles:  c.config.SRTPProtectionProfiles,
 		srtpMasterKeyIdentifier: c.config.Bugs.SRTPMasterKeyIdentifer,
 		customExtension:         c.config.Bugs.CustomExtension,
+		pskBinderFirst:          c.config.Bugs.PSKBinderFirst,
 	}
 
 	disableEMS := c.config.Bugs.NoExtendedMasterSecret
@@ -94,6 +96,10 @@
 		hello.supportedCurves = nil
 	}
 
+	if len(c.config.Bugs.SendPSKKeyExchangeModes) != 0 {
+		hello.pskKEModes = c.config.Bugs.SendPSKKeyExchangeModes
+	}
+
 	if c.config.Bugs.SendCompressionMethods != nil {
 		hello.compressionMethods = c.config.Bugs.SendCompressionMethods
 	}
@@ -217,11 +223,17 @@
 			// Check that the ciphersuite/version used for the
 			// previous session are still valid.
 			cipherSuiteOk := false
-			for _, id := range hello.cipherSuites {
-				if id == candidateSession.cipherSuite {
-					cipherSuiteOk = true
-					break
+			if candidateSession.vers <= VersionTLS12 {
+				for _, id := range hello.cipherSuites {
+					if id == candidateSession.cipherSuite {
+						cipherSuiteOk = true
+						break
+					}
 				}
+			} else {
+				// TLS 1.3 allows the cipher to change on
+				// resumption.
+				cipherSuiteOk = true
 			}
 
 			versOk := candidateSession.vers >= minVersion &&
@@ -232,34 +244,37 @@
 		}
 	}
 
+	var pskCipherSuite *cipherSuite
 	if session != nil && c.config.time().Before(session.ticketExpiration) {
 		ticket := session.sessionTicket
-		if c.config.Bugs.CorruptTicket && len(ticket) > 0 {
+		if c.config.Bugs.FilterTicket != nil && len(ticket) > 0 {
+			// Copy the ticket so FilterTicket may act in-place.
 			ticket = make([]byte, len(session.sessionTicket))
 			copy(ticket, session.sessionTicket)
-			offset := 40
-			if offset >= len(ticket) {
-				offset = len(ticket) - 1
+
+			ticket, err = c.config.Bugs.FilterTicket(ticket)
+			if err != nil {
+				return err
 			}
-			ticket[offset] ^= 0x40
 		}
 
 		if session.vers >= VersionTLS13 || c.config.Bugs.SendBothTickets {
+			pskCipherSuite = cipherSuiteFromID(session.cipherSuite)
+			if pskCipherSuite == nil {
+				return errors.New("tls: client session cache has invalid cipher suite")
+			}
 			// TODO(nharper): Support sending more
 			// than one PSK identity.
+			ticketAge := uint32(c.config.time().Sub(session.ticketCreationTime) / time.Millisecond)
 			psk := pskIdentity{
-				keModes:   []byte{pskDHEKEMode},
-				authModes: []byte{pskAuthMode},
-				ticket:    ticket,
+				ticket:              ticket,
+				obfuscatedTicketAge: session.ticketAgeAdd + ticketAge,
 			}
-			if len(c.config.Bugs.SendPSKKeyExchangeModes) != 0 {
-				psk.keModes = c.config.Bugs.SendPSKKeyExchangeModes
-			}
-			if len(c.config.Bugs.SendPSKAuthModes) != 0 {
-				psk.authModes = c.config.Bugs.SendPSKAuthModes
-			}
-
 			hello.pskIdentities = []pskIdentity{psk}
+
+			if c.config.Bugs.ExtraPSKIdentity {
+				hello.pskIdentities = append(hello.pskIdentities, psk)
+			}
 		}
 
 		if session.vers < VersionTLS13 || c.config.Bugs.SendBothTickets {
@@ -300,6 +315,10 @@
 		hello.vers = c.config.Bugs.SendClientVersion
 	}
 
+	if c.config.Bugs.SendCipherSuites != nil {
+		hello.cipherSuites = c.config.Bugs.SendCipherSuites
+	}
+
 	var helloBytes []byte
 	if c.config.Bugs.SendV2ClientHello {
 		// Test that the peer left-pads random.
@@ -314,7 +333,11 @@
 		helloBytes = v2Hello.marshal()
 		c.writeV2Record(helloBytes)
 	} else {
+		if len(hello.pskIdentities) > 0 {
+			generatePSKBinders(hello, pskCipherSuite, session.masterSecret, []byte{}, c.config)
+		}
 		helloBytes = hello.marshal()
+
 		if c.config.Bugs.PartialClientFinishedWithClientHello {
 			// Include one byte of Finished. We can compute it
 			// without completing the handshake. This assumes we
@@ -341,7 +364,7 @@
 	if c.isDTLS {
 		helloVerifyRequest, ok := msg.(*helloVerifyRequestMsg)
 		if ok {
-			if helloVerifyRequest.vers != VersionTLS10 {
+			if helloVerifyRequest.vers != versionToWire(VersionTLS10, c.isDTLS) {
 				// Per RFC 6347, the version field in
 				// HelloVerifyRequest SHOULD be always DTLS
 				// 1.0. Enforce this for testing purposes.
@@ -419,10 +442,10 @@
 				return err
 			}
 			keyShares[group] = curve
-			hello.keyShares = append(hello.keyShares, keyShareEntry{
+			hello.keyShares = []keyShareEntry{{
 				group:       group,
 				keyExchange: publicKey,
-			})
+			}}
 		}
 
 		if c.config.Bugs.SecondClientHelloMissingKeyShare {
@@ -430,9 +453,11 @@
 		}
 
 		hello.hasEarlyData = false
-		hello.earlyDataContext = nil
 		hello.raw = nil
 
+		if len(hello.pskIdentities) > 0 {
+			generatePSKBinders(hello, pskCipherSuite, session.masterSecret, append(helloBytes, helloRetryRequest.marshal()...), c.config)
+		}
 		secondHelloBytes = hello.marshal()
 		c.writeRecord(recordTypeHandshake, secondHelloBytes)
 		c.flushHandshake()
@@ -599,35 +624,29 @@
 	// 0-RTT is implemented.
 	var psk []byte
 	if hs.serverHello.hasPSKIdentity {
-		if hs.serverHello.useCertAuth || !hs.serverHello.hasKeyShare {
-			c.sendAlert(alertUnsupportedExtension)
-			return errors.New("tls: server omitted KeyShare or included SignatureAlgorithms on resumption.")
-		}
-
 		// We send at most one PSK identity.
 		if hs.session == nil || hs.serverHello.pskIdentity != 0 {
 			c.sendAlert(alertUnknownPSKIdentity)
 			return errors.New("tls: server sent unknown PSK identity")
 		}
-		if hs.session.cipherSuite != hs.suite.id {
+		sessionCipher := cipherSuiteFromID(hs.session.cipherSuite)
+		if sessionCipher == nil || sessionCipher.hash() != hs.suite.hash() {
 			c.sendAlert(alertHandshakeFailure)
-			return errors.New("tls: server sent invalid cipher suite")
+			return errors.New("tls: server resumed an invalid session for the cipher suite")
 		}
-		psk = deriveResumptionPSK(hs.suite, hs.session.masterSecret)
-		hs.finishedHash.setResumptionContext(deriveResumptionContext(hs.suite, hs.session.masterSecret))
+		psk = hs.session.masterSecret
 		c.didResume = true
 	} else {
-		if !hs.serverHello.useCertAuth || !hs.serverHello.hasKeyShare {
-			c.sendAlert(alertUnsupportedExtension)
-			return errors.New("tls: server omitted KeyShare and SignatureAlgorithms on non-resumption.")
-		}
-
 		psk = zeroSecret
-		hs.finishedHash.setResumptionContext(zeroSecret)
 	}
 
 	earlySecret := hs.finishedHash.extractKey(zeroSecret, psk)
 
+	if !hs.serverHello.hasKeyShare {
+		c.sendAlert(alertUnsupportedExtension)
+		return errors.New("tls: server omitted KeyShare on resumption.")
+	}
+
 	// Resolve ECDHE and compute the handshake secret.
 	var ecdheSecret []byte
 	if !c.config.Bugs.MissingKeyShare && !c.config.Bugs.SecondClientHelloMissingKeyShare {
@@ -652,9 +671,9 @@
 
 	// Switch to handshake traffic keys.
 	clientHandshakeTrafficSecret := hs.finishedHash.deriveSecret(handshakeSecret, clientHandshakeTrafficLabel)
-	c.out.useTrafficSecret(c.vers, hs.suite, clientHandshakeTrafficSecret, handshakePhase, clientWrite)
+	c.out.useTrafficSecret(c.vers, hs.suite, clientHandshakeTrafficSecret, clientWrite)
 	serverHandshakeTrafficSecret := hs.finishedHash.deriveSecret(handshakeSecret, serverHandshakeTrafficLabel)
-	c.in.useTrafficSecret(c.vers, hs.suite, serverHandshakeTrafficSecret, handshakePhase, serverWrite)
+	c.in.useTrafficSecret(c.vers, hs.suite, serverHandshakeTrafficSecret, serverWrite)
 
 	msg, err := c.readHandshake()
 	if err != nil {
@@ -675,24 +694,12 @@
 
 	var chainToSend *Certificate
 	var certReq *certificateRequestMsg
-	if !hs.serverHello.useCertAuth {
-		if encryptedExtensions.extensions.ocspResponse != nil {
-			c.sendAlert(alertUnsupportedExtension)
-			return errors.New("tls: server sent OCSP response without a certificate")
-		}
-		if encryptedExtensions.extensions.sctList != nil {
-			c.sendAlert(alertUnsupportedExtension)
-			return errors.New("tls: server sent SCT list without a certificate")
-		}
-
+	if c.didResume {
 		// Copy over authentication from the session.
 		c.peerCertificates = hs.session.serverCertificates
 		c.sctList = hs.session.sctList
 		c.ocspResponse = hs.session.ocspResponse
 	} else {
-		c.ocspResponse = encryptedExtensions.extensions.ocspResponse
-		c.sctList = encryptedExtensions.extensions.sctList
-
 		msg, err := c.readHandshake()
 		if err != nil {
 			return err
@@ -729,10 +736,28 @@
 		}
 		hs.writeServerHash(certMsg.marshal())
 
+		// Check for unsolicited extensions.
+		for i, cert := range certMsg.certificates {
+			if c.config.Bugs.NoOCSPStapling && cert.ocspResponse != nil {
+				c.sendAlert(alertUnsupportedExtension)
+				return errors.New("tls: unexpected OCSP response in the server certificate")
+			}
+			if c.config.Bugs.NoSignedCertificateTimestamps && cert.sctList != nil {
+				c.sendAlert(alertUnsupportedExtension)
+				return errors.New("tls: unexpected SCT list in the server certificate")
+			}
+			if i > 0 && c.config.Bugs.ExpectNoExtensionsOnIntermediate && (cert.ocspResponse != nil || cert.sctList != nil) {
+				c.sendAlert(alertUnsupportedExtension)
+				return errors.New("tls: unexpected extensions in the server certificate")
+			}
+		}
+
 		if err := hs.verifyCertificates(certMsg); err != nil {
 			return err
 		}
 		leaf := c.peerCertificates[0]
+		c.ocspResponse = certMsg.certificates[0].ocspResponse
+		c.sctList = certMsg.certificates[0].sctList
 
 		msg, err = c.readHandshake()
 		if err != nil {
@@ -785,7 +810,12 @@
 			requestContext:    certReq.requestContext,
 		}
 		if chainToSend != nil {
-			certMsg.certificates = chainToSend.Certificate
+			for _, certData := range chainToSend.Certificate {
+				certMsg.certificates = append(certMsg.certificates, certificateEntry{
+					data:           certData,
+					extraExtension: c.config.Bugs.SendExtensionOnCertificate,
+				})
+			}
 		}
 		hs.writeClientHash(certMsg.marshal())
 		c.writeRecord(recordTypeHandshake, certMsg.marshal())
@@ -820,6 +850,17 @@
 		}
 	}
 
+	if encryptedExtensions.extensions.channelIDRequested {
+		channelIDHash := crypto.SHA256.New()
+		channelIDHash.Write(hs.finishedHash.certificateVerifyInput(channelIDContextTLS13))
+		channelIDMsgBytes, err := hs.writeChannelIDMessage(channelIDHash.Sum(nil))
+		if err != nil {
+			return err
+		}
+		hs.writeClientHash(channelIDMsgBytes)
+		c.writeRecord(recordTypeHandshake, channelIDMsgBytes)
+	}
+
 	// Send a client Finished message.
 	finished := new(finishedMsg)
 	finished.verifyData = hs.finishedHash.clientSum(clientHandshakeTrafficSecret)
@@ -839,8 +880,8 @@
 	c.flushHandshake()
 
 	// Switch to application data keys.
-	c.out.useTrafficSecret(c.vers, hs.suite, clientTrafficSecret, applicationPhase, clientWrite)
-	c.in.useTrafficSecret(c.vers, hs.suite, serverTrafficSecret, applicationPhase, serverWrite)
+	c.out.useTrafficSecret(c.vers, hs.suite, clientTrafficSecret, clientWrite)
+	c.in.useTrafficSecret(c.vers, hs.suite, serverTrafficSecret, serverWrite)
 
 	c.exporterSecret = hs.finishedHash.deriveSecret(masterSecret, exporterLabel)
 	c.resumptionSecret = hs.finishedHash.deriveSecret(masterSecret, resumptionLabel)
@@ -953,7 +994,11 @@
 		} else if !c.config.Bugs.SkipClientCertificate {
 			certMsg := new(certificateMsg)
 			if chainToSend != nil {
-				certMsg.certificates = chainToSend.Certificate
+				for _, certData := range chainToSend.Certificate {
+					certMsg.certificates = append(certMsg.certificates, certificateEntry{
+						data: certData,
+					})
+				}
 			}
 			hs.writeClientHash(certMsg.marshal())
 			c.writeRecord(recordTypeHandshake, certMsg.marshal())
@@ -1041,8 +1086,8 @@
 	}
 
 	certs := make([]*x509.Certificate, len(certMsg.certificates))
-	for i, asn1Data := range certMsg.certificates {
-		cert, err := x509.ParseCertificate(asn1Data)
+	for i, certEntry := range certMsg.certificates {
+		cert, err := x509.ParseCertificate(certEntry.data)
 		if err != nil {
 			c.sendAlert(alertBadCertificate)
 			return errors.New("tls: failed to parse certificate from server: " + err.Error())
@@ -1169,11 +1214,6 @@
 		return errors.New("server advertised unrequested Channel ID extension")
 	}
 
-	if serverExtensions.channelIDRequested && c.vers >= VersionTLS13 {
-		c.sendAlert(alertHandshakeFailure)
-		return errors.New("server advertised Channel ID over TLS 1.3")
-	}
-
 	if serverExtensions.extendedMasterSecret && c.vers >= VersionTLS13 {
 		return errors.New("tls: server advertised extended master secret over TLS 1.3")
 	}
@@ -1182,6 +1222,22 @@
 		return errors.New("tls: server advertised ticket extension over TLS 1.3")
 	}
 
+	if serverExtensions.ocspStapling && c.vers >= VersionTLS13 {
+		return errors.New("tls: server advertised OCSP in ServerHello over TLS 1.3")
+	}
+
+	if serverExtensions.ocspStapling && c.config.Bugs.NoOCSPStapling {
+		return errors.New("tls: server advertised unrequested OCSP extension")
+	}
+
+	if len(serverExtensions.sctList) > 0 && c.vers >= VersionTLS13 {
+		return errors.New("tls: server advertised SCTs in ServerHello over TLS 1.3")
+	}
+
+	if len(serverExtensions.sctList) > 0 && c.config.Bugs.NoSignedCertificateTimestamps {
+		return errors.New("tls: server advertised unrequested SCTs")
+	}
+
 	if serverExtensions.srtpProtectionProfile != 0 {
 		if serverExtensions.srtpMasterKeyIdentifier != "" {
 			return errors.New("tls: server selected SRTP MKI value")
@@ -1287,7 +1343,7 @@
 		vers:               c.vers,
 		cipherSuite:        hs.suite.id,
 		masterSecret:       hs.masterSecret,
-		handshakeHash:      hs.finishedHash.server.Sum(nil),
+		handshakeHash:      hs.finishedHash.Sum(),
 		serverCertificates: c.peerCertificates,
 		sctList:            c.sctList,
 		ocspResponse:       c.ocspResponse,
@@ -1346,31 +1402,14 @@
 	}
 
 	if hs.serverHello.extensions.channelIDRequested {
-		channelIDMsg := new(channelIDMsg)
-		if c.config.ChannelID.Curve != elliptic.P256() {
-			return fmt.Errorf("tls: Channel ID is not on P-256.")
-		}
 		var resumeHash []byte
 		if isResume {
 			resumeHash = hs.session.handshakeHash
 		}
-		r, s, err := ecdsa.Sign(c.config.rand(), c.config.ChannelID, hs.finishedHash.hashForChannelID(resumeHash))
+		channelIDMsgBytes, err := hs.writeChannelIDMessage(hs.finishedHash.hashForChannelID(resumeHash))
 		if err != nil {
 			return err
 		}
-		channelID := make([]byte, 128)
-		writeIntPadded(channelID[0:32], c.config.ChannelID.X)
-		writeIntPadded(channelID[32:64], c.config.ChannelID.Y)
-		writeIntPadded(channelID[64:96], r)
-		writeIntPadded(channelID[96:128], s)
-		if c.config.Bugs.InvalidChannelIDSignature {
-			channelID[64] ^= 1
-		}
-		channelIDMsg.channelID = channelID
-
-		c.channelID = &c.config.ChannelID.PublicKey
-
-		channelIDMsgBytes := channelIDMsg.marshal()
 		hs.writeHash(channelIDMsgBytes, seqno)
 		seqno++
 		postCCSMsgs = append(postCCSMsgs, channelIDMsgBytes)
@@ -1431,6 +1470,31 @@
 	return nil
 }
 
+func (hs *clientHandshakeState) writeChannelIDMessage(channelIDHash []byte) ([]byte, error) {
+	c := hs.c
+	channelIDMsg := new(channelIDMsg)
+	if c.config.ChannelID.Curve != elliptic.P256() {
+		return nil, fmt.Errorf("tls: Channel ID is not on P-256.")
+	}
+	r, s, err := ecdsa.Sign(c.config.rand(), c.config.ChannelID, channelIDHash)
+	if err != nil {
+		return nil, err
+	}
+	channelID := make([]byte, 128)
+	writeIntPadded(channelID[0:32], c.config.ChannelID.X)
+	writeIntPadded(channelID[32:64], c.config.ChannelID.Y)
+	writeIntPadded(channelID[64:96], r)
+	writeIntPadded(channelID[96:128], s)
+	if c.config.Bugs.InvalidChannelIDSignature {
+		channelID[64] ^= 1
+	}
+	channelIDMsg.channelID = channelID
+
+	c.channelID = &c.config.ChannelID.PublicKey
+
+	return channelIDMsg.marshal(), nil
+}
+
 func (hs *clientHandshakeState) writeClientHash(msg []byte) {
 	// writeClientHash is called before writeRecord.
 	hs.writeHash(msg, hs.c.sendHandshakeSeq)
@@ -1573,3 +1637,39 @@
 	xb := x.Bytes()
 	copy(b[len(b)-len(xb):], xb)
 }
+
+func generatePSKBinders(hello *clientHelloMsg, pskCipherSuite *cipherSuite, psk, transcript []byte, config *Config) {
+	if config.Bugs.SendNoPSKBinder {
+		return
+	}
+
+	binderLen := pskCipherSuite.hash().Size()
+	if config.Bugs.SendShortPSKBinder {
+		binderLen--
+	}
+
+	// Fill hello.pskBinders with appropriate length arrays of zeros so the
+	// length prefixes are correct when computing the binder over the truncated
+	// ClientHello message.
+	hello.pskBinders = make([][]byte, len(hello.pskIdentities))
+	for i := range hello.pskIdentities {
+		hello.pskBinders[i] = make([]byte, binderLen)
+	}
+
+	helloBytes := hello.marshal()
+	binderSize := len(hello.pskBinders)*(binderLen+1) + 2
+	truncatedHello := helloBytes[:len(helloBytes)-binderSize]
+	binder := computePSKBinder(psk, resumptionPSKBinderLabel, pskCipherSuite, transcript, truncatedHello)
+	if config.Bugs.SendShortPSKBinder {
+		binder = binder[:binderLen]
+	}
+	if config.Bugs.SendInvalidPSKBinder {
+		binder[0] ^= 1
+	}
+
+	for i := range hello.pskBinders {
+		hello.pskBinders[i] = binder
+	}
+
+	hello.raw = nil
+}
diff --git a/src/ssl/test/runner/handshake_messages.go b/src/ssl/test/runner/handshake_messages.go
index 285587e..8a338f0 100644
--- a/src/ssl/test/runner/handshake_messages.go
+++ b/src/ssl/test/runner/handshake_messages.go
@@ -125,9 +125,8 @@
 }
 
 type pskIdentity struct {
-	keModes   []byte
-	authModes []byte
-	ticket    []uint8
+	ticket              []uint8
+	obfuscatedTicketAge uint32
 }
 
 type clientHelloMsg struct {
@@ -148,8 +147,9 @@
 	keyShares               []keyShareEntry
 	trailingKeyShareData    bool
 	pskIdentities           []pskIdentity
+	pskKEModes              []byte
+	pskBinders              [][]uint8
 	hasEarlyData            bool
-	earlyDataContext        []byte
 	tls13Cookie             []byte
 	ticketSupported         bool
 	sessionTicket           []uint8
@@ -159,13 +159,14 @@
 	alpnProtocols           []string
 	duplicateExtension      bool
 	channelIDSupported      bool
-	npnLast                 bool
+	npnAfterAlpn            bool
 	extendedMasterSecret    bool
 	srtpProtectionProfiles  []uint16
 	srtpMasterKeyIdentifier string
 	sctListSupported        bool
 	customExtension         string
 	hasGREASEExtension      bool
+	pskBinderFirst          bool
 }
 
 func (m *clientHelloMsg) equal(i interface{}) bool {
@@ -191,8 +192,9 @@
 		eqKeyShareEntryLists(m.keyShares, m1.keyShares) &&
 		m.trailingKeyShareData == m1.trailingKeyShareData &&
 		eqPSKIdentityLists(m.pskIdentities, m1.pskIdentities) &&
+		bytes.Equal(m.pskKEModes, m1.pskKEModes) &&
+		eqByteSlices(m.pskBinders, m1.pskBinders) &&
 		m.hasEarlyData == m1.hasEarlyData &&
-		bytes.Equal(m.earlyDataContext, m1.earlyDataContext) &&
 		bytes.Equal(m.tls13Cookie, m1.tls13Cookie) &&
 		m.ticketSupported == m1.ticketSupported &&
 		bytes.Equal(m.sessionTicket, m1.sessionTicket) &&
@@ -203,13 +205,14 @@
 		eqStrings(m.alpnProtocols, m1.alpnProtocols) &&
 		m.duplicateExtension == m1.duplicateExtension &&
 		m.channelIDSupported == m1.channelIDSupported &&
-		m.npnLast == m1.npnLast &&
+		m.npnAfterAlpn == m1.npnAfterAlpn &&
 		m.extendedMasterSecret == m1.extendedMasterSecret &&
 		eqUint16s(m.srtpProtectionProfiles, m1.srtpProtectionProfiles) &&
 		m.srtpMasterKeyIdentifier == m1.srtpMasterKeyIdentifier &&
 		m.sctListSupported == m1.sctListSupported &&
 		m.customExtension == m1.customExtension &&
-		m.hasGREASEExtension == m1.hasGREASEExtension
+		m.hasGREASEExtension == m1.hasGREASEExtension &&
+		m.pskBinderFirst == m1.pskBinderFirst
 }
 
 func (m *clientHelloMsg) marshal() []byte {
@@ -236,12 +239,26 @@
 	compressionMethods.addBytes(m.compressionMethods)
 
 	extensions := hello.addU16LengthPrefixed()
+	if len(m.pskIdentities) > 0 && m.pskBinderFirst {
+		extensions.addU16(extensionPreSharedKey)
+		pskExtension := extensions.addU16LengthPrefixed()
+
+		pskIdentities := pskExtension.addU16LengthPrefixed()
+		for _, psk := range m.pskIdentities {
+			pskIdentities.addU16LengthPrefixed().addBytes(psk.ticket)
+			pskIdentities.addU32(psk.obfuscatedTicketAge)
+		}
+		pskBinders := pskExtension.addU16LengthPrefixed()
+		for _, binder := range m.pskBinders {
+			pskBinders.addU8LengthPrefixed().addBytes(binder)
+		}
+	}
 	if m.duplicateExtension {
 		// Add a duplicate bogus extension at the beginning and end.
 		extensions.addU16(0xffff)
 		extensions.addU16(0) // 0-length for empty extension
 	}
-	if m.nextProtoNeg && !m.npnLast {
+	if m.nextProtoNeg && !m.npnAfterAlpn {
 		extensions.addU16(extensionNextProtoNeg)
 		extensions.addU16(0) // The length is always 0
 	}
@@ -316,23 +333,14 @@
 			keyShares.addU8(0)
 		}
 	}
-	if len(m.pskIdentities) > 0 {
-		extensions.addU16(extensionPreSharedKey)
-		pskExtension := extensions.addU16LengthPrefixed()
-
-		pskIdentities := pskExtension.addU16LengthPrefixed()
-		for _, psk := range m.pskIdentities {
-			pskIdentities.addU8LengthPrefixed().addBytes(psk.keModes)
-			pskIdentities.addU8LengthPrefixed().addBytes(psk.authModes)
-			pskIdentities.addU16LengthPrefixed().addBytes(psk.ticket)
-		}
+	if len(m.pskKEModes) > 0 {
+		extensions.addU16(extensionPSKKeyExchangeModes)
+		pskModesExtension := extensions.addU16LengthPrefixed()
+		pskModesExtension.addU8LengthPrefixed().addBytes(m.pskKEModes)
 	}
 	if m.hasEarlyData {
 		extensions.addU16(extensionEarlyData)
-		earlyDataIndication := extensions.addU16LengthPrefixed()
-
-		context := earlyDataIndication.addU8LengthPrefixed()
-		context.addBytes(m.earlyDataContext)
+		extensions.addU16(0) // The length is zero.
 	}
 	if len(m.tls13Cookie) > 0 {
 		extensions.addU16(extensionCookie)
@@ -383,7 +391,7 @@
 		extensions.addU16(extensionChannelID)
 		extensions.addU16(0) // Length is always 0
 	}
-	if m.nextProtoNeg && m.npnLast {
+	if m.nextProtoNeg && m.npnAfterAlpn {
 		extensions.addU16(extensionNextProtoNeg)
 		extensions.addU16(0) // Length is always 0
 	}
@@ -422,6 +430,21 @@
 		customExt := extensions.addU16LengthPrefixed()
 		customExt.addBytes([]byte(m.customExtension))
 	}
+	// The PSK extension must be last (draft-ietf-tls-tls13-18 section 4.2.6).
+	if len(m.pskIdentities) > 0 && !m.pskBinderFirst {
+		extensions.addU16(extensionPreSharedKey)
+		pskExtension := extensions.addU16LengthPrefixed()
+
+		pskIdentities := pskExtension.addU16LengthPrefixed()
+		for _, psk := range m.pskIdentities {
+			pskIdentities.addU16LengthPrefixed().addBytes(psk.ticket)
+			pskIdentities.addU32(psk.obfuscatedTicketAge)
+		}
+		pskBinders := pskExtension.addU16LengthPrefixed()
+		for _, binder := range m.pskBinders {
+			pskBinders.addU8LengthPrefixed().addBytes(binder)
+		}
+	}
 
 	if extensions.len() == 0 {
 		hello.discardChild()
@@ -490,7 +513,6 @@
 	m.keyShares = nil
 	m.pskIdentities = nil
 	m.hasEarlyData = false
-	m.earlyDataContext = nil
 	m.ticketSupported = false
 	m.sessionTicket = nil
 	m.signatureAlgorithms = nil
@@ -614,63 +636,75 @@
 				m.keyShares = append(m.keyShares, entry)
 			}
 		case extensionPreSharedKey:
-			// draft-ietf-tls-tls13 section 6.3.2.4
+			// draft-ietf-tls-tls13-18 section 4.2.6
 			if length < 2 {
 				return false
 			}
 			l := int(data[0])<<8 | int(data[1])
-			if l != length-2 {
-				return false
-			}
-			d := data[2:length]
+			d := data[2 : l+2]
+			// Parse PSK identities.
 			for len(d) > 0 {
-				var psk pskIdentity
-
-				if len(d) < 1 {
-					return false
-				}
-				keModesLen := int(d[0])
-				d = d[1:]
-				if len(d) < keModesLen {
-					return false
-				}
-				psk.keModes = d[:keModesLen]
-				d = d[keModesLen:]
-
-				if len(d) < 1 {
-					return false
-				}
-				authModesLen := int(d[0])
-				d = d[1:]
-				if len(d) < authModesLen {
-					return false
-				}
-				psk.authModes = d[:authModesLen]
-				d = d[authModesLen:]
 				if len(d) < 2 {
 					return false
 				}
 				pskLen := int(d[0])<<8 | int(d[1])
 				d = d[2:]
 
-				if len(d) < pskLen {
+				if len(d) < pskLen+4 {
 					return false
 				}
-				psk.ticket = d[:pskLen]
+				ticket := d[:pskLen]
+				obfuscatedTicketAge := uint32(d[pskLen])<<24 | uint32(d[pskLen+1])<<16 | uint32(d[pskLen+2])<<8 | uint32(d[pskLen+3])
+				psk := pskIdentity{
+					ticket:              ticket,
+					obfuscatedTicketAge: obfuscatedTicketAge,
+				}
 				m.pskIdentities = append(m.pskIdentities, psk)
-				d = d[pskLen:]
+				d = d[pskLen+4:]
 			}
-		case extensionEarlyData:
-			// draft-ietf-tls-tls13 section 6.3.2.5
+			d = data[l+2:]
+			if len(d) < 2 {
+				return false
+			}
+			l = int(d[0])<<8 | int(d[1])
+			d = d[2:]
+			if l != len(d) {
+				return false
+			}
+			// Parse PSK binders.
+			for len(d) > 0 {
+				if len(d) < 1 {
+					return false
+				}
+				binderLen := int(d[0])
+				d = d[1:]
+				if binderLen > len(d) {
+					return false
+				}
+				m.pskBinders = append(m.pskBinders, d[:binderLen])
+				d = d[binderLen:]
+			}
+
+			// There must be the same number of identities as binders.
+			if len(m.pskIdentities) != len(m.pskBinders) {
+				return false
+			}
+		case extensionPSKKeyExchangeModes:
+			// draft-ietf-tls-tls13-18 section 4.2.7
 			if length < 1 {
 				return false
 			}
 			l := int(data[0])
-			if length != l+1 {
+			if l != length-1 {
+				return false
+			}
+			m.pskKEModes = data[1:length]
+		case extensionEarlyData:
+			// draft-ietf-tls-tls13 section 6.3.2.5
+			if length != 0 {
 				return false
 			}
 			m.hasEarlyData = true
-			m.earlyDataContext = data[1:length]
 		case extensionCookie:
 			if length < 2 {
 				return false
@@ -793,7 +827,6 @@
 	keyShare            keyShareEntry
 	hasPSKIdentity      bool
 	pskIdentity         uint16
-	useCertAuth         bool
 	earlyDataIndication bool
 	compressionMethod   uint8
 	customExtension     string
@@ -848,10 +881,6 @@
 			extensions.addU16(2) // Length
 			extensions.addU16(m.pskIdentity)
 		}
-		if m.useCertAuth {
-			extensions.addU16(extensionSignatureAlgorithms)
-			extensions.addU16(0) // Length
-		}
 		if m.earlyDataIndication {
 			extensions.addU16(extensionEarlyData)
 			extensions.addU16(0) // Length
@@ -870,7 +899,7 @@
 			protocolName.addBytes([]byte(m.unencryptedALPN))
 		}
 	} else {
-		m.extensions.marshal(extensions, vers)
+		m.extensions.marshal(extensions)
 		if extensions.len() == 0 {
 			hello.discardChild()
 		}
@@ -962,11 +991,6 @@
 				}
 				m.pskIdentity = uint16(d[0])<<8 | uint16(d[1])
 				m.hasPSKIdentity = true
-			case extensionSignatureAlgorithms:
-				if len(d) != 0 {
-					return false
-				}
-				m.useCertAuth = true
 			case extensionEarlyData:
 				if len(d) != 0 {
 					return false
@@ -1001,7 +1025,7 @@
 	encryptedExtensions := encryptedExtensionsMsg.addU24LengthPrefixed()
 	if !m.empty {
 		extensions := encryptedExtensions.addU16LengthPrefixed()
-		m.extensions.marshal(extensions, VersionTLS13)
+		m.extensions.marshal(extensions)
 	}
 
 	m.raw = encryptedExtensionsMsg.finish()
@@ -1033,7 +1057,6 @@
 	nextProtoNeg            bool
 	nextProtos              []string
 	ocspStapling            bool
-	ocspResponse            []byte
 	ticketSupported         bool
 	secureRenegotiation     []byte
 	alpnProtocol            string
@@ -1045,18 +1068,18 @@
 	srtpMasterKeyIdentifier string
 	sctList                 []byte
 	customExtension         string
-	npnLast                 bool
+	npnAfterAlpn            bool
 	hasKeyShare             bool
 	keyShare                keyShareEntry
 }
 
-func (m *serverExtensions) marshal(extensions *byteBuilder, version uint16) {
+func (m *serverExtensions) marshal(extensions *byteBuilder) {
 	if m.duplicateExtension {
 		// Add a duplicate bogus extension at the beginning and end.
 		extensions.addU16(0xffff)
 		extensions.addU16(0) // length = 0 for empty extension
 	}
-	if m.nextProtoNeg && !m.npnLast {
+	if m.nextProtoNeg && !m.npnAfterAlpn {
 		extensions.addU16(extensionNextProtoNeg)
 		extension := extensions.addU16LengthPrefixed()
 
@@ -1068,19 +1091,9 @@
 			npn.addBytes([]byte(v))
 		}
 	}
-	if version >= VersionTLS13 {
-		if m.ocspResponse != nil {
-			extensions.addU16(extensionStatusRequest)
-			body := extensions.addU16LengthPrefixed()
-			body.addU8(statusTypeOCSP)
-			response := body.addU24LengthPrefixed()
-			response.addBytes(m.ocspResponse)
-		}
-	} else {
-		if m.ocspStapling {
-			extensions.addU16(extensionStatusRequest)
-			extensions.addU16(0)
-		}
+	if m.ocspStapling {
+		extensions.addU16(extensionStatusRequest)
+		extensions.addU16(0)
 	}
 	if m.ticketSupported {
 		extensions.addU16(extensionSessionTicket)
@@ -1133,7 +1146,7 @@
 		customExt := extensions.addU16LengthPrefixed()
 		customExt.addBytes([]byte(m.customExtension))
 	}
-	if m.nextProtoNeg && m.npnLast {
+	if m.nextProtoNeg && m.npnAfterAlpn {
 		extensions.addU16(extensionNextProtoNeg)
 		extension := extensions.addU16LengthPrefixed()
 
@@ -1183,25 +1196,10 @@
 				d = d[l:]
 			}
 		case extensionStatusRequest:
-			if version >= VersionTLS13 {
-				if length < 4 {
-					return false
-				}
-				d := data[:length]
-				if d[0] != statusTypeOCSP {
-					return false
-				}
-				respLen := int(d[1])<<16 | int(d[2])<<8 | int(d[3])
-				if respLen+4 != len(d) || respLen == 0 {
-					return false
-				}
-				m.ocspResponse = d[4:]
-			} else {
-				if length > 0 {
-					return false
-				}
-				m.ocspStapling = true
+			if length > 0 {
+				return false
 			}
+			m.ocspStapling = true
 		case extensionSessionTicket:
 			if length > 0 {
 				return false
@@ -1377,11 +1375,19 @@
 	return true
 }
 
+type certificateEntry struct {
+	data                []byte
+	ocspResponse        []byte
+	sctList             []byte
+	duplicateExtensions bool
+	extraExtension      []byte
+}
+
 type certificateMsg struct {
 	raw               []byte
 	hasRequestContext bool
 	requestContext    []byte
-	certificates      [][]byte
+	certificates      []certificateEntry
 }
 
 func (m *certificateMsg) marshal() (x []byte) {
@@ -1399,7 +1405,33 @@
 	certificateList := certificate.addU24LengthPrefixed()
 	for _, cert := range m.certificates {
 		certEntry := certificateList.addU24LengthPrefixed()
-		certEntry.addBytes(cert)
+		certEntry.addBytes(cert.data)
+		if m.hasRequestContext {
+			extensions := certificateList.addU16LengthPrefixed()
+			count := 1
+			if cert.duplicateExtensions {
+				count = 2
+			}
+
+			for i := 0; i < count; i++ {
+				if cert.ocspResponse != nil {
+					extensions.addU16(extensionStatusRequest)
+					body := extensions.addU16LengthPrefixed()
+					body.addU8(statusTypeOCSP)
+					response := body.addU24LengthPrefixed()
+					response.addBytes(cert.ocspResponse)
+				}
+
+				if cert.sctList != nil {
+					extensions.addU16(extensionSignedCertificateTimestamp)
+					extension := extensions.addU16LengthPrefixed()
+					extension.addBytes(cert.sctList)
+				}
+			}
+			if cert.extraExtension != nil {
+				extensions.addBytes(cert.extraExtension)
+			}
+		}
 	}
 
 	m.raw = certMsg.finish()
@@ -1436,27 +1468,62 @@
 		return false
 	}
 
-	numCerts := 0
-	d := data
-	for certsLen > 0 {
-		if len(d) < 4 {
+	m.certificates = nil
+	for len(data) != 0 {
+		if len(data) < 3 {
 			return false
 		}
-		certLen := int(d[0])<<16 | int(d[1])<<8 | int(d[2])
-		if len(d) < 3+certLen {
+		certLen := int(data[0])<<16 | int(data[1])<<8 | int(data[2])
+		if len(data) < 3+certLen {
 			return false
 		}
-		d = d[3+certLen:]
-		certsLen -= 3 + certLen
-		numCerts++
-	}
+		cert := certificateEntry{
+			data: data[3 : 3+certLen],
+		}
+		data = data[3+certLen:]
+		if m.hasRequestContext {
+			if len(data) < 2 {
+				return false
+			}
+			extensionsLen := int(data[0])<<8 | int(data[1])
+			if len(data) < 2+extensionsLen {
+				return false
+			}
+			extensions := data[2 : 2+extensionsLen]
+			data = data[2+extensionsLen:]
+			for len(extensions) != 0 {
+				if len(extensions) < 4 {
+					return false
+				}
+				extension := uint16(extensions[0])<<8 | uint16(extensions[1])
+				length := int(extensions[2])<<8 | int(extensions[3])
+				if len(extensions) < 4+length {
+					return false
+				}
+				contents := extensions[4 : 4+length]
+				extensions = extensions[4+length:]
 
-	m.certificates = make([][]byte, numCerts)
-	d = data
-	for i := 0; i < numCerts; i++ {
-		certLen := uint32(d[0])<<16 | uint32(d[1])<<8 | uint32(d[2])
-		m.certificates[i] = d[3 : 3+certLen]
-		d = d[3+certLen:]
+				switch extension {
+				case extensionStatusRequest:
+					if length < 4 {
+						return false
+					}
+					if contents[0] != statusTypeOCSP {
+						return false
+					}
+					respLen := int(contents[1])<<16 | int(contents[2])<<8 | int(contents[3])
+					if respLen+4 != len(contents) || respLen == 0 {
+						return false
+					}
+					cert.ocspResponse = contents[4:]
+				case extensionSignedCertificateTimestamp:
+					cert.sctList = contents
+				default:
+					return false
+				}
+			}
+		}
+		m.certificates = append(m.certificates, cert)
 	}
 
 	return true
@@ -1904,8 +1971,7 @@
 	raw                []byte
 	version            uint16
 	ticketLifetime     uint32
-	keModes            []byte
-	authModes          []byte
+	ticketAgeAdd       uint32
 	ticket             []byte
 	customExtension    string
 	hasGREASEExtension bool
@@ -1922,8 +1988,7 @@
 	body := ticketMsg.addU24LengthPrefixed()
 	body.addU32(m.ticketLifetime)
 	if m.version >= VersionTLS13 {
-		body.addU8LengthPrefixed().addBytes(m.keModes)
-		body.addU8LengthPrefixed().addBytes(m.authModes)
+		body.addU32(m.ticketAgeAdd)
 	}
 
 	ticket := body.addU16LengthPrefixed()
@@ -1951,25 +2016,11 @@
 	data = data[8:]
 
 	if m.version >= VersionTLS13 {
-		if len(data) < 1 {
+		if len(data) < 4 {
 			return false
 		}
-		keModesLength := int(data[0])
-		if len(data)-1 < keModesLength {
-			return false
-		}
-		m.keModes = data[1 : 1+keModesLength]
-		data = data[1+keModesLength:]
-
-		if len(data) < 1 {
-			return false
-		}
-		authModesLength := int(data[0])
-		if len(data)-1 < authModesLength {
-			return false
-		}
-		m.authModes = data[1 : 1+authModesLength]
-		data = data[1+authModesLength:]
+		m.ticketAgeAdd = uint32(data[0])<<24 | uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
+		data = data[4:]
 	}
 
 	if len(data) < 2 {
@@ -2268,7 +2319,7 @@
 		return false
 	}
 	for i, v := range x {
-		if !bytes.Equal(y[i].keModes, v.keModes) || !bytes.Equal(y[i].authModes, v.authModes) || !bytes.Equal(y[i].ticket, v.ticket) {
+		if !bytes.Equal(y[i].ticket, v.ticket) || y[i].obfuscatedTicketAge != v.obfuscatedTicketAge {
 			return false
 		}
 	}
diff --git a/src/ssl/test/runner/handshake_server.go b/src/ssl/test/runner/handshake_server.go
index 9147134..67950ba 100644
--- a/src/ssl/test/runner/handshake_server.go
+++ b/src/ssl/test/runner/handshake_server.go
@@ -16,6 +16,7 @@
 	"fmt"
 	"io"
 	"math/big"
+	"time"
 )
 
 // serverHandshakeState contains details of a server handshake in progress.
@@ -158,7 +159,7 @@
 		// Per RFC 6347, the version field in HelloVerifyRequest SHOULD
 		// be always DTLS 1.0
 		helloVerifyRequest := &helloVerifyRequestMsg{
-			vers:   VersionTLS10,
+			vers:   versionToWire(VersionTLS10, c.isDTLS),
 			cookie: make([]byte, 32),
 		}
 		if _, err := io.ReadFull(c.config.rand(), helloVerifyRequest.cookie); err != nil {
@@ -384,6 +385,36 @@
 		return err
 	}
 
+	// Select the cipher suite.
+	var preferenceList, supportedList []uint16
+	if config.PreferServerCipherSuites {
+		preferenceList = config.cipherSuites()
+		supportedList = hs.clientHello.cipherSuites
+	} else {
+		preferenceList = hs.clientHello.cipherSuites
+		supportedList = config.cipherSuites()
+	}
+
+	for _, id := range preferenceList {
+		if hs.suite = c.tryCipherSuite(id, supportedList, c.vers, true, true); hs.suite != nil {
+			break
+		}
+	}
+
+	if hs.suite == nil {
+		c.sendAlert(alertHandshakeFailure)
+		return errors.New("tls: no cipher suite supported by both client and server")
+	}
+
+	hs.hello.cipherSuite = hs.suite.id
+	if c.config.Bugs.SendCipherSuite != 0 {
+		hs.hello.cipherSuite = c.config.Bugs.SendCipherSuite
+	}
+
+	hs.finishedHash = newFinishedHash(c.vers, hs.suite)
+	hs.finishedHash.discardHandshakeBuffer()
+	hs.writeClientHash(hs.clientHello.marshal())
+
 	supportedCurve := false
 	var selectedCurve CurveID
 	preferredCurves := config.curvePreferences()
@@ -404,78 +435,55 @@
 	}
 
 	pskIdentities := hs.clientHello.pskIdentities
+	pskKEModes := hs.clientHello.pskKEModes
+
 	if len(pskIdentities) == 0 && len(hs.clientHello.sessionTicket) > 0 && c.config.Bugs.AcceptAnySession {
 		psk := pskIdentity{
-			keModes:   []byte{pskDHEKEMode},
-			authModes: []byte{pskAuthMode},
-			ticket:    hs.clientHello.sessionTicket,
+			ticket: hs.clientHello.sessionTicket,
 		}
 		pskIdentities = []pskIdentity{psk}
+		pskKEModes = []byte{pskDHEKEMode}
 	}
-	for i, pskIdentity := range pskIdentities {
-		foundKE := false
-		foundAuth := false
 
-		for _, keMode := range pskIdentity.keModes {
-			if keMode == pskDHEKEMode {
-				foundKE = true
-			}
-		}
-
-		for _, authMode := range pskIdentity.authModes {
-			if authMode == pskAuthMode {
-				foundAuth = true
-			}
-		}
-
-		if !foundKE || !foundAuth {
-			continue
-		}
-
-		sessionState, ok := c.decryptTicket(pskIdentity.ticket)
-		if !ok {
-			continue
-		}
-		if config.Bugs.AcceptAnySession {
-			// Replace the cipher suite with one known to work, to
-			// test cross-version resumption attempts.
-			sessionState.cipherSuite = TLS_AES_128_GCM_SHA256
-		} else {
-			if sessionState.vers != c.vers && c.config.Bugs.AcceptAnySession {
-				continue
-			}
-			if sessionState.ticketExpiration.Before(c.config.time()) {
+	var pskIndex int
+	foundKEMode := bytes.IndexByte(pskKEModes, pskDHEKEMode) >= 0
+	if foundKEMode {
+		for i, pskIdentity := range pskIdentities {
+			// TODO(svaldez): Check the obfuscatedTicketAge before accepting 0-RTT.
+			sessionState, ok := c.decryptTicket(pskIdentity.ticket)
+			if !ok {
 				continue
 			}
 
-			cipherSuiteOk := false
-			// Check that the client is still offering the ciphersuite in the session.
-			for _, id := range hs.clientHello.cipherSuites {
-				if id == sessionState.cipherSuite {
-					cipherSuiteOk = true
-					break
+			if !config.Bugs.AcceptAnySession {
+				if sessionState.vers != c.vers {
+					continue
+				}
+				if sessionState.ticketExpiration.Before(c.config.time()) {
+					continue
+				}
+				sessionCipher := cipherSuiteFromID(sessionState.cipherSuite)
+				if sessionCipher == nil || sessionCipher.hash() != hs.suite.hash() {
+					continue
 				}
 			}
-			if !cipherSuiteOk {
-				continue
+
+			clientTicketAge := time.Duration(uint32(pskIdentity.obfuscatedTicketAge-sessionState.ticketAgeAdd)) * time.Millisecond
+			if config.Bugs.ExpectTicketAge != 0 && clientTicketAge != config.Bugs.ExpectTicketAge {
+				c.sendAlert(alertHandshakeFailure)
+				return errors.New("tls: invalid ticket age")
 			}
-		}
 
-		// Check that we also support the ciphersuite from the session.
-		suite := c.tryCipherSuite(sessionState.cipherSuite, c.config.cipherSuites(), c.vers, true, true)
-		if suite == nil {
-			continue
+			hs.sessionState = sessionState
+			hs.hello.hasPSKIdentity = true
+			hs.hello.pskIdentity = uint16(i)
+			pskIndex = i
+			if config.Bugs.SelectPSKIdentityOnResume != 0 {
+				hs.hello.pskIdentity = config.Bugs.SelectPSKIdentityOnResume
+			}
+			c.didResume = true
+			break
 		}
-
-		hs.sessionState = sessionState
-		hs.suite = suite
-		hs.hello.hasPSKIdentity = true
-		hs.hello.pskIdentity = uint16(i)
-		if config.Bugs.SelectPSKIdentityOnResume != 0 {
-			hs.hello.pskIdentity = config.Bugs.SelectPSKIdentityOnResume
-		}
-		c.didResume = true
-		break
 	}
 
 	if config.Bugs.AlwaysSelectPSKIdentity {
@@ -483,58 +491,25 @@
 		hs.hello.pskIdentity = 0
 	}
 
-	// If not resuming, select the cipher suite.
-	if hs.suite == nil {
-		var preferenceList, supportedList []uint16
-		if config.PreferServerCipherSuites {
-			preferenceList = config.cipherSuites()
-			supportedList = hs.clientHello.cipherSuites
-		} else {
-			preferenceList = hs.clientHello.cipherSuites
-			supportedList = config.cipherSuites()
-		}
-
-		for _, id := range preferenceList {
-			if hs.suite = c.tryCipherSuite(id, supportedList, c.vers, true, true); hs.suite != nil {
-				break
-			}
+	// Verify the PSK binder. Note there may not be a PSK binder if
+	// AcceptAnyBinder is set. See https://crbug.com/boringssl/115.
+	if hs.sessionState != nil && !config.Bugs.AcceptAnySession {
+		binderToVerify := hs.clientHello.pskBinders[pskIndex]
+		if err := verifyPSKBinder(hs.clientHello, hs.sessionState, binderToVerify, []byte{}); err != nil {
+			return err
 		}
 	}
 
-	if hs.suite == nil {
-		c.sendAlert(alertHandshakeFailure)
-		return errors.New("tls: no cipher suite supported by both client and server")
-	}
-
-	hs.hello.cipherSuite = hs.suite.id
-	if c.config.Bugs.SendCipherSuite != 0 {
-		hs.hello.cipherSuite = c.config.Bugs.SendCipherSuite
-	}
-
-	hs.finishedHash = newFinishedHash(c.vers, hs.suite)
-	hs.finishedHash.discardHandshakeBuffer()
-	hs.writeClientHash(hs.clientHello.marshal())
-
-	hs.hello.useCertAuth = hs.sessionState == nil
-
 	// Resolve PSK and compute the early secret.
 	var psk []byte
 	if hs.sessionState != nil {
-		psk = deriveResumptionPSK(hs.suite, hs.sessionState.masterSecret)
-		hs.finishedHash.setResumptionContext(deriveResumptionContext(hs.suite, hs.sessionState.masterSecret))
+		psk = hs.sessionState.masterSecret
 	} else {
 		psk = hs.finishedHash.zeroSecret()
-		hs.finishedHash.setResumptionContext(hs.finishedHash.zeroSecret())
 	}
 
 	earlySecret := hs.finishedHash.extractKey(hs.finishedHash.zeroSecret(), psk)
 
-	if config.Bugs.OmitServerHelloSignatureAlgorithms {
-		hs.hello.useCertAuth = false
-	} else if config.Bugs.IncludeServerHelloSignatureAlgorithms {
-		hs.hello.useCertAuth = true
-	}
-
 	hs.hello.hasKeyShare = true
 	if hs.sessionState != nil && config.Bugs.NegotiatePSKResumption {
 		hs.hello.hasKeyShare = false
@@ -598,6 +573,7 @@
 	}
 
 	if sendHelloRetryRequest {
+		oldClientHelloBytes := hs.clientHello.marshal()
 		hs.writeServerHash(helloRetryRequest.marshal())
 		c.writeRecord(recordTypeHandshake, helloRetryRequest.marshal())
 		c.flushHandshake()
@@ -621,17 +597,16 @@
 		oldClientHelloCopy := *hs.clientHello
 		oldClientHelloCopy.raw = nil
 		oldClientHelloCopy.hasEarlyData = false
-		oldClientHelloCopy.earlyDataContext = nil
 		newClientHelloCopy := *newClientHello
 		newClientHelloCopy.raw = nil
 
 		if helloRetryRequest.hasSelectedGroup {
 			newKeyShares := newClientHelloCopy.keyShares
-			if len(newKeyShares) == 0 || newKeyShares[len(newKeyShares)-1].group != helloRetryRequest.selectedGroup {
-				return errors.New("tls: KeyShare from HelloRetryRequest not present in new ClientHello")
+			if len(newKeyShares) != 1 || newKeyShares[0].group != helloRetryRequest.selectedGroup {
+				return errors.New("tls: KeyShare from HelloRetryRequest not in new ClientHello")
 			}
-			selectedKeyShare = &newKeyShares[len(newKeyShares)-1]
-			newClientHelloCopy.keyShares = newKeyShares[:len(newKeyShares)-1]
+			selectedKeyShare = &newKeyShares[0]
+			newClientHelloCopy.keyShares = oldClientHelloCopy.keyShares
 		}
 
 		if len(helloRetryRequest.cookie) > 0 {
@@ -641,6 +616,16 @@
 			newClientHelloCopy.tls13Cookie = nil
 		}
 
+		// PSK binders and obfuscated ticket age are both updated in the
+		// second ClientHello.
+		if len(oldClientHelloCopy.pskIdentities) != len(newClientHelloCopy.pskIdentities) {
+			return errors.New("tls: PSK identity count from old and new ClientHello do not match")
+		}
+		for i, identity := range oldClientHelloCopy.pskIdentities {
+			newClientHelloCopy.pskIdentities[i].obfuscatedTicketAge = identity.obfuscatedTicketAge
+		}
+		newClientHelloCopy.pskBinders = oldClientHelloCopy.pskBinders
+
 		if !oldClientHelloCopy.equal(&newClientHelloCopy) {
 			return errors.New("tls: new ClientHello does not match")
 		}
@@ -649,6 +634,16 @@
 			firstHelloRetryRequest = false
 			goto ResendHelloRetryRequest
 		}
+
+		// Verify the PSK binder. Note there may not be a PSK binder if
+		// AcceptAnyBinder is set. See https://crbug.com/115.
+		if hs.sessionState != nil && !config.Bugs.AcceptAnySession {
+			binderToVerify := newClientHello.pskBinders[pskIndex]
+			err := verifyPSKBinder(newClientHello, hs.sessionState, binderToVerify, append(oldClientHelloBytes, helloRetryRequest.marshal()...))
+			if err != nil {
+				return err
+			}
+		}
 	}
 
 	// Resolve ECDHE and compute the handshake secret.
@@ -728,25 +723,9 @@
 
 	// Switch to handshake traffic keys.
 	serverHandshakeTrafficSecret := hs.finishedHash.deriveSecret(handshakeSecret, serverHandshakeTrafficLabel)
-	c.out.useTrafficSecret(c.vers, hs.suite, serverHandshakeTrafficSecret, handshakePhase, serverWrite)
+	c.out.useTrafficSecret(c.vers, hs.suite, serverHandshakeTrafficSecret, serverWrite)
 	clientHandshakeTrafficSecret := hs.finishedHash.deriveSecret(handshakeSecret, clientHandshakeTrafficLabel)
-	c.in.useTrafficSecret(c.vers, hs.suite, clientHandshakeTrafficSecret, handshakePhase, clientWrite)
-
-	if hs.hello.useCertAuth {
-		if hs.clientHello.ocspStapling {
-			encryptedExtensions.extensions.ocspResponse = hs.cert.OCSPStaple
-		}
-		if hs.clientHello.sctListSupported {
-			encryptedExtensions.extensions.sctList = hs.cert.SignedCertificateTimestampList
-		}
-	} else {
-		if config.Bugs.SendOCSPResponseOnResume != nil {
-			encryptedExtensions.extensions.ocspResponse = config.Bugs.SendOCSPResponseOnResume
-		}
-		if config.Bugs.SendSCTListOnResume != nil {
-			encryptedExtensions.extensions.sctList = config.Bugs.SendSCTListOnResume
-		}
-	}
+	c.in.useTrafficSecret(c.vers, hs.suite, clientHandshakeTrafficSecret, clientWrite)
 
 	// Send EncryptedExtensions.
 	hs.writeServerHash(encryptedExtensions.marshal())
@@ -757,7 +736,7 @@
 		c.writeRecord(recordTypeHandshake, encryptedExtensions.marshal())
 	}
 
-	if hs.hello.useCertAuth {
+	if hs.sessionState == nil {
 		if config.ClientAuth >= RequestClientCert {
 			// Request a client certificate
 			certReq := &certificateRequestMsg{
@@ -785,7 +764,29 @@
 			hasRequestContext: true,
 		}
 		if !config.Bugs.EmptyCertificateList {
-			certMsg.certificates = hs.cert.Certificate
+			for i, certData := range hs.cert.Certificate {
+				cert := certificateEntry{
+					data: certData,
+				}
+				if i == 0 {
+					if hs.clientHello.ocspStapling {
+						cert.ocspResponse = hs.cert.OCSPStaple
+					}
+					if hs.clientHello.sctListSupported {
+						cert.sctList = hs.cert.SignedCertificateTimestampList
+					}
+					cert.duplicateExtensions = config.Bugs.SendDuplicateCertExtensions
+					cert.extraExtension = config.Bugs.SendExtensionOnCertificate
+				} else {
+					if config.Bugs.SendOCSPOnIntermediates != nil {
+						cert.ocspResponse = config.Bugs.SendOCSPOnIntermediates
+					}
+					if config.Bugs.SendSCTOnIntermediates != nil {
+						cert.sctList = config.Bugs.SendSCTOnIntermediates
+					}
+				}
+				certMsg.certificates = append(certMsg.certificates, cert)
+			}
 		}
 		certMsgBytes := certMsg.marshal()
 		hs.writeServerHash(certMsgBytes)
@@ -844,10 +845,11 @@
 	masterSecret := hs.finishedHash.extractKey(handshakeSecret, hs.finishedHash.zeroSecret())
 	clientTrafficSecret := hs.finishedHash.deriveSecret(masterSecret, clientApplicationTrafficLabel)
 	serverTrafficSecret := hs.finishedHash.deriveSecret(masterSecret, serverApplicationTrafficLabel)
+	c.exporterSecret = hs.finishedHash.deriveSecret(masterSecret, exporterLabel)
 
 	// Switch to application data keys on write. In particular, any alerts
 	// from the client certificate are sent over these keys.
-	c.out.useTrafficSecret(c.vers, hs.suite, serverTrafficSecret, applicationPhase, serverWrite)
+	c.out.useTrafficSecret(c.vers, hs.suite, serverTrafficSecret, serverWrite)
 
 	// If we requested a client certificate, then the client must send a
 	// certificate message, even if it's empty.
@@ -873,7 +875,17 @@
 			}
 		}
 
-		pub, err := hs.processCertsFromClient(certMsg.certificates)
+		var certs [][]byte
+		for _, cert := range certMsg.certificates {
+			certs = append(certs, cert.data)
+			// OCSP responses and SCT lists are not negotiated in
+			// client certificates.
+			if cert.ocspResponse != nil || cert.sctList != nil {
+				c.sendAlert(alertUnsupportedExtension)
+				return errors.New("tls: unexpected extensions in the client certificate")
+			}
+		}
+		pub, err := hs.processCertsFromClient(certs)
 		if err != nil {
 			return err
 		}
@@ -900,6 +912,27 @@
 		}
 	}
 
+	if encryptedExtensions.extensions.channelIDRequested {
+		msg, err := c.readHandshake()
+		if err != nil {
+			return err
+		}
+		channelIDMsg, ok := msg.(*channelIDMsg)
+		if !ok {
+			c.sendAlert(alertUnexpectedMessage)
+			return unexpectedMessageError(channelIDMsg, msg)
+		}
+		channelIDHash := crypto.SHA256.New()
+		channelIDHash.Write(hs.finishedHash.certificateVerifyInput(channelIDContextTLS13))
+		channelID, err := verifyChannelIDMessage(channelIDMsg, channelIDHash.Sum(nil))
+		if err != nil {
+			return err
+		}
+		c.channelID = channelID
+
+		hs.writeClientHash(channelIDMsg.marshal())
+	}
+
 	// Read the client Finished message.
 	msg, err := c.readHandshake()
 	if err != nil {
@@ -920,15 +953,14 @@
 	hs.writeClientHash(clientFinished.marshal())
 
 	// Switch to application data keys on read.
-	c.in.useTrafficSecret(c.vers, hs.suite, clientTrafficSecret, applicationPhase, clientWrite)
+	c.in.useTrafficSecret(c.vers, hs.suite, clientTrafficSecret, clientWrite)
 
 	c.cipherSuite = hs.suite
-	c.exporterSecret = hs.finishedHash.deriveSecret(masterSecret, exporterLabel)
 	c.resumptionSecret = hs.finishedHash.deriveSecret(masterSecret, resumptionLabel)
 
 	// TODO(davidben): Allow configuring the number of tickets sent for
 	// testing.
-	if !c.config.SessionTicketsDisabled {
+	if !c.config.SessionTicketsDisabled && foundKEMode {
 		ticketCount := 2
 		for i := 0; i < ticketCount; i++ {
 			c.SendNewSessionTicket()
@@ -1113,7 +1145,7 @@
 			if hs.clientHello.nextProtoNeg && len(config.NextProtos) > 0 {
 				serverExtensions.nextProtoNeg = true
 				serverExtensions.nextProtos = config.NextProtos
-				serverExtensions.npnLast = config.Bugs.SwapNPNAndALPN
+				serverExtensions.npnAfterAlpn = config.Bugs.SwapNPNAndALPN
 			}
 		}
 	}
@@ -1126,10 +1158,8 @@
 		serverExtensions.extendedMasterSecret = c.vers >= VersionTLS10 && hs.clientHello.extendedMasterSecret && !disableEMS
 	}
 
-	if c.vers < VersionTLS13 || config.Bugs.NegotiateChannelIDAtAllVersions {
-		if hs.clientHello.channelIDSupported && config.RequestChannelID {
-			serverExtensions.channelIDRequested = true
-		}
+	if hs.clientHello.channelIDSupported && config.RequestChannelID {
+		serverExtensions.channelIDRequested = true
 	}
 
 	if hs.clientHello.srtpProtectionProfiles != nil {
@@ -1321,7 +1351,11 @@
 	if !isPSK {
 		certMsg := new(certificateMsg)
 		if !config.Bugs.EmptyCertificateList {
-			certMsg.certificates = hs.cert.Certificate
+			for _, certData := range hs.cert.Certificate {
+				certMsg.certificates = append(certMsg.certificates, certificateEntry{
+					data: certData,
+				})
+			}
 		}
 		if !config.Bugs.UnauthenticatedECDH {
 			certMsgBytes := certMsg.marshal()
@@ -1409,7 +1443,9 @@
 			}
 
 			hs.writeClientHash(certMsg.marshal())
-			certificates = certMsg.certificates
+			for _, cert := range certMsg.certificates {
+				certificates = append(certificates, cert.data)
+			}
 		} else if c.vers != VersionSSL30 {
 			// In TLS, the Certificate message is required. In SSL
 			// 3.0, the peer skips it when sending no certificates.
@@ -1568,20 +1604,13 @@
 			c.sendAlert(alertUnexpectedMessage)
 			return unexpectedMessageError(channelIDMsg, msg)
 		}
-		x := new(big.Int).SetBytes(channelIDMsg.channelID[0:32])
-		y := new(big.Int).SetBytes(channelIDMsg.channelID[32:64])
-		r := new(big.Int).SetBytes(channelIDMsg.channelID[64:96])
-		s := new(big.Int).SetBytes(channelIDMsg.channelID[96:128])
-		if !elliptic.P256().IsOnCurve(x, y) {
-			return errors.New("tls: invalid channel ID public key")
-		}
-		channelID := &ecdsa.PublicKey{elliptic.P256(), x, y}
 		var resumeHash []byte
 		if isResume {
 			resumeHash = hs.sessionState.handshakeHash
 		}
-		if !ecdsa.Verify(channelID, hs.finishedHash.hashForChannelID(resumeHash), r, s) {
-			return errors.New("tls: invalid channel ID signature")
+		channelID, err := verifyChannelIDMessage(channelIDMsg, hs.finishedHash.hashForChannelID(resumeHash))
+		if err != nil {
+			return err
 		}
 		c.channelID = channelID
 
@@ -1618,7 +1647,7 @@
 		cipherSuite:   hs.suite.id,
 		masterSecret:  hs.masterSecret,
 		certificates:  hs.certsFromClient,
-		handshakeHash: hs.finishedHash.server.Sum(nil),
+		handshakeHash: hs.finishedHash.Sum(),
 	}
 
 	if !hs.hello.extensions.ticketSupported || hs.c.config.Bugs.SkipNewSessionTicket {
@@ -1765,6 +1794,21 @@
 	return nil, nil
 }
 
+func verifyChannelIDMessage(channelIDMsg *channelIDMsg, channelIDHash []byte) (*ecdsa.PublicKey, error) {
+	x := new(big.Int).SetBytes(channelIDMsg.channelID[0:32])
+	y := new(big.Int).SetBytes(channelIDMsg.channelID[32:64])
+	r := new(big.Int).SetBytes(channelIDMsg.channelID[64:96])
+	s := new(big.Int).SetBytes(channelIDMsg.channelID[96:128])
+	if !elliptic.P256().IsOnCurve(x, y) {
+		return nil, errors.New("tls: invalid channel ID public key")
+	}
+	channelID := &ecdsa.PublicKey{elliptic.P256(), x, y}
+	if !ecdsa.Verify(channelID, channelIDHash, r, s) {
+		return nil, errors.New("tls: invalid channel ID signature")
+	}
+	return channelID, nil
+}
+
 func (hs *serverHandshakeState) writeServerHash(msg []byte) {
 	// writeServerHash is called before writeRecord.
 	hs.writeHash(msg, hs.c.sendHandshakeSeq)
@@ -1849,3 +1893,24 @@
 func isGREASEValue(val uint16) bool {
 	return val&0x0f0f == 0x0a0a && val&0xff == val>>8
 }
+
+func verifyPSKBinder(clientHello *clientHelloMsg, sessionState *sessionState, binderToVerify, transcript []byte) error {
+	binderLen := 2
+	for _, binder := range clientHello.pskBinders {
+		binderLen += 1 + len(binder)
+	}
+
+	truncatedHello := clientHello.marshal()
+	truncatedHello = truncatedHello[:len(truncatedHello)-binderLen]
+	pskCipherSuite := cipherSuiteFromID(sessionState.cipherSuite)
+	if pskCipherSuite == nil {
+		return errors.New("tls: Unknown cipher suite for PSK in session")
+	}
+
+	binder := computePSKBinder(sessionState.masterSecret, resumptionPSKBinderLabel, pskCipherSuite, transcript, truncatedHello)
+	if !bytes.Equal(binder, binderToVerify) {
+		return errors.New("tls: PSK binder does not verify")
+	}
+
+	return nil
+}
diff --git a/src/ssl/test/runner/prf.go b/src/ssl/test/runner/prf.go
index ffa68e9..c311e99 100644
--- a/src/ssl/test/runner/prf.go
+++ b/src/ssl/test/runner/prf.go
@@ -230,10 +230,6 @@
 	// full buffer is required.
 	buffer []byte
 
-	// TLS 1.3 has a resumption context which is carried over on PSK
-	// resumption.
-	resumptionContextHash []byte
-
 	version uint16
 	prf     func(result, secret, label, seed []byte)
 }
@@ -357,7 +353,7 @@
 		hash.Write(channelIDResumeLabel)
 		hash.Write(resumeHash)
 	}
-	hash.Write(h.server.Sum(nil))
+	hash.Write(h.Sum())
 	return hash.Sum(nil)
 }
 
@@ -374,13 +370,6 @@
 	return make([]byte, h.hash.Size())
 }
 
-// setResumptionContext sets the TLS 1.3 resumption context.
-func (h *finishedHash) setResumptionContext(resumptionContext []byte) {
-	hash := h.hash.New()
-	hash.Write(resumptionContext)
-	h.resumptionContextHash = hash.Sum(nil)
-}
-
 // extractKey combines two secrets together with HKDF-Expand in the TLS 1.3 key
 // derivation schedule.
 func (h *finishedHash) extractKey(salt, ikm []byte) []byte {
@@ -412,12 +401,13 @@
 // resumption context hash, as used in TLS 1.3.
 func (h *finishedHash) appendContextHashes(b []byte) []byte {
 	b = h.client.Sum(b)
-	b = append(b, h.resumptionContextHash...)
 	return b
 }
 
 // The following are labels for traffic secret derivation in TLS 1.3.
 var (
+	externalPSKBinderLabel        = []byte("external psk binder key")
+	resumptionPSKBinderLabel      = []byte("resumption psk binder key")
 	earlyTrafficLabel             = []byte("client early traffic secret")
 	clientHandshakeTrafficLabel   = []byte("client handshake traffic secret")
 	serverHandshakeTrafficLabel   = []byte("server handshake traffic secret")
@@ -431,10 +421,6 @@
 // deriveSecret implements TLS 1.3's Derive-Secret function, as defined in
 // section 7.1 of draft ietf-tls-tls13-16.
 func (h *finishedHash) deriveSecret(secret, label []byte) []byte {
-	if h.resumptionContextHash == nil {
-		panic("Resumption context not set.")
-	}
-
 	return hkdfExpandLabel(h.hash, secret, label, h.appendContextHashes(nil), h.hash.Size())
 }
 
@@ -442,6 +428,7 @@
 var (
 	clientCertificateVerifyContextTLS13 = []byte("TLS 1.3, client CertificateVerify")
 	serverCertificateVerifyContextTLS13 = []byte("TLS 1.3, server CertificateVerify")
+	channelIDContextTLS13               = []byte("TLS 1.3, Channel ID")
 )
 
 // certificateVerifyMessage returns the input to be signed for CertificateVerify
@@ -458,14 +445,6 @@
 	return b
 }
 
-// The following are phase values for traffic key derivation in TLS 1.3.
-var (
-	earlyHandshakePhase   = []byte("early handshake key expansion")
-	earlyApplicationPhase = []byte("early application data key expansion")
-	handshakePhase        = []byte("handshake key expansion")
-	applicationPhase      = []byte("application data key expansion")
-)
-
 type trafficDirection int
 
 const (
@@ -473,17 +452,16 @@
 	serverWrite
 )
 
+var (
+	keyTLS13 = []byte("key")
+	ivTLS13  = []byte("iv")
+)
+
 // deriveTrafficAEAD derives traffic keys and constructs an AEAD given a traffic
 // secret.
-func deriveTrafficAEAD(version uint16, suite *cipherSuite, secret, phase []byte, side trafficDirection) interface{} {
-	label := make([]byte, 0, len(phase)+2+16)
-	label = append(label, phase...)
-	label = append(label, []byte(", key")...)
-	key := hkdfExpandLabel(suite.hash(), secret, label, nil, suite.keyLen)
-
-	label = label[:len(label)-3] // Remove "key" from the end.
-	label = append(label, []byte("iv")...)
-	iv := hkdfExpandLabel(suite.hash(), secret, label, nil, suite.ivLen(version))
+func deriveTrafficAEAD(version uint16, suite *cipherSuite, secret []byte, side trafficDirection) interface{} {
+	key := hkdfExpandLabel(suite.hash(), secret, keyTLS13, nil, suite.keyLen)
+	iv := hkdfExpandLabel(suite.hash(), secret, ivTLS13, nil, suite.ivLen(version))
 
 	return suite.aead(version, key, iv)
 }
@@ -492,10 +470,11 @@
 	return hkdfExpandLabel(hash, secret, applicationTrafficLabel, nil, hash.Size())
 }
 
-func deriveResumptionPSK(suite *cipherSuite, resumptionSecret []byte) []byte {
-	return hkdfExpandLabel(suite.hash(), resumptionSecret, []byte("resumption psk"), nil, suite.hash().Size())
-}
-
-func deriveResumptionContext(suite *cipherSuite, resumptionSecret []byte) []byte {
-	return hkdfExpandLabel(suite.hash(), resumptionSecret, []byte("resumption context"), nil, suite.hash().Size())
+func computePSKBinder(psk, label []byte, cipherSuite *cipherSuite, transcript, truncatedHello []byte) []byte {
+	finishedHash := newFinishedHash(VersionTLS13, cipherSuite)
+	earlySecret := finishedHash.extractKey(finishedHash.zeroSecret(), psk)
+	binderKey := finishedHash.deriveSecret(earlySecret, label)
+	finishedHash.Write(transcript)
+	finishedHash.Write(truncatedHello)
+	return finishedHash.clientSum(binderKey)
 }
diff --git a/src/ssl/test/runner/rsa_chain_cert.pem b/src/ssl/test/runner/rsa_chain_cert.pem
new file mode 100644
index 0000000..8eb6e60
--- /dev/null
+++ b/src/ssl/test/runner/rsa_chain_cert.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIC0jCCAbqgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwDzENMAsGA1UEAwwEQiBD
+QTAeFw0xNjAyMjgyMDI3MDNaFw0yNjAyMjUyMDI3MDNaMBgxFjAUBgNVBAMMDUNs
+aWVudCBDZXJ0IEEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDRvaz8
+CC/cshpCafJo4jLkHEoBqDLhdgFelJoAiQUyIqyWl2O7YHPnpJH+TgR7oelzNzt/
+kLRcH89M/TszB6zqyLTC4aqmvzKL0peD/jL2LWBucR0WXIvjA3zoRuF/x86+rYH3
+tHb+xs2PSs8EGL/Ev+ss+qTzTGEn26fuGNHkNw6tOwPpc+o8+wUtzf/kAthamo+c
+IDs2rQ+lP7+aLZTLeU/q4gcLutlzcK5imex5xy2jPkweq48kijK0kIzl1cPlA5d1
+z7C8jU50Pj9X9sQDJTN32j7UYRisJeeYQF8GaaN8SbrDI6zHgKzrRLyxDt/KQa9V
+iLeXANgZi+Xx9KgfAgMBAAGjLzAtMAwGA1UdEwEB/wQCMAAwHQYDVR0lBBYwFAYI
+KwYBBQUHAwEGCCsGAQUFBwMCMA0GCSqGSIb3DQEBCwUAA4IBAQBFEVbmYl+2RtNw
+rDftRDF1v2QUbcN2ouSnQDHxeDQdSgasLzT3ui8iYu0Rw2WWcZ0DV5e0ztGPhWq7
+AO0B120aFRMOY+4+bzu9Q2FFkQqc7/fKTvTDzIJI5wrMnFvUfzzvxh3OHWMYSs/w
+giq33hTKeHEq6Jyk3btCny0Ycecyc3yGXH10sizUfiHlhviCkDuESk8mFDwDDzqW
+ZF0IipzFbEDHoIxLlm3GQxpiLoEV4k8KYJp3R5KBLFyxM6UGPz8h72mIPCJp2RuK
+MYgF91UDvVzvnYm6TfseM2+ewKirC00GOrZ7rEcFvtxnKSqYf4ckqfNdSU1Y+RRC
+1ngWZ7Ih
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICwjCCAaqgAwIBAgICEAEwDQYJKoZIhvcNAQELBQAwFDESMBAGA1UEAwwJQyBS
+b290IENBMB4XDTE2MDIyODIwMjcwM1oXDTI2MDIyNTIwMjcwM1owDzENMAsGA1UE
+AwwEQiBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALsSCYmDip2D
+GkjFxw7ykz26JSjELkl6ArlYjFJ3aT/SCh8qbS4gln7RH8CPBd78oFdfhIKQrwtZ
+3/q21ykD9BAS3qHe2YdcJfm8/kWAy5DvXk6NXU4qX334KofBAEpgdA/igEFq1P1l
+HAuIfZCpMRfT+i5WohVsGi8f/NgpRvVaMONLNfgw57mz1lbtFeBEISmX0kbsuJxF
+Qj/Bwhi5/0HAEXG8e7zN4cEx0yPRvmOATRdVb/8dW2pwOHRJq9R5M0NUkIsTSnL7
+6N/z8hRAHMsV3IudC5Yd7GXW1AGu9a+iKU+Q4xcZCoj0DC99tL4VKujrV1kAeqsM
+cz5/dKzi6+cCAwEAAaMjMCEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
+AQYwDQYJKoZIhvcNAQELBQADggEBAIIeZiEeNhWWQ8Y4D+AGDwqUUeG8NjCbKrXQ
+BlHg5wZ8xftFaiP1Dp/UAezmx2LNazdmuwrYB8lm3FVTyaPDTKEGIPS4wJKHgqH1
+QPDhqNm85ey7TEtI9oYjsNim/Rb+iGkIAMXaxt58SzxbjvP0kMr1JfJIZbic9vye
+NwIspMFIpP3FB8ywyu0T0hWtCQgL4J47nigCHpOu58deP88fS/Nyz/fyGVWOZ76b
+WhWwgM3P3X95fQ3d7oFPR/bVh0YV+Cf861INwplokXgXQ3/TCQ+HNXeAMWn3JLWv
+XFwk8owk9dq/kQGdndGgy3KTEW4ctPX5GNhf3LJ9Q7dLji4ReQ4=
+-----END CERTIFICATE-----
diff --git a/src/ssl/test/runner/rsa_chain_key.pem b/src/ssl/test/runner/rsa_chain_key.pem
new file mode 100644
index 0000000..d94d704
--- /dev/null
+++ b/src/ssl/test/runner/rsa_chain_key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDRvaz8CC/cshpC
+afJo4jLkHEoBqDLhdgFelJoAiQUyIqyWl2O7YHPnpJH+TgR7oelzNzt/kLRcH89M
+/TszB6zqyLTC4aqmvzKL0peD/jL2LWBucR0WXIvjA3zoRuF/x86+rYH3tHb+xs2P
+Ss8EGL/Ev+ss+qTzTGEn26fuGNHkNw6tOwPpc+o8+wUtzf/kAthamo+cIDs2rQ+l
+P7+aLZTLeU/q4gcLutlzcK5imex5xy2jPkweq48kijK0kIzl1cPlA5d1z7C8jU50
+Pj9X9sQDJTN32j7UYRisJeeYQF8GaaN8SbrDI6zHgKzrRLyxDt/KQa9ViLeXANgZ
+i+Xx9KgfAgMBAAECggEBAK0VjSJzkyPaamcyTVSWjo7GdaBGcK60lk657RjR+lK0
+YJ7pkej4oM2hdsVZFsP8Cs4E33nXLa/0pDsRov/qrp0WQm2skwqGMC1I/bZ0WRPk
+wHaDrBBfESWnJDX/AGpVtlyOjPmgmK6J2usMPihQUDkKdAYrVWJePrMIxt1q6BMe
+iczs3qriMmtY3bUc4UyUwJ5fhDLjshHvfuIpYQyI6EXZM6dZksn9LylXJnigY6QJ
+HxOYO0BDwOsZ8yQ8J8afLk88i0GizEkgE1z3REtQUwgWfxr1WV/ud+T6/ZhSAgH9
+042mQvSFZnIUSEsmCvjhWuAunfxHKCTcAoYISWfzWpkCgYEA7gpf3HHU5Tn+CgUn
+1X5uGpG3DmcMgfeGgs2r2f/IIg/5Ac1dfYILiybL1tN9zbyLCJfcbFpWBc9hJL6f
+CPc5hUiwWFJqBJewxQkC1Ae/HakHbip+IZ+Jr0842O4BAArvixk4Lb7/N2Ct9sTE
+NJO6RtK9lbEZ5uK61DglHy8CS2UCgYEA4ZC1o36kPAMQBggajgnucb2yuUEelk0f
+AEr+GI32MGE+93xMr7rAhBoqLg4AITyIfEnOSQ5HwagnIHonBbv1LV/Gf9ursx8Z
+YOGbvT8zzzC+SU1bkDzdjAYnFQVGIjMtKOBJ3K07++ypwX1fr4QsQ8uKL8WSOWwt
+Z3Bym6XiZzMCgYADnhy+2OwHX85AkLt+PyGlPbmuelpyTzS4IDAQbBa6jcuW/2wA
+UE2km75VUXmD+u2R/9zVuLm99NzhFhSMqlUxdV1YukfqMfP5yp1EY6m/5aW7QuIP
+2MDa7TVL9rIFMiVZ09RKvbBbQxjhuzPQKL6X/PPspnhiTefQ+dl2k9xREQKBgHDS
+fMfGNEeAEKezrfSVqxphE9/tXms3L+ZpnCaT+yu/uEr5dTIAawKoQ6i9f/sf1/Sy
+xedsqR+IB+oKrzIDDWMgoJybN4pkZ8E5lzhVQIjFjKgFdWLzzqyW9z1gYfABQPlN
+FiS20WX0vgP1vcKAjdNrHzc9zyHBpgQzDmAj3NZZAoGBAI8vKCKdH7w3aL5CNkZQ
+2buIeWNA2HZazVwAGG5F2TU/LmXfRKnG6dX5bkU+AkBZh56jNZy//hfFSewJB4Kk
+buB7ERSdaNbO21zXt9FEA3+z0RfMd/Zv2vlIWOSB5nzl/7UKti3sribK6s9ZVLfi
+SxpiPQ8d/hmSGwn4ksrWUsJD
+-----END PRIVATE KEY-----
diff --git a/src/ssl/test/runner/runner.go b/src/ssl/test/runner/runner.go
index 367fef1..683f07c 100644
--- a/src/ssl/test/runner/runner.go
+++ b/src/ssl/test/runner/runner.go
@@ -62,6 +62,7 @@
 	looseErrors        = flag.Bool("loose-errors", false, "If true, allow shims to report an untranslated error code.")
 	shimConfigFile     = flag.String("shim-config", "", "A config file to use to configure the tests for this shim.")
 	includeDisabled    = flag.Bool("include-disabled", false, "If true, also runs disabled tests.")
+	repeatUntilFailure = flag.Bool("repeat-until-failure", false, "If true, the first selected test will be run repeatedly until failure.")
 )
 
 // ShimConfigurations is used with the “json” package and represents a shim
@@ -87,6 +88,7 @@
 const (
 	testCertRSA testCert = iota
 	testCertRSA1024
+	testCertRSAChain
 	testCertECDSAP256
 	testCertECDSAP384
 	testCertECDSAP521
@@ -95,6 +97,7 @@
 const (
 	rsaCertificateFile       = "cert.pem"
 	rsa1024CertificateFile   = "rsa_1024_cert.pem"
+	rsaChainCertificateFile  = "rsa_chain_cert.pem"
 	ecdsaP256CertificateFile = "ecdsa_p256_cert.pem"
 	ecdsaP384CertificateFile = "ecdsa_p384_cert.pem"
 	ecdsaP521CertificateFile = "ecdsa_p521_cert.pem"
@@ -103,6 +106,7 @@
 const (
 	rsaKeyFile       = "key.pem"
 	rsa1024KeyFile   = "rsa_1024_key.pem"
+	rsaChainKeyFile  = "rsa_chain_key.pem"
 	ecdsaP256KeyFile = "ecdsa_p256_key.pem"
 	ecdsaP384KeyFile = "ecdsa_p384_key.pem"
 	ecdsaP521KeyFile = "ecdsa_p521_key.pem"
@@ -112,6 +116,7 @@
 var (
 	rsaCertificate       Certificate
 	rsa1024Certificate   Certificate
+	rsaChainCertificate  Certificate
 	ecdsaP256Certificate Certificate
 	ecdsaP384Certificate Certificate
 	ecdsaP521Certificate Certificate
@@ -135,6 +140,12 @@
 		cert:     &rsa1024Certificate,
 	},
 	{
+		id:       testCertRSAChain,
+		certFile: rsaChainCertificateFile,
+		keyFile:  rsaChainKeyFile,
+		cert:     &rsaChainCertificate,
+	},
+	{
 		id:       testCertECDSAP256,
 		certFile: ecdsaP256CertificateFile,
 		keyFile:  ecdsaP256KeyFile,
@@ -158,7 +169,10 @@
 var channelIDBytes []byte
 
 var testOCSPResponse = []byte{1, 2, 3, 4}
-var testSCTList = []byte{5, 6, 7, 8}
+var testSCTList = []byte{0, 6, 0, 4, 5, 6, 7, 8}
+
+var testOCSPExtension = append([]byte{byte(extensionStatusRequest) >> 8, byte(extensionStatusRequest), 0, 8, statusTypeOCSP, 0, 0, 4}, testOCSPResponse...)
+var testSCTExtension = append([]byte{byte(extensionSignedCertificateTimestamp) >> 8, byte(extensionSignedCertificateTimestamp), 0, byte(len(testSCTList))}, testSCTList...)
 
 func initCertificates() {
 	for i := range testCerts {
@@ -364,6 +378,9 @@
 	// expectMessageDropped, if true, means the test message is expected to
 	// be dropped by the client rather than echoed back.
 	expectMessageDropped bool
+	// expectPeerCertificate, if not nil, is the certificate chain the peer
+	// is expected to send.
+	expectPeerCertificate *Certificate
 }
 
 var testCases []testCase
@@ -581,6 +598,17 @@
 		return fmt.Errorf("expected peer to use curve %04x, but got %04x", expected, connState.CurveID)
 	}
 
+	if test.expectPeerCertificate != nil {
+		if len(connState.PeerCertificates) != len(test.expectPeerCertificate.Certificate) {
+			return fmt.Errorf("expected peer to send %d certificates, but got %d", len(connState.PeerCertificates), len(test.expectPeerCertificate.Certificate))
+		}
+		for i, cert := range connState.PeerCertificates {
+			if !bytes.Equal(cert.Raw, test.expectPeerCertificate.Certificate[i]) {
+				return fmt.Errorf("peer certificate %d did not match", i+1)
+			}
+		}
+	}
+
 	if test.exportKeyingMaterial > 0 {
 		actual := make([]byte, test.exportKeyingMaterial)
 		if _, err := io.ReadFull(tlsConn, actual); err != nil {
@@ -1682,6 +1710,50 @@
 			expectedLocalError: "remote error: handshake failure",
 		},
 		{
+			name: "FailCertCallback-Client-TLS12",
+			config: Config{
+				MaxVersion: VersionTLS12,
+				ClientAuth: RequestClientCert,
+			},
+			flags:              []string{"-fail-cert-callback"},
+			shouldFail:         true,
+			expectedError:      ":CERT_CB_ERROR:",
+			expectedLocalError: "remote error: internal error",
+		},
+		{
+			testType: serverTest,
+			name:     "FailCertCallback-Server-TLS12",
+			config: Config{
+				MaxVersion: VersionTLS12,
+			},
+			flags:              []string{"-fail-cert-callback"},
+			shouldFail:         true,
+			expectedError:      ":CERT_CB_ERROR:",
+			expectedLocalError: "remote error: internal error",
+		},
+		{
+			name: "FailCertCallback-Client-TLS13",
+			config: Config{
+				MaxVersion: VersionTLS13,
+				ClientAuth: RequestClientCert,
+			},
+			flags:              []string{"-fail-cert-callback"},
+			shouldFail:         true,
+			expectedError:      ":CERT_CB_ERROR:",
+			expectedLocalError: "remote error: internal error",
+		},
+		{
+			testType: serverTest,
+			name:     "FailCertCallback-Server-TLS13",
+			config: Config{
+				MaxVersion: VersionTLS13,
+			},
+			flags:              []string{"-fail-cert-callback"},
+			shouldFail:         true,
+			expectedError:      ":CERT_CB_ERROR:",
+			expectedLocalError: "remote error: internal error",
+		},
+		{
 			protocol: dtls,
 			name:     "FragmentMessageTypeMismatch-DTLS",
 			config: Config{
@@ -2299,10 +2371,13 @@
 			config: Config{
 				MaxVersion: VersionTLS13,
 				Bugs: ProtocolBugs{
+					// TLS 1.3 servers are expected to
+					// always enable GREASE. TLS 1.3 is new,
+					// so there is no existing ecosystem to
+					// worry about.
 					ExpectGREASE: true,
 				},
 			},
-			flags: []string{"-enable-grease"},
 		},
 	}
 	testCases = append(testCases, basicTests...)
@@ -2485,7 +2560,8 @@
 				if !shouldClientFail {
 					// Ensure the maximum record size is accepted.
 					testCases = append(testCases, testCase{
-						name: prefix + ver.name + "-" + suite.name + "-LargeRecord",
+						protocol: protocol,
+						name:     prefix + ver.name + "-" + suite.name + "-LargeRecord",
 						config: Config{
 							MinVersion:           ver.version,
 							MaxVersion:           ver.version,
@@ -2497,6 +2573,33 @@
 						flags:      flags,
 						messageLen: maxPlaintext,
 					})
+
+					// Test bad records for all ciphers. Bad records are fatal in TLS
+					// and ignored in DTLS.
+					var shouldFail bool
+					var expectedError string
+					if protocol == tls {
+						shouldFail = true
+						expectedError = ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:"
+					}
+
+					testCases = append(testCases, testCase{
+						protocol: protocol,
+						name:     prefix + ver.name + "-" + suite.name + "-BadRecord",
+						config: Config{
+							MinVersion:           ver.version,
+							MaxVersion:           ver.version,
+							CipherSuites:         []uint16{suite.id},
+							Certificates:         []Certificate{cert},
+							PreSharedKey:         []byte(psk),
+							PreSharedKeyIdentity: pskIdentity,
+						},
+						flags:            flags,
+						damageFirstWrite: true,
+						messageLen:       maxPlaintext,
+						shouldFail:       shouldFail,
+						expectedError:    expectedError,
+					})
 				}
 			}
 		}
@@ -3940,33 +4043,54 @@
 			},
 		})
 
-		// Client sends a Channel ID.
-		tests = append(tests, testCase{
-			name: "ChannelID-Client",
-			config: Config{
-				MaxVersion:       VersionTLS12,
-				RequestChannelID: true,
-			},
-			flags:           []string{"-send-channel-id", path.Join(*resourceDir, channelIDKeyFile)},
-			resumeSession:   true,
-			expectChannelID: true,
-		})
+		// Test Channel ID
+		for _, ver := range tlsVersions {
+			if ver.version < VersionTLS10 {
+				continue
+			}
+			// Client sends a Channel ID.
+			tests = append(tests, testCase{
+				name: "ChannelID-Client-" + ver.name,
+				config: Config{
+					MaxVersion:       ver.version,
+					RequestChannelID: true,
+				},
+				flags:           []string{"-send-channel-id", path.Join(*resourceDir, channelIDKeyFile)},
+				resumeSession:   true,
+				expectChannelID: true,
+			})
 
-		// Server accepts a Channel ID.
-		tests = append(tests, testCase{
-			testType: serverTest,
-			name:     "ChannelID-Server",
-			config: Config{
-				MaxVersion: VersionTLS12,
-				ChannelID:  channelIDKey,
-			},
-			flags: []string{
-				"-expect-channel-id",
-				base64.StdEncoding.EncodeToString(channelIDBytes),
-			},
-			resumeSession:   true,
-			expectChannelID: true,
-		})
+			// Server accepts a Channel ID.
+			tests = append(tests, testCase{
+				testType: serverTest,
+				name:     "ChannelID-Server-" + ver.name,
+				config: Config{
+					MaxVersion: ver.version,
+					ChannelID:  channelIDKey,
+				},
+				flags: []string{
+					"-expect-channel-id",
+					base64.StdEncoding.EncodeToString(channelIDBytes),
+				},
+				resumeSession:   true,
+				expectChannelID: true,
+			})
+
+			tests = append(tests, testCase{
+				testType: serverTest,
+				name:     "InvalidChannelIDSignature-" + ver.name,
+				config: Config{
+					MaxVersion: ver.version,
+					ChannelID:  channelIDKey,
+					Bugs: ProtocolBugs{
+						InvalidChannelIDSignature: true,
+					},
+				},
+				flags:         []string{"-enable-channel-id"},
+				shouldFail:    true,
+				expectedError: ":CHANNEL_ID_SIGNATURE_INVALID:",
+			})
+		}
 
 		// Channel ID and NPN at the same time, to ensure their relative
 		// ordering is correct.
@@ -4333,6 +4457,19 @@
 		expectedVersion: VersionTLS12,
 	})
 
+	// Test that the maximum version is selected regardless of the
+	// client-sent order.
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "IgnoreClientVersionOrder",
+		config: Config{
+			Bugs: ProtocolBugs{
+				SendSupportedVersions: []uint16{VersionTLS12, tls13DraftVersion},
+			},
+		},
+		expectedVersion: VersionTLS13,
+	})
+
 	// Test for version tolerance.
 	testCases = append(testCases, testCase{
 		testType: serverTest,
@@ -4715,6 +4852,8 @@
 			config: Config{
 				MaxVersion: ver.version,
 				NextProtos: []string{"foo", "bar", "baz"},
+				// Prior to TLS 1.3, exercise the asynchronous session callback.
+				SessionTicketsDisabled: ver.version < VersionTLS13,
 			},
 			flags: []string{
 				"-expect-advertised-alpn", "\x03foo\x03bar\x03baz",
@@ -4859,7 +4998,10 @@
 			config: Config{
 				MaxVersion: ver.version,
 				Bugs: ProtocolBugs{
-					CorruptTicket: true,
+					FilterTicket: func(in []byte) ([]byte, error) {
+						in[len(in)-1] ^= 1
+						return in, nil
+					},
 				},
 			},
 			resumeSession:        true,
@@ -4897,7 +5039,10 @@
 			config: Config{
 				MaxVersion: ver.version,
 				Bugs: ProtocolBugs{
-					CorruptTicket: true,
+					FilterTicket: func(in []byte) ([]byte, error) {
+						in[len(in)-1] ^= 1
+						return in, nil
+					},
 				},
 			},
 			resumeSession:        true,
@@ -5024,6 +5169,10 @@
 			resumeSession: true,
 		})
 
+		var differentSCTList []byte
+		differentSCTList = append(differentSCTList, testSCTList...)
+		differentSCTList[len(differentSCTList)-1] ^= 1
+
 		// The SCT extension did not specify that it must only be sent on resumption as it
 		// should have, so test that we tolerate but ignore it.
 		testCases = append(testCases, testCase{
@@ -5031,7 +5180,7 @@
 			config: Config{
 				MaxVersion: ver.version,
 				Bugs: ProtocolBugs{
-					SendSCTListOnResume: []byte("bogus"),
+					SendSCTListOnResume: differentSCTList,
 				},
 			},
 			flags: []string{
@@ -5055,6 +5204,61 @@
 			expectedSCTList: testSCTList,
 			resumeSession:   true,
 		})
+
+		emptySCTListCert := *testCerts[0].cert
+		emptySCTListCert.SignedCertificateTimestampList = []byte{0, 0}
+
+		// Test empty SCT list.
+		testCases = append(testCases, testCase{
+			name:     "SignedCertificateTimestampListEmpty-Client-" + ver.name,
+			testType: clientTest,
+			config: Config{
+				MaxVersion:   ver.version,
+				Certificates: []Certificate{emptySCTListCert},
+			},
+			flags: []string{
+				"-enable-signed-cert-timestamps",
+			},
+			shouldFail:    true,
+			expectedError: ":ERROR_PARSING_EXTENSION:",
+		})
+
+		emptySCTCert := *testCerts[0].cert
+		emptySCTCert.SignedCertificateTimestampList = []byte{0, 6, 0, 2, 1, 2, 0, 0}
+
+		// Test empty SCT in non-empty list.
+		testCases = append(testCases, testCase{
+			name:     "SignedCertificateTimestampListEmptySCT-Client-" + ver.name,
+			testType: clientTest,
+			config: Config{
+				MaxVersion:   ver.version,
+				Certificates: []Certificate{emptySCTCert},
+			},
+			flags: []string{
+				"-enable-signed-cert-timestamps",
+			},
+			shouldFail:    true,
+			expectedError: ":ERROR_PARSING_EXTENSION:",
+		})
+
+		// Test that certificate-related extensions are not sent unsolicited.
+		testCases = append(testCases, testCase{
+			testType: serverTest,
+			name:     "UnsolicitedCertificateExtensions-" + ver.name,
+			config: Config{
+				MaxVersion: ver.version,
+				Bugs: ProtocolBugs{
+					NoOCSPStapling:                true,
+					NoSignedCertificateTimestamps: true,
+				},
+			},
+			flags: []string{
+				"-ocsp-response",
+				base64.StdEncoding.EncodeToString(testOCSPResponse),
+				"-signed-cert-timestamps",
+				base64.StdEncoding.EncodeToString(testSCTList),
+			},
+		})
 	}
 
 	testCases = append(testCases, testCase{
@@ -5171,19 +5375,6 @@
 		expectedError: ":ERROR_PARSING_EXTENSION:",
 	})
 	testCases = append(testCases, testCase{
-		name: "ChannelID-Forbidden-TLS13",
-		config: Config{
-			MaxVersion:       VersionTLS13,
-			RequestChannelID: true,
-			Bugs: ProtocolBugs{
-				NegotiateChannelIDAtAllVersions: true,
-			},
-		},
-		flags:         []string{"-send-channel-id", path.Join(*resourceDir, channelIDKeyFile)},
-		shouldFail:    true,
-		expectedError: ":ERROR_PARSING_EXTENSION:",
-	})
-	testCases = append(testCases, testCase{
 		name: "Ticket-Forbidden-TLS13",
 		config: Config{
 			MaxVersion: VersionTLS12,
@@ -5205,15 +5396,6 @@
 	// implicit in every test.)
 	testCases = append(testCases, testCase{
 		testType: serverTest,
-		name:     "ChannelID-Declined-TLS13",
-		config: Config{
-			MaxVersion: VersionTLS13,
-			ChannelID:  channelIDKey,
-		},
-		flags: []string{"-enable-channel-id"},
-	})
-	testCases = append(testCases, testCase{
-		testType: serverTest,
 		name:     "NPN-Declined-TLS13",
 		config: Config{
 			MaxVersion: VersionTLS13,
@@ -5222,22 +5404,6 @@
 		flags: []string{"-advertise-npn", "\x03foo\x03bar\x03baz"},
 	})
 
-	testCases = append(testCases, testCase{
-		testType: serverTest,
-		name:     "InvalidChannelIDSignature",
-		config: Config{
-			MaxVersion: VersionTLS12,
-			ChannelID:  channelIDKey,
-			Bugs: ProtocolBugs{
-				InvalidChannelIDSignature: true,
-			},
-		},
-		flags:              []string{"-enable-channel-id"},
-		shouldFail:         true,
-		expectedError:      ":CHANNEL_ID_SIGNATURE_INVALID:",
-		expectedLocalError: "remote error: error decrypting message",
-	})
-
 	// OpenSSL sends the status_request extension on resumption in TLS 1.2. Test that this is
 	// tolerated.
 	testCases = append(testCases, testCase{
@@ -5256,23 +5422,154 @@
 		resumeSession: true,
 	})
 
-	// Beginning TLS 1.3, enforce this does not happen.
 	testCases = append(testCases, testCase{
-		name: "SendOCSPResponseOnResume-TLS13",
+		name: "SendUnsolicitedOCSPOnCertificate-TLS13",
 		config: Config{
 			MaxVersion: VersionTLS13,
 			Bugs: ProtocolBugs{
-				SendOCSPResponseOnResume: []byte("bogus"),
+				SendExtensionOnCertificate: testOCSPExtension,
+			},
+		},
+		shouldFail:    true,
+		expectedError: ":UNEXPECTED_EXTENSION:",
+	})
+
+	testCases = append(testCases, testCase{
+		name: "SendUnsolicitedSCTOnCertificate-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				SendExtensionOnCertificate: testSCTExtension,
+			},
+		},
+		shouldFail:    true,
+		expectedError: ":UNEXPECTED_EXTENSION:",
+	})
+
+	// Test that extensions on client certificates are never accepted.
+	testCases = append(testCases, testCase{
+		name:     "SendExtensionOnClientCertificate-TLS13",
+		testType: serverTest,
+		config: Config{
+			MaxVersion:   VersionTLS13,
+			Certificates: []Certificate{rsaCertificate},
+			Bugs: ProtocolBugs{
+				SendExtensionOnCertificate: testOCSPExtension,
+			},
+		},
+		flags: []string{
+			"-enable-ocsp-stapling",
+			"-require-any-client-certificate",
+		},
+		shouldFail:    true,
+		expectedError: ":UNEXPECTED_EXTENSION:",
+	})
+
+	testCases = append(testCases, testCase{
+		name: "SendUnknownExtensionOnCertificate-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				SendExtensionOnCertificate: []byte{0x00, 0x7f, 0, 0},
+			},
+		},
+		shouldFail:    true,
+		expectedError: ":UNEXPECTED_EXTENSION:",
+	})
+
+	var differentSCTList []byte
+	differentSCTList = append(differentSCTList, testSCTList...)
+	differentSCTList[len(differentSCTList)-1] ^= 1
+
+	// Test that extensions on intermediates are allowed but ignored.
+	testCases = append(testCases, testCase{
+		name: "IgnoreExtensionsOnIntermediates-TLS13",
+		config: Config{
+			MaxVersion:   VersionTLS13,
+			Certificates: []Certificate{rsaChainCertificate},
+			Bugs: ProtocolBugs{
+				// Send different values on the intermediate. This tests
+				// the intermediate's extensions do not override the
+				// leaf's.
+				SendOCSPOnIntermediates: []byte{1, 3, 3, 7},
+				SendSCTOnIntermediates:  differentSCTList,
 			},
 		},
 		flags: []string{
 			"-enable-ocsp-stapling",
 			"-expect-ocsp-response",
 			base64.StdEncoding.EncodeToString(testOCSPResponse),
+			"-enable-signed-cert-timestamps",
+			"-expect-signed-cert-timestamps",
+			base64.StdEncoding.EncodeToString(testSCTList),
+		},
+		resumeSession: true,
+	})
+
+	// Test that extensions are not sent on intermediates when configured
+	// only for a leaf.
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "SendNoExtensionsOnIntermediate-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				ExpectNoExtensionsOnIntermediate: true,
+			},
+		},
+		flags: []string{
+			"-cert-file", path.Join(*resourceDir, rsaChainCertificateFile),
+			"-key-file", path.Join(*resourceDir, rsaChainKeyFile),
+			"-ocsp-response",
+			base64.StdEncoding.EncodeToString(testOCSPResponse),
+			"-signed-cert-timestamps",
+			base64.StdEncoding.EncodeToString(testSCTList),
+		},
+	})
+
+	// Test that extensions are not sent on client certificates.
+	testCases = append(testCases, testCase{
+		name: "SendNoClientCertificateExtensions-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			ClientAuth: RequireAnyClientCert,
+		},
+		flags: []string{
+			"-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+			"-key-file", path.Join(*resourceDir, rsaKeyFile),
+			"-ocsp-response",
+			base64.StdEncoding.EncodeToString(testOCSPResponse),
+			"-signed-cert-timestamps",
+			base64.StdEncoding.EncodeToString(testSCTList),
+		},
+	})
+
+	testCases = append(testCases, testCase{
+		name: "SendDuplicateExtensionsOnCerts-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				SendDuplicateCertExtensions: true,
+			},
+		},
+		flags: []string{
+			"-enable-ocsp-stapling",
+			"-enable-signed-cert-timestamps",
 		},
 		resumeSession: true,
 		shouldFail:    true,
-		expectedError: ":ERROR_PARSING_EXTENSION:",
+		expectedError: ":DUPLICATE_EXTENSION:",
+	})
+
+	testCases = append(testCases, testCase{
+		name:     "SignedCertificateTimestampListInvalid-Server",
+		testType: serverTest,
+		flags: []string{
+			"-signed-cert-timestamps",
+			base64.StdEncoding.EncodeToString([]byte{0, 0}),
+		},
+		shouldFail: true,
+		expectedError: ":INVALID_SCT_LIST:",
 	})
 }
 
@@ -5381,6 +5678,223 @@
 		}
 	}
 
+	// Make sure shim ticket mutations are functional.
+	testCases = append(testCases, testCase{
+		testType:      serverTest,
+		name:          "ShimTicketRewritable",
+		resumeSession: true,
+		config: Config{
+			MaxVersion:   VersionTLS12,
+			CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+			Bugs: ProtocolBugs{
+				FilterTicket: func(in []byte) ([]byte, error) {
+					in, err := SetShimTicketVersion(in, VersionTLS12)
+					if err != nil {
+						return nil, err
+					}
+					return SetShimTicketCipherSuite(in, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256)
+				},
+			},
+		},
+		flags: []string{
+			"-ticket-key",
+			base64.StdEncoding.EncodeToString(TestShimTicketKey),
+		},
+	})
+
+	// Resumptions are declined if the version does not match.
+	testCases = append(testCases, testCase{
+		testType:      serverTest,
+		name:          "Resume-Server-DeclineCrossVersion",
+		resumeSession: true,
+		config: Config{
+			MaxVersion: VersionTLS12,
+			Bugs: ProtocolBugs{
+				ExpectNewTicket: true,
+				FilterTicket: func(in []byte) ([]byte, error) {
+					return SetShimTicketVersion(in, VersionTLS13)
+				},
+			},
+		},
+		flags: []string{
+			"-ticket-key",
+			base64.StdEncoding.EncodeToString(TestShimTicketKey),
+		},
+		expectResumeRejected: true,
+	})
+
+	testCases = append(testCases, testCase{
+		testType:      serverTest,
+		name:          "Resume-Server-DeclineCrossVersion-TLS13",
+		resumeSession: true,
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				FilterTicket: func(in []byte) ([]byte, error) {
+					return SetShimTicketVersion(in, VersionTLS12)
+				},
+			},
+		},
+		flags: []string{
+			"-ticket-key",
+			base64.StdEncoding.EncodeToString(TestShimTicketKey),
+		},
+		expectResumeRejected: true,
+	})
+
+	// Resumptions are declined if the cipher is invalid or disabled.
+	testCases = append(testCases, testCase{
+		testType:      serverTest,
+		name:          "Resume-Server-DeclineBadCipher",
+		resumeSession: true,
+		config: Config{
+			MaxVersion: VersionTLS12,
+			Bugs: ProtocolBugs{
+				ExpectNewTicket: true,
+				FilterTicket: func(in []byte) ([]byte, error) {
+					return SetShimTicketCipherSuite(in, TLS_AES_128_GCM_SHA256)
+				},
+			},
+		},
+		flags: []string{
+			"-ticket-key",
+			base64.StdEncoding.EncodeToString(TestShimTicketKey),
+		},
+		expectResumeRejected: true,
+	})
+
+	testCases = append(testCases, testCase{
+		testType:      serverTest,
+		name:          "Resume-Server-DeclineBadCipher-2",
+		resumeSession: true,
+		config: Config{
+			MaxVersion: VersionTLS12,
+			Bugs: ProtocolBugs{
+				ExpectNewTicket: true,
+				FilterTicket: func(in []byte) ([]byte, error) {
+					return SetShimTicketCipherSuite(in, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384)
+				},
+			},
+		},
+		flags: []string{
+			"-cipher", "AES128",
+			"-ticket-key",
+			base64.StdEncoding.EncodeToString(TestShimTicketKey),
+		},
+		expectResumeRejected: true,
+	})
+
+	// Sessions are not resumed if they do not use the preferred cipher.
+	testCases = append(testCases, testCase{
+		testType:      serverTest,
+		name:          "Resume-Server-CipherNotPreferred",
+		resumeSession: true,
+		config: Config{
+			MaxVersion: VersionTLS12,
+			Bugs: ProtocolBugs{
+				ExpectNewTicket: true,
+				FilterTicket: func(in []byte) ([]byte, error) {
+					return SetShimTicketCipherSuite(in, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA)
+				},
+			},
+		},
+		flags: []string{
+			"-ticket-key",
+			base64.StdEncoding.EncodeToString(TestShimTicketKey),
+		},
+		shouldFail:           false,
+		expectResumeRejected: true,
+	})
+
+	// TLS 1.3 allows sessions to be resumed at a different cipher if their
+	// PRF hashes match, but BoringSSL will always decline such resumptions.
+	testCases = append(testCases, testCase{
+		testType:      serverTest,
+		name:          "Resume-Server-CipherNotPreferred-TLS13",
+		resumeSession: true,
+		config: Config{
+			MaxVersion:   VersionTLS13,
+			CipherSuites: []uint16{TLS_CHACHA20_POLY1305_SHA256, TLS_AES_128_GCM_SHA256},
+			Bugs: ProtocolBugs{
+				FilterTicket: func(in []byte) ([]byte, error) {
+					// If the client (runner) offers ChaCha20-Poly1305 first, the
+					// server (shim) always prefers it. Switch it to AES-GCM.
+					return SetShimTicketCipherSuite(in, TLS_AES_128_GCM_SHA256)
+				},
+			},
+		},
+		flags: []string{
+			"-ticket-key",
+			base64.StdEncoding.EncodeToString(TestShimTicketKey),
+		},
+		shouldFail:           false,
+		expectResumeRejected: true,
+	})
+
+	// Sessions may not be resumed if they contain another version's cipher.
+	testCases = append(testCases, testCase{
+		testType:      serverTest,
+		name:          "Resume-Server-DeclineBadCipher-TLS13",
+		resumeSession: true,
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				FilterTicket: func(in []byte) ([]byte, error) {
+					return SetShimTicketCipherSuite(in, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256)
+				},
+			},
+		},
+		flags: []string{
+			"-ticket-key",
+			base64.StdEncoding.EncodeToString(TestShimTicketKey),
+		},
+		expectResumeRejected: true,
+	})
+
+	// If the client does not offer the cipher from the session, decline to
+	// resume. Clients are forbidden from doing this, but BoringSSL selects
+	// the cipher first, so we only decline.
+	testCases = append(testCases, testCase{
+		testType:      serverTest,
+		name:          "Resume-Server-UnofferedCipher",
+		resumeSession: true,
+		config: Config{
+			MaxVersion:   VersionTLS12,
+			CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256},
+		},
+		resumeConfig: &Config{
+			MaxVersion:   VersionTLS12,
+			CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256},
+			Bugs: ProtocolBugs{
+				SendCipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+			},
+		},
+		expectResumeRejected: true,
+	})
+
+	// In TLS 1.3, clients may advertise a cipher list which does not
+	// include the selected cipher. Test that we tolerate this. Servers may
+	// resume at another cipher if the PRF matches, but BoringSSL will
+	// always decline.
+	testCases = append(testCases, testCase{
+		testType:      serverTest,
+		name:          "Resume-Server-UnofferedCipher-TLS13",
+		resumeSession: true,
+		config: Config{
+			MaxVersion:   VersionTLS13,
+			CipherSuites: []uint16{TLS_CHACHA20_POLY1305_SHA256},
+		},
+		resumeConfig: &Config{
+			MaxVersion:   VersionTLS13,
+			CipherSuites: []uint16{TLS_CHACHA20_POLY1305_SHA256},
+			Bugs: ProtocolBugs{
+				SendCipherSuites: []uint16{TLS_AES_128_GCM_SHA256},
+			},
+		},
+		expectResumeRejected: true,
+	})
+
+	// Sessions may not be resumed at a different cipher.
 	testCases = append(testCases, testCase{
 		name:          "Resume-Client-CipherMismatch",
 		resumeSession: true,
@@ -5399,6 +5913,8 @@
 		expectedError: ":OLD_SESSION_CIPHER_NOT_RETURNED:",
 	})
 
+	// Session resumption in TLS 1.3 may change the cipher suite if the PRF
+	// matches.
 	testCases = append(testCases, testCase{
 		name:          "Resume-Client-CipherMismatch-TLS13",
 		resumeSession: true,
@@ -5408,13 +5924,87 @@
 		},
 		resumeConfig: &Config{
 			MaxVersion:   VersionTLS13,
+			CipherSuites: []uint16{TLS_CHACHA20_POLY1305_SHA256},
+		},
+	})
+
+	// Session resumption in TLS 1.3 is forbidden if the PRF does not match.
+	testCases = append(testCases, testCase{
+		name:          "Resume-Client-PRFMismatch-TLS13",
+		resumeSession: true,
+		config: Config{
+			MaxVersion:   VersionTLS13,
+			CipherSuites: []uint16{TLS_AES_128_GCM_SHA256},
+		},
+		resumeConfig: &Config{
+			MaxVersion:   VersionTLS13,
 			CipherSuites: []uint16{TLS_AES_128_GCM_SHA256},
 			Bugs: ProtocolBugs{
 				SendCipherSuite: TLS_AES_256_GCM_SHA384,
 			},
 		},
 		shouldFail:    true,
-		expectedError: ":OLD_SESSION_CIPHER_NOT_RETURNED:",
+		expectedError: ":OLD_SESSION_PRF_HASH_MISMATCH:",
+	})
+
+	testCases = append(testCases, testCase{
+		testType:      serverTest,
+		name:          "Resume-Server-BinderWrongLength",
+		resumeSession: true,
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				SendShortPSKBinder: true,
+			},
+		},
+		shouldFail:         true,
+		expectedLocalError: "remote error: error decrypting message",
+		expectedError:      ":DIGEST_CHECK_FAILED:",
+	})
+
+	testCases = append(testCases, testCase{
+		testType:      serverTest,
+		name:          "Resume-Server-NoPSKBinder",
+		resumeSession: true,
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				SendNoPSKBinder: true,
+			},
+		},
+		shouldFail:         true,
+		expectedLocalError: "remote error: error decoding message",
+		expectedError:      ":DECODE_ERROR:",
+	})
+
+	testCases = append(testCases, testCase{
+		testType:      serverTest,
+		name:          "Resume-Server-InvalidPSKBinder",
+		resumeSession: true,
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				SendInvalidPSKBinder: true,
+			},
+		},
+		shouldFail:         true,
+		expectedLocalError: "remote error: error decrypting message",
+		expectedError:      ":DIGEST_CHECK_FAILED:",
+	})
+
+	testCases = append(testCases, testCase{
+		testType:      serverTest,
+		name:          "Resume-Server-PSKBinderFirstExtension",
+		resumeSession: true,
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				PSKBinderFirst: true,
+			},
+		},
+		shouldFail:         true,
+		expectedLocalError: "remote error: illegal parameter",
+		expectedError:      ":PRE_SHARED_KEY_MUST_BE_LAST:",
 	})
 }
 
@@ -5579,6 +6169,8 @@
 			CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA},
 			Bugs: ProtocolBugs{
 				NegotiateVersionOnRenego: VersionTLS11,
+				// Avoid failing early at the record layer.
+				SendRecordVersion: VersionTLS12,
 			},
 		},
 		renegotiate: 1,
@@ -6874,6 +7466,7 @@
 			useExportContext:     true,
 		})
 	}
+
 	testCases = append(testCases, testCase{
 		name: "ExportKeyingMaterial-SSL3",
 		config: Config{
@@ -6886,6 +7479,47 @@
 		shouldFail:           true,
 		expectedError:        "failed to export keying material",
 	})
+
+	// Exporters work during a False Start.
+	testCases = append(testCases, testCase{
+		name: "ExportKeyingMaterial-FalseStart",
+		config: Config{
+			MaxVersion:   VersionTLS12,
+			CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+			NextProtos:   []string{"foo"},
+			Bugs: ProtocolBugs{
+				ExpectFalseStart: true,
+			},
+		},
+		flags: []string{
+			"-false-start",
+			"-advertise-alpn", "\x03foo",
+		},
+		shimWritesFirst:      true,
+		exportKeyingMaterial: 1024,
+		exportLabel:          "label",
+		exportContext:        "context",
+		useExportContext:     true,
+	})
+
+	// Exporters do not work in the middle of a renegotiation. Test this by
+	// triggering the exporter after every SSL_read call and configuring the
+	// shim to run asynchronously.
+	testCases = append(testCases, testCase{
+		name: "ExportKeyingMaterial-Renegotiate",
+		config: Config{
+			MaxVersion: VersionTLS12,
+		},
+		renegotiate: 1,
+		flags: []string{
+			"-async",
+			"-use-exporter-between-reads",
+			"-renegotiate-freely",
+			"-expect-total-renegotiations", "1",
+		},
+		shouldFail:    true,
+		expectedError: "failed to export keying material",
+	})
 }
 
 func addTLSUniqueTests() {
@@ -7636,19 +8270,34 @@
 			MaxVersion: VersionTLS13,
 			Bugs: ProtocolBugs{
 				SendPSKKeyExchangeModes: []byte{0x1a, pskDHEKEMode, 0x2a},
-				SendPSKAuthModes:        []byte{0x1a, pskAuthMode, 0x2a},
 			},
 		},
 		resumeSession:         true,
 		expectedResumeVersion: VersionTLS13,
 	})
 
-	// Test that the server declines sessions with no matching key exchange mode.
+	// Test that the server does not send session tickets with no matching key exchange mode.
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "TLS13-ExpectNoSessionTicketOnBadKEMode-Server",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				SendPSKKeyExchangeModes:  []byte{0x1a},
+				ExpectNoNewSessionTicket: true,
+			},
+		},
+	})
+
+	// Test that the server does not accept a session with no matching key exchange mode.
 	testCases = append(testCases, testCase{
 		testType: serverTest,
 		name:     "TLS13-SendBadKEModeSessionTicket-Server",
 		config: Config{
 			MaxVersion: VersionTLS13,
+		},
+		resumeConfig: &Config{
+			MaxVersion: VersionTLS13,
 			Bugs: ProtocolBugs{
 				SendPSKKeyExchangeModes: []byte{0x1a},
 			},
@@ -7657,60 +8306,37 @@
 		expectResumeRejected: true,
 	})
 
-	// Test that the server declines sessions with no matching auth mode.
-	testCases = append(testCases, testCase{
-		testType: serverTest,
-		name:     "TLS13-SendBadAuthModeSessionTicket-Server",
-		config: Config{
-			MaxVersion: VersionTLS13,
-			Bugs: ProtocolBugs{
-				SendPSKAuthModes: []byte{0x1a},
-			},
-		},
-		resumeSession:        true,
-		expectResumeRejected: true,
-	})
-
-	// Test that the client ignores unknown PSK modes.
+	// Test that the client ticket age is sent correctly.
 	testCases = append(testCases, testCase{
 		testType: clientTest,
-		name:     "TLS13-SendUnknownModeSessionTicket-Client",
+		name:     "TLS13-TestValidTicketAge-Client",
 		config: Config{
 			MaxVersion: VersionTLS13,
 			Bugs: ProtocolBugs{
-				SendPSKKeyExchangeModes: []byte{0x1a, pskDHEKEMode, 0x2a},
-				SendPSKAuthModes:        []byte{0x1a, pskAuthMode, 0x2a},
+				ExpectTicketAge: 10 * time.Second,
 			},
 		},
-		resumeSession:         true,
-		expectedResumeVersion: VersionTLS13,
+		resumeSession: true,
+		flags: []string{
+			"-resumption-delay", "10",
+		},
 	})
 
-	// Test that the client ignores tickets with no matching key exchange mode.
+	// Test that the client ticket age is enforced.
 	testCases = append(testCases, testCase{
 		testType: clientTest,
-		name:     "TLS13-SendBadKEModeSessionTicket-Client",
+		name:     "TLS13-TestBadTicketAge-Client",
 		config: Config{
 			MaxVersion: VersionTLS13,
 			Bugs: ProtocolBugs{
-				SendPSKKeyExchangeModes: []byte{0x1a},
+				ExpectTicketAge: 1000 * time.Second,
 			},
 		},
-		flags: []string{"-expect-no-session"},
+		resumeSession:      true,
+		shouldFail:         true,
+		expectedLocalError: "tls: invalid ticket age",
 	})
 
-	// Test that the client ignores tickets with no matching auth mode.
-	testCases = append(testCases, testCase{
-		testType: clientTest,
-		name:     "TLS13-SendBadAuthModeSessionTicket-Client",
-		config: Config{
-			MaxVersion: VersionTLS13,
-			Bugs: ProtocolBugs{
-				SendPSKAuthModes: []byte{0x1a},
-			},
-		},
-		flags: []string{"-expect-no-session"},
-	})
 }
 
 func addChangeCipherSpecTests() {
@@ -8369,33 +8995,6 @@
 
 	testCases = append(testCases, testCase{
 		testType: clientTest,
-		name:     "OmitServerHelloSignatureAlgorithms",
-		config: Config{
-			MaxVersion: VersionTLS13,
-			Bugs: ProtocolBugs{
-				OmitServerHelloSignatureAlgorithms: true,
-			},
-		},
-		shouldFail:    true,
-		expectedError: ":UNEXPECTED_EXTENSION:",
-	})
-
-	testCases = append(testCases, testCase{
-		testType: clientTest,
-		name:     "IncludeServerHelloSignatureAlgorithms",
-		config: Config{
-			MaxVersion: VersionTLS13,
-			Bugs: ProtocolBugs{
-				IncludeServerHelloSignatureAlgorithms: true,
-			},
-		},
-		resumeSession: true,
-		shouldFail:    true,
-		expectedError: ":UNEXPECTED_EXTENSION:",
-	})
-
-	testCases = append(testCases, testCase{
-		testType: clientTest,
 		name:     "MissingKeyShare-Client",
 		config: Config{
 			MaxVersion: VersionTLS13,
@@ -8759,6 +9358,18 @@
 		expectedError: ":PSK_IDENTITY_NOT_FOUND:",
 	})
 
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "TLS13-ExtraPSKIdentity",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				ExtraPSKIdentity: true,
+			},
+		},
+		resumeSession: true,
+	})
+
 	// Test that unknown NewSessionTicket extensions are tolerated.
 	testCases = append(testCases, testCase{
 		name: "TLS13-CustomTicketExtension",
@@ -8771,6 +9382,58 @@
 	})
 }
 
+func addTLS13CipherPreferenceTests() {
+	// Test that client preference is honored if the shim has AES hardware
+	// and ChaCha20-Poly1305 is preferred otherwise.
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "TLS13-CipherPreference-Server-ChaCha20-AES",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			CipherSuites: []uint16{
+				TLS_CHACHA20_POLY1305_SHA256,
+				TLS_AES_128_GCM_SHA256,
+			},
+		},
+		flags: []string{
+			"-expect-cipher-aes", strconv.Itoa(int(TLS_CHACHA20_POLY1305_SHA256)),
+			"-expect-cipher-no-aes", strconv.Itoa(int(TLS_CHACHA20_POLY1305_SHA256)),
+		},
+	})
+
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "TLS13-CipherPreference-Server-AES-ChaCha20",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			CipherSuites: []uint16{
+				TLS_AES_128_GCM_SHA256,
+				TLS_CHACHA20_POLY1305_SHA256,
+			},
+		},
+		flags: []string{
+			"-expect-cipher-aes", strconv.Itoa(int(TLS_AES_128_GCM_SHA256)),
+			"-expect-cipher-no-aes", strconv.Itoa(int(TLS_CHACHA20_POLY1305_SHA256)),
+		},
+	})
+
+	// Test that the client orders ChaCha20-Poly1305 and AES-GCM based on
+	// whether it has AES hardware.
+	testCases = append(testCases, testCase{
+		name: "TLS13-CipherPreference-Client",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			// Use the client cipher order. (This is the default but
+			// is listed to be explicit.)
+			PreferServerCipherSuites: false,
+		},
+		flags: []string{
+			"-expect-cipher-aes", strconv.Itoa(int(TLS_AES_128_GCM_SHA256)),
+			"-expect-cipher-no-aes", strconv.Itoa(int(TLS_CHACHA20_POLY1305_SHA256)),
+		},
+	})
+}
+
 func addPeekTests() {
 	// Test SSL_peek works, including on empty records.
 	testCases = append(testCases, testCase{
@@ -8841,16 +9504,177 @@
 	})
 }
 
+func addRecordVersionTests() {
+	for _, ver := range tlsVersions {
+		// Test that the record version is enforced.
+		testCases = append(testCases, testCase{
+			name: "CheckRecordVersion-" + ver.name,
+			config: Config{
+				MinVersion: ver.version,
+				MaxVersion: ver.version,
+				Bugs: ProtocolBugs{
+					SendRecordVersion: 0x03ff,
+				},
+			},
+			shouldFail:    true,
+			expectedError: ":WRONG_VERSION_NUMBER:",
+		})
+
+		// Test that the ClientHello may use any record version, for
+		// compatibility reasons.
+		testCases = append(testCases, testCase{
+			testType: serverTest,
+			name:     "LooseInitialRecordVersion-" + ver.name,
+			config: Config{
+				MinVersion: ver.version,
+				MaxVersion: ver.version,
+				Bugs: ProtocolBugs{
+					SendInitialRecordVersion: 0x03ff,
+				},
+			},
+		})
+
+		// Test that garbage ClientHello record versions are rejected.
+		testCases = append(testCases, testCase{
+			testType: serverTest,
+			name:     "GarbageInitialRecordVersion-" + ver.name,
+			config: Config{
+				MinVersion: ver.version,
+				MaxVersion: ver.version,
+				Bugs: ProtocolBugs{
+					SendInitialRecordVersion: 0xffff,
+				},
+			},
+			shouldFail:    true,
+			expectedError: ":WRONG_VERSION_NUMBER:",
+		})
+	}
+}
+
+func addCertificateTests() {
+	// Test that a certificate chain with intermediate may be sent and
+	// received as both client and server.
+	for _, ver := range tlsVersions {
+		testCases = append(testCases, testCase{
+			testType: clientTest,
+			name:     "SendReceiveIntermediate-Client-" + ver.name,
+			config: Config{
+				Certificates: []Certificate{rsaChainCertificate},
+				ClientAuth:   RequireAnyClientCert,
+			},
+			expectPeerCertificate: &rsaChainCertificate,
+			flags: []string{
+				"-cert-file", path.Join(*resourceDir, rsaChainCertificateFile),
+				"-key-file", path.Join(*resourceDir, rsaChainKeyFile),
+				"-expect-peer-cert-file", path.Join(*resourceDir, rsaChainCertificateFile),
+			},
+		})
+
+		testCases = append(testCases, testCase{
+			testType: serverTest,
+			name:     "SendReceiveIntermediate-Server-" + ver.name,
+			config: Config{
+				Certificates: []Certificate{rsaChainCertificate},
+			},
+			expectPeerCertificate: &rsaChainCertificate,
+			flags: []string{
+				"-cert-file", path.Join(*resourceDir, rsaChainCertificateFile),
+				"-key-file", path.Join(*resourceDir, rsaChainKeyFile),
+				"-require-any-client-certificate",
+				"-expect-peer-cert-file", path.Join(*resourceDir, rsaChainCertificateFile),
+			},
+		})
+	}
+}
+
+func addRetainOnlySHA256ClientCertTests() {
+	for _, ver := range tlsVersions {
+		// Test that enabling
+		// SSL_CTX_set_retain_only_sha256_of_client_certs without
+		// actually requesting a client certificate is a no-op.
+		testCases = append(testCases, testCase{
+			testType: serverTest,
+			name:     "RetainOnlySHA256-NoCert-" + ver.name,
+			config: Config{
+				MinVersion: ver.version,
+				MaxVersion: ver.version,
+			},
+			flags: []string{
+				"-retain-only-sha256-client-cert-initial",
+				"-retain-only-sha256-client-cert-resume",
+			},
+			resumeSession: true,
+		})
+
+		// Test that when retaining only a SHA-256 certificate is
+		// enabled, the hash appears as expected.
+		testCases = append(testCases, testCase{
+			testType: serverTest,
+			name:     "RetainOnlySHA256-Cert-" + ver.name,
+			config: Config{
+				MinVersion:   ver.version,
+				MaxVersion:   ver.version,
+				Certificates: []Certificate{rsaCertificate},
+			},
+			flags: []string{
+				"-verify-peer",
+				"-retain-only-sha256-client-cert-initial",
+				"-retain-only-sha256-client-cert-resume",
+				"-expect-sha256-client-cert-initial",
+				"-expect-sha256-client-cert-resume",
+			},
+			resumeSession: true,
+		})
+
+		// Test that when the config changes from on to off, a
+		// resumption is rejected because the server now wants the full
+		// certificate chain.
+		testCases = append(testCases, testCase{
+			testType: serverTest,
+			name:     "RetainOnlySHA256-OnOff-" + ver.name,
+			config: Config{
+				MinVersion:   ver.version,
+				MaxVersion:   ver.version,
+				Certificates: []Certificate{rsaCertificate},
+			},
+			flags: []string{
+				"-verify-peer",
+				"-retain-only-sha256-client-cert-initial",
+				"-expect-sha256-client-cert-initial",
+			},
+			resumeSession:        true,
+			expectResumeRejected: true,
+		})
+
+		// Test that when the config changes from off to on, a
+		// resumption is rejected because the server now wants just the
+		// hash.
+		testCases = append(testCases, testCase{
+			testType: serverTest,
+			name:     "RetainOnlySHA256-OffOn-" + ver.name,
+			config: Config{
+				MinVersion:   ver.version,
+				MaxVersion:   ver.version,
+				Certificates: []Certificate{rsaCertificate},
+			},
+			flags: []string{
+				"-verify-peer",
+				"-retain-only-sha256-client-cert-resume",
+				"-expect-sha256-client-cert-resume",
+			},
+			resumeSession:        true,
+			expectResumeRejected: true,
+		})
+	}
+}
+
 func worker(statusChan chan statusMsg, c chan *testCase, shimPath string, wg *sync.WaitGroup) {
 	defer wg.Done()
 
 	for test := range c {
 		var err error
 
-		if *mallocTest < 0 {
-			statusChan <- statusMsg{test: test, started: true}
-			err = runTest(test, shimPath, -1)
-		} else {
+		if *mallocTest >= 0 {
 			for mallocNumToFail := int64(*mallocTest); ; mallocNumToFail++ {
 				statusChan <- statusMsg{test: test, started: true}
 				if err = runTest(test, shimPath, mallocNumToFail); err != errMoreMallocs {
@@ -8860,6 +9684,14 @@
 					break
 				}
 			}
+		} else if *repeatUntilFailure {
+			for err == nil {
+				statusChan <- statusMsg{test: test, started: true}
+				err = runTest(test, shimPath, -1)
+			}
+		} else {
+			statusChan <- statusMsg{test: test, started: true}
+			err = runTest(test, shimPath, -1)
 		}
 		statusChan <- statusMsg{test: test, err: err}
 	}
@@ -8958,7 +9790,11 @@
 	addWrongMessageTypeTests()
 	addTrailingMessageDataTests()
 	addTLS13HandshakeTests()
+	addTLS13CipherPreferenceTests()
 	addPeekTests()
+	addRecordVersionTests()
+	addCertificateTests()
+	addRetainOnlySHA256ClientCertTests()
 
 	var wg sync.WaitGroup
 
@@ -9016,6 +9852,11 @@
 		if matched {
 			foundTest = true
 			testChan <- &testCases[i]
+
+			// Only run one test if repeating until failure.
+			if *repeatUntilFailure {
+				break
+			}
 		}
 	}
 
diff --git a/src/ssl/test/runner/shim_ticket.go b/src/ssl/test/runner/shim_ticket.go
new file mode 100644
index 0000000..9e57d48
--- /dev/null
+++ b/src/ssl/test/runner/shim_ticket.go
@@ -0,0 +1,249 @@
+// Copyright (c) 2016, Google Inc.
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+package runner
+
+import (
+	"bytes"
+	"crypto/aes"
+	"crypto/cipher"
+	"crypto/hmac"
+	"crypto/sha256"
+	"encoding/asn1"
+	"errors"
+)
+
+// TestShimTicketKey is the testing key assumed for the shim.
+var TestShimTicketKey = make([]byte, 48)
+
+func DecryptShimTicket(in []byte) ([]byte, error) {
+	name := TestShimTicketKey[:16]
+	macKey := TestShimTicketKey[16:32]
+	encKey := TestShimTicketKey[32:48]
+
+	h := hmac.New(sha256.New, macKey)
+
+	block, err := aes.NewCipher(encKey)
+	if err != nil {
+		panic(err)
+	}
+
+	if len(in) < len(name)+block.BlockSize()+1+h.Size() {
+		return nil, errors.New("tls: shim ticket too short")
+	}
+
+	// Check the key name.
+	if !bytes.Equal(name, in[:len(name)]) {
+		return nil, errors.New("tls: shim ticket name mismatch")
+	}
+
+	// Check the MAC at the end of the ticket.
+	mac := in[len(in)-h.Size():]
+	in = in[:len(in)-h.Size()]
+	h.Write(in)
+	if !hmac.Equal(mac, h.Sum(nil)) {
+		return nil, errors.New("tls: shim ticket MAC mismatch")
+	}
+
+	// The MAC covers the key name, but the encryption does not.
+	in = in[len(name):]
+
+	// Decrypt in-place.
+	iv := in[:block.BlockSize()]
+	in = in[block.BlockSize():]
+	if l := len(in); l == 0 || l%block.BlockSize() != 0 {
+		return nil, errors.New("tls: ticket ciphertext not a multiple of the block size")
+	}
+	out := make([]byte, len(in))
+	cbc := cipher.NewCBCDecrypter(block, iv)
+	cbc.CryptBlocks(out, in)
+
+	// Remove the padding.
+	pad := int(out[len(out)-1])
+	if pad == 0 || pad > block.BlockSize() || pad > len(in) {
+		return nil, errors.New("tls: bad shim ticket CBC pad")
+	}
+
+	for i := 0; i < pad; i++ {
+		if out[len(out)-1-i] != byte(pad) {
+			return nil, errors.New("tls: bad shim ticket CBC pad")
+		}
+	}
+
+	return out[:len(out)-pad], nil
+}
+
+func EncryptShimTicket(in []byte) []byte {
+	name := TestShimTicketKey[:16]
+	macKey := TestShimTicketKey[16:32]
+	encKey := TestShimTicketKey[32:48]
+
+	h := hmac.New(sha256.New, macKey)
+
+	block, err := aes.NewCipher(encKey)
+	if err != nil {
+		panic(err)
+	}
+
+	// Use the zero IV for rewritten tickets.
+	iv := make([]byte, block.BlockSize())
+	cbc := cipher.NewCBCEncrypter(block, iv)
+	pad := block.BlockSize() - (len(in) % block.BlockSize())
+
+	out := make([]byte, 0, len(name)+len(iv)+len(in)+pad+h.Size())
+	out = append(out, name...)
+	out = append(out, iv...)
+	out = append(out, in...)
+	for i := 0; i < pad; i++ {
+		out = append(out, byte(pad))
+	}
+
+	ciphertext := out[len(name)+len(iv):]
+	cbc.CryptBlocks(ciphertext, ciphertext)
+
+	h.Write(out)
+	return h.Sum(out)
+}
+
+const asn1Constructed = 0x20
+
+func parseDERElement(in []byte) (tag byte, body, rest []byte, ok bool) {
+	rest = in
+	if len(rest) < 1 {
+		return
+	}
+
+	tag = rest[0]
+	rest = rest[1:]
+
+	if tag&0x1f == 0x1f {
+		// Long-form tags not supported.
+		return
+	}
+
+	if len(rest) < 1 {
+		return
+	}
+
+	length := int(rest[0])
+	rest = rest[1:]
+	if length > 0x7f {
+		lengthLength := length & 0x7f
+		length = 0
+		if lengthLength == 0 {
+			// No indefinite-length encoding.
+			return
+		}
+
+		// Decode long-form lengths.
+		for lengthLength > 0 {
+			if len(rest) < 1 || (length<<8)>>8 != length {
+				return
+			}
+			if length == 0 && rest[0] == 0 {
+				// Length not minimally-encoded.
+				return
+			}
+			length <<= 8
+			length |= int(rest[0])
+			rest = rest[1:]
+			lengthLength--
+		}
+
+		if length < 0x80 {
+			// Length not minimally-encoded.
+			return
+		}
+	}
+
+	if len(rest) < length {
+		return
+	}
+
+	body = rest[:length]
+	rest = rest[length:]
+	ok = true
+	return
+}
+
+func SetShimTicketVersion(in []byte, vers uint16) ([]byte, error) {
+	plaintext, err := DecryptShimTicket(in)
+	if err != nil {
+		return nil, err
+	}
+
+	tag, session, _, ok := parseDERElement(plaintext)
+	if !ok || tag != asn1.TagSequence|asn1Constructed {
+		return nil, errors.New("tls: could not decode shim session")
+	}
+
+	// Skip the session version.
+	tag, _, session, ok = parseDERElement(session)
+	if !ok || tag != asn1.TagInteger {
+		return nil, errors.New("tls: could not decode shim session")
+	}
+
+	// Next field is the protocol version.
+	tag, version, _, ok := parseDERElement(session)
+	if !ok || tag != asn1.TagInteger {
+		return nil, errors.New("tls: could not decode shim session")
+	}
+
+	// This code assumes both old and new versions are encoded in two
+	// bytes. This isn't quite right as INTEGERs are minimally-encoded, but
+	// we do not need to support other caess for now.
+	if len(version) != 2 || vers < 0x80 || vers >= 0x8000 {
+		return nil, errors.New("tls: unsupported version in shim session")
+	}
+
+	version[0] = byte(vers >> 8)
+	version[1] = byte(vers)
+
+	return EncryptShimTicket(plaintext), nil
+}
+
+func SetShimTicketCipherSuite(in []byte, id uint16) ([]byte, error) {
+	plaintext, err := DecryptShimTicket(in)
+	if err != nil {
+		return nil, err
+	}
+
+	tag, session, _, ok := parseDERElement(plaintext)
+	if !ok || tag != asn1.TagSequence|asn1Constructed {
+		return nil, errors.New("tls: could not decode shim session")
+	}
+
+	// Skip the session version.
+	tag, _, session, ok = parseDERElement(session)
+	if !ok || tag != asn1.TagInteger {
+		return nil, errors.New("tls: could not decode shim session")
+	}
+
+	// Skip the protocol version.
+	tag, _, session, ok = parseDERElement(session)
+	if !ok || tag != asn1.TagInteger {
+		return nil, errors.New("tls: could not decode shim session")
+	}
+
+	// Next field is the cipher suite.
+	tag, cipherSuite, _, ok := parseDERElement(session)
+	if !ok || tag != asn1.TagOctetString || len(cipherSuite) != 2 {
+		return nil, errors.New("tls: could not decode shim session")
+	}
+
+	cipherSuite[0] = byte(id >> 8)
+	cipherSuite[1] = byte(id)
+
+	return EncryptShimTicket(plaintext), nil
+}
diff --git a/src/ssl/test/test_config.cc b/src/ssl/test/test_config.cc
index 425664d..940e676 100644
--- a/src/ssl/test/test_config.cc
+++ b/src/ssl/test/test_config.cc
@@ -75,6 +75,7 @@
   { "-install-ddos-callback", &TestConfig::install_ddos_callback },
   { "-fail-ddos-callback", &TestConfig::fail_ddos_callback },
   { "-fail-second-ddos-callback", &TestConfig::fail_second_ddos_callback },
+  { "-fail-cert-callback", &TestConfig::fail_cert_callback },
   { "-handshake-never-done", &TestConfig::handshake_never_done },
   { "-use-export-context", &TestConfig::use_export_context },
   { "-tls-unique", &TestConfig::tls_unique },
@@ -106,6 +107,15 @@
   { "-send-alert", &TestConfig::send_alert },
   { "-peek-then-read", &TestConfig::peek_then_read },
   { "-enable-grease", &TestConfig::enable_grease },
+  { "-use-exporter-between-reads", &TestConfig::use_exporter_between_reads },
+  { "-retain-only-sha256-client-cert-initial",
+    &TestConfig::retain_only_sha256_client_cert_initial },
+  { "-retain-only-sha256-client-cert-resume",
+    &TestConfig::retain_only_sha256_client_cert_resume },
+  { "-expect-sha256-client-cert-initial",
+    &TestConfig::expect_sha256_client_cert_initial },
+  { "-expect-sha256-client-cert-resume",
+    &TestConfig::expect_sha256_client_cert_resume },
 };
 
 const Flag<std::string> kStringFlags[] = {
@@ -130,6 +140,7 @@
   { "-cipher-tls11", &TestConfig::cipher_tls11 },
   { "-export-label", &TestConfig::export_label },
   { "-export-context", &TestConfig::export_context },
+  { "-expect-peer-cert-file", &TestConfig::expect_peer_cert_file },
 };
 
 const Flag<std::string> kBase64Flags[] = {
@@ -140,6 +151,7 @@
     &TestConfig::expected_signed_cert_timestamps },
   { "-ocsp-response", &TestConfig::ocsp_response },
   { "-signed-cert-timestamps", &TestConfig::signed_cert_timestamps },
+  { "-ticket-key", &TestConfig::ticket_key },
 };
 
 const Flag<int> kIntFlags[] = {
@@ -156,6 +168,9 @@
   { "-expect-dhe-group-size", &TestConfig::expect_dhe_group_size },
   { "-initial-timeout-duration-ms", &TestConfig::initial_timeout_duration_ms },
   { "-max-cert-list", &TestConfig::max_cert_list },
+  { "-expect-cipher-aes", &TestConfig::expect_cipher_aes },
+  { "-expect-cipher-no-aes", &TestConfig::expect_cipher_no_aes },
+  { "-resumption-delay", &TestConfig::resumption_delay },
 };
 
 const Flag<std::vector<int>> kIntVectorFlags[] = {
diff --git a/src/ssl/test/test_config.h b/src/ssl/test/test_config.h
index 9f74297..ed1a47b 100644
--- a/src/ssl/test/test_config.h
+++ b/src/ssl/test/test_config.h
@@ -73,6 +73,7 @@
   bool install_ddos_callback = false;
   bool fail_ddos_callback = false;
   bool fail_second_ddos_callback = false;
+  bool fail_cert_callback = false;
   std::string cipher;
   std::string cipher_tls10;
   std::string cipher_tls11;
@@ -115,6 +116,16 @@
   bool peek_then_read = false;
   bool enable_grease = false;
   int max_cert_list = 0;
+  std::string ticket_key;
+  bool use_exporter_between_reads = false;
+  int expect_cipher_aes = 0;
+  int expect_cipher_no_aes = 0;
+  std::string expect_peer_cert_file;
+  int resumption_delay = 0;
+  bool retain_only_sha256_client_cert_initial = false;
+  bool retain_only_sha256_client_cert_resume = false;
+  bool expect_sha256_client_cert_initial = false;
+  bool expect_sha256_client_cert_resume = false;
 };
 
 bool ParseConfig(int argc, char **argv, TestConfig *out_config);
diff --git a/src/ssl/tls13_both.c b/src/ssl/tls13_both.c
index e32464d..17f7161 100644
--- a/src/ssl/tls13_both.c
+++ b/src/ssl/tls13_both.c
@@ -25,6 +25,7 @@
 #include <openssl/x509.h>
 #include <openssl/x509v3.h>
 
+#include "../crypto/internal.h"
 #include "internal.h"
 
 
@@ -79,6 +80,11 @@
         hs->wait = ssl_hs_ok;
         return -1;
 
+      case ssl_hs_channel_id_lookup:
+        ssl->rwstate = SSL_CHANNEL_ID_LOOKUP;
+        hs->wait = ssl_hs_ok;
+        return -1;
+
       case ssl_hs_private_key_operation:
         ssl->rwstate = SSL_PRIVATE_KEY_OPERATION;
         hs->wait = ssl_hs_ok;
@@ -105,8 +111,9 @@
   }
 }
 
-static int tls13_get_cert_verify_signature_input(SSL *ssl, uint8_t **out,
-                                                 size_t *out_len, int server) {
+int tls13_get_cert_verify_signature_input(
+    SSL *ssl, uint8_t **out, size_t *out_len,
+    enum ssl_cert_verify_context_t cert_verify_context) {
   CBB cbb;
   if (!CBB_init(&cbb, 64 + 33 + 1 + 2 * EVP_MAX_MD_SIZE)) {
     goto err;
@@ -118,23 +125,33 @@
     }
   }
 
-  if (server) {
+  const uint8_t *context;
+  size_t context_len;
+  if (cert_verify_context == ssl_cert_verify_server) {
     /* Include the NUL byte. */
     static const char kContext[] = "TLS 1.3, server CertificateVerify";
-    if (!CBB_add_bytes(&cbb, (const uint8_t *)kContext, sizeof(kContext))) {
-      goto err;
-    }
-  } else {
+    context = (const uint8_t *)kContext;
+    context_len = sizeof(kContext);
+  } else if (cert_verify_context == ssl_cert_verify_client) {
     static const char kContext[] = "TLS 1.3, client CertificateVerify";
-    if (!CBB_add_bytes(&cbb, (const uint8_t *)kContext, sizeof(kContext))) {
-      goto err;
-    }
+    context = (const uint8_t *)kContext;
+    context_len = sizeof(kContext);
+  } else if (cert_verify_context == ssl_cert_verify_channel_id) {
+    static const char kContext[] = "TLS 1.3, Channel ID";
+    context = (const uint8_t *)kContext;
+    context_len = sizeof(kContext);
+  } else {
+    goto err;
   }
 
-  uint8_t context_hashes[2 * EVP_MAX_MD_SIZE];
-  size_t context_hashes_len;
-  if (!tls13_get_context_hashes(ssl, context_hashes, &context_hashes_len) ||
-      !CBB_add_bytes(&cbb, context_hashes, context_hashes_len) ||
+  if (!CBB_add_bytes(&cbb, context, context_len)) {
+    goto err;
+  }
+
+  uint8_t context_hash[EVP_MAX_MD_SIZE];
+  size_t context_hash_len;
+  if (!tls13_get_context_hash(ssl, context_hash, &context_hash_len) ||
+      !CBB_add_bytes(&cbb, context_hash, context_hash_len) ||
       !CBB_finish(&cbb, out, out_len)) {
     goto err;
   }
@@ -148,7 +165,7 @@
 }
 
 int tls13_process_certificate(SSL *ssl, int allow_anonymous) {
-  CBS cbs, context;
+  CBS cbs, context, certificate_list;
   CBS_init(&cbs, ssl->init_msg, ssl->init_num);
   if (!CBS_get_u8_length_prefixed(&cbs, &context) ||
       CBS_len(&context) != 0) {
@@ -158,17 +175,117 @@
   }
 
   const int retain_sha256 =
-      ssl->server && ssl->ctx->retain_only_sha256_of_client_certs;
+      ssl->server && ssl->retain_only_sha256_of_client_certs;
   int ret = 0;
-  uint8_t alert;
-  STACK_OF(X509) *chain = ssl_parse_cert_chain(
-      ssl, &alert, retain_sha256 ? ssl->s3->new_session->peer_sha256 : NULL,
-      &cbs);
+
+  STACK_OF(X509) *chain = sk_X509_new_null();
   if (chain == NULL) {
-    ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
+    ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+    OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
     goto err;
   }
 
+  if (!CBS_get_u24_length_prefixed(&cbs, &certificate_list)) {
+    ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+    OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+    goto err;
+  }
+
+  while (CBS_len(&certificate_list) > 0) {
+    CBS certificate, extensions;
+    if (!CBS_get_u24_length_prefixed(&certificate_list, &certificate) ||
+        !CBS_get_u16_length_prefixed(&certificate_list, &extensions)) {
+      ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+      OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_LENGTH_MISMATCH);
+      goto err;
+    }
+
+    /* Retain the hash of the leaf certificate if requested. */
+    if (sk_X509_num(chain) == 0 && retain_sha256) {
+      SHA256(CBS_data(&certificate), CBS_len(&certificate),
+             ssl->s3->new_session->peer_sha256);
+    }
+
+    X509 *x = ssl_parse_x509(&certificate);
+    if (x == NULL || CBS_len(&certificate) != 0) {
+      ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+      X509_free(x);
+      goto err;
+    }
+    if (!sk_X509_push(chain, x)) {
+      ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+      OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+      X509_free(x);
+      goto err;
+    }
+
+    /* Parse out the extensions. */
+    int have_status_request = 0, have_sct = 0;
+    CBS status_request, sct;
+    const SSL_EXTENSION_TYPE ext_types[] = {
+        {TLSEXT_TYPE_status_request, &have_status_request, &status_request},
+        {TLSEXT_TYPE_certificate_timestamp, &have_sct, &sct},
+    };
+
+    uint8_t alert;
+    if (!ssl_parse_extensions(&extensions, &alert, ext_types,
+                              OPENSSL_ARRAY_SIZE(ext_types))) {
+      ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
+      goto err;
+    }
+
+    /* All Certificate extensions are parsed, but only the leaf extensions are
+     * stored. */
+    if (have_status_request) {
+      if (ssl->server || !ssl->ocsp_stapling_enabled) {
+        OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
+        ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION);
+        goto err;
+      }
+
+      uint8_t status_type;
+      CBS ocsp_response;
+      if (!CBS_get_u8(&status_request, &status_type) ||
+          status_type != TLSEXT_STATUSTYPE_ocsp ||
+          !CBS_get_u24_length_prefixed(&status_request, &ocsp_response) ||
+          CBS_len(&ocsp_response) == 0 ||
+          CBS_len(&status_request) != 0) {
+        ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+        goto err;
+      }
+
+      if (sk_X509_num(chain) == 1 &&
+          !CBS_stow(&ocsp_response, &ssl->s3->new_session->ocsp_response,
+                    &ssl->s3->new_session->ocsp_response_length)) {
+        ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+        goto err;
+      }
+    }
+
+    if (have_sct) {
+      if (ssl->server || !ssl->signed_cert_timestamps_enabled) {
+        OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
+        ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION);
+        goto err;
+      }
+
+      if (!ssl_is_sct_list_valid(&sct)) {
+        OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_PARSING_EXTENSION);
+        ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+        goto err;
+      }
+
+      if (sk_X509_num(chain) == 1 &&
+          !CBS_stow(&sct,
+                    &ssl->s3->new_session->tlsext_signed_cert_timestamp_list,
+                    &ssl->s3->new_session
+                         ->tlsext_signed_cert_timestamp_list_length)) {
+        ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+        goto err;
+      }
+    }
+  }
+
   if (CBS_len(&cbs) != 0) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
@@ -198,13 +315,13 @@
     goto err;
   }
 
-  X509_free(ssl->s3->new_session->peer);
+  X509_free(ssl->s3->new_session->x509_peer);
   X509 *leaf = sk_X509_value(chain, 0);
   X509_up_ref(leaf);
-  ssl->s3->new_session->peer = leaf;
+  ssl->s3->new_session->x509_peer = leaf;
 
-  sk_X509_pop_free(ssl->s3->new_session->cert_chain, X509_free);
-  ssl->s3->new_session->cert_chain = chain;
+  sk_X509_pop_free(ssl->s3->new_session->x509_chain, X509_free);
+  ssl->s3->new_session->x509_chain = chain;
   chain = NULL;
 
   ret = 1;
@@ -216,7 +333,7 @@
 
 int tls13_process_certificate_verify(SSL *ssl) {
   int ret = 0;
-  X509 *peer = ssl->s3->new_session->peer;
+  X509 *peer = ssl->s3->new_session->x509_peer;
   EVP_PKEY *pkey = NULL;
   uint8_t *msg = NULL;
   size_t msg_len;
@@ -245,8 +362,9 @@
   }
   ssl->s3->tmp.peer_signature_algorithm = signature_algorithm;
 
-  if (!tls13_get_cert_verify_signature_input(ssl, &msg, &msg_len,
-                                             !ssl->server)) {
+  if (!tls13_get_cert_verify_signature_input(
+          ssl, &msg, &msg_len,
+          ssl->server ? ssl_cert_verify_client : ssl_cert_verify_server)) {
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
     goto err;
   }
@@ -307,17 +425,79 @@
 }
 
 int tls13_prepare_certificate(SSL *ssl) {
-  CBB cbb, body;
+  CBB cbb, body, certificate_list;
   if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_CERTIFICATE) ||
       /* The request context is always empty in the handshake. */
       !CBB_add_u8(&body, 0) ||
-      !ssl_add_cert_chain(ssl, &body) ||
-      !ssl->method->finish_message(ssl, &cbb)) {
-    CBB_cleanup(&cbb);
-    return 0;
+      !CBB_add_u24_length_prefixed(&body, &certificate_list)) {
+    OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+    goto err;
+  }
+
+  if (!ssl_has_certificate(ssl)) {
+    if (!ssl_complete_message(ssl, &cbb)) {
+      goto err;
+    }
+
+    return 1;
+  }
+
+  CERT *cert = ssl->cert;
+  CBB leaf, extensions;
+  if (!CBB_add_u24_length_prefixed(&certificate_list, &leaf) ||
+      !ssl_add_cert_to_cbb(&leaf, cert->x509_leaf) ||
+      !CBB_add_u16_length_prefixed(&certificate_list, &extensions)) {
+    OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+    goto err;
+  }
+
+  if (ssl->s3->hs->scts_requested &&
+      ssl->ctx->signed_cert_timestamp_list_length != 0) {
+    CBB contents;
+    if (!CBB_add_u16(&extensions, TLSEXT_TYPE_certificate_timestamp) ||
+        !CBB_add_u16_length_prefixed(&extensions, &contents) ||
+        !CBB_add_bytes(&contents, ssl->ctx->signed_cert_timestamp_list,
+                       ssl->ctx->signed_cert_timestamp_list_length) ||
+        !CBB_flush(&extensions)) {
+      OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+      goto err;
+    }
+  }
+
+  if (ssl->s3->hs->ocsp_stapling_requested &&
+      ssl->ctx->ocsp_response_length != 0) {
+    CBB contents, ocsp_response;
+    if (!CBB_add_u16(&extensions, TLSEXT_TYPE_status_request) ||
+        !CBB_add_u16_length_prefixed(&extensions, &contents) ||
+        !CBB_add_u8(&contents, TLSEXT_STATUSTYPE_ocsp) ||
+        !CBB_add_u24_length_prefixed(&contents, &ocsp_response) ||
+        !CBB_add_bytes(&ocsp_response, ssl->ctx->ocsp_response,
+                       ssl->ctx->ocsp_response_length) ||
+        !CBB_flush(&extensions)) {
+      OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+      goto err;
+    }
+  }
+
+  for (size_t i = 0; i < sk_X509_num(cert->x509_chain); i++) {
+    CBB child;
+    if (!CBB_add_u24_length_prefixed(&certificate_list, &child) ||
+        !ssl_add_cert_to_cbb(&child, sk_X509_value(cert->x509_chain, i)) ||
+        !CBB_add_u16(&certificate_list, 0 /* no extensions */)) {
+      OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+      goto err;
+    }
+  }
+
+  if (!ssl_complete_message(ssl, &cbb)) {
+    goto err;
   }
 
   return 1;
+
+err:
+  CBB_cleanup(&cbb);
+  return 0;
 }
 
 enum ssl_private_key_result_t tls13_prepare_certificate_verify(
@@ -352,8 +532,9 @@
 
   enum ssl_private_key_result_t sign_result;
   if (is_first_run) {
-    if (!tls13_get_cert_verify_signature_input(ssl, &msg, &msg_len,
-                                               ssl->server)) {
+    if (!tls13_get_cert_verify_signature_input(
+            ssl, &msg, &msg_len,
+            ssl->server ? ssl_cert_verify_server : ssl_cert_verify_client)) {
       ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
       goto err;
     }
@@ -369,7 +550,7 @@
   }
 
   if (!CBB_did_write(&child, sig_len) ||
-      !ssl->method->finish_message(ssl, &cbb)) {
+      !ssl_complete_message(ssl, &cbb)) {
     goto err;
   }
 
@@ -394,7 +575,7 @@
   CBB cbb, body;
   if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_FINISHED) ||
       !CBB_add_bytes(&body, verify_data, verify_data_len) ||
-      !ssl->method->finish_message(ssl, &cbb)) {
+      !ssl_complete_message(ssl, &cbb)) {
     CBB_cleanup(&cbb);
     return 0;
   }
diff --git a/src/ssl/tls13_client.c b/src/ssl/tls13_client.c
index 87ccdc4..4a30ce3 100644
--- a/src/ssl/tls13_client.c
+++ b/src/ssl/tls13_client.c
@@ -24,6 +24,7 @@
 #include <openssl/stack.h>
 #include <openssl/x509.h>
 
+#include "../crypto/internal.h"
 #include "internal.h"
 
 
@@ -41,6 +42,7 @@
   state_send_client_certificate,
   state_send_client_certificate_verify,
   state_complete_client_certificate_verify,
+  state_send_channel_id,
   state_send_client_finished,
   state_flush,
   state_done,
@@ -66,97 +68,73 @@
     return ssl_hs_error;
   }
 
-  while (CBS_len(&extensions) != 0) {
-    uint16_t type;
-    CBS extension;
-    if (!CBS_get_u16(&extensions, &type) ||
-        !CBS_get_u16_length_prefixed(&extensions, &extension)) {
+  int have_cookie, have_key_share;
+  CBS cookie, key_share;
+  const SSL_EXTENSION_TYPE ext_types[] = {
+      {TLSEXT_TYPE_key_share, &have_key_share, &key_share},
+      {TLSEXT_TYPE_cookie, &have_cookie, &cookie},
+  };
+
+  uint8_t alert;
+  if (!ssl_parse_extensions(&extensions, &alert, ext_types,
+                            OPENSSL_ARRAY_SIZE(ext_types))) {
+    ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
+    return ssl_hs_error;
+  }
+
+  if (have_cookie) {
+    CBS cookie_value;
+    if (!CBS_get_u16_length_prefixed(&cookie, &cookie_value) ||
+        CBS_len(&cookie_value) == 0 ||
+        CBS_len(&cookie) != 0) {
       OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
       ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
       return ssl_hs_error;
     }
 
-    switch (type) {
-      case TLSEXT_TYPE_cookie: {
-        if (hs->cookie != NULL) {
-          OPENSSL_PUT_ERROR(SSL, SSL_R_DUPLICATE_EXTENSION);
-          ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
-          return ssl_hs_error;
-        }
-
-        /* Cookies may be requested whether or not advertised, so no need to
-         * check. */
-
-        CBS cookie;
-        if (!CBS_get_u16_length_prefixed(&extension, &cookie) ||
-            CBS_len(&cookie) == 0 ||
-            CBS_len(&extension) != 0) {
-          OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
-          ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
-          return ssl_hs_error;
-        }
-
-        if (!CBS_stow(&cookie, &hs->cookie, &hs->cookie_len)) {
-          return ssl_hs_error;
-        }
-        break;
-      }
-
-      case TLSEXT_TYPE_key_share: {
-        if (hs->retry_group != 0) {
-          OPENSSL_PUT_ERROR(SSL, SSL_R_DUPLICATE_EXTENSION);
-          ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
-          return ssl_hs_error;
-        }
-
-        /* key_share is always advertised, so no need to check. */
-
-        uint16_t group_id;
-        if (!CBS_get_u16(&extension, &group_id) ||
-            CBS_len(&extension) != 0) {
-          OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
-          ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
-          return ssl_hs_error;
-        }
-
-        /* The group must be supported. */
-        const uint16_t *groups;
-        size_t groups_len;
-        tls1_get_grouplist(ssl, &groups, &groups_len);
-        int found = 0;
-        for (size_t i = 0; i < groups_len; i++) {
-          if (groups[i] == group_id) {
-            found = 1;
-            break;
-          }
-        }
-
-        if (!found) {
-          ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
-          OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE);
-          return ssl_hs_error;
-        }
-
-        /* Check that the HelloRetryRequest does not request the key share that
-         * was provided in the initial ClientHello. */
-        if (SSL_ECDH_CTX_get_id(&hs->ecdh_ctx) == group_id) {
-          ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
-          OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE);
-          return ssl_hs_error;
-        }
-
-        SSL_ECDH_CTX_cleanup(&hs->ecdh_ctx);
-        hs->retry_group = group_id;
-        break;
-      }
-
-      default:
-        OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
-        ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION);
-        return ssl_hs_error;
+    if (!CBS_stow(&cookie_value, &hs->cookie, &hs->cookie_len)) {
+      return ssl_hs_error;
     }
   }
 
+  if (have_key_share) {
+    uint16_t group_id;
+    if (!CBS_get_u16(&key_share, &group_id) || CBS_len(&key_share) != 0) {
+      OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+      ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+      return ssl_hs_error;
+    }
+
+    /* The group must be supported. */
+    const uint16_t *groups;
+    size_t groups_len;
+    tls1_get_grouplist(ssl, &groups, &groups_len);
+    int found = 0;
+    for (size_t i = 0; i < groups_len; i++) {
+      if (groups[i] == group_id) {
+        found = 1;
+        break;
+      }
+    }
+
+    if (!found) {
+      ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+      OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE);
+      return ssl_hs_error;
+    }
+
+    /* Check that the HelloRetryRequest does not request the key share that
+     * was provided in the initial ClientHello. */
+    if (SSL_ECDH_CTX_get_id(&hs->ecdh_ctx) == group_id) {
+      ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+      OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE);
+      return ssl_hs_error;
+    }
+
+    SSL_ECDH_CTX_cleanup(&hs->ecdh_ctx);
+    hs->retry_group = group_id;
+  }
+
   hs->received_hello_retry_request = 1;
   hs->state = state_send_second_client_hello;
   return ssl_hs_ok;
@@ -164,11 +142,7 @@
 
 static enum ssl_hs_wait_t do_send_second_client_hello(SSL *ssl,
                                                       SSL_HANDSHAKE *hs) {
-  CBB cbb, body;
-  if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_CLIENT_HELLO) ||
-      !ssl_add_client_hello_body(ssl, &body) ||
-      !ssl->method->finish_message(ssl, &cbb)) {
-    CBB_cleanup(&cbb);
+  if (!ssl_write_client_hello(ssl)) {
     return ssl_hs_error;
   }
 
@@ -217,73 +191,37 @@
     return ssl_hs_error;
   }
 
-  /* Check if the cipher is disabled. */
-  if ((cipher->algorithm_mkey & ssl->cert->mask_k) ||
-      (cipher->algorithm_auth & ssl->cert->mask_a) ||
-      SSL_CIPHER_get_min_version(cipher) > ssl3_protocol_version(ssl) ||
-      SSL_CIPHER_get_max_version(cipher) < ssl3_protocol_version(ssl) ||
-      !sk_SSL_CIPHER_find(ssl_get_ciphers_by_id(ssl), NULL, cipher)) {
+  /* Check if the cipher is a TLS 1.3 cipher. */
+  if (SSL_CIPHER_get_min_version(cipher) > ssl3_protocol_version(ssl) ||
+      SSL_CIPHER_get_max_version(cipher) < ssl3_protocol_version(ssl)) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CIPHER_RETURNED);
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
     return ssl_hs_error;
   }
 
   /* Parse out the extensions. */
-  int have_key_share = 0, have_pre_shared_key = 0, have_sigalgs = 0;
-  CBS key_share, pre_shared_key, sigalgs;
-  while (CBS_len(&extensions) != 0) {
-    uint16_t type;
-    CBS extension;
-    if (!CBS_get_u16(&extensions, &type) ||
-        !CBS_get_u16_length_prefixed(&extensions, &extension)) {
-      OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT);
-      ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
-      return ssl_hs_error;
-    }
+  int have_key_share = 0, have_pre_shared_key = 0;
+  CBS key_share, pre_shared_key;
+  const SSL_EXTENSION_TYPE ext_types[] = {
+      {TLSEXT_TYPE_key_share, &have_key_share, &key_share},
+      {TLSEXT_TYPE_pre_shared_key, &have_pre_shared_key, &pre_shared_key},
+  };
 
-    switch (type) {
-      case TLSEXT_TYPE_key_share:
-        if (have_key_share) {
-          OPENSSL_PUT_ERROR(SSL, SSL_R_DUPLICATE_EXTENSION);
-          ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
-          return ssl_hs_error;
-        }
-        key_share = extension;
-        have_key_share = 1;
-        break;
-      case TLSEXT_TYPE_pre_shared_key:
-        if (have_pre_shared_key) {
-          OPENSSL_PUT_ERROR(SSL, SSL_R_DUPLICATE_EXTENSION);
-          ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
-          return ssl_hs_error;
-        }
-        pre_shared_key = extension;
-        have_pre_shared_key = 1;
-        break;
-      case TLSEXT_TYPE_signature_algorithms:
-        if (have_sigalgs) {
-          OPENSSL_PUT_ERROR(SSL, SSL_R_DUPLICATE_EXTENSION);
-          ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
-          return ssl_hs_error;
-        }
-        sigalgs = extension;
-        have_sigalgs = 1;
-        break;
-      default:
-        OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
-        ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION);
-        return ssl_hs_error;
-    }
+  uint8_t alert;
+  if (!ssl_parse_extensions(&extensions, &alert, ext_types,
+                            OPENSSL_ARRAY_SIZE(ext_types))) {
+    ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
+    return ssl_hs_error;
   }
 
-  /* We only support PSK_AUTH and PSK_DHE_KE. */
-  if (!have_key_share || have_sigalgs == have_pre_shared_key) {
+  /* We only support PSK_DHE_KE. */
+  if (!have_key_share) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
     return ssl_hs_error;
   }
 
-  uint8_t alert = SSL_AD_DECODE_ERROR;
+  alert = SSL_AD_DECODE_ERROR;
   if (have_pre_shared_key) {
     if (ssl->session == NULL) {
       OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
@@ -303,8 +241,8 @@
       return ssl_hs_error;
     }
 
-    if (ssl->session->cipher != cipher) {
-      OPENSSL_PUT_ERROR(SSL, SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED);
+    if (ssl->session->cipher->algorithm_prf != cipher->algorithm_prf) {
+      OPENSSL_PUT_ERROR(SSL, SSL_R_OLD_SESSION_PRF_HASH_MISMATCH);
       ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
       return ssl_hs_error;
     }
@@ -339,20 +277,17 @@
       EVP_MD_size(ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl)));
 
   /* Derive resumption material. */
-  uint8_t resumption_ctx[EVP_MAX_MD_SIZE] = {0};
   uint8_t psk_secret[EVP_MAX_MD_SIZE] = {0};
   if (ssl->s3->session_reused) {
-    if (!tls13_resumption_context(ssl, resumption_ctx, hash_len,
-                                  ssl->s3->new_session) ||
-        !tls13_resumption_psk(ssl, psk_secret, hash_len,
-                              ssl->s3->new_session)) {
+    if (hash_len != (size_t) ssl->s3->new_session->master_key_length) {
       return ssl_hs_error;
     }
+    memcpy(psk_secret, ssl->s3->new_session->master_key, hash_len);
   }
 
   /* Set up the key schedule, hash in the ClientHello, and incorporate the PSK
    * into the running secret. */
-  if (!tls13_init_key_schedule(ssl, resumption_ctx, hash_len) ||
+  if (!tls13_init_key_schedule(ssl) ||
       !tls13_advance_key_schedule(ssl, psk_secret, hash_len)) {
     return ssl_hs_error;
   }
@@ -372,16 +307,10 @@
   }
   OPENSSL_free(dhe_secret);
 
-  if (have_sigalgs &&
-      CBS_len(&sigalgs) != 0) {
-    ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
-    return ssl_hs_error;
-  }
-
   /* If there was no HelloRetryRequest, the version negotiation logic has
    * already hashed the message. */
   if (hs->received_hello_retry_request &&
-      !ssl->method->hash_current_message(ssl)) {
+      !ssl_hash_current_message(ssl)) {
     return ssl_hs_error;
   }
 
@@ -411,7 +340,7 @@
     return ssl_hs_error;
   }
 
-  if (!ssl->method->hash_current_message(ssl)) {
+  if (!ssl_hash_current_message(ssl)) {
     return ssl_hs_error;
   }
 
@@ -467,7 +396,7 @@
   sk_X509_NAME_pop_free(ssl->s3->hs->ca_names, X509_NAME_free);
   ssl->s3->hs->ca_names = ca_sk;
 
-  if (!ssl->method->hash_current_message(ssl)) {
+  if (!ssl_hash_current_message(ssl)) {
     return ssl_hs_error;
   }
 
@@ -479,7 +408,7 @@
                                                         SSL_HANDSHAKE *hs) {
   if (!tls13_check_message_type(ssl, SSL3_MT_CERTIFICATE) ||
       !tls13_process_certificate(ssl, 0 /* certificate required */) ||
-      !ssl->method->hash_current_message(ssl)) {
+      !ssl_hash_current_message(ssl)) {
     return ssl_hs_error;
   }
 
@@ -491,8 +420,8 @@
     SSL *ssl, SSL_HANDSHAKE *hs) {
   if (!tls13_check_message_type(ssl, SSL3_MT_CERTIFICATE_VERIFY) ||
       !tls13_process_certificate_verify(ssl) ||
-      !ssl->method->hash_current_message(ssl)) {
-    return 0;
+      !ssl_hash_current_message(ssl)) {
+    return ssl_hs_error;
   }
 
   hs->state = state_process_server_finished;
@@ -504,10 +433,10 @@
   static const uint8_t kZeroes[EVP_MAX_MD_SIZE] = {0};
   if (!tls13_check_message_type(ssl, SSL3_MT_FINISHED) ||
       !tls13_process_finished(ssl) ||
-      !ssl->method->hash_current_message(ssl) ||
+      !ssl_hash_current_message(ssl) ||
       /* Update the secret to the master secret and derive traffic keys. */
       !tls13_advance_key_schedule(ssl, kZeroes, hs->hash_len) ||
-      !tls13_derive_traffic_secret_0(ssl)) {
+      !tls13_derive_application_secrets(ssl)) {
     return ssl_hs_error;
   }
 
@@ -519,7 +448,7 @@
 static enum ssl_hs_wait_t do_certificate_callback(SSL *ssl, SSL_HANDSHAKE *hs) {
   /* The peer didn't request a certificate. */
   if (!ssl->s3->hs->cert_request) {
-    hs->state = state_send_client_finished;
+    hs->state = state_send_channel_id;
     return ssl_hs_ok;
   }
 
@@ -566,13 +495,13 @@
                                                             int is_first_run) {
   /* Don't send CertificateVerify if there is no certificate. */
   if (!ssl_has_certificate(ssl)) {
-    hs->state = state_send_client_finished;
+    hs->state = state_send_channel_id;
     return ssl_hs_ok;
   }
 
   switch (tls13_prepare_certificate_verify(ssl, is_first_run)) {
     case ssl_private_key_success:
-      hs->state = state_send_client_finished;
+      hs->state = state_send_channel_id;
       return ssl_hs_write_message;
 
     case ssl_private_key_retry:
@@ -587,6 +516,32 @@
   return ssl_hs_error;
 }
 
+static enum ssl_hs_wait_t do_send_channel_id(SSL *ssl, SSL_HANDSHAKE *hs) {
+  if (!ssl->s3->tlsext_channel_id_valid) {
+    hs->state = state_send_client_finished;
+    return ssl_hs_ok;
+  }
+
+  if (!ssl_do_channel_id_callback(ssl)) {
+    return ssl_hs_error;
+  }
+
+  if (ssl->tlsext_channel_id_private == NULL) {
+    return ssl_hs_channel_id_lookup;
+  }
+
+  CBB cbb, body;
+  if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_CHANNEL_ID) ||
+      !tls1_write_channel_id(ssl, &body) ||
+      !ssl_complete_message(ssl, &cbb)) {
+    CBB_cleanup(&cbb);
+    return ssl_hs_error;
+  }
+
+  hs->state = state_send_client_finished;
+  return ssl_hs_write_message;
+}
+
 static enum ssl_hs_wait_t do_send_client_finished(SSL *ssl, SSL_HANDSHAKE *hs) {
   if (!tls13_prepare_finished(ssl)) {
     return ssl_hs_error;
@@ -597,11 +552,11 @@
 }
 
 static enum ssl_hs_wait_t do_flush(SSL *ssl, SSL_HANDSHAKE *hs) {
-  if (!tls13_set_traffic_key(ssl, type_data, evp_aead_open,
-                             hs->server_traffic_secret_0, hs->hash_len) ||
-      !tls13_set_traffic_key(ssl, type_data, evp_aead_seal,
-                             hs->client_traffic_secret_0, hs->hash_len) ||
-      !tls13_finalize_keys(ssl)) {
+  if (!tls13_set_traffic_key(ssl, evp_aead_open, hs->server_traffic_secret_0,
+                             hs->hash_len) ||
+      !tls13_set_traffic_key(ssl, evp_aead_seal, hs->client_traffic_secret_0,
+                             hs->hash_len) ||
+      !tls13_derive_resumption_secret(ssl)) {
     return ssl_hs_error;
   }
 
@@ -651,10 +606,13 @@
         break;
       case state_send_client_certificate_verify:
         ret = do_send_client_certificate_verify(ssl, hs, 1 /* first run */);
-      break;
+        break;
       case state_complete_client_certificate_verify:
         ret = do_send_client_certificate_verify(ssl, hs, 0 /* complete */);
-      break;
+        break;
+      case state_send_channel_id:
+        ret = do_send_channel_id(ssl, hs);
+        break;
       case state_send_client_finished:
         ret = do_send_client_finished(ssl, hs);
         break;
@@ -682,13 +640,12 @@
     return 0;
   }
 
-  CBS cbs, ke_modes, auth_modes, ticket, extensions;
+  ssl_session_refresh_time(ssl, session);
+
+  CBS cbs, ticket, extensions;
   CBS_init(&cbs, ssl->init_msg, ssl->init_num);
   if (!CBS_get_u32(&cbs, &session->tlsext_tick_lifetime_hint) ||
-      !CBS_get_u8_length_prefixed(&cbs, &ke_modes) ||
-      CBS_len(&ke_modes) == 0 ||
-      !CBS_get_u8_length_prefixed(&cbs, &auth_modes) ||
-      CBS_len(&auth_modes) == 0 ||
+      !CBS_get_u32(&cbs, &session->ticket_age_add) ||
       !CBS_get_u16_length_prefixed(&cbs, &ticket) ||
       !CBS_stow(&ticket, &session->tlsext_tick, &session->tlsext_ticklen) ||
       !CBS_get_u16_length_prefixed(&cbs, &extensions) ||
@@ -699,13 +656,10 @@
     return 0;
   }
 
+  session->ticket_age_add_valid = 1;
   session->not_resumable = 0;
 
-  /* Ignore the ticket unless the server preferences are compatible with us. */
-  if (memchr(CBS_data(&ke_modes), SSL_PSK_DHE_KE, CBS_len(&ke_modes)) != NULL &&
-      memchr(CBS_data(&auth_modes), SSL_PSK_AUTH, CBS_len(&auth_modes)) !=
-          NULL &&
-      ssl->ctx->new_session_cb != NULL &&
+  if (ssl->ctx->new_session_cb != NULL &&
       ssl->ctx->new_session_cb(ssl, session)) {
     /* |new_session_cb|'s return value signals that it took ownership. */
     return 1;
diff --git a/src/ssl/tls13_enc.c b/src/ssl/tls13_enc.c
index 1fcde51..d87d8a6 100644
--- a/src/ssl/tls13_enc.c
+++ b/src/ssl/tls13_enc.c
@@ -20,27 +20,19 @@
 #include <openssl/aead.h>
 #include <openssl/bytestring.h>
 #include <openssl/digest.h>
-#include <openssl/hmac.h>
 #include <openssl/hkdf.h>
+#include <openssl/hmac.h>
 #include <openssl/mem.h>
 
 #include "internal.h"
 
 
-int tls13_init_key_schedule(SSL *ssl, const uint8_t *resumption_ctx,
-                            size_t resumption_ctx_len) {
+int tls13_init_key_schedule(SSL *ssl) {
   SSL_HANDSHAKE *hs = ssl->s3->hs;
   const EVP_MD *digest = ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl));
 
   hs->hash_len = EVP_MD_size(digest);
 
-  /* Save the hash of the resumption context. */
-  unsigned resumption_hash_len;
-  if (!EVP_Digest(resumption_ctx, resumption_ctx_len, hs->resumption_hash,
-                  &resumption_hash_len, digest, NULL)) {
-    return 0;
-  }
-
   /* Initialize the secret to the zero key. */
   memset(hs->secret, 0, hs->hash_len);
 
@@ -89,22 +81,17 @@
   return ret;
 }
 
-int tls13_get_context_hashes(SSL *ssl, uint8_t *out, size_t *out_len) {
-  SSL_HANDSHAKE *hs = ssl->s3->hs;
-
+int tls13_get_context_hash(SSL *ssl, uint8_t *out, size_t *out_len) {
   EVP_MD_CTX ctx;
   EVP_MD_CTX_init(&ctx);
   unsigned handshake_len = 0;
   int ok = EVP_MD_CTX_copy_ex(&ctx, &ssl->s3->handshake_hash) &&
            EVP_DigestFinal_ex(&ctx, out, &handshake_len);
   EVP_MD_CTX_cleanup(&ctx);
-  if (!ok) {
-    return 0;
+  if (ok) {
+    *out_len = handshake_len;
   }
-
-  memcpy(out + handshake_len, hs->resumption_hash, hs->hash_len);
-  *out_len = handshake_len + hs->hash_len;
-  return 1;
+  return ok;
 }
 
 /* derive_secret derives a secret of length |len| and writes the result in |out|
@@ -115,18 +102,17 @@
   SSL_HANDSHAKE *hs = ssl->s3->hs;
   const EVP_MD *digest = ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl));
 
-  uint8_t context_hashes[2 * EVP_MAX_MD_SIZE];
-  size_t context_hashes_len;
-  if (!tls13_get_context_hashes(ssl, context_hashes, &context_hashes_len)) {
+  uint8_t context_hash[EVP_MAX_MD_SIZE];
+  size_t context_hash_len;
+  if (!tls13_get_context_hash(ssl, context_hash, &context_hash_len)) {
     return 0;
   }
 
   return hkdf_expand_label(out, digest, hs->secret, hs->hash_len, label,
-                           label_len, context_hashes, context_hashes_len, len);
+                           label_len, context_hash, context_hash_len, len);
 }
 
-int tls13_set_traffic_key(SSL *ssl, enum tls_record_type_t type,
-                          enum evp_aead_direction_t direction,
+int tls13_set_traffic_key(SSL *ssl, enum evp_aead_direction_t direction,
                           const uint8_t *traffic_secret,
                           size_t traffic_secret_len) {
   if (traffic_secret_len > 0xff) {
@@ -134,33 +120,11 @@
     return 0;
   }
 
-  const char *key_label, *iv_label;
-  switch (type) {
-    case type_early_handshake:
-      key_label = "early handshake key expansion, key";
-      iv_label = "early handshake key expansion, iv";
-      break;
-    case type_early_data:
-      key_label = "early application data key expansion, key";
-      iv_label = "early application data key expansion, iv";
-      break;
-    case type_handshake:
-      key_label = "handshake key expansion, key";
-      iv_label = "handshake key expansion, iv";
-      break;
-    case type_data:
-      key_label = "application data key expansion, key";
-      iv_label = "application data key expansion, iv";
-      break;
-    default:
-      return 0;
-  }
-
   /* Look up cipher suite properties. */
   const EVP_AEAD *aead;
   const EVP_MD *digest = ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl));
-  size_t mac_secret_len, fixed_iv_len;
-  if (!ssl_cipher_get_evp_aead(&aead, &mac_secret_len, &fixed_iv_len,
+  size_t discard;
+  if (!ssl_cipher_get_evp_aead(&aead, &discard, &discard,
                                SSL_get_session(ssl)->cipher,
                                ssl3_protocol_version(ssl))) {
     return 0;
@@ -170,8 +134,7 @@
   size_t key_len = EVP_AEAD_key_length(aead);
   uint8_t key[EVP_AEAD_MAX_KEY_LENGTH];
   if (!hkdf_expand_label(key, digest, traffic_secret, traffic_secret_len,
-                         (const uint8_t *)key_label, strlen(key_label), NULL, 0,
-                         key_len)) {
+                         (const uint8_t *)"key", 3, NULL, 0, key_len)) {
     return 0;
   }
 
@@ -179,8 +142,7 @@
   size_t iv_len = EVP_AEAD_nonce_length(aead);
   uint8_t iv[EVP_AEAD_MAX_NONCE_LENGTH];
   if (!hkdf_expand_label(iv, digest, traffic_secret, traffic_secret_len,
-                         (const uint8_t *)iv_label, strlen(iv_label), NULL, 0,
-                         iv_len)) {
+                         (const uint8_t *)"iv", 2, NULL, 0, iv_len)) {
     return 0;
   }
 
@@ -241,26 +203,29 @@
   }
 
   if (ssl->server) {
-    if (!tls13_set_traffic_key(ssl, type_handshake, evp_aead_open,
-                               client_traffic_secret, hs->hash_len) ||
-        !tls13_set_traffic_key(ssl, type_handshake, evp_aead_seal,
-                               server_traffic_secret, hs->hash_len)) {
+    if (!tls13_set_traffic_key(ssl, evp_aead_open, client_traffic_secret,
+                               hs->hash_len) ||
+        !tls13_set_traffic_key(ssl, evp_aead_seal, server_traffic_secret,
+                               hs->hash_len)) {
       return 0;
     }
   } else {
-    if (!tls13_set_traffic_key(ssl, type_handshake, evp_aead_open,
-                               server_traffic_secret, hs->hash_len) ||
-        !tls13_set_traffic_key(ssl, type_handshake, evp_aead_seal,
-                               client_traffic_secret, hs->hash_len)) {
+    if (!tls13_set_traffic_key(ssl, evp_aead_open, server_traffic_secret,
+                               hs->hash_len) ||
+        !tls13_set_traffic_key(ssl, evp_aead_seal, client_traffic_secret,
+                               hs->hash_len)) {
       return 0;
     }
   }
   return 1;
 }
 
-int tls13_derive_traffic_secret_0(SSL *ssl) {
+static const char kTLS13LabelExporter[] = "exporter master secret";
+
+int tls13_derive_application_secrets(SSL *ssl) {
   SSL_HANDSHAKE *hs = ssl->s3->hs;
 
+  ssl->s3->exporter_secret_len = hs->hash_len;
   return derive_secret(ssl, hs->client_traffic_secret_0, hs->hash_len,
                        (const uint8_t *)kTLS13LabelClientApplicationTraffic,
                        strlen(kTLS13LabelClientApplicationTraffic)) &&
@@ -270,7 +235,10 @@
                        (const uint8_t *)kTLS13LabelServerApplicationTraffic,
                        strlen(kTLS13LabelServerApplicationTraffic)) &&
          ssl_log_secret(ssl, "SERVER_TRAFFIC_SECRET_0",
-                        hs->server_traffic_secret_0, hs->hash_len);
+                        hs->server_traffic_secret_0, hs->hash_len) &&
+         derive_secret(ssl, ssl->s3->exporter_secret, hs->hash_len,
+                       (const uint8_t *)kTLS13LabelExporter,
+                       strlen(kTLS13LabelExporter));
 }
 
 static const char kTLS13LabelApplicationTraffic[] =
@@ -296,27 +264,36 @@
     return 0;
   }
 
-  return tls13_set_traffic_key(ssl, type_data, direction, secret, secret_len);
+  return tls13_set_traffic_key(ssl, direction, secret, secret_len);
 }
 
-static const char kTLS13LabelExporter[] = "exporter master secret";
 static const char kTLS13LabelResumption[] = "resumption master secret";
 
-int tls13_finalize_keys(SSL *ssl) {
-  SSL_HANDSHAKE *hs = ssl->s3->hs;
+int tls13_derive_resumption_secret(SSL *ssl) {
+  ssl->s3->new_session->master_key_length = ssl->s3->hs->hash_len;
+  return derive_secret(ssl, ssl->s3->new_session->master_key,
+                       ssl->s3->new_session->master_key_length,
+                       (const uint8_t *)kTLS13LabelResumption,
+                       strlen(kTLS13LabelResumption));
+}
 
-  ssl->s3->exporter_secret_len = hs->hash_len;
-  ssl->s3->new_session->master_key_length = hs->hash_len;
-  if (!derive_secret(
-          ssl, ssl->s3->exporter_secret, ssl->s3->exporter_secret_len,
-          (const uint8_t *)kTLS13LabelExporter, strlen(kTLS13LabelExporter)) ||
-      !derive_secret(ssl, ssl->s3->new_session->master_key,
-                     ssl->s3->new_session->master_key_length,
-                     (const uint8_t *)kTLS13LabelResumption,
-                     strlen(kTLS13LabelResumption))) {
+static const char kTLS13LabelFinished[] = "finished";
+
+/* tls13_verify_data sets |out| to be the HMAC of |context| using a derived
+ * Finished key for both Finished messages and the PSK binder. */
+static int tls13_verify_data(const EVP_MD *digest, uint8_t *out,
+                             size_t *out_len, const uint8_t *secret,
+                             size_t hash_len, uint8_t *context,
+                             size_t context_len) {
+  uint8_t key[EVP_MAX_MD_SIZE];
+  unsigned len;
+  if (!hkdf_expand_label(key, digest, secret, hash_len,
+                         (const uint8_t *)kTLS13LabelFinished,
+                         strlen(kTLS13LabelFinished), NULL, 0, hash_len) ||
+      HMAC(digest, key, hash_len, context, context_len, out, &len) == NULL) {
     return 0;
   }
-
+  *out_len = len;
   return 1;
 }
 
@@ -324,54 +301,23 @@
   SSL_HANDSHAKE *hs = ssl->s3->hs;
   const EVP_MD *digest = ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl));
 
-  uint8_t key[EVP_MAX_MD_SIZE];
-  size_t key_len = EVP_MD_size(digest);
-
   const uint8_t *traffic_secret;
-  const char *label = "finished";
   if (is_server == ssl->server) {
     traffic_secret = ssl->s3->write_traffic_secret;
   } else {
     traffic_secret = ssl->s3->read_traffic_secret;
   }
 
-  uint8_t context_hashes[2 * EVP_MAX_MD_SIZE];
-  size_t context_hashes_len;
-  unsigned len;
-  if (!hkdf_expand_label(key, digest, traffic_secret, hs->hash_len,
-                         (const uint8_t *)label, strlen(label), NULL, 0,
-                         hs->hash_len) ||
-      !tls13_get_context_hashes(ssl, context_hashes, &context_hashes_len) ||
-      HMAC(digest, key, key_len, context_hashes, context_hashes_len, out,
-           &len) == NULL) {
+  uint8_t context_hash[EVP_MAX_MD_SIZE];
+  size_t context_hash_len;
+  if (!tls13_get_context_hash(ssl, context_hash, &context_hash_len) ||
+      !tls13_verify_data(digest, out, out_len, traffic_secret, hs->hash_len,
+                         context_hash, context_hash_len)) {
     return 0;
   }
-  *out_len = len;
   return 1;
 }
 
-static const char kTLS13LabelResumptionPSK[] = "resumption psk";
-static const char kTLS13LabelResumptionContext[] = "resumption context";
-
-int tls13_resumption_psk(SSL *ssl, uint8_t *out, size_t out_len,
-                         const SSL_SESSION *session) {
-  const EVP_MD *digest = ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl));
-  return hkdf_expand_label(out, digest, session->master_key,
-                           session->master_key_length,
-                           (const uint8_t *)kTLS13LabelResumptionPSK,
-                           strlen(kTLS13LabelResumptionPSK), NULL, 0, out_len);
-}
-
-int tls13_resumption_context(SSL *ssl, uint8_t *out, size_t out_len,
-                             const SSL_SESSION *session) {
-  const EVP_MD *digest = ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl));
-  return hkdf_expand_label(out, digest, session->master_key,
-                           session->master_key_length,
-                           (const uint8_t *)kTLS13LabelResumptionContext,
-                           strlen(kTLS13LabelResumptionContext), NULL, 0,
-                           out_len);
-}
-
 int tls13_export_keying_material(SSL *ssl, uint8_t *out, size_t out_len,
                                  const char *label, size_t label_len,
                                  const uint8_t *context, size_t context_len,
@@ -388,3 +334,119 @@
                            ssl->s3->exporter_secret_len, (const uint8_t *)label,
                            label_len, hash, hash_len, out_len);
 }
+
+static const char kTLS13LabelPSKBinder[] = "resumption psk binder key";
+
+static int tls13_psk_binder(SSL *ssl, uint8_t *out, const EVP_MD *digest,
+                            uint8_t *psk, size_t psk_len, uint8_t *context,
+                            size_t context_len, size_t hash_len) {
+  uint8_t binder_context[EVP_MAX_MD_SIZE];
+  unsigned binder_context_len;
+  if (!EVP_Digest(NULL, 0, binder_context, &binder_context_len, digest, NULL)) {
+    return 0;
+  }
+
+  uint8_t early_secret[EVP_MAX_MD_SIZE] = {0};
+  size_t early_secret_len;
+  if (!HKDF_extract(early_secret, &early_secret_len, digest, psk, hash_len,
+                    NULL, 0)) {
+    return 0;
+  }
+
+  uint8_t binder_key[EVP_MAX_MD_SIZE] = {0};
+  size_t len;
+  if (!hkdf_expand_label(binder_key, digest, early_secret, hash_len,
+                         (const uint8_t *)kTLS13LabelPSKBinder,
+                         strlen(kTLS13LabelPSKBinder), binder_context,
+                         binder_context_len, hash_len) ||
+      !tls13_verify_data(digest, out, &len, binder_key, hash_len, context,
+                         context_len)) {
+    return 0;
+  }
+
+  return 1;
+}
+
+int tls13_write_psk_binder(SSL *ssl, uint8_t *msg, size_t len) {
+  const EVP_MD *digest =
+      ssl_get_handshake_digest(ssl->session->cipher->algorithm_prf);
+  size_t hash_len = EVP_MD_size(digest);
+
+  if (len < hash_len + 3) {
+    OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+    return 0;
+  }
+
+  EVP_MD_CTX ctx;
+  EVP_MD_CTX_init(&ctx);
+  uint8_t context[EVP_MAX_MD_SIZE];
+  unsigned context_len;
+  if (!EVP_DigestInit_ex(&ctx, digest, NULL) ||
+      !EVP_DigestUpdate(&ctx, ssl->s3->handshake_buffer->data,
+                        ssl->s3->handshake_buffer->length) ||
+      !EVP_DigestUpdate(&ctx, msg, len - hash_len - 3) ||
+      !EVP_DigestFinal_ex(&ctx, context, &context_len)) {
+    EVP_MD_CTX_cleanup(&ctx);
+    return 0;
+  }
+
+  EVP_MD_CTX_cleanup(&ctx);
+
+  uint8_t verify_data[EVP_MAX_MD_SIZE] = {0};
+  if (!tls13_psk_binder(ssl, verify_data, digest, ssl->session->master_key,
+                        ssl->session->master_key_length, context,
+                        context_len, hash_len)) {
+    return 0;
+  }
+
+  memcpy(msg + len - hash_len, verify_data, hash_len);
+  return 1;
+}
+
+int tls13_verify_psk_binder(SSL *ssl, SSL_SESSION *session,
+                            CBS *binders) {
+  const EVP_MD *digest =
+      ssl_get_handshake_digest(session->cipher->algorithm_prf);
+  size_t hash_len = EVP_MD_size(digest);
+
+  /* Get the full ClientHello, including message header. It must be large enough
+   * to exclude the binders. */
+  CBS message;
+  ssl->method->get_current_message(ssl, &message);
+  if (CBS_len(&message) < CBS_len(binders) + 2) {
+    OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+    return 0;
+  }
+
+  /* Hash a ClientHello prefix up to the binders. For now, this assumes we only
+   * ever verify PSK binders on initial ClientHellos. */
+  uint8_t context[EVP_MAX_MD_SIZE];
+  unsigned context_len;
+  if (!EVP_Digest(CBS_data(&message), CBS_len(&message) - CBS_len(binders) - 2,
+                  context, &context_len, digest, NULL)) {
+    return 0;
+  }
+
+  uint8_t verify_data[EVP_MAX_MD_SIZE] = {0};
+  CBS binder;
+  if (!tls13_psk_binder(ssl, verify_data, digest, session->master_key,
+                        session->master_key_length, context, context_len,
+                        hash_len) ||
+      /* We only consider the first PSK, so compare against the first binder. */
+      !CBS_get_u8_length_prefixed(binders, &binder)) {
+    OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+    return 0;
+  }
+
+  int binder_ok = CBS_len(&binder) == hash_len &&
+                  CRYPTO_memcmp(CBS_data(&binder), verify_data, hash_len) == 0;
+#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+  binder_ok = 1;
+#endif
+  if (!binder_ok) {
+    OPENSSL_PUT_ERROR(SSL, SSL_R_DIGEST_CHECK_FAILED);
+    return 0;
+  }
+
+  return 1;
+}
diff --git a/src/ssl/tls13_server.c b/src/ssl/tls13_server.c
index 2570069..83ef679 100644
--- a/src/ssl/tls13_server.c
+++ b/src/ssl/tls13_server.c
@@ -17,6 +17,7 @@
 #include <assert.h>
 #include <string.h>
 
+#include <openssl/aead.h>
 #include <openssl/bytestring.h>
 #include <openssl/digest.h>
 #include <openssl/err.h>
@@ -43,9 +44,10 @@
   state_flush,
   state_process_client_certificate,
   state_process_client_certificate_verify,
+  state_process_channel_id,
   state_process_client_finished,
   state_send_new_session_ticket,
-  state_flush_new_session_ticket,
+  state_flush_new_session_tickets,
   state_done,
 };
 
@@ -61,7 +63,7 @@
                                         TLSEXT_TYPE_key_share)) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_KEY_SHARE);
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_MISSING_EXTENSION);
-    return ssl_hs_error;
+    return 0;
   }
 
   int found_key_share;
@@ -103,53 +105,9 @@
   /* Load the client random. */
   if (client_hello.random_len != SSL3_RANDOM_SIZE) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
-    return -1;
-  }
-  memcpy(ssl->s3->client_random, client_hello.random, client_hello.random_len);
-
-  uint8_t alert = SSL_AD_DECODE_ERROR;
-  SSL_SESSION *session = NULL;
-  CBS pre_shared_key;
-  if (ssl_early_callback_get_extension(&client_hello, &pre_shared_key,
-                                       TLSEXT_TYPE_pre_shared_key) &&
-      !ssl_ext_pre_shared_key_parse_clienthello(ssl, &session, &alert,
-                                                &pre_shared_key)) {
-    ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
-    return 0;
-  }
-
-  if (session != NULL &&
-      /* Only resume if the session's version matches. */
-      (session->ssl_version != ssl->version ||
-       !ssl_client_cipher_list_contains_cipher(
-           &client_hello, (uint16_t)SSL_CIPHER_get_id(session->cipher)))) {
-    SSL_SESSION_free(session);
-    session = NULL;
-  }
-
-  if (session == NULL) {
-    if (!ssl_get_new_session(ssl, 1 /* server */)) {
-      ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
-      return ssl_hs_error;
-    }
-  } else {
-    /* Only authentication information carries over in TLS 1.3. */
-    ssl->s3->new_session = SSL_SESSION_dup(session, SSL_SESSION_DUP_AUTH_ONLY);
-    if (ssl->s3->new_session == NULL) {
-      ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
-      return ssl_hs_error;
-    }
-    ssl->s3->session_reused = 1;
-    SSL_SESSION_free(session);
-  }
-
-  if (ssl->ctx->dos_protection_cb != NULL &&
-      ssl->ctx->dos_protection_cb(&client_hello) == 0) {
-    /* Connection rejected for DOS reasons. */
-    OPENSSL_PUT_ERROR(SSL, SSL_R_CONNECTION_REJECTED);
-    ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
     return ssl_hs_error;
   }
+  memcpy(ssl->s3->client_random, client_hello.random, client_hello.random_len);
 
   /* TLS 1.3 requires the peer only advertise the null compression. */
   if (client_hello.compression_methods_len != 1 ||
@@ -169,20 +127,64 @@
   return ssl_hs_ok;
 }
 
+static const SSL_CIPHER *choose_tls13_cipher(
+    const SSL *ssl, const struct ssl_early_callback_ctx *client_hello) {
+  if (client_hello->cipher_suites_len % 2 != 0) {
+    return NULL;
+  }
+
+  CBS cipher_suites;
+  CBS_init(&cipher_suites, client_hello->cipher_suites,
+           client_hello->cipher_suites_len);
+
+  const int aes_is_fine = EVP_has_aes_hardware();
+  const uint16_t version = ssl3_protocol_version(ssl);
+
+  const SSL_CIPHER *best = NULL;
+  while (CBS_len(&cipher_suites) > 0) {
+    uint16_t cipher_suite;
+    if (!CBS_get_u16(&cipher_suites, &cipher_suite)) {
+      return NULL;
+    }
+
+    /* Limit to TLS 1.3 ciphers we know about. */
+    const SSL_CIPHER *candidate = SSL_get_cipher_by_value(cipher_suite);
+    if (candidate == NULL ||
+        SSL_CIPHER_get_min_version(candidate) > version ||
+        SSL_CIPHER_get_max_version(candidate) < version) {
+      continue;
+    }
+
+    /* TLS 1.3 removes legacy ciphers, so honor the client order, but prefer
+     * ChaCha20 if we do not have AES hardware. */
+    if (aes_is_fine) {
+      return candidate;
+    }
+
+    if (candidate->algorithm_enc == SSL_CHACHA20POLY1305) {
+      return candidate;
+    }
+
+    if (best == NULL) {
+      best = candidate;
+    }
+  }
+
+  return best;
+}
+
 static enum ssl_hs_wait_t do_select_parameters(SSL *ssl, SSL_HANDSHAKE *hs) {
-  if (!ssl->s3->session_reused) {
-    /* Call |cert_cb| to update server certificates if required. */
-    if (ssl->cert->cert_cb != NULL) {
-      int rv = ssl->cert->cert_cb(ssl, ssl->cert->cert_cb_arg);
-      if (rv == 0) {
-        OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_CB_ERROR);
-        ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
-        return ssl_hs_error;
-      }
-      if (rv < 0) {
-        hs->state = state_select_parameters;
-        return ssl_hs_x509_lookup;
-      }
+  /* Call |cert_cb| to update server certificates if required. */
+  if (ssl->cert->cert_cb != NULL) {
+    int rv = ssl->cert->cert_cb(ssl, ssl->cert->cert_cb_arg);
+    if (rv == 0) {
+      OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_CB_ERROR);
+      ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+      return ssl_hs_error;
+    }
+    if (rv < 0) {
+      hs->state = state_select_parameters;
+      return ssl_hs_x509_lookup;
     }
   }
 
@@ -194,45 +196,116 @@
     return ssl_hs_error;
   }
 
-  if (!ssl->s3->session_reused) {
-    const SSL_CIPHER *cipher =
-        ssl3_choose_cipher(ssl, &client_hello, ssl_get_cipher_preferences(ssl));
-    if (cipher == NULL) {
-      OPENSSL_PUT_ERROR(SSL, SSL_R_NO_SHARED_CIPHER);
-      ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
+  /* Negotiate the cipher suite. */
+  ssl->s3->tmp.new_cipher = choose_tls13_cipher(ssl, &client_hello);
+  if (ssl->s3->tmp.new_cipher == NULL) {
+    OPENSSL_PUT_ERROR(SSL, SSL_R_NO_SHARED_CIPHER);
+    ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
+    return ssl_hs_error;
+  }
+
+  /* Decode the ticket if we agree on a PSK key exchange mode. */
+  uint8_t alert = SSL_AD_DECODE_ERROR;
+  SSL_SESSION *session = NULL;
+  CBS pre_shared_key, binders;
+  if (hs->accept_psk_mode &&
+      ssl_early_callback_get_extension(&client_hello, &pre_shared_key,
+                                       TLSEXT_TYPE_pre_shared_key)) {
+    /* Verify that the pre_shared_key extension is the last extension in
+     * ClientHello. */
+    if (CBS_data(&pre_shared_key) + CBS_len(&pre_shared_key) !=
+        client_hello.extensions + client_hello.extensions_len) {
+      OPENSSL_PUT_ERROR(SSL, SSL_R_PRE_SHARED_KEY_MUST_BE_LAST);
+      ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
       return ssl_hs_error;
     }
 
-    ssl->s3->new_session->cipher = cipher;
+    if (!ssl_ext_pre_shared_key_parse_clienthello(ssl, &session, &binders,
+                                                  &alert, &pre_shared_key)) {
+      ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
+      return ssl_hs_error;
+    }
   }
 
-  ssl->s3->tmp.new_cipher = ssl->s3->new_session->cipher;
-  ssl->method->received_flight(ssl);
+  if (session != NULL &&
+      !ssl_session_is_resumable(ssl, session)) {
+    SSL_SESSION_free(session);
+    session = NULL;
+  }
 
+  /* Set up the new session, either using the original one as a template or
+   * creating a fresh one. */
+  if (session == NULL) {
+    if (!ssl_get_new_session(ssl, 1 /* server */)) {
+      ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+      return ssl_hs_error;
+    }
+
+    ssl->s3->new_session->cipher = ssl->s3->tmp.new_cipher;
+
+    /* On new sessions, stash the SNI value in the session. */
+    if (ssl->s3->hs->hostname != NULL) {
+      ssl->s3->new_session->tlsext_hostname = BUF_strdup(ssl->s3->hs->hostname);
+      if (ssl->s3->new_session->tlsext_hostname == NULL) {
+        ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+        return ssl_hs_error;
+      }
+    }
+  } else {
+    /* Check the PSK binder. */
+    if (!tls13_verify_psk_binder(ssl, session, &binders)) {
+      SSL_SESSION_free(session);
+      ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECRYPT_ERROR);
+      return ssl_hs_error;
+    }
+
+    /* Only authentication information carries over in TLS 1.3. */
+    ssl->s3->new_session = SSL_SESSION_dup(session, SSL_SESSION_DUP_AUTH_ONLY);
+    if (ssl->s3->new_session == NULL) {
+      ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+      return ssl_hs_error;
+    }
+    ssl->s3->session_reused = 1;
+    SSL_SESSION_free(session);
+  }
+
+  if (ssl->ctx->dos_protection_cb != NULL &&
+      ssl->ctx->dos_protection_cb(&client_hello) == 0) {
+    /* Connection rejected for DOS reasons. */
+    OPENSSL_PUT_ERROR(SSL, SSL_R_CONNECTION_REJECTED);
+    ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+    return ssl_hs_error;
+  }
+
+  /* HTTP/2 negotiation depends on the cipher suite, so ALPN negotiation was
+   * deferred. Complete it now. */
+  if (!ssl_negotiate_alpn(ssl, &alert, &client_hello)) {
+    ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
+    return ssl_hs_error;
+  }
 
   /* The PRF hash is now known. */
   size_t hash_len =
       EVP_MD_size(ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl)));
 
   /* Derive resumption material. */
-  uint8_t resumption_ctx[EVP_MAX_MD_SIZE] = {0};
   uint8_t psk_secret[EVP_MAX_MD_SIZE] = {0};
   if (ssl->s3->session_reused) {
-    if (!tls13_resumption_context(ssl, resumption_ctx, hash_len,
-                                  ssl->s3->new_session) ||
-        !tls13_resumption_psk(ssl, psk_secret, hash_len,
-                              ssl->s3->new_session)) {
+    if (hash_len != (size_t) ssl->s3->new_session->master_key_length) {
       return ssl_hs_error;
     }
+    memcpy(psk_secret, ssl->s3->new_session->master_key, hash_len);
   }
 
   /* Set up the key schedule, hash in the ClientHello, and incorporate the PSK
    * into the running secret. */
-  if (!tls13_init_key_schedule(ssl, resumption_ctx, hash_len) ||
+  if (!tls13_init_key_schedule(ssl) ||
       !tls13_advance_key_schedule(ssl, psk_secret, hash_len)) {
     return ssl_hs_error;
   }
 
+  ssl->method->received_flight(ssl);
+
   /* Resolve ECDHE and incorporate it into the secret. */
   int need_retry;
   if (!resolve_ecdhe_secret(ssl, &need_retry, &client_hello)) {
@@ -259,7 +332,7 @@
       !CBB_add_u16(&extensions, TLSEXT_TYPE_key_share) ||
       !CBB_add_u16(&extensions, 2 /* length */) ||
       !CBB_add_u16(&extensions, group_id) ||
-      !ssl->method->finish_message(ssl, &cbb)) {
+      !ssl_complete_message(ssl, &cbb)) {
     CBB_cleanup(&cbb);
     return ssl_hs_error;
   }
@@ -298,7 +371,7 @@
     return ssl_hs_error;
   }
 
-  if (!ssl->method->hash_current_message(ssl)) {
+  if (!ssl_hash_current_message(ssl)) {
     return ssl_hs_error;
   }
 
@@ -316,18 +389,8 @@
       !CBB_add_u16(&body, ssl_cipher_get_value(ssl->s3->tmp.new_cipher)) ||
       !CBB_add_u16_length_prefixed(&body, &extensions) ||
       !ssl_ext_pre_shared_key_add_serverhello(ssl, &extensions) ||
-      !ssl_ext_key_share_add_serverhello(ssl, &extensions)) {
-    goto err;
-  }
-
-  if (!ssl->s3->session_reused) {
-    if (!CBB_add_u16(&extensions, TLSEXT_TYPE_signature_algorithms) ||
-        !CBB_add_u16(&extensions, 0)) {
-      goto err;
-    }
-  }
-
-  if (!ssl->method->finish_message(ssl, &cbb)) {
+      !ssl_ext_key_share_add_serverhello(ssl, &extensions) ||
+      !ssl_complete_message(ssl, &cbb)) {
     goto err;
   }
 
@@ -349,7 +412,7 @@
   if (!ssl->method->init_message(ssl, &cbb, &body,
                                  SSL3_MT_ENCRYPTED_EXTENSIONS) ||
       !ssl_add_serverhello_tlsext(ssl, &body) ||
-      !ssl->method->finish_message(ssl, &cbb)) {
+      !ssl_complete_message(ssl, &cbb)) {
     CBB_cleanup(&cbb);
     return ssl_hs_error;
   }
@@ -394,7 +457,7 @@
 
   if (!ssl_add_client_CA_list(ssl, &body) ||
       !CBB_add_u16(&body, 0 /* empty certificate_extensions. */) ||
-      !ssl->method->finish_message(ssl, &cbb)) {
+      !ssl_complete_message(ssl, &cbb)) {
     goto err;
   }
 
@@ -458,9 +521,9 @@
 static enum ssl_hs_wait_t do_flush(SSL *ssl, SSL_HANDSHAKE *hs) {
   /* Update the secret to the master secret and derive traffic keys. */
   if (!tls13_advance_key_schedule(ssl, kZeroes, hs->hash_len) ||
-      !tls13_derive_traffic_secret_0(ssl) ||
-      !tls13_set_traffic_key(ssl, type_data, evp_aead_seal,
-                             hs->server_traffic_secret_0, hs->hash_len)) {
+      !tls13_derive_application_secrets(ssl) ||
+      !tls13_set_traffic_key(ssl, evp_aead_seal, hs->server_traffic_secret_0,
+                             hs->hash_len)) {
     return ssl_hs_error;
   }
 
@@ -476,7 +539,7 @@
     ssl->s3->new_session->verify_result = X509_V_OK;
 
     /* Skip this state. */
-    hs->state = state_process_client_finished;
+    hs->state = state_process_channel_id;
     return ssl_hs_ok;
   }
 
@@ -485,14 +548,14 @@
 
   if (!tls13_check_message_type(ssl, SSL3_MT_CERTIFICATE) ||
       !tls13_process_certificate(ssl, allow_anonymous) ||
-      !ssl->method->hash_current_message(ssl)) {
+      !ssl_hash_current_message(ssl)) {
     return ssl_hs_error;
   }
 
   /* For historical reasons, the server's copy of the chain does not include the
    * leaf while the client's does. */
-  if (sk_X509_num(ssl->s3->new_session->cert_chain) > 0) {
-    X509_free(sk_X509_shift(ssl->s3->new_session->cert_chain));
+  if (sk_X509_num(ssl->s3->new_session->x509_chain) > 0) {
+    X509_free(sk_X509_shift(ssl->s3->new_session->x509_chain));
   }
 
   hs->state = state_process_client_certificate_verify;
@@ -501,16 +564,32 @@
 
 static enum ssl_hs_wait_t do_process_client_certificate_verify(
     SSL *ssl, SSL_HANDSHAKE *hs) {
-  if (ssl->s3->new_session->peer == NULL) {
+  if (ssl->s3->new_session->x509_peer == NULL) {
     /* Skip this state. */
-    hs->state = state_process_client_finished;
+    hs->state = state_process_channel_id;
     return ssl_hs_ok;
   }
 
   if (!tls13_check_message_type(ssl, SSL3_MT_CERTIFICATE_VERIFY) ||
       !tls13_process_certificate_verify(ssl) ||
-      !ssl->method->hash_current_message(ssl)) {
-    return 0;
+      !ssl_hash_current_message(ssl)) {
+    return ssl_hs_error;
+  }
+
+  hs->state = state_process_channel_id;
+  return ssl_hs_read_message;
+}
+
+static enum ssl_hs_wait_t do_process_channel_id(SSL *ssl, SSL_HANDSHAKE *hs) {
+  if (!ssl->s3->tlsext_channel_id_valid) {
+    hs->state = state_process_client_finished;
+    return ssl_hs_ok;
+  }
+
+  if (!tls13_check_message_type(ssl, SSL3_MT_CHANNEL_ID) ||
+      !tls1_verify_channel_id(ssl) ||
+      !ssl_hash_current_message(ssl)) {
+    return ssl_hs_error;
   }
 
   hs->state = state_process_client_finished;
@@ -521,35 +600,49 @@
                                                      SSL_HANDSHAKE *hs) {
   if (!tls13_check_message_type(ssl, SSL3_MT_FINISHED) ||
       !tls13_process_finished(ssl) ||
-      !ssl->method->hash_current_message(ssl) ||
+      !ssl_hash_current_message(ssl) ||
       /* evp_aead_seal keys have already been switched. */
-      !tls13_set_traffic_key(ssl, type_data, evp_aead_open,
-                             hs->client_traffic_secret_0, hs->hash_len) ||
-      !tls13_finalize_keys(ssl)) {
+      !tls13_set_traffic_key(ssl, evp_aead_open, hs->client_traffic_secret_0,
+                             hs->hash_len) ||
+      !tls13_derive_resumption_secret(ssl)) {
     return ssl_hs_error;
   }
 
   ssl->method->received_flight(ssl);
+
+  /* Refresh the session timestamp so that it is measured from ticket
+   * issuance. */
+  ssl_session_refresh_time(ssl, ssl->s3->new_session);
   hs->state = state_send_new_session_ticket;
   return ssl_hs_ok;
 }
 
+/* TLS 1.3 recommends single-use tickets, so issue multiple tickets in case the
+ * client makes several connections before getting a renewal. */
+static const int kNumTickets = 2;
+
 static enum ssl_hs_wait_t do_send_new_session_ticket(SSL *ssl,
                                                      SSL_HANDSHAKE *hs) {
+  /* If the client doesn't accept resumption with PSK_DHE_KE, don't send a
+   * session ticket. */
+  if (!hs->accept_psk_mode) {
+    hs->state = state_done;
+    return ssl_hs_ok;
+  }
+
   SSL_SESSION *session = ssl->s3->new_session;
-  session->tlsext_tick_lifetime_hint = session->timeout;
+  if (!RAND_bytes((uint8_t *)&session->ticket_age_add, 4)) {
+    goto err;
+  }
 
   /* TODO(svaldez): Add support for sending 0RTT through TicketEarlyDataInfo
    * extension. */
 
-  CBB cbb, body, ke_modes, auth_modes, ticket, extensions;
+  CBB cbb, body, ticket, extensions;
   if (!ssl->method->init_message(ssl, &cbb, &body,
                                  SSL3_MT_NEW_SESSION_TICKET) ||
-      !CBB_add_u32(&body, session->tlsext_tick_lifetime_hint) ||
-      !CBB_add_u8_length_prefixed(&body, &ke_modes) ||
-      !CBB_add_u8(&ke_modes, SSL_PSK_DHE_KE) ||
-      !CBB_add_u8_length_prefixed(&body, &auth_modes) ||
-      !CBB_add_u8(&auth_modes, SSL_PSK_AUTH) ||
+      !CBB_add_u32(&body, session->timeout) ||
+      !CBB_add_u32(&body, session->ticket_age_add) ||
       !CBB_add_u16_length_prefixed(&body, &ticket) ||
       !ssl_encrypt_ticket(ssl, &ticket, session) ||
       !CBB_add_u16_length_prefixed(&body, &extensions)) {
@@ -557,21 +650,23 @@
   }
 
   /* Add a fake extension. See draft-davidben-tls-grease-01. */
-  if (ssl->ctx->grease_enabled) {
-    if (!CBB_add_u16(&extensions,
-                     ssl_get_grease_value(ssl, ssl_grease_ticket_extension)) ||
-        !CBB_add_u16(&extensions, 0 /* empty */)) {
-      goto err;
-    }
+  if (!CBB_add_u16(&extensions,
+                   ssl_get_grease_value(ssl, ssl_grease_ticket_extension)) ||
+      !CBB_add_u16(&extensions, 0 /* empty */)) {
+    goto err;
   }
 
-  if (!ssl->method->finish_message(ssl, &cbb)) {
+  if (!ssl_complete_message(ssl, &cbb)) {
     goto err;
   }
 
   hs->session_tickets_sent++;
+  if (hs->session_tickets_sent >= kNumTickets) {
+    hs->state = state_flush_new_session_tickets;
+  } else {
+    hs->state = state_send_new_session_ticket;
+  }
 
-  hs->state = state_flush_new_session_ticket;
   return ssl_hs_write_message;
 
 err:
@@ -579,17 +674,9 @@
   return ssl_hs_error;
 }
 
-/* TLS 1.3 recommends single-use tickets, so issue multiple tickets in case the
- * client makes several connections before getting a renewal. */
-static const int kNumTickets = 2;
-
-static enum ssl_hs_wait_t do_flush_new_session_ticket(SSL *ssl,
-                                                      SSL_HANDSHAKE *hs) {
-  if (hs->session_tickets_sent >= kNumTickets) {
-    hs->state = state_done;
-  } else {
-    hs->state = state_send_new_session_ticket;
-  }
+static enum ssl_hs_wait_t do_flush_new_session_tickets(SSL *ssl,
+                                                       SSL_HANDSHAKE *hs) {
+  hs->state = state_done;
   return ssl_hs_flush;
 }
 
@@ -645,14 +732,17 @@
       case state_process_client_certificate_verify:
         ret = do_process_client_certificate_verify(ssl, hs);
         break;
+      case state_process_channel_id:
+        ret = do_process_channel_id(ssl, hs);
+        break;
       case state_process_client_finished:
         ret = do_process_client_finished(ssl, hs);
         break;
       case state_send_new_session_ticket:
         ret = do_send_new_session_ticket(ssl, hs);
         break;
-      case state_flush_new_session_ticket:
-        ret = do_flush_new_session_ticket(ssl, hs);
+      case state_flush_new_session_tickets:
+        ret = do_flush_new_session_tickets(ssl, hs);
         break;
       case state_done:
         ret = ssl_hs_ok;
diff --git a/src/ssl/tls_method.c b/src/ssl/tls_method.c
index 8bcdf8f..ce42904 100644
--- a/src/ssl/tls_method.c
+++ b/src/ssl/tls_method.c
@@ -130,7 +130,7 @@
     ssl3_new,
     ssl3_free,
     ssl3_get_message,
-    ssl3_hash_current_message,
+    ssl3_get_current_message,
     ssl3_release_current_message,
     ssl3_read_app_data,
     ssl3_read_change_cipher_spec,
@@ -140,6 +140,7 @@
     ssl3_supports_cipher,
     ssl3_init_message,
     ssl3_finish_message,
+    ssl3_queue_message,
     ssl3_write_message,
     ssl3_send_change_cipher_spec,
     ssl3_expect_flight,
diff --git a/src/ssl/tls_record.c b/src/ssl/tls_record.c
index 7041ce3..5931922 100644
--- a/src/ssl/tls_record.c
+++ b/src/ssl/tls_record.c
@@ -174,7 +174,7 @@
   }
 }
 
-size_t ssl_max_seal_overhead(const SSL *ssl) {
+size_t SSL_max_seal_overhead(const SSL *ssl) {
   size_t ret = SSL_AEAD_CTX_max_overhead(ssl->s3->aead_write_ctx);
   if (SSL_is_dtls(ssl)) {
     ret += DTLS1_RT_HEADER_LENGTH;
@@ -210,9 +210,20 @@
     return ssl_open_record_partial;
   }
 
-  /* Check that the major version in the record matches. As of TLS 1.3, the
-   * minor version is no longer checked. */
-  if ((version >> 8) != SSL3_VERSION_MAJOR) {
+  int version_ok;
+  if (ssl->s3->aead_read_ctx == NULL) {
+    /* Only check the first byte. Enforcing beyond that can prevent decoding
+     * version negotiation failure alerts. */
+    version_ok = (version >> 8) == SSL3_VERSION_MAJOR;
+  } else if (ssl3_protocol_version(ssl) < TLS1_3_VERSION) {
+    /* Earlier versions of TLS switch the record version. */
+    version_ok = version == ssl->version;
+  } else {
+    /* Starting TLS 1.3, the version field is frozen at {3, 1}. */
+    version_ok = version == TLS1_VERSION;
+  }
+
+  if (!version_ok) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_VERSION_NUMBER);
     *out_alert = SSL_AD_PROTOCOL_VERSION;
     return ssl_open_record_error;
diff --git a/src/tool/digest.cc b/src/tool/digest.cc
index 2e3e608..7b6c88b 100644
--- a/src/tool/digest.cc
+++ b/src/tool/digest.cc
@@ -21,6 +21,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <limits.h>
+#include <stdio.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 
@@ -64,8 +65,9 @@
   };
 
   Source() : is_stdin_(false) {}
-  Source(Type) : is_stdin_(true) {}
-  Source(const std::string &name) : is_stdin_(false), filename_(name) {}
+  explicit Source(Type) : is_stdin_(true) {}
+  explicit Source(const std::string &name)
+      : is_stdin_(false), filename_(name) {}
 
   bool is_stdin() const { return is_stdin_; }
   const std::string &filename() const { return filename_; }
@@ -132,12 +134,8 @@
   static const size_t kBufSize = 8192;
   std::unique_ptr<uint8_t[]> buf(new uint8_t[kBufSize]);
 
-  EVP_MD_CTX ctx;
-  EVP_MD_CTX_init(&ctx);
-  std::unique_ptr<EVP_MD_CTX, func_delete<EVP_MD_CTX, int, EVP_MD_CTX_cleanup>>
-      scoped_ctx(&ctx);
-
-  if (!EVP_DigestInit_ex(&ctx, md, NULL)) {
+  bssl::ScopedEVP_MD_CTX ctx;
+  if (!EVP_DigestInit_ex(ctx.get(), md, NULL)) {
     fprintf(stderr, "Failed to initialize EVP_MD_CTX.\n");
     return false;
   }
@@ -158,7 +156,7 @@
       return false;
     }
 
-    if (!EVP_DigestUpdate(&ctx, buf.get(), n)) {
+    if (!EVP_DigestUpdate(ctx.get(), buf.get(), n)) {
       fprintf(stderr, "Failed to update hash.\n");
       return false;
     }
@@ -166,7 +164,7 @@
 
   uint8_t digest[EVP_MAX_MD_SIZE];
   unsigned digest_len;
-  if (!EVP_DigestFinal_ex(&ctx, digest, &digest_len)) {
+  if (!EVP_DigestFinal_ex(ctx.get(), digest, &digest_len)) {
     fprintf(stderr, "Failed to finish hash.\n");
     return false;
   }
diff --git a/src/tool/pkcs12.cc b/src/tool/pkcs12.cc
index 15e32d3..7fd6f13 100644
--- a/src/tool/pkcs12.cc
+++ b/src/tool/pkcs12.cc
@@ -120,23 +120,22 @@
   CBS_init(&pkcs12, contents.get(), size);
 
   EVP_PKEY *key;
-  STACK_OF(X509) *certs = sk_X509_new_null();
+  bssl::UniquePtr<STACK_OF(X509)> certs(sk_X509_new_null());
 
-  if (!PKCS12_get_key_and_certs(&key, certs, &pkcs12, password)) {
+  if (!PKCS12_get_key_and_certs(&key, certs.get(), &pkcs12, password)) {
     fprintf(stderr, "Failed to parse PKCS#12 data:\n");
     ERR_print_errors_fp(stderr);
     return false;
   }
+  bssl::UniquePtr<EVP_PKEY> key_owned(key);
 
   if (key != NULL) {
     PEM_write_PrivateKey(stdout, key, NULL, NULL, 0, NULL, NULL);
-    EVP_PKEY_free(key);
   }
 
-  for (size_t i = 0; i < sk_X509_num(certs); i++) {
-    PEM_write_X509(stdout, sk_X509_value(certs, i));
+  for (size_t i = 0; i < sk_X509_num(certs.get()); i++) {
+    PEM_write_X509(stdout, sk_X509_value(certs.get(), i));
   }
-  sk_X509_pop_free(certs, X509_free);
 
   return true;
 }
diff --git a/src/tool/rand.cc b/src/tool/rand.cc
index 3701748..b442e0d 100644
--- a/src/tool/rand.cc
+++ b/src/tool/rand.cc
@@ -16,6 +16,7 @@
 #include <vector>
 
 #include <stdint.h>
+#include <stdio.h>
 #include <stdlib.h>
 
 #include <openssl/rand.h>
diff --git a/src/tool/server.cc b/src/tool/server.cc
index 012f671..d0213e9 100644
--- a/src/tool/server.cc
+++ b/src/tool/server.cc
@@ -103,25 +103,25 @@
     return false;
   }
 
-  SSL_CTX *ctx = SSL_CTX_new(SSLv23_server_method());
-  SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3);
+  bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
+  SSL_CTX_set_options(ctx.get(), SSL_OP_NO_SSLv3);
 
   // Server authentication is required.
   std::string key_file = "server.pem";
   if (args_map.count("-key") != 0) {
     key_file = args_map["-key"];
   }
-  if (!SSL_CTX_use_PrivateKey_file(ctx, key_file.c_str(), SSL_FILETYPE_PEM)) {
+  if (!SSL_CTX_use_PrivateKey_file(ctx.get(), key_file.c_str(), SSL_FILETYPE_PEM)) {
     fprintf(stderr, "Failed to load private key: %s\n", key_file.c_str());
     return false;
   }
-  if (!SSL_CTX_use_certificate_chain_file(ctx, key_file.c_str())) {
+  if (!SSL_CTX_use_certificate_chain_file(ctx.get(), key_file.c_str())) {
     fprintf(stderr, "Failed to load cert chain: %s\n", key_file.c_str());
     return false;
   }
 
   if (args_map.count("-cipher") != 0 &&
-      !SSL_CTX_set_cipher_list(ctx, args_map["-cipher"].c_str())) {
+      !SSL_CTX_set_cipher_list(ctx.get(), args_map["-cipher"].c_str())) {
     fprintf(stderr, "Failed setting cipher list\n");
     return false;
   }
@@ -133,7 +133,7 @@
               args_map["-max-version"].c_str());
       return false;
     }
-    if (!SSL_CTX_set_max_proto_version(ctx, version)) {
+    if (!SSL_CTX_set_max_proto_version(ctx.get(), version)) {
       return false;
     }
   }
@@ -145,13 +145,13 @@
               args_map["-min-version"].c_str());
       return false;
     }
-    if (!SSL_CTX_set_min_proto_version(ctx, version)) {
+    if (!SSL_CTX_set_min_proto_version(ctx.get(), version)) {
       return false;
     }
   }
 
   if (args_map.count("-ocsp-response") != 0 &&
-      !LoadOCSPResponse(ctx, args_map["-ocsp-response"].c_str())) {
+      !LoadOCSPResponse(ctx.get(), args_map["-ocsp-response"].c_str())) {
     fprintf(stderr, "Failed to load OCSP response: %s\n", args_map["-ocsp-response"].c_str());
     return false;
   }
@@ -162,23 +162,19 @@
   }
 
   BIO *bio = BIO_new_socket(sock, BIO_CLOSE);
-  SSL *ssl = SSL_new(ctx);
-  SSL_set_bio(ssl, bio, bio);
+  bssl::UniquePtr<SSL> ssl(SSL_new(ctx.get()));
+  SSL_set_bio(ssl.get(), bio, bio);
 
-  int ret = SSL_accept(ssl);
+  int ret = SSL_accept(ssl.get());
   if (ret != 1) {
-    int ssl_err = SSL_get_error(ssl, ret);
+    int ssl_err = SSL_get_error(ssl.get(), ret);
     fprintf(stderr, "Error while connecting: %d\n", ssl_err);
     ERR_print_errors_cb(PrintErrorCallback, stderr);
     return false;
   }
 
   fprintf(stderr, "Connected.\n");
-  PrintConnectionInfo(ssl);
+  PrintConnectionInfo(ssl.get());
 
-  bool ok = TransferData(ssl, sock);
-
-  SSL_free(ssl);
-  SSL_CTX_free(ctx);
-  return ok;
+  return TransferData(ssl.get(), sock);
 }
diff --git a/src/tool/speed.cc b/src/tool/speed.cc
index d5f94e1..f16a9eb 100644
--- a/src/tool/speed.cc
+++ b/src/tool/speed.cc
@@ -203,7 +203,7 @@
                            size_t chunk_len, size_t ad_len) {
   static const unsigned kAlignment = 16;
 
-  EVP_AEAD_CTX ctx;
+  bssl::ScopedEVP_AEAD_CTX ctx;
   const size_t key_len = EVP_AEAD_key_length(aead);
   const size_t nonce_len = EVP_AEAD_nonce_length(aead);
   const size_t overhead_len = EVP_AEAD_max_overhead(aead);
@@ -222,7 +222,7 @@
   uint8_t *const out = align(out_storage.get(), kAlignment);
   memset(out, 0, chunk_len + overhead_len);
 
-  if (!EVP_AEAD_CTX_init_with_direction(&ctx, aead, key.get(), key_len,
+  if (!EVP_AEAD_CTX_init_with_direction(ctx.get(), aead, key.get(), key_len,
                                         EVP_AEAD_DEFAULT_TAG_LENGTH,
                                         evp_aead_seal)) {
     fprintf(stderr, "Failed to create EVP_AEAD_CTX.\n");
@@ -234,10 +234,9 @@
   if (!TimeFunction(&results, [chunk_len, overhead_len, nonce_len, ad_len, in,
                                out, &ctx, &nonce, &ad]() -> bool {
         size_t out_len;
-
-        return EVP_AEAD_CTX_seal(
-            &ctx, out, &out_len, chunk_len + overhead_len, nonce.get(),
-            nonce_len, in, chunk_len, ad.get(), ad_len);
+        return EVP_AEAD_CTX_seal(ctx.get(), out, &out_len,
+                                 chunk_len + overhead_len, nonce.get(),
+                                 nonce_len, in, chunk_len, ad.get(), ad_len);
       })) {
     fprintf(stderr, "EVP_AEAD_CTX_seal failed.\n");
     ERR_print_errors_fp(stderr);
@@ -245,9 +244,6 @@
   }
 
   results.PrintWithBytes(name + " seal", chunk_len);
-
-  EVP_AEAD_CTX_cleanup(&ctx);
-
   return true;
 }
 
@@ -302,7 +298,7 @@
          SpeedHashChunk(md, name + " (8192 bytes)", 8192);
 }
 
-static bool SpeedRandomChunk(const std::string name, size_t chunk_len) {
+static bool SpeedRandomChunk(const std::string &name, size_t chunk_len) {
   uint8_t scratch[8192];
 
   if (chunk_len > sizeof(scratch)) {
@@ -547,15 +543,16 @@
   }
 
   TimeResults results;
-  NEWHOPE_POLY *sk = NEWHOPE_POLY_new();
+  bssl::UniquePtr<NEWHOPE_POLY> sk(NEWHOPE_POLY_new());
   uint8_t acceptmsg[NEWHOPE_ACCEPTMSG_LENGTH];
   RAND_bytes(acceptmsg, sizeof(acceptmsg));
 
-  if (!TimeFunction(&results, [sk, &acceptmsg]() -> bool {
+  if (!TimeFunction(&results, [&sk, &acceptmsg]() -> bool {
         uint8_t key[SHA256_DIGEST_LENGTH];
         uint8_t offermsg[NEWHOPE_OFFERMSG_LENGTH];
-        NEWHOPE_offer(offermsg, sk);
-        if (!NEWHOPE_finish(key, sk, acceptmsg, NEWHOPE_ACCEPTMSG_LENGTH)) {
+        NEWHOPE_offer(offermsg, sk.get());
+        if (!NEWHOPE_finish(key, sk.get(), acceptmsg,
+                            NEWHOPE_ACCEPTMSG_LENGTH)) {
           return false;
         }
         return true;
@@ -564,7 +561,6 @@
     return false;
   }
 
-  NEWHOPE_POLY_free(sk);
   results.Print("newhope key exchange");
   return true;
 }
@@ -599,45 +595,43 @@
     g_timeout_seconds = atoi(args_map["-timeout"].c_str());
   }
 
-  RSA *key = RSA_private_key_from_bytes(kDERRSAPrivate2048,
-                                        kDERRSAPrivate2048Len);
-  if (key == NULL) {
+  bssl::UniquePtr<RSA> key(
+      RSA_private_key_from_bytes(kDERRSAPrivate2048, kDERRSAPrivate2048Len));
+  if (key == nullptr) {
     fprintf(stderr, "Failed to parse RSA key.\n");
     ERR_print_errors_fp(stderr);
     return false;
   }
 
-  if (!SpeedRSA("RSA 2048", key, selected)) {
+  if (!SpeedRSA("RSA 2048", key.get(), selected)) {
     return false;
   }
 
-  RSA_free(key);
-  key = RSA_private_key_from_bytes(kDERRSAPrivate3Prime2048,
-                                   kDERRSAPrivate3Prime2048Len);
-  if (key == NULL) {
+  key.reset(RSA_private_key_from_bytes(kDERRSAPrivate3Prime2048,
+                                       kDERRSAPrivate3Prime2048Len));
+  if (key == nullptr) {
     fprintf(stderr, "Failed to parse RSA key.\n");
     ERR_print_errors_fp(stderr);
     return false;
   }
 
-  if (!SpeedRSA("RSA 2048 (3 prime, e=3)", key, selected)) {
+  if (!SpeedRSA("RSA 2048 (3 prime, e=3)", key.get(), selected)) {
     return false;
   }
 
-  RSA_free(key);
-  key = RSA_private_key_from_bytes(kDERRSAPrivate4096,
-                                   kDERRSAPrivate4096Len);
-  if (key == NULL) {
+  key.reset(
+      RSA_private_key_from_bytes(kDERRSAPrivate4096, kDERRSAPrivate4096Len));
+  if (key == nullptr) {
     fprintf(stderr, "Failed to parse 4096-bit RSA key.\n");
     ERR_print_errors_fp(stderr);
     return 1;
   }
 
-  if (!SpeedRSA("RSA 4096", key, selected)) {
+  if (!SpeedRSA("RSA 4096", key.get(), selected)) {
     return false;
   }
 
-  RSA_free(key);
+  key.reset();
 
   // kTLSADLen is the number of bytes of additional data that TLS passes to
   // AEADs.
diff --git a/src/tool/transport_common.cc b/src/tool/transport_common.cc
index d5326b5..7eed8ba 100644
--- a/src/tool/transport_common.cc
+++ b/src/tool/transport_common.cc
@@ -154,7 +154,7 @@
   memset(&addr, 0, sizeof(addr));
 
   addr.sin6_family = AF_INET6;
-  addr.sin6_addr = in6addr_any;
+  addr.sin6_addr = IN6ADDR_ANY_INIT;
   addr.sin6_port = htons(atoi(port.c_str()));
 
   bool ok = false;
@@ -267,17 +267,21 @@
   SSL_get0_alpn_selected(ssl, &alpn, &alpn_len);
   fprintf(stderr, "  ALPN protocol: %.*s\n", alpn_len, alpn);
 
+  const char *host_name = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
+  if (host_name != nullptr && SSL_is_server(ssl)) {
+    fprintf(stderr, "  Client sent SNI: %s\n", host_name);
+  }
+
   // Print the server cert subject and issuer names.
-  X509 *peer = SSL_get_peer_certificate(ssl);
-  if (peer != NULL) {
+  bssl::UniquePtr<X509> peer(SSL_get_peer_certificate(ssl));
+  if (peer != nullptr) {
     fprintf(stderr, "  Cert subject: ");
-    X509_NAME_print_ex_fp(stderr, X509_get_subject_name(peer), 0,
+    X509_NAME_print_ex_fp(stderr, X509_get_subject_name(peer.get()), 0,
                           XN_FLAG_ONELINE);
     fprintf(stderr, "\n  Cert issuer: ");
-    X509_NAME_print_ex_fp(stderr, X509_get_issuer_name(peer), 0,
+    X509_NAME_print_ex_fp(stderr, X509_get_issuer_name(peer.get()), 0,
                           XN_FLAG_ONELINE);
     fprintf(stderr, "\n");
-    X509_free(peer);
   }
 }
 
diff --git a/src/util/all_tests.json b/src/util/all_tests.json
index ac4b3c7..d2e39ce 100644
--- a/src/util/all_tests.json
+++ b/src/util/all_tests.json
@@ -35,6 +35,7 @@
 	["crypto/dsa/dsa_test"],
 	["crypto/ec/ec_test"],
 	["crypto/ec/example_mul"],
+	["crypto/ec/p256-x86_64_test", "crypto/ec/p256-x86_64_tests.txt"],
 	["crypto/ecdh/ecdh_test", "crypto/ecdh/ecdh_tests.txt"],
 	["crypto/ecdsa/ecdsa_sign_test", "crypto/ecdsa/ecdsa_sign_tests.txt"],
 	["crypto/ecdsa/ecdsa_test"],
@@ -54,6 +55,7 @@
 	["crypto/pkcs8/pkcs12_test"],
 	["crypto/pkcs8/pkcs8_test"],
 	["crypto/poly1305/poly1305_test", "crypto/poly1305/poly1305_tests.txt"],
+	["crypto/pool/pool_test"],
 	["crypto/refcount_test"],
 	["crypto/rsa/rsa_test"],
 	["crypto/thread_test"],
diff --git a/src/util/bot/DEPS b/src/util/bot/DEPS
index c57864c..0452d55 100644
--- a/src/util/bot/DEPS
+++ b/src/util/bot/DEPS
@@ -24,10 +24,15 @@
 deps_os = {
   'android': {
     'boringssl/util/bot/android_tools':
-      Var('chromium_git') + '/android_tools.git' + '@' + 'af1c5a4cd6329ccdcf8c2bc93d9eea02f9d74869',
+      Var('chromium_git') + '/android_tools.git' + '@' + 'c02a002b48d6637714ef98f0e4bf6952b9c4cf10',
   },
 }
 
+recursedeps = [
+  # android_tools pulls in the NDK from a separate repository.
+  'boringssl/util/bot/android_tools',
+]
+
 hooks = [
   {
     'name': 'cmake_linux64',
diff --git a/src/util/bot/go/bootstrap.py b/src/util/bot/go/bootstrap.py
index 058cc6c..5661be2 100755
--- a/src/util/bot/go/bootstrap.py
+++ b/src/util/bot/go/bootstrap.py
@@ -45,7 +45,7 @@
 EXE_SFX = '.exe' if sys.platform == 'win32' else ''
 
 # Pinned version of Go toolset to download.
-TOOLSET_VERSION = 'go1.7'
+TOOLSET_VERSION = 'go1.7.3'
 
 # Platform dependent portion of a download URL. See http://golang.org/dl/.
 TOOLSET_VARIANTS = {
diff --git a/src/util/bot/update_clang.py b/src/util/bot/update_clang.py
index cd446e8..32fb01a 100644
--- a/src/util/bot/update_clang.py
+++ b/src/util/bot/update_clang.py
@@ -22,7 +22,7 @@
 # CLANG_REVISION and CLANG_SUB_REVISION determine the build of clang
 # to use. These should be synced with tools/clang/scripts/update.py in
 # Chromium.
-CLANG_REVISION = "280106"
+CLANG_REVISION = "284979"
 CLANG_SUB_REVISION = "1"
 
 PACKAGE_VERSION = "%s-%s" % (CLANG_REVISION, CLANG_SUB_REVISION)
diff --git a/src/util/bot/vs_toolchain.py b/src/util/bot/vs_toolchain.py
index f90bb46..201b000 100644
--- a/src/util/bot/vs_toolchain.py
+++ b/src/util/bot/vs_toolchain.py
@@ -19,7 +19,7 @@
 
 
 TOOLCHAIN_VERSION = '2015'
-TOOLCHAIN_HASH = '95ddda401ec5678f15eeed01d2bee08fcbc5ee97'
+TOOLCHAIN_HASH = 'd5dc33b15d1b2c086f2f6632e2fd15882f80dbd3'
 
 
 def SetEnvironmentAndGetRuntimeDllDirs():
diff --git a/src/util/doc.config b/src/util/doc.config
index e7cfa82..f3f3d52 100644
--- a/src/util/doc.config
+++ b/src/util/doc.config
@@ -14,6 +14,7 @@
       "include/openssl/lhash.h",
       "include/openssl/mem.h",
       "include/openssl/obj.h",
+      "include/openssl/pool.h",
       "include/openssl/rand.h",
       "include/openssl/stack.h",
       "include/openssl/time_support.h"
diff --git a/src/util/generate_build_files.py b/src/util/generate_build_files.py
index 0b84bfd..aae158d 100644
--- a/src/util/generate_build_files.py
+++ b/src/util/generate_build_files.py
@@ -266,7 +266,7 @@
               out.write('          "%s",\n' % arg)
           out.write('      ],\n')
 
-        out.write('      copts = copts,\n')
+        out.write('      copts = copts + ["-DBORINGSSL_SHARED_LIBRARY"],\n')
 
         if len(data_files) > 0:
           out.write('      data = [\n')
diff --git a/src/util/run_android_tests.go b/src/util/run_android_tests.go
index fe5392a..8e42596 100644
--- a/src/util/run_android_tests.go
+++ b/src/util/run_android_tests.go
@@ -241,7 +241,6 @@
 		binaries = append(binaries, "ssl/test/bssl_shim")
 		files = append(files,
 			"BUILDING.md",
-			"util/all_tests.json",
 			"ssl/test/runner/cert.pem",
 			"ssl/test/runner/channel_id_key.pem",
 			"ssl/test/runner/ecdsa_p256_cert.pem",
@@ -253,6 +252,9 @@
 			"ssl/test/runner/key.pem",
 			"ssl/test/runner/rsa_1024_cert.pem",
 			"ssl/test/runner/rsa_1024_key.pem",
+			"ssl/test/runner/rsa_chain_cert.pem",
+			"ssl/test/runner/rsa_chain_key.pem",
+			"util/all_tests.json",
 		)
 
 		fmt.Printf("Building runner...\n")
diff --git a/win-x86_64/crypto/ec/p256-x86_64-asm.asm b/win-x86_64/crypto/ec/p256-x86_64-asm.asm
index 45df829..cbcf883 100644
--- a/win-x86_64/crypto/ec/p256-x86_64-asm.asm
+++ b/win-x86_64/crypto/ec/p256-x86_64-asm.asm
@@ -35,6 +35,7 @@
 	push	r13
 
 	mov	r8,QWORD[rsi]
+	xor	r13,r13
 	mov	r9,QWORD[8+rsi]
 	add	r8,r8
 	mov	r10,QWORD[16+rsi]
@@ -45,7 +46,7 @@
 	adc	r10,r10
 	adc	r11,r11
 	mov	rdx,r9
-	sbb	r13,r13
+	adc	r13,0
 
 	sub	r8,QWORD[rsi]
 	mov	rcx,r10
@@ -53,14 +54,14 @@
 	sbb	r10,QWORD[16+rsi]
 	mov	r12,r11
 	sbb	r11,QWORD[24+rsi]
-	test	r13,r13
+	sbb	r13,0
 
-	cmovz	r8,rax
-	cmovz	r9,rdx
+	cmovc	r8,rax
+	cmovc	r9,rdx
 	mov	QWORD[rdi],r8
-	cmovz	r10,rcx
+	cmovc	r10,rcx
 	mov	QWORD[8+rdi],r9
-	cmovz	r11,r12
+	cmovc	r11,r12
 	mov	QWORD[16+rdi],r10
 	mov	QWORD[24+rdi],r11
 
@@ -875,13 +876,14 @@
 
 ALIGN	32
 __ecp_nistz256_add_toq:
+	xor	r11,r11
 	add	r12,QWORD[rbx]
 	adc	r13,QWORD[8+rbx]
 	mov	rax,r12
 	adc	r8,QWORD[16+rbx]
 	adc	r9,QWORD[24+rbx]
 	mov	rbp,r13
-	sbb	r11,r11
+	adc	r11,0
 
 	sub	r12,-1
 	mov	rcx,r8
@@ -889,14 +891,14 @@
 	sbb	r8,0
 	mov	r10,r9
 	sbb	r9,r15
-	test	r11,r11
+	sbb	r11,0
 
-	cmovz	r12,rax
-	cmovz	r13,rbp
+	cmovc	r12,rax
+	cmovc	r13,rbp
 	mov	QWORD[rdi],r12
-	cmovz	r8,rcx
+	cmovc	r8,rcx
 	mov	QWORD[8+rdi],r13
-	cmovz	r9,r10
+	cmovc	r9,r10
 	mov	QWORD[16+rdi],r8
 	mov	QWORD[24+rdi],r9
 
@@ -964,13 +966,14 @@
 
 ALIGN	32
 __ecp_nistz256_mul_by_2q:
+	xor	r11,r11
 	add	r12,r12
 	adc	r13,r13
 	mov	rax,r12
 	adc	r8,r8
 	adc	r9,r9
 	mov	rbp,r13
-	sbb	r11,r11
+	adc	r11,0
 
 	sub	r12,-1
 	mov	rcx,r8
@@ -978,14 +981,14 @@
 	sbb	r8,0
 	mov	r10,r9
 	sbb	r9,r15
-	test	r11,r11
+	sbb	r11,0
 
-	cmovz	r12,rax
-	cmovz	r13,rbp
+	cmovc	r12,rax
+	cmovc	r13,rbp
 	mov	QWORD[rdi],r12
-	cmovz	r8,rcx
+	cmovc	r8,rcx
 	mov	QWORD[8+rdi],r13
-	cmovz	r9,r10
+	cmovc	r9,r10
 	mov	QWORD[16+rdi],r8
 	mov	QWORD[24+rdi],r9
 
@@ -1234,16 +1237,14 @@
 	mov	rsi,rdx
 	movdqa	XMMWORD[384+rsp],xmm0
 	movdqa	XMMWORD[(384+16)+rsp],xmm1
-	por	xmm1,xmm0
 	movdqa	XMMWORD[416+rsp],xmm2
 	movdqa	XMMWORD[(416+16)+rsp],xmm3
-	por	xmm3,xmm2
 	movdqa	XMMWORD[448+rsp],xmm4
 	movdqa	XMMWORD[(448+16)+rsp],xmm5
-	por	xmm3,xmm1
+	por	xmm5,xmm4
 
 	movdqu	xmm0,XMMWORD[rsi]
-	pshufd	xmm5,xmm3,0xb1
+	pshufd	xmm3,xmm5,0xb1
 	movdqu	xmm1,XMMWORD[16+rsi]
 	movdqu	xmm2,XMMWORD[32+rsi]
 	por	xmm5,xmm3
@@ -1255,14 +1256,14 @@
 	movdqa	XMMWORD[480+rsp],xmm0
 	pshufd	xmm4,xmm5,0x1e
 	movdqa	XMMWORD[(480+16)+rsp],xmm1
-	por	xmm1,xmm0
-DB	102,72,15,110,199
+	movdqu	xmm0,XMMWORD[64+rsi]
+	movdqu	xmm1,XMMWORD[80+rsi]
 	movdqa	XMMWORD[512+rsp],xmm2
 	movdqa	XMMWORD[(512+16)+rsp],xmm3
-	por	xmm3,xmm2
 	por	xmm5,xmm4
 	pxor	xmm4,xmm4
-	por	xmm3,xmm1
+	por	xmm1,xmm0
+DB	102,72,15,110,199
 
 	lea	rsi,[((64-0))+rsi]
 	mov	QWORD[((544+0))+rsp],rax
@@ -1273,8 +1274,8 @@
 	call	__ecp_nistz256_sqr_montq
 
 	pcmpeqd	xmm5,xmm4
-	pshufd	xmm4,xmm3,0xb1
-	por	xmm4,xmm3
+	pshufd	xmm4,xmm1,0xb1
+	por	xmm4,xmm1
 	pshufd	xmm5,xmm5,0
 	pshufd	xmm3,xmm4,0x1e
 	por	xmm4,xmm3
@@ -1457,6 +1458,7 @@
 
 
 
+	xor	r11,r11
 	add	r12,r12
 	lea	rsi,[96+rsp]
 	adc	r13,r13
@@ -1464,7 +1466,7 @@
 	adc	r8,r8
 	adc	r9,r9
 	mov	rbp,r13
-	sbb	r11,r11
+	adc	r11,0
 
 	sub	r12,-1
 	mov	rcx,r8
@@ -1472,15 +1474,15 @@
 	sbb	r8,0
 	mov	r10,r9
 	sbb	r9,r15
-	test	r11,r11
+	sbb	r11,0
 
-	cmovz	r12,rax
+	cmovc	r12,rax
 	mov	rax,QWORD[rsi]
-	cmovz	r13,rbp
+	cmovc	r13,rbp
 	mov	rbp,QWORD[8+rsi]
-	cmovz	r8,rcx
+	cmovc	r8,rcx
 	mov	rcx,QWORD[16+rsi]
-	cmovz	r9,r10
+	cmovc	r9,r10
 	mov	r10,QWORD[24+rsi]
 
 	call	__ecp_nistz256_subq
@@ -1645,16 +1647,14 @@
 	mov	r8,QWORD[((64+24))+rsi]
 	movdqa	XMMWORD[320+rsp],xmm0
 	movdqa	XMMWORD[(320+16)+rsp],xmm1
-	por	xmm1,xmm0
 	movdqa	XMMWORD[352+rsp],xmm2
 	movdqa	XMMWORD[(352+16)+rsp],xmm3
-	por	xmm3,xmm2
 	movdqa	XMMWORD[384+rsp],xmm4
 	movdqa	XMMWORD[(384+16)+rsp],xmm5
-	por	xmm3,xmm1
+	por	xmm5,xmm4
 
 	movdqu	xmm0,XMMWORD[rbx]
-	pshufd	xmm5,xmm3,0xb1
+	pshufd	xmm3,xmm5,0xb1
 	movdqu	xmm1,XMMWORD[16+rbx]
 	movdqu	xmm2,XMMWORD[32+rbx]
 	por	xmm5,xmm3
@@ -1772,6 +1772,7 @@
 
 
 
+	xor	r11,r11
 	add	r12,r12
 	lea	rsi,[192+rsp]
 	adc	r13,r13
@@ -1779,7 +1780,7 @@
 	adc	r8,r8
 	adc	r9,r9
 	mov	rbp,r13
-	sbb	r11,r11
+	adc	r11,0
 
 	sub	r12,-1
 	mov	rcx,r8
@@ -1787,15 +1788,15 @@
 	sbb	r8,0
 	mov	r10,r9
 	sbb	r9,r15
-	test	r11,r11
+	sbb	r11,0
 
-	cmovz	r12,rax
+	cmovc	r12,rax
 	mov	rax,QWORD[rsi]
-	cmovz	r13,rbp
+	cmovc	r13,rbp
 	mov	rbp,QWORD[8+rsi]
-	cmovz	r8,rcx
+	cmovc	r8,rcx
 	mov	rcx,QWORD[16+rsi]
-	cmovz	r9,r10
+	cmovc	r9,r10
 	mov	r10,QWORD[24+rsi]
 
 	call	__ecp_nistz256_subq