Adding RSA-PSS signature algorithms.

[Rebased and tests added by davidben.]

In doing so, regenerate the test RSA certificate to be 2048-bit RSA.
RSA-PSS with SHA-512 is actually too large for 1024-bit RSA. Also make
the sigalg test loop test versions that do and don't work which subsumes
the ecdsa_sha1 TLS 1.3 test.

For now, RSA-PKCS1 is still allowed because NSS has yet to implement
RSA-PSS and we'd like to avoid complicated interop testing.

Change-Id: I686b003ef7042ff757bdaab8d5838b7a4d6edd87
Reviewed-on: https://boringssl-review.googlesource.com/8613
Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h
index cfb314d..84ff12f 100644
--- a/include/openssl/tls1.h
+++ b/include/openssl/tls1.h
@@ -253,6 +253,9 @@
 #define SSL_SIGN_ECDSA_SECP256R1_SHA256 0x0403
 #define SSL_SIGN_ECDSA_SECP384R1_SHA384 0x0503
 #define SSL_SIGN_ECDSA_SECP521R1_SHA512 0x0603
+#define SSL_SIGN_RSA_PSS_SHA256         0x0700
+#define SSL_SIGN_RSA_PSS_SHA384         0x0701
+#define SSL_SIGN_RSA_PSS_SHA512         0x0702
 
 /* Reserved SignatureScheme value to indicate RSA with MD5-SHA1. This will never
  * be negotiated in TLS 1.2 and up, but is used to unify signing interfaces in
diff --git a/ssl/ssl_rsa.c b/ssl/ssl_rsa.c
index cca2f06..929de04 100644
--- a/ssl/ssl_rsa.c
+++ b/ssl/ssl_rsa.c
@@ -401,6 +401,9 @@
   return EVP_PKEY_size(ssl->cert->privatekey);
 }
 
+/* TODO(davidben): Forbid RSA-PKCS1 in TLS 1.3. For now we allow it because NSS
+ * has yet to start doing RSA-PSS, so enforcing it would complicate interop
+ * testing. */
 static int is_rsa_pkcs1(const EVP_MD **out_md, uint16_t sigalg) {
   switch (sigalg) {
     case SSL_SIGN_RSA_PKCS1_MD5_SHA1:
@@ -530,6 +533,61 @@
   return ret;
 }
 
+static int is_rsa_pss(const EVP_MD **out_md, uint16_t sigalg) {
+  switch (sigalg) {
+    case SSL_SIGN_RSA_PSS_SHA256:
+      *out_md = EVP_sha256();
+      return 1;
+    case SSL_SIGN_RSA_PSS_SHA384:
+      *out_md = EVP_sha384();
+      return 1;
+    case SSL_SIGN_RSA_PSS_SHA512:
+      *out_md = EVP_sha512();
+      return 1;
+    default:
+      return 0;
+  }
+}
+
+static int ssl_sign_rsa_pss(SSL *ssl, uint8_t *out, size_t *out_len,
+                              size_t max_out, const EVP_MD *md,
+                              const uint8_t *in, size_t in_len) {
+  EVP_MD_CTX ctx;
+  EVP_MD_CTX_init(&ctx);
+  *out_len = max_out;
+  EVP_PKEY_CTX *pctx;
+  int ret =
+      EVP_DigestSignInit(&ctx, &pctx, md, NULL, ssl->cert->privatekey) &&
+      EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) &&
+      EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, -1 /* salt len = hash len */) &&
+      EVP_DigestSignUpdate(&ctx, in, in_len) &&
+      EVP_DigestSignFinal(&ctx, out, out_len);
+  EVP_MD_CTX_cleanup(&ctx);
+  return ret;
+}
+
+static int ssl_verify_rsa_pss(SSL *ssl, const uint8_t *signature,
+                                size_t signature_len, const EVP_MD *md,
+                                EVP_PKEY *pkey, const uint8_t *in,
+                                size_t in_len) {
+  if (pkey->type != EVP_PKEY_RSA) {
+    OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SIGNATURE_TYPE);
+    return 0;
+  }
+
+  EVP_MD_CTX md_ctx;
+  EVP_MD_CTX_init(&md_ctx);
+  EVP_PKEY_CTX *pctx;
+  int ret =
+      EVP_DigestVerifyInit(&md_ctx, &pctx, md, NULL, pkey) &&
+      EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) &&
+      EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, -1 /* salt len = hash len */) &&
+      EVP_DigestVerifyUpdate(&md_ctx, in, in_len) &&
+      EVP_DigestVerifyFinal(&md_ctx, signature, signature_len);
+  EVP_MD_CTX_cleanup(&md_ctx);
+  return ret;
+}
+
 enum ssl_private_key_result_t ssl_private_key_sign(
     SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out,
     uint16_t signature_algorithm, const uint8_t *in, size_t in_len) {
@@ -562,6 +620,7 @@
                ? ssl_private_key_success
                : ssl_private_key_failure;
   }
