summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--crypto/ec_signature_creator_unittest.cc16
-rw-r--r--crypto/signature_verifier_openssl.cc15
-rw-r--r--net/data/ssl/certificates/README5
-rw-r--r--net/data/ssl/certificates/quic_intermediate.crt53
-rw-r--r--net/data/ssl/certificates/quic_proof_verify.crt106
-rw-r--r--net/data/ssl/certificates/quic_test.example.com.crt56
-rw-r--r--net/data/ssl/certificates/quic_test_ecc.example.com.crt50
-rw-r--r--net/net.gyp5
-rw-r--r--net/quic/crypto/crypto_handshake.cc12
-rw-r--r--net/quic/crypto/crypto_handshake.h11
-rw-r--r--net/quic/crypto/proof_test.cc348
-rw-r--r--net/quic/crypto/proof_verifier.h20
-rw-r--r--net/quic/crypto/proof_verifier_chromium.cc240
-rw-r--r--net/quic/crypto/proof_verifier_chromium.h89
-rw-r--r--net/quic/quic_crypto_client_stream.cc78
-rw-r--r--net/quic/quic_crypto_client_stream.h14
-rw-r--r--net/quic/quic_session.cc11
-rw-r--r--net/quic/quic_session.h10
-rw-r--r--net/quic/test_tools/crypto_test_utils_chromium.cc48
19 files changed, 1137 insertions, 50 deletions
diff --git a/crypto/ec_signature_creator_unittest.cc b/crypto/ec_signature_creator_unittest.cc
index b34022b..bc0cb4a 100644
--- a/crypto/ec_signature_creator_unittest.cc
+++ b/crypto/ec_signature_creator_unittest.cc
@@ -54,12 +54,22 @@ TEST(ECSignatureCreatorTest, BasicTest) {
std::vector<uint8> public_key_info;
ASSERT_TRUE(key_original->ExportPublicKey(&public_key_info));
- // This is the algorithm ID for SHA-256 with EC encryption.
+ // This is the algorithm ID for ECDSA with SHA-256. Parameters are ABSENT.
+ // RFC 5758:
+ // ecdsa-with-SHA256 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+ // us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 2 }
+ // ...
+ // When the ecdsa-with-SHA224, ecdsa-with-SHA256, ecdsa-with-SHA384, or
+ // ecdsa-with-SHA512 algorithm identifier appears in the algorithm field
+ // as an AlgorithmIdentifier, the encoding MUST omit the parameters
+ // field. That is, the AlgorithmIdentifier SHALL be a SEQUENCE of one
+ // component, the OID ecdsa-with-SHA224, ecdsa-with-SHA256, ecdsa-with-
+ // SHA384, or ecdsa-with-SHA512.
+ // See also RFC 5480, Appendix A.
const uint8 kECDSAWithSHA256AlgorithmID[] = {
- 0x30, 0x0c,
+ 0x30, 0x0a,
0x06, 0x08,
0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02,
- 0x05, 0x00
};
crypto::SignatureVerifier verifier;
ASSERT_TRUE(verifier.VerifyInit(
diff --git a/crypto/signature_verifier_openssl.cc b/crypto/signature_verifier_openssl.cc
index 1e71339..a85f00b 100644
--- a/crypto/signature_verifier_openssl.cc
+++ b/crypto/signature_verifier_openssl.cc
@@ -53,7 +53,17 @@ bool SignatureVerifier::VerifyInit(const uint8* signature_algorithm,
d2i_X509_ALGOR(NULL, &signature_algorithm, signature_algorithm_len));
if (!algorithm.get())
return false;
- const EVP_MD* digest = EVP_get_digestbyobj(algorithm.get()->algorithm);
+ int nid = OBJ_obj2nid(algorithm.get()->algorithm);
+ const EVP_MD* digest;
+ if (nid == NID_ecdsa_with_SHA1) {
+ digest = EVP_sha1();
+ } else if (nid == NID_ecdsa_with_SHA256) {
+ digest = EVP_sha256();
+ } else {
+ // This works for PKCS #1 v1.5 RSA signatures, but not for ECDSA
+ // signatures.
+ digest = EVP_get_digestbyobj(algorithm.get()->algorithm);
+ }
if (!digest)
return false;
@@ -104,7 +114,8 @@ bool SignatureVerifier::VerifyFinal() {
int rv = EVP_DigestVerifyFinal(verify_context_->ctx.get(),
vector_as_array(&signature_),
signature_.size());
- DCHECK_GE(rv, 0);
+ // rv is -1 if a DER-encoded ECDSA signature cannot be decoded correctly.
+ DCHECK_GE(rv, -1);
Reset();
return rv == 1;
}
diff --git a/net/data/ssl/certificates/README b/net/data/ssl/certificates/README
index 84844ea..84e65e9 100644
--- a/net/data/ssl/certificates/README
+++ b/net/data/ssl/certificates/README
@@ -214,3 +214,8 @@ unit tests.
server for simulating HTTPS connections. They are generated by running
the script net/data/ssl/scripts/generate-test-certs.sh.
+- quic_intermediate.crt
+- quic_test_ecc.example.com.crt
+- quic_test.example.com.crt
+- quic_proof_verify.crt
+ These certificates are used by the ProofVerifier's unit tests of QUIC.
diff --git a/net/data/ssl/certificates/quic_intermediate.crt b/net/data/ssl/certificates/quic_intermediate.crt
new file mode 100644
index 0000000..ca1e6f6
--- /dev/null
+++ b/net/data/ssl/certificates/quic_intermediate.crt
@@ -0,0 +1,53 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 2 (0x2)
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: O=Acme Co, CN=Root CA
+ Validity
+ Not Before: Jan 1 10:00:00 2013 GMT
+ Not After : Dec 31 10:00:00 2023 GMT
+ Subject: O=Acme Co, CN=Intermediate CA
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (1024 bit)
+ Modulus:
+ 00:af:95:dd:a0:eb:d7:c3:ba:a6:ae:db:6e:05:68:
+ a0:00:15:a1:85:d1:89:ba:be:3a:7a:3b:8c:3b:41:
+ 07:76:63:71:28:f7:bf:a5:fb:b3:28:94:f9:9a:de:
+ 1d:03:00:ce:5e:25:06:6a:e6:c7:0a:6b:6d:d3:76:
+ 95:57:f5:16:f8:f0:43:de:b7:c7:1b:0b:83:f4:70:
+ e6:29:a1:8d:22:12:9a:df:4b:31:e8:9b:86:7d:95:
+ 29:97:18:c1:34:2f:b6:a7:c1:c7:46:d6:9c:c6:a6:
+ ae:6e:dd:8f:be:c2:ec:02:00:d2:54:f6:0f:a0:cc:
+ af:04:85:65:98:a1:ea:73:f1
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Key Usage: critical
+ Certificate Sign
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha1WithRSAEncryption
+ 9a:68:79:17:6c:13:20:b3:5f:01:ca:ae:c0:bf:d2:7b:98:bf:
+ dd:4d:d1:c3:a5:ab:01:47:2e:c8:61:b4:f5:1d:55:04:f0:eb:
+ 5d:84:5a:78:09:b0:f1:42:64:14:e8:9e:ba:c3:38:32:d3:16:
+ fe:e1:65:1f:76:da:e4:c0:83:62:4a:ae:d0:4e:00:2e:38:52:
+ 91:81:62:94:b0:3d:69:b3:87:72:39:55:94:9e:ca:2c:ca:51:
+ 3c:d3:3f:d2:1c:92:d3:de:df:ba:bc:45:9b:30:99:b4:39:f8:
+ 17:55:94:7d:3a:ba:0e:e9:3f:2d:bc:f0:ea:6d:17:85:23:e4:
+ ca:94
+-----BEGIN CERTIFICATE-----
+MIIB+DCCAWOgAwIBAgIBAjALBgkqhkiG9w0BAQUwJDEQMA4GA1UEChMHQWNtZSBD
+bzEQMA4GA1UEAxMHUm9vdCBDQTAeFw0xMzAxMDExMDAwMDBaFw0yMzEyMzExMDAw
+MDBaMCwxEDAOBgNVBAoTB0FjbWUgQ28xGDAWBgNVBAMTD0ludGVybWVkaWF0ZSBD
+QTCBnTALBgkqhkiG9w0BAQEDgY0AMIGJAoGBAK+V3aDr18O6pq7bbgVooAAVoYXR
+ibq+Ono7jDtBB3ZjcSj3v6X7syiU+ZreHQMAzl4lBmrmxwprbdN2lVf1FvjwQ963
+xxsLg/Rw5imhjSISmt9LMeibhn2VKZcYwTQvtqfBx0bWnMamrm7dj77C7AIA0lT2
+D6DMrwSFZZih6nPxAgMBAAGjODA2MA4GA1UdDwEB/wQEAwIABDATBgNVHSUEDDAK
+BggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MAsGCSqGSIb3DQEBBQOBgQCaaHkX
+bBMgs18Byq7Av9J7mL/dTdHDpasBRy7IYbT1HVUE8OtdhFp4CbDxQmQU6J66wzgy
+0xb+4WUfdtrkwINiSq7QTgAuOFKRgWKUsD1ps4dyOVWUnsosylE80z/SHJLT3t+6
+vEWbMJm0OfgXVZR9OroO6T8tvPDqbReFI+TKlA==
+-----END CERTIFICATE-----
diff --git a/net/data/ssl/certificates/quic_proof_verify.crt b/net/data/ssl/certificates/quic_proof_verify.crt
new file mode 100644
index 0000000..55502e6
--- /dev/null
+++ b/net/data/ssl/certificates/quic_proof_verify.crt
@@ -0,0 +1,106 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: O=Acme Co, CN=Root CA
+ Validity
+ Not Before: Jan 1 10:00:00 2013 GMT
+ Not After : Dec 31 10:00:00 2023 GMT
+ Subject: O=Acme Co, CN=Root CA
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (1024 bit)
+ Modulus:
+ 00:f3:8f:b5:01:f7:8f:bf:0e:c3:bc:2e:43:f9:63:
+ 32:ae:e2:70:2d:77:70:bf:32:57:77:dd:00:f4:16:
+ 08:e2:f4:b8:b4:c9:bc:41:be:54:ba:44:3f:6f:77:
+ f9:d1:1b:52:25:16:7d:df:f9:29:79:3c:7c:8f:16:
+ e3:85:d5:7c:96:5e:2e:60:b3:80:e1:fc:09:b9:04:
+ 4d:ff:bc:05:25:55:96:b8:e7:7e:03:ed:f4:a1:93:
+ 54:66:b6:d5:e4:1f:92:94:52:7d:c3:60:89:5f:79:
+ f9:63:d1:f4:bb:4d:fa:da:4d:2e:d2:1d:ac:dc:7a:
+ 4f:52:67:3f:ad:eb:ed:ba:cd
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Key Usage: critical
+ Certificate Sign
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha1WithRSAEncryption
+ 7c:0f:20:54:85:ea:e9:68:c5:15:fc:10:8a:09:98:0e:51:53:
+ 7a:a3:37:c3:ec:8d:61:2c:49:66:d0:34:0b:8b:68:50:58:75:
+ 1f:fb:76:87:89:16:7d:56:d1:be:2f:bb:ef:95:26:92:55:37:
+ 6f:ca:82:e2:d4:93:33:80:1f:9c:b9:2d:1e:ee:3b:90:7d:13:
+ 2e:28:9b:17:8c:15:5f:12:eb:ed:f2:86:2f:a5:f5:59:e4:f3:
+ 07:a9:99:2d:32:70:d4:2a:d0:43:f2:1c:92:6d:75:f8:60:fa:
+ b5:8f:4f:07:6b:f6:c0:80:b3:4f:c8:9f:ed:11:bd:4d:d9:d7:
+ 4a:2c
+-----BEGIN CERTIFICATE-----
+MIIB8DCCAVugAwIBAgIBATALBgkqhkiG9w0BAQUwJDEQMA4GA1UEChMHQWNtZSBD
+bzEQMA4GA1UEAxMHUm9vdCBDQTAeFw0xMzAxMDExMDAwMDBaFw0yMzEyMzExMDAw
+MDBaMCQxEDAOBgNVBAoTB0FjbWUgQ28xEDAOBgNVBAMTB1Jvb3QgQ0EwgZ0wCwYJ
+KoZIhvcNAQEBA4GNADCBiQKBgQDzj7UB94+/DsO8LkP5YzKu4nAtd3C/Mld33QD0
+Fgji9Li0ybxBvlS6RD9vd/nRG1IlFn3f+Sl5PHyPFuOF1XyWXi5gs4Dh/Am5BE3/
+vAUlVZa4534D7fShk1RmttXkH5KUUn3DYIlfeflj0fS7TfraTS7SHazcek9SZz+t
+6+26zQIDAQABozgwNjAOBgNVHQ8BAf8EBAMCAAQwEwYDVR0lBAwwCgYIKwYBBQUH
+AwEwDwYDVR0TAQH/BAUwAwEB/zALBgkqhkiG9w0BAQUDgYEAfA8gVIXq6WjFFfwQ
+igmYDlFTeqM3w+yNYSxJZtA0C4toUFh1H/t2h4kWfVbRvi+775UmklU3b8qC4tST
+M4AfnLktHu47kH0TLiibF4wVXxLr7fKGL6X1WeTzB6mZLTJw1CrQQ/Ickm11+GD6
+tY9PB2v2wICzT8if7RG9TdnXSiw=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: O=Acme Co, CN=Root CA
+ Validity
+ Not Before: Jan 1 10:00:00 2013 GMT
+ Not After : Dec 31 10:00:00 2023 GMT
+ Subject: O=Acme Co, CN=Root CA
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (1024 bit)
+ Modulus:
+ 00:f3:8f:b5:01:f7:8f:bf:0e:c3:bc:2e:43:f9:63:
+ 32:ae:e2:70:2d:77:70:bf:32:57:77:dd:00:f4:16:
+ 08:e2:f4:b8:b4:c9:bc:41:be:54:ba:44:3f:6f:77:
+ f9:d1:1b:52:25:16:7d:df:f9:29:79:3c:7c:8f:16:
+ e3:85:d5:7c:96:5e:2e:60:b3:80:e1:fc:09:b9:04:
+ 4d:ff:bc:05:25:55:96:b8:e7:7e:03:ed:f4:a1:93:
+ 54:66:b6:d5:e4:1f:92:94:52:7d:c3:60:89:5f:79:
+ f9:63:d1:f4:bb:4d:fa:da:4d:2e:d2:1d:ac:dc:7a:
+ 4f:52:67:3f:ad:eb:ed:ba:cd
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Key Usage: critical
+ Certificate Sign
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha1WithRSAEncryption
+ 7c:0f:20:54:85:ea:e9:68:c5:15:fc:10:8a:09:98:0e:51:53:
+ 7a:a3:37:c3:ec:8d:61:2c:49:66:d0:34:0b:8b:68:50:58:75:
+ 1f:fb:76:87:89:16:7d:56:d1:be:2f:bb:ef:95:26:92:55:37:
+ 6f:ca:82:e2:d4:93:33:80:1f:9c:b9:2d:1e:ee:3b:90:7d:13:
+ 2e:28:9b:17:8c:15:5f:12:eb:ed:f2:86:2f:a5:f5:59:e4:f3:
+ 07:a9:99:2d:32:70:d4:2a:d0:43:f2:1c:92:6d:75:f8:60:fa:
+ b5:8f:4f:07:6b:f6:c0:80:b3:4f:c8:9f:ed:11:bd:4d:d9:d7:
+ 4a:2c
+-----BEGIN CERTIFICATE-----
+MIIB8DCCAVugAwIBAgIBATALBgkqhkiG9w0BAQUwJDEQMA4GA1UEChMHQWNtZSBD
+bzEQMA4GA1UEAxMHUm9vdCBDQTAeFw0xMzAxMDExMDAwMDBaFw0yMzEyMzExMDAw
+MDBaMCQxEDAOBgNVBAoTB0FjbWUgQ28xEDAOBgNVBAMTB1Jvb3QgQ0EwgZ0wCwYJ
+KoZIhvcNAQEBA4GNADCBiQKBgQDzj7UB94+/DsO8LkP5YzKu4nAtd3C/Mld33QD0
+Fgji9Li0ybxBvlS6RD9vd/nRG1IlFn3f+Sl5PHyPFuOF1XyWXi5gs4Dh/Am5BE3/
+vAUlVZa4534D7fShk1RmttXkH5KUUn3DYIlfeflj0fS7TfraTS7SHazcek9SZz+t
+6+26zQIDAQABozgwNjAOBgNVHQ8BAf8EBAMCAAQwEwYDVR0lBAwwCgYIKwYBBQUH
+AwEwDwYDVR0TAQH/BAUwAwEB/zALBgkqhkiG9w0BAQUDgYEAfA8gVIXq6WjFFfwQ
+igmYDlFTeqM3w+yNYSxJZtA0C4toUFh1H/t2h4kWfVbRvi+775UmklU3b8qC4tST
+M4AfnLktHu47kH0TLiibF4wVXxLr7fKGL6X1WeTzB6mZLTJw1CrQQ/Ickm11+GD6
+tY9PB2v2wICzT8if7RG9TdnXSiw=
+-----END CERTIFICATE-----
diff --git a/net/data/ssl/certificates/quic_test.example.com.crt b/net/data/ssl/certificates/quic_test.example.com.crt
new file mode 100644
index 0000000..375cedd
--- /dev/null
+++ b/net/data/ssl/certificates/quic_test.example.com.crt
@@ -0,0 +1,56 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 3 (0x3)
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: O=Acme Co, CN=Intermediate CA
+ Validity
+ Not Before: Jan 1 10:00:00 2013 GMT
+ Not After : Dec 31 10:00:00 2023 GMT
+ Subject: O=Acme Co, CN=Leaf certificate
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (1024 bit)
+ Modulus:
+ 00:c1:31:32:b2:28:dc:0d:a4:e0:4b:54:d6:fa:b7:
+ d2:0c:45:29:bf:67:c7:d1:b8:a9:90:63:51:c4:96:
+ 9f:86:a9:47:d7:67:f6:f9:1d:37:29:c2:0a:55:a7:
+ 8c:29:97:dc:f2:7f:f4:97:d0:d5:44:c9:04:1c:48:
+ ea:cc:a9:48:5c:eb:69:11:75:6e:db:7d:1a:5a:c0:
+ 9f:ad:a7:b8:0e:3b:a1:61:24:24:6f:64:84:ad:bb:
+ 28:06:c2:4a:c8:07:7b:46:33:8a:c7:81:77:92:4f:
+ 9d:88:1c:52:04:23:61:12:97:c7:e4:af:90:67:7e:
+ fb:ac:3d:23:92:f0:c9:39:6d
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Key Usage: critical
+ Digital Signature, Key Encipherment
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication
+ X509v3 Basic Constraints: critical
+ CA:FALSE
+ X509v3 Subject Alternative Name:
+ DNS:test.example.com
+ Signature Algorithm: sha1WithRSAEncryption
+ ad:33:55:2a:80:4c:ab:bc:b3:34:f7:b3:7e:fb:05:a8:11:3f:
+ a1:35:56:4c:46:2f:8d:24:70:35:3a:66:8d:14:c4:fb:7f:d9:
+ 76:de:c4:52:a7:42:8f:70:1d:fd:d5:33:04:69:5d:3c:18:03:
+ 8f:db:19:d0:14:d8:1c:0b:b6:74:9c:cf:41:ba:24:d9:c4:c3:
+ cf:86:fb:15:3d:c4:99:ea:af:6a:29:34:ed:97:03:38:ed:38:
+ b3:21:39:a0:f0:16:ac:81:d3:88:52:d8:5e:a3:6d:e6:ec:3f:
+ e9:20:ac:d3:78:7b:ae:59:9e:5d:3b:5e:61:bb:43:88:cd:8e:
+ d0:0d
+-----BEGIN CERTIFICATE-----
+MIICGzCCAYagAwIBAgIBAzALBgkqhkiG9w0BAQUwLDEQMA4GA1UEChMHQWNtZSBD
+bzEYMBYGA1UEAxMPSW50ZXJtZWRpYXRlIENBMB4XDTEzMDEwMTEwMDAwMFoXDTIz
+MTIzMTEwMDAwMFowLTEQMA4GA1UEChMHQWNtZSBDbzEZMBcGA1UEAxMQTGVhZiBj
+ZXJ0aWZpY2F0ZTCBnTALBgkqhkiG9w0BAQEDgY0AMIGJAoGBAMExMrIo3A2k4EtU
+1vq30gxFKb9nx9G4qZBjUcSWn4apR9dn9vkdNynCClWnjCmX3PJ/9JfQ1UTJBBxI
+6sypSFzraRF1btt9GlrAn62nuA47oWEkJG9khK27KAbCSsgHe0YziseBd5JPnYgc
+UgQjYRKXx+SvkGd++6w9I5LwyTltAgMBAAGjUjBQMA4GA1UdDwEB/wQEAwIAoDAT
+BgNVHSUEDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMBsGA1UdEQQUMBKCEHRl
+c3QuZXhhbXBsZS5jb20wCwYJKoZIhvcNAQEFA4GBAK0zVSqATKu8szT3s377BagR
+P6E1VkxGL40kcDU6Zo0UxPt/2XbexFKnQo9wHf3VMwRpXTwYA4/bGdAU2BwLtnSc
+z0G6JNnEw8+G+xU9xJnqr2opNO2XAzjtOLMhOaDwFqyB04hS2F6jbebsP+kgrNN4
+e65Znl07XmG7Q4jNjtAN
+-----END CERTIFICATE-----
diff --git a/net/data/ssl/certificates/quic_test_ecc.example.com.crt b/net/data/ssl/certificates/quic_test_ecc.example.com.crt
new file mode 100644
index 0000000..0e6bfba
--- /dev/null
+++ b/net/data/ssl/certificates/quic_test_ecc.example.com.crt
@@ -0,0 +1,50 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 4 (0x4)
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: O=Acme Co, CN=Intermediate CA
+ Validity
+ Not Before: Jan 1 10:00:00 2013 GMT
+ Not After : Dec 31 10:00:00 2023 GMT
+ Subject: O=Acme Co, CN=ECDSA Leaf certificate
+ Subject Public Key Info:
+ Public Key Algorithm: id-ecPublicKey
+ Public-Key: (256 bit)
+ pub:
+ 04:6d:48:d0:30:76:bb:bf:91:b1:d7:03:c2:fc:95:
+ 9b:e0:ea:42:ed:43:2c:a6:b2:23:c4:52:33:93:95:
+ 25:fc:16:75:83:9e:0f:0f:91:a5:47:b1:21:91:d4:
+ 94:94:30:b8:00:dc:1c:79:2c:fa:72:99:62:b2:fa:
+ af:b0:ca:f2:42
+ ASN1 OID: prime256v1
+ X509v3 extensions:
+ X509v3 Key Usage: critical
+ Digital Signature
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication
+ X509v3 Basic Constraints: critical
+ CA:FALSE
+ X509v3 Subject Alternative Name:
+ DNS:test.example.com
+ Signature Algorithm: sha1WithRSAEncryption
+ 5d:23:47:b4:b5:0f:38:18:cd:63:90:24:37:f1:da:67:66:a4:
+ fe:8d:53:3f:c5:a7:10:e6:21:a3:1d:b7:42:b0:1a:e7:d7:83:
+ 3d:ea:7b:6b:89:85:bb:13:77:4d:45:ab:b2:e7:1e:ac:6e:74:
+ b6:9f:c4:e0:76:1c:e4:13:e9:6c:b1:20:a3:34:e8:1e:8a:71:
+ 51:cb:00:44:71:64:f6:4b:9e:9a:2d:d9:9a:44:62:f5:8c:3c:
+ c5:ec:c1:1c:d5:bb:05:53:33:af:70:44:1d:5b:aa:23:67:30:
+ 3e:d3:a9:5e:a2:57:84:86:aa:be:bd:7b:4f:74:d9:3b:cd:2e:
+ 7e:d1
+-----BEGIN CERTIFICATE-----
+MIIB3DCCAUegAwIBAgIBBDALBgkqhkiG9w0BAQUwLDEQMA4GA1UEChMHQWNtZSBD
+bzEYMBYGA1UEAxMPSW50ZXJtZWRpYXRlIENBMB4XDTEzMDEwMTEwMDAwMFoXDTIz
+MTIzMTEwMDAwMFowMzEQMA4GA1UEChMHQWNtZSBDbzEfMB0GA1UEAxMWRUNEU0Eg
+TGVhZiBjZXJ0aWZpY2F0ZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABG1I0DB2
+u7+RsdcDwvyVm+DqQu1DLKayI8RSM5OVJfwWdYOeDw+RpUexIZHUlJQwuADcHHks
++nKZYrL6r7DK8kKjUjBQMA4GA1UdDwEB/wQEAwIAgDATBgNVHSUEDDAKBggrBgEF
+BQcDATAMBgNVHRMBAf8EAjAAMBsGA1UdEQQUMBKCEHRlc3QuZXhhbXBsZS5jb20w
+CwYJKoZIhvcNAQEFA4GBAF0jR7S1DzgYzWOQJDfx2mdmpP6NUz/FpxDmIaMdt0Kw
+GufXgz3qe2uJhbsTd01Fq7LnHqxudLafxOB2HOQT6WyxIKM06B6KcVHLAERxZPZL
+npot2ZpEYvWMPMXswRzVuwVTM69wRB1bqiNnMD7TqV6iV4SGqr69e0902TvNLn7R
+-----END CERTIFICATE-----
diff --git a/net/net.gyp b/net/net.gyp
index f0991c7..5d5c131 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -758,6 +758,8 @@
'quic/crypto/p256_key_exchange_nss.cc',
'quic/crypto/p256_key_exchange_openssl.cc',
'quic/crypto/proof_source.h',
+ 'quic/crypto/proof_verifier_chromium.cc',
+ 'quic/crypto/proof_verifier_chromium.h',
'quic/crypto/quic_decrypter.cc',
'quic/crypto/quic_decrypter.h',
'quic/crypto/quic_encrypter.cc',
@@ -1680,6 +1682,7 @@
'quic/crypto/strike_register_test.cc',
'quic/test_tools/crypto_test_utils.cc',
'quic/test_tools/crypto_test_utils.h',
+ 'quic/test_tools/crypto_test_utils_chromium.cc',
'quic/test_tools/crypto_test_utils_nss.cc',
'quic/test_tools/crypto_test_utils_openssl.cc',
'quic/test_tools/mock_clock.cc',
@@ -2684,6 +2687,7 @@
'../testing/gmock.gyp:gmock',
'../testing/gtest.gyp:gtest',
'net',
+ 'net_test_support',
'quic_library',
],
'sources': [
@@ -2691,6 +2695,7 @@
'quic/test_tools/quic_session_peer.h',
'quic/test_tools/crypto_test_utils.cc',
'quic/test_tools/crypto_test_utils.h',
+ 'quic/test_tools/crypto_test_utils_chromium.cc',
'quic/test_tools/crypto_test_utils_nss.cc',
'quic/test_tools/crypto_test_utils_openssl.cc',
'quic/test_tools/mock_clock.cc',
diff --git a/net/quic/crypto/crypto_handshake.cc b/net/quic/crypto/crypto_handshake.cc
index be296be..66a83de 100644
--- a/net/quic/crypto/crypto_handshake.cc
+++ b/net/quic/crypto/crypto_handshake.cc
@@ -357,7 +357,8 @@ QuicCryptoClientConfig::~QuicCryptoClientConfig() {
}
QuicCryptoClientConfig::CachedState::CachedState()
- : server_config_valid_(false) {}
+ : server_config_valid_(false),
+ generation_counter_(0) {}
QuicCryptoClientConfig::CachedState::~CachedState() {}
@@ -430,6 +431,7 @@ QuicErrorCode QuicCryptoClientConfig::CachedState::SetServerConfig(
if (!matches_existing) {
server_config_ = server_config.as_string();
server_config_valid_ = false;
+ ++generation_counter_;
scfg_.reset(new_scfg_storage.release());
}
return QUIC_NO_ERROR;
@@ -439,6 +441,7 @@ void QuicCryptoClientConfig::CachedState::InvalidateServerConfig() {
server_config_.clear();
scfg_.reset();
server_config_valid_ = false;
+ ++generation_counter_;
}
void QuicCryptoClientConfig::CachedState::SetProof(const vector<string>& certs,
@@ -461,6 +464,7 @@ void QuicCryptoClientConfig::CachedState::SetProof(const vector<string>& certs,
// If the proof has changed then it needs to be revalidated.
server_config_valid_ = false;
+ ++generation_counter_;
certs_ = certs;
server_config_sig_ = signature.as_string();
}
@@ -490,6 +494,10 @@ bool QuicCryptoClientConfig::CachedState::proof_valid() const {
return server_config_valid_;
}
+uint64 QuicCryptoClientConfig::CachedState::generation_counter() const {
+ return generation_counter_;
+}
+
void QuicCryptoClientConfig::CachedState::set_source_address_token(
StringPiece token) {
source_address_token_ = token.as_string();
@@ -836,7 +844,7 @@ QuicErrorCode QuicCryptoClientConfig::ProcessServerHello(
return QUIC_NO_ERROR;
}
-const ProofVerifier* QuicCryptoClientConfig::proof_verifier() const {
+ProofVerifier* QuicCryptoClientConfig::proof_verifier() const {
return proof_verifier_.get();
}
diff --git a/net/quic/crypto/crypto_handshake.h b/net/quic/crypto/crypto_handshake.h
index 919f777..e702bb6 100644
--- a/net/quic/crypto/crypto_handshake.h
+++ b/net/quic/crypto/crypto_handshake.h
@@ -273,6 +273,7 @@ class NET_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig {
const std::vector<std::string>& certs() const;
const std::string& signature() const;
bool proof_valid() const;
+ uint64 generation_counter() const;
void set_source_address_token(base::StringPiece token);
@@ -283,8 +284,12 @@ class NET_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig {
std::vector<std::string> certs_; // A list of certificates in leaf-first
// order.
std::string server_config_sig_; // A signature of |server_config_|.
- bool server_config_valid_; // true if |server_config_| is correctly signed
- // and |certs_| has been validated.
+ bool server_config_valid_; // True if |server_config_| is correctly
+ // signed and |certs_| has been
+ // validated.
+ uint64 generation_counter_; // Generation counter associated with
+ // the |server_config_|, |certs_| and
+ // |server_config_sig_| combination.
// scfg contains the cached, parsed value of |server_config|.
mutable scoped_ptr<CryptoHandshakeMessage> scfg_;
@@ -348,7 +353,7 @@ class NET_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig {
QuicCryptoNegotiatedParameters* out_params,
std::string* error_details);
- const ProofVerifier* proof_verifier() const;
+ ProofVerifier* proof_verifier() const;
// SetProofVerifier takes ownership of a |ProofVerifier| that clients are
// free to use in order to verify certificate chains from servers. If a
diff --git a/net/quic/crypto/proof_test.cc b/net/quic/crypto/proof_test.cc
index 3423b50..b30c9aa 100644
--- a/net/quic/crypto/proof_test.cc
+++ b/net/quic/crypto/proof_test.cc
@@ -2,11 +2,21 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/files/file_path.h"
+#include "net/base/net_errors.h"
+#include "net/base/test_completion_callback.h"
+#include "net/base/test_data_directory.h"
+#include "net/cert/x509_certificate.h"
#include "net/quic/crypto/proof_source.h"
#include "net/quic/crypto/proof_verifier.h"
#include "net/quic/test_tools/crypto_test_utils.h"
+#include "net/test/cert_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
+#if defined(OS_WIN)
+#include "base/win/windows_version.h"
+#endif
+
using std::string;
using std::vector;
@@ -34,25 +44,341 @@ TEST(Proof, Verify) {
ASSERT_EQ(first_certs, certs);
ASSERT_EQ(signature, first_signature);
- ASSERT_TRUE(verifier->VerifyProof(hostname, server_config, *certs, signature,
- &error_details));
- ASSERT_FALSE(verifier->VerifyProof("foo.com", server_config, *certs,
- signature, &error_details));
- ASSERT_FALSE(
- verifier->VerifyProof(hostname, server_config.substr(1, string::npos),
- *certs, signature, &error_details));
+ int rv;
+ TestCompletionCallback callback;
+ rv = verifier->VerifyProof(hostname, server_config, *certs, signature,
+ &error_details, callback.callback());
+ rv = callback.GetResult(rv);
+ ASSERT_EQ(OK, rv);
+ ASSERT_EQ("", error_details);
+
+ rv = verifier->VerifyProof("foo.com", server_config, *certs, signature,
+ &error_details, callback.callback());
+ rv = callback.GetResult(rv);
+ ASSERT_EQ(ERR_FAILED, rv);
+ ASSERT_NE("", error_details);
+
+ rv = verifier->VerifyProof(hostname, server_config.substr(1, string::npos),
+ *certs, signature, &error_details,
+ callback.callback());
+ rv = callback.GetResult(rv);
+ ASSERT_EQ(ERR_FAILED, rv);
+ ASSERT_NE("", error_details);
+
const string corrupt_signature = "1" + signature;
- ASSERT_FALSE(verifier->VerifyProof(hostname, server_config, *certs,
- corrupt_signature, &error_details));
+ rv = verifier->VerifyProof(hostname, server_config, *certs, corrupt_signature,
+ &error_details, callback.callback());
+ rv = callback.GetResult(rv);
+ ASSERT_EQ(ERR_FAILED, rv);
+ ASSERT_NE("", error_details);
vector<string> wrong_certs;
for (size_t i = 1; i < certs->size(); i++) {
wrong_certs.push_back((*certs)[i]);
}
- ASSERT_FALSE(verifier->VerifyProof("foo.com", server_config, wrong_certs,
- signature, &error_details));
+ rv = verifier->VerifyProof("foo.com", server_config, wrong_certs, signature,
+ &error_details, callback.callback());
+ rv = callback.GetResult(rv);
+ ASSERT_EQ(ERR_FAILED, rv);
+ ASSERT_NE("", error_details);
#endif // 0
}
+static string PEMCertFileToDER(const string& file_name) {
+ base::FilePath certs_dir = GetTestCertsDirectory();
+ scoped_refptr<X509Certificate> cert =
+ ImportCertFromFile(certs_dir, file_name);
+ CHECK_NE(static_cast<X509Certificate*>(NULL), cert);
+
+ string der_bytes;
+ CHECK(X509Certificate::GetDEREncoded(cert->os_cert_handle(), &der_bytes));
+ return der_bytes;
+}
+
+// A known answer test that allows us to test ProofVerifier without a working
+// ProofSource.
+TEST(Proof, VerifyRSAKnownAnswerTest) {
+ // These sample signatures were generated by running the Proof.Verify test
+ // and dumping the bytes of the |signature| output of ProofSource::GetProof().
+#if 0
+ // In the future, we will change the |sLen| parameter of RSA-PSS to be the
+ // same as |hLen|, and these are the sample signatures with the parameter
+ // |sLen| equal to |hLen|.
+ static const unsigned char signature_data_0[] = {
+ 0x9e, 0xe6, 0x74, 0x3b, 0x8f, 0xb8, 0x66, 0x77, 0x57, 0x09,
+ 0x8a, 0x04, 0xe9, 0xf0, 0x7c, 0x91, 0xa9, 0x5c, 0xe9, 0xdf,
+ 0x12, 0x4d, 0x23, 0x82, 0x8c, 0x29, 0x72, 0x7f, 0xc2, 0x20,
+ 0xa7, 0xb3, 0xe5, 0xbc, 0xcf, 0x3c, 0x0d, 0x8f, 0xae, 0x46,
+ 0x6a, 0xb9, 0xee, 0x0c, 0xe1, 0x13, 0x21, 0xc0, 0x7e, 0x45,
+ 0x24, 0x24, 0x4b, 0x72, 0x43, 0x5e, 0xc4, 0x0d, 0xdf, 0x6c,
+ 0xd8, 0xaa, 0x35, 0x97, 0x05, 0x40, 0x76, 0xd3, 0x2c, 0xee,
+ 0x82, 0x16, 0x6a, 0x43, 0xf9, 0xa2, 0xd0, 0x41, 0x3c, 0xed,
+ 0x3f, 0x40, 0x10, 0x95, 0xc7, 0xa9, 0x1f, 0x04, 0xdb, 0xd5,
+ 0x98, 0x9f, 0xe2, 0xbf, 0x77, 0x3d, 0xc9, 0x9a, 0xaf, 0xf7,
+ 0xef, 0x63, 0x0b, 0x7d, 0xc8, 0x37, 0xda, 0x37, 0x23, 0x88,
+ 0x78, 0xc8, 0x8b, 0xf5, 0xb9, 0x36, 0x5d, 0x72, 0x1f, 0xfc,
+ 0x14, 0xff, 0xa7, 0x81, 0x27, 0x49, 0xae, 0xe1,
+ };
+ static const unsigned char signature_data_1[] = {
+ 0x5e, 0xc2, 0xab, 0x6b, 0x16, 0xe6, 0x55, 0xf3, 0x16, 0x46,
+ 0x35, 0xdc, 0xcc, 0xde, 0xd0, 0xbd, 0x6c, 0x66, 0xb2, 0x3d,
+ 0xd3, 0x14, 0x78, 0xed, 0x47, 0x55, 0xfb, 0xdb, 0xe1, 0x7d,
+ 0xbf, 0x31, 0xf6, 0xf4, 0x10, 0x4c, 0x8d, 0x22, 0x17, 0xaa,
+ 0xe1, 0x85, 0xc7, 0x96, 0x4c, 0x42, 0xfb, 0xf4, 0x63, 0x53,
+ 0x8a, 0x79, 0x01, 0x63, 0x48, 0xa8, 0x3a, 0xbc, 0xc9, 0xd2,
+ 0xf5, 0xec, 0xe9, 0x09, 0x71, 0xaf, 0xce, 0x34, 0x56, 0xe5,
+ 0x00, 0xbe, 0xee, 0x3c, 0x1c, 0xc4, 0xa0, 0x07, 0xd5, 0x77,
+ 0xb8, 0x83, 0x57, 0x7d, 0x1a, 0xc9, 0xd0, 0xc0, 0x59, 0x9a,
+ 0x88, 0x19, 0x3f, 0xb9, 0xf0, 0x45, 0x37, 0xc3, 0x00, 0x8b,
+ 0xb3, 0x89, 0xf4, 0x89, 0x07, 0xa9, 0xc3, 0x26, 0xbf, 0x81,
+ 0xaf, 0x6b, 0x47, 0xbc, 0x16, 0x55, 0x37, 0x0a, 0xbe, 0x0e,
+ 0xc5, 0x75, 0x3f, 0x3d, 0x8e, 0xe8, 0x44, 0xe3,
+ };
+ static const unsigned char signature_data_2[] = {
+ 0x8e, 0x5c, 0x78, 0x63, 0x74, 0x99, 0x2e, 0x96, 0xc0, 0x14,
+ 0x8d, 0xb5, 0x13, 0x74, 0xa3, 0xa4, 0xe0, 0x43, 0x3e, 0x85,
+ 0xba, 0x8f, 0x3c, 0x5e, 0x14, 0x64, 0x0e, 0x5e, 0xff, 0x89,
+ 0x88, 0x8a, 0x65, 0xe2, 0xa2, 0x79, 0xe4, 0xe9, 0x3a, 0x7f,
+ 0xf6, 0x9d, 0x3d, 0xe2, 0xb0, 0x8a, 0x35, 0x55, 0xed, 0x21,
+ 0xee, 0x20, 0xd8, 0x8a, 0x60, 0x47, 0xca, 0x52, 0x54, 0x91,
+ 0x99, 0x69, 0x8d, 0x16, 0x34, 0x69, 0xe1, 0x46, 0x56, 0x67,
+ 0x5f, 0x50, 0xf0, 0x94, 0xe7, 0x8b, 0xf2, 0x6a, 0x73, 0x0f,
+ 0x30, 0x30, 0xde, 0x59, 0xdc, 0xc7, 0xfe, 0xb6, 0x83, 0xe1,
+ 0x86, 0x1d, 0x88, 0xd3, 0x2f, 0x2f, 0x74, 0x68, 0xbd, 0x6c,
+ 0xd1, 0x46, 0x76, 0x06, 0xa9, 0xd4, 0x03, 0x3f, 0xda, 0x7d,
+ 0xa7, 0xff, 0x48, 0xe4, 0xb4, 0x42, 0x06, 0xac, 0x19, 0x12,
+ 0xe6, 0x05, 0xae, 0xbe, 0x29, 0x94, 0x8f, 0x99,
+ };
+#else
+ // sLen = special value -2 used by OpenSSL.
+ static const unsigned char signature_data_0[] = {
+ 0x4c, 0x68, 0x3c, 0xc2, 0x1f, 0x31, 0x73, 0xa5, 0x29, 0xd3,
+ 0x56, 0x75, 0xb1, 0xbf, 0xbd, 0x31, 0x17, 0xfb, 0x2e, 0x24,
+ 0xb3, 0xc4, 0x0d, 0xfa, 0x56, 0xb8, 0x65, 0x94, 0x12, 0x38,
+ 0x6e, 0xff, 0xb3, 0x10, 0x2e, 0xf8, 0x5c, 0xc1, 0x21, 0x9d,
+ 0x29, 0x0c, 0x3a, 0x0a, 0x1a, 0xbf, 0x6b, 0x1c, 0x63, 0x77,
+ 0xf7, 0x86, 0xd3, 0xa4, 0x36, 0xf2, 0xb1, 0x6f, 0xac, 0xc3,
+ 0x23, 0x8d, 0xda, 0xe6, 0xd5, 0x83, 0xba, 0xdf, 0x28, 0x3e,
+ 0x7f, 0x4e, 0x79, 0xfc, 0xba, 0xdb, 0xf7, 0xd0, 0x4b, 0xad,
+ 0x79, 0xd0, 0xeb, 0xcf, 0xfa, 0x6e, 0x84, 0x44, 0x7a, 0x26,
+ 0xb1, 0x29, 0xa3, 0x08, 0xa8, 0x63, 0xfd, 0xed, 0x85, 0xff,
+ 0x9a, 0xe6, 0x79, 0x8b, 0xb6, 0x81, 0x13, 0x2c, 0xde, 0xe2,
+ 0xd8, 0x31, 0x29, 0xa4, 0xe0, 0x1b, 0x75, 0x2d, 0x8a, 0xf8,
+ 0x27, 0x55, 0xbc, 0xc7, 0x3b, 0x1e, 0xc1, 0x42,
+ };
+ static const unsigned char signature_data_1[] = {
+ 0xbb, 0xd1, 0x17, 0x43, 0xf3, 0x42, 0x16, 0xe9, 0xf9, 0x76,
+ 0xe6, 0xe3, 0xaa, 0x50, 0x47, 0x5f, 0x93, 0xb6, 0x7d, 0x35,
+ 0x03, 0x49, 0x0a, 0x07, 0x61, 0xd5, 0xf1, 0x9c, 0x6b, 0xaf,
+ 0xaa, 0xd7, 0x64, 0xe4, 0x0a, 0x0c, 0xab, 0x97, 0xfb, 0x4e,
+ 0x5c, 0x14, 0x08, 0xf6, 0xb9, 0xa9, 0x1d, 0xa9, 0xf8, 0x6d,
+ 0xb0, 0x2b, 0x2a, 0x0e, 0xc4, 0xd0, 0xd2, 0xe9, 0x96, 0x4f,
+ 0x44, 0x70, 0x90, 0x46, 0xb9, 0xd5, 0x89, 0x72, 0xb9, 0xa8,
+ 0xe4, 0xfb, 0x88, 0xbc, 0x69, 0x7f, 0xc9, 0xdc, 0x84, 0x87,
+ 0x18, 0x21, 0x9b, 0xde, 0x22, 0x33, 0xde, 0x16, 0x3f, 0xe6,
+ 0xfd, 0x27, 0x56, 0xd3, 0xa4, 0x97, 0x91, 0x65, 0x1a, 0xe7,
+ 0x5e, 0x80, 0x9a, 0xbf, 0xbf, 0x1a, 0x29, 0x8a, 0xbe, 0xa2,
+ 0x8c, 0x9c, 0x23, 0xf4, 0xcb, 0xba, 0x79, 0x31, 0x28, 0xab,
+ 0x77, 0x94, 0x92, 0xb2, 0xc2, 0x35, 0xb2, 0xfa,
+ };
+ static const unsigned char signature_data_2[] = {
+ 0x7e, 0x17, 0x01, 0xcb, 0x76, 0x9e, 0x9f, 0xce, 0xeb, 0x66,
+ 0x3e, 0xaa, 0xc9, 0x36, 0x5b, 0x7e, 0x48, 0x25, 0x99, 0xf8,
+ 0x0d, 0xe1, 0xa8, 0x48, 0x93, 0x3c, 0xe8, 0x97, 0x2e, 0x98,
+ 0xd6, 0x73, 0x0f, 0xd0, 0x74, 0x9c, 0x17, 0xef, 0xee, 0xf8,
+ 0x0e, 0x2a, 0x27, 0x3f, 0xc6, 0x55, 0xc6, 0xb9, 0xfe, 0x17,
+ 0xcc, 0xeb, 0x5d, 0xa1, 0xdc, 0xbd, 0x64, 0xd9, 0x5e, 0xec,
+ 0x57, 0x9d, 0xc3, 0xdc, 0x11, 0xbf, 0x23, 0x02, 0x58, 0xc4,
+ 0xf1, 0x18, 0xc1, 0x6f, 0x3f, 0xef, 0x18, 0x4d, 0xa6, 0x1e,
+ 0xe8, 0x25, 0x32, 0x8f, 0x92, 0x1e, 0xad, 0xbc, 0xbe, 0xde,
+ 0x83, 0x2a, 0x92, 0xd5, 0x59, 0x6f, 0xe4, 0x95, 0x6f, 0xe6,
+ 0xb1, 0xf9, 0xaf, 0x3f, 0xdb, 0x69, 0x6f, 0xae, 0xa6, 0x36,
+ 0xd2, 0x50, 0x81, 0x78, 0x41, 0x13, 0x2c, 0x65, 0x9c, 0x9e,
+ 0xf4, 0xd2, 0xd5, 0x58, 0x5b, 0x8b, 0x87, 0xcf,
+ };
+#endif
+
+ scoped_ptr<ProofVerifier> verifier(
+ CryptoTestUtils::ProofVerifierForTesting());
+
+ const string server_config = "server config bytes";
+ const string hostname = "test.example.com";
+ string error_details;
+
+ vector<string> certs(2);
+ certs[0] = PEMCertFileToDER("quic_test.example.com.crt");
+ certs[1] = PEMCertFileToDER("quic_intermediate.crt");
+
+ // Signatures are nondeterministic, so we test multiple signatures on the
+ // same server_config.
+ vector<string> signatures(3);
+ signatures[0].assign(reinterpret_cast<const char*>(signature_data_0),
+ sizeof(signature_data_0));
+ signatures[1].assign(reinterpret_cast<const char*>(signature_data_1),
+ sizeof(signature_data_1));
+ signatures[2].assign(reinterpret_cast<const char*>(signature_data_2),
+ sizeof(signature_data_2));
+
+ for (size_t i = 0; i < signatures.size(); i++) {
+ const string& signature = signatures[i];
+ int rv;
+ TestCompletionCallback callback;
+ rv = verifier->VerifyProof(hostname, server_config, certs, signature,
+ &error_details, callback.callback());
+ rv = callback.GetResult(rv);
+ ASSERT_EQ(OK, rv);
+ ASSERT_EQ("", error_details);
+
+ rv = verifier->VerifyProof("foo.com", server_config, certs, signature,
+ &error_details, callback.callback());
+ rv = callback.GetResult(rv);
+ ASSERT_EQ(ERR_FAILED, rv);
+ ASSERT_NE("", error_details);
+
+ rv = verifier->VerifyProof(hostname, server_config.substr(1, string::npos),
+ certs, signature, &error_details,
+ callback.callback());
+ rv = callback.GetResult(rv);
+ ASSERT_EQ(ERR_FAILED, rv);
+ ASSERT_NE("", error_details);
+
+ const string corrupt_signature = "1" + signature;
+ rv = verifier->VerifyProof(hostname, server_config, certs,
+ corrupt_signature, &error_details,
+ callback.callback());
+ rv = callback.GetResult(rv);
+ ASSERT_EQ(ERR_FAILED, rv);
+ ASSERT_NE("", error_details);
+
+ vector<string> wrong_certs;
+ for (size_t i = 1; i < certs.size(); i++) {
+ wrong_certs.push_back(certs[i]);
+ }
+ rv = verifier->VerifyProof("foo.com", server_config, wrong_certs, signature,
+ &error_details, callback.callback());
+ rv = callback.GetResult(rv);
+ ASSERT_EQ(ERR_FAILED, rv);
+ ASSERT_NE("", error_details);
+ }
+}
+
+// A known answer test that allows us to test ProofVerifier without a working
+// ProofSource.
+// TODO(rtenneti): Enable VerifyECDSAKnownAnswerTest on win_rel and XP.
+#if defined(OS_WIN)
+#define MAYBE_VerifyECDSAKnownAnswerTest DISABLED_VerifyECDSAKnownAnswerTest
+#else
+#define MAYBE_VerifyECDSAKnownAnswerTest VerifyECDSAKnownAnswerTest
+#endif
+TEST(Proof, MAYBE_VerifyECDSAKnownAnswerTest) {
+ // These sample signatures were generated by running the Proof.Verify test
+ // (modified to use ECDSA for signing proofs) and dumping the bytes of the
+ // |signature| output of ProofSource::GetProof().
+ static const unsigned char signature_data_0[] = {
+ 0x30, 0x45, 0x02, 0x20, 0x15, 0xb7, 0x9f, 0xe3, 0xd9, 0x7a,
+ 0x3c, 0x3b, 0x18, 0xb0, 0xdb, 0x60, 0x23, 0x56, 0xa0, 0x06,
+ 0x4e, 0x70, 0xa3, 0xf7, 0x4b, 0xe5, 0x0d, 0x69, 0xf0, 0x35,
+ 0x8c, 0xae, 0xb5, 0x54, 0x32, 0xe9, 0x02, 0x21, 0x00, 0xf7,
+ 0xe3, 0x06, 0x99, 0x16, 0x56, 0x7e, 0xab, 0x33, 0x53, 0x0d,
+ 0xde, 0xbe, 0xef, 0x6d, 0xb0, 0xc7, 0xa6, 0x63, 0xaf, 0x8d,
+ 0xab, 0x34, 0xa9, 0xc0, 0x63, 0x88, 0x47, 0x17, 0x4c, 0x4c,
+ 0x04,
+ };
+ static const unsigned char signature_data_1[] = {
+ 0x30, 0x44, 0x02, 0x20, 0x69, 0x60, 0x55, 0xbb, 0x11, 0x93,
+ 0x6a, 0xdc, 0x9b, 0x61, 0x2c, 0x60, 0x19, 0xbc, 0x15, 0x55,
+ 0xcf, 0xf2, 0x8e, 0x2e, 0x27, 0x0b, 0x69, 0xef, 0x33, 0x25,
+ 0x1e, 0x5d, 0x8c, 0x00, 0x11, 0xef, 0x02, 0x20, 0x0c, 0x26,
+ 0xfe, 0x0b, 0x06, 0x8f, 0xe8, 0xe2, 0x02, 0x63, 0xe5, 0x43,
+ 0x0d, 0xc9, 0x80, 0x4d, 0xe9, 0x6f, 0x6e, 0x18, 0xdb, 0xb0,
+ 0x04, 0x2a, 0x45, 0x37, 0x1a, 0x60, 0x0e, 0xc6, 0xc4, 0x8f,
+ };
+ static const unsigned char signature_data_2[] = {
+ 0x30, 0x45, 0x02, 0x21, 0x00, 0xd5, 0x43, 0x36, 0x60, 0x50,
+ 0xce, 0xe0, 0x00, 0x51, 0x02, 0x84, 0x95, 0x51, 0x47, 0xaf,
+ 0xe4, 0xf9, 0xe1, 0x23, 0xae, 0x21, 0xb4, 0x98, 0xd1, 0xa3,
+ 0x5f, 0x3b, 0xf3, 0x6a, 0x65, 0x44, 0x6b, 0x02, 0x20, 0x30,
+ 0x7e, 0xb4, 0xea, 0xf0, 0xda, 0xdb, 0xbd, 0x38, 0xb9, 0x7a,
+ 0x5d, 0x12, 0x04, 0x0e, 0xc2, 0xf0, 0xb1, 0x0e, 0x25, 0xf8,
+ 0x0a, 0x27, 0xa3, 0x16, 0x94, 0xac, 0x1e, 0xb8, 0x6e, 0x00,
+ 0x05,
+ };
+
+ scoped_ptr<ProofVerifier> verifier(
+ CryptoTestUtils::ProofVerifierForTesting());
+
+ const string server_config = "server config bytes";
+ const string hostname = "test.example.com";
+ string error_details;
+
+ vector<string> certs(2);
+ certs[0] = PEMCertFileToDER("quic_test_ecc.example.com.crt");
+ certs[1] = PEMCertFileToDER("quic_intermediate.crt");
+
+ // Signatures are nondeterministic, so we test multiple signatures on the
+ // same server_config.
+ vector<string> signatures(3);
+ signatures[0].assign(reinterpret_cast<const char*>(signature_data_0),
+ sizeof(signature_data_0));
+ signatures[1].assign(reinterpret_cast<const char*>(signature_data_1),
+ sizeof(signature_data_1));
+ signatures[2].assign(reinterpret_cast<const char*>(signature_data_2),
+ sizeof(signature_data_2));
+
+ for (size_t i = 0; i < signatures.size(); i++) {
+ const string& signature = signatures[i];
+ int rv;
+ TestCompletionCallback callback;
+ rv = verifier->VerifyProof(hostname, server_config, certs, signature,
+ &error_details, callback.callback());
+ rv = callback.GetResult(rv);
+ ASSERT_EQ(OK, rv);
+ ASSERT_EQ("", error_details);
+
+ rv = verifier->VerifyProof("foo.com", server_config, certs, signature,
+ &error_details, callback.callback());
+ rv = callback.GetResult(rv);
+ ASSERT_EQ(ERR_FAILED, rv);
+ ASSERT_NE("", error_details);
+
+ rv = verifier->VerifyProof(hostname, server_config.substr(1, string::npos),
+ certs, signature, &error_details,
+ callback.callback());
+ rv = callback.GetResult(rv);
+ ASSERT_EQ(ERR_FAILED, rv);
+ ASSERT_NE("", error_details);
+
+ // An ECDSA signature is DER-encoded. Corrupt the last byte so that the
+ // signature can still be DER-decoded correctly.
+ string corrupt_signature = signature;
+ corrupt_signature[corrupt_signature.size() - 1] += 1;
+ rv = verifier->VerifyProof(hostname, server_config, certs,
+ corrupt_signature, &error_details,
+ callback.callback());
+ rv = callback.GetResult(rv);
+ ASSERT_EQ(ERR_FAILED, rv);
+ ASSERT_NE("", error_details);
+
+ // Prepending a "1" makes the DER invalid.
+ const string bad_der_signature1 = "1" + signature;
+ rv = verifier->VerifyProof(hostname, server_config, certs,
+ bad_der_signature1, &error_details,
+ callback.callback());
+ rv = callback.GetResult(rv);
+ ASSERT_EQ(ERR_FAILED, rv);
+ ASSERT_NE("", error_details);
+
+ vector<string> wrong_certs;
+ for (size_t i = 1; i < certs.size(); i++) {
+ wrong_certs.push_back(certs[i]);
+ }
+ rv = verifier->VerifyProof("foo.com", server_config, wrong_certs, signature,
+ &error_details, callback.callback());
+ rv = callback.GetResult(rv);
+ ASSERT_EQ(ERR_FAILED, rv);
+ ASSERT_NE("", error_details);
+ }
+}
+
} // namespace test
} // namespace net
diff --git a/net/quic/crypto/proof_verifier.h b/net/quic/crypto/proof_verifier.h
index 29ed7ea..406f41e 100644
--- a/net/quic/crypto/proof_verifier.h
+++ b/net/quic/crypto/proof_verifier.h
@@ -8,6 +8,7 @@
#include <string>
#include <vector>
+#include "net/base/completion_callback.h"
#include "net/base/net_export.h"
namespace net {
@@ -20,20 +21,23 @@ class NET_EXPORT_PRIVATE ProofVerifier {
// VerifyProof checks that |signature| is a valid signature of
// |server_config| by the public key in the leaf certificate of |certs|, and
- // that |certs| is a valid chain for |hostname|. On success, it returns true.
- // On failure, it returns false and sets |*error_details| to a description of
- // the problem.
+ // that |certs| is a valid chain for |hostname|. On success, it returns OK.
+ // On failure, it returns ERR_FAILED and sets |*error_details| to a
+ // description of the problem. This function may also return ERR_IO_PENDING,
+ // in which case the |callback| will be run on the calling thread with the
+ // final OK/ERR_FAILED result when the proof is verified.
//
// The signature uses SHA-256 as the hash function and PSS padding in the
// case of RSA.
//
// Note: this is just for testing. The CN of the certificate is ignored and
// wildcards in the SANs are not supported.
- virtual bool VerifyProof(const std::string& hostname,
- const std::string& server_config,
- const std::vector<std::string>& certs,
- const std::string& signature,
- std::string* error_details) const = 0;
+ virtual int VerifyProof(const std::string& hostname,
+ const std::string& server_config,
+ const std::vector<std::string>& certs,
+ const std::string& signature,
+ std::string* error_details,
+ const CompletionCallback& callback) = 0;
};
} // namespace net
diff --git a/net/quic/crypto/proof_verifier_chromium.cc b/net/quic/crypto/proof_verifier_chromium.cc
new file mode 100644
index 0000000..7a764b6
--- /dev/null
+++ b/net/quic/crypto/proof_verifier_chromium.cc
@@ -0,0 +1,240 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/crypto/proof_verifier_chromium.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+#include "crypto/signature_verifier.h"
+#include "net/base/net_errors.h"
+#include "net/base/net_log.h"
+#include "net/cert/asn1_util.h"
+#include "net/cert/cert_status_flags.h"
+#include "net/cert/cert_verifier.h"
+#include "net/cert/cert_verify_result.h"
+#include "net/cert/single_request_cert_verifier.h"
+#include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util.h"
+#include "net/quic/crypto/crypto_protocol.h"
+#include "net/ssl/ssl_config_service.h"
+
+using base::StringPiece;
+using base::StringPrintf;
+using std::string;
+using std::vector;
+
+namespace net {
+
+ProofVerifierChromium::ProofVerifierChromium(CertVerifier* cert_verifier,
+ const BoundNetLog& net_log)
+ : cert_verifier_(cert_verifier),
+ error_details_(NULL),
+ next_state_(STATE_NONE),
+ net_log_(net_log) {
+}
+
+ProofVerifierChromium::~ProofVerifierChromium() {
+ verifier_.reset();
+
+ // Reset object state.
+ callback_.Reset();
+ cert_verify_result_.Reset();
+}
+
+int ProofVerifierChromium::VerifyProof(const string& hostname,
+ const string& server_config,
+ const vector<string>& certs,
+ const string& signature,
+ std::string* error_details,
+ const CompletionCallback& callback) {
+ DCHECK(error_details);
+ error_details->clear();
+
+ DCHECK_EQ(STATE_NONE, next_state_);
+ if (STATE_NONE != next_state_) {
+ *error_details = "Certificate is already set and VerifyProof has begun";
+ DLOG(WARNING) << *error_details;
+ return ERR_FAILED;
+ }
+
+ if (certs.empty()) {
+ *error_details = "Failed to create certificate chain. Certs are empty.";
+ DLOG(WARNING) << *error_details;
+ return ERR_FAILED;
+ }
+
+ // Convert certs to X509Certificate.
+ vector<StringPiece> cert_pieces(certs.size());
+ for (unsigned i = 0; i < certs.size(); i++) {
+ cert_pieces[i] = base::StringPiece(certs[i]);
+ }
+ cert_ = X509Certificate::CreateFromDERCertChain(cert_pieces);
+ if (!cert_.get()) {
+ cert_verify_result_.Reset();
+ cert_verify_result_.cert_status = CERT_STATUS_INVALID;
+ *error_details = "Failed to create certificate chain";
+ DLOG(WARNING) << *error_details;
+ return ERR_FAILED;
+ }
+
+ // We call VerifySignature first to avoid copying of server_config and
+ // signature.
+ if (!VerifySignature(server_config, signature, certs[0])) {
+ *error_details = "Failed to verify signature of server config";
+ DLOG(WARNING) << *error_details;
+ return ERR_FAILED;
+ }
+
+ hostname_ = hostname;
+ callback_ = callback;
+ error_details_ = error_details;
+
+ next_state_ = STATE_VERIFY_CERT;
+ return DoLoop(OK);
+}
+
+int ProofVerifierChromium::DoLoop(int last_result) {
+ int rv = last_result;
+ do {
+ State state = next_state_;
+ next_state_ = STATE_NONE;
+ switch (state) {
+ case STATE_VERIFY_CERT:
+ DCHECK(rv == OK);
+ rv = DoVerifyCert(rv);
+ break;
+ case STATE_VERIFY_CERT_COMPLETE:
+ rv = DoVerifyCertComplete(rv);
+ break;
+ case STATE_NONE:
+ default:
+ rv = ERR_UNEXPECTED;
+ LOG(DFATAL) << "unexpected state " << state;
+ break;
+ }
+ } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
+ return rv;
+}
+
+void ProofVerifierChromium::OnIOComplete(int result) {
+ int rv = DoLoop(result);
+ if (rv != ERR_IO_PENDING) {
+ base::ResetAndReturn(&callback_).Run(rv);
+ }
+}
+
+int ProofVerifierChromium::DoVerifyCert(int result) {
+ next_state_ = STATE_VERIFY_CERT_COMPLETE;
+
+ int flags = 0;
+ verifier_.reset(new SingleRequestCertVerifier(cert_verifier_));
+ return verifier_->Verify(
+ cert_.get(),
+ hostname_,
+ flags,
+ SSLConfigService::GetCRLSet().get(),
+ &cert_verify_result_,
+ base::Bind(&ProofVerifierChromium::OnIOComplete,
+ base::Unretained(this)),
+ net_log_);
+}
+
+int ProofVerifierChromium::DoVerifyCertComplete(int result) {
+ verifier_.reset();
+
+ if (result <= ERR_FAILED) {
+ *error_details_ = StringPrintf("Failed to verify certificate chain: %s",
+ ErrorToString(result));
+ DLOG(WARNING) << *error_details_;
+ result = ERR_FAILED;
+ }
+
+ // Exit DoLoop and return the result to the caller to VerifyProof.
+ DCHECK_EQ(STATE_NONE, next_state_);
+ return result;
+}
+
+bool ProofVerifierChromium::VerifySignature(const string& signed_data,
+ const string& signature,
+ const string& cert) {
+ StringPiece spki;
+ if (!asn1::ExtractSPKIFromDERCert(cert, &spki)) {
+ DLOG(WARNING) << "ExtractSPKIFromDERCert failed";
+ return false;
+ }
+
+ crypto::SignatureVerifier verifier;
+
+ size_t size_bits;
+ X509Certificate::PublicKeyType type;
+ X509Certificate::GetPublicKeyInfo(cert_->os_cert_handle(), &size_bits,
+ &type);
+ if (type == X509Certificate::kPublicKeyTypeRSA) {
+ crypto::SignatureVerifier::HashAlgorithm hash_alg =
+ crypto::SignatureVerifier::SHA256;
+ crypto::SignatureVerifier::HashAlgorithm mask_hash_alg = hash_alg;
+ unsigned int hash_len = 32; // 32 is the length of a SHA-256 hash.
+ // TODO(wtc): change this to hash_len when we can change the wire format.
+ unsigned int salt_len = signature.size() - hash_len - 2;
+
+ bool ok = verifier.VerifyInitRSAPSS(
+ hash_alg, mask_hash_alg, salt_len,
+ reinterpret_cast<const uint8*>(signature.data()), signature.size(),
+ reinterpret_cast<const uint8*>(spki.data()), spki.size());
+ if (!ok) {
+ DLOG(WARNING) << "VerifyInitRSAPSS failed";
+ return false;
+ }
+ } else if (type == X509Certificate::kPublicKeyTypeECDSA) {
+ // This is the algorithm ID for ECDSA with SHA-256. Parameters are ABSENT.
+ // RFC 5758:
+ // ecdsa-with-SHA256 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+ // us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 2 }
+ // ...
+ // When the ecdsa-with-SHA224, ecdsa-with-SHA256, ecdsa-with-SHA384, or
+ // ecdsa-with-SHA512 algorithm identifier appears in the algorithm field
+ // as an AlgorithmIdentifier, the encoding MUST omit the parameters
+ // field. That is, the AlgorithmIdentifier SHALL be a SEQUENCE of one
+ // component, the OID ecdsa-with-SHA224, ecdsa-with-SHA256, ecdsa-with-
+ // SHA384, or ecdsa-with-SHA512.
+ // See also RFC 5480, Appendix A.
+ static const uint8 kECDSAWithSHA256AlgorithmID[] = {
+ 0x30, 0x0a,
+ 0x06, 0x08,
+ 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02,
+ };
+
+ if (!verifier.VerifyInit(
+ kECDSAWithSHA256AlgorithmID, sizeof(kECDSAWithSHA256AlgorithmID),
+ reinterpret_cast<const uint8*>(signature.data()),
+ signature.size(),
+ reinterpret_cast<const uint8*>(spki.data()),
+ spki.size())) {
+ DLOG(WARNING) << "VerifyInit failed";
+ return false;
+ }
+ } else {
+ LOG(ERROR) << "Unsupported public key type " << type;
+ return false;
+ }
+
+ verifier.VerifyUpdate(reinterpret_cast<const uint8*>(kProofSignatureLabel),
+ sizeof(kProofSignatureLabel));
+ verifier.VerifyUpdate(reinterpret_cast<const uint8*>(signed_data.data()),
+ signed_data.size());
+
+ if (!verifier.VerifyFinal()) {
+ DLOG(WARNING) << "VerifyFinal failed";
+ return false;
+ }
+
+ DLOG(INFO) << "VerifyFinal success";
+ return true;
+}
+
+} // namespace net
diff --git a/net/quic/crypto/proof_verifier_chromium.h b/net/quic/crypto/proof_verifier_chromium.h
new file mode 100644
index 0000000..2466507
--- /dev/null
+++ b/net/quic/crypto/proof_verifier_chromium.h
@@ -0,0 +1,89 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_CRYPTO_PROOF_VERIFIER_CHROMIUM_H_
+#define NET_QUIC_CRYPTO_PROOF_VERIFIER_CHROMIUM_H_
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "net/base/completion_callback.h"
+#include "net/base/net_export.h"
+#include "net/base/net_log.h"
+#include "net/cert/cert_verify_result.h"
+#include "net/cert/x509_certificate.h"
+#include "net/quic/crypto/proof_verifier.h"
+
+namespace net {
+
+class BoundNetLog;
+class CertVerifier;
+class CertVerifyResult;
+class SingleRequestCertVerifier;
+class X509Certificate;
+
+// ProofVerifierChromium implements the QUIC ProofVerifier interface.
+// TODO(rtenneti): Add support for multiple requests for one ProofVerifier.
+class NET_EXPORT_PRIVATE ProofVerifierChromium : public ProofVerifier {
+ public:
+ explicit ProofVerifierChromium(CertVerifier* cert_verifier,
+ const BoundNetLog& net_log);
+ virtual ~ProofVerifierChromium();
+
+ // ProofVerifier interface
+ virtual int VerifyProof(const std::string& hostname,
+ const std::string& server_config,
+ const std::vector<std::string>& certs,
+ const std::string& signature,
+ std::string* error_details,
+ const CompletionCallback& callback) OVERRIDE;
+
+ private:
+ enum State {
+ STATE_NONE,
+ STATE_VERIFY_CERT,
+ STATE_VERIFY_CERT_COMPLETE,
+ };
+
+ int DoLoop(int last_io_result);
+ void OnIOComplete(int result);
+ int DoVerifyCert(int result);
+ int DoVerifyCertComplete(int result);
+
+ bool VerifySignature(const std::string& signed_data,
+ const std::string& signature,
+ const std::string& cert);
+
+ // |cert_verifier_| and |verifier_| are used for verifying certificates.
+ CertVerifier* const cert_verifier_;
+ scoped_ptr<SingleRequestCertVerifier> verifier_;
+
+ // |hostname| specifies the hostname for which |certs| is a valid chain.
+ std::string hostname_;
+
+ CompletionCallback callback_;
+
+ // The result of certificate verification.
+ CertVerifyResult cert_verify_result_;
+ std::string* error_details_;
+
+ // X509Certificate from a chain of DER encoded certificates.
+ scoped_refptr<X509Certificate> cert_;
+
+ // |generation_counter| passed to VerifyProof call.
+ uint64 generation_counter_;
+
+ State next_state_;
+
+ BoundNetLog net_log_;
+
+ DISALLOW_COPY_AND_ASSIGN(ProofVerifierChromium);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CRYPTO_PROOF_VERIFIER_CHROMIUM_H_
diff --git a/net/quic/quic_crypto_client_stream.cc b/net/quic/quic_crypto_client_stream.cc
index 674a441..f0ec9130 100644
--- a/net/quic/quic_crypto_client_stream.cc
+++ b/net/quic/quic_crypto_client_stream.cc
@@ -4,6 +4,8 @@
#include "net/quic/quic_crypto_client_stream.h"
+#include "net/base/completion_callback.h"
+#include "net/base/net_errors.h"
#include "net/quic/crypto/crypto_protocol.h"
#include "net/quic/crypto/crypto_utils.h"
#include "net/quic/crypto/null_encrypter.h"
@@ -18,10 +20,12 @@ QuicCryptoClientStream::QuicCryptoClientStream(
QuicSession* session,
QuicCryptoClientConfig* crypto_config)
: QuicCryptoStream(session),
+ weak_factory_(this),
next_state_(STATE_IDLE),
num_client_hellos_(0),
crypto_config_(crypto_config),
- server_hostname_(server_hostname) {
+ server_hostname_(server_hostname),
+ generation_counter_(0) {
}
QuicCryptoClientStream::~QuicCryptoClientStream() {
@@ -29,12 +33,12 @@ QuicCryptoClientStream::~QuicCryptoClientStream() {
void QuicCryptoClientStream::OnHandshakeMessage(
const CryptoHandshakeMessage& message) {
- DoHandshakeLoop(&message);
+ DoHandshakeLoop(&message, OK);
}
bool QuicCryptoClientStream::CryptoConnect() {
next_state_ = STATE_SEND_CHLO;
- DoHandshakeLoop(NULL);
+ DoHandshakeLoop(NULL, OK);
return true;
}
@@ -50,7 +54,8 @@ int QuicCryptoClientStream::num_sent_client_hellos() const {
static const int kMaxClientHellos = 3;
void QuicCryptoClientStream::DoHandshakeLoop(
- const CryptoHandshakeMessage* in) {
+ const CryptoHandshakeMessage* in,
+ int result) {
CryptoHandshakeMessage out;
QuicErrorCode error;
string error_details;
@@ -66,6 +71,8 @@ void QuicCryptoClientStream::DoHandshakeLoop(
next_state_ = STATE_IDLE;
switch (state) {
case STATE_SEND_CHLO: {
+ // Send the subsequent client hello in plaintext.
+ session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_NONE);
if (num_client_hellos_ > kMaxClientHellos) {
CloseConnection(QUIC_CRYPTO_TOO_MANY_REJECTS);
return;
@@ -122,6 +129,7 @@ void QuicCryptoClientStream::DoHandshakeLoop(
return;
}
case STATE_RECV_REJ:
+ DCHECK_EQ(OK, result);
// We sent a dummy CHLO because we didn't have enough information to
// perform a handshake, or we sent a full hello that the server
// rejected. Here we hope to have a REJ that contains the information
@@ -139,30 +147,54 @@ void QuicCryptoClientStream::DoHandshakeLoop(
return;
}
if (!cached->proof_valid()) {
- const ProofVerifier* verifier = crypto_config_->proof_verifier();
+ ProofVerifier* verifier = session()->proof_verifier();
if (!verifier) {
// If no verifier is set then we don't check the certificates.
cached->SetProofValid();
} else if (!cached->signature().empty()) {
- // TODO(rtenneti): In Chromium, we will need to make VerifyProof()
- // asynchronous.
- if (!verifier->VerifyProof(server_hostname_,
- cached->server_config(),
- cached->certs(),
- cached->signature(),
- &error_details)) {
- CloseConnectionWithDetails(QUIC_PROOF_INVALID,
- "Proof invalid: " + error_details);
- return;
- }
- cached->SetProofValid();
+ next_state_ = STATE_VERIFY_PROOF;
+ continue;
}
}
- // Send the subsequent client hello in plaintext.
- session()->connection()->SetDefaultEncryptionLevel(
- ENCRYPTION_NONE);
next_state_ = STATE_SEND_CHLO;
break;
+ case STATE_VERIFY_PROOF: {
+ ProofVerifier* verifier = session()->proof_verifier();
+ DCHECK(verifier);
+ next_state_ = STATE_VERIFY_PROOF_COMPLETED;
+ generation_counter_ = cached->generation_counter();
+ result = verifier->VerifyProof(
+ server_hostname_,
+ cached->server_config(),
+ cached->certs(),
+ cached->signature(),
+ &error_details_,
+ base::Bind(&QuicCryptoClientStream::OnVerifyProofComplete,
+ weak_factory_.GetWeakPtr()));
+ if (result == ERR_IO_PENDING) {
+ DVLOG(1) << "Doing VerifyProof";
+ return;
+ }
+ break;
+ }
+ case STATE_VERIFY_PROOF_COMPLETED: {
+ if (result != OK) {
+ CloseConnectionWithDetails(
+ QUIC_PROOF_INVALID, "Proof invalid: " + error_details_);
+ return;
+ }
+ ProofVerifier* verifier = session()->proof_verifier();
+ DCHECK(verifier);
+ // Check if generation_counter has changed between STATE_VERIFY_PROOF
+ // and STATE_VERIFY_PROOF_COMPLETED state changes.
+ if (generation_counter_ != cached->generation_counter()) {
+ next_state_ = STATE_VERIFY_PROOF;
+ continue;
+ }
+ cached->SetProofValid();
+ next_state_ = STATE_SEND_CHLO;
+ break;
+ }
case STATE_RECV_SHLO: {
// We sent a CHLO that we expected to be accepted and now we're hoping
// for a SHLO from the server to confirm that.
@@ -232,4 +264,10 @@ void QuicCryptoClientStream::DoHandshakeLoop(
}
}
+void QuicCryptoClientStream::OnVerifyProofComplete(int result) {
+ DCHECK_EQ(STATE_VERIFY_PROOF_COMPLETED, next_state_);
+ DVLOG(1) << "VerifyProof completed: " << result;
+ DoHandshakeLoop(NULL, result);
+}
+
} // namespace net
diff --git a/net/quic/quic_crypto_client_stream.h b/net/quic/quic_crypto_client_stream.h
index e85a764..86633da 100644
--- a/net/quic/quic_crypto_client_stream.h
+++ b/net/quic/quic_crypto_client_stream.h
@@ -47,12 +47,18 @@ class NET_EXPORT_PRIVATE QuicCryptoClientStream : public QuicCryptoStream {
STATE_IDLE,
STATE_SEND_CHLO,
STATE_RECV_REJ,
+ STATE_VERIFY_PROOF,
+ STATE_VERIFY_PROOF_COMPLETED,
STATE_RECV_SHLO,
};
// DoHandshakeLoop performs a step of the handshake state machine. Note that
// |in| is NULL for the first call.
- void DoHandshakeLoop(const CryptoHandshakeMessage* in);
+ void DoHandshakeLoop(const CryptoHandshakeMessage* in, int result);
+
+ void OnVerifyProofComplete(int result);
+
+ base::WeakPtrFactory<QuicCryptoClientStream> weak_factory_;
State next_state_;
// num_client_hellos_ contains the number of client hello messages that this
@@ -66,6 +72,12 @@ class NET_EXPORT_PRIVATE QuicCryptoClientStream : public QuicCryptoStream {
// Server's hostname
std::string server_hostname_;
+ // Generation counter from QuicCryptoClientConfig's CachedState.
+ uint64 generation_counter_;
+
+ // Error details for ProofVerifier's VerifyProof call.
+ std::string error_details_;
+
DISALLOW_COPY_AND_ASSIGN(QuicCryptoClientStream);
};
diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc
index 3df8b0a..b6c3f10 100644
--- a/net/quic/quic_session.cc
+++ b/net/quic/quic_session.cc
@@ -5,6 +5,7 @@
#include "net/quic/quic_session.h"
#include "base/stl_util.h"
+#include "net/quic/crypto/proof_verifier.h"
#include "net/quic/quic_connection.h"
using base::StringPiece;
@@ -257,6 +258,16 @@ void QuicSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) {
}
}
+// TODO(rtenneti): Don't port proof_verifier code back to google3 until we have
+// a way to have single ProofVerifier that can handle multiple requests.
+ProofVerifier* QuicSession::proof_verifier() const {
+ return proof_verifier_.get();
+}
+
+void QuicSession::SetProofVerifier(ProofVerifier* verifier) {
+ proof_verifier_.reset(verifier);
+}
+
QuicConfig* QuicSession::config() {
return &config_;
}
diff --git a/net/quic/quic_session.h b/net/quic/quic_session.h
index 31a05fe..bd3f604 100644
--- a/net/quic/quic_session.h
+++ b/net/quic/quic_session.h
@@ -23,6 +23,7 @@
namespace net {
+class ProofVerifier;
class QuicCryptoStream;
class ReliableQuicStream;
class VisitorShim;
@@ -104,6 +105,14 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface {
// Servers will simply call it once with HANDSHAKE_CONFIRMED.
virtual void OnCryptoHandshakeEvent(CryptoHandshakeEvent event);
+ virtual ProofVerifier* proof_verifier() const;
+
+ // SetProofVerifier takes ownership of a |ProofVerifier| that clients are
+ // free to use in order to verify certificate chains from servers. If a
+ // ProofVerifier is set then the client will request a certificate chain from
+ // the server.
+ virtual void SetProofVerifier(ProofVerifier* verifier);
+
// Returns mutable config for this session. Returned config is owned
// by QuicSession.
QuicConfig* config();
@@ -214,6 +223,7 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface {
QuicSpdyCompressor compressor_;
QuicConfig config_;
+ scoped_ptr<ProofVerifier> proof_verifier_;
// Returns the maximum number of streams this connection can open.
size_t max_open_streams_;
diff --git a/net/quic/test_tools/crypto_test_utils_chromium.cc b/net/quic/test_tools/crypto_test_utils_chromium.cc
new file mode 100644
index 0000000..5a3212ae
--- /dev/null
+++ b/net/quic/test_tools/crypto_test_utils_chromium.cc
@@ -0,0 +1,48 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/test_tools/crypto_test_utils.h"
+
+#include "base/files/file_path.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "net/base/test_data_directory.h"
+#include "net/cert/cert_verifier.h"
+#include "net/cert/test_root_certs.h"
+#include "net/cert/x509_certificate.h"
+#include "net/quic/crypto/proof_verifier_chromium.h"
+#include "net/test/cert_test_util.h"
+
+namespace net {
+
+namespace test {
+
+class TestProofVerifierChromium : public ProofVerifierChromium {
+ public:
+ TestProofVerifierChromium(CertVerifier* cert_verifier,
+ const std::string& cert_file)
+ : ProofVerifierChromium(cert_verifier, BoundNetLog()),
+ cert_verifier_(cert_verifier) {
+ // Load and install the root for the validated chain.
+ scoped_refptr<X509Certificate> root_cert =
+ ImportCertFromFile(GetTestCertsDirectory(), cert_file);
+ scoped_root_.Reset(root_cert.get());
+ }
+ virtual ~TestProofVerifierChromium() { }
+
+ private:
+ ScopedTestRoot scoped_root_;
+ scoped_ptr<CertVerifier> cert_verifier_;
+};
+
+// static
+ProofVerifier* CryptoTestUtils::ProofVerifierForTesting() {
+ TestProofVerifierChromium* proof_verifier = new TestProofVerifierChromium(
+ CertVerifier::CreateDefault(), "quic_proof_verify.crt");
+ return proof_verifier;
+}
+
+} // namespace test
+
+} // namespace net