summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorrtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-07-03 10:27:46 +0000
committerrtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-07-03 10:27:46 +0000
commit2662ed5650f65efe8c59acba3db6366d006e6a7d (patch)
tree1c571925ab02dbe7f6389364c8f134cabd3ef290 /net
parentd47d11d525fe4de37b7812528875347c38ca4f83 (diff)
downloadchromium_src-2662ed5650f65efe8c59acba3db6366d006e6a7d.zip
chromium_src-2662ed5650f65efe8c59acba3db6366d006e6a7d.tar.gz
chromium_src-2662ed5650f65efe8c59acba3db6366d006e6a7d.tar.bz2
OpenSSL/NSS implementation of ProofVerfifier.
Changes to make ProofVerifier asynchronous. Each QuicSession's ProofVerifier is used to verify the signature and cert chain. Implemented generation counter in QuicCryptoClientConfig's CachedState in case certs change when we are verifying the Proof. Review URL: https://chromiumcodereview.appspot.com/17385010 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@209946 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-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
17 files changed, 1111 insertions, 45 deletions
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