+
   int curve;
   if (is_ecdsa(&curve, &md, signature_algorithm)) {
     return ssl_sign_ecdsa(ssl, out, out_len, max_out, curve, md, in, in_len)
@@ -569,6 +628,13 @@
                : ssl_private_key_failure;
   }
 
+  if (is_rsa_pss(&md, signature_algorithm) &&
+      ssl3_protocol_version(ssl) >= TLS1_3_VERSION) {
+    return ssl_sign_rsa_pss(ssl, out, out_len, max_out, md, in, in_len)
+               ? ssl_private_key_success
+               : ssl_private_key_failure;
+  }
+
   OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SIGNATURE_TYPE);
   return ssl_private_key_failure;
 }
@@ -587,12 +653,19 @@
     return ssl_verify_rsa_pkcs1(ssl, signature, signature_len, md, pkey, in,
                                 in_len);
   }
+
   int curve;
   if (is_ecdsa(&curve, &md, signature_algorithm)) {
     return ssl_verify_ecdsa(ssl, signature, signature_len, curve, md, pkey, in,
                             in_len);
   }
 
+  if (is_rsa_pss(&md, signature_algorithm) &&
+      ssl3_protocol_version(ssl) >= TLS1_3_VERSION) {
+    return ssl_verify_rsa_pss(ssl, signature, signature_len, md, pkey, in,
+                              in_len);
+  }
+
   OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SIGNATURE_TYPE);
   return 0;
 }
@@ -652,5 +725,10 @@
     return 1;
   }
 
+  if (is_rsa_pss(&md, signature_algorithm)) {
+    return ssl_private_key_type(ssl) == EVP_PKEY_RSA &&
+           ssl3_protocol_version(ssl) >= TLS1_3_VERSION;
+  }
+
   return 0;
 }
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index 5279a5d..4594649 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -517,7 +517,37 @@
     SSL_SIGN_ECDSA_SHA1,
 };
 
