SSL_export_keying_material should work in half-RTT.

QUIC will need to derive keys at this point. This also smooths over a
part of the server 0-RTT abstraction. Like with False Start, the SSL
object is largely in a functional state at this point.

Bug: 221
Change-Id: I4207d8cb1273a1156e728a7bff3943cc2c69e288
Reviewed-on: https://boringssl-review.googlesource.com/24224
Commit-Queue: Steven Valdez <svaldez@google.com>
Reviewed-by: Steven Valdez <svaldez@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
diff --git a/crypto/err/ssl.errordata b/crypto/err/ssl.errordata
index f5c2873..58c9115 100644
--- a/crypto/err/ssl.errordata
+++ b/crypto/err/ssl.errordata
@@ -65,6 +65,7 @@
 SSL,152,FRAGMENT_MISMATCH
 SSL,153,GOT_NEXT_PROTO_WITHOUT_EXTENSION
 SSL,154,HANDSHAKE_FAILURE_ON_CLIENT_HELLO
+SSL,284,HANDSHAKE_NOT_COMPLETE
 SSL,155,HTTPS_PROXY_REQUEST
 SSL,156,HTTP_REQUEST
 SSL,157,INAPPROPRIATE_FALLBACK
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 8dad6a4..066390b 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -4569,6 +4569,7 @@
 #define SSL_R_APPLICATION_DATA_INSTEAD_OF_HANDSHAKE 281
 #define SSL_R_EMPTY_HELLO_RETRY_REQUEST 282
 #define SSL_R_EARLY_DATA_NOT_IN_USE 283
+#define SSL_R_HANDSHAKE_NOT_COMPLETE 284
 #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/ssl/t1_enc.cc b/ssl/t1_enc.cc
index 4e81fe8..6b5447d 100644
--- a/ssl/t1_enc.cc
+++ b/ssl/t1_enc.cc
@@ -458,11 +458,16 @@
                                const uint8_t *context, size_t context_len,
                                int use_context) {
   if (!ssl->s3->have_version || ssl->version == SSL3_VERSION) {
+    OPENSSL_PUT_ERROR(SSL, SSL_R_HANDSHAKE_NOT_COMPLETE);
     return 0;
   }
 
-  // Exporters may not be used in the middle of a renegotiation.
-  if (SSL_in_init(ssl) && !SSL_in_false_start(ssl)) {
+  // Exporters may be used in False Start and server 0-RTT, where the handshake
+  // has progressed enough. Otherwise, they may not be used during a handshake.
+  if (SSL_in_init(ssl) &&
+      !SSL_in_false_start(ssl) &&
+      !(SSL_is_server(ssl) && SSL_in_early_data(ssl))) {
+    OPENSSL_PUT_ERROR(SSL, SSL_R_HANDSHAKE_NOT_COMPLETE);
     return 0;
   }
 
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index fbd016a..4cfce26 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -9070,6 +9070,9 @@
 			config: Config{
 				MaxVersion: vers.version,
 			},
+			// Test the exporter in both initial and resumption
+			// handshakes.
+			resumeSession:        true,
 			tls13Variant:         vers.tls13Variant,
 			exportKeyingMaterial: 1024,
 			exportLabel:          "label",
@@ -9106,6 +9109,28 @@
 		})
 
 		if vers.version >= VersionTLS13 {
+			// Test the exporters do not work while the client is
+			// sending 0-RTT data.
+			testCases = append(testCases, testCase{
+				name: "NoEarlyKeyingMaterial-Client-InEarlyData-" + vers.name,
+				config: Config{
+					MaxVersion:       vers.version,
+					MaxEarlyDataSize: 16384,
+				},
+				resumeSession: true,
+				tls13Variant:  vers.tls13Variant,
+				flags: []string{
+					"-enable-early-data",
+					"-expect-ticket-supports-early-data",
+					"-expect-accept-early-data",
+					"-on-resume-export-keying-material", "1024",
+					"-on-resume-export-label", "label",
+					"-on-resume-export-context", "context",
+				},
+				shouldFail:    true,
+				expectedError: ":HANDSHAKE_NOT_COMPLETE:",
+			})
+
 			// Test the early exporter works while the client is
 			// sending 0-RTT data. This data arrives during the
 			// server handshake, so we test it with ProtocolBugs.
@@ -9211,10 +9236,30 @@
 				expectedError: ":EARLY_DATA_NOT_IN_USE:",
 			})
 
-			// Test the early exporter works on the server.
+			// Test the normal exporter on the server in half-RTT.
 			testCases = append(testCases, testCase{
 				testType: serverTest,
-				name:     "ExportEarlyKeyingMaterial-Server-" + vers.name,
+				name:     "ExportKeyingMaterial-Server-HalfRTT-" + vers.name,
+				config: Config{
+					MaxVersion: vers.version,
+					Bugs: ProtocolBugs{
+						SendEarlyData:           [][]byte{},
+						ExpectEarlyDataAccepted: true,
+					},
+				},
+				tls13Variant:         vers.tls13Variant,
+				resumeSession:        true,
+				exportKeyingMaterial: 1024,
+				exportLabel:          "label",
+				exportContext:        "context",
+				useExportContext:     true,
+				flags:                []string{"-enable-early-data"},
+			})
+
+			// Test the early exporter works on the server in half-RTT.
+			testCases = append(testCases, testCase{
+				testType: serverTest,
+				name:     "ExportEarlyKeyingMaterial-Server-HalfRTT-" + vers.name,
 				config: Config{
 					MaxVersion: vers.version,
 					Bugs: ProtocolBugs{