+static const uint16_t kDefaultTLS13SignatureAlgorithms[] = {
+    SSL_SIGN_RSA_PSS_SHA512,
+    SSL_SIGN_RSA_PKCS1_SHA512,
+    SSL_SIGN_ECDSA_SECP521R1_SHA512,
+
+    SSL_SIGN_RSA_PSS_SHA384,
+    SSL_SIGN_RSA_PKCS1_SHA384,
+    SSL_SIGN_ECDSA_SECP384R1_SHA384,
+
+    SSL_SIGN_RSA_PSS_SHA256,
+    SSL_SIGN_RSA_PKCS1_SHA256,
+    SSL_SIGN_ECDSA_SECP256R1_SHA256,
+
+    SSL_SIGN_RSA_PKCS1_SHA1,
+    SSL_SIGN_ECDSA_SHA1,
+};
+
 size_t tls12_get_psigalgs(SSL *ssl, const uint16_t **psigs) {
+  uint16_t version;
+  if (ssl->s3->have_version) {
+    version = ssl3_protocol_version(ssl);
+  } else {
+    version = ssl->method->version_from_wire(ssl->client_version);
+  }
+
+  if (version >= TLS1_3_VERSION) {
+    *psigs = kDefaultTLS13SignatureAlgorithms;
+    return sizeof(kDefaultTLS13SignatureAlgorithms) /
+           sizeof(kDefaultTLS13SignatureAlgorithms[0]);
+  }
+
   *psigs = kDefaultSignatureAlgorithms;
   return sizeof(kDefaultSignatureAlgorithms) /
          sizeof(kDefaultSignatureAlgorithms[0]);
@@ -561,6 +591,9 @@
   sigalgslen = tls12_get_psigalgs(ssl, &sigalgs);
   for (i = 0; i < sigalgslen; i++) {
     switch (sigalgs[i]) {
+      case SSL_SIGN_RSA_PSS_SHA512:
+      case SSL_SIGN_RSA_PSS_SHA384:
+      case SSL_SIGN_RSA_PSS_SHA256:
       case SSL_SIGN_RSA_PKCS1_SHA512:
       case SSL_SIGN_RSA_PKCS1_SHA384:
       case SSL_SIGN_RSA_PKCS1_SHA256:
@@ -2571,9 +2604,8 @@
     return 1;
   }
 
-  const uint16_t *sigalgs = kDefaultSignatureAlgorithms;
-  size_t sigalgs_len = sizeof(kDefaultSignatureAlgorithms) /
-                       sizeof(kDefaultSignatureAlgorithms[0]);
+  const uint16_t *sigalgs;
+  size_t sigalgs_len = tls12_get_psigalgs(ssl, &sigalgs);
   if (cert->sigalgs != NULL) {
     sigalgs = cert->sigalgs;
     sigalgs_len = cert->sigalgs_len;
diff --git a/ssl/test/runner/cert.pem b/ssl/test/runner/cert.pem
index 4de4f49..c360dc7 100644
--- a/ssl/test/runner/cert.pem
+++ b/ssl/test/runner/cert.pem
@@ -1,15 +1,22 @@
 -----BEGIN CERTIFICATE-----
-MIICWDCCAcGgAwIBAgIJAPuwTC6rEJsMMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV
-BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
-aWRnaXRzIFB0eSBMdGQwHhcNMTQwNDIzMjA1MDQwWhcNMTcwNDIyMjA1MDQwWjBF
-MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
-ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB
-gQDYK8imMuRi/03z0K1Zi0WnvfFHvwlYeyK9Na6XJYaUoIDAtB92kWdGMdAQhLci
-HnAjkXLI6W15OoV3gA/ElRZ1xUpxTMhjP6PyY5wqT5r6y8FxbiiFKKAnHmUcrgfV
-W28tQ+0rkLGMryRtrukXOgXBv7gcrmU7G1jC2a7WqmeI8QIDAQABo1AwTjAdBgNV
-HQ4EFgQUi3XVrMsIvg4fZbf6Vr5sp3Xaha8wHwYDVR0jBBgwFoAUi3XVrMsIvg4f
-Zbf6Vr5sp3Xaha8wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQA76Hht
-ldY9avcTGSwbwoiuIqv0jTL1fHFnzy3RHMLDh+Lpvolc5DSrSJHCP5WuK0eeJXhr
-T5oQpHL9z/cCDLAKCKRa4uV0fhEdOWBqyR9p8y5jJtye72t6CuFUV5iqcpF4BH4f
-j2VNHwsSrJwkD4QUGlUtH7vwnQmyCFxZMmWAJg==
+MIIDtTCCAp2gAwIBAgIJALW2IrlaBKUhMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
+BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX
+aWRnaXRzIFB0eSBMdGQwHhcNMTYwNzA5MDQzODA5WhcNMTYwODA4MDQzODA5WjBF
+MQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50
+ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEAugvahBkSAUF1fC49vb1bvlPrcl80kop1iLpiuYoz4Qptwy57+EWssZBc
+HprZ5BkWf6PeGZ7F5AX1PyJbGHZLqvMCvViP6pd4MFox/igESISEHEixoiXCzepB
+rhtp5UQSjHD4D4hKtgdMgVxX+LRtwgW3mnu/vBu7rzpr/DS8io99p3lqZ1Aky+aN
+lcMj6MYy8U+YFEevb/V0lRY9oqwmW7BHnXikm/vi6sjIS350U8zb/mRzYeIs2R65
+LUduTL50+UMgat9ocewI2dv8aO9Dph+8NdGtg8LFYyTTHcUxJoMr1PTOgnmET19W
+JH4PrFwk7ZE1QJQQ1L4iKmPeQistuQIDAQABo4GnMIGkMB0GA1UdDgQWBBT5m6Vv
+zYjVYHG30iBE+j2XDhUE8jB1BgNVHSMEbjBsgBT5m6VvzYjVYHG30iBE+j2XDhUE
+8qFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNV
+BAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJALW2IrlaBKUhMAwGA1UdEwQF
+MAMBAf8wDQYJKoZIhvcNAQELBQADggEBAD7Jg68SArYWlcoHfZAB90Pmyrt5H6D8
+LRi+W2Ri1fBNxREELnezWJ2scjl4UMcsKYp4Pi950gVN+62IgrImcCNvtb5I1Cfy
+/MNNur9ffas6X334D0hYVIQTePyFk3umI+2mJQrtZZyMPIKSY/sYGQHhGGX6wGK+
+GO/og0PQk/Vu6D+GU2XRnDV0YZg1lsAsHd21XryK6fDmNkEMwbIWrts4xc7scRrG
+HWy+iMf6/7p/Ak/SIicM4XSwmlQ8pPxAZPr+E2LoVd9pMpWUwpW2UbtO5wsGTrY5
+sO45tFNN/y+jtUheB1C2ijObG/tXELaiyCdM+S/waeuv0MXtI4xnn1A=
 -----END CERTIFICATE-----
diff --git a/ssl/test/runner/key.pem b/ssl/test/runner/key.pem
index e9107bf..8cab774 100644
--- a/ssl/test/runner/key.pem
+++ b/ssl/test/runner/key.pem
@@ -1,15 +1,27 @@
 -----BEGIN RSA PRIVATE KEY-----
-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
+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
 -----END RSA PRIVATE KEY-----
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index aa86ea7..94476d4 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -4679,6 +4679,9 @@
 	{"ECDSA-P256-SHA256", signatureECDSAWithP256AndSHA256, testCertECDSAP256},
 	{"ECDSA-P384-SHA384", signatureECDSAWithP384AndSHA384, testCertECDSAP384},
 	{"ECDSA-P521-SHA512", signatureECDSAWithP521AndSHA512, testCertECDSAP521},
+	{"RSA-PSS-SHA256", signatureRSAPSSWithSHA256, testCertRSA},
+	{"RSA-PSS-SHA384", signatureRSAPSSWithSHA384, testCertRSA},
+	{"RSA-PSS-SHA512", signatureRSAPSSWithSHA512, testCertRSA},
 }
 
 const fakeSigAlg1 signatureAlgorithm = 0x2a01
@@ -4693,54 +4696,70 @@
 				continue
 			}
 
+			var shouldFail bool
 			// ecdsa_sha1 does not exist in TLS 1.3.
-			if ver.version == VersionTLS13 && alg.id == signatureECDSAWithSHA1 {
-				continue
+			if ver.version >= VersionTLS13 && alg.id == signatureECDSAWithSHA1 {
+				shouldFail = true
+			}
+			// RSA-PSS does not exist in TLS 1.2.
+			if ver.version == VersionTLS12 && hasComponent(alg.name, "PSS") {
+				shouldFail = true
+			}
+
+			var signError, verifyError string
+			if shouldFail {
+				signError = ":NO_COMMON_SIGNATURE_ALGORITHMS:"
+				verifyError = ":WRONG_SIGNATURE_TYPE:"
 			}
 
 			suffix := "-" + alg.name + "-" + ver.name
-			testCases = append(testCases, testCase{
-				name: "SigningHash-ClientAuth-Sign" + suffix,
-				config: Config{
-					MaxVersion: ver.version,
-					// SignatureAlgorithms is shared, so we must
-					// configure a matching server certificate too.
-					Certificates: []Certificate{getRunnerCertificate(alg.cert)},
-					ClientAuth:   RequireAnyClientCert,
-					SignatureAlgorithms: []signatureAlgorithm{
-						fakeSigAlg1,
-						alg.id,
-						fakeSigAlg2,
-					},
-				},
-				flags: []string{
-					"-cert-file", path.Join(*resourceDir, getShimCertificate(alg.cert)),
-					"-key-file", path.Join(*resourceDir, getShimKey(alg.cert)),
-					"-enable-all-curves",
-				},
-				expectedPeerSignatureAlgorithm: alg.id,
-			})
 
-			testCases = append(testCases, testCase{
-				testType: serverTest,
-				name:     "SigningHash-ClientAuth-Verify" + suffix,
-				config: Config{
-					MaxVersion:   ver.version,
-					Certificates: []Certificate{getRunnerCertificate(alg.cert)},
-					SignatureAlgorithms: []signatureAlgorithm{
-						alg.id,
+			// TODO(davidben): Separate signing and verifying sigalg
+			// configuration in Go, so we can run both sides.
+			if !shouldFail {
+				testCases = append(testCases, testCase{
+					name: "SigningHash-ClientAuth-Sign" + suffix,
+					config: Config{
+						MaxVersion: ver.version,
+						// SignatureAlgorithms is shared, so we must
+						// configure a matching server certificate too.
+						Certificates: []Certificate{getRunnerCertificate(alg.cert)},
+						ClientAuth:   RequireAnyClientCert,
+						SignatureAlgorithms: []signatureAlgorithm{
+							fakeSigAlg1,
+							alg.id,
+							fakeSigAlg2,
+						},
 					},
-				},
-				flags: []string{
-					"-require-any-client-certificate",
-					"-expect-peer-signature-algorithm", strconv.Itoa(int(alg.id)),
-					// SignatureAlgorithms is shared, so we must
-					// configure a matching server certificate too.
-					"-cert-file", path.Join(*resourceDir, getShimCertificate(alg.cert)),
-					"-key-file", path.Join(*resourceDir, getShimKey(alg.cert)),
-					"-enable-all-curves",
-				},
-			})
+					flags: []string{
+						"-cert-file", path.Join(*resourceDir, getShimCertificate(alg.cert)),
+						"-key-file", path.Join(*resourceDir, getShimKey(alg.cert)),
+						"-enable-all-curves",
+					},
+					expectedPeerSignatureAlgorithm: alg.id,
+				})
+
+				testCases = append(testCases, testCase{
+					testType: serverTest,
+					name:     "SigningHash-ClientAuth-Verify" + suffix,
+					config: Config{
+						MaxVersion:   ver.version,
+						Certificates: []Certificate{getRunnerCertificate(alg.cert)},
+						SignatureAlgorithms: []signatureAlgorithm{
+							alg.id,
+						},
+					},
+					flags: []string{
+						"-require-any-client-certificate",
+						"-expect-peer-signature-algorithm", strconv.Itoa(int(alg.id)),
+						// SignatureAlgorithms is shared, so we must
+						// configure a matching server certificate too.
+						"-cert-file", path.Join(*resourceDir, getShimCertificate(alg.cert)),
+						"-key-file", path.Join(*resourceDir, getShimKey(alg.cert)),
+						"-enable-all-curves",
+					},
+				})
+			}
 
 			testCases = append(testCases, testCase{
 				testType: serverTest,
@@ -4756,12 +4775,18 @@
 						alg.id,
 						fakeSigAlg2,
 					},
+					Bugs: ProtocolBugs{
+						SkipECDSACurveCheck:          shouldFail,
+						IgnoreSignatureVersionChecks: shouldFail,
+					},
 				},
 				flags: []string{
 					"-cert-file", path.Join(*resourceDir, getShimCertificate(alg.cert)),
 					"-key-file", path.Join(*resourceDir, getShimKey(alg.cert)),
 					"-enable-all-curves",
 				},
+				shouldFail:                     shouldFail,
+				expectedError:                  signError,
 				expectedPeerSignatureAlgorithm: alg.id,
 			})
 
@@ -4777,11 +4802,17 @@
 					SignatureAlgorithms: []signatureAlgorithm{
 						alg.id,
 					},
+					Bugs: ProtocolBugs{
+						SkipECDSACurveCheck:          shouldFail,
+						IgnoreSignatureVersionChecks: shouldFail,
+					},
 				},
 				flags: []string{
 					"-expect-peer-signature-algorithm", strconv.Itoa(int(alg.id)),
 					"-enable-all-curves",
 				},
+				shouldFail:    shouldFail,
+				expectedError: verifyError,
 			})
 		}
 	}
@@ -5123,24 +5154,6 @@
 		},
 		expectedPeerSignatureAlgorithm: signatureECDSAWithP256AndSHA256,
 	})
-
-	// ecdsa_sha1 cannot be negotiated in TLS 1.3.
-	testCases = append(testCases, testCase{
-		name: "NoECDSAWithSHA1-TLS13",
-		config: Config{
-			MaxVersion:   VersionTLS13,
-			CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
-			Certificates: []Certificate{ecdsaP256Certificate},
-			SignatureAlgorithms: []signatureAlgorithm{
-				signatureECDSAWithSHA1,
-			},
-			Bugs: ProtocolBugs{
-				SkipECDSACurveCheck: true,
-			},
-		},
-		shouldFail:    true,
-		expectedError: ":WRONG_SIGNATURE_TYPE:",
-	})
 }
 
 // timeouts is the retransmit schedule for BoringSSL. It doubles and