summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Sloan <varomodt@google.com>2017-03-27 22:42:16 +0000
committerandroid-build-merger <android-build-merger@google.com>2017-03-27 22:42:16 +0000
commit6844d1aab02d8c732584a7e85bc92efa6c83dfef (patch)
treec478b31bb734b02e26a264d7c1b45e49c5593acc
parentd540c9cbf76fdff98d32997f96e9341210744c29 (diff)
parentd922d6aa2268b72362edc789c00ed3de2f99145b (diff)
downloadboringssl-6844d1aab02d8c732584a7e85bc92efa6c83dfef.tar.gz
external/boringssl: Sync to bbfe603519bc54fbc4c8dd87efe1ed385df550b4. am: 6d0d00e090 am: 9ef60e37fc
am: d922d6aa22 Change-Id: I50dd83aaa70fdd2abd93068cb0dd64789109992d
-rw-r--r--BORINGSSL_REVISION2
-rw-r--r--err_data.c903
-rw-r--r--sources.bp6
-rw-r--r--sources.mk2
-rw-r--r--src/crypto/CMakeLists.txt16
-rw-r--r--src/crypto/asn1/a_time.c26
-rw-r--r--src/crypto/bio/CMakeLists.txt14
-rw-r--r--src/crypto/bio/bio_test.cc535
-rw-r--r--src/crypto/constant_time_test.cc285
-rw-r--r--src/crypto/digest/digests.c49
-rw-r--r--src/crypto/digest/internal.h2
-rw-r--r--src/crypto/err/digest.errordata2
-rw-r--r--src/crypto/err/pkcs8.errordata6
-rw-r--r--src/crypto/err/ssl.errordata3
-rw-r--r--src/crypto/evp/evp_tests.txt100
-rw-r--r--src/crypto/pkcs8/CMakeLists.txt2
-rw-r--r--src/crypto/pkcs8/internal.h34
-rw-r--r--src/crypto/pkcs8/p5_pbev2.c133
-rw-r--r--src/crypto/pkcs8/p8_pkey.c85
-rw-r--r--src/crypto/pkcs8/pkcs12_test.cc220
-rw-r--r--src/crypto/pkcs8/pkcs8.c957
-rw-r--r--src/crypto/pkcs8/pkcs8_test.cc27
-rw-r--r--src/crypto/pkcs8/pkcs8_x509.c790
-rw-r--r--src/crypto/rand/deterministic.c8
-rw-r--r--src/crypto/rsa/internal.h16
-rw-r--r--src/crypto/rsa/padding.c137
-rw-r--r--src/crypto/test/gtest_main.cc23
-rw-r--r--src/crypto/test/test_util.h2
-rw-r--r--src/crypto/x509/pkcs7.c34
-rw-r--r--src/decrepit/CMakeLists.txt3
-rw-r--r--src/decrepit/rsa/rsa_decrepit.c6
-rw-r--r--src/include/openssl/digest.h2
-rw-r--r--src/include/openssl/pkcs8.h15
-rw-r--r--src/include/openssl/rsa.h10
-rw-r--r--src/include/openssl/ssl.h59
-rw-r--r--src/ssl/CMakeLists.txt3
-rw-r--r--src/ssl/custom_extensions.c8
-rw-r--r--src/ssl/handshake_client.c31
-rw-r--r--src/ssl/handshake_server.c16
-rw-r--r--src/ssl/internal.h49
-rw-r--r--src/ssl/s3_both.c1
-rw-r--r--src/ssl/s3_pkt.c33
-rw-r--r--src/ssl/ssl_cipher.c12
-rw-r--r--src/ssl/ssl_lib.c29
-rw-r--r--src/ssl/ssl_test.cc131
-rw-r--r--src/ssl/t1_lib.c69
-rw-r--r--src/ssl/test/bssl_shim.cc84
-rw-r--r--src/ssl/test/runner/cipher_suites.go16
-rw-r--r--src/ssl/test/runner/common.go35
-rw-r--r--src/ssl/test/runner/conn.go73
-rw-r--r--src/ssl/test/runner/handshake_client.go52
-rw-r--r--src/ssl/test/runner/handshake_server.go31
-rw-r--r--src/ssl/test/runner/runner.go785
-rw-r--r--src/ssl/test/runner/ticket.go12
-rw-r--r--src/ssl/test/test_config.cc7
-rw-r--r--src/ssl/test/test_config.h7
-rw-r--r--src/ssl/tls13_both.c29
-rw-r--r--src/ssl/tls13_client.c82
-rw-r--r--src/ssl/tls13_enc.c73
-rw-r--r--src/ssl/tls13_server.c241
-rw-r--r--src/ssl/tls_record.c8
-rw-r--r--src/tool/client.cc7
-rw-r--r--src/tool/server.cc7
-rw-r--r--src/tool/transport_common.cc3
-rw-r--r--src/util/all_tests.json2
65 files changed, 3918 insertions, 2532 deletions
diff --git a/BORINGSSL_REVISION b/BORINGSSL_REVISION
index 4f7aa82b..4d70d6c4 100644
--- a/BORINGSSL_REVISION
+++ b/BORINGSSL_REVISION
@@ -1 +1 @@
-2d05568a7b7bc62affbd13ea97a81b5829b99794
+bbfe603519bc54fbc4c8dd87efe1ed385df550b4
diff --git a/err_data.c b/err_data.c
index 87a88ddb..ea6dd730 100644
--- a/err_data.c
+++ b/err_data.c
@@ -74,51 +74,51 @@ const uint32_t kOpenSSLReasonValues[] = {
0xc3a8845,
0xc3b00ea,
0x10320845,
- 0x103293c7,
- 0x103313d3,
- 0x103393ec,
- 0x103413ff,
- 0x10348ea7,
- 0x10350c35,
- 0x10359412,
- 0x10361427,
- 0x1036943a,
- 0x10371459,
- 0x10379472,
- 0x10381487,
- 0x103894a5,
- 0x103914b4,
- 0x103994d0,
- 0x103a14eb,
- 0x103a94fa,
- 0x103b1516,
- 0x103b9531,
- 0x103c1548,
+ 0x1032943b,
+ 0x10331447,
+ 0x10339460,
+ 0x10341473,
+ 0x10348eb4,
+ 0x10350c42,
+ 0x10359486,
+ 0x1036149b,
+ 0x103694ae,
+ 0x103714cd,
+ 0x103794e6,
+ 0x103814fb,
+ 0x10389519,
+ 0x10391528,
+ 0x10399544,
+ 0x103a155f,
+ 0x103a956e,
+ 0x103b158a,
+ 0x103b95a5,
+ 0x103c15bc,
0x103c80ea,
- 0x103d1559,
- 0x103d956d,
- 0x103e158c,
- 0x103e959b,
- 0x103f15b2,
- 0x103f95c5,
+ 0x103d15cd,
+ 0x103d95e1,
+ 0x103e1600,
+ 0x103e960f,
+ 0x103f1626,
+ 0x103f9639,
0x10400c06,
- 0x104095d8,
- 0x104115f6,
- 0x10419609,
- 0x10421623,
- 0x10429633,
- 0x10431647,
- 0x1043965d,
- 0x10441675,
- 0x1044968a,
- 0x1045169e,
- 0x104596b0,
+ 0x1040964c,
+ 0x1041166a,
+ 0x1041967d,
+ 0x10421697,
+ 0x104296a7,
+ 0x104316bb,
+ 0x104396d1,
+ 0x104416e9,
+ 0x104496fe,
+ 0x10451712,
+ 0x10459724,
0x104605fb,
0x1046893f,
- 0x104716c5,
- 0x104796dc,
- 0x104816f1,
- 0x104896ff,
+ 0x10471739,
+ 0x10479750,
+ 0x10481765,
+ 0x10489773,
0x14320be9,
0x14328bf7,
0x14330c06,
@@ -126,94 +126,94 @@ const uint32_t kOpenSSLReasonValues[] = {
0x143400ac,
0x143480ea,
0x18320083,
- 0x18328efd,
+ 0x18328f0a,
0x183300ac,
- 0x18338f13,
- 0x18340f27,
+ 0x18338f20,
+ 0x18340f34,
0x183480ea,
- 0x18350f3c,
- 0x18358f54,
- 0x18360f69,
- 0x18368f7d,
- 0x18370fa1,
- 0x18378fb7,
- 0x18380fcb,
- 0x18388fdb,
+ 0x18350f49,
+ 0x18358f61,
+ 0x18360f76,
+ 0x18368f8a,
+ 0x18370fae,
+ 0x18378fc4,
+ 0x18380fd8,
+ 0x18388fe8,
0x18390a57,
- 0x18398feb,
- 0x183a1000,
- 0x183a9014,
- 0x183b0c41,
- 0x183b9021,
- 0x183c1033,
- 0x183c903e,
- 0x183d104e,
- 0x183d905f,
- 0x183e1070,
- 0x183e9082,
- 0x183f10ab,
- 0x183f90c4,
- 0x184010dc,
+ 0x18398ff8,
+ 0x183a100d,
+ 0x183a9021,
+ 0x183b0c4e,
+ 0x183b902e,
+ 0x183c1040,
+ 0x183c904b,
+ 0x183d105b,
+ 0x183d906c,
+ 0x183e107d,
+ 0x183e908f,
+ 0x183f10b8,
+ 0x183f90d1,
+ 0x184010e9,
0x184086d3,
- 0x20321103,
- 0x2432110f,
+ 0x20321110,
+ 0x2432111c,
0x24328985,
- 0x24331121,
- 0x2433912e,
- 0x2434113b,
- 0x2434914d,
- 0x2435115c,
- 0x24359179,
- 0x24361186,
- 0x24369194,
- 0x243711a2,
- 0x243791b0,
- 0x243811b9,
- 0x243891c6,
- 0x243911d9,
- 0x28320c29,
- 0x28328c41,
+ 0x2433112e,
+ 0x2433913b,
+ 0x24341148,
+ 0x2434915a,
+ 0x24351169,
+ 0x24359186,
+ 0x24361193,
+ 0x243691a1,
+ 0x243711af,
+ 0x243791bd,
+ 0x243811c6,
+ 0x243891d3,
+ 0x243911e6,
+ 0x28320c36,
+ 0x28328c4e,
0x28330c06,
- 0x28338c54,
- 0x28340c35,
+ 0x28338c61,
+ 0x28340c42,
0x283480ac,
0x283500ea,
- 0x2c322a2c,
- 0x2c32aa3a,
- 0x2c332a4c,
- 0x2c33aa5e,
- 0x2c342a72,
- 0x2c34aa84,
- 0x2c352a9f,
- 0x2c35aab1,
- 0x2c362ac4,
+ 0x2c322af1,
+ 0x2c32aaff,
+ 0x2c332b11,
+ 0x2c33ab23,
+ 0x2c342b37,
+ 0x2c34ab49,
+ 0x2c352b64,
+ 0x2c35ab76,
+ 0x2c362b89,
0x2c36832d,
- 0x2c372ad1,
- 0x2c37aae3,
- 0x2c382af6,
- 0x2c38ab0d,
- 0x2c392b1b,
- 0x2c39ab2b,
- 0x2c3a2b3d,
- 0x2c3aab51,
- 0x2c3b2b62,
- 0x2c3bab81,
- 0x2c3c2b95,
- 0x2c3cabab,
- 0x2c3d2bc4,
- 0x2c3dabe1,
- 0x2c3e2bf2,
- 0x2c3eac00,
- 0x2c3f2c18,
- 0x2c3fac30,
- 0x2c402c3d,
- 0x2c409103,
- 0x2c412c4e,
- 0x2c41ac61,
- 0x2c4210dc,
- 0x2c42ac72,
+ 0x2c372b96,
+ 0x2c37aba8,
+ 0x2c382bbb,
+ 0x2c38abd2,
+ 0x2c392be0,
+ 0x2c39abf0,
+ 0x2c3a2c02,
+ 0x2c3aac16,
+ 0x2c3b2c27,
+ 0x2c3bac46,
+ 0x2c3c2c5a,
+ 0x2c3cac70,
+ 0x2c3d2c89,
+ 0x2c3daca6,
+ 0x2c3e2cb7,
+ 0x2c3eacc5,
+ 0x2c3f2cdd,
+ 0x2c3facf5,
+ 0x2c402d02,
+ 0x2c409110,
+ 0x2c412d13,
+ 0x2c41ad26,
+ 0x2c4210e9,
+ 0x2c42ad37,
0x2c430720,
- 0x2c43ab73,
+ 0x2c43ac38,
0x30320000,
0x30328015,
0x3033001f,
@@ -314,245 +314,248 @@ const uint32_t kOpenSSLReasonValues[] = {
0x34348bd3,
0x34350bb7,
0x3c320083,
- 0x3c328c7e,
- 0x3c330c97,
- 0x3c338cb2,
- 0x3c340ccf,
- 0x3c348cf9,
- 0x3c350d14,
- 0x3c358d3a,
- 0x3c360d53,
- 0x3c368d6b,
- 0x3c370d7c,
- 0x3c378d8a,
- 0x3c380d97,
- 0x3c388dab,
- 0x3c390c41,
- 0x3c398dbf,
- 0x3c3a0dd3,
+ 0x3c328c8b,
+ 0x3c330ca4,
+ 0x3c338cbf,
+ 0x3c340cdc,
+ 0x3c348d06,
+ 0x3c350d21,
+ 0x3c358d47,
+ 0x3c360d60,
+ 0x3c368d78,
+ 0x3c370d89,
+ 0x3c378d97,
+ 0x3c380da4,
+ 0x3c388db8,
+ 0x3c390c4e,
+ 0x3c398dcc,
+ 0x3c3a0de0,
0x3c3a88ff,
- 0x3c3b0de3,
- 0x3c3b8dfe,
- 0x3c3c0e10,
- 0x3c3c8e26,
- 0x3c3d0e30,
- 0x3c3d8e44,
- 0x3c3e0e52,
- 0x3c3e8e77,
- 0x3c3f0c6a,
- 0x3c3f8e60,
+ 0x3c3b0df0,
+ 0x3c3b8e0b,
+ 0x3c3c0e1d,
+ 0x3c3c8e33,
+ 0x3c3d0e3d,
+ 0x3c3d8e51,
+ 0x3c3e0e5f,
+ 0x3c3e8e84,
+ 0x3c3f0c77,
+ 0x3c3f8e6d,
0x3c4000ac,
0x3c4080ea,
- 0x3c410cea,
- 0x3c418d29,
- 0x40321716,
- 0x4032972c,
- 0x4033175a,
- 0x40339764,
- 0x4034177b,
- 0x40349799,
- 0x403517a9,
- 0x403597bb,
- 0x403617c8,
- 0x403697d4,
- 0x403717e9,
- 0x403797fb,
- 0x40381806,
- 0x40389818,
- 0x40390ea7,
- 0x40399828,
- 0x403a183b,
- 0x403a985c,
- 0x403b186d,
- 0x403b987d,
+ 0x3c410cf7,
+ 0x3c418d36,
+ 0x403217a6,
+ 0x403297bc,
+ 0x403317ea,
+ 0x403397f4,
+ 0x4034180b,
+ 0x40349829,
+ 0x40351839,
+ 0x4035984b,
+ 0x40361858,
+ 0x40369864,
+ 0x40371879,
+ 0x4037988b,
+ 0x40381896,
+ 0x403898a8,
+ 0x40390eb4,
+ 0x403998b8,
+ 0x403a18cb,
+ 0x403a98ec,
+ 0x403b18fd,
+ 0x403b990d,
0x403c0064,
0x403c8083,
- 0x403d1901,
- 0x403d9917,
- 0x403e1926,
- 0x403e995e,
- 0x403f1978,
- 0x403f9986,
- 0x4040199b,
- 0x404099af,
- 0x404119cc,
- 0x404199e7,
- 0x40421a00,
- 0x40429a13,
- 0x40431a27,
- 0x40439a3f,
- 0x40441a56,
+ 0x403d1991,
+ 0x403d99a7,
+ 0x403e19b6,
+ 0x403e99ee,
+ 0x403f1a08,
+ 0x403f9a16,
+ 0x40401a2b,
+ 0x40409a58,
+ 0x40411a75,
+ 0x40419a90,
+ 0x40421aa9,
+ 0x40429abc,
+ 0x40431ad0,
+ 0x40439ae8,
+ 0x40441aff,
0x404480ac,
- 0x40451a6b,
- 0x40459a7d,
- 0x40461aa1,
- 0x40469ac1,
- 0x40471acf,
- 0x40479af6,
- 0x40481b33,
- 0x40489b4c,
- 0x40491b63,
- 0x40499b7d,
- 0x404a1b94,
- 0x404a9bb2,
- 0x404b1bca,
- 0x404b9be1,
- 0x404c1bf7,
- 0x404c9c09,
- 0x404d1c2a,
- 0x404d9c4c,
- 0x404e1c60,
- 0x404e9c6d,
- 0x404f1c9a,
- 0x404f9cc3,
- 0x40501cfe,
- 0x40509d12,
- 0x40511d2d,
- 0x40521d3d,
- 0x40529d61,
- 0x40531d79,
- 0x40539d8c,
- 0x40541da1,
- 0x40549dc4,
- 0x40551dd2,
- 0x40559def,
- 0x40561dfc,
- 0x40569e15,
- 0x40571e2d,
- 0x40579e40,
- 0x40581e55,
- 0x40589e7c,
- 0x40591eab,
- 0x40599ed8,
- 0x405a1eec,
- 0x405a9efc,
- 0x405b1f14,
- 0x405b9f25,
- 0x405c1f38,
- 0x405c9f59,
- 0x405d1f66,
- 0x405d9f7d,
- 0x405e1fbb,
+ 0x40451b14,
+ 0x40459b26,
+ 0x40461b4a,
+ 0x40469b6a,
+ 0x40471b78,
+ 0x40479b9f,
+ 0x40481bdc,
+ 0x40489bf5,
+ 0x40491c0c,
+ 0x40499c26,
+ 0x404a1c3d,
+ 0x404a9c5b,
+ 0x404b1c73,
+ 0x404b9c8a,
+ 0x404c1ca0,
+ 0x404c9cb2,
+ 0x404d1cd3,
+ 0x404d9cf5,
+ 0x404e1d09,
+ 0x404e9d16,
+ 0x404f1d43,
+ 0x404f9d6c,
+ 0x40501da7,
+ 0x40509dbb,
+ 0x40511dd6,
+ 0x40521de6,
+ 0x40529e0a,
+ 0x40531e22,
+ 0x40539e35,
+ 0x40541e4a,
+ 0x40549e6d,
+ 0x40551e7b,
+ 0x40559e98,
+ 0x40561ea5,
+ 0x40569ebe,
+ 0x40571ed6,
+ 0x40579ee9,
+ 0x40581efe,
+ 0x40589f25,
+ 0x40591f54,
+ 0x40599f81,
+ 0x405a1f95,
+ 0x405a9fa5,
+ 0x405b1fbd,
+ 0x405b9fce,
+ 0x405c1fe1,
+ 0x405ca002,
+ 0x405d200f,
+ 0x405da026,
+ 0x405e2064,
0x405e8a95,
- 0x405f1fdc,
- 0x405f9fe9,
- 0x40601ff7,
- 0x4060a019,
- 0x4061205d,
- 0x4061a095,
- 0x406220ac,
- 0x4062a0bd,
- 0x406320ce,
- 0x4063a0e3,
- 0x406420fa,
- 0x4064a126,
- 0x40652141,
- 0x4065a158,
- 0x40662170,
- 0x4066a19a,
- 0x406721c5,
- 0x4067a1e6,
- 0x4068220d,
- 0x4068a22e,
- 0x40692260,
- 0x4069a28e,
- 0x406a22af,
- 0x406aa2cf,
- 0x406b2457,
- 0x406ba47a,
- 0x406c2490,
- 0x406ca70b,
- 0x406d273a,
- 0x406da762,
- 0x406e2790,
- 0x406ea7c4,
- 0x406f27e3,
- 0x406fa7f8,
- 0x4070280b,
- 0x4070a828,
+ 0x405f2085,
+ 0x405fa092,
+ 0x406020a0,
+ 0x4060a0c2,
+ 0x40612106,
+ 0x4061a13e,
+ 0x40622155,
+ 0x4062a166,
+ 0x40632177,
+ 0x4063a18c,
+ 0x406421a3,
+ 0x4064a1cf,
+ 0x406521ea,
+ 0x4065a201,
+ 0x40662219,
+ 0x4066a243,
+ 0x4067226e,
+ 0x4067a28f,
+ 0x406822b6,
+ 0x4068a2d7,
+ 0x40692309,
+ 0x4069a337,
+ 0x406a2358,
+ 0x406aa378,
+ 0x406b2500,
+ 0x406ba523,
+ 0x406c2539,
+ 0x406ca7b4,
+ 0x406d27e3,
+ 0x406da80b,
+ 0x406e2839,
+ 0x406ea86d,
+ 0x406f288c,
+ 0x406fa8a1,
+ 0x407028b4,
+ 0x4070a8d1,
0x40710800,
- 0x4071a83a,
- 0x4072284d,
- 0x4072a866,
- 0x4073287e,
- 0x40739389,
- 0x40742892,
- 0x4074a8ac,
- 0x407528bd,
- 0x4075a8d1,
- 0x407628df,
- 0x407691c6,
- 0x40772904,
- 0x4077a926,
- 0x40782941,
- 0x4078a97a,
- 0x40792991,
- 0x4079a9a7,
- 0x407a29b3,
- 0x407aa9c6,
- 0x407b29db,
- 0x407ba9ed,
- 0x407c2a02,
- 0x407caa0b,
- 0x407d2249,
- 0x407d9cd3,
- 0x407e2956,
- 0x407e9e8c,
- 0x407f1ae3,
- 0x407f98a3,
- 0x40801caa,
- 0x40809b0b,
- 0x40811d4f,
- 0x40819c84,
- 0x4082277b,
- 0x40829889,
- 0x40831e67,
- 0x4083a10b,
- 0x40841b1f,
- 0x40849ec4,
- 0x40851f49,
- 0x4085a041,
- 0x40861f9d,
- 0x40869ced,
- 0x408727a8,
- 0x4087a072,
- 0x408818ea,
- 0x4088a1f9,
- 0x40891939,
- 0x408998c6,
- 0x408a24b0,
- 0x41f42382,
- 0x41f92414,
- 0x41fe2307,
- 0x41fea4fc,
- 0x41ff25ed,
- 0x4203239b,
- 0x420823bd,
- 0x4208a3f9,
- 0x420922eb,
- 0x4209a433,
- 0x420a2342,
- 0x420aa322,
- 0x420b2362,
- 0x420ba3db,
- 0x420c2609,
- 0x420ca4c9,
- 0x420d24e3,
- 0x420da51a,
- 0x42122534,
- 0x421725d0,
- 0x4217a576,
- 0x421c2598,
- 0x421f2553,
- 0x42212620,
- 0x422625b3,
- 0x422b26ef,
- 0x422ba69d,
- 0x422c26d7,
- 0x422ca65c,
- 0x422d263b,
- 0x422da6bc,
- 0x422e2682,
+ 0x4071a8e3,
+ 0x407228f6,
+ 0x4072a90f,
+ 0x40732927,
+ 0x407393aa,
+ 0x4074293b,
+ 0x4074a955,
+ 0x40752966,
+ 0x4075a97a,
+ 0x40762988,
+ 0x407691d3,
+ 0x407729ad,
+ 0x4077a9cf,
+ 0x407829ea,
+ 0x4078aa23,
+ 0x40792a3a,
+ 0x4079aa50,
+ 0x407a2a5c,
+ 0x407aaa6f,
+ 0x407b2a84,
+ 0x407baa96,
+ 0x407c2ac7,
+ 0x407caad0,
+ 0x407d22f2,
+ 0x407d9d7c,
+ 0x407e29ff,
+ 0x407e9f35,
+ 0x407f1b8c,
+ 0x407f9933,
+ 0x40801d53,
+ 0x40809bb4,
+ 0x40811df8,
+ 0x40819d2d,
+ 0x40822824,
+ 0x40829919,
+ 0x40831f10,
+ 0x4083a1b4,
+ 0x40841bc8,
+ 0x40849f6d,
+ 0x40851ff2,
+ 0x4085a0ea,
+ 0x40862046,
+ 0x40869d96,
+ 0x40872851,
+ 0x4087a11b,
+ 0x4088197a,
+ 0x4088a2a2,
+ 0x408919c9,
+ 0x40899956,
+ 0x408a2559,
+ 0x408a978a,
+ 0x408b2aab,
+ 0x408b9a3f,
+ 0x41f4242b,
+ 0x41f924bd,
+ 0x41fe23b0,
+ 0x41fea5a5,
+ 0x41ff2696,
+ 0x42032444,
+ 0x42082466,
+ 0x4208a4a2,
+ 0x42092394,
+ 0x4209a4dc,
+ 0x420a23eb,
+ 0x420aa3cb,
+ 0x420b240b,
+ 0x420ba484,
+ 0x420c26b2,
+ 0x420ca572,
+ 0x420d258c,
+ 0x420da5c3,
+ 0x421225dd,
+ 0x42172679,
+ 0x4217a61f,
+ 0x421c2641,
+ 0x421f25fc,
+ 0x422126c9,
+ 0x4226265c,
+ 0x422b2798,
+ 0x422ba746,
+ 0x422c2780,
+ 0x422ca705,
+ 0x422d26e4,
+ 0x422da765,
+ 0x422e272b,
0x4432072b,
0x4432873a,
0x44330746,
@@ -570,105 +573,113 @@ const uint32_t kOpenSSLReasonValues[] = {
0x44390800,
0x4439880e,
0x443a0821,
- 0x4c3211f0,
- 0x4c329200,
- 0x4c331213,
- 0x4c339233,
+ 0x4c321211,
+ 0x4c329221,
+ 0x4c331234,
+ 0x4c339254,
0x4c3400ac,
0x4c3480ea,
- 0x4c35123f,
- 0x4c35924d,
- 0x4c361269,
- 0x4c36927c,
- 0x4c37128b,
- 0x4c379299,
- 0x4c3812ae,
- 0x4c3892ba,
- 0x4c3912da,
- 0x4c399304,
- 0x4c3a131d,
- 0x4c3a9336,
+ 0x4c351260,
+ 0x4c35926e,
+ 0x4c36128a,
+ 0x4c36929d,
+ 0x4c3712ac,
+ 0x4c3792ba,
+ 0x4c3812cf,
+ 0x4c3892db,
+ 0x4c3912fb,
+ 0x4c399325,
+ 0x4c3a133e,
+ 0x4c3a9357,
0x4c3b05fb,
- 0x4c3b934f,
- 0x4c3c1361,
- 0x4c3c9370,
- 0x4c3d1389,
- 0x4c3d9398,
- 0x4c3e13a5,
- 0x50322c84,
- 0x5032ac93,
- 0x50332c9e,
- 0x5033acae,
- 0x50342cc7,
- 0x5034ace1,
- 0x50352cef,
- 0x5035ad05,
- 0x50362d17,
- 0x5036ad2d,
- 0x50372d46,
- 0x5037ad59,
- 0x50382d71,
- 0x5038ad82,
- 0x50392d97,
- 0x5039adab,
- 0x503a2dcb,
- 0x503aade1,
- 0x503b2df9,
- 0x503bae0b,
- 0x503c2e27,
- 0x503cae3e,
- 0x503d2e57,
- 0x503dae6d,
- 0x503e2e7a,
- 0x503eae90,
- 0x503f2ea2,
+ 0x4c3b9370,
+ 0x4c3c1382,
+ 0x4c3c9391,
+ 0x4c3d13aa,
+ 0x4c3d8c29,
+ 0x4c3e1403,
+ 0x4c3e93b9,
+ 0x4c3f1425,
+ 0x4c3f91d3,
+ 0x4c4013cf,
+ 0x4c4091fd,
+ 0x4c4113f3,
+ 0x50322d49,
+ 0x5032ad58,
+ 0x50332d63,
+ 0x5033ad73,
+ 0x50342d8c,
+ 0x5034ada6,
+ 0x50352db4,
+ 0x5035adca,
+ 0x50362ddc,
+ 0x5036adf2,
+ 0x50372e0b,
+ 0x5037ae1e,
+ 0x50382e36,
+ 0x5038ae47,
+ 0x50392e5c,
+ 0x5039ae70,
+ 0x503a2e90,
+ 0x503aaea6,
+ 0x503b2ebe,
+ 0x503baed0,
+ 0x503c2eec,
+ 0x503caf03,
+ 0x503d2f1c,
+ 0x503daf32,
+ 0x503e2f3f,
+ 0x503eaf55,
+ 0x503f2f67,
0x503f8382,
- 0x50402eb5,
- 0x5040aec5,
- 0x50412edf,
- 0x5041aeee,
- 0x50422f08,
- 0x5042af25,
- 0x50432f35,
- 0x5043af45,
- 0x50442f54,
+ 0x50402f7a,
+ 0x5040af8a,
+ 0x50412fa4,
+ 0x5041afb3,
+ 0x50422fcd,
+ 0x5042afea,
+ 0x50432ffa,
+ 0x5043b00a,
+ 0x50443019,
0x5044843f,
- 0x50452f68,
- 0x5045af86,
- 0x50462f99,
- 0x5046afaf,
- 0x50472fc1,
- 0x5047afd6,
- 0x50482ffc,
- 0x5048b00a,
- 0x5049301d,
- 0x5049b032,
- 0x504a3048,
- 0x504ab058,
- 0x504b3078,
- 0x504bb08b,
- 0x504c30ae,
- 0x504cb0dc,
- 0x504d30ee,
- 0x504db10b,
- 0x504e3126,
- 0x504eb142,
- 0x504f3154,
- 0x504fb16b,
- 0x5050317a,
+ 0x5045302d,
+ 0x5045b04b,
+ 0x5046305e,
+ 0x5046b074,
+ 0x50473086,
+ 0x5047b09b,
+ 0x504830c1,
+ 0x5048b0cf,
+ 0x504930e2,
+ 0x5049b0f7,
+ 0x504a310d,
+ 0x504ab11d,
+ 0x504b313d,
+ 0x504bb150,
+ 0x504c3173,
+ 0x504cb1a1,
+ 0x504d31b3,
+ 0x504db1d0,
+ 0x504e31eb,
+ 0x504eb207,
+ 0x504f3219,
+ 0x504fb230,
+ 0x5050323f,
0x505086ef,
- 0x5051318d,
- 0x58320ee5,
- 0x68320ea7,
- 0x68328c41,
- 0x68330c54,
- 0x68338eb5,
- 0x68340ec5,
+ 0x50513252,
+ 0x58320ef2,
+ 0x68320eb4,
+ 0x68328c4e,
+ 0x68330c61,
+ 0x68338ec2,
+ 0x68340ed2,
0x683480ea,
- 0x6c320e83,
+ 0x6c320e90,
0x6c328c18,
- 0x6c330e8e,
+ 0x6c330e9b,
0x74320a0b,
+ 0x743280ac,
+ 0x74330c29,
0x78320970,
0x78328985,
0x78330991,
@@ -694,7 +705,7 @@ const uint32_t kOpenSSLReasonValues[] = {
0x783d0b19,
0x783d8b2e,
0x783e0a84,
- 0x7c3210f2,
+ 0x7c3210ff,
};
const size_t kOpenSSLReasonValuesLen = sizeof(kOpenSSLReasonValues) / sizeof(kOpenSSLReasonValues[0]);
@@ -862,6 +873,7 @@ const char kOpenSSLReasonStringData[] =
"INVALID_PUBKEY\0"
"MODULUS_TOO_LARGE\0"
"NO_PRIVATE_VALUE\0"
+ "UNKNOWN_HASH\0"
"BAD_Q_VALUE\0"
"BAD_VERSION\0"
"MISSING_PARAMETERS\0"
@@ -939,6 +951,7 @@ const char kOpenSSLReasonStringData[] =
"SHORT_HEADER\0"
"UNSUPPORTED_CIPHER\0"
"UNSUPPORTED_ENCRYPTION\0"
+ "BAD_ITERATION_COUNT\0"
"BAD_PKCS12_DATA\0"
"BAD_PKCS12_VERSION\0"
"CIPHER_HAS_NO_OBJECT_IDENTIFIER\0"
@@ -959,8 +972,11 @@ const char kOpenSSLReasonStringData[] =
"UNKNOWN_CIPHER\0"
"UNKNOWN_CIPHER_ALGORITHM\0"
"UNKNOWN_DIGEST\0"
- "UNKNOWN_HASH\0"
+ "UNSUPPORTED_KEYLENGTH\0"
+ "UNSUPPORTED_KEY_DERIVATION_FUNCTION\0"
+ "UNSUPPORTED_PRF\0"
"UNSUPPORTED_PRIVATE_KEY_ALGORITHM\0"
+ "UNSUPPORTED_SALT_TYPE\0"
"BAD_E_VALUE\0"
"BAD_FIXED_HEADER_DECRYPT\0"
"BAD_PAD_BYTE_COUNT\0"
@@ -1000,6 +1016,7 @@ const char kOpenSSLReasonStringData[] =
"UNKNOWN_PADDING_TYPE\0"
"VALUE_MISSING\0"
"WRONG_SIGNATURE_LENGTH\0"
+ "ALPN_MISMATCH_ON_EARLY_DATA\0"
"APP_DATA_IN_HANDSHAKE\0"
"ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT\0"
"BAD_ALERT\0"
@@ -1031,6 +1048,7 @@ const char kOpenSSLReasonStringData[] =
"CERT_CB_ERROR\0"
"CERT_LENGTH_MISMATCH\0"
"CHANNEL_ID_NOT_P256\0"
+ "CHANNEL_ID_ON_EARLY_DATA\0"
"CHANNEL_ID_SIGNATURE_INVALID\0"
"CIPHER_OR_HASH_UNAVAILABLE\0"
"CLIENTHELLO_PARSE_FAILED\0"
@@ -1198,6 +1216,7 @@ const char kOpenSSLReasonStringData[] =
"WRONG_SIGNATURE_TYPE\0"
"WRONG_SSL_VERSION\0"
"WRONG_VERSION_NUMBER\0"
+ "WRONG_VERSION_ON_EARLY_DATA\0"
"X509_LIB\0"
"X509_VERIFICATION_SETUP_PROBLEMS\0"
"AKID_MISMATCH\0"
diff --git a/sources.bp b/sources.bp
index d40ff4c3..cad184c6 100644
--- a/sources.bp
+++ b/sources.bp
@@ -173,8 +173,8 @@ cc_defaults {
"src/crypto/pem/pem_x509.c",
"src/crypto/pem/pem_xaux.c",
"src/crypto/pkcs8/p5_pbev2.c",
- "src/crypto/pkcs8/p8_pkey.c",
"src/crypto/pkcs8/pkcs8.c",
+ "src/crypto/pkcs8/pkcs8_x509.c",
"src/crypto/poly1305/poly1305.c",
"src/crypto/poly1305/poly1305_arm.c",
"src/crypto/poly1305/poly1305_vec.c",
@@ -465,7 +465,9 @@ cc_defaults {
name: "boringssl_crypto_test_sources",
srcs: [
"src/crypto/asn1/asn1_test.cc",
+ "src/crypto/bio/bio_test.cc",
"src/crypto/chacha/chacha_test.cc",
+ "src/crypto/constant_time_test.cc",
"src/crypto/curve25519/x25519_test.cc",
"src/crypto/dh/dh_test.cc",
"src/crypto/dsa/dsa_test.cc",
@@ -490,13 +492,11 @@ cc_defaults {
srcs: [
"src/crypto/aes/aes_test.cc",
"src/crypto/base64/base64_test.cc",
- "src/crypto/bio/bio_test.cc",
"src/crypto/bn/bn_test.cc",
"src/crypto/bytestring/bytestring_test.cc",
"src/crypto/cipher/aead_test.cc",
"src/crypto/cipher/cipher_test.cc",
"src/crypto/cmac/cmac_test.cc",
- "src/crypto/constant_time_test.cc",
"src/crypto/curve25519/ed25519_test.cc",
"src/crypto/curve25519/spake25519_test.cc",
"src/crypto/digest/digest_test.cc",
diff --git a/sources.mk b/sources.mk
index bfc9b7b4..d3d689d9 100644
--- a/sources.mk
+++ b/sources.mk
@@ -171,8 +171,8 @@ crypto_sources := \
src/crypto/pem/pem_x509.c\
src/crypto/pem/pem_xaux.c\
src/crypto/pkcs8/p5_pbev2.c\
- src/crypto/pkcs8/p8_pkey.c\
src/crypto/pkcs8/pkcs8.c\
+ src/crypto/pkcs8/pkcs8_x509.c\
src/crypto/poly1305/poly1305.c\
src/crypto/poly1305/poly1305_arm.c\
src/crypto/poly1305/poly1305_vec.c\
diff --git a/src/crypto/CMakeLists.txt b/src/crypto/CMakeLists.txt
index 81efad40..3728e6f6 100644
--- a/src/crypto/CMakeLists.txt
+++ b/src/crypto/CMakeLists.txt
@@ -177,17 +177,6 @@ if(NOT MSVC AND NOT ANDROID)
endif()
add_executable(
- constant_time_test
-
- constant_time_test.cc
-
- $<TARGET_OBJECTS:test_support>
-)
-
-target_link_libraries(constant_time_test crypto)
-add_dependencies(all_tests constant_time_test)
-
-add_executable(
thread_test
thread_test.c
@@ -212,7 +201,9 @@ add_executable(
crypto_test
asn1/asn1_test.cc
+ bio/bio_test.cc
chacha/chacha_test.cc
+ constant_time_test.cc
curve25519/x25519_test.cc
dh/dh_test.cc
dsa/dsa_test.cc
@@ -226,4 +217,7 @@ add_executable(
)
target_link_libraries(crypto_test crypto gtest)
+if (WIN32)
+ target_link_libraries(crypto_test ws2_32)
+endif()
add_dependencies(all_tests crypto_test)
diff --git a/src/crypto/asn1/a_time.c b/src/crypto/asn1/a_time.c
index 4b584297..c962c0bf 100644
--- a/src/crypto/asn1/a_time.c
+++ b/src/crypto/asn1/a_time.c
@@ -114,7 +114,7 @@ int ASN1_TIME_check(ASN1_TIME *t)
ASN1_GENERALIZEDTIME *ASN1_TIME_to_generalizedtime(ASN1_TIME *t,
ASN1_GENERALIZEDTIME **out)
{
- ASN1_GENERALIZEDTIME *ret;
+ ASN1_GENERALIZEDTIME *ret = NULL;
char *str;
int newlen;
@@ -123,22 +123,21 @@ ASN1_GENERALIZEDTIME *ASN1_TIME_to_generalizedtime(ASN1_TIME *t,
if (!out || !*out) {
if (!(ret = ASN1_GENERALIZEDTIME_new()))
- return NULL;
- if (out)
- *out = ret;
- } else
+ goto err;
+ } else {
ret = *out;
+ }
/* If already GeneralizedTime just copy across */
if (t->type == V_ASN1_GENERALIZEDTIME) {
if (!ASN1_STRING_set(ret, t->data, t->length))
- return NULL;
- return ret;
+ goto err;
+ goto done;
}
/* grow the string */
if (!ASN1_STRING_set(ret, NULL, t->length + 2))
- return NULL;
+ goto err;
/* ASN1_STRING_set() allocated 'len + 1' bytes. */
newlen = t->length + 2 + 1;
str = (char *)ret->data;
@@ -150,9 +149,18 @@ ASN1_GENERALIZEDTIME *ASN1_TIME_to_generalizedtime(ASN1_TIME *t,
BUF_strlcat(str, (char *)t->data, newlen);
- return ret;
+ done:
+ if (out != NULL && *out == NULL)
+ *out = ret;
+ return ret;
+
+ err:
+ if (out == NULL || *out != ret)
+ ASN1_GENERALIZEDTIME_free(ret);
+ return NULL;
}
+
int ASN1_TIME_set_string(ASN1_TIME *s, const char *str)
{
ASN1_TIME t;
diff --git a/src/crypto/bio/CMakeLists.txt b/src/crypto/bio/CMakeLists.txt
index 49b9d769..fccb1522 100644
--- a/src/crypto/bio/CMakeLists.txt
+++ b/src/crypto/bio/CMakeLists.txt
@@ -16,17 +16,3 @@ add_library(
socket.c
socket_helper.c
)
-
-add_executable(
- bio_test
-
- bio_test.cc
-
- $<TARGET_OBJECTS:test_support>
-)
-
-target_link_libraries(bio_test crypto)
-if (WIN32)
- target_link_libraries(bio_test ws2_32)
-endif()
-add_dependencies(all_tests bio_test)
diff --git a/src/crypto/bio/bio_test.cc b/src/crypto/bio/bio_test.cc
index fbfacf89..beb182ba 100644
--- a/src/crypto/bio/bio_test.cc
+++ b/src/crypto/bio/bio_test.cc
@@ -16,7 +16,18 @@
#define _POSIX_C_SOURCE 201410L
#endif
-#include <openssl/base.h>
+#include <algorithm>
+#include <string>
+
+#include <gtest/gtest.h>
+
+#include <openssl/bio.h>
+#include <openssl/crypto.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+#include "../internal.h"
+#include "../test/test_util.h"
#if !defined(OPENSSL_WINDOWS)
#include <arpa/inet.h>
@@ -33,27 +44,15 @@ OPENSSL_MSVC_PRAGMA(warning(push, 3))
OPENSSL_MSVC_PRAGMA(warning(pop))
#endif
-#include <openssl/bio.h>
-#include <openssl/crypto.h>
-#include <openssl/err.h>
-#include <openssl/mem.h>
-
-#include <algorithm>
-
-#include "../internal.h"
-
#if !defined(OPENSSL_WINDOWS)
-static int closesocket(int sock) {
- return close(sock);
-}
-
-static void PrintSocketError(const char *func) {
- perror(func);
-}
+static int closesocket(int sock) { return close(sock); }
+static std::string LastSocketError() { return strerror(errno); }
#else
-static void PrintSocketError(const char *func) {
- fprintf(stderr, "%s: %d\n", func, WSAGetLastError());
+static std::string LastSocketError() {
+ char buf[DECIMAL_SIZE(int) + 1];
+ BIO_snprintf(buf, sizeof(buf), "%d", WSAGetLastError());
+ return buf;
}
#endif
@@ -68,356 +67,246 @@ class ScopedSocket {
const int sock_;
};
-static bool TestSocketConnect() {
+TEST(BIOTest, SocketConnect) {
static const char kTestMessage[] = "test";
+ // Set up a listening socket on localhost.
int listening_sock = socket(AF_INET, SOCK_STREAM, 0);
- if (listening_sock == -1) {
- PrintSocketError("socket");
- return false;
- }
+ ASSERT_NE(-1, listening_sock) << LastSocketError();
ScopedSocket listening_sock_closer(listening_sock);
struct sockaddr_in sin;
OPENSSL_memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
- if (!inet_pton(AF_INET, "127.0.0.1", &sin.sin_addr)) {
- PrintSocketError("inet_pton");
- return false;
- }
- if (bind(listening_sock, (struct sockaddr *)&sin, sizeof(sin)) != 0) {
- PrintSocketError("bind");
- return false;
- }
- if (listen(listening_sock, 1)) {
- PrintSocketError("listen");
- return false;
- }
+ ASSERT_EQ(1, inet_pton(AF_INET, "127.0.0.1", &sin.sin_addr))
+ << LastSocketError();
+ ASSERT_EQ(0, bind(listening_sock, (struct sockaddr *)&sin, sizeof(sin)))
+ << LastSocketError();
+ ASSERT_EQ(0, listen(listening_sock, 1)) << LastSocketError();
socklen_t sockaddr_len = sizeof(sin);
- if (getsockname(listening_sock, (struct sockaddr *)&sin, &sockaddr_len) ||
- sockaddr_len != sizeof(sin)) {
- PrintSocketError("getsockname");
- return false;
- }
+ ASSERT_EQ(0,
+ getsockname(listening_sock, (struct sockaddr *)&sin, &sockaddr_len))
+ << LastSocketError();
+ // The Android NDK, contrary to POSIX, makes |socklen_t| signed.
+ ASSERT_EQ(sizeof(sin), static_cast<size_t>(sockaddr_len));
+ // Connect to it with a connect BIO.
char hostname[80];
BIO_snprintf(hostname, sizeof(hostname), "%s:%d", "127.0.0.1",
ntohs(sin.sin_port));
bssl::UniquePtr<BIO> bio(BIO_new_connect(hostname));
- if (!bio) {
- fprintf(stderr, "BIO_new_connect failed.\n");
- return false;
- }
+ ASSERT_TRUE(bio);
- if (BIO_write(bio.get(), kTestMessage, sizeof(kTestMessage)) !=
- sizeof(kTestMessage)) {
- fprintf(stderr, "BIO_write failed.\n");
- ERR_print_errors_fp(stderr);
- return false;
- }
+ // Write a test message to the BIO.
+ ASSERT_EQ(static_cast<int>(sizeof(kTestMessage)),
+ BIO_write(bio.get(), kTestMessage, sizeof(kTestMessage)));
+ // Accept the socket.
int sock = accept(listening_sock, (struct sockaddr *) &sin, &sockaddr_len);
- if (sock == -1) {
- PrintSocketError("accept");
- return false;
- }
+ ASSERT_NE(-1, sock) << LastSocketError();
ScopedSocket sock_closer(sock);
- char buf[5];
- if (recv(sock, buf, sizeof(buf), 0) != sizeof(kTestMessage)) {
- PrintSocketError("read");
- return false;
- }
- if (OPENSSL_memcmp(buf, kTestMessage, sizeof(kTestMessage))) {
- return false;
- }
-
- return true;
+ // Check the same message is read back out.
+ char buf[sizeof(kTestMessage)];
+ ASSERT_EQ(static_cast<int>(sizeof(kTestMessage)),
+ recv(sock, buf, sizeof(buf), 0))
+ << LastSocketError();
+ EXPECT_EQ(Bytes(kTestMessage, sizeof(kTestMessage)), Bytes(buf, sizeof(buf)));
}
-static bool TestPrintf() {
+TEST(BIOTest, Printf) {
// Test a short output, a very long one, and various sizes around
// 256 (the size of the buffer) to ensure edge cases are correct.
- static const size_t kLengths[] = { 5, 250, 251, 252, 253, 254, 1023 };
+ static const size_t kLengths[] = {5, 250, 251, 252, 253, 254, 1023};
bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_mem()));
- if (!bio) {
- fprintf(stderr, "BIO_new failed\n");
- return false;
- }
+ ASSERT_TRUE(bio);
+
+ for (size_t length : kLengths) {
+ SCOPED_TRACE(length);
+
+ std::string in(length, 'a');
+
+ int ret = BIO_printf(bio.get(), "test %s", in.c_str());
+ ASSERT_GE(ret, 0);
+ EXPECT_EQ(5 + length, static_cast<size_t>(ret));
- for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kLengths); i++) {
- char string[1024];
- if (kLengths[i] >= sizeof(string)) {
- fprintf(stderr, "Bad test string length\n");
- return false;
- }
- OPENSSL_memset(string, 'a', sizeof(string));
- string[kLengths[i]] = '\0';
-
- int ret = BIO_printf(bio.get(), "test %s", string);
- if (ret < 0 || static_cast<size_t>(ret) != 5 + kLengths[i]) {
- fprintf(stderr, "BIO_printf failed: %d\n", ret);
- return false;
- }
const uint8_t *contents;
size_t len;
- if (!BIO_mem_contents(bio.get(), &contents, &len)) {
- fprintf(stderr, "BIO_mem_contents failed\n");
- return false;
- }
- if (len != 5 + kLengths[i] ||
- strncmp((const char *)contents, "test ", 5) != 0 ||
- strncmp((const char *)contents + 5, string, kLengths[i]) != 0) {
- fprintf(stderr, "Contents did not match: %.*s\n", (int)len, contents);
- return false;
- }
-
- if (!BIO_reset(bio.get())) {
- fprintf(stderr, "BIO_reset failed\n");
- return false;
- }
- }
+ ASSERT_TRUE(BIO_mem_contents(bio.get(), &contents, &len));
+ EXPECT_EQ("test " + in,
+ std::string(reinterpret_cast<const char *>(contents), len));
- return true;
+ ASSERT_TRUE(BIO_reset(bio.get()));
+ }
}
-static bool ReadASN1(bool should_succeed, const uint8_t *data, size_t data_len,
- size_t expected_len, size_t max_len) {
- bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(data, data_len));
+static const size_t kLargeASN1PayloadLen = 8000;
+
+struct ASN1TestParam {
+ bool should_succeed;
+ std::vector<uint8_t> input;
+ // suffix_len is the number of zeros to append to |input|.
+ size_t suffix_len;
+ // expected_len, if |should_succeed| is true, is the expected length of the
+ // ASN.1 element.
+ size_t expected_len;
+ size_t max_len;
+} kASN1TestParams[] = {
+ {true, {0x30, 2, 1, 2, 0, 0}, 0, 4, 100},
+ {false /* truncated */, {0x30, 3, 1, 2}, 0, 0, 100},
+ {false /* should be short len */, {0x30, 0x81, 1, 1}, 0, 0, 100},
+ {false /* zero padded */, {0x30, 0x82, 0, 1, 1}, 0, 0, 100},
+
+ // Test a large payload.
+ {true,
+ {0x30, 0x82, kLargeASN1PayloadLen >> 8, kLargeASN1PayloadLen & 0xff},
+ kLargeASN1PayloadLen,
+ 4 + kLargeASN1PayloadLen,
+ kLargeASN1PayloadLen * 2},
+ {false /* max_len too short */,
+ {0x30, 0x82, kLargeASN1PayloadLen >> 8, kLargeASN1PayloadLen & 0xff},
+ kLargeASN1PayloadLen,
+ 4 + kLargeASN1PayloadLen,
+ 3 + kLargeASN1PayloadLen},
+
+ // Test an indefinite-length input.
+ {true,
+ {0x30, 0x80},
+ kLargeASN1PayloadLen + 2,
+ 2 + kLargeASN1PayloadLen + 2,
+ kLargeASN1PayloadLen * 2},
+ {false /* max_len too short */,
+ {0x30, 0x80},
+ kLargeASN1PayloadLen + 2,
+ 2 + kLargeASN1PayloadLen + 2,
+ 2 + kLargeASN1PayloadLen + 1},
+};
+
+class BIOASN1Test : public testing::TestWithParam<ASN1TestParam> {};
+
+TEST_P(BIOASN1Test, ReadASN1) {
+ const ASN1TestParam& param = GetParam();
+ std::vector<uint8_t> input = param.input;
+ input.resize(input.size() + param.suffix_len, 0);
+
+ bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(input.data(), input.size()));
+ ASSERT_TRUE(bio);
uint8_t *out;
size_t out_len;
- int ok = BIO_read_asn1(bio.get(), &out, &out_len, max_len);
+ int ok = BIO_read_asn1(bio.get(), &out, &out_len, param.max_len);
if (!ok) {
out = nullptr;
}
bssl::UniquePtr<uint8_t> out_storage(out);
- if (should_succeed != (ok == 1)) {
- return false;
- }
-
- if (should_succeed && (out_len != expected_len ||
- OPENSSL_memcmp(data, out, expected_len) != 0)) {
- return false;
+ ASSERT_EQ(param.should_succeed, (ok == 1));
+ if (param.should_succeed) {
+ EXPECT_EQ(Bytes(input.data(), param.expected_len), Bytes(out, out_len));
}
-
- return true;
}
-static bool TestASN1() {
- static const uint8_t kData1[] = {0x30, 2, 1, 2, 0, 0};
- static const uint8_t kData2[] = {0x30, 3, 1, 2}; /* truncated */
- static const uint8_t kData3[] = {0x30, 0x81, 1, 1}; /* should be short len */
- static const uint8_t kData4[] = {0x30, 0x82, 0, 1, 1}; /* zero padded. */
-
- if (!ReadASN1(true, kData1, sizeof(kData1), 4, 100) ||
- !ReadASN1(false, kData2, sizeof(kData2), 0, 100) ||
- !ReadASN1(false, kData3, sizeof(kData3), 0, 100) ||
- !ReadASN1(false, kData4, sizeof(kData4), 0, 100)) {
- return false;
- }
+INSTANTIATE_TEST_CASE_P(, BIOASN1Test, testing::ValuesIn(kASN1TestParams));
- static const size_t kLargePayloadLen = 8000;
- static const uint8_t kLargePrefix[] = {0x30, 0x82, kLargePayloadLen >> 8,
- kLargePayloadLen & 0xff};
- bssl::UniquePtr<uint8_t> large(reinterpret_cast<uint8_t *>(
- OPENSSL_malloc(sizeof(kLargePrefix) + kLargePayloadLen)));
- if (!large) {
- return false;
- }
- OPENSSL_memset(large.get() + sizeof(kLargePrefix), 0, kLargePayloadLen);
- OPENSSL_memcpy(large.get(), kLargePrefix, sizeof(kLargePrefix));
-
- if (!ReadASN1(true, large.get(), sizeof(kLargePrefix) + kLargePayloadLen,
- sizeof(kLargePrefix) + kLargePayloadLen,
- kLargePayloadLen * 2)) {
- fprintf(stderr, "Large payload test failed.\n");
- return false;
- }
-
- if (!ReadASN1(false, large.get(), sizeof(kLargePrefix) + kLargePayloadLen,
- sizeof(kLargePrefix) + kLargePayloadLen,
- kLargePayloadLen - 1)) {
- fprintf(stderr, "max_len test failed.\n");
- return false;
- }
-
- static const uint8_t kIndefPrefix[] = {0x30, 0x80};
- OPENSSL_memcpy(large.get(), kIndefPrefix, sizeof(kIndefPrefix));
- if (!ReadASN1(true, large.get(), sizeof(kLargePrefix) + kLargePayloadLen,
- sizeof(kLargePrefix) + kLargePayloadLen,
- kLargePayloadLen*2)) {
- fprintf(stderr, "indefinite length test failed.\n");
- return false;
- }
-
- if (!ReadASN1(false, large.get(), sizeof(kLargePrefix) + kLargePayloadLen,
- sizeof(kLargePrefix) + kLargePayloadLen,
- kLargePayloadLen-1)) {
- fprintf(stderr, "indefinite length, max_len test failed.\n");
- return false;
- }
+// Run through the tests twice, swapping |bio1| and |bio2|, for symmetry.
+class BIOPairTest : public testing::TestWithParam<bool> {};
- return true;
-}
+TEST_P(BIOPairTest, TestPair) {
+ BIO *bio1, *bio2;
+ ASSERT_TRUE(BIO_new_bio_pair(&bio1, 10, &bio2, 10));
+ bssl::UniquePtr<BIO> free_bio1(bio1), free_bio2(bio2);
-static bool TestPair() {
- // Run through the tests twice, swapping |bio1| and |bio2|, for symmetry.
- for (int i = 0; i < 2; i++) {
- BIO *bio1, *bio2;
- if (!BIO_new_bio_pair(&bio1, 10, &bio2, 10)) {
- return false;
- }
- bssl::UniquePtr<BIO> free_bio1(bio1), free_bio2(bio2);
-
- if (i == 1) {
- std::swap(bio1, bio2);
- }
-
- // Check initial states.
- if (BIO_ctrl_get_write_guarantee(bio1) != 10 ||
- BIO_ctrl_get_read_request(bio1) != 0) {
- return false;
- }
-
- // Data written in one end may be read out the other.
- char buf[20];
- if (BIO_write(bio1, "12345", 5) != 5 ||
- BIO_ctrl_get_write_guarantee(bio1) != 5 ||
- BIO_read(bio2, buf, sizeof(buf)) != 5 ||
- OPENSSL_memcmp(buf, "12345", 5) != 0 ||
- BIO_ctrl_get_write_guarantee(bio1) != 10) {
- return false;
- }
-
- // Attempting to write more than 10 bytes will write partially.
- if (BIO_write(bio1, "1234567890___", 13) != 10 ||
- BIO_ctrl_get_write_guarantee(bio1) != 0 ||
- BIO_write(bio1, "z", 1) != -1 ||
- !BIO_should_write(bio1) ||
- BIO_read(bio2, buf, sizeof(buf)) != 10 ||
- OPENSSL_memcmp(buf, "1234567890", 10) != 0 ||
- BIO_ctrl_get_write_guarantee(bio1) != 10) {
- return false;
- }
-
- // Unsuccessful reads update the read request.
- if (BIO_read(bio2, buf, 5) != -1 ||
- !BIO_should_read(bio2) ||
- BIO_ctrl_get_read_request(bio1) != 5) {
- return false;
- }
-
- // The read request is clamped to the size of the buffer.
- if (BIO_read(bio2, buf, 20) != -1 ||
- !BIO_should_read(bio2) ||
- BIO_ctrl_get_read_request(bio1) != 10) {
- return false;
- }
-
- // Data may be written and read in chunks.
- if (BIO_write(bio1, "12345", 5) != 5 ||
- BIO_ctrl_get_write_guarantee(bio1) != 5 ||
- BIO_write(bio1, "67890___", 8) != 5 ||
- BIO_ctrl_get_write_guarantee(bio1) != 0 ||
- BIO_read(bio2, buf, 3) != 3 ||
- OPENSSL_memcmp(buf, "123", 3) != 0 ||
- BIO_ctrl_get_write_guarantee(bio1) != 3 ||
- BIO_read(bio2, buf, sizeof(buf)) != 7 ||
- OPENSSL_memcmp(buf, "4567890", 7) != 0 ||
- BIO_ctrl_get_write_guarantee(bio1) != 10) {
- return false;
- }
-
- // Successful reads reset the read request.
- if (BIO_ctrl_get_read_request(bio1) != 0) {
- return false;
- }
-
- // Test writes and reads starting in the middle of the ring buffer and
- // wrapping to front.
- if (BIO_write(bio1, "abcdefgh", 8) != 8 ||
- BIO_ctrl_get_write_guarantee(bio1) != 2 ||
- BIO_read(bio2, buf, 3) != 3 ||
- OPENSSL_memcmp(buf, "abc", 3) != 0 ||
- BIO_ctrl_get_write_guarantee(bio1) != 5 ||
- BIO_write(bio1, "ijklm___", 8) != 5 ||
- BIO_ctrl_get_write_guarantee(bio1) != 0 ||
- BIO_read(bio2, buf, sizeof(buf)) != 10 ||
- OPENSSL_memcmp(buf, "defghijklm", 10) != 0 ||
- BIO_ctrl_get_write_guarantee(bio1) != 10) {
- return false;
- }
-
- // Data may flow from both ends in parallel.
- if (BIO_write(bio1, "12345", 5) != 5 ||
- BIO_write(bio2, "67890", 5) != 5 ||
- BIO_read(bio2, buf, sizeof(buf)) != 5 ||
- OPENSSL_memcmp(buf, "12345", 5) != 0 ||
- BIO_read(bio1, buf, sizeof(buf)) != 5 ||
- OPENSSL_memcmp(buf, "67890", 5) != 0) {
- return false;
- }
-
- // Closing the write end causes an EOF on the read half, after draining.
- if (BIO_write(bio1, "12345", 5) != 5 ||
- !BIO_shutdown_wr(bio1) ||
- BIO_read(bio2, buf, sizeof(buf)) != 5 ||
- OPENSSL_memcmp(buf, "12345", 5) != 0 ||
- BIO_read(bio2, buf, sizeof(buf)) != 0) {
- return false;
- }
-
- // A closed write end may not be written to.
- if (BIO_ctrl_get_write_guarantee(bio1) != 0 ||
- BIO_write(bio1, "_____", 5) != -1) {
- return false;
- }
-
- uint32_t err = ERR_get_error();
- if (ERR_GET_LIB(err) != ERR_LIB_BIO ||
- ERR_GET_REASON(err) != BIO_R_BROKEN_PIPE) {
- return false;
- }
-
- // The other end is still functional.
- if (BIO_write(bio2, "12345", 5) != 5 ||
- BIO_read(bio1, buf, sizeof(buf)) != 5 ||
- OPENSSL_memcmp(buf, "12345", 5) != 0) {
- return false;
- }
+ if (GetParam()) {
+ std::swap(bio1, bio2);
}
- return true;
+ // Check initial states.
+ EXPECT_EQ(10u, BIO_ctrl_get_write_guarantee(bio1));
+ EXPECT_EQ(0u, BIO_ctrl_get_read_request(bio1));
+
+ // Data written in one end may be read out the other.
+ uint8_t buf[20];
+ EXPECT_EQ(5, BIO_write(bio1, "12345", 5));
+ EXPECT_EQ(5u, BIO_ctrl_get_write_guarantee(bio1));
+ ASSERT_EQ(5, BIO_read(bio2, buf, sizeof(buf)));
+ EXPECT_EQ(Bytes("12345"), Bytes(buf, 5));
+ EXPECT_EQ(10u, BIO_ctrl_get_write_guarantee(bio1));
+
+ // Attempting to write more than 10 bytes will write partially.
+ EXPECT_EQ(10, BIO_write(bio1, "1234567890___", 13));
+ EXPECT_EQ(0u, BIO_ctrl_get_write_guarantee(bio1));
+ EXPECT_EQ(-1, BIO_write(bio1, "z", 1));
+ EXPECT_TRUE(BIO_should_write(bio1));
+ ASSERT_EQ(10, BIO_read(bio2, buf, sizeof(buf)));
+ EXPECT_EQ(Bytes("1234567890"), Bytes(buf, 10));
+ EXPECT_EQ(10u, BIO_ctrl_get_write_guarantee(bio1));
+
+ // Unsuccessful reads update the read request.
+ EXPECT_EQ(-1, BIO_read(bio2, buf, 5));
+ EXPECT_TRUE(BIO_should_read(bio2));
+ EXPECT_EQ(5u, BIO_ctrl_get_read_request(bio1));
+
+ // The read request is clamped to the size of the buffer.
+ EXPECT_EQ(-1, BIO_read(bio2, buf, 20));
+ EXPECT_TRUE(BIO_should_read(bio2));
+ EXPECT_EQ(10u, BIO_ctrl_get_read_request(bio1));
+
+ // Data may be written and read in chunks.
+ EXPECT_EQ(5, BIO_write(bio1, "12345", 5));
+ EXPECT_EQ(5u, BIO_ctrl_get_write_guarantee(bio1));
+ EXPECT_EQ(5, BIO_write(bio1, "67890___", 8));
+ EXPECT_EQ(0u, BIO_ctrl_get_write_guarantee(bio1));
+ ASSERT_EQ(3, BIO_read(bio2, buf, 3));
+ EXPECT_EQ(Bytes("123"), Bytes(buf, 3));
+ EXPECT_EQ(3u, BIO_ctrl_get_write_guarantee(bio1));
+ ASSERT_EQ(7, BIO_read(bio2, buf, sizeof(buf)));
+ EXPECT_EQ(Bytes("4567890"), Bytes(buf, 7));
+ EXPECT_EQ(10u, BIO_ctrl_get_write_guarantee(bio1));
+
+ // Successful reads reset the read request.
+ EXPECT_EQ(0u, BIO_ctrl_get_read_request(bio1));
+
+ // Test writes and reads starting in the middle of the ring buffer and
+ // wrapping to front.
+ EXPECT_EQ(8, BIO_write(bio1, "abcdefgh", 8));
+ EXPECT_EQ(2u, BIO_ctrl_get_write_guarantee(bio1));
+ ASSERT_EQ(3, BIO_read(bio2, buf, 3));
+ EXPECT_EQ(Bytes("abc"), Bytes(buf, 3));
+ EXPECT_EQ(5u, BIO_ctrl_get_write_guarantee(bio1));
+ EXPECT_EQ(5, BIO_write(bio1, "ijklm___", 8));
+ EXPECT_EQ(0u, BIO_ctrl_get_write_guarantee(bio1));
+ ASSERT_EQ(10, BIO_read(bio2, buf, sizeof(buf)));
+ EXPECT_EQ(Bytes("defghijklm"), Bytes(buf, 10));
+ EXPECT_EQ(10u, BIO_ctrl_get_write_guarantee(bio1));
+
+ // Data may flow from both ends in parallel.
+ EXPECT_EQ(5, BIO_write(bio1, "12345", 5));
+ EXPECT_EQ(5, BIO_write(bio2, "67890", 5));
+ ASSERT_EQ(5, BIO_read(bio2, buf, sizeof(buf)));
+ EXPECT_EQ(Bytes("12345"), Bytes(buf, 5));
+ ASSERT_EQ(5, BIO_read(bio1, buf, sizeof(buf)));
+ EXPECT_EQ(Bytes("67890"), Bytes(buf, 5));
+
+ // Closing the write end causes an EOF on the read half, after draining.
+ EXPECT_EQ(5, BIO_write(bio1, "12345", 5));
+ EXPECT_TRUE(BIO_shutdown_wr(bio1));
+ ASSERT_EQ(5, BIO_read(bio2, buf, sizeof(buf)));
+ EXPECT_EQ(Bytes("12345"), Bytes(buf, 5));
+ EXPECT_EQ(0, BIO_read(bio2, buf, sizeof(buf)));
+
+ // A closed write end may not be written to.
+ EXPECT_EQ(0u, BIO_ctrl_get_write_guarantee(bio1));
+ EXPECT_EQ(-1, BIO_write(bio1, "_____", 5));
+
+ uint32_t err = ERR_get_error();
+ EXPECT_EQ(ERR_LIB_BIO, ERR_GET_LIB(err));
+ EXPECT_EQ(BIO_R_BROKEN_PIPE, ERR_GET_REASON(err));
+
+ // The other end is still functional.
+ EXPECT_EQ(5, BIO_write(bio2, "12345", 5));
+ ASSERT_EQ(5, BIO_read(bio1, buf, sizeof(buf)));
+ EXPECT_EQ(Bytes("12345"), Bytes(buf, 5));
}
-int main() {
- CRYPTO_library_init();
-
-#if defined(OPENSSL_WINDOWS)
- // Initialize Winsock.
- WORD wsa_version = MAKEWORD(2, 2);
- WSADATA wsa_data;
- int wsa_err = WSAStartup(wsa_version, &wsa_data);
- if (wsa_err != 0) {
- fprintf(stderr, "WSAStartup failed: %d\n", wsa_err);
- return 1;
- }
- if (wsa_data.wVersion != wsa_version) {
- fprintf(stderr, "Didn't get expected version: %x\n", wsa_data.wVersion);
- return 1;
- }
-#endif
-
- if (!TestSocketConnect() ||
- !TestPrintf() ||
- !TestASN1() ||
- !TestPair()) {
- return 1;
- }
-
- printf("PASS\n");
- return 0;
-}
+INSTANTIATE_TEST_CASE_P(, BIOPairTest, testing::Values(false, true));
diff --git a/src/crypto/constant_time_test.cc b/src/crypto/constant_time_test.cc
index bc127c1c..adfe272d 100644
--- a/src/crypto/constant_time_test.cc
+++ b/src/crypto/constant_time_test.cc
@@ -49,259 +49,84 @@
#include <stdio.h>
#include <stdlib.h>
+#include <gtest/gtest.h>
-static const unsigned int CONSTTIME_TRUE = (unsigned)(~0);
-static const unsigned int CONSTTIME_FALSE = 0;
+
+static const unsigned CONSTTIME_TRUE = (unsigned)(~0);
+static const unsigned CONSTTIME_FALSE = 0;
static const uint8_t CONSTTIME_TRUE_8 = 0xff;
static const uint8_t CONSTTIME_FALSE_8 = 0;
-static int test_binary_op(unsigned int (*op)(unsigned int a, unsigned int b),
- const char* op_name, unsigned int a, unsigned int b,
- int is_true) {
- unsigned c = op(a, b);
- if (is_true && c != CONSTTIME_TRUE) {
- fprintf(stderr,
- "Test failed for %s(%du, %du): expected %du (TRUE), got %du\n",
- op_name, a, b, CONSTTIME_TRUE, c);
- return 1;
- } else if (!is_true && c != CONSTTIME_FALSE) {
- fprintf(stderr,
- "Test failed for %s(%du, %du): expected %du (FALSE), got %du\n",
- op_name, a, b, CONSTTIME_FALSE, c);
- return 1;
- }
- return 0;
+static unsigned FromBool(bool b) {
+ return b ? CONSTTIME_TRUE : CONSTTIME_FALSE;
}
-static int test_binary_op_8(uint8_t (*op)(unsigned int a, unsigned int b),
- const char* op_name, unsigned int a, unsigned int b,
- int is_true) {
- uint8_t c = op(a, b);
- if (is_true && c != CONSTTIME_TRUE_8) {
- fprintf(stderr,
- "Test failed for %s(%du, %du): expected %u (TRUE), got %u\n",
- op_name, a, b, CONSTTIME_TRUE_8, c);
- return 1;
- } else if (!is_true && c != CONSTTIME_FALSE_8) {
- fprintf(stderr,
- "Test failed for %s(%du, %du): expected %u (FALSE), got %u\n",
- op_name, a, b, CONSTTIME_FALSE_8, c);
- return 1;
- }
- return 0;
+static uint8_t FromBool8(bool b) {
+ return b ? CONSTTIME_TRUE_8 : CONSTTIME_FALSE_8;
}
-static int test_is_zero(unsigned int a) {
- unsigned int c = constant_time_is_zero(a);
- if (a == 0 && c != CONSTTIME_TRUE) {
- fprintf(stderr,
- "Test failed for constant_time_is_zero(%du): expected %du (TRUE), "
- "got %du\n",
- a, CONSTTIME_TRUE, c);
- return 1;
- } else if (a != 0 && c != CONSTTIME_FALSE) {
- fprintf(stderr,
- "Test failed for constant_time_is_zero(%du): expected %du (FALSE), "
- "got %du\n",
- a, CONSTTIME_FALSE, c);
- return 1;
- }
- return 0;
-}
+static unsigned test_values[] = {
+ 0,
+ 1,
+ 1024,
+ 12345,
+ 32000,
+ UINT_MAX / 2 - 1,
+ UINT_MAX / 2,
+ UINT_MAX / 2 + 1,
+ UINT_MAX - 1,
+ UINT_MAX,
+};
-static int test_is_zero_8(unsigned int a) {
- uint8_t c = constant_time_is_zero_8(a);
- if (a == 0 && c != CONSTTIME_TRUE_8) {
- fprintf(stderr,
- "Test failed for constant_time_is_zero(%du): expected %u (TRUE), "
- "got %u\n",
- a, CONSTTIME_TRUE_8, c);
- return 1;
- } else if (a != 0 && c != CONSTTIME_FALSE) {
- fprintf(stderr,
- "Test failed for constant_time_is_zero(%du): expected %u (FALSE), "
- "got %u\n",
- a, CONSTTIME_FALSE_8, c);
- return 1;
- }
- return 0;
-}
-
-static int test_select(unsigned int a, unsigned int b) {
- unsigned int selected = constant_time_select(CONSTTIME_TRUE, a, b);
- if (selected != a) {
- fprintf(stderr,
- "Test failed for constant_time_select(%du, %du,"
- "%du): expected %du(first value), got %du\n",
- CONSTTIME_TRUE, a, b, a, selected);
- return 1;
- }
- selected = constant_time_select(CONSTTIME_FALSE, a, b);
- if (selected != b) {
- fprintf(stderr,
- "Test failed for constant_time_select(%du, %du,"
- "%du): expected %du(second value), got %du\n",
- CONSTTIME_FALSE, a, b, b, selected);
- return 1;
- }
- return 0;
-}
-
-static int test_select_8(uint8_t a, uint8_t b) {
- uint8_t selected = constant_time_select_8(CONSTTIME_TRUE_8, a, b);
- if (selected != a) {
- fprintf(stderr,
- "Test failed for constant_time_select(%u, %u,"
- "%u): expected %u(first value), got %u\n",
- CONSTTIME_TRUE, a, b, a, selected);
- return 1;
- }
- selected = constant_time_select_8(CONSTTIME_FALSE_8, a, b);
- if (selected != b) {
- fprintf(stderr,
- "Test failed for constant_time_select(%u, %u,"
- "%u): expected %u(second value), got %u\n",
- CONSTTIME_FALSE, a, b, b, selected);
- return 1;
- }
- return 0;
-}
+static uint8_t test_values_8[] = {0, 1, 2, 20, 32, 127, 128, 129, 255};
-static int test_select_int(int a, int b) {
- int selected = constant_time_select_int(CONSTTIME_TRUE, a, b);
- if (selected != a) {
- fprintf(stderr,
- "Test failed for constant_time_select(%du, %d,"
- "%d): expected %d(first value), got %d\n",
- CONSTTIME_TRUE, a, b, a, selected);
- return 1;
- }
- selected = constant_time_select_int(CONSTTIME_FALSE, a, b);
- if (selected != b) {
- fprintf(stderr,
- "Test failed for constant_time_select(%du, %d,"
- "%d): expected %d(second value), got %d\n",
- CONSTTIME_FALSE, a, b, b, selected);
- return 1;
- }
- return 0;
-}
+static int signed_test_values[] = {
+ 0, 1, -1, 1024, -1024, 12345, -12345,
+ 32000, -32000, INT_MAX, INT_MIN, INT_MAX - 1, INT_MIN + 1};
-static int test_eq_int(int a, int b) {
- unsigned int equal = constant_time_eq_int(a, b);
- if (a == b && equal != CONSTTIME_TRUE) {
- fprintf(stderr,
- "Test failed for constant_time_eq_int(%d, %d): expected %du(TRUE), "
- "got %du\n",
- a, b, CONSTTIME_TRUE, equal);
- return 1;
- } else if (a != b && equal != CONSTTIME_FALSE) {
- fprintf(stderr,
- "Test failed for constant_time_eq_int(%d, %d): expected "
- "%du(FALSE), got %du\n",
- a, b, CONSTTIME_FALSE, equal);
- return 1;
- }
- return 0;
-}
+TEST(ConstantTimeTest, Test) {
+ for (unsigned a : test_values) {
+ SCOPED_TRACE(a);
-static int test_eq_int_8(int a, int b) {
- uint8_t equal = constant_time_eq_int_8(a, b);
- if (a == b && equal != CONSTTIME_TRUE_8) {
- fprintf(stderr,
- "Test failed for constant_time_eq_int_8(%d, %d): expected "
- "%u(TRUE), got %u\n",
- a, b, CONSTTIME_TRUE_8, equal);
- return 1;
- } else if (a != b && equal != CONSTTIME_FALSE_8) {
- fprintf(stderr,
- "Test failed for constant_time_eq_int_8(%d, %d): expected "
- "%u(FALSE), got %u\n",
- a, b, CONSTTIME_FALSE_8, equal);
- return 1;
- }
- return 0;
-}
+ EXPECT_EQ(FromBool(a == 0), constant_time_is_zero(a));
+ EXPECT_EQ(FromBool8(a == 0), constant_time_is_zero_8(a));
-static unsigned int test_values[] = {0, 1, 1024, 12345, 32000, UINT_MAX / 2 - 1,
- UINT_MAX / 2, UINT_MAX / 2 + 1,
- UINT_MAX - 1, UINT_MAX};
+ for (unsigned b : test_values) {
+ SCOPED_TRACE(b);
-static uint8_t test_values_8[] = {0, 1, 2, 20, 32, 127, 128, 129, 255};
+ EXPECT_EQ(FromBool(a < b), constant_time_lt(a, b));
+ EXPECT_EQ(FromBool8(a < b), constant_time_lt_8(a, b));
-static int signed_test_values[] = {
- 0, 1, -1, 1024, -1024, 12345, -12345,
- 32000, -32000, INT_MAX, INT_MIN, INT_MAX - 1, INT_MIN + 1};
+ EXPECT_EQ(FromBool(a >= b), constant_time_ge(a, b));
+ EXPECT_EQ(FromBool8(a >= b), constant_time_ge_8(a, b));
-int main(int argc, char* argv[]) {
- unsigned int a, b, i, j;
- int c, d;
- uint8_t e, f;
- int num_failed = 0, num_all = 0;
- fprintf(stdout, "Testing constant time operations...\n");
+ EXPECT_EQ(FromBool(a == b), constant_time_eq(a, b));
+ EXPECT_EQ(FromBool8(a == b), constant_time_eq_8(a, b));
- for (i = 0; i < sizeof(test_values) / sizeof(int); ++i) {
- a = test_values[i];
- num_failed += test_is_zero(a);
- num_failed += test_is_zero_8(a);
- num_all += 2;
- for (j = 0; j < sizeof(test_values) / sizeof(int); ++j) {
- b = test_values[j];
- num_failed +=
- test_binary_op(&constant_time_lt, "constant_time_lt", a, b, a < b);
- num_failed += test_binary_op_8(&constant_time_lt_8, "constant_time_lt_8",
- a, b, a < b);
- num_failed +=
- test_binary_op(&constant_time_lt, "constant_time_lt_8", b, a, b < a);
- num_failed += test_binary_op_8(&constant_time_lt_8, "constant_time_lt_8",
- b, a, b < a);
- num_failed +=
- test_binary_op(&constant_time_ge, "constant_time_ge", a, b, a >= b);
- num_failed += test_binary_op_8(&constant_time_ge_8, "constant_time_ge_8",
- a, b, a >= b);
- num_failed +=
- test_binary_op(&constant_time_ge, "constant_time_ge", b, a, b >= a);
- num_failed += test_binary_op_8(&constant_time_ge_8, "constant_time_ge_8",
- b, a, b >= a);
- num_failed +=
- test_binary_op(&constant_time_eq, "constant_time_eq", a, b, a == b);
- num_failed += test_binary_op_8(&constant_time_eq_8, "constant_time_eq_8",
- a, b, a == b);
- num_failed +=
- test_binary_op(&constant_time_eq, "constant_time_eq", b, a, b == a);
- num_failed += test_binary_op_8(&constant_time_eq_8, "constant_time_eq_8",
- b, a, b == a);
- num_failed += test_select(a, b);
- num_all += 13;
+ EXPECT_EQ(a, constant_time_select(CONSTTIME_TRUE, a, b));
+ EXPECT_EQ(b, constant_time_select(CONSTTIME_FALSE, a, b));
}
}
- for (i = 0; i < sizeof(signed_test_values) / sizeof(int); ++i) {
- c = signed_test_values[i];
- for (j = 0; j < sizeof(signed_test_values) / sizeof(int); ++j) {
- d = signed_test_values[j];
- num_failed += test_select_int(c, d);
- num_failed += test_eq_int(c, d);
- num_failed += test_eq_int_8(c, d);
- num_all += 3;
- }
- }
+ for (int a : signed_test_values) {
+ SCOPED_TRACE(a);
+ for (int b : signed_test_values) {
+ SCOPED_TRACE(b);
- for (i = 0; i < sizeof(test_values_8); ++i) {
- e = test_values_8[i];
- for (j = 0; j < sizeof(test_values_8); ++j) {
- f = test_values_8[j];
- num_failed += test_select_8(e, f);
- num_all += 1;
+ EXPECT_EQ(a, constant_time_select_int(CONSTTIME_TRUE, a, b));
+ EXPECT_EQ(b, constant_time_select_int(CONSTTIME_FALSE, a, b));
+
+ EXPECT_EQ(FromBool(a == b), constant_time_eq_int(a, b));
+ EXPECT_EQ(FromBool8(a == b), constant_time_eq_int_8(a, b));
}
}
- if (!num_failed) {
- fprintf(stdout, "ok (ran %d tests)\n", num_all);
- fprintf(stdout, "PASS\n");
- return EXIT_SUCCESS;
- } else {
- fprintf(stdout, "%d of %d tests failed!\n", num_failed, num_all);
- return EXIT_FAILURE;
+ for (uint8_t a : test_values_8) {
+ SCOPED_TRACE(static_cast<int>(a));
+ for (uint8_t b : test_values_8) {
+ SCOPED_TRACE(static_cast<int>(b));
+ EXPECT_EQ(a, constant_time_select_8(CONSTTIME_TRUE_8, a, b));
+ EXPECT_EQ(b, constant_time_select_8(CONSTTIME_FALSE_8, a, b));
+ }
}
}
diff --git a/src/crypto/digest/digests.c b/src/crypto/digest/digests.c
index fd2a939a..9ad2d491 100644
--- a/src/crypto/digest/digests.c
+++ b/src/crypto/digest/digests.c
@@ -60,6 +60,7 @@
#include <string.h>
#include <openssl/asn1.h>
+#include <openssl/bytestring.h>
#include <openssl/md4.h>
#include <openssl/md5.h>
#include <openssl/nid.h>
@@ -328,20 +329,58 @@ static const struct {
{ {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04}, 9, EVP_sha224 },
};
+static const EVP_MD *cbs_to_md(const CBS *cbs) {
+ for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kMDOIDs); i++) {
+ if (CBS_len(cbs) == kMDOIDs[i].oid_len &&
+ OPENSSL_memcmp(CBS_data(cbs), kMDOIDs[i].oid, kMDOIDs[i].oid_len) ==
+ 0) {
+ return kMDOIDs[i].md_func();
+ }
+ }
+
+ return NULL;
+}
+
const EVP_MD *EVP_get_digestbyobj(const ASN1_OBJECT *obj) {
/* Handle objects with no corresponding OID. */
if (obj->nid != NID_undef) {
return EVP_get_digestbynid(obj->nid);
}
- for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kMDOIDs); i++) {
- if (obj->length == kMDOIDs[i].oid_len &&
- memcmp(obj->data, kMDOIDs[i].oid, obj->length) == 0) {
- return kMDOIDs[i].md_func();
+ CBS cbs;
+ CBS_init(&cbs, obj->data, obj->length);
+ return cbs_to_md(&cbs);
+}
+
+const EVP_MD *EVP_parse_digest_algorithm(CBS *cbs) {
+ CBS algorithm, oid;
+ if (!CBS_get_asn1(cbs, &algorithm, CBS_ASN1_SEQUENCE) ||
+ !CBS_get_asn1(&algorithm, &oid, CBS_ASN1_OBJECT)) {
+ OPENSSL_PUT_ERROR(DIGEST, DIGEST_R_DECODE_ERROR);
+ return NULL;
+ }
+
+ const EVP_MD *ret = cbs_to_md(&oid);
+ if (ret == NULL) {
+ OPENSSL_PUT_ERROR(DIGEST, DIGEST_R_UNKNOWN_HASH);
+ return NULL;
+ }
+
+ /* The parameters, if present, must be NULL. Historically, whether the NULL
+ * was included or omitted was not well-specified. When parsing an
+ * AlgorithmIdentifier, we allow both. (Note this code is not used when
+ * verifying RSASSA-PKCS1-v1_5 signatures.) */
+ if (CBS_len(&algorithm) > 0) {
+ CBS param;
+ if (!CBS_get_asn1(&algorithm, &param, CBS_ASN1_NULL) ||
+ CBS_len(&param) != 0 ||
+ CBS_len(&algorithm) != 0) {
+ OPENSSL_PUT_ERROR(DIGEST, DIGEST_R_DECODE_ERROR);
+ return NULL;
}
}
- return NULL;
+ return ret;
}
const EVP_MD *EVP_get_digestbyname(const char *name) {
diff --git a/src/crypto/digest/internal.h b/src/crypto/digest/internal.h
index e3d812ad..9f83bcb8 100644
--- a/src/crypto/digest/internal.h
+++ b/src/crypto/digest/internal.h
@@ -104,6 +104,8 @@ struct evp_md_pctx_ops {
EVP_PKEY_CTX* (*dup) (EVP_PKEY_CTX *pctx);
};
+const EVP_MD *EVP_parse_digest_algorithm(CBS *cbs);
+
#if defined(__cplusplus)
} /* extern C */
diff --git a/src/crypto/err/digest.errordata b/src/crypto/err/digest.errordata
index 411e778b..bbcd9cdc 100644
--- a/src/crypto/err/digest.errordata
+++ b/src/crypto/err/digest.errordata
@@ -1 +1,3 @@
+DIGEST,101,DECODE_ERROR
DIGEST,100,INPUT_NOT_INITIALIZED
+DIGEST,102,UNKNOWN_HASH
diff --git a/src/crypto/err/pkcs8.errordata b/src/crypto/err/pkcs8.errordata
index 0eb5083b..8b51274a 100644
--- a/src/crypto/err/pkcs8.errordata
+++ b/src/crypto/err/pkcs8.errordata
@@ -1,3 +1,4 @@
+PKCS8,129,BAD_ITERATION_COUNT
PKCS8,100,BAD_PKCS12_DATA
PKCS8,101,BAD_PKCS12_VERSION
PKCS8,102,CIPHER_HAS_NO_OBJECT_IDENTIFIER
@@ -22,4 +23,9 @@ PKCS8,120,UNKNOWN_CIPHER
PKCS8,121,UNKNOWN_CIPHER_ALGORITHM
PKCS8,122,UNKNOWN_DIGEST
PKCS8,123,UNKNOWN_HASH
+PKCS8,127,UNSUPPORTED_CIPHER
+PKCS8,125,UNSUPPORTED_KEYLENGTH
+PKCS8,128,UNSUPPORTED_KEY_DERIVATION_FUNCTION
+PKCS8,130,UNSUPPORTED_PRF
PKCS8,124,UNSUPPORTED_PRIVATE_KEY_ALGORITHM
+PKCS8,126,UNSUPPORTED_SALT_TYPE
diff --git a/src/crypto/err/ssl.errordata b/src/crypto/err/ssl.errordata
index 7fddc983..5e38b30c 100644
--- a/src/crypto/err/ssl.errordata
+++ b/src/crypto/err/ssl.errordata
@@ -1,3 +1,4 @@
+SSL,277,ALPN_MISMATCH_ON_EARLY_DATA
SSL,100,APP_DATA_IN_HANDSHAKE
SSL,101,ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT
SSL,102,BAD_ALERT
@@ -32,6 +33,7 @@ SSL,125,CERTIFICATE_VERIFY_FAILED
SSL,126,CERT_CB_ERROR
SSL,127,CERT_LENGTH_MISMATCH
SSL,128,CHANNEL_ID_NOT_P256
+SSL,279,CHANNEL_ID_ON_EARLY_DATA
SSL,129,CHANNEL_ID_SIGNATURE_INVALID
SSL,130,CIPHER_OR_HASH_UNAVAILABLE
SSL,131,CLIENTHELLO_PARSE_FAILED
@@ -204,5 +206,6 @@ SSL,244,WRONG_MESSAGE_TYPE
SSL,245,WRONG_SIGNATURE_TYPE
SSL,246,WRONG_SSL_VERSION
SSL,247,WRONG_VERSION_NUMBER
+SSL,278,WRONG_VERSION_ON_EARLY_DATA
SSL,248,X509_LIB
SSL,249,X509_VERIFICATION_SETUP_PROBLEMS
diff --git a/src/crypto/evp/evp_tests.txt b/src/crypto/evp/evp_tests.txt
index 48121f9c..e70ebbcf 100644
--- a/src/crypto/evp/evp_tests.txt
+++ b/src/crypto/evp/evp_tests.txt
@@ -27,6 +27,11 @@ PrivateKey = RSA-512
Type = RSA
Input = 30820154020100300d06092a864886f70d01010105000482013e3082013a020100024100dd20403d976a38c9d79152d87b5c8e9f05033eadd7b7de709bf5b0c4a5182a97d18483526b02362b992e154a9f37faa396ca2685cdab8fec09877ebe705f4dd70203010001024055bebcca655d7e39de8a6eaa9d636db682161907064039544755c53eeb99ec618c03a210dbc61471eaba10c5c365c9726d6b7a96f54d455f7d168d49367270e1022100f21a05d9fd6817301ce49ce10448f9bdd44f5ef5b7557cd7d83155db46382ae7022100e9d1f7157783db2feab1936954ddc4e83aa365695868144cda1be6813b61d791022100d6001eb0040920860ce41fafdf23ca6dfbdf74e6e9f98cf3164cf5c16f9e727d02206f6f73f4b52b10517be6f9bc5f87fa0a3bb817e2e711636b651f9af1c85d4f21022063eff2e57f5b4ca20342cfe793e25526624e3692f192461f9e1ce7f13f2d72c8
+# RSA 515 bit key.
+PrivateKey = RSA-515
+Type = RSA
+Input = 30820157020100300d06092a864886f70d0101010500048201413082013d0201000241054fa166e205e658bbe8a2dc35311c0c2b75b7e4569fd9642c8bae809279271fc824f26baa1166ea46298ca63379ea76adbada2b61e5066820a35beaec1aca227f020301000102410266c972be0d30e53ac2acb1aa13b4bd0401cccf212452a66b4615f7e943831f67b4ca48560582d0ca886044aaaaf87945252a848c1947944186e6eb83969bf91102210309e631761842cc8a2ccfd372c20a9cba21de1a199c30ab440bc6b51079f4e825022101bf715c1db432627ca7c29a293b9210f2eff1e92d12f306ebaa5334f8ee03dcd30221018ac58a765f2b8f37d434081fe5ff92b81735ead2f263f4968ccf63d61fbe3d0d0221015b247a1159a2d5a25d0db049593c6405f77f3a278c521d066e290c2a2d8fb59d0221026224aa31fd95c14d24fd03b8a195bba4cc88df7c37f5370a5ab19f882f1404d6
+
# EC P-256 key
PrivateKey = P-256
Type = EC
@@ -177,6 +182,14 @@ Digest = SHA256
Input = "0123456789ABCDEF0123456789ABCDEF"
Output = 4de433d5844043ef08d354da03cb29068780d52706d7d1e4d50efb7d58c9d547d83a747ddd0635a96b28f854e50145518482cb49e963054621b53c60c498d07c16e9c2789c893cf38d4d86900de71bde463bd2761d1271e358c7480a1ac0bab930ddf39602ad1bc165b5d7436b516b7a7858e8eb7ab1c420eeb482f4d207f0e462b1724959320a084e13848d11d10fb593e66bf680bf6d3f345fc3e9c3de60abbac37e1c6ec80a268c8d9fc49626c679097aa690bc1aa662b95eb8db70390861aa0898229f9349b4b5fdd030d4928c47084708a933144be23bd3c6e661b85b2c0ef9ed36d498d5b7320e8194d363d4ad478c059bae804181965e0b81b663158a
+# Auto-detected salt length
+Verify = RSA-2048-SPKI
+RSAPadding = PSS
+PSSSaltLength = -2
+Digest = SHA256
+Input = "0123456789ABCDEF0123456789ABCDEF"
+Output = 4de433d5844043ef08d354da03cb29068780d52706d7d1e4d50efb7d58c9d547d83a747ddd0635a96b28f854e50145518482cb49e963054621b53c60c498d07c16e9c2789c893cf38d4d86900de71bde463bd2761d1271e358c7480a1ac0bab930ddf39602ad1bc165b5d7436b516b7a7858e8eb7ab1c420eeb482f4d207f0e462b1724959320a084e13848d11d10fb593e66bf680bf6d3f345fc3e9c3de60abbac37e1c6ec80a268c8d9fc49626c679097aa690bc1aa662b95eb8db70390861aa0898229f9349b4b5fdd030d4928c47084708a933144be23bd3c6e661b85b2c0ef9ed36d498d5b7320e8194d363d4ad478c059bae804181965e0b81b663158a
+
# Wrong digest
Verify = RSA-2048-SPKI
RSAPadding = PSS
@@ -213,6 +226,15 @@ Input = "0123456789ABCDEF0123456789ABCDEF"
Output = 4de433d5844043ef08d354da03cb29068780d52706d7d1e4d50efb7d58c9d547d83a747ddd0635a96b28f854e50145518482cb49e963054621b53c60c498d07c16e9c2789c893cf38d4d86900de71bde463bd2761d1271e358c7480a1ac0bab930ddf39602ad1bc165b5d7436b516b7a7858e8eb7ab1c420eeb482f4d207f0e462b1724959320a084e13848d11d10fb593e66bf680bf6d3f345fc3e9c3de60abbac37e1c6ec80a268c8d9fc49626c679097aa690bc1aa662b95eb8db70390861aa0898229f9349b4b5fdd030d4928c47084708a933144be23bd3c6e661b85b2c0ef9ed36d498d5b7320e8194d363d4ad478c059bae804181965e0b81b663158a
Error = SLEN_CHECK_FAILED
+# Wrong salt length using implicit hash length
+Verify = RSA-2048
+RSAPadding = PSS
+PSSSaltLength = -1
+Digest = SHA256
+Input = "0123456789ABCDEF0123456789ABCDEF"
+Output = 4de433d5844043ef08d354da03cb29068780d52706d7d1e4d50efb7d58c9d547d83a747ddd0635a96b28f854e50145518482cb49e963054621b53c60c498d07c16e9c2789c893cf38d4d86900de71bde463bd2761d1271e358c7480a1ac0bab930ddf39602ad1bc165b5d7436b516b7a7858e8eb7ab1c420eeb482f4d207f0e462b1724959320a084e13848d11d10fb593e66bf680bf6d3f345fc3e9c3de60abbac37e1c6ec80a268c8d9fc49626c679097aa690bc1aa662b95eb8db70390861aa0898229f9349b4b5fdd030d4928c47084708a933144be23bd3c6e661b85b2c0ef9ed36d498d5b7320e8194d363d4ad478c059bae804181965e0b81b663158a
+Error = SLEN_CHECK_FAILED
+
# Wrong MGF1 digest, SHA-1
Verify = RSA-2048
RSAPadding = PSS
@@ -285,6 +307,84 @@ Input = "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF"
Output = 457001d9ca50a93385fc5ec721c9dbbe7a0f2e9e4a2f846a30a8811dde66347b83901c7492039243537c7a667fafffd69049bcbd36afd0010d9b425e2d8785c1
Error = DATA_TOO_LARGE
+# Sample RSA-515 signature.
+Verify = RSA-515
+RSAPadding = PSS
+PSSSaltLength = 0
+Digest = SHA256
+Input = "0123456789ABCDEF0123456789ABCDEF"
+Output = 00c5926600f160f85e7fe950cfe123908384211cd8fe25c90cb8e8cc0593308e9aa2efe3acbf100ec1658ded8f72f506525fc2c44f06251b08d896e7bb3f05b135
+
+# The above, but with too few leading zeros.
+Verify = RSA-515
+RSAPadding = PSS
+PSSSaltLength = 0
+Digest = SHA256
+Input = "0123456789ABCDEF0123456789ABCDEF"
+Output = c5926600f160f85e7fe950cfe123908384211cd8fe25c90cb8e8cc0593308e9aa2efe3acbf100ec1658ded8f72f506525fc2c44f06251b08d896e7bb3f05b135
+Error = DATA_LEN_NOT_EQUAL_TO_MOD_LEN
+
+# The above, but with too many leading zeros.
+Verify = RSA-515
+RSAPadding = PSS
+PSSSaltLength = 0
+Digest = SHA256
+Input = "0123456789ABCDEF0123456789ABCDEF"
+Output = 0000c5926600f160f85e7fe950cfe123908384211cd8fe25c90cb8e8cc0593308e9aa2efe3acbf100ec1658ded8f72f506525fc2c44f06251b08d896e7bb3f05b135
+Error = DATA_LEN_NOT_EQUAL_TO_MOD_LEN
+
+# The above with an invalid leading byte. The top few bits of EM are required to
+# be cleared.
+Verify = RSA-515
+RSAPadding = PSS
+PSSSaltLength = 0
+Digest = SHA256
+Input = "0123456789ABCDEF0123456789ABCDEF"
+Output = 007f803c832a2090aea04013d9fa9c1630732a1625232826d235f0950f7050d3fb0eb06ef9ea8b260fad68e1165a2d770a8c7fc7a8aaa68620b021fc19c97e0041
+Error = FIRST_OCTET_INVALID
+
+# The above with an invalid trailing byte.
+Verify = RSA-515
+RSAPadding = PSS
+PSSSaltLength = 0
+Digest = SHA256
+Input = "0123456789ABCDEF0123456789ABCDEF"
+Output = 03e68555035891eb08d96c0967db22328cd892ad2856d88516ecb946bfdba732bb029b5c0dfa2119ed7349897d2324e95e86d91d0c4afc82700a36db8933abbf58
+Error = LAST_OCTET_INVALID
+
+# Non-zero salt length.
+Verify = RSA-2048-SPKI
+RSAPadding = PSS
+PSSSaltLength = 32
+Digest = SHA256
+Input = "0123456789ABCDEF0123456789ABCDEF"
+Output = 4065b284b0a6e98d4c41a8427007f878d8dd61599c87764fa79b8bf03f030c48127a4b1a5af5a6e0cf9055e57a1f47e5b0c0d8c600e78369cf1c39374899fac91a812692aa2216ba10900ce85a5cf7fddcafb726e4b83479c5bb7b3b84b08ffe183b4c2973aa3193ec7b7d4ea73bf1b579c6657b78ad7800e1975a4838c28ffe353fafef96be27b5c69677760a71b6f4df65ba6fe6b3565580a536f966928294c6e9ece807a90c1477779bcbfa3a250e98d685097c162c1c8c56ab02bd2e16eec7a019b51c067bdba7fa8cd5460796e22c607a8b6d12e1deb9be51c6943c46590f416800c48bb4cbb8c409d316573e59eadf7d3b9e6e5c2d0e570692e511e139
+
+# Non-zero salt length, wrong salt length.
+Verify = RSA-2048-SPKI
+RSAPadding = PSS
+PSSSaltLength = 31
+Digest = SHA256
+Input = "0123456789ABCDEF0123456789ABCDEF"
+Output = 4065b284b0a6e98d4c41a8427007f878d8dd61599c87764fa79b8bf03f030c48127a4b1a5af5a6e0cf9055e57a1f47e5b0c0d8c600e78369cf1c39374899fac91a812692aa2216ba10900ce85a5cf7fddcafb726e4b83479c5bb7b3b84b08ffe183b4c2973aa3193ec7b7d4ea73bf1b579c6657b78ad7800e1975a4838c28ffe353fafef96be27b5c69677760a71b6f4df65ba6fe6b3565580a536f966928294c6e9ece807a90c1477779bcbfa3a250e98d685097c162c1c8c56ab02bd2e16eec7a019b51c067bdba7fa8cd5460796e22c607a8b6d12e1deb9be51c6943c46590f416800c48bb4cbb8c409d316573e59eadf7d3b9e6e5c2d0e570692e511e139
+Error = SLEN_CHECK_FAILED
+
+# Non-zero salt length, match hash length.
+Verify = RSA-2048-SPKI
+RSAPadding = PSS
+PSSSaltLength = -1
+Digest = SHA256
+Input = "0123456789ABCDEF0123456789ABCDEF"
+Output = 4065b284b0a6e98d4c41a8427007f878d8dd61599c87764fa79b8bf03f030c48127a4b1a5af5a6e0cf9055e57a1f47e5b0c0d8c600e78369cf1c39374899fac91a812692aa2216ba10900ce85a5cf7fddcafb726e4b83479c5bb7b3b84b08ffe183b4c2973aa3193ec7b7d4ea73bf1b579c6657b78ad7800e1975a4838c28ffe353fafef96be27b5c69677760a71b6f4df65ba6fe6b3565580a536f966928294c6e9ece807a90c1477779bcbfa3a250e98d685097c162c1c8c56ab02bd2e16eec7a019b51c067bdba7fa8cd5460796e22c607a8b6d12e1deb9be51c6943c46590f416800c48bb4cbb8c409d316573e59eadf7d3b9e6e5c2d0e570692e511e139
+
+# Non-zero salt length, auto-detected.
+Verify = RSA-2048-SPKI
+RSAPadding = PSS
+PSSSaltLength = -2
+Digest = SHA256
+Input = "0123456789ABCDEF0123456789ABCDEF"
+Output = 4065b284b0a6e98d4c41a8427007f878d8dd61599c87764fa79b8bf03f030c48127a4b1a5af5a6e0cf9055e57a1f47e5b0c0d8c600e78369cf1c39374899fac91a812692aa2216ba10900ce85a5cf7fddcafb726e4b83479c5bb7b3b84b08ffe183b4c2973aa3193ec7b7d4ea73bf1b579c6657b78ad7800e1975a4838c28ffe353fafef96be27b5c69677760a71b6f4df65ba6fe6b3565580a536f966928294c6e9ece807a90c1477779bcbfa3a250e98d685097c162c1c8c56ab02bd2e16eec7a019b51c067bdba7fa8cd5460796e22c607a8b6d12e1deb9be51c6943c46590f416800c48bb4cbb8c409d316573e59eadf7d3b9e6e5c2d0e570692e511e139
+
# RSA decrypt
diff --git a/src/crypto/pkcs8/CMakeLists.txt b/src/crypto/pkcs8/CMakeLists.txt
index a2e52e15..0bdccec0 100644
--- a/src/crypto/pkcs8/CMakeLists.txt
+++ b/src/crypto/pkcs8/CMakeLists.txt
@@ -6,7 +6,7 @@ add_library(
OBJECT
pkcs8.c
- p8_pkey.c
+ pkcs8_x509.c
p5_pbev2.c
)
diff --git a/src/crypto/pkcs8/internal.h b/src/crypto/pkcs8/internal.h
index 9cebe296..583997d6 100644
--- a/src/crypto/pkcs8/internal.h
+++ b/src/crypto/pkcs8/internal.h
@@ -63,35 +63,53 @@ extern "C" {
#endif
-#define PBE_UCS2_CONVERT_PASSWORD 0x1
+/* pkcs8_pbe_decrypt decrypts |in| using the PBE scheme described by
+ * |algorithm|, which should be a serialized AlgorithmIdentifier structure. On
+ * success, it sets |*out| to a newly-allocated buffer containing the decrypted
+ * result and returns one. Otherwise, it returns zero. */
+int pkcs8_pbe_decrypt(uint8_t **out, size_t *out_len, CBS *algorithm,
+ const char *pass, size_t pass_len, const uint8_t *in,
+ size_t in_len);
+
+#define PKCS12_KEY_ID 1
+#define PKCS12_IV_ID 2
+#define PKCS12_MAC_ID 3
+
+/* pkcs12_key_gen runs the PKCS#12 key derivation function as specified in
+ * RFC 7292, appendix B. On success, it writes the resulting |out_len| bytes of
+ * key material to |out| and returns one. Otherwise, it returns zero. |id|
+ * should be one of the |PKCS12_*_ID| values. */
+int pkcs12_key_gen(const char *pass, size_t pass_len, const uint8_t *salt,
+ size_t salt_len, uint8_t id, unsigned iterations,
+ size_t out_len, uint8_t *out, const EVP_MD *md);
struct pbe_suite {
int pbe_nid;
+ uint8_t oid[10];
+ uint8_t oid_len;
const EVP_CIPHER *(*cipher_func)(void);
const EVP_MD *(*md_func)(void);
/* decrypt_init initialize |ctx| for decrypting. The password is specified by
- * |pass_raw| and |pass_raw_len|. |param| contains the serialized parameters
- * field of the AlgorithmIdentifier.
+ * |pass| and |pass_len|. |param| contains the serialized parameters field of
+ * the AlgorithmIdentifier.
*
* It returns one on success and zero on error. */
int (*decrypt_init)(const struct pbe_suite *suite, EVP_CIPHER_CTX *ctx,
- const uint8_t *pass_raw, size_t pass_raw_len, CBS *param);
- int flags;
+ const char *pass, size_t pass_len, CBS *param);
};
#define PKCS5_DEFAULT_ITERATIONS 2048
#define PKCS5_SALT_LEN 8
int PKCS5_pbe2_decrypt_init(const struct pbe_suite *suite, EVP_CIPHER_CTX *ctx,
- const uint8_t *pass_raw, size_t pass_raw_len,
- CBS *param);
+ const char *pass, size_t pass_len, CBS *param);
/* PKCS5_pbe2_encrypt_init configures |ctx| for encrypting with PKCS #5 PBES2,
* as defined in RFC 2998, with the specified parameters. It writes the
* corresponding AlgorithmIdentifier to |out|. */
int PKCS5_pbe2_encrypt_init(CBB *out, EVP_CIPHER_CTX *ctx,
const EVP_CIPHER *cipher, unsigned iterations,
- const uint8_t *pass_raw, size_t pass_raw_len,
+ const char *pass, size_t pass_len,
const uint8_t *salt, size_t salt_len);
diff --git a/src/crypto/pkcs8/p5_pbev2.c b/src/crypto/pkcs8/p5_pbev2.c
index 59e20677..29d89297 100644
--- a/src/crypto/pkcs8/p5_pbev2.c
+++ b/src/crypto/pkcs8/p5_pbev2.c
@@ -62,16 +62,86 @@
#include <openssl/cipher.h>
#include <openssl/err.h>
#include <openssl/mem.h>
-#include <openssl/obj.h>
+#include <openssl/nid.h>
#include <openssl/rand.h>
#include "internal.h"
#include "../internal.h"
+/* 1.2.840.113549.1.5.12 */
+static const uint8_t kPBKDF2[] = {0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x05, 0x0c};
+
+/* 1.2.840.113549.1.5.13 */
+static const uint8_t kPBES2[] = {0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x05, 0x0d};
+
+/* 1.2.840.113549.2.7 */
+static const uint8_t kHMACWithSHA1[] = {0x2a, 0x86, 0x48, 0x86,
+ 0xf7, 0x0d, 0x02, 0x07};
+
+static const struct {
+ uint8_t oid[9];
+ uint8_t oid_len;
+ int nid;
+ const EVP_CIPHER *(*cipher_func)(void);
+} kCipherOIDs[] = {
+ /* 1.2.840.113549.3.2 */
+ {{0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x03, 0x02},
+ 8,
+ NID_rc2_cbc,
+ &EVP_rc2_cbc},
+ /* 1.2.840.113549.3.7 */
+ {{0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x03, 0x07},
+ 8,
+ NID_des_ede3_cbc,
+ &EVP_des_ede3_cbc},
+ /* 2.16.840.1.101.3.4.1.2 */
+ {{0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x02},
+ 9,
+ NID_aes_128_cbc,
+ &EVP_aes_128_cbc},
+ /* 2.16.840.1.101.3.4.1.22 */
+ {{0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x16},
+ 9,
+ NID_aes_192_cbc,
+ &EVP_aes_192_cbc},
+ /* 2.16.840.1.101.3.4.1.42 */
+ {{0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x2a},
+ 9,
+ NID_aes_256_cbc,
+ &EVP_aes_256_cbc},
+};
+
+static const EVP_CIPHER *cbs_to_cipher(const CBS *cbs) {
+ for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kCipherOIDs); i++) {
+ if (CBS_mem_equal(cbs, kCipherOIDs[i].oid, kCipherOIDs[i].oid_len)) {
+ return kCipherOIDs[i].cipher_func();
+ }
+ }
+
+ return NULL;
+}
+
+static int add_cipher_oid(CBB *out, int nid) {
+ for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kCipherOIDs); i++) {
+ if (kCipherOIDs[i].nid == nid) {
+ CBB child;
+ return CBB_add_asn1(out, &child, CBS_ASN1_OBJECT) &&
+ CBB_add_bytes(&child, kCipherOIDs[i].oid,
+ kCipherOIDs[i].oid_len) &&
+ CBB_flush(out);
+ }
+ }
+
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNSUPPORTED_CIPHER);
+ return 0;
+}
+
static int pkcs5_pbe2_cipher_init(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
- unsigned iterations, const uint8_t *pass_raw,
- size_t pass_raw_len, const uint8_t *salt,
+ unsigned iterations, const char *pass,
+ size_t pass_len, const uint8_t *salt,
size_t salt_len, const uint8_t *iv,
size_t iv_len, int enc) {
if (iv_len != EVP_CIPHER_iv_length(cipher)) {
@@ -80,8 +150,7 @@ static int pkcs5_pbe2_cipher_init(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
}
uint8_t key[EVP_MAX_KEY_LENGTH];
- int ret = PKCS5_PBKDF2_HMAC_SHA1((const char *)pass_raw, pass_raw_len, salt,
- salt_len, iterations,
+ int ret = PKCS5_PBKDF2_HMAC_SHA1(pass, pass_len, salt, salt_len, iterations,
EVP_CIPHER_key_length(cipher), key) &&
EVP_CipherInit_ex(ctx, cipher, NULL /* engine */, key, iv, enc);
OPENSSL_cleanse(key, EVP_MAX_KEY_LENGTH);
@@ -90,7 +159,7 @@ static int pkcs5_pbe2_cipher_init(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
int PKCS5_pbe2_encrypt_init(CBB *out, EVP_CIPHER_CTX *ctx,
const EVP_CIPHER *cipher, unsigned iterations,
- const uint8_t *pass_raw, size_t pass_raw_len,
+ const char *pass, size_t pass_len,
const uint8_t *salt, size_t salt_len) {
int cipher_nid = EVP_CIPHER_nid(cipher);
if (cipher_nid == NID_undef) {
@@ -105,12 +174,15 @@ int PKCS5_pbe2_encrypt_init(CBB *out, EVP_CIPHER_CTX *ctx,
}
/* See RFC 2898, appendix A. */
- CBB algorithm, param, kdf, kdf_param, salt_cbb, cipher_cbb, iv_cbb;
+ CBB algorithm, oid, param, kdf, kdf_oid, kdf_param, salt_cbb, cipher_cbb,
+ iv_cbb;
if (!CBB_add_asn1(out, &algorithm, CBS_ASN1_SEQUENCE) ||
- !OBJ_nid2cbb(&algorithm, NID_pbes2) ||
+ !CBB_add_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) ||
+ !CBB_add_bytes(&oid, kPBES2, sizeof(kPBES2)) ||
!CBB_add_asn1(&algorithm, &param, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1(&param, &kdf, CBS_ASN1_SEQUENCE) ||
- !OBJ_nid2cbb(&kdf, NID_id_pbkdf2) ||
+ !CBB_add_asn1(&kdf, &kdf_oid, CBS_ASN1_OBJECT) ||
+ !CBB_add_bytes(&kdf_oid, kPBKDF2, sizeof(kPBKDF2)) ||
!CBB_add_asn1(&kdf, &kdf_param, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1(&kdf_param, &salt_cbb, CBS_ASN1_OCTETSTRING) ||
!CBB_add_bytes(&salt_cbb, salt, salt_len) ||
@@ -120,7 +192,7 @@ int PKCS5_pbe2_encrypt_init(CBB *out, EVP_CIPHER_CTX *ctx,
!CBB_add_asn1_uint64(&kdf_param, EVP_CIPHER_key_length(cipher))) ||
/* Omit the PRF. We use the default hmacWithSHA1. */
!CBB_add_asn1(&param, &cipher_cbb, CBS_ASN1_SEQUENCE) ||
- !OBJ_nid2cbb(&cipher_cbb, cipher_nid) ||
+ !add_cipher_oid(&cipher_cbb, cipher_nid) ||
/* RFC 2898 says RC2-CBC and RC5-CBC-Pad use a SEQUENCE with version and
* IV, but OpenSSL always uses an OCTET STRING IV, so we do the same. */
!CBB_add_asn1(&cipher_cbb, &iv_cbb, CBS_ASN1_OCTETSTRING) ||
@@ -129,14 +201,13 @@ int PKCS5_pbe2_encrypt_init(CBB *out, EVP_CIPHER_CTX *ctx,
return 0;
}
- return pkcs5_pbe2_cipher_init(ctx, cipher, iterations, pass_raw, pass_raw_len,
- salt, salt_len, iv,
- EVP_CIPHER_iv_length(cipher), 1 /* encrypt */);
+ return pkcs5_pbe2_cipher_init(ctx, cipher, iterations, pass, pass_len, salt,
+ salt_len, iv, EVP_CIPHER_iv_length(cipher),
+ 1 /* encrypt */);
}
int PKCS5_pbe2_decrypt_init(const struct pbe_suite *suite, EVP_CIPHER_CTX *ctx,
- const uint8_t *pass_raw, size_t pass_raw_len,
- CBS *param) {
+ const char *pass, size_t pass_len, CBS *param) {
CBS pbe_param, kdf, kdf_obj, enc_scheme, enc_obj;
if (!CBS_get_asn1(param, &pbe_param, CBS_ASN1_SEQUENCE) ||
CBS_len(param) != 0 ||
@@ -149,20 +220,20 @@ int PKCS5_pbe2_decrypt_init(const struct pbe_suite *suite, EVP_CIPHER_CTX *ctx,
return 0;
}
- /* Check that the key derivation function is PBKDF2. */
- if (OBJ_cbs2nid(&kdf_obj) != NID_id_pbkdf2) {
+ /* Only PBKDF2 is supported. */
+ if (!CBS_mem_equal(&kdf_obj, kPBKDF2, sizeof(kPBKDF2))) {
OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNSUPPORTED_KEY_DERIVATION_FUNCTION);
return 0;
}
/* See if we recognise the encryption algorithm. */
- const EVP_CIPHER *cipher = EVP_get_cipherbynid(OBJ_cbs2nid(&enc_obj));
+ const EVP_CIPHER *cipher = cbs_to_cipher(&enc_obj);
if (cipher == NULL) {
OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNSUPPORTED_CIPHER);
return 0;
}
- /* Parse the KDF parameters. */
+ /* Parse the KDF parameters. See RFC 8018, appendix A.2. */
CBS pbkdf2_params, salt;
uint64_t iterations;
if (!CBS_get_asn1(&kdf, &pbkdf2_params, CBS_ASN1_SEQUENCE) ||
@@ -194,8 +265,9 @@ int PKCS5_pbe2_decrypt_init(const struct pbe_suite *suite, EVP_CIPHER_CTX *ctx,
}
if (CBS_len(&pbkdf2_params) != 0) {
- CBS prf;
- if (!CBS_get_asn1(&pbkdf2_params, &prf, CBS_ASN1_OBJECT) ||
+ CBS alg_id, prf;
+ if (!CBS_get_asn1(&pbkdf2_params, &alg_id, CBS_ASN1_SEQUENCE) ||
+ !CBS_get_asn1(&alg_id, &prf, CBS_ASN1_OBJECT) ||
CBS_len(&pbkdf2_params) != 0) {
OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR);
return 0;
@@ -203,16 +275,25 @@ int PKCS5_pbe2_decrypt_init(const struct pbe_suite *suite, EVP_CIPHER_CTX *ctx,
/* We only support hmacWithSHA1. It is the DEFAULT, so DER requires it be
* omitted, but we match OpenSSL in tolerating it being present. */
- if (OBJ_cbs2nid(&prf) != NID_hmacWithSHA1) {
+ if (!CBS_mem_equal(&prf, kHMACWithSHA1, sizeof(kHMACWithSHA1))) {
OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNSUPPORTED_PRF);
return 0;
}
+
+ /* hmacWithSHA1 has a NULL parameter. */
+ CBS null;
+ if (!CBS_get_asn1(&alg_id, &null, CBS_ASN1_NULL) ||
+ CBS_len(&null) != 0 ||
+ CBS_len(&alg_id) != 0) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR);
+ return 0;
+ }
}
/* Parse the encryption scheme parameters. Note OpenSSL does not match the
* specification. Per RFC 2898, this should depend on the encryption scheme.
- * In particular, RC2-CBC and RC5-CBC-Pad use a SEQUENCE with version and IV.
- * We align with OpenSSL. */
+ * In particular, RC2-CBC uses a SEQUENCE with version and IV. We align with
+ * OpenSSL. */
CBS iv;
if (!CBS_get_asn1(&enc_scheme, &iv, CBS_ASN1_OCTETSTRING) ||
CBS_len(&enc_scheme) != 0) {
@@ -220,7 +301,7 @@ int PKCS5_pbe2_decrypt_init(const struct pbe_suite *suite, EVP_CIPHER_CTX *ctx,
return 0;
}
- return pkcs5_pbe2_cipher_init(ctx, cipher, (unsigned)iterations, pass_raw,
- pass_raw_len, CBS_data(&salt), CBS_len(&salt),
+ return pkcs5_pbe2_cipher_init(ctx, cipher, (unsigned)iterations, pass,
+ pass_len, CBS_data(&salt), CBS_len(&salt),
CBS_data(&iv), CBS_len(&iv), 0 /* decrypt */);
}
diff --git a/src/crypto/pkcs8/p8_pkey.c b/src/crypto/pkcs8/p8_pkey.c
deleted file mode 100644
index 69a7e293..00000000
--- a/src/crypto/pkcs8/p8_pkey.c
+++ /dev/null
@@ -1,85 +0,0 @@
-/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
- * project 1999.
- */
-/* ====================================================================
- * Copyright (c) 1999-2005 The OpenSSL Project. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * licensing@OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- * ====================================================================
- *
- * This product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com). */
-
-
-#include <stdio.h>
-
-#include <openssl/asn1t.h>
-#include <openssl/mem.h>
-#include <openssl/x509.h>
-
-/* Minor tweak to operation: zero private key data */
-static int pkey_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
- void *exarg) {
- /* Since the structure must still be valid use ASN1_OP_FREE_PRE */
- if (operation == ASN1_OP_FREE_PRE) {
- PKCS8_PRIV_KEY_INFO *key = (PKCS8_PRIV_KEY_INFO *)*pval;
- if (key->pkey && key->pkey->type == V_ASN1_OCTET_STRING &&
- key->pkey->value.octet_string) {
- OPENSSL_cleanse(key->pkey->value.octet_string->data,
- key->pkey->value.octet_string->length);
- }
- }
- return 1;
-}
-
-ASN1_SEQUENCE_cb(PKCS8_PRIV_KEY_INFO, pkey_cb) = {
- ASN1_SIMPLE(PKCS8_PRIV_KEY_INFO, version, ASN1_INTEGER),
- ASN1_SIMPLE(PKCS8_PRIV_KEY_INFO, pkeyalg, X509_ALGOR),
- ASN1_SIMPLE(PKCS8_PRIV_KEY_INFO, pkey, ASN1_ANY),
- ASN1_IMP_SET_OF_OPT(PKCS8_PRIV_KEY_INFO, attributes, X509_ATTRIBUTE, 0)
-} ASN1_SEQUENCE_END_cb(PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO)
-
-IMPLEMENT_ASN1_FUNCTIONS(PKCS8_PRIV_KEY_INFO)
diff --git a/src/crypto/pkcs8/pkcs12_test.cc b/src/crypto/pkcs8/pkcs12_test.cc
index 5c1a1b48..ba027615 100644
--- a/src/crypto/pkcs8/pkcs12_test.cc
+++ b/src/crypto/pkcs8/pkcs12_test.cc
@@ -679,6 +679,225 @@ static const uint8_t kWindows[] = {
0xfe, 0x3a, 0x66, 0x47, 0x40, 0x49, 0x02, 0x02, 0x07, 0xd0,
};
+/* kPBES2 is a PKCS#12 file using PBES2 created with:
+ * openssl pkcs12 -export -inkey key.pem -in cert.pem -keypbe AES-128-CBC \
+ * -certpbe AES-128-CBC */
+static const uint8_t kPBES2[] = {
+ 0x30, 0x82, 0x0a, 0x03, 0x02, 0x01, 0x03, 0x30, 0x82, 0x09, 0xc9, 0x06,
+ 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x82,
+ 0x09, 0xba, 0x04, 0x82, 0x09, 0xb6, 0x30, 0x82, 0x09, 0xb2, 0x30, 0x82,
+ 0x04, 0x34, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
+ 0x06, 0xa0, 0x82, 0x04, 0x25, 0x30, 0x82, 0x04, 0x21, 0x02, 0x01, 0x00,
+ 0x30, 0x82, 0x04, 0x1a, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x07, 0x01, 0x30, 0x49, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x05, 0x0d, 0x30, 0x3c, 0x30, 0x1b, 0x06, 0x09, 0x2a, 0x86,
+ 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x05, 0x0c, 0x30, 0x0e, 0x04, 0x08, 0xdb,
+ 0x48, 0xe6, 0x98, 0x09, 0x8f, 0x6e, 0x2d, 0x02, 0x02, 0x08, 0x00, 0x30,
+ 0x1d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x02,
+ 0x04, 0x10, 0xee, 0xb3, 0x10, 0xe5, 0x21, 0x85, 0x03, 0x3e, 0x69, 0xad,
+ 0xdf, 0x78, 0xa7, 0xd8, 0xac, 0xf1, 0x80, 0x82, 0x03, 0xc0, 0xcb, 0x58,
+ 0x11, 0x28, 0x1d, 0xbc, 0x3c, 0x8c, 0xe7, 0x7b, 0x15, 0x67, 0x30, 0xf3,
+ 0x2b, 0x94, 0x10, 0x8c, 0xbe, 0xfd, 0xaa, 0x11, 0xd7, 0x99, 0xee, 0x21,
+ 0xb6, 0x1b, 0x4f, 0x53, 0xcb, 0x44, 0xff, 0x4f, 0xbf, 0xf6, 0x43, 0x3d,
+ 0x12, 0xe6, 0x09, 0xe8, 0x05, 0xdd, 0x2f, 0xc5, 0x39, 0xde, 0x0c, 0x88,
+ 0xe8, 0x4e, 0x89, 0x8f, 0x5f, 0xdf, 0x23, 0x50, 0xe6, 0xb7, 0xba, 0x1a,
+ 0xdd, 0x1c, 0x63, 0x51, 0x0e, 0x71, 0xb7, 0xf7, 0x39, 0x3c, 0xd4, 0xe7,
+ 0x52, 0x50, 0xc5, 0xd7, 0xbf, 0x65, 0x94, 0x72, 0x97, 0x2a, 0xb9, 0x68,
+ 0xc2, 0xbd, 0x0c, 0x97, 0x02, 0x74, 0x23, 0x7f, 0x11, 0x6b, 0xea, 0xb4,
+ 0xe4, 0x2f, 0xf0, 0x8b, 0x91, 0x5c, 0xdb, 0xae, 0x10, 0xbf, 0x89, 0xbc,
+ 0x62, 0xef, 0x99, 0xbf, 0x07, 0x59, 0x58, 0x12, 0xef, 0xaf, 0xe6, 0xcd,
+ 0x30, 0x27, 0xe4, 0xab, 0x44, 0xf7, 0xf9, 0x14, 0xb2, 0x5d, 0xfa, 0x97,
+ 0xe6, 0x9a, 0xed, 0x85, 0x60, 0x86, 0xd9, 0xb0, 0xd7, 0xa4, 0xe4, 0x00,
+ 0xa8, 0xee, 0xbb, 0xfc, 0x0d, 0xe8, 0x58, 0x7a, 0xca, 0x02, 0x1d, 0x02,
+ 0xab, 0xbd, 0x16, 0x50, 0x4f, 0xfc, 0x60, 0xde, 0x48, 0xb1, 0x7f, 0xea,
+ 0xba, 0x45, 0x7b, 0x29, 0xfe, 0x8e, 0xed, 0x48, 0xd2, 0x31, 0x64, 0xda,
+ 0x89, 0x84, 0x6f, 0xd1, 0xd2, 0xb1, 0x7b, 0x97, 0x19, 0x38, 0x16, 0xd9,
+ 0x3f, 0xd6, 0xdb, 0x6f, 0xab, 0x56, 0x34, 0xca, 0x34, 0x9c, 0x57, 0x41,
+ 0x6e, 0x87, 0x85, 0x2a, 0xa8, 0xfb, 0xe9, 0xf6, 0x3d, 0xb6, 0x83, 0x7b,
+ 0x02, 0xc9, 0xbe, 0xf1, 0xbb, 0x8e, 0xe5, 0x68, 0xae, 0xaa, 0xe1, 0x25,
+ 0x8d, 0x1f, 0x1f, 0x52, 0x45, 0x3e, 0xef, 0x33, 0xd8, 0x58, 0xd9, 0x48,
+ 0xd4, 0xb5, 0xe1, 0x53, 0x21, 0xb5, 0xbd, 0xd4, 0x63, 0x1f, 0xbf, 0xe4,
+ 0x30, 0x5e, 0xc3, 0x63, 0xce, 0xdc, 0x12, 0x8c, 0xc7, 0x0c, 0xea, 0x3b,
+ 0xf3, 0x0b, 0x38, 0x8d, 0xcc, 0x9b, 0xe7, 0xa0, 0x14, 0x5e, 0x48, 0x9c,
+ 0x74, 0x86, 0x8e, 0x2b, 0x77, 0x80, 0xbb, 0x85, 0xa6, 0xd4, 0x25, 0x6e,
+ 0x75, 0x07, 0x59, 0xd6, 0x88, 0x00, 0x35, 0x03, 0x5a, 0xb0, 0x86, 0x7e,
+ 0x01, 0xa7, 0x77, 0x74, 0x13, 0xfa, 0x9f, 0x2d, 0xe3, 0x90, 0xda, 0x68,
+ 0x23, 0x36, 0x0b, 0x62, 0x21, 0x76, 0xda, 0x6c, 0x05, 0x35, 0x80, 0xfc,
+ 0xee, 0x5f, 0x3c, 0xac, 0x60, 0x2a, 0x9c, 0x6e, 0x4c, 0xaa, 0xa3, 0xd1,
+ 0xdf, 0x2c, 0x7e, 0x0e, 0xc0, 0xa0, 0x84, 0xe4, 0xb2, 0x33, 0x1f, 0x8c,
+ 0xcb, 0x74, 0x31, 0x18, 0x5b, 0x0b, 0x18, 0x41, 0xc6, 0x87, 0x13, 0xa2,
+ 0xad, 0x1d, 0x43, 0x5e, 0x67, 0xd0, 0x31, 0xf5, 0x61, 0x7c, 0x3d, 0x16,
+ 0x55, 0x01, 0x94, 0x45, 0xa4, 0x50, 0x0f, 0xb1, 0x1b, 0x81, 0x51, 0xa7,
+ 0x92, 0xae, 0xa3, 0x6d, 0x4e, 0x55, 0x46, 0x37, 0x98, 0xe1, 0xe4, 0x5c,
+ 0x29, 0x79, 0xc9, 0x76, 0x0a, 0xb5, 0x9d, 0x1b, 0x8a, 0xf6, 0xab, 0xeb,
+ 0x69, 0x6e, 0x17, 0x88, 0xeb, 0x82, 0xfa, 0x78, 0x2f, 0x8c, 0x30, 0xfd,
+ 0xf1, 0x74, 0xcd, 0x53, 0x78, 0x27, 0x43, 0x82, 0x05, 0x37, 0x07, 0xb3,
+ 0x4c, 0x89, 0x9d, 0x00, 0x1d, 0x73, 0xad, 0x0f, 0xcd, 0x63, 0xbe, 0x9b,
+ 0xa9, 0x50, 0xa5, 0x43, 0x74, 0x86, 0x87, 0xbc, 0xd9, 0x97, 0x66, 0x84,
+ 0x35, 0x3e, 0x67, 0xce, 0x92, 0x2c, 0x78, 0xc7, 0x88, 0x19, 0x6a, 0x1c,
+ 0xa8, 0x93, 0x0b, 0x79, 0x21, 0xe5, 0x39, 0x1b, 0x00, 0x68, 0x2a, 0x0b,
+ 0xac, 0x6a, 0x2f, 0xc1, 0x9c, 0x90, 0x18, 0x86, 0x63, 0x53, 0x72, 0x34,
+ 0xd9, 0xa8, 0x92, 0xce, 0x64, 0x3a, 0xeb, 0xba, 0xd8, 0x31, 0xf3, 0xfb,
+ 0x2a, 0xac, 0xc6, 0xe7, 0xd1, 0x0b, 0x7c, 0xfc, 0xbb, 0x69, 0x57, 0xc8,
+ 0x97, 0x3d, 0xdb, 0x81, 0x77, 0x2a, 0x9f, 0x07, 0x2c, 0x79, 0x69, 0xbc,
+ 0x51, 0x0e, 0x68, 0x11, 0x00, 0x10, 0xed, 0x9f, 0xb8, 0x8d, 0xa0, 0x25,
+ 0x20, 0xd3, 0x3d, 0x08, 0x20, 0x46, 0xfa, 0x89, 0xef, 0x69, 0x4c, 0x60,
+ 0x33, 0x80, 0xb9, 0x53, 0xb4, 0x7b, 0xab, 0x38, 0xf1, 0xcd, 0xb8, 0x75,
+ 0xc4, 0x85, 0x0a, 0xda, 0xab, 0x19, 0x40, 0xd3, 0x88, 0xd5, 0xf7, 0x5f,
+ 0x8e, 0xcd, 0x8e, 0xa4, 0x1c, 0x9c, 0x22, 0x6d, 0xce, 0x66, 0x29, 0xfa,
+ 0x62, 0x6f, 0x01, 0xdc, 0x46, 0x45, 0x38, 0x64, 0xf7, 0xc4, 0x94, 0xfd,
+ 0x48, 0x44, 0x70, 0x4d, 0xef, 0xf0, 0x4b, 0x95, 0xf8, 0x68, 0x8d, 0xb7,
+ 0x35, 0x7d, 0xc6, 0xf5, 0x97, 0xce, 0x5d, 0xad, 0xe8, 0x5c, 0xeb, 0x4f,
+ 0x9b, 0x5b, 0x03, 0xce, 0x33, 0x60, 0xf5, 0xce, 0xcc, 0xfe, 0xfb, 0x77,
+ 0x40, 0xc4, 0xf4, 0x9d, 0xf3, 0x2c, 0xdb, 0x83, 0xc2, 0x1a, 0xf2, 0xb6,
+ 0xbe, 0xfc, 0x2c, 0x7f, 0x29, 0x20, 0x35, 0x50, 0x00, 0x60, 0x03, 0xd2,
+ 0xb3, 0x03, 0x18, 0x64, 0xb9, 0x64, 0x98, 0x33, 0xdb, 0x47, 0x43, 0xe2,
+ 0xa1, 0x85, 0x79, 0x9b, 0xb1, 0x0b, 0x0e, 0xbb, 0x14, 0x5f, 0xb9, 0x16,
+ 0xb6, 0xc3, 0xf6, 0x5c, 0x01, 0xe3, 0xaa, 0x3f, 0x03, 0xad, 0x18, 0xeb,
+ 0x0e, 0x3d, 0xa3, 0x1f, 0xcc, 0x4d, 0x48, 0x44, 0x7e, 0xda, 0xb9, 0x9d,
+ 0x17, 0xe8, 0x92, 0x46, 0xea, 0xf5, 0x3e, 0x05, 0x4e, 0xa7, 0xb5, 0x94,
+ 0x6d, 0x95, 0x42, 0xa7, 0x71, 0xfb, 0xc2, 0x45, 0xd6, 0xd2, 0x86, 0xd0,
+ 0x79, 0x99, 0x1f, 0x96, 0x78, 0x22, 0xeb, 0x05, 0x26, 0xf2, 0xa1, 0x67,
+ 0x67, 0x2b, 0xae, 0x1d, 0x28, 0x42, 0xd6, 0xbe, 0x08, 0xf6, 0xb7, 0x54,
+ 0xc8, 0x82, 0xbf, 0x92, 0x0f, 0x2c, 0xba, 0x47, 0xe2, 0x01, 0x73, 0x2c,
+ 0xd7, 0x34, 0x84, 0x2f, 0xb6, 0x41, 0x84, 0xeb, 0x7a, 0xb2, 0xf9, 0xdd,
+ 0x31, 0xbe, 0x07, 0xb4, 0x88, 0x05, 0xd8, 0xe1, 0x79, 0x55, 0xe6, 0x4b,
+ 0x8c, 0xdc, 0xd1, 0x76, 0x58, 0x72, 0x42, 0x28, 0xb3, 0x9f, 0xd0, 0x05,
+ 0x37, 0x6b, 0x65, 0x74, 0xce, 0x0d, 0x01, 0xa9, 0x49, 0xc5, 0x90, 0xab,
+ 0x90, 0x16, 0x2c, 0x9c, 0xba, 0xcb, 0x94, 0xc7, 0xfa, 0xe0, 0x39, 0x82,
+ 0xa2, 0x88, 0xd6, 0x0c, 0xc4, 0x4d, 0xfe, 0xb4, 0xbc, 0x87, 0xe5, 0x63,
+ 0x3b, 0x6b, 0xf0, 0xd1, 0x09, 0x39, 0x8f, 0x51, 0x4f, 0x32, 0xae, 0xed,
+ 0x0c, 0xff, 0x79, 0x52, 0x19, 0xa9, 0x4e, 0x45, 0x11, 0xc3, 0x5f, 0xd6,
+ 0x2b, 0x66, 0xe3, 0x9c, 0xbe, 0xbc, 0xda, 0x65, 0x25, 0xcd, 0xf5, 0x73,
+ 0x45, 0x09, 0xf5, 0x5d, 0x6b, 0x83, 0x45, 0x28, 0x98, 0x2c, 0x58, 0x44,
+ 0xca, 0x37, 0xeb, 0xc3, 0xc2, 0x10, 0x77, 0x14, 0x79, 0x9b, 0xd8, 0xb2,
+ 0xbf, 0x45, 0xd5, 0x63, 0xe4, 0x37, 0x42, 0x7b, 0x2d, 0xe2, 0x49, 0xb3,
+ 0x18, 0x8e, 0x86, 0x73, 0xf1, 0x59, 0x8a, 0xf2, 0x3c, 0x49, 0x12, 0x7b,
+ 0xb1, 0x40, 0x8c, 0x8c, 0xac, 0x05, 0x50, 0xbd, 0x9b, 0x3b, 0x84, 0x81,
+ 0x68, 0x26, 0x88, 0x1b, 0xbf, 0xa0, 0x28, 0xc2, 0x06, 0xa9, 0xe4, 0xd9,
+ 0x1f, 0x5d, 0xca, 0x96, 0x4f, 0xfe, 0xd8, 0x64, 0xee, 0x73, 0x30, 0x82,
+ 0x05, 0x76, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
+ 0x01, 0xa0, 0x82, 0x05, 0x67, 0x04, 0x82, 0x05, 0x63, 0x30, 0x82, 0x05,
+ 0x5f, 0x30, 0x82, 0x05, 0x5b, 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x0c, 0x0a, 0x01, 0x02, 0xa0, 0x82, 0x05, 0x23, 0x30, 0x82,
+ 0x05, 0x1f, 0x30, 0x49, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x05, 0x0d, 0x30, 0x3c, 0x30, 0x1b, 0x06, 0x09, 0x2a, 0x86, 0x48,
+ 0x86, 0xf7, 0x0d, 0x01, 0x05, 0x0c, 0x30, 0x0e, 0x04, 0x08, 0xe3, 0x3e,
+ 0xd3, 0x8d, 0xd6, 0xb5, 0x8a, 0x05, 0x02, 0x02, 0x08, 0x00, 0x30, 0x1d,
+ 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x02, 0x04,
+ 0x10, 0x61, 0xa0, 0x2f, 0x8d, 0x0c, 0xa1, 0x03, 0xc9, 0xdf, 0x2e, 0x81,
+ 0x65, 0xe0, 0x63, 0x70, 0x55, 0x04, 0x82, 0x04, 0xd0, 0x24, 0x1e, 0xf9,
+ 0x1d, 0xc4, 0xe9, 0xbf, 0x49, 0x3c, 0x1e, 0x55, 0x4a, 0xd4, 0xb0, 0x0c,
+ 0xdd, 0x5b, 0x92, 0xb2, 0xed, 0x18, 0xac, 0x66, 0x90, 0x1b, 0x29, 0x3d,
+ 0x10, 0xad, 0x02, 0xe7, 0x17, 0x83, 0x44, 0x67, 0xba, 0x11, 0x6f, 0x05,
+ 0xf5, 0xf7, 0x37, 0xcb, 0x5a, 0xe9, 0x0e, 0xc3, 0x4b, 0x1b, 0x62, 0xee,
+ 0xb2, 0xb7, 0x14, 0x85, 0x07, 0x2d, 0x95, 0x83, 0xa9, 0xdc, 0x3d, 0x4b,
+ 0x33, 0xad, 0x68, 0xbf, 0x54, 0xf8, 0xef, 0x25, 0x05, 0x40, 0xcd, 0x61,
+ 0xbe, 0x12, 0xeb, 0x78, 0x75, 0x36, 0x08, 0x8c, 0x5a, 0x57, 0xa1, 0x98,
+ 0xd5, 0x42, 0x01, 0x1b, 0x4c, 0x25, 0xc2, 0x18, 0x9f, 0x91, 0xfe, 0x78,
+ 0x88, 0x99, 0x47, 0x5a, 0x20, 0x2c, 0x37, 0x31, 0x05, 0x98, 0xef, 0x91,
+ 0x6e, 0xeb, 0x2e, 0x86, 0x90, 0x61, 0xb1, 0x57, 0x1a, 0x05, 0x82, 0x14,
+ 0x0c, 0xa8, 0x94, 0xae, 0x56, 0x7b, 0xd6, 0x2f, 0x8b, 0x2e, 0x91, 0xa6,
+ 0x12, 0x68, 0x1f, 0x06, 0x09, 0x2f, 0xa6, 0xed, 0x33, 0x99, 0x72, 0x56,
+ 0xe5, 0xf7, 0xea, 0xcc, 0xcf, 0x27, 0xa5, 0xad, 0x49, 0x5a, 0xbc, 0x7b,
+ 0xe3, 0x62, 0x63, 0x8f, 0x00, 0x2b, 0x96, 0xc5, 0x3f, 0xaf, 0x24, 0xba,
+ 0xf6, 0x8d, 0xe2, 0xef, 0x18, 0x50, 0xd6, 0xd8, 0x4f, 0xb2, 0x5d, 0xb7,
+ 0x96, 0x6f, 0x02, 0xf7, 0x7d, 0xf2, 0xa2, 0x7b, 0x9b, 0x13, 0x98, 0xde,
+ 0xdd, 0x6e, 0xb5, 0x48, 0x52, 0x8e, 0x44, 0xad, 0xe0, 0xcf, 0x40, 0x9f,
+ 0xfd, 0x88, 0x33, 0x66, 0xce, 0x6a, 0x49, 0x5f, 0xe7, 0x4b, 0x36, 0x93,
+ 0x7f, 0x49, 0x62, 0xc9, 0x5a, 0xae, 0xa1, 0xca, 0xf7, 0x5a, 0xbe, 0x85,
+ 0x77, 0x9a, 0x8f, 0xce, 0x4d, 0x84, 0x81, 0xd0, 0xa2, 0xee, 0x60, 0x92,
+ 0x86, 0x16, 0x2a, 0xd5, 0x08, 0xb6, 0x58, 0x63, 0x07, 0x7c, 0x41, 0xac,
+ 0x97, 0x4f, 0xf0, 0xcf, 0xd8, 0xd2, 0xb1, 0xd7, 0x1d, 0xe5, 0xb8, 0x7c,
+ 0x04, 0x2b, 0xd9, 0xee, 0xf7, 0x22, 0x88, 0xa1, 0x53, 0xdb, 0x5e, 0x5b,
+ 0x47, 0x49, 0xeb, 0xcf, 0x04, 0x78, 0x69, 0xd1, 0xfc, 0x8a, 0xa9, 0x61,
+ 0x92, 0xbf, 0x5c, 0x7f, 0xde, 0x49, 0x42, 0xfc, 0x0d, 0xc2, 0xa2, 0x8f,
+ 0xba, 0xdf, 0x12, 0xa4, 0x62, 0xfb, 0x8d, 0xd3, 0xc5, 0xf9, 0x85, 0x4c,
+ 0x17, 0x70, 0xb7, 0xf7, 0x99, 0x29, 0x52, 0x92, 0x36, 0xc5, 0x4b, 0x31,
+ 0x23, 0x5c, 0x09, 0x27, 0x3c, 0xa0, 0x76, 0x5d, 0x92, 0x99, 0x63, 0x88,
+ 0xca, 0xad, 0xed, 0xd7, 0x85, 0x98, 0x2f, 0xbe, 0xaa, 0xa5, 0xf3, 0x0a,
+ 0x76, 0x13, 0x01, 0x90, 0x8a, 0xe7, 0x5a, 0x2d, 0x2b, 0x1a, 0x80, 0x33,
+ 0x86, 0xab, 0xd8, 0xa7, 0xae, 0x0b, 0x7d, 0xcd, 0x64, 0x8d, 0xa6, 0xb6,
+ 0xfb, 0x83, 0x9f, 0x91, 0x23, 0xcb, 0xda, 0x63, 0xd0, 0xde, 0xf4, 0xdd,
+ 0xaa, 0x23, 0x49, 0x6c, 0x44, 0xfa, 0x6f, 0x12, 0x13, 0x90, 0x37, 0xde,
+ 0xa3, 0x72, 0x45, 0x1a, 0xa7, 0xab, 0x01, 0x6d, 0xd6, 0x34, 0xe7, 0x51,
+ 0x0e, 0x33, 0xbc, 0x09, 0xbf, 0xb6, 0x16, 0xf8, 0xd3, 0x11, 0x11, 0xd1,
+ 0x5f, 0xaa, 0x32, 0xb6, 0x5b, 0xe7, 0xbc, 0xdd, 0xaa, 0xe4, 0xed, 0x42,
+ 0x3d, 0x2e, 0xf7, 0xa1, 0x06, 0x39, 0xd4, 0x00, 0xc6, 0xc8, 0xed, 0xb5,
+ 0x96, 0xc1, 0xbf, 0x4c, 0xf1, 0xf6, 0xc6, 0x59, 0xf4, 0x99, 0x9c, 0x10,
+ 0x22, 0xa1, 0x3a, 0xcd, 0x94, 0xac, 0x0b, 0xc8, 0x7e, 0x29, 0xbc, 0xf0,
+ 0xae, 0x27, 0x7a, 0xb8, 0x5c, 0xa0, 0x13, 0x36, 0xb5, 0x19, 0x4b, 0x2c,
+ 0xc1, 0xce, 0x49, 0x57, 0x1d, 0x36, 0xf0, 0xc2, 0x4c, 0xdf, 0x6d, 0xc9,
+ 0x64, 0x68, 0xcb, 0xea, 0x22, 0x32, 0xd7, 0x11, 0x2c, 0x77, 0xbe, 0x01,
+ 0xa3, 0x82, 0x2d, 0xa1, 0x4b, 0x13, 0x93, 0x87, 0x3d, 0x01, 0x74, 0xc6,
+ 0xc6, 0xf9, 0xae, 0x2e, 0xa1, 0x44, 0x5d, 0x47, 0x6c, 0x6f, 0xc6, 0xce,
+ 0xef, 0x32, 0xf8, 0x8d, 0x53, 0x4d, 0xa5, 0xf0, 0xa0, 0x51, 0x7e, 0xd8,
+ 0x35, 0x55, 0x2a, 0x04, 0xb9, 0x42, 0xa7, 0x51, 0xba, 0xad, 0xce, 0x88,
+ 0x7b, 0x93, 0x25, 0x9d, 0x03, 0x08, 0xfa, 0x75, 0x38, 0x63, 0x78, 0x13,
+ 0x11, 0x9d, 0xf6, 0xcc, 0x18, 0xe3, 0x99, 0xa9, 0x5d, 0x90, 0x6b, 0xbf,
+ 0x9c, 0x69, 0x99, 0x63, 0x27, 0x35, 0x8a, 0x26, 0x07, 0x67, 0xd1, 0xae,
+ 0x57, 0xec, 0xc0, 0x45, 0x6e, 0x2a, 0x42, 0x46, 0x8f, 0xe4, 0x84, 0xc7,
+ 0x67, 0x06, 0x0c, 0xa7, 0x7e, 0x5c, 0x20, 0x80, 0xdc, 0xc1, 0xe4, 0x7a,
+ 0x74, 0x76, 0x8f, 0x41, 0x78, 0xce, 0x6a, 0xf9, 0xcb, 0x7f, 0xe9, 0x17,
+ 0x70, 0x45, 0x01, 0x9a, 0xc3, 0x9c, 0xa2, 0x68, 0xa0, 0x79, 0xfd, 0x44,
+ 0x4c, 0xc8, 0xa0, 0xaf, 0xa5, 0xba, 0x0f, 0x03, 0x30, 0x43, 0x4a, 0x1d,
+ 0x3e, 0xd4, 0x8e, 0x1f, 0x6d, 0x09, 0xf9, 0x63, 0xde, 0xd2, 0x9e, 0x77,
+ 0xe7, 0xde, 0x61, 0x52, 0x76, 0x0f, 0x6d, 0x37, 0xf7, 0xc2, 0x69, 0x96,
+ 0x9d, 0xc5, 0xd9, 0x15, 0x10, 0xf2, 0x22, 0x1f, 0x3b, 0x83, 0xb3, 0xb4,
+ 0x2c, 0x25, 0x36, 0xc3, 0x3a, 0x24, 0x17, 0xed, 0xad, 0x11, 0x1f, 0x46,
+ 0x31, 0x0c, 0x6a, 0x3c, 0xd2, 0x1a, 0xe7, 0x41, 0xb3, 0x75, 0xd8, 0x80,
+ 0xb3, 0xf8, 0x2b, 0xab, 0xb5, 0x81, 0xc6, 0x5e, 0x40, 0x9a, 0x77, 0xaa,
+ 0x79, 0x31, 0x1f, 0x79, 0xfe, 0x0f, 0x0f, 0xb0, 0x36, 0xb7, 0xdc, 0xca,
+ 0xf6, 0xbf, 0x80, 0xeb, 0x78, 0xc6, 0x73, 0x6a, 0xb3, 0x71, 0x69, 0x9c,
+ 0x1d, 0xdd, 0x90, 0xd9, 0x73, 0x07, 0x43, 0x37, 0x19, 0x7f, 0x22, 0xa4,
+ 0x9a, 0x4d, 0x98, 0x66, 0x10, 0x5b, 0x08, 0x62, 0xb3, 0xd8, 0x2f, 0x56,
+ 0x68, 0x22, 0xdf, 0xd1, 0xa2, 0x5a, 0x45, 0xf9, 0xb4, 0xb9, 0xf2, 0x48,
+ 0x4e, 0x38, 0x1a, 0x23, 0x36, 0x6d, 0x42, 0x56, 0xbb, 0x32, 0xe3, 0x00,
+ 0x84, 0xa9, 0xe2, 0xba, 0xb6, 0x86, 0xc9, 0xa6, 0x64, 0x8a, 0xd6, 0xa6,
+ 0xc4, 0xd7, 0x3e, 0x8b, 0x34, 0x1b, 0x6b, 0x65, 0xfe, 0xb1, 0xc9, 0x93,
+ 0xe1, 0xeb, 0x8a, 0x3b, 0xf1, 0x0f, 0xdb, 0x84, 0xe2, 0x2d, 0xf8, 0x69,
+ 0x04, 0xee, 0xaf, 0x58, 0x2f, 0xc7, 0x96, 0x70, 0x4d, 0xd9, 0x4c, 0x1d,
+ 0x52, 0x38, 0xc6, 0x26, 0x27, 0x41, 0x38, 0x0b, 0xa5, 0x1c, 0x16, 0xd0,
+ 0x1d, 0x32, 0x99, 0xb9, 0x1f, 0x35, 0xaf, 0x02, 0xb0, 0x13, 0x0f, 0x95,
+ 0xd3, 0x9b, 0xd6, 0x09, 0xcc, 0x29, 0x46, 0xe8, 0xf1, 0x54, 0x4d, 0xb8,
+ 0x96, 0xa6, 0x0d, 0x59, 0x61, 0x1f, 0xee, 0xaf, 0xbc, 0x23, 0x58, 0xff,
+ 0xcf, 0x96, 0x91, 0x1f, 0x00, 0x80, 0x4e, 0x9a, 0xa2, 0xe0, 0x00, 0xf7,
+ 0x3e, 0xb1, 0x91, 0x6c, 0x29, 0x58, 0x5e, 0xe7, 0xc7, 0x23, 0xfa, 0x88,
+ 0xf7, 0xfb, 0x0b, 0x0e, 0x4a, 0x04, 0x46, 0xe0, 0x67, 0x10, 0x09, 0xea,
+ 0xc0, 0xa9, 0xbe, 0x83, 0x11, 0x33, 0x8e, 0xfb, 0xd6, 0xd5, 0x67, 0xef,
+ 0xb4, 0x13, 0x4d, 0x17, 0xa1, 0x44, 0xb7, 0x98, 0x77, 0xd0, 0x63, 0xe7,
+ 0x9c, 0xa7, 0x96, 0x29, 0xe5, 0xfe, 0x72, 0x4c, 0xa9, 0x85, 0x9b, 0xc9,
+ 0xf3, 0xf6, 0x05, 0x0a, 0x28, 0x68, 0x99, 0x31, 0xe8, 0x64, 0x30, 0x9c,
+ 0x2a, 0x90, 0x48, 0x84, 0x00, 0x1a, 0x66, 0x0e, 0x3e, 0xf7, 0xaa, 0xc9,
+ 0x6c, 0x5b, 0x57, 0x7b, 0xa9, 0x17, 0x91, 0x1e, 0x6b, 0xe8, 0x12, 0xa1,
+ 0xd4, 0xde, 0x1e, 0x38, 0x14, 0x7b, 0xe0, 0x9a, 0x15, 0xae, 0x5a, 0x26,
+ 0x93, 0x7a, 0xd6, 0x8d, 0x26, 0x61, 0x28, 0xf2, 0x40, 0x71, 0xc7, 0x8a,
+ 0x2d, 0x69, 0x72, 0x04, 0x5b, 0xb9, 0xc1, 0x7b, 0x17, 0xde, 0x2c, 0xfc,
+ 0xa9, 0xf2, 0xf8, 0x34, 0x33, 0x09, 0x87, 0x91, 0xdf, 0xeb, 0xf7, 0x57,
+ 0x5b, 0x32, 0xe2, 0xd4, 0xe4, 0x47, 0x78, 0xe8, 0x9b, 0x1a, 0xab, 0x44,
+ 0x55, 0x28, 0x98, 0x20, 0xa7, 0x16, 0x8b, 0x4e, 0x42, 0xf1, 0x91, 0xbe,
+ 0x00, 0x87, 0x3a, 0x91, 0x63, 0x9a, 0xc2, 0x8d, 0x13, 0x34, 0x8b, 0x33,
+ 0x02, 0x88, 0x1e, 0xb1, 0xa8, 0x07, 0x6d, 0xb1, 0xf5, 0xb3, 0x7a, 0x3d,
+ 0x17, 0x3f, 0xbd, 0xa1, 0xdb, 0x04, 0x0f, 0x29, 0x7b, 0x0e, 0x98, 0x18,
+ 0x63, 0x0b, 0x60, 0xcd, 0xa5, 0x0d, 0x5f, 0x1e, 0x53, 0xcd, 0xfa, 0xc0,
+ 0xc7, 0x99, 0x53, 0x5f, 0xb7, 0xe5, 0x4a, 0x30, 0xde, 0x14, 0xc9, 0x49,
+ 0x46, 0x31, 0xb6, 0x92, 0xf3, 0x4b, 0xc1, 0xb0, 0xdd, 0xec, 0x48, 0xff,
+ 0x2d, 0x52, 0x53, 0x64, 0x27, 0x4c, 0x78, 0x96, 0x80, 0x90, 0xa3, 0xd7,
+ 0xfd, 0x7a, 0x23, 0x36, 0xa0, 0x76, 0x9e, 0x96, 0xfc, 0xcd, 0xec, 0x58,
+ 0xf8, 0x76, 0x4b, 0x2f, 0x8d, 0xb9, 0xd6, 0x89, 0xa1, 0x57, 0xe1, 0xc6,
+ 0xed, 0x9a, 0x1e, 0xde, 0xc7, 0x68, 0x93, 0x2b, 0x2e, 0x84, 0x1a, 0xf9,
+ 0x8c, 0x58, 0xb8, 0xf0, 0x29, 0xfe, 0x7b, 0x03, 0x84, 0xe8, 0x52, 0x1c,
+ 0x01, 0xbb, 0xcc, 0x5d, 0x88, 0xcd, 0x37, 0x8b, 0xe2, 0x2d, 0x30, 0xd1,
+ 0xbe, 0xf7, 0xc1, 0x95, 0xb7, 0x01, 0x43, 0xab, 0x30, 0x3f, 0x96, 0x47,
+ 0x6d, 0x52, 0x29, 0x87, 0x10, 0x31, 0x25, 0x30, 0x23, 0x06, 0x09, 0x2a,
+ 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x15, 0x31, 0x16, 0x04, 0x14,
+ 0x14, 0x74, 0x2d, 0x52, 0x8e, 0x0d, 0x0c, 0x06, 0x6c, 0x32, 0x64, 0xd3,
+ 0x7e, 0x33, 0x31, 0x68, 0x8b, 0x28, 0x1a, 0x75, 0x30, 0x31, 0x30, 0x21,
+ 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04,
+ 0x14, 0x2f, 0x5c, 0xc6, 0xaf, 0xa7, 0xcc, 0xb5, 0x77, 0x40, 0xca, 0x71,
+ 0xc3, 0x8c, 0xc6, 0x69, 0xdc, 0xc6, 0x7f, 0x54, 0xef, 0x04, 0x08, 0xf8,
+ 0x9c, 0x8b, 0x12, 0x27, 0xe8, 0xec, 0x65, 0x02, 0x02, 0x08, 0x00};
+
static const char kPassword[] = "foo";
static bool Test(const char *name, const uint8_t *der, size_t der_len) {
@@ -759,6 +978,7 @@ int main(int argc, char **argv) {
if (!Test("OpenSSL", kOpenSSL, sizeof(kOpenSSL)) ||
!Test("NSS", kNSS, sizeof(kNSS)) ||
!Test("Windows", kWindows, sizeof(kWindows)) ||
+ !Test("PBES2", kPBES2, sizeof(kPBES2)) ||
!TestCompat(kWindows, sizeof(kWindows))) {
return 1;
}
diff --git a/src/crypto/pkcs8/pkcs8.c b/src/crypto/pkcs8/pkcs8.c
index 64a2d021..08cc5a35 100644
--- a/src/crypto/pkcs8/pkcs8.c
+++ b/src/crypto/pkcs8/pkcs8.c
@@ -59,27 +59,18 @@
#include <limits.h>
#include <string.h>
-#include <openssl/asn1.h>
-#include <openssl/buf.h>
#include <openssl/bytestring.h>
#include <openssl/cipher.h>
#include <openssl/digest.h>
#include <openssl/err.h>
-#include <openssl/hmac.h>
#include <openssl/mem.h>
-#include <openssl/obj.h>
+#include <openssl/nid.h>
#include <openssl/rand.h>
-#include <openssl/x509.h>
#include "internal.h"
#include "../internal.h"
-#include "../bytestring/internal.h"
-#define PKCS12_KEY_ID 1
-#define PKCS12_IV_ID 2
-#define PKCS12_MAC_ID 3
-
static int ascii_to_ucs2(const char *ascii, size_t ascii_len,
uint8_t **out, size_t *out_len) {
size_t ulen = ascii_len * 2 + 2;
@@ -89,6 +80,7 @@ static int ascii_to_ucs2(const char *ascii, size_t ascii_len,
uint8_t *unitmp = OPENSSL_malloc(ulen);
if (unitmp == NULL) {
+ OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE);
return 0;
}
for (size_t i = 0; i < ulen - 2; i += 2) {
@@ -104,11 +96,9 @@ static int ascii_to_ucs2(const char *ascii, size_t ascii_len,
return 1;
}
-static int pkcs12_key_gen_raw(const uint8_t *pass_raw, size_t pass_raw_len,
- const uint8_t *salt, size_t salt_len,
- uint8_t id, unsigned iterations,
- size_t out_len, uint8_t *out,
- const EVP_MD *md) {
+int pkcs12_key_gen(const char *pass, size_t pass_len, const uint8_t *salt,
+ size_t salt_len, uint8_t id, unsigned iterations,
+ size_t out_len, uint8_t *out, const EVP_MD *md) {
/* See https://tools.ietf.org/html/rfc7292#appendix-B. Quoted parts of the
* specification have errata applied and other typos fixed. */
@@ -117,6 +107,18 @@ static int pkcs12_key_gen_raw(const uint8_t *pass_raw, size_t pass_raw_len,
return 0;
}
+ int ret = 0;
+ EVP_MD_CTX ctx;
+ EVP_MD_CTX_init(&ctx);
+ uint8_t *pass_raw = NULL, *I = NULL;
+ size_t pass_raw_len = 0, I_len = 0;
+ /* If |pass| is NULL, we use the empty string rather than {0, 0} as the raw
+ * password. */
+ if (pass != NULL &&
+ !ascii_to_ucs2(pass, pass_len, &pass_raw, &pass_raw_len)) {
+ goto err;
+ }
+
/* In the spec, |block_size| is called "v", but measured in bits. */
size_t block_size = EVP_MD_block_size(md);
@@ -138,20 +140,20 @@ static int pkcs12_key_gen_raw(const uint8_t *pass_raw, size_t pass_raw_len,
if (salt_len + block_size - 1 < salt_len ||
pass_raw_len + block_size - 1 < pass_raw_len) {
OPENSSL_PUT_ERROR(PKCS8, ERR_R_OVERFLOW);
- return 0;
+ goto err;
}
size_t S_len = block_size * ((salt_len + block_size - 1) / block_size);
size_t P_len = block_size * ((pass_raw_len + block_size - 1) / block_size);
- size_t I_len = S_len + P_len;
+ I_len = S_len + P_len;
if (I_len < S_len) {
OPENSSL_PUT_ERROR(PKCS8, ERR_R_OVERFLOW);
- return 0;
+ goto err;
}
- uint8_t *I = OPENSSL_malloc(I_len);
+ I = OPENSSL_malloc(I_len);
if (I_len != 0 && I == NULL) {
OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE);
- return 0;
+ goto err;
}
for (size_t i = 0; i < S_len; i++) {
@@ -161,10 +163,6 @@ static int pkcs12_key_gen_raw(const uint8_t *pass_raw, size_t pass_raw_len,
I[i + S_len] = pass_raw[i % pass_raw_len];
}
- int ret = 0;
- EVP_MD_CTX ctx;
- EVP_MD_CTX_init(&ctx);
-
while (out_len != 0) {
/* A. Set A_i=H^r(D||I). (i.e., the r-th hash of D||I,
* H(H(H(... H(D||I)))) */
@@ -216,32 +214,32 @@ static int pkcs12_key_gen_raw(const uint8_t *pass_raw, size_t pass_raw_len,
ret = 1;
err:
- OPENSSL_cleanse(I, I_len);
- OPENSSL_free(I);
+ if (I != NULL) {
+ OPENSSL_cleanse(I, I_len);
+ OPENSSL_free(I);
+ }
+ if (pass_raw != NULL) {
+ OPENSSL_cleanse(pass_raw, pass_raw_len);
+ OPENSSL_free(pass_raw);
+ }
EVP_MD_CTX_cleanup(&ctx);
return ret;
}
static int pkcs12_pbe_cipher_init(const struct pbe_suite *suite,
EVP_CIPHER_CTX *ctx, unsigned iterations,
- const uint8_t *pass_raw, size_t pass_raw_len,
+ const char *pass, size_t pass_len,
const uint8_t *salt, size_t salt_len,
int is_encrypt) {
const EVP_CIPHER *cipher = suite->cipher_func();
const EVP_MD *md = suite->md_func();
uint8_t key[EVP_MAX_KEY_LENGTH];
- if (!pkcs12_key_gen_raw(pass_raw, pass_raw_len, salt,
- salt_len, PKCS12_KEY_ID, iterations,
- EVP_CIPHER_key_length(cipher), key, md)) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_KEY_GEN_ERROR);
- return 0;
- }
-
uint8_t iv[EVP_MAX_IV_LENGTH];
- if (!pkcs12_key_gen_raw(pass_raw, pass_raw_len, salt,
- salt_len, PKCS12_IV_ID, iterations,
- EVP_CIPHER_iv_length(cipher), iv, md)) {
+ if (!pkcs12_key_gen(pass, pass_len, salt, salt_len, PKCS12_KEY_ID, iterations,
+ EVP_CIPHER_key_length(cipher), key, md) ||
+ !pkcs12_key_gen(pass, pass_len, salt, salt_len, PKCS12_IV_ID, iterations,
+ EVP_CIPHER_iv_length(cipher), iv, md)) {
OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_KEY_GEN_ERROR);
return 0;
}
@@ -253,8 +251,8 @@ static int pkcs12_pbe_cipher_init(const struct pbe_suite *suite,
}
static int pkcs12_pbe_decrypt_init(const struct pbe_suite *suite,
- EVP_CIPHER_CTX *ctx, const uint8_t *pass_raw,
- size_t pass_raw_len, CBS *param) {
+ EVP_CIPHER_CTX *ctx, const char *pass,
+ size_t pass_len, CBS *param) {
CBS pbe_param, salt;
uint64_t iterations;
if (!CBS_get_asn1(param, &pbe_param, CBS_ASN1_SEQUENCE) ||
@@ -271,32 +269,52 @@ static int pkcs12_pbe_decrypt_init(const struct pbe_suite *suite,
return 0;
}
- return pkcs12_pbe_cipher_init(suite, ctx, (unsigned)iterations, pass_raw,
- pass_raw_len, CBS_data(&salt), CBS_len(&salt),
+ return pkcs12_pbe_cipher_init(suite, ctx, (unsigned)iterations, pass,
+ pass_len, CBS_data(&salt), CBS_len(&salt),
0 /* decrypt */);
}
static const struct pbe_suite kBuiltinPBE[] = {
{
- NID_pbe_WithSHA1And40BitRC2_CBC, EVP_rc2_40_cbc, EVP_sha1,
- pkcs12_pbe_decrypt_init, PBE_UCS2_CONVERT_PASSWORD,
+ NID_pbe_WithSHA1And40BitRC2_CBC,
+ /* 1.2.840.113549.1.12.1.6 */
+ {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x01, 0x06},
+ 10,
+ EVP_rc2_40_cbc,
+ EVP_sha1,
+ pkcs12_pbe_decrypt_init,
},
{
- NID_pbe_WithSHA1And128BitRC4, EVP_rc4, EVP_sha1,
- pkcs12_pbe_decrypt_init, PBE_UCS2_CONVERT_PASSWORD,
+ NID_pbe_WithSHA1And128BitRC4,
+ /* 1.2.840.113549.1.12.1.1 */
+ {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x01, 0x01},
+ 10,
+ EVP_rc4,
+ EVP_sha1,
+ pkcs12_pbe_decrypt_init,
},
{
- NID_pbe_WithSHA1And3_Key_TripleDES_CBC, EVP_des_ede3_cbc, EVP_sha1,
- pkcs12_pbe_decrypt_init, PBE_UCS2_CONVERT_PASSWORD,
+ NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
+ /* 1.2.840.113549.1.12.1.3 */
+ {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x01, 0x03},
+ 10,
+ EVP_des_ede3_cbc,
+ EVP_sha1,
+ pkcs12_pbe_decrypt_init,
},
{
- NID_pbes2, NULL, NULL, PKCS5_pbe2_decrypt_init, 0,
+ NID_pbes2,
+ /* 1.2.840.113549.1.5.13 */
+ {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x05, 0x0d},
+ 9,
+ NULL,
+ NULL,
+ PKCS5_pbe2_decrypt_init,
},
};
static const struct pbe_suite *get_pbe_suite(int pbe_nid) {
- unsigned i;
- for (i = 0; i < OPENSSL_ARRAY_SIZE(kBuiltinPBE); i++) {
+ for (unsigned i = 0; i < OPENSSL_ARRAY_SIZE(kBuiltinPBE); i++) {
if (kBuiltinPBE[i].pbe_nid == pbe_nid) {
return &kBuiltinPBE[i];
}
@@ -305,51 +323,9 @@ static const struct pbe_suite *get_pbe_suite(int pbe_nid) {
return NULL;
}
-/* pass_to_pass_raw performs a password conversion (possibly a no-op)
- * appropriate to the supplied |pbe_nid|. The input |pass| is treated as a
- * NUL-terminated string if |pass_len| is -1, otherwise it is treated as a
- * buffer of the specified length. If the supplied PBE NID sets the
- * |PBE_UCS2_CONVERT_PASSWORD| flag, the supplied |pass| will be converted to
- * UCS-2.
- *
- * It sets |*out_pass_raw| to a new buffer that must be freed by the caller. It
- * returns one on success and zero on error. */
-static int pass_to_pass_raw(int pbe_nid, const char *pass, int pass_len,
- uint8_t **out_pass_raw, size_t *out_pass_raw_len) {
- if (pass == NULL) {
- *out_pass_raw = NULL;
- *out_pass_raw_len = 0;
- return 1;
- }
-
- if (pass_len == -1) {
- pass_len = strlen(pass);
- } else if (pass_len < 0 || pass_len > 2000000000) {
- OPENSSL_PUT_ERROR(PKCS8, ERR_R_OVERFLOW);
- return 0;
- }
-
- const struct pbe_suite *suite = get_pbe_suite(pbe_nid);
- if (suite != NULL && (suite->flags & PBE_UCS2_CONVERT_PASSWORD)) {
- if (!ascii_to_ucs2(pass, pass_len, out_pass_raw, out_pass_raw_len)) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR);
- return 0;
- }
- } else {
- *out_pass_raw = BUF_memdup(pass, pass_len);
- if (*out_pass_raw == NULL) {
- OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE);
- return 0;
- }
- *out_pass_raw_len = (size_t)pass_len;
- }
-
- return 1;
-}
-
static int pkcs12_pbe_encrypt_init(CBB *out, EVP_CIPHER_CTX *ctx, int alg,
- unsigned iterations, const uint8_t *pass_raw,
- size_t pass_raw_len, const uint8_t *salt,
+ unsigned iterations, const char *pass,
+ size_t pass_len, const uint8_t *salt,
size_t salt_len) {
const struct pbe_suite *suite = get_pbe_suite(alg);
if (suite == NULL) {
@@ -358,9 +334,10 @@ static int pkcs12_pbe_encrypt_init(CBB *out, EVP_CIPHER_CTX *ctx, int alg,
}
/* See RFC 2898, appendix A.3. */
- CBB algorithm, param, salt_cbb;
+ CBB algorithm, oid, param, salt_cbb;
if (!CBB_add_asn1(out, &algorithm, CBS_ASN1_SEQUENCE) ||
- !OBJ_nid2cbb(&algorithm, alg) ||
+ !CBB_add_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) ||
+ !CBB_add_bytes(&oid, suite->oid, suite->oid_len) ||
!CBB_add_asn1(&algorithm, &param, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1(&param, &salt_cbb, CBS_ASN1_OCTETSTRING) ||
!CBB_add_bytes(&salt_cbb, salt, salt_len) ||
@@ -369,13 +346,13 @@ static int pkcs12_pbe_encrypt_init(CBB *out, EVP_CIPHER_CTX *ctx, int alg,
return 0;
}
- return pkcs12_pbe_cipher_init(suite, ctx, iterations, pass_raw, pass_raw_len,
- salt, salt_len, 1 /* encrypt */);
+ return pkcs12_pbe_cipher_init(suite, ctx, iterations, pass, pass_len, salt,
+ salt_len, 1 /* encrypt */);
}
-static int pbe_decrypt(uint8_t **out, size_t *out_len, CBS *algorithm,
- const uint8_t *pass_raw, size_t pass_raw_len,
- const uint8_t *in, size_t in_len) {
+int pkcs8_pbe_decrypt(uint8_t **out, size_t *out_len, CBS *algorithm,
+ const char *pass, size_t pass_len, const uint8_t *in,
+ size_t in_len) {
int ret = 0;
uint8_t *buf = NULL;;
EVP_CIPHER_CTX ctx;
@@ -387,13 +364,19 @@ static int pbe_decrypt(uint8_t **out, size_t *out_len, CBS *algorithm,
goto err;
}
- const struct pbe_suite *suite = get_pbe_suite(OBJ_cbs2nid(&obj));
+ const struct pbe_suite *suite = NULL;
+ for (unsigned i = 0; i < OPENSSL_ARRAY_SIZE(kBuiltinPBE); i++) {
+ if (CBS_mem_equal(&obj, kBuiltinPBE[i].oid, kBuiltinPBE[i].oid_len)) {
+ suite = &kBuiltinPBE[i];
+ break;
+ }
+ }
if (suite == NULL) {
OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNKNOWN_ALGORITHM);
goto err;
}
- if (!suite->decrypt_init(suite, &ctx, pass_raw, pass_raw_len, algorithm)) {
+ if (!suite->decrypt_init(suite, &ctx, pass, pass_len, algorithm)) {
OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_KEYGEN_FAILURE);
goto err;
}
@@ -426,86 +409,41 @@ err:
return ret;
}
-static PKCS8_PRIV_KEY_INFO *pkcs8_decrypt_raw(X509_SIG *pkcs8,
- const uint8_t *pass_raw,
- size_t pass_raw_len) {
- PKCS8_PRIV_KEY_INFO *ret = NULL;
- uint8_t *in = NULL, *out = NULL;
- size_t out_len = 0;
-
- /* Convert the legacy ASN.1 object to a byte string. */
- int in_len = i2d_X509_SIG(pkcs8, &in);
- if (in_len < 0) {
- goto err;
- }
-
+EVP_PKEY *PKCS8_parse_encrypted_private_key(CBS *cbs, const char *pass,
+ size_t pass_len) {
/* See RFC 5208, section 6. */
- CBS cbs, epki, algorithm, ciphertext;
- CBS_init(&cbs, in, in_len);
- if (!CBS_get_asn1(&cbs, &epki, CBS_ASN1_SEQUENCE) ||
+ CBS epki, algorithm, ciphertext;
+ if (!CBS_get_asn1(cbs, &epki, CBS_ASN1_SEQUENCE) ||
!CBS_get_asn1(&epki, &algorithm, CBS_ASN1_SEQUENCE) ||
!CBS_get_asn1(&epki, &ciphertext, CBS_ASN1_OCTETSTRING) ||
- CBS_len(&epki) != 0 ||
- CBS_len(&cbs) != 0) {
+ CBS_len(&epki) != 0) {
OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR);
- goto err;
- }
-
- if (!pbe_decrypt(&out, &out_len, &algorithm, pass_raw, pass_raw_len,
- CBS_data(&ciphertext), CBS_len(&ciphertext))) {
- goto err;
- }
-
- if (out_len > LONG_MAX) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR);
- goto err;
+ return 0;
}
- /* Convert back to legacy ASN.1 objects. */
- const uint8_t *ptr = out;
- ret = d2i_PKCS8_PRIV_KEY_INFO(NULL, &ptr, (long)out_len);
- OPENSSL_cleanse(out, out_len);
- if (ret == NULL || ptr != out + out_len) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR);
- PKCS8_PRIV_KEY_INFO_free(ret);
- ret = NULL;
+ uint8_t *out;
+ size_t out_len;
+ if (!pkcs8_pbe_decrypt(&out, &out_len, &algorithm, pass, pass_len,
+ CBS_data(&ciphertext), CBS_len(&ciphertext))) {
+ return 0;
}
-err:
- OPENSSL_free(in);
+ CBS pki;
+ CBS_init(&pki, out, out_len);
+ EVP_PKEY *ret = EVP_parse_private_key(&pki);
OPENSSL_cleanse(out, out_len);
OPENSSL_free(out);
return ret;
}
-PKCS8_PRIV_KEY_INFO *PKCS8_decrypt(X509_SIG *pkcs8, const char *pass,
- int pass_len) {
- uint8_t *pass_raw = NULL;
- size_t pass_raw_len = 0;
- if (!pass_to_pass_raw(OBJ_obj2nid(pkcs8->algor->algorithm), pass, pass_len,
- &pass_raw, &pass_raw_len)) {
- return NULL;
- }
-
- PKCS8_PRIV_KEY_INFO *ret = pkcs8_decrypt_raw(pkcs8, pass_raw, pass_raw_len);
-
- if (pass_raw) {
- OPENSSL_cleanse(pass_raw, pass_raw_len);
- OPENSSL_free(pass_raw);
- }
- return ret;
-}
-
-static X509_SIG *pkcs8_encrypt_raw(int pbe_nid, const EVP_CIPHER *cipher,
- const uint8_t *pass_raw, size_t pass_raw_len,
- const uint8_t *salt, size_t salt_len,
- int iterations, PKCS8_PRIV_KEY_INFO *p8inf) {
- X509_SIG *ret = NULL;
- uint8_t *plaintext = NULL, *salt_buf = NULL, *der = NULL;
- int plaintext_len = -1;
- size_t der_len;
- CBB cbb;
- CBB_zero(&cbb);
+int PKCS8_marshal_encrypted_private_key(CBB *out, int pbe_nid,
+ const EVP_CIPHER *cipher,
+ const char *pass, size_t pass_len,
+ const uint8_t *salt, size_t salt_len,
+ int iterations, const EVP_PKEY *pkey) {
+ int ret = 0;
+ uint8_t *plaintext = NULL, *salt_buf = NULL;
+ size_t plaintext_len = 0;
EVP_CIPHER_CTX ctx;
EVP_CIPHER_CTX_init(&ctx);
@@ -528,699 +466,58 @@ static X509_SIG *pkcs8_encrypt_raw(int pbe_nid, const EVP_CIPHER *cipher,
iterations = PKCS5_DEFAULT_ITERATIONS;
}
- /* Convert the input from the legacy ASN.1 format. */
- plaintext_len = i2d_PKCS8_PRIV_KEY_INFO(p8inf, &plaintext);
- if (plaintext_len < 0) {
+ /* Serialize the input key. */
+ CBB plaintext_cbb;
+ if (!CBB_init(&plaintext_cbb, 128) ||
+ !EVP_marshal_private_key(&plaintext_cbb, pkey) ||
+ !CBB_finish(&plaintext_cbb, &plaintext, &plaintext_len)) {
+ CBB_cleanup(&plaintext_cbb);
goto err;
}
CBB epki;
- if (!CBB_init(&cbb, 128) ||
- !CBB_add_asn1(&cbb, &epki, CBS_ASN1_SEQUENCE)) {
+ if (!CBB_add_asn1(out, &epki, CBS_ASN1_SEQUENCE)) {
goto err;
}
int alg_ok;
if (pbe_nid == -1) {
alg_ok = PKCS5_pbe2_encrypt_init(&epki, &ctx, cipher, (unsigned)iterations,
- pass_raw, pass_raw_len, salt, salt_len);
+ pass, pass_len, salt, salt_len);
} else {
alg_ok = pkcs12_pbe_encrypt_init(&epki, &ctx, pbe_nid, (unsigned)iterations,
- pass_raw, pass_raw_len, salt, salt_len);
+ pass, pass_len, salt, salt_len);
}
if (!alg_ok) {
goto err;
}
- size_t max_out = (size_t)plaintext_len + EVP_CIPHER_CTX_block_size(&ctx);
- if (max_out < (size_t)plaintext_len) {
+ size_t max_out = plaintext_len + EVP_CIPHER_CTX_block_size(&ctx);
+ if (max_out < plaintext_len) {
OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_TOO_LONG);
goto err;
}
CBB ciphertext;
- uint8_t *out;
+ uint8_t *ptr;
int n1, n2;
if (!CBB_add_asn1(&epki, &ciphertext, CBS_ASN1_OCTETSTRING) ||
- !CBB_reserve(&ciphertext, &out, max_out) ||
- !EVP_CipherUpdate(&ctx, out, &n1, plaintext, plaintext_len) ||
- !EVP_CipherFinal_ex(&ctx, out + n1, &n2) ||
+ !CBB_reserve(&ciphertext, &ptr, max_out) ||
+ !EVP_CipherUpdate(&ctx, ptr, &n1, plaintext, plaintext_len) ||
+ !EVP_CipherFinal_ex(&ctx, ptr + n1, &n2) ||
!CBB_did_write(&ciphertext, n1 + n2) ||
- !CBB_finish(&cbb, &der, &der_len)) {
+ !CBB_flush(out)) {
goto err;
}
- /* Convert back to legacy ASN.1 objects. */
- const uint8_t *ptr = der;
- ret = d2i_X509_SIG(NULL, &ptr, der_len);
- if (ret == NULL || ptr != der + der_len) {
- OPENSSL_PUT_ERROR(PKCS8, ERR_R_INTERNAL_ERROR);
- X509_SIG_free(ret);
- ret = NULL;
- }
+ ret = 1;
err:
- if (plaintext_len > 0) {
+ if (plaintext != NULL) {
OPENSSL_cleanse(plaintext, plaintext_len);
+ OPENSSL_free(plaintext);
}
- OPENSSL_free(plaintext);
OPENSSL_free(salt_buf);
- OPENSSL_free(der);
- CBB_cleanup(&cbb);
EVP_CIPHER_CTX_cleanup(&ctx);
return ret;
}
-
-X509_SIG *PKCS8_encrypt(int pbe_nid, const EVP_CIPHER *cipher, const char *pass,
- int pass_len, const uint8_t *salt, size_t salt_len,
- int iterations, PKCS8_PRIV_KEY_INFO *p8inf) {
- uint8_t *pass_raw = NULL;
- size_t pass_raw_len = 0;
- if (!pass_to_pass_raw(pbe_nid, pass, pass_len, &pass_raw, &pass_raw_len)) {
- return NULL;
- }
-
- X509_SIG *ret = pkcs8_encrypt_raw(pbe_nid, cipher, pass_raw, pass_raw_len,
- salt, salt_len, iterations, p8inf);
-
- if (pass_raw) {
- OPENSSL_cleanse(pass_raw, pass_raw_len);
- OPENSSL_free(pass_raw);
- }
- return ret;
-}
-
-EVP_PKEY *EVP_PKCS82PKEY(PKCS8_PRIV_KEY_INFO *p8) {
- uint8_t *der = NULL;
- int der_len = i2d_PKCS8_PRIV_KEY_INFO(p8, &der);
- if (der_len < 0) {
- return NULL;
- }
-
- CBS cbs;
- CBS_init(&cbs, der, (size_t)der_len);
- EVP_PKEY *ret = EVP_parse_private_key(&cbs);
- if (ret == NULL || CBS_len(&cbs) != 0) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR);
- EVP_PKEY_free(ret);
- OPENSSL_free(der);
- return NULL;
- }
-
- OPENSSL_free(der);
- return ret;
-}
-
-PKCS8_PRIV_KEY_INFO *EVP_PKEY2PKCS8(EVP_PKEY *pkey) {
- CBB cbb;
- uint8_t *der = NULL;
- size_t der_len;
- if (!CBB_init(&cbb, 0) ||
- !EVP_marshal_private_key(&cbb, pkey) ||
- !CBB_finish(&cbb, &der, &der_len) ||
- der_len > LONG_MAX) {
- CBB_cleanup(&cbb);
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_ENCODE_ERROR);
- goto err;
- }
-
- const uint8_t *p = der;
- PKCS8_PRIV_KEY_INFO *p8 = d2i_PKCS8_PRIV_KEY_INFO(NULL, &p, (long)der_len);
- if (p8 == NULL || p != der + der_len) {
- PKCS8_PRIV_KEY_INFO_free(p8);
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR);
- goto err;
- }
-
- OPENSSL_free(der);
- return p8;
-
-err:
- OPENSSL_free(der);
- return NULL;
-}
-
-struct pkcs12_context {
- EVP_PKEY **out_key;
- STACK_OF(X509) *out_certs;
- uint8_t *password;
- size_t password_len;
-};
-
-/* PKCS12_handle_sequence parses a BER-encoded SEQUENCE of elements in a PKCS#12
- * structure. */
-static int PKCS12_handle_sequence(
- CBS *sequence, struct pkcs12_context *ctx,
- int (*handle_element)(CBS *cbs, struct pkcs12_context *ctx)) {
- uint8_t *der_bytes = NULL;
- size_t der_len;
- CBS in;
- int ret = 0;
-
- /* Although a BER->DER conversion is done at the beginning of |PKCS12_parse|,
- * the ASN.1 data gets wrapped in OCTETSTRINGs and/or encrypted and the
- * conversion cannot see through those wrappings. So each time we step
- * through one we need to convert to DER again. */
- if (!CBS_asn1_ber_to_der(sequence, &der_bytes, &der_len)) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
- return 0;
- }
-
- if (der_bytes != NULL) {
- CBS_init(&in, der_bytes, der_len);
- } else {
- CBS_init(&in, CBS_data(sequence), CBS_len(sequence));
- }
-
- CBS child;
- if (!CBS_get_asn1(&in, &child, CBS_ASN1_SEQUENCE) ||
- CBS_len(&in) != 0) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
- goto err;
- }
-
- while (CBS_len(&child) > 0) {
- CBS element;
- if (!CBS_get_asn1(&child, &element, CBS_ASN1_SEQUENCE)) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
- goto err;
- }
-
- if (!handle_element(&element, ctx)) {
- goto err;
- }
- }
-
- ret = 1;
-
-err:
- OPENSSL_free(der_bytes);
- return ret;
-}
-
-/* PKCS12_handle_safe_bag parses a single SafeBag element in a PKCS#12
- * structure. */
-static int PKCS12_handle_safe_bag(CBS *safe_bag, struct pkcs12_context *ctx) {
- CBS bag_id, wrapped_value;
- if (!CBS_get_asn1(safe_bag, &bag_id, CBS_ASN1_OBJECT) ||
- !CBS_get_asn1(safe_bag, &wrapped_value,
- CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)
- /* Ignore the bagAttributes field. */) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
- return 0;
- }
-
- int nid = OBJ_cbs2nid(&bag_id);
- if (nid == NID_pkcs8ShroudedKeyBag) {
- /* See RFC 7292, section 4.2.2. */
- if (*ctx->out_key) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_MULTIPLE_PRIVATE_KEYS_IN_PKCS12);
- return 0;
- }
-
- if (CBS_len(&wrapped_value) > LONG_MAX) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
- return 0;
- }
-
- /* |encrypted| isn't actually an X.509 signature, but it has the same
- * structure as one and so |X509_SIG| is reused to store it. */
- const uint8_t *inp = CBS_data(&wrapped_value);
- X509_SIG *encrypted =
- d2i_X509_SIG(NULL, &inp, (long)CBS_len(&wrapped_value));
- if (encrypted == NULL) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
- return 0;
- }
- if (inp != CBS_data(&wrapped_value) + CBS_len(&wrapped_value)) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
- X509_SIG_free(encrypted);
- return 0;
- }
-
- PKCS8_PRIV_KEY_INFO *pki =
- pkcs8_decrypt_raw(encrypted, ctx->password, ctx->password_len);
- X509_SIG_free(encrypted);
- if (pki == NULL) {
- return 0;
- }
-
- *ctx->out_key = EVP_PKCS82PKEY(pki);
- PKCS8_PRIV_KEY_INFO_free(pki);
- return ctx->out_key != NULL;
- }
-
- if (nid == NID_certBag) {
- /* See RFC 7292, section 4.2.3. */
- CBS cert_bag, cert_type, wrapped_cert, cert;
- if (!CBS_get_asn1(&wrapped_value, &cert_bag, CBS_ASN1_SEQUENCE) ||
- !CBS_get_asn1(&cert_bag, &cert_type, CBS_ASN1_OBJECT) ||
- !CBS_get_asn1(&cert_bag, &wrapped_cert,
- CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) ||
- !CBS_get_asn1(&wrapped_cert, &cert, CBS_ASN1_OCTETSTRING)) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
- return 0;
- }
-
- if (OBJ_cbs2nid(&cert_type) != NID_x509Certificate) {
- return 1;
- }
-
- if (CBS_len(&cert) > LONG_MAX) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
- return 0;
- }
-
- const uint8_t *inp = CBS_data(&cert);
- X509 *x509 = d2i_X509(NULL, &inp, (long)CBS_len(&cert));
- if (!x509) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
- return 0;
- }
-
- if (inp != CBS_data(&cert) + CBS_len(&cert)) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
- X509_free(x509);
- return 0;
- }
-
- if (0 == sk_X509_push(ctx->out_certs, x509)) {
- X509_free(x509);
- return 0;
- }
-
- return 1;
- }
-
- /* Unknown element type - ignore it. */
- return 1;
-}
-
-/* PKCS12_handle_content_info parses a single PKCS#7 ContentInfo element in a
- * PKCS#12 structure. */
-static int PKCS12_handle_content_info(CBS *content_info,
- struct pkcs12_context *ctx) {
- CBS content_type, wrapped_contents, contents;
- int nid, ret = 0;
- uint8_t *storage = NULL;
-
- if (!CBS_get_asn1(content_info, &content_type, CBS_ASN1_OBJECT) ||
- !CBS_get_asn1(content_info, &wrapped_contents,
- CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) ||
- CBS_len(content_info) != 0) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
- goto err;
- }
-
- nid = OBJ_cbs2nid(&content_type);
- if (nid == NID_pkcs7_encrypted) {
- /* See https://tools.ietf.org/html/rfc2315#section-13.
- *
- * PKCS#7 encrypted data inside a PKCS#12 structure is generally an
- * encrypted certificate bag and it's generally encrypted with 40-bit
- * RC2-CBC. */
- CBS version_bytes, eci, contents_type, ai, encrypted_contents;
- uint8_t *out;
- size_t out_len;
-
- if (!CBS_get_asn1(&wrapped_contents, &contents, CBS_ASN1_SEQUENCE) ||
- !CBS_get_asn1(&contents, &version_bytes, CBS_ASN1_INTEGER) ||
- /* EncryptedContentInfo, see
- * https://tools.ietf.org/html/rfc2315#section-10.1 */
- !CBS_get_asn1(&contents, &eci, CBS_ASN1_SEQUENCE) ||
- !CBS_get_asn1(&eci, &contents_type, CBS_ASN1_OBJECT) ||
- /* AlgorithmIdentifier, see
- * https://tools.ietf.org/html/rfc5280#section-4.1.1.2 */
- !CBS_get_asn1(&eci, &ai, CBS_ASN1_SEQUENCE) ||
- !CBS_get_asn1_implicit_string(
- &eci, &encrypted_contents, &storage,
- CBS_ASN1_CONTEXT_SPECIFIC | 0, CBS_ASN1_OCTETSTRING)) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
- goto err;
- }
-
- if (OBJ_cbs2nid(&contents_type) != NID_pkcs7_data) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
- goto err;
- }
-
- if (!pbe_decrypt(&out, &out_len, &ai, ctx->password, ctx->password_len,
- CBS_data(&encrypted_contents),
- CBS_len(&encrypted_contents))) {
- goto err;
- }
-
- CBS safe_contents;
- CBS_init(&safe_contents, out, out_len);
- ret = PKCS12_handle_sequence(&safe_contents, ctx, PKCS12_handle_safe_bag);
- OPENSSL_free(out);
- } else if (nid == NID_pkcs7_data) {
- CBS octet_string_contents;
-
- if (!CBS_get_asn1(&wrapped_contents, &octet_string_contents,
- CBS_ASN1_OCTETSTRING)) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
- goto err;
- }
-
- ret = PKCS12_handle_sequence(&octet_string_contents, ctx,
- PKCS12_handle_safe_bag);
- } else {
- /* Unknown element type - ignore it. */
- ret = 1;
- }
-
-err:
- OPENSSL_free(storage);
- return ret;
-}
-
-int PKCS12_get_key_and_certs(EVP_PKEY **out_key, STACK_OF(X509) *out_certs,
- CBS *ber_in, const char *password) {
- uint8_t *der_bytes = NULL;
- size_t der_len;
- CBS in, pfx, mac_data, authsafe, content_type, wrapped_authsafes, authsafes;
- uint64_t version;
- int ret = 0;
- struct pkcs12_context ctx;
- const size_t original_out_certs_len = sk_X509_num(out_certs);
-
- /* The input may be in BER format. */
- if (!CBS_asn1_ber_to_der(ber_in, &der_bytes, &der_len)) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
- return 0;
- }
- if (der_bytes != NULL) {
- CBS_init(&in, der_bytes, der_len);
- } else {
- CBS_init(&in, CBS_data(ber_in), CBS_len(ber_in));
- }
-
- *out_key = NULL;
- OPENSSL_memset(&ctx, 0, sizeof(ctx));
-
- /* See ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-12/pkcs-12v1.pdf, section
- * four. */
- if (!CBS_get_asn1(&in, &pfx, CBS_ASN1_SEQUENCE) ||
- CBS_len(&in) != 0 ||
- !CBS_get_asn1_uint64(&pfx, &version)) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
- goto err;
- }
-
- if (version < 3) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_VERSION);
- goto err;
- }
-
- if (!CBS_get_asn1(&pfx, &authsafe, CBS_ASN1_SEQUENCE)) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
- goto err;
- }
-
- if (CBS_len(&pfx) == 0) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_MISSING_MAC);
- goto err;
- }
-
- if (!CBS_get_asn1(&pfx, &mac_data, CBS_ASN1_SEQUENCE)) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
- goto err;
- }
-
- /* authsafe is a PKCS#7 ContentInfo. See
- * https://tools.ietf.org/html/rfc2315#section-7. */
- if (!CBS_get_asn1(&authsafe, &content_type, CBS_ASN1_OBJECT) ||
- !CBS_get_asn1(&authsafe, &wrapped_authsafes,
- CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
- goto err;
- }
-
- /* The content type can either be |NID_pkcs7_data| or |NID_pkcs7_signed|. The
- * latter indicates that it's signed by a public key, which isn't
- * supported. */
- if (OBJ_cbs2nid(&content_type) != NID_pkcs7_data) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_PKCS12_PUBLIC_KEY_INTEGRITY_NOT_SUPPORTED);
- goto err;
- }
-
- if (!CBS_get_asn1(&wrapped_authsafes, &authsafes, CBS_ASN1_OCTETSTRING)) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
- goto err;
- }
-
- ctx.out_key = out_key;
- ctx.out_certs = out_certs;
- if (!ascii_to_ucs2(password, password ? strlen(password) : 0, &ctx.password,
- &ctx.password_len)) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR);
- goto err;
- }
-
- /* Verify the MAC. */
- {
- CBS mac, hash_type_seq, hash_oid, salt, expected_mac;
- uint64_t iterations;
- int hash_nid;
- const EVP_MD *md;
- uint8_t hmac_key[EVP_MAX_MD_SIZE];
- uint8_t hmac[EVP_MAX_MD_SIZE];
- unsigned hmac_len;
-
- if (!CBS_get_asn1(&mac_data, &mac, CBS_ASN1_SEQUENCE) ||
- !CBS_get_asn1(&mac, &hash_type_seq, CBS_ASN1_SEQUENCE) ||
- !CBS_get_asn1(&hash_type_seq, &hash_oid, CBS_ASN1_OBJECT) ||
- !CBS_get_asn1(&mac, &expected_mac, CBS_ASN1_OCTETSTRING) ||
- !CBS_get_asn1(&mac_data, &salt, CBS_ASN1_OCTETSTRING)) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
- goto err;
- }
-
- /* The iteration count is optional and the default is one. */
- iterations = 1;
- if (CBS_len(&mac_data) > 0) {
- if (!CBS_get_asn1_uint64(&mac_data, &iterations) ||
- iterations > UINT_MAX) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
- goto err;
- }
- }
-
- hash_nid = OBJ_cbs2nid(&hash_oid);
- if (hash_nid == NID_undef ||
- (md = EVP_get_digestbynid(hash_nid)) == NULL) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNKNOWN_HASH);
- goto err;
- }
-
- if (!pkcs12_key_gen_raw(ctx.password, ctx.password_len, CBS_data(&salt),
- CBS_len(&salt), PKCS12_MAC_ID, iterations,
- EVP_MD_size(md), hmac_key, md)) {
- goto err;
- }
-
- if (NULL == HMAC(md, hmac_key, EVP_MD_size(md), CBS_data(&authsafes),
- CBS_len(&authsafes), hmac, &hmac_len)) {
- goto err;
- }
-
- if (!CBS_mem_equal(&expected_mac, hmac, hmac_len)) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_INCORRECT_PASSWORD);
- goto err;
- }
- }
-
- /* authsafes contains a series of PKCS#7 ContentInfos. */
- if (!PKCS12_handle_sequence(&authsafes, &ctx, PKCS12_handle_content_info)) {
- goto err;
- }
-
- ret = 1;
-
-err:
- OPENSSL_free(ctx.password);
- OPENSSL_free(der_bytes);
- if (!ret) {
- EVP_PKEY_free(*out_key);
- *out_key = NULL;
- while (sk_X509_num(out_certs) > original_out_certs_len) {
- X509 *x509 = sk_X509_pop(out_certs);
- X509_free(x509);
- }
- }
-
- return ret;
-}
-
-void PKCS12_PBE_add(void) {}
-
-struct pkcs12_st {
- uint8_t *ber_bytes;
- size_t ber_len;
-};
-
-PKCS12 *d2i_PKCS12(PKCS12 **out_p12, const uint8_t **ber_bytes,
- size_t ber_len) {
- PKCS12 *p12;
-
- p12 = OPENSSL_malloc(sizeof(PKCS12));
- if (!p12) {
- return NULL;
- }
-
- p12->ber_bytes = OPENSSL_malloc(ber_len);
- if (!p12->ber_bytes) {
- OPENSSL_free(p12);
- return NULL;
- }
-
- OPENSSL_memcpy(p12->ber_bytes, *ber_bytes, ber_len);
- p12->ber_len = ber_len;
- *ber_bytes += ber_len;
-
- if (out_p12) {
- PKCS12_free(*out_p12);
-
- *out_p12 = p12;
- }
-
- return p12;
-}
-
-PKCS12* d2i_PKCS12_bio(BIO *bio, PKCS12 **out_p12) {
- size_t used = 0;
- BUF_MEM *buf;
- const uint8_t *dummy;
- static const size_t kMaxSize = 256 * 1024;
- PKCS12 *ret = NULL;
-
- buf = BUF_MEM_new();
- if (buf == NULL) {
- return NULL;
- }
- if (BUF_MEM_grow(buf, 8192) == 0) {
- goto out;
- }
-
- for (;;) {
- int n = BIO_read(bio, &buf->data[used], buf->length - used);
- if (n < 0) {
- if (used == 0) {
- goto out;
- }
- /* Workaround a bug in node.js. It uses a memory BIO for this in the wrong
- * mode. */
- n = 0;
- }
-
- if (n == 0) {
- break;
- }
- used += n;
-
- if (used < buf->length) {
- continue;
- }
-
- if (buf->length > kMaxSize ||
- BUF_MEM_grow(buf, buf->length * 2) == 0) {
- goto out;
- }
- }
-
- dummy = (uint8_t*) buf->data;
- ret = d2i_PKCS12(out_p12, &dummy, used);
-
-out:
- BUF_MEM_free(buf);
- return ret;
-}
-
-PKCS12* d2i_PKCS12_fp(FILE *fp, PKCS12 **out_p12) {
- BIO *bio;
- PKCS12 *ret;
-
- bio = BIO_new_fp(fp, 0 /* don't take ownership */);
- if (!bio) {
- return NULL;
- }
-
- ret = d2i_PKCS12_bio(bio, out_p12);
- BIO_free(bio);
- return ret;
-}
-
-int PKCS12_parse(const PKCS12 *p12, const char *password, EVP_PKEY **out_pkey,
- X509 **out_cert, STACK_OF(X509) **out_ca_certs) {
- CBS ber_bytes;
- STACK_OF(X509) *ca_certs = NULL;
- char ca_certs_alloced = 0;
-
- if (out_ca_certs != NULL && *out_ca_certs != NULL) {
- ca_certs = *out_ca_certs;
- }
-
- if (!ca_certs) {
- ca_certs = sk_X509_new_null();
- if (ca_certs == NULL) {
- OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE);
- return 0;
- }
- ca_certs_alloced = 1;
- }
-
- CBS_init(&ber_bytes, p12->ber_bytes, p12->ber_len);
- if (!PKCS12_get_key_and_certs(out_pkey, ca_certs, &ber_bytes, password)) {
- if (ca_certs_alloced) {
- sk_X509_free(ca_certs);
- }
- return 0;
- }
-
- *out_cert = NULL;
- if (sk_X509_num(ca_certs) > 0) {
- *out_cert = sk_X509_shift(ca_certs);
- }
-
- if (out_ca_certs) {
- *out_ca_certs = ca_certs;
- } else {
- sk_X509_pop_free(ca_certs, X509_free);
- }
-
- return 1;
-}
-
-int PKCS12_verify_mac(const PKCS12 *p12, const char *password,
- int password_len) {
- if (password == NULL) {
- if (password_len != 0) {
- return 0;
- }
- } else if (password_len != -1 &&
- (password[password_len] != 0 ||
- OPENSSL_memchr(password, 0, password_len) != NULL)) {
- return 0;
- }
-
- EVP_PKEY *pkey = NULL;
- X509 *cert = NULL;
- if (!PKCS12_parse(p12, password, &pkey, &cert, NULL)) {
- ERR_clear_error();
- return 0;
- }
-
- EVP_PKEY_free(pkey);
- X509_free(cert);
-
- return 1;
-}
-
-void PKCS12_free(PKCS12 *p12) {
- if (p12 == NULL) {
- return;
- }
- OPENSSL_free(p12->ber_bytes);
- OPENSSL_free(p12);
-}
diff --git a/src/crypto/pkcs8/pkcs8_test.cc b/src/crypto/pkcs8/pkcs8_test.cc
index 1196f9f4..94385ac7 100644
--- a/src/crypto/pkcs8/pkcs8_test.cc
+++ b/src/crypto/pkcs8/pkcs8_test.cc
@@ -143,6 +143,31 @@ static const uint8_t kEmptyPasswordOpenSSL[] = {
0xed,
};
+// kExplicitHMACWithSHA1 is a PBES2-encrypted private key with an explicit
+// hmacWithSHA1 AlgorithmIdentifier in the PBKDF2 parameters.
+static const uint8_t kExplicitHMACWithSHA1[] = {
+ 0x30, 0x81, 0xec, 0x30, 0x57, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x05, 0x0d, 0x30, 0x4a, 0x30, 0x29, 0x06, 0x09, 0x2a, 0x86,
+ 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x05, 0x0c, 0x30, 0x1c, 0x04, 0x08, 0x90,
+ 0xcd, 0x1e, 0x47, 0x1d, 0xff, 0x4c, 0xa8, 0x02, 0x02, 0x08, 0x00, 0x30,
+ 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x07, 0x05,
+ 0x00, 0x30, 0x1d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04,
+ 0x01, 0x02, 0x04, 0x10, 0x34, 0xe7, 0x5b, 0x9b, 0xf9, 0x17, 0xcf, 0x15,
+ 0x59, 0x7c, 0xfd, 0xc1, 0xac, 0xed, 0x6f, 0xdd, 0x04, 0x81, 0x90, 0xe3,
+ 0xd7, 0xfc, 0xbe, 0xe6, 0xe8, 0x92, 0xc1, 0xa2, 0x57, 0x42, 0x4b, 0xf1,
+ 0x35, 0x6c, 0x4f, 0x58, 0x61, 0x14, 0x30, 0x4e, 0xa3, 0x8d, 0x4f, 0xde,
+ 0x2d, 0x0b, 0xa2, 0x62, 0x4b, 0xee, 0x9f, 0xc4, 0xeb, 0x89, 0x33, 0x76,
+ 0x3f, 0x0c, 0x20, 0xad, 0x75, 0x29, 0x42, 0xbc, 0xbd, 0x83, 0x46, 0x1d,
+ 0x5c, 0xae, 0xec, 0x10, 0x05, 0xbb, 0xd3, 0x98, 0xc9, 0x5a, 0x5e, 0x0a,
+ 0x95, 0x12, 0x1e, 0x65, 0x93, 0xdd, 0xdd, 0x51, 0xd5, 0x56, 0xc2, 0xa9,
+ 0xf9, 0x43, 0x0f, 0x68, 0x8a, 0x14, 0x40, 0xe5, 0x62, 0x9e, 0x0d, 0xd7,
+ 0x67, 0x62, 0xf4, 0x49, 0xb1, 0x62, 0x22, 0x42, 0xb1, 0xe1, 0xb2, 0x1d,
+ 0x37, 0x3e, 0x95, 0x52, 0xe9, 0x61, 0x89, 0xc7, 0x62, 0xcc, 0xb1, 0x44,
+ 0x40, 0xef, 0x89, 0xc8, 0xc4, 0x0e, 0xae, 0xa8, 0xf9, 0x17, 0x42, 0x2b,
+ 0x8c, 0x0b, 0x26, 0xf6, 0x07, 0x00, 0xab, 0x25, 0x2b, 0x64, 0xcf, 0xc3,
+ 0x68, 0xf9, 0x5e, 0x01, 0x66, 0x59, 0x5f, 0x3f, 0x05, 0x57, 0xcd,
+};
+
static bool TestDecrypt(const uint8_t *der, size_t der_len,
const char *password) {
const uint8_t *data = der;
@@ -222,6 +247,8 @@ int main(int argc, char **argv) {
!TestDecrypt(kNullPassword, sizeof(kNullPassword), NULL) ||
!TestDecrypt(kNullPasswordNSS, sizeof(kNullPasswordNSS), NULL) ||
!TestDecrypt(kEmptyPasswordOpenSSL, sizeof(kEmptyPasswordOpenSSL), "") ||
+ !TestDecrypt(kExplicitHMACWithSHA1, sizeof(kExplicitHMACWithSHA1),
+ "foo") ||
!TestRoundTrip(NID_pbe_WithSHA1And3_Key_TripleDES_CBC, nullptr,
"password", nullptr, 0, 10) ||
// Vary the salt
diff --git a/src/crypto/pkcs8/pkcs8_x509.c b/src/crypto/pkcs8/pkcs8_x509.c
new file mode 100644
index 00000000..242f9115
--- /dev/null
+++ b/src/crypto/pkcs8/pkcs8_x509.c
@@ -0,0 +1,790 @@
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 1999.
+ */
+/* ====================================================================
+ * Copyright (c) 1999 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com). */
+
+#include <openssl/pkcs8.h>
+
+#include <limits.h>
+
+#include <openssl/asn1t.h>
+#include <openssl/asn1.h>
+#include <openssl/bio.h>
+#include <openssl/buf.h>
+#include <openssl/bytestring.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/digest.h>
+#include <openssl/hmac.h>
+#include <openssl/mem.h>
+#include <openssl/x509.h>
+
+#include "internal.h"
+#include "../bytestring/internal.h"
+#include "../digest/internal.h"
+#include "../internal.h"
+
+
+/* Minor tweak to operation: zero private key data */
+static int pkey_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
+ void *exarg) {
+ /* Since the structure must still be valid use ASN1_OP_FREE_PRE */
+ if (operation == ASN1_OP_FREE_PRE) {
+ PKCS8_PRIV_KEY_INFO *key = (PKCS8_PRIV_KEY_INFO *)*pval;
+ if (key->pkey && key->pkey->type == V_ASN1_OCTET_STRING &&
+ key->pkey->value.octet_string) {
+ OPENSSL_cleanse(key->pkey->value.octet_string->data,
+ key->pkey->value.octet_string->length);
+ }
+ }
+ return 1;
+}
+
+ASN1_SEQUENCE_cb(PKCS8_PRIV_KEY_INFO, pkey_cb) = {
+ ASN1_SIMPLE(PKCS8_PRIV_KEY_INFO, version, ASN1_INTEGER),
+ ASN1_SIMPLE(PKCS8_PRIV_KEY_INFO, pkeyalg, X509_ALGOR),
+ ASN1_SIMPLE(PKCS8_PRIV_KEY_INFO, pkey, ASN1_ANY),
+ ASN1_IMP_SET_OF_OPT(PKCS8_PRIV_KEY_INFO, attributes, X509_ATTRIBUTE, 0)
+} ASN1_SEQUENCE_END_cb(PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO)
+
+IMPLEMENT_ASN1_FUNCTIONS(PKCS8_PRIV_KEY_INFO)
+
+EVP_PKEY *EVP_PKCS82PKEY(PKCS8_PRIV_KEY_INFO *p8) {
+ uint8_t *der = NULL;
+ int der_len = i2d_PKCS8_PRIV_KEY_INFO(p8, &der);
+ if (der_len < 0) {
+ return NULL;
+ }
+
+ CBS cbs;
+ CBS_init(&cbs, der, (size_t)der_len);
+ EVP_PKEY *ret = EVP_parse_private_key(&cbs);
+ if (ret == NULL || CBS_len(&cbs) != 0) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR);
+ EVP_PKEY_free(ret);
+ OPENSSL_free(der);
+ return NULL;
+ }
+
+ OPENSSL_free(der);
+ return ret;
+}
+
+PKCS8_PRIV_KEY_INFO *EVP_PKEY2PKCS8(EVP_PKEY *pkey) {
+ CBB cbb;
+ uint8_t *der = NULL;
+ size_t der_len;
+ if (!CBB_init(&cbb, 0) ||
+ !EVP_marshal_private_key(&cbb, pkey) ||
+ !CBB_finish(&cbb, &der, &der_len) ||
+ der_len > LONG_MAX) {
+ CBB_cleanup(&cbb);
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_ENCODE_ERROR);
+ goto err;
+ }
+
+ const uint8_t *p = der;
+ PKCS8_PRIV_KEY_INFO *p8 = d2i_PKCS8_PRIV_KEY_INFO(NULL, &p, (long)der_len);
+ if (p8 == NULL || p != der + der_len) {
+ PKCS8_PRIV_KEY_INFO_free(p8);
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR);
+ goto err;
+ }
+
+ OPENSSL_free(der);
+ return p8;
+
+err:
+ OPENSSL_free(der);
+ return NULL;
+}
+
+PKCS8_PRIV_KEY_INFO *PKCS8_decrypt(X509_SIG *pkcs8, const char *pass,
+ int pass_len_in) {
+ size_t pass_len;
+ if (pass_len_in == -1 && pass != NULL) {
+ pass_len = strlen(pass);
+ } else {
+ pass_len = (size_t)pass_len_in;
+ }
+
+ PKCS8_PRIV_KEY_INFO *ret = NULL;
+ EVP_PKEY *pkey = NULL;
+ uint8_t *in = NULL;
+
+ /* Convert the legacy ASN.1 object to a byte string. */
+ int in_len = i2d_X509_SIG(pkcs8, &in);
+ if (in_len < 0) {
+ goto err;
+ }
+
+ CBS cbs;
+ CBS_init(&cbs, in, in_len);
+ pkey = PKCS8_parse_encrypted_private_key(&cbs, pass, pass_len);
+ if (pkey == NULL || CBS_len(&cbs) != 0) {
+ goto err;
+ }
+
+ ret = EVP_PKEY2PKCS8(pkey);
+
+err:
+ OPENSSL_free(in);
+ EVP_PKEY_free(pkey);
+ return ret;
+}
+
+X509_SIG *PKCS8_encrypt(int pbe_nid, const EVP_CIPHER *cipher, const char *pass,
+ int pass_len_in, const uint8_t *salt, size_t salt_len,
+ int iterations, PKCS8_PRIV_KEY_INFO *p8inf) {
+ size_t pass_len;
+ if (pass_len_in == -1 && pass != NULL) {
+ pass_len = strlen(pass);
+ } else {
+ pass_len = (size_t)pass_len_in;
+ }
+
+ /* Parse out the private key. */
+ EVP_PKEY *pkey = EVP_PKCS82PKEY(p8inf);
+ if (pkey == NULL) {
+ return NULL;
+ }
+
+ X509_SIG *ret = NULL;
+ uint8_t *der = NULL;
+ size_t der_len;
+ CBB cbb;
+ if (!CBB_init(&cbb, 128) ||
+ !PKCS8_marshal_encrypted_private_key(&cbb, pbe_nid, cipher, pass,
+ pass_len, salt, salt_len, iterations,
+ pkey) ||
+ !CBB_finish(&cbb, &der, &der_len)) {
+ CBB_cleanup(&cbb);
+ goto err;
+ }
+
+ /* Convert back to legacy ASN.1 objects. */
+ const uint8_t *ptr = der;
+ ret = d2i_X509_SIG(NULL, &ptr, der_len);
+ if (ret == NULL || ptr != der + der_len) {
+ OPENSSL_PUT_ERROR(PKCS8, ERR_R_INTERNAL_ERROR);
+ X509_SIG_free(ret);
+ ret = NULL;
+ }
+
+err:
+ OPENSSL_free(der);
+ EVP_PKEY_free(pkey);
+ return ret;
+}
+
+struct pkcs12_context {
+ EVP_PKEY **out_key;
+ STACK_OF(X509) *out_certs;
+ const char *password;
+ size_t password_len;
+};
+
+/* PKCS12_handle_sequence parses a BER-encoded SEQUENCE of elements in a PKCS#12
+ * structure. */
+static int PKCS12_handle_sequence(
+ CBS *sequence, struct pkcs12_context *ctx,
+ int (*handle_element)(CBS *cbs, struct pkcs12_context *ctx)) {
+ uint8_t *der_bytes = NULL;
+ size_t der_len;
+ CBS in;
+ int ret = 0;
+
+ /* Although a BER->DER conversion is done at the beginning of |PKCS12_parse|,
+ * the ASN.1 data gets wrapped in OCTETSTRINGs and/or encrypted and the
+ * conversion cannot see through those wrappings. So each time we step
+ * through one we need to convert to DER again. */
+ if (!CBS_asn1_ber_to_der(sequence, &der_bytes, &der_len)) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
+ return 0;
+ }
+
+ if (der_bytes != NULL) {
+ CBS_init(&in, der_bytes, der_len);
+ } else {
+ CBS_init(&in, CBS_data(sequence), CBS_len(sequence));
+ }
+
+ CBS child;
+ if (!CBS_get_asn1(&in, &child, CBS_ASN1_SEQUENCE) ||
+ CBS_len(&in) != 0) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
+ goto err;
+ }
+
+ while (CBS_len(&child) > 0) {
+ CBS element;
+ if (!CBS_get_asn1(&child, &element, CBS_ASN1_SEQUENCE)) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
+ goto err;
+ }
+
+ if (!handle_element(&element, ctx)) {
+ goto err;
+ }
+ }
+
+ ret = 1;
+
+err:
+ OPENSSL_free(der_bytes);
+ return ret;
+}
+
+/* 1.2.840.113549.1.12.10.1.2 */
+static const uint8_t kPKCS8ShroudedKeyBag[] = {
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x0a, 0x01, 0x02};
+
+/* 1.2.840.113549.1.12.10.1.3 */
+static const uint8_t kCertBag[] = {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x0c, 0x0a, 0x01, 0x03};
+
+/* 1.2.840.113549.1.9.22.1 */
+static const uint8_t kX509Certificate[] = {0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x09, 0x16, 0x01};
+
+/* PKCS12_handle_safe_bag parses a single SafeBag element in a PKCS#12
+ * structure. */
+static int PKCS12_handle_safe_bag(CBS *safe_bag, struct pkcs12_context *ctx) {
+ CBS bag_id, wrapped_value;
+ if (!CBS_get_asn1(safe_bag, &bag_id, CBS_ASN1_OBJECT) ||
+ !CBS_get_asn1(safe_bag, &wrapped_value,
+ CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)
+ /* Ignore the bagAttributes field. */) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
+ return 0;
+ }
+
+ if (CBS_mem_equal(&bag_id, kPKCS8ShroudedKeyBag,
+ sizeof(kPKCS8ShroudedKeyBag))) {
+ /* See RFC 7292, section 4.2.2. */
+ if (*ctx->out_key) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_MULTIPLE_PRIVATE_KEYS_IN_PKCS12);
+ return 0;
+ }
+
+ EVP_PKEY *pkey = PKCS8_parse_encrypted_private_key(
+ &wrapped_value, ctx->password, ctx->password_len);
+ if (pkey == NULL) {
+ return 0;
+ }
+
+ if (CBS_len(&wrapped_value) != 0) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
+ EVP_PKEY_free(pkey);
+ return 0;
+ }
+
+ *ctx->out_key = pkey;
+ return 1;
+ }
+
+ if (CBS_mem_equal(&bag_id, kCertBag, sizeof(kCertBag))) {
+ /* See RFC 7292, section 4.2.3. */
+ CBS cert_bag, cert_type, wrapped_cert, cert;
+ if (!CBS_get_asn1(&wrapped_value, &cert_bag, CBS_ASN1_SEQUENCE) ||
+ !CBS_get_asn1(&cert_bag, &cert_type, CBS_ASN1_OBJECT) ||
+ !CBS_get_asn1(&cert_bag, &wrapped_cert,
+ CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) ||
+ !CBS_get_asn1(&wrapped_cert, &cert, CBS_ASN1_OCTETSTRING)) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
+ return 0;
+ }
+
+ /* Skip unknown certificate types. */
+ if (!CBS_mem_equal(&cert_type, kX509Certificate,
+ sizeof(kX509Certificate))) {
+ return 1;
+ }
+
+ if (CBS_len(&cert) > LONG_MAX) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
+ return 0;
+ }
+
+ const uint8_t *inp = CBS_data(&cert);
+ X509 *x509 = d2i_X509(NULL, &inp, (long)CBS_len(&cert));
+ if (!x509) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
+ return 0;
+ }
+
+ if (inp != CBS_data(&cert) + CBS_len(&cert)) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
+ X509_free(x509);
+ return 0;
+ }
+
+ if (0 == sk_X509_push(ctx->out_certs, x509)) {
+ X509_free(x509);
+ return 0;
+ }
+
+ return 1;
+ }
+
+ /* Unknown element type - ignore it. */
+ return 1;
+}
+
+/* 1.2.840.113549.1.7.1 */
+static const uint8_t kPKCS7Data[] = {0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x07, 0x01};
+
+/* 1.2.840.113549.1.7.6 */
+static const uint8_t kPKCS7EncryptedData[] = {0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x07, 0x06};
+
+/* PKCS12_handle_content_info parses a single PKCS#7 ContentInfo element in a
+ * PKCS#12 structure. */
+static int PKCS12_handle_content_info(CBS *content_info,
+ struct pkcs12_context *ctx) {
+ CBS content_type, wrapped_contents, contents;
+ int ret = 0;
+ uint8_t *storage = NULL;
+
+ if (!CBS_get_asn1(content_info, &content_type, CBS_ASN1_OBJECT) ||
+ !CBS_get_asn1(content_info, &wrapped_contents,
+ CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) ||
+ CBS_len(content_info) != 0) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
+ goto err;
+ }
+
+ if (CBS_mem_equal(&content_type, kPKCS7EncryptedData,
+ sizeof(kPKCS7EncryptedData))) {
+ /* See https://tools.ietf.org/html/rfc2315#section-13.
+ *
+ * PKCS#7 encrypted data inside a PKCS#12 structure is generally an
+ * encrypted certificate bag and it's generally encrypted with 40-bit
+ * RC2-CBC. */
+ CBS version_bytes, eci, contents_type, ai, encrypted_contents;
+ uint8_t *out;
+ size_t out_len;
+
+ if (!CBS_get_asn1(&wrapped_contents, &contents, CBS_ASN1_SEQUENCE) ||
+ !CBS_get_asn1(&contents, &version_bytes, CBS_ASN1_INTEGER) ||
+ /* EncryptedContentInfo, see
+ * https://tools.ietf.org/html/rfc2315#section-10.1 */
+ !CBS_get_asn1(&contents, &eci, CBS_ASN1_SEQUENCE) ||
+ !CBS_get_asn1(&eci, &contents_type, CBS_ASN1_OBJECT) ||
+ /* AlgorithmIdentifier, see
+ * https://tools.ietf.org/html/rfc5280#section-4.1.1.2 */
+ !CBS_get_asn1(&eci, &ai, CBS_ASN1_SEQUENCE) ||
+ !CBS_get_asn1_implicit_string(
+ &eci, &encrypted_contents, &storage,
+ CBS_ASN1_CONTEXT_SPECIFIC | 0, CBS_ASN1_OCTETSTRING)) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
+ goto err;
+ }
+
+ if (!CBS_mem_equal(&contents_type, kPKCS7Data, sizeof(kPKCS7Data))) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
+ goto err;
+ }
+
+ if (!pkcs8_pbe_decrypt(&out, &out_len, &ai, ctx->password,
+ ctx->password_len, CBS_data(&encrypted_contents),
+ CBS_len(&encrypted_contents))) {
+ goto err;
+ }
+
+ CBS safe_contents;
+ CBS_init(&safe_contents, out, out_len);
+ ret = PKCS12_handle_sequence(&safe_contents, ctx, PKCS12_handle_safe_bag);
+ OPENSSL_free(out);
+ } else if (CBS_mem_equal(&content_type, kPKCS7Data, sizeof(kPKCS7Data))) {
+ CBS octet_string_contents;
+
+ if (!CBS_get_asn1(&wrapped_contents, &octet_string_contents,
+ CBS_ASN1_OCTETSTRING)) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
+ goto err;
+ }
+
+ ret = PKCS12_handle_sequence(&octet_string_contents, ctx,
+ PKCS12_handle_safe_bag);
+ } else {
+ /* Unknown element type - ignore it. */
+ ret = 1;
+ }
+
+err:
+ OPENSSL_free(storage);
+ return ret;
+}
+
+int PKCS12_get_key_and_certs(EVP_PKEY **out_key, STACK_OF(X509) *out_certs,
+ CBS *ber_in, const char *password) {
+ uint8_t *der_bytes = NULL;
+ size_t der_len;
+ CBS in, pfx, mac_data, authsafe, content_type, wrapped_authsafes, authsafes;
+ uint64_t version;
+ int ret = 0;
+ struct pkcs12_context ctx;
+ const size_t original_out_certs_len = sk_X509_num(out_certs);
+
+ /* The input may be in BER format. */
+ if (!CBS_asn1_ber_to_der(ber_in, &der_bytes, &der_len)) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
+ return 0;
+ }
+ if (der_bytes != NULL) {
+ CBS_init(&in, der_bytes, der_len);
+ } else {
+ CBS_init(&in, CBS_data(ber_in), CBS_len(ber_in));
+ }
+
+ *out_key = NULL;
+ OPENSSL_memset(&ctx, 0, sizeof(ctx));
+
+ /* See ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-12/pkcs-12v1.pdf, section
+ * four. */
+ if (!CBS_get_asn1(&in, &pfx, CBS_ASN1_SEQUENCE) ||
+ CBS_len(&in) != 0 ||
+ !CBS_get_asn1_uint64(&pfx, &version)) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
+ goto err;
+ }
+
+ if (version < 3) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_VERSION);
+ goto err;
+ }
+
+ if (!CBS_get_asn1(&pfx, &authsafe, CBS_ASN1_SEQUENCE)) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
+ goto err;
+ }
+
+ if (CBS_len(&pfx) == 0) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_MISSING_MAC);
+ goto err;
+ }
+
+ if (!CBS_get_asn1(&pfx, &mac_data, CBS_ASN1_SEQUENCE)) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
+ goto err;
+ }
+
+ /* authsafe is a PKCS#7 ContentInfo. See
+ * https://tools.ietf.org/html/rfc2315#section-7. */
+ if (!CBS_get_asn1(&authsafe, &content_type, CBS_ASN1_OBJECT) ||
+ !CBS_get_asn1(&authsafe, &wrapped_authsafes,
+ CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
+ goto err;
+ }
+
+ /* The content type can either be data or signedData. The latter indicates
+ * that it's signed by a public key, which isn't supported. */
+ if (!CBS_mem_equal(&content_type, kPKCS7Data, sizeof(kPKCS7Data))) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_PKCS12_PUBLIC_KEY_INTEGRITY_NOT_SUPPORTED);
+ goto err;
+ }
+
+ if (!CBS_get_asn1(&wrapped_authsafes, &authsafes, CBS_ASN1_OCTETSTRING)) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
+ goto err;
+ }
+
+ ctx.out_key = out_key;
+ ctx.out_certs = out_certs;
+ ctx.password = password;
+ ctx.password_len = password != NULL ? strlen(password) : 0;
+
+ /* Verify the MAC. */
+ {
+ CBS mac, salt, expected_mac;
+ if (!CBS_get_asn1(&mac_data, &mac, CBS_ASN1_SEQUENCE)) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
+ goto err;
+ }
+
+ const EVP_MD *md = EVP_parse_digest_algorithm(&mac);
+ if (md == NULL) {
+ goto err;
+ }
+
+ if (!CBS_get_asn1(&mac, &expected_mac, CBS_ASN1_OCTETSTRING) ||
+ !CBS_get_asn1(&mac_data, &salt, CBS_ASN1_OCTETSTRING)) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
+ goto err;
+ }
+
+ /* The iteration count is optional and the default is one. */
+ uint64_t iterations = 1;
+ if (CBS_len(&mac_data) > 0) {
+ if (!CBS_get_asn1_uint64(&mac_data, &iterations) ||
+ iterations > UINT_MAX) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
+ goto err;
+ }
+ }
+
+ uint8_t hmac_key[EVP_MAX_MD_SIZE];
+ if (!pkcs12_key_gen(ctx.password, ctx.password_len, CBS_data(&salt),
+ CBS_len(&salt), PKCS12_MAC_ID, iterations,
+ EVP_MD_size(md), hmac_key, md)) {
+ goto err;
+ }
+
+ uint8_t hmac[EVP_MAX_MD_SIZE];
+ unsigned hmac_len;
+ if (NULL == HMAC(md, hmac_key, EVP_MD_size(md), CBS_data(&authsafes),
+ CBS_len(&authsafes), hmac, &hmac_len)) {
+ goto err;
+ }
+
+ if (!CBS_mem_equal(&expected_mac, hmac, hmac_len)) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_INCORRECT_PASSWORD);
+ goto err;
+ }
+ }
+
+ /* authsafes contains a series of PKCS#7 ContentInfos. */
+ if (!PKCS12_handle_sequence(&authsafes, &ctx, PKCS12_handle_content_info)) {
+ goto err;
+ }
+
+ ret = 1;
+
+err:
+ OPENSSL_free(der_bytes);
+ if (!ret) {
+ EVP_PKEY_free(*out_key);
+ *out_key = NULL;
+ while (sk_X509_num(out_certs) > original_out_certs_len) {
+ X509 *x509 = sk_X509_pop(out_certs);
+ X509_free(x509);
+ }
+ }
+
+ return ret;
+}
+
+void PKCS12_PBE_add(void) {}
+
+struct pkcs12_st {
+ uint8_t *ber_bytes;
+ size_t ber_len;
+};
+
+PKCS12 *d2i_PKCS12(PKCS12 **out_p12, const uint8_t **ber_bytes,
+ size_t ber_len) {
+ PKCS12 *p12;
+
+ p12 = OPENSSL_malloc(sizeof(PKCS12));
+ if (!p12) {
+ return NULL;
+ }
+
+ p12->ber_bytes = OPENSSL_malloc(ber_len);
+ if (!p12->ber_bytes) {
+ OPENSSL_free(p12);
+ return NULL;
+ }
+
+ OPENSSL_memcpy(p12->ber_bytes, *ber_bytes, ber_len);
+ p12->ber_len = ber_len;
+ *ber_bytes += ber_len;
+
+ if (out_p12) {
+ PKCS12_free(*out_p12);
+
+ *out_p12 = p12;
+ }
+
+ return p12;
+}
+
+PKCS12* d2i_PKCS12_bio(BIO *bio, PKCS12 **out_p12) {
+ size_t used = 0;
+ BUF_MEM *buf;
+ const uint8_t *dummy;
+ static const size_t kMaxSize = 256 * 1024;
+ PKCS12 *ret = NULL;
+
+ buf = BUF_MEM_new();
+ if (buf == NULL) {
+ return NULL;
+ }
+ if (BUF_MEM_grow(buf, 8192) == 0) {
+ goto out;
+ }
+
+ for (;;) {
+ int n = BIO_read(bio, &buf->data[used], buf->length - used);
+ if (n < 0) {
+ if (used == 0) {
+ goto out;
+ }
+ /* Workaround a bug in node.js. It uses a memory BIO for this in the wrong
+ * mode. */
+ n = 0;
+ }
+
+ if (n == 0) {
+ break;
+ }
+ used += n;
+
+ if (used < buf->length) {
+ continue;
+ }
+
+ if (buf->length > kMaxSize ||
+ BUF_MEM_grow(buf, buf->length * 2) == 0) {
+ goto out;
+ }
+ }
+
+ dummy = (uint8_t*) buf->data;
+ ret = d2i_PKCS12(out_p12, &dummy, used);
+
+out:
+ BUF_MEM_free(buf);
+ return ret;
+}
+
+PKCS12* d2i_PKCS12_fp(FILE *fp, PKCS12 **out_p12) {
+ BIO *bio;
+ PKCS12 *ret;
+
+ bio = BIO_new_fp(fp, 0 /* don't take ownership */);
+ if (!bio) {
+ return NULL;
+ }
+
+ ret = d2i_PKCS12_bio(bio, out_p12);
+ BIO_free(bio);
+ return ret;
+}
+
+int PKCS12_parse(const PKCS12 *p12, const char *password, EVP_PKEY **out_pkey,
+ X509 **out_cert, STACK_OF(X509) **out_ca_certs) {
+ CBS ber_bytes;
+ STACK_OF(X509) *ca_certs = NULL;
+ char ca_certs_alloced = 0;
+
+ if (out_ca_certs != NULL && *out_ca_certs != NULL) {
+ ca_certs = *out_ca_certs;
+ }
+
+ if (!ca_certs) {
+ ca_certs = sk_X509_new_null();
+ if (ca_certs == NULL) {
+ OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ ca_certs_alloced = 1;
+ }
+
+ CBS_init(&ber_bytes, p12->ber_bytes, p12->ber_len);
+ if (!PKCS12_get_key_and_certs(out_pkey, ca_certs, &ber_bytes, password)) {
+ if (ca_certs_alloced) {
+ sk_X509_free(ca_certs);
+ }
+ return 0;
+ }
+
+ *out_cert = NULL;
+ if (sk_X509_num(ca_certs) > 0) {
+ *out_cert = sk_X509_shift(ca_certs);
+ }
+
+ if (out_ca_certs) {
+ *out_ca_certs = ca_certs;
+ } else {
+ sk_X509_pop_free(ca_certs, X509_free);
+ }
+
+ return 1;
+}
+
+int PKCS12_verify_mac(const PKCS12 *p12, const char *password,
+ int password_len) {
+ if (password == NULL) {
+ if (password_len != 0) {
+ return 0;
+ }
+ } else if (password_len != -1 &&
+ (password[password_len] != 0 ||
+ OPENSSL_memchr(password, 0, password_len) != NULL)) {
+ return 0;
+ }
+
+ EVP_PKEY *pkey = NULL;
+ X509 *cert = NULL;
+ if (!PKCS12_parse(p12, password, &pkey, &cert, NULL)) {
+ ERR_clear_error();
+ return 0;
+ }
+
+ EVP_PKEY_free(pkey);
+ X509_free(cert);
+
+ return 1;
+}
+
+void PKCS12_free(PKCS12 *p12) {
+ if (p12 == NULL) {
+ return;
+ }
+ OPENSSL_free(p12->ber_bytes);
+ OPENSSL_free(p12);
+}
diff --git a/src/crypto/rand/deterministic.c b/src/crypto/rand/deterministic.c
index d96a5053..8c754c1e 100644
--- a/src/crypto/rand/deterministic.c
+++ b/src/crypto/rand/deterministic.c
@@ -24,11 +24,11 @@
#include "../internal.h"
-/* g_num_calls is the number of calls to |CRYPTO_sysrand| that have occured.
+/* g_num_calls is the number of calls to |CRYPTO_sysrand| that have occurred.
*
- * TODO(davidben): This is intentionally not thread-safe. If the fuzzer mode is
- * ever used in a multi-threaded program, replace this with a thread-local. (A
- * mutex would not be deterministic.) */
+ * This is intentionally not thread-safe. If the fuzzer mode is ever used in a
+ * multi-threaded program, replace this with a thread-local. (A mutex would not
+ * be deterministic.) */
static uint64_t g_num_calls = 0;
void RAND_reset_for_fuzzing(void) { g_num_calls = 0; }
diff --git a/src/crypto/rsa/internal.h b/src/crypto/rsa/internal.h
index c6ea97f0..b6a07276 100644
--- a/src/crypto/rsa/internal.h
+++ b/src/crypto/rsa/internal.h
@@ -95,24 +95,20 @@ int BN_BLINDING_invert(BIGNUM *n, const BN_BLINDING *b, BN_MONT_CTX *mont_ctx,
BN_CTX *ctx);
-int RSA_padding_add_PKCS1_type_1(uint8_t *to, unsigned to_len,
- const uint8_t *from, unsigned from_len);
+int RSA_padding_add_PKCS1_type_1(uint8_t *to, size_t to_len,
+ const uint8_t *from, size_t from_len);
int RSA_padding_check_PKCS1_type_1(uint8_t *to, unsigned to_len,
const uint8_t *from, unsigned from_len);
-int RSA_padding_add_PKCS1_type_2(uint8_t *to, unsigned to_len,
- const uint8_t *from, unsigned from_len);
+int RSA_padding_add_PKCS1_type_2(uint8_t *to, size_t to_len,
+ const uint8_t *from, size_t from_len);
int RSA_padding_check_PKCS1_type_2(uint8_t *to, unsigned to_len,
const uint8_t *from, unsigned from_len);
-int RSA_padding_add_PKCS1_OAEP_mgf1(uint8_t *to, unsigned to_len,
- const uint8_t *from, unsigned from_len,
- const uint8_t *param, unsigned plen,
- const EVP_MD *md, const EVP_MD *mgf1md);
int RSA_padding_check_PKCS1_OAEP_mgf1(uint8_t *to, unsigned to_len,
const uint8_t *from, unsigned from_len,
const uint8_t *param, unsigned plen,
const EVP_MD *md, const EVP_MD *mgf1md);
-int RSA_padding_add_none(uint8_t *to, unsigned to_len, const uint8_t *from,
- unsigned from_len);
+int RSA_padding_add_none(uint8_t *to, size_t to_len, const uint8_t *from,
+ size_t from_len);
/* RSA_private_transform calls either the method-specific |private_transform|
* function (if given) or the generic one. See the comment for
diff --git a/src/crypto/rsa/padding.c b/src/crypto/rsa/padding.c
index 678457bf..ac583c46 100644
--- a/src/crypto/rsa/padding.c
+++ b/src/crypto/rsa/padding.c
@@ -71,10 +71,9 @@
/* TODO(fork): don't the check functions have to be constant time? */
-int RSA_padding_add_PKCS1_type_1(uint8_t *to, unsigned to_len,
- const uint8_t *from, unsigned from_len) {
- unsigned j;
-
+int RSA_padding_add_PKCS1_type_1(uint8_t *to, size_t to_len,
+ const uint8_t *from, size_t from_len) {
+ /* See RFC 8017, section 9.2. */
if (to_len < RSA_PKCS1_PADDING_SIZE) {
OPENSSL_PUT_ERROR(RSA, RSA_R_KEY_SIZE_TOO_SMALL);
return 0;
@@ -85,17 +84,11 @@ int RSA_padding_add_PKCS1_type_1(uint8_t *to, unsigned to_len,
return 0;
}
- uint8_t *p = to;
-
- *(p++) = 0;
- *(p++) = 1; /* Private Key BT (Block Type) */
-
- /* pad out with 0xff data */
- j = to_len - 3 - from_len;
- OPENSSL_memset(p, 0xff, j);
- p += j;
- *(p++) = 0;
- OPENSSL_memcpy(p, from, from_len);
+ to[0] = 0;
+ to[1] = 1;
+ OPENSSL_memset(to + 2, 0xff, to_len - 3 - from_len);
+ to[to_len - from_len - 1] = 0;
+ OPENSSL_memcpy(to + to_len - from_len, from, from_len);
return 1;
}
@@ -151,10 +144,25 @@ int RSA_padding_check_PKCS1_type_1(uint8_t *to, unsigned to_len,
return j;
}
-int RSA_padding_add_PKCS1_type_2(uint8_t *to, unsigned to_len,
- const uint8_t *from, unsigned from_len) {
- unsigned i, j;
+static int rand_nonzero(uint8_t *out, size_t len) {
+ if (!RAND_bytes(out, len)) {
+ return 0;
+ }
+
+ for (size_t i = 0; i < len; i++) {
+ while (out[i] == 0) {
+ if (!RAND_bytes(out + i, 1)) {
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
+
+int RSA_padding_add_PKCS1_type_2(uint8_t *to, size_t to_len,
+ const uint8_t *from, size_t from_len) {
+ /* See RFC 8017, section 7.2.1. */
if (to_len < RSA_PKCS1_PADDING_SIZE) {
OPENSSL_PUT_ERROR(RSA, RSA_R_KEY_SIZE_TOO_SMALL);
return 0;
@@ -165,30 +173,16 @@ int RSA_padding_add_PKCS1_type_2(uint8_t *to, unsigned to_len,
return 0;
}
- uint8_t *p = to;
-
- *(p++) = 0;
- *(p++) = 2; /* Public Key BT (Block Type) */
-
- /* pad out with non-zero random data */
- j = to_len - 3 - from_len;
+ to[0] = 0;
+ to[1] = 2;
- if (!RAND_bytes(p, j)) {
+ size_t padding_len = to_len - 3 - from_len;
+ if (!rand_nonzero(to + 2, padding_len)) {
return 0;
}
- for (i = 0; i < j; i++) {
- while (*p == 0) {
- if (!RAND_bytes(p, 1)) {
- return 0;
- }
- }
- p++;
- }
-
- *(p++) = 0;
-
- OPENSSL_memcpy(p, from, from_len);
+ to[2 + padding_len] = 0;
+ OPENSSL_memcpy(to + to_len - from_len, from, from_len);
return 1;
}
@@ -258,8 +252,8 @@ int RSA_padding_check_PKCS1_type_2(uint8_t *to, unsigned to_len,
return (int)msg_len;
}
-int RSA_padding_add_none(uint8_t *to, unsigned to_len, const uint8_t *from,
- unsigned from_len) {
+int RSA_padding_add_none(uint8_t *to, size_t to_len, const uint8_t *from,
+ size_t from_len) {
if (from_len > to_len) {
OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
return 0;
@@ -317,15 +311,10 @@ err:
return ret;
}
-int RSA_padding_add_PKCS1_OAEP_mgf1(uint8_t *to, unsigned to_len,
- const uint8_t *from, unsigned from_len,
- const uint8_t *param, unsigned param_len,
+int RSA_padding_add_PKCS1_OAEP_mgf1(uint8_t *to, size_t to_len,
+ const uint8_t *from, size_t from_len,
+ const uint8_t *param, size_t param_len,
const EVP_MD *md, const EVP_MD *mgf1md) {
- unsigned i, emlen, mdlen;
- uint8_t *db, *seed;
- uint8_t *dbmask = NULL, seedmask[EVP_MAX_MD_SIZE];
- int ret = 0;
-
if (md == NULL) {
md = EVP_sha1();
}
@@ -333,14 +322,14 @@ int RSA_padding_add_PKCS1_OAEP_mgf1(uint8_t *to, unsigned to_len,
mgf1md = md;
}
- mdlen = EVP_MD_size(md);
+ size_t mdlen = EVP_MD_size(md);
if (to_len < 2 * mdlen + 2) {
OPENSSL_PUT_ERROR(RSA, RSA_R_KEY_SIZE_TOO_SMALL);
return 0;
}
- emlen = to_len - 1;
+ size_t emlen = to_len - 1;
if (from_len > emlen - 2 * mdlen - 1) {
OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
return 0;
@@ -352,8 +341,8 @@ int RSA_padding_add_PKCS1_OAEP_mgf1(uint8_t *to, unsigned to_len,
}
to[0] = 0;
- seed = to + 1;
- db = to + mdlen + 1;
+ uint8_t *seed = to + 1;
+ uint8_t *db = to + mdlen + 1;
if (!EVP_Digest(param, param_len, db, NULL, md, NULL)) {
return 0;
@@ -365,23 +354,25 @@ int RSA_padding_add_PKCS1_OAEP_mgf1(uint8_t *to, unsigned to_len,
return 0;
}
- dbmask = OPENSSL_malloc(emlen - mdlen);
+ uint8_t *dbmask = OPENSSL_malloc(emlen - mdlen);
if (dbmask == NULL) {
OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
return 0;
}
+ int ret = 0;
if (!PKCS1_MGF1(dbmask, emlen - mdlen, seed, mdlen, mgf1md)) {
goto out;
}
- for (i = 0; i < emlen - mdlen; i++) {
+ for (size_t i = 0; i < emlen - mdlen; i++) {
db[i] ^= dbmask[i];
}
+ uint8_t seedmask[EVP_MAX_MD_SIZE];
if (!PKCS1_MGF1(seedmask, mdlen, db, emlen - mdlen, mgf1md)) {
goto out;
}
- for (i = 0; i < mdlen; i++) {
+ for (size_t i = 0; i < mdlen; i++) {
seed[i] ^= seedmask[i];
}
ret = 1;
@@ -486,7 +477,7 @@ decoding_err:
return -1;
}
-static const unsigned char zeroes[] = {0,0,0,0,0,0,0,0};
+static const uint8_t kPSSZeroes[] = {0, 0, 0, 0, 0, 0, 0, 0};
int RSA_verify_PKCS1_PSS_mgf1(RSA *rsa, const uint8_t *mHash,
const EVP_MD *Hash, const EVP_MD *mgf1Hash,
@@ -567,16 +558,10 @@ int RSA_verify_PKCS1_PSS_mgf1(RSA *rsa, const uint8_t *mHash,
goto err;
}
if (!EVP_DigestInit_ex(&ctx, Hash, NULL) ||
- !EVP_DigestUpdate(&ctx, zeroes, sizeof zeroes) ||
- !EVP_DigestUpdate(&ctx, mHash, hLen)) {
- goto err;
- }
- if (maskedDBLen - i) {
- if (!EVP_DigestUpdate(&ctx, DB + i, maskedDBLen - i)) {
- goto err;
- }
- }
- if (!EVP_DigestFinal_ex(&ctx, H_, NULL)) {
+ !EVP_DigestUpdate(&ctx, kPSSZeroes, sizeof(kPSSZeroes)) ||
+ !EVP_DigestUpdate(&ctx, mHash, hLen) ||
+ !EVP_DigestUpdate(&ctx, DB + i, maskedDBLen - i) ||
+ !EVP_DigestFinal_ex(&ctx, H_, NULL)) {
goto err;
}
if (OPENSSL_memcmp(H_, H, hLen)) {
@@ -601,7 +586,6 @@ int RSA_padding_add_PKCS1_PSS_mgf1(RSA *rsa, unsigned char *EM,
size_t maskedDBLen, MSBits, emLen;
size_t hLen;
unsigned char *H, *salt = NULL, *p;
- EVP_MD_CTX ctx;
if (mgf1Hash == NULL) {
mgf1Hash = Hash;
@@ -660,19 +644,18 @@ int RSA_padding_add_PKCS1_PSS_mgf1(RSA *rsa, unsigned char *EM,
}
maskedDBLen = emLen - hLen - 1;
H = EM + maskedDBLen;
+
+ EVP_MD_CTX ctx;
EVP_MD_CTX_init(&ctx);
- if (!EVP_DigestInit_ex(&ctx, Hash, NULL) ||
- !EVP_DigestUpdate(&ctx, zeroes, sizeof zeroes) ||
- !EVP_DigestUpdate(&ctx, mHash, hLen)) {
- goto err;
- }
- if (sLen && !EVP_DigestUpdate(&ctx, salt, sLen)) {
- goto err;
- }
- if (!EVP_DigestFinal_ex(&ctx, H, NULL)) {
+ int digest_ok = EVP_DigestInit_ex(&ctx, Hash, NULL) &&
+ EVP_DigestUpdate(&ctx, kPSSZeroes, sizeof(kPSSZeroes)) &&
+ EVP_DigestUpdate(&ctx, mHash, hLen) &&
+ EVP_DigestUpdate(&ctx, salt, sLen) &&
+ EVP_DigestFinal_ex(&ctx, H, NULL);
+ EVP_MD_CTX_cleanup(&ctx);
+ if (!digest_ok) {
goto err;
}
- EVP_MD_CTX_cleanup(&ctx);
/* Generate dbMask in place then perform XOR on it */
if (!PKCS1_MGF1(EM, maskedDBLen, H, hLen, mgf1Hash)) {
diff --git a/src/crypto/test/gtest_main.cc b/src/crypto/test/gtest_main.cc
index 50970af3..ea1135c4 100644
--- a/src/crypto/test/gtest_main.cc
+++ b/src/crypto/test/gtest_main.cc
@@ -19,6 +19,13 @@
#include <openssl/err.h>
#include <openssl/crypto.h>
+#if defined(OPENSSL_WINDOWS)
+OPENSSL_MSVC_PRAGMA(warning(push, 3))
+#include <winsock2.h>
+OPENSSL_MSVC_PRAGMA(warning(pop))
+#endif
+
+
namespace {
class ErrorTestEventListener : public testing::EmptyTestEventListener {
@@ -41,6 +48,22 @@ class ErrorTestEventListener : public testing::EmptyTestEventListener {
int main(int argc, char **argv) {
CRYPTO_library_init();
+
+#if defined(OPENSSL_WINDOWS)
+ // Initialize Winsock.
+ WORD wsa_version = MAKEWORD(2, 2);
+ WSADATA wsa_data;
+ int wsa_err = WSAStartup(wsa_version, &wsa_data);
+ if (wsa_err != 0) {
+ fprintf(stderr, "WSAStartup failed: %d\n", wsa_err);
+ return 1;
+ }
+ if (wsa_data.wVersion != wsa_version) {
+ fprintf(stderr, "Didn't get expected version: %x\n", wsa_data.wVersion);
+ return 1;
+ }
+#endif
+
testing::InitGoogleTest(&argc, argv);
testing::UnitTest::GetInstance()->listeners().Append(
new ErrorTestEventListener);
diff --git a/src/crypto/test/test_util.h b/src/crypto/test/test_util.h
index 1447bf69..bce34d4f 100644
--- a/src/crypto/test/test_util.h
+++ b/src/crypto/test/test_util.h
@@ -34,6 +34,8 @@ void hexdump(FILE *fp, const char *msg, const void *in, size_t len);
struct Bytes {
Bytes(const uint8_t *data_arg, size_t len_arg)
: data(data_arg), len(len_arg) {}
+ Bytes(const char *data_arg, size_t len_arg)
+ : data(reinterpret_cast<const uint8_t *>(data_arg)), len(len_arg) {}
Bytes(const char *str)
: data(reinterpret_cast<const uint8_t *>(str)), len(strlen(str)) {}
diff --git a/src/crypto/x509/pkcs7.c b/src/crypto/x509/pkcs7.c
index 9e6a52f2..dc3ea7d9 100644
--- a/src/crypto/x509/pkcs7.c
+++ b/src/crypto/x509/pkcs7.c
@@ -27,6 +27,14 @@
#include "../bytestring/internal.h"
+/* 1.2.840.113549.1.7.1 */
+static const uint8_t kPKCS7Data[] = {0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x07, 0x01};
+
+/* 1.2.840.113549.1.7.2 */
+static const uint8_t kPKCS7SignedData[] = {0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x07, 0x02};
+
/* pkcs7_parse_header reads the non-certificate/non-CRL prefix of a PKCS#7
* SignedData blob from |cbs| and sets |*out| to point to the rest of the
* input. If the input is in BER format, then |*der_bytes| will be set to a
@@ -57,7 +65,8 @@ static int pkcs7_parse_header(uint8_t **der_bytes, CBS *out, CBS *cbs) {
goto err;
}
- if (OBJ_cbs2nid(&content_type) != NID_pkcs7_signed) {
+ if (!CBS_mem_equal(&content_type, kPKCS7SignedData,
+ sizeof(kPKCS7SignedData))) {
OPENSSL_PUT_ERROR(X509, X509_R_NOT_PKCS7_SIGNED_DATA);
goto err;
}
@@ -81,11 +90,8 @@ static int pkcs7_parse_header(uint8_t **der_bytes, CBS *out, CBS *cbs) {
return 1;
err:
- if (*der_bytes) {
- OPENSSL_free(*der_bytes);
- *der_bytes = NULL;
- }
-
+ OPENSSL_free(*der_bytes);
+ *der_bytes = NULL;
return 0;
}
@@ -135,9 +141,7 @@ int PKCS7_get_certificates(STACK_OF(X509) *out_certs, CBS *cbs) {
ret = 1;
err:
- if (der_bytes) {
- OPENSSL_free(der_bytes);
- }
+ OPENSSL_free(der_bytes);
if (!ret) {
while (sk_X509_num(out_certs) != initial_certs_len) {
@@ -205,9 +209,7 @@ int PKCS7_get_CRLs(STACK_OF(X509_CRL) *out_crls, CBS *cbs) {
ret = 1;
err:
- if (der_bytes) {
- OPENSSL_free(der_bytes);
- }
+ OPENSSL_free(der_bytes);
if (!ret) {
while (sk_X509_CRL_num(out_crls) != initial_crls_len) {
@@ -270,12 +272,13 @@ int PKCS7_get_PEM_CRLs(STACK_OF(X509_CRL) *out_crls, BIO *pem_bio) {
* pkcs7_bundle returns one on success or zero on error. */
static int pkcs7_bundle(CBB *out, int (*cb)(CBB *out, const void *arg),
const void *arg) {
- CBB outer_seq, wrapped_seq, seq, version_bytes, digest_algos_set,
+ CBB outer_seq, oid, wrapped_seq, seq, version_bytes, digest_algos_set,
content_info;
/* See https://tools.ietf.org/html/rfc2315#section-7 */
if (!CBB_add_asn1(out, &outer_seq, CBS_ASN1_SEQUENCE) ||
- !OBJ_nid2cbb(&outer_seq, NID_pkcs7_signed) ||
+ !CBB_add_asn1(&outer_seq, &oid, CBS_ASN1_OBJECT) ||
+ !CBB_add_bytes(&oid, kPKCS7SignedData, sizeof(kPKCS7SignedData)) ||
!CBB_add_asn1(&outer_seq, &wrapped_seq,
CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) ||
/* See https://tools.ietf.org/html/rfc2315#section-9.1 */
@@ -284,7 +287,8 @@ static int pkcs7_bundle(CBB *out, int (*cb)(CBB *out, const void *arg),
!CBB_add_u8(&version_bytes, 1) ||
!CBB_add_asn1(&seq, &digest_algos_set, CBS_ASN1_SET) ||
!CBB_add_asn1(&seq, &content_info, CBS_ASN1_SEQUENCE) ||
- !OBJ_nid2cbb(&content_info, NID_pkcs7_data) ||
+ !CBB_add_asn1(&content_info, &oid, CBS_ASN1_OBJECT) ||
+ !CBB_add_bytes(&oid, kPKCS7Data, sizeof(kPKCS7Data)) ||
!cb(&seq, arg)) {
return 0;
}
diff --git a/src/decrepit/CMakeLists.txt b/src/decrepit/CMakeLists.txt
index 223320d2..a3e409b5 100644
--- a/src/decrepit/CMakeLists.txt
+++ b/src/decrepit/CMakeLists.txt
@@ -46,4 +46,7 @@ add_executable(
)
target_link_libraries(decrepit_test crypto decrepit gtest)
+if (WIN32)
+ target_link_libraries(decrepit_test ws2_32)
+endif()
add_dependencies(all_tests decrepit_test)
diff --git a/src/decrepit/rsa/rsa_decrepit.c b/src/decrepit/rsa/rsa_decrepit.c
index 0d7c5f66..c4ef5b66 100644
--- a/src/decrepit/rsa/rsa_decrepit.c
+++ b/src/decrepit/rsa/rsa_decrepit.c
@@ -95,9 +95,9 @@ int RSA_verify_PKCS1_PSS(RSA *rsa, const uint8_t *mHash, const EVP_MD *Hash,
return RSA_verify_PKCS1_PSS_mgf1(rsa, mHash, Hash, NULL, EM, sLen);
}
-int RSA_padding_add_PKCS1_OAEP(uint8_t *to, unsigned to_len,
- const uint8_t *from, unsigned from_len,
- const uint8_t *param, unsigned param_len) {
+int RSA_padding_add_PKCS1_OAEP(uint8_t *to, size_t to_len,
+ const uint8_t *from, size_t from_len,
+ const uint8_t *param, size_t param_len) {
return RSA_padding_add_PKCS1_OAEP_mgf1(to, to_len, from, from_len, param,
param_len, NULL, NULL);
}
diff --git a/src/include/openssl/digest.h b/src/include/openssl/digest.h
index 87de3dfe..2de84f7d 100644
--- a/src/include/openssl/digest.h
+++ b/src/include/openssl/digest.h
@@ -283,5 +283,7 @@ using ScopedEVP_MD_CTX =
#endif
#define DIGEST_R_INPUT_NOT_INITIALIZED 100
+#define DIGEST_R_DECODE_ERROR 101
+#define DIGEST_R_UNKNOWN_HASH 102
#endif /* OPENSSL_HEADER_DIGEST_H */
diff --git a/src/include/openssl/pkcs8.h b/src/include/openssl/pkcs8.h
index 70d6f495..d30ea8e3 100644
--- a/src/include/openssl/pkcs8.h
+++ b/src/include/openssl/pkcs8.h
@@ -88,6 +88,14 @@ OPENSSL_EXPORT X509_SIG *PKCS8_encrypt(int pbe_nid, const EVP_CIPHER *cipher,
int iterations,
PKCS8_PRIV_KEY_INFO *p8inf);
+/* PKCS8_marshal_encrypted_private_key behaves like |PKCS8_encrypt| but encrypts
+ * an |EVP_PKEY| and writes the serialized EncryptedPrivateKeyInfo to |out|. It
+ * returns one on success and zero on error. */
+OPENSSL_EXPORT int PKCS8_marshal_encrypted_private_key(
+ CBB *out, int pbe_nid, const EVP_CIPHER *cipher, const char *pass,
+ size_t pass_len, const uint8_t *salt, size_t salt_len, int iterations,
+ const EVP_PKEY *pkey);
+
/* PKCS8_decrypt decrypts and decodes a PKCS8_PRIV_KEY_INFO with PBES1 or PBES2
* as defined in PKCS #5. Only pbeWithSHAAnd128BitRC4,
* pbeWithSHAAnd3-KeyTripleDES-CBC and pbeWithSHA1And40BitRC2, and PBES2,
@@ -103,6 +111,13 @@ OPENSSL_EXPORT PKCS8_PRIV_KEY_INFO *PKCS8_decrypt(X509_SIG *pkcs8,
const char *pass,
int pass_len);
+/* PKCS8_parse_encrypted_private_key behaves like |PKCS8_decrypt| but it parses
+ * the EncryptedPrivateKeyInfo structure from |cbs| and advances |cbs|. It
+ * returns a newly-allocated |EVP_PKEY| on success and zero on error. */
+OPENSSL_EXPORT EVP_PKEY *PKCS8_parse_encrypted_private_key(CBS *cbs,
+ const char *pass,
+ size_t pass_len);
+
/* PKCS12_get_key_and_certs parses a PKCS#12 structure from |in|, authenticates
* and decrypts it using |password|, sets |*out_key| to the included private
* key and appends the included certificates to |out_certs|. It returns one on
diff --git a/src/include/openssl/rsa.h b/src/include/openssl/rsa.h
index bad3fad8..d8f76f02 100644
--- a/src/include/openssl/rsa.h
+++ b/src/include/openssl/rsa.h
@@ -354,8 +354,8 @@ OPENSSL_EXPORT int RSA_padding_add_PKCS1_PSS_mgf1(RSA *rsa, uint8_t *EM,
*
* It returns one on success or zero on error. */
OPENSSL_EXPORT int RSA_padding_add_PKCS1_OAEP_mgf1(
- uint8_t *to, unsigned to_len, const uint8_t *from, unsigned from_len,
- const uint8_t *param, unsigned param_len, const EVP_MD *md,
+ uint8_t *to, size_t to_len, const uint8_t *from, size_t from_len,
+ const uint8_t *param, size_t param_len, const EVP_MD *md,
const EVP_MD *mgf1md);
/* RSA_add_pkcs1_prefix builds a version of |msg| prefixed with the DigestInfo
@@ -519,11 +519,11 @@ OPENSSL_EXPORT int RSA_verify_PKCS1_PSS(RSA *rsa, const uint8_t *mHash,
/* RSA_padding_add_PKCS1_OAEP acts like |RSA_padding_add_PKCS1_OAEP_mgf1| but
* the |md| and |mgf1md| parameters of the latter are implicitly set to NULL,
* which means SHA-1. */
-OPENSSL_EXPORT int RSA_padding_add_PKCS1_OAEP(uint8_t *to, unsigned to_len,
+OPENSSL_EXPORT int RSA_padding_add_PKCS1_OAEP(uint8_t *to, size_t to_len,
const uint8_t *from,
- unsigned from_len,
+ size_t from_len,
const uint8_t *param,
- unsigned param_len);
+ size_t param_len);
struct rsa_meth_st {
diff --git a/src/include/openssl/ssl.h b/src/include/openssl/ssl.h
index 11f8ef2e..5182df7f 100644
--- a/src/include/openssl/ssl.h
+++ b/src/include/openssl/ssl.h
@@ -3078,10 +3078,26 @@ OPENSSL_EXPORT int SSL_renegotiate_pending(SSL *ssl);
OPENSSL_EXPORT int SSL_total_renegotiations(const SSL *ssl);
/* SSL_CTX_set_early_data_enabled sets whether early data is allowed to be used
- * with resumptions using |ctx|. WARNING: This is experimental and may cause
- * interoperability failures until fully implemented. */
+ * with resumptions using |ctx|.
+ *
+ * As a server, if the client's early data is accepted, |SSL_do_handshake| will
+ * complete as soon as the ClientHello is processed and server flight sent.
+ * |SSL_write| may be used to send half-RTT data. |SSL_read| will consume early
+ * data and transition to 1-RTT data as appropriate.
+ *
+ * Note early data is replayable by a network attacker. |SSL_in_init| and
+ * |SSL_is_init_finished| will report the handshake is still in progress until
+ * the client's Finished message is received. Callers may use these functions
+ * to defer some processing if desired.
+ *
+ * WARNING: This is experimental and may cause interoperability failures until
+ * fully implemented. */
OPENSSL_EXPORT void SSL_CTX_set_early_data_enabled(SSL_CTX *ctx, int enabled);
+/* SSL_early_data_accepted returns whether early data was accepted on the
+ * handshake performed by |ssl|. */
+OPENSSL_EXPORT int SSL_early_data_accepted(const SSL *ssl);
+
/* SSL_MAX_CERT_LIST_DEFAULT is the default maximum length, in bytes, of a peer
* certificate chain. */
#define SSL_MAX_CERT_LIST_DEFAULT (1024 * 100)
@@ -3144,6 +3160,20 @@ typedef struct ssl_early_callback_ctx {
size_t extensions_len;
} SSL_CLIENT_HELLO;
+/* ssl_select_cert_result_t enumerates the possible results from selecting a
+ * certificate with |select_certificate_cb|. */
+enum ssl_select_cert_result_t {
+ /* ssl_select_cert_success indicates that the certificate selection was
+ * successful. */
+ ssl_select_cert_success = 1,
+ /* ssl_select_cert_retry indicates that the operation could not be
+ * immediately completed and must be reattempted at a later point. */
+ ssl_select_cert_retry = 0,
+ /* ssl_select_cert_error indicates that a fatal error occured and the
+ * handshake should be terminated. */
+ ssl_select_cert_error = -1,
+};
+
/* SSL_early_callback_ctx_extension_get searches the extensions in
* |client_hello| for an extension of the given type. If not found, it returns
* zero. Otherwise it sets |out_data| to point to the extension contents (not
@@ -3156,14 +3186,18 @@ OPENSSL_EXPORT int SSL_early_callback_ctx_extension_get(
/* SSL_CTX_set_select_certificate_cb sets a callback that is called before most
* ClientHello processing and before the decision whether to resume a session
* is made. The callback may inspect the ClientHello and configure the
- * connection. It may then return one to continue the handshake or zero to
- * pause the handshake to perform an asynchronous operation. If paused,
- * |SSL_get_error| will return |SSL_ERROR_PENDING_CERTIFICATE|.
+ * connection. See |ssl_select_cert_result_t| for details of the return values.
+ *
+ * In the case that a retry is indicated, |SSL_get_error| will return
+ * |SSL_ERROR_PENDING_CERTIFICATE| and the caller should arrange for the
+ * high-level operation on |ssl| to be retried at a later time, which will
+ * result in another call to |cb|.
*
* Note: The |SSL_CLIENT_HELLO| is only valid for the duration of the callback
* and is not valid while the handshake is paused. */
OPENSSL_EXPORT void SSL_CTX_set_select_certificate_cb(
- SSL_CTX *ctx, int (*cb)(const SSL_CLIENT_HELLO *));
+ SSL_CTX *ctx,
+ enum ssl_select_cert_result_t (*cb)(const SSL_CLIENT_HELLO *));
/* SSL_CTX_set_dos_protection_cb sets a callback that is called once the
* resumption decision for a ClientHello has been made. It can return one to
@@ -4112,12 +4146,10 @@ struct ssl_ctx_st {
X509_VERIFY_PARAM *param;
/* select_certificate_cb is called before most ClientHello processing and
- * before the decision whether to resume a session is made. It may return one
- * to continue the handshake or zero to cause the handshake loop to return
- * with an error and cause SSL_get_error to return
- * SSL_ERROR_PENDING_CERTIFICATE. Note: when the handshake loop is resumed, it
- * will not call the callback a second time. */
- int (*select_certificate_cb)(const SSL_CLIENT_HELLO *);
+ * before the decision whether to resume a session is made. See
+ * |ssl_select_cert_result_t| for details of the return values. */
+ enum ssl_select_cert_result_t (*select_certificate_cb)(
+ const SSL_CLIENT_HELLO *);
/* dos_protection_cb is called once the resumption decision for a ClientHello
* has been made. It returns one to continue the handshake or zero to
@@ -4584,6 +4616,9 @@ BORINGSSL_MAKE_DELETER(SSL_SESSION, SSL_SESSION_free)
#define SSL_R_CERTIFICATE_AND_PRIVATE_KEY_MISMATCH 274
#define SSL_R_CANNOT_HAVE_BOTH_PRIVKEY_AND_METHOD 275
#define SSL_R_TICKET_ENCRYPTION_FAILED 276
+#define SSL_R_ALPN_MISMATCH_ON_EARLY_DATA 277
+#define SSL_R_WRONG_VERSION_ON_EARLY_DATA 278
+#define SSL_R_CHANNEL_ID_ON_EARLY_DATA 279
#define SSL_R_SSLV3_ALERT_CLOSE_NOTIFY 1000
#define SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE 1010
#define SSL_R_SSLV3_ALERT_BAD_RECORD_MAC 1020
diff --git a/src/ssl/CMakeLists.txt b/src/ssl/CMakeLists.txt
index 5b5ea976..3e9cd402 100644
--- a/src/ssl/CMakeLists.txt
+++ b/src/ssl/CMakeLists.txt
@@ -52,4 +52,7 @@ add_executable(
)
target_link_libraries(ssl_test ssl crypto gtest)
+if (WIN32)
+ target_link_libraries(ssl_test ws2_32)
+endif()
add_dependencies(all_tests ssl_test)
diff --git a/src/ssl/custom_extensions.c b/src/ssl/custom_extensions.c
index 10fbfc8f..ea57c20a 100644
--- a/src/ssl/custom_extensions.c
+++ b/src/ssl/custom_extensions.c
@@ -69,6 +69,14 @@ static int custom_ext_add_hello(SSL_HANDSHAKE *hs, CBB *extensions) {
return 1;
}
+ if (ssl->ctx->enable_early_data) {
+ /* TODO(svaldez): Support Custom Extensions with 0-RTT. For now the caller
+ * is expected not to configure both together.
+ * https://crbug.com/boringssl/173. */
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CUSTOM_EXTENSION_ERROR);
+ return 0;
+ }
+
for (size_t i = 0; i < sk_SSL_CUSTOM_EXTENSION_num(stack); i++) {
const SSL_CUSTOM_EXTENSION *ext = sk_SSL_CUSTOM_EXTENSION_value(stack, i);
diff --git a/src/ssl/handshake_client.c b/src/ssl/handshake_client.c
index 1feb7d8d..7eddd359 100644
--- a/src/ssl/handshake_client.c
+++ b/src/ssl/handshake_client.c
@@ -208,6 +208,18 @@ int ssl3_connect(SSL_HANDSHAKE *hs) {
}
if (!SSL_is_dtls(ssl) || ssl->d1->send_cookie) {
+ if (hs->early_data_offered) {
+ if (!tls13_init_early_key_schedule(hs) ||
+ !tls13_advance_key_schedule(hs, ssl->session->master_key,
+ ssl->session->master_key_length) ||
+ !tls13_derive_early_secrets(hs) ||
+ !tls13_set_traffic_key(ssl, evp_aead_seal,
+ hs->early_traffic_secret,
+ hs->hash_len)) {
+ ret = -1;
+ goto end;
+ }
+ }
hs->next_state = SSL3_ST_CR_SRVR_HELLO_A;
} else {
hs->next_state = DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A;
@@ -394,6 +406,7 @@ int ssl3_connect(SSL_HANDSHAKE *hs) {
case SSL3_ST_FALSE_START:
hs->state = SSL3_ST_CR_SESSION_TICKET_A;
hs->in_false_start = 1;
+ hs->can_early_write = 1;
ret = 1;
goto end;
@@ -445,13 +458,21 @@ int ssl3_connect(SSL_HANDSHAKE *hs) {
}
break;
- case SSL_ST_TLS13:
- ret = tls13_handshake(hs);
+ case SSL_ST_TLS13: {
+ int early_return = 0;
+ ret = tls13_handshake(hs, &early_return);
if (ret <= 0) {
goto end;
}
+
+ if (early_return) {
+ ret = 1;
+ goto end;
+ }
+
hs->state = SSL3_ST_FINISH_CLIENT_HANDSHAKE;
break;
+ }
case SSL3_ST_FINISH_CLIENT_HANDSHAKE:
ssl->method->release_current_message(ssl, 1 /* free_buffer */);
@@ -875,6 +896,12 @@ static int ssl3_get_server_hello(SSL_HANDSHAKE *hs) {
return 1;
}
+ if (hs->early_data_offered) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_VERSION_ON_EARLY_DATA);
+ al = SSL_AD_PROTOCOL_VERSION;
+ goto f_err;
+ }
+
ssl_clear_tls13_state(hs);
if (!ssl_check_message_type(ssl, SSL3_MT_SERVER_HELLO)) {
diff --git a/src/ssl/handshake_server.c b/src/ssl/handshake_server.c
index 81e45ef0..a1341d6c 100644
--- a/src/ssl/handshake_server.c
+++ b/src/ssl/handshake_server.c
@@ -448,13 +448,21 @@ int ssl3_accept(SSL_HANDSHAKE *hs) {
}
break;
- case SSL_ST_TLS13:
- ret = tls13_handshake(hs);
+ case SSL_ST_TLS13: {
+ int early_return = 0;
+ ret = tls13_handshake(hs, &early_return);
if (ret <= 0) {
goto end;
}
+
+ if (early_return) {
+ ret = 1;
+ goto end;
+ }
+
hs->state = SSL_ST_OK;
break;
+ }
case SSL_ST_OK:
ssl->method->release_current_message(ssl, 1 /* free_buffer */);
@@ -812,11 +820,11 @@ static int ssl3_process_client_hello(SSL_HANDSHAKE *hs) {
/* Run the early callback. */
if (ssl->ctx->select_certificate_cb != NULL) {
switch (ssl->ctx->select_certificate_cb(&client_hello)) {
- case 0:
+ case ssl_select_cert_retry:
ssl->rwstate = SSL_CERTIFICATE_SELECTION_PENDING;
return -1;
- case -1:
+ case ssl_select_cert_error:
/* Connection rejected. */
OPENSSL_PUT_ERROR(SSL, SSL_R_CONNECTION_REJECTED);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
diff --git a/src/ssl/internal.h b/src/ssl/internal.h
index 99980d84..ded5ba83 100644
--- a/src/ssl/internal.h
+++ b/src/ssl/internal.h
@@ -865,6 +865,11 @@ int ssl_check_leaf_certificate(SSL_HANDSHAKE *hs, EVP_PKEY *pkey,
* It returns one on success and zero on error. */
int tls13_init_key_schedule(SSL_HANDSHAKE *hs);
+/* tls13_init_early_key_schedule initializes the handshake hash and key
+ * derivation state from the resumption secret to derive the early secrets. It
+ * returns one on success and zero on error. */
+int tls13_init_early_key_schedule(SSL_HANDSHAKE *hs);
+
/* tls13_advance_key_schedule incorporates |in| into the key schedule with
* HKDF-Extract. It returns one on success and zero on error. */
int tls13_advance_key_schedule(SSL_HANDSHAKE *hs, const uint8_t *in,
@@ -876,6 +881,10 @@ int tls13_set_traffic_key(SSL *ssl, enum evp_aead_direction_t direction,
const uint8_t *traffic_secret,
size_t traffic_secret_len);
+/* tls13_derive_early_secrets derives the early traffic secret. It returns one
+ * on success and zero on error. */
+int tls13_derive_early_secrets(SSL_HANDSHAKE *hs);
+
/* tls13_derive_handshake_secrets derives the handshake traffic secret. It
* returns one on success and zero on error. */
int tls13_derive_handshake_secrets(SSL_HANDSHAKE *hs);
@@ -930,6 +939,7 @@ enum ssl_hs_wait_t {
ssl_hs_channel_id_lookup,
ssl_hs_private_key_operation,
ssl_hs_pending_ticket,
+ ssl_hs_read_end_of_early_data,
};
struct ssl_handshake_st {
@@ -957,10 +967,12 @@ struct ssl_handshake_st {
size_t hash_len;
uint8_t secret[EVP_MAX_MD_SIZE];
+ uint8_t early_traffic_secret[EVP_MAX_MD_SIZE];
uint8_t client_handshake_secret[EVP_MAX_MD_SIZE];
uint8_t server_handshake_secret[EVP_MAX_MD_SIZE];
uint8_t client_traffic_secret_0[EVP_MAX_MD_SIZE];
uint8_t server_traffic_secret_0[EVP_MAX_MD_SIZE];
+ uint8_t expected_client_finished[EVP_MAX_MD_SIZE];
union {
/* sent is a bitset where the bits correspond to elements of kExtensions
@@ -1063,10 +1075,6 @@ struct ssl_handshake_st {
uint8_t *key_block;
uint8_t key_block_len;
- /* session_tickets_sent, in TLS 1.3, is the number of tickets the server has
- * sent. */
- uint8_t session_tickets_sent;
-
/* scts_requested is one if the SCT extension is in the ClientHello. */
unsigned scts_requested:1;
@@ -1100,6 +1108,17 @@ struct ssl_handshake_st {
* Start. The client may write data at this point. */
unsigned in_false_start:1;
+ /* early_data_offered is one if the client sent the early_data extension. */
+ unsigned early_data_offered:1;
+
+ /* can_early_read is one if application data may be read at this point in the
+ * handshake. */
+ unsigned can_early_read:1;
+
+ /* can_early_write is one if application data may be written at this point in
+ * the handshake. */
+ unsigned can_early_write:1;
+
/* next_proto_neg_seen is one of NPN was negotiated. */
unsigned next_proto_neg_seen:1;
@@ -1128,8 +1147,9 @@ void ssl_handshake_free(SSL_HANDSHAKE *hs);
int ssl_check_message_type(SSL *ssl, int type);
/* tls13_handshake runs the TLS 1.3 handshake. It returns one on success and <=
- * 0 on error. */
-int tls13_handshake(SSL_HANDSHAKE *hs);
+ * 0 on error. It sets |out_early_return| to one if we've completed the
+ * handshake early. */
+int tls13_handshake(SSL_HANDSHAKE *hs, int *out_early_return);
/* The following are implementations of |do_tls13_handshake| for the client and
* server. */
@@ -1142,7 +1162,11 @@ int tls13_post_handshake(SSL *ssl);
int tls13_process_certificate(SSL_HANDSHAKE *hs, int allow_anonymous);
int tls13_process_certificate_verify(SSL_HANDSHAKE *hs);
-int tls13_process_finished(SSL_HANDSHAKE *hs);
+
+/* tls13_process_finished processes the current message as a Finished message
+ * from the peer. If |use_saved_value| is one, the verify_data is compared
+ * against |hs->expected_client_finished| rather than computed fresh. */
+int tls13_process_finished(SSL_HANDSHAKE *hs, int use_saved_value);
int tls13_add_certificate(SSL_HANDSHAKE *hs);
enum ssl_private_key_result_t tls13_add_certificate_verify(SSL_HANDSHAKE *hs,
@@ -1629,9 +1653,11 @@ typedef struct ssl3_state_st {
uint8_t write_traffic_secret[EVP_MAX_MD_SIZE];
uint8_t read_traffic_secret[EVP_MAX_MD_SIZE];
uint8_t exporter_secret[EVP_MAX_MD_SIZE];
+ uint8_t early_exporter_secret[EVP_MAX_MD_SIZE];
uint8_t write_traffic_secret_len;
uint8_t read_traffic_secret_len;
uint8_t exporter_secret_len;
+ uint8_t early_exporter_secret_len;
/* Connection binding to prevent renegotiation attacks */
uint8_t previous_client_finished[12];
@@ -1933,6 +1959,9 @@ struct ssl_st {
* hash of the peer's certificate and then discard it to save memory and
* session space. Only effective on the server side. */
unsigned retain_only_sha256_of_client_certs:1;
+
+ /* early_data_accepted is true if early data was accepted by the server. */
+ unsigned early_data_accepted:1;
};
/* From draft-ietf-tls-tls13-18, used in determining PSK modes. */
@@ -2209,6 +2238,12 @@ int ssl_do_channel_id_callback(SSL *ssl);
* otherwise. */
int ssl3_can_false_start(const SSL *ssl);
+/* ssl_can_write returns one if |ssl| is allowed to write and zero otherwise. */
+int ssl_can_write(const SSL *ssl);
+
+/* ssl_can_read returns one if |ssl| is allowed to read and zero otherwise. */
+int ssl_can_read(const SSL *ssl);
+
/* ssl_get_version_range sets |*out_min_version| and |*out_max_version| to the
* minimum and maximum enabled protocol versions, respectively. */
int ssl_get_version_range(const SSL *ssl, uint16_t *out_min_version,
diff --git a/src/ssl/s3_both.c b/src/ssl/s3_both.c
index 8fa51e93..7ef400a8 100644
--- a/src/ssl/s3_both.c
+++ b/src/ssl/s3_both.c
@@ -153,6 +153,7 @@ void ssl_handshake_free(SSL_HANDSHAKE *hs) {
}
OPENSSL_cleanse(hs->secret, sizeof(hs->secret));
+ OPENSSL_cleanse(hs->early_traffic_secret, sizeof(hs->early_traffic_secret));
OPENSSL_cleanse(hs->client_handshake_secret,
sizeof(hs->client_handshake_secret));
OPENSSL_cleanse(hs->server_handshake_secret,
diff --git a/src/ssl/s3_pkt.c b/src/ssl/s3_pkt.c
index 2f919cae..c2d30ca2 100644
--- a/src/ssl/s3_pkt.c
+++ b/src/ssl/s3_pkt.c
@@ -189,7 +189,7 @@ again:
}
int ssl3_write_app_data(SSL *ssl, const uint8_t *buf, int len) {
- assert(!SSL_in_init(ssl) || SSL_in_false_start(ssl));
+ assert(ssl_can_write(ssl));
unsigned tot, n, nw;
@@ -325,10 +325,11 @@ static int consume_record(SSL *ssl, uint8_t *out, int len, int peek) {
int ssl3_read_app_data(SSL *ssl, int *out_got_handshake, uint8_t *buf, int len,
int peek) {
- assert(!SSL_in_init(ssl));
- assert(ssl->s3->initial_handshake_complete);
+ assert(ssl_can_read(ssl));
*out_got_handshake = 0;
+ ssl->method->release_current_message(ssl, 0 /* don't free buffer */);
+
SSL3_RECORD *rr = &ssl->s3->rrec;
for (;;) {
@@ -345,6 +346,14 @@ int ssl3_read_app_data(SSL *ssl, int *out_got_handshake, uint8_t *buf, int len,
}
if (has_hs_data || rr->type == SSL3_RT_HANDSHAKE) {
+ /* If reading 0-RTT data, reject handshake data. 0-RTT data is terminated
+ * by an alert. */
+ if (SSL_in_init(ssl)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
/* Post-handshake data prior to TLS 1.3 is always renegotiation, which we
* never accept as a server. Otherwise |ssl3_get_message| will send
* |SSL_R_EXCESSIVE_MESSAGE_SIZE|. */
@@ -363,6 +372,24 @@ int ssl3_read_app_data(SSL *ssl, int *out_got_handshake, uint8_t *buf, int len,
return -1;
}
+ /* Handle the end_of_early_data alert. */
+ if (rr->type == SSL3_RT_ALERT &&
+ rr->length == 2 &&
+ rr->data[0] == SSL3_AL_WARNING &&
+ rr->data[1] == TLS1_AD_END_OF_EARLY_DATA &&
+ ssl->server &&
+ ssl->s3->hs != NULL &&
+ ssl->s3->hs->can_early_read &&
+ ssl3_protocol_version(ssl) >= TLS1_3_VERSION) {
+ /* Consume the record. */
+ rr->length = 0;
+ ssl_read_buffer_discard(ssl);
+ /* Stop accepting early data. */
+ ssl->s3->hs->can_early_read = 0;
+ *out_got_handshake = 1;
+ return -1;
+ }
+
if (rr->type != SSL3_RT_APPLICATION_DATA) {
OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
diff --git a/src/ssl/ssl_cipher.c b/src/ssl/ssl_cipher.c
index 4ee3c125..a72b5415 100644
--- a/src/ssl/ssl_cipher.c
+++ b/src/ssl/ssl_cipher.c
@@ -193,6 +193,7 @@ static const SSL_CIPHER kCiphers[] = {
SSL_HANDSHAKE_MAC_DEFAULT,
},
+#ifdef BORINGSSL_ENABLE_DHE_TLS
/* Cipher 33 */
{
TLS1_TXT_DHE_RSA_WITH_AES_128_SHA,
@@ -203,6 +204,7 @@ static const SSL_CIPHER kCiphers[] = {
SSL_SHA1,
SSL_HANDSHAKE_MAC_DEFAULT,
},
+#endif
/* Cipher 35 */
{
@@ -215,6 +217,7 @@ static const SSL_CIPHER kCiphers[] = {
SSL_HANDSHAKE_MAC_DEFAULT,
},
+#ifdef BORINGSSL_ENABLE_DHE_TLS
/* Cipher 39 */
{
TLS1_TXT_DHE_RSA_WITH_AES_256_SHA,
@@ -225,6 +228,7 @@ static const SSL_CIPHER kCiphers[] = {
SSL_SHA1,
SSL_HANDSHAKE_MAC_DEFAULT,
},
+#endif
/* TLS v1.2 ciphersuites */
@@ -251,6 +255,7 @@ static const SSL_CIPHER kCiphers[] = {
SSL_HANDSHAKE_MAC_SHA256,
},
+#ifdef BORINGSSL_ENABLE_DHE_TLS
/* Cipher 67 */
{
TLS1_TXT_DHE_RSA_WITH_AES_128_SHA256,
@@ -272,6 +277,7 @@ static const SSL_CIPHER kCiphers[] = {
SSL_SHA256,
SSL_HANDSHAKE_MAC_SHA256,
},
+#endif
/* PSK cipher suites. */
@@ -321,6 +327,7 @@ static const SSL_CIPHER kCiphers[] = {
SSL_HANDSHAKE_MAC_SHA384,
},
+#ifdef BORINGSSL_ENABLE_DHE_TLS
/* Cipher 9E */
{
TLS1_TXT_DHE_RSA_WITH_AES_128_GCM_SHA256,
@@ -342,6 +349,7 @@ static const SSL_CIPHER kCiphers[] = {
SSL_AEAD,
SSL_HANDSHAKE_MAC_SHA384,
},
+#endif
/* TLS 1.3 suites. */
@@ -622,9 +630,11 @@ static const CIPHER_ALIAS kCipherAliases[] = {
* e.g. kEDH combines DHE_DSS and DHE_RSA) */
{"kRSA", SSL_kRSA, ~0u, ~0u, ~0u, 0},
+#ifdef BORINGSSL_ENABLE_DHE_TLS
{"kDHE", SSL_kDHE, ~0u, ~0u, ~0u, 0},
{"kEDH", SSL_kDHE, ~0u, ~0u, ~0u, 0},
{"DH", SSL_kDHE, ~0u, ~0u, ~0u, 0},
+#endif
{"kECDHE", SSL_kECDHE, ~0u, ~0u, ~0u, 0},
{"kEECDH", SSL_kECDHE, ~0u, ~0u, ~0u, 0},
@@ -639,8 +649,10 @@ static const CIPHER_ALIAS kCipherAliases[] = {
{"aPSK", ~0u, SSL_aPSK, ~0u, ~0u, 0},
/* aliases combining key exchange and server authentication */
+#ifdef BORINGSSL_ENABLE_DHE_TLS
{"DHE", SSL_kDHE, ~0u, ~0u, ~0u, 0},
{"EDH", SSL_kDHE, ~0u, ~0u, ~0u, 0},
+#endif
{"ECDHE", SSL_kECDHE, ~0u, ~0u, ~0u, 0},
{"EECDH", SSL_kECDHE, ~0u, ~0u, ~0u, 0},
{"RSA", SSL_kRSA, SSL_aRSA, ~SSL_eNULL, ~0u, 0},
diff --git a/src/ssl/ssl_lib.c b/src/ssl/ssl_lib.c
index d16c952f..d01f6a2e 100644
--- a/src/ssl/ssl_lib.c
+++ b/src/ssl/ssl_lib.c
@@ -613,6 +613,14 @@ int SSL_accept(SSL *ssl) {
return SSL_do_handshake(ssl);
}
+int ssl_can_write(const SSL *ssl) {
+ return !SSL_in_init(ssl) || ssl->s3->hs->can_early_write;
+}
+
+int ssl_can_read(const SSL *ssl) {
+ return !SSL_in_init(ssl) || ssl->s3->hs->can_early_read;
+}
+
static int ssl_do_renegotiate(SSL *ssl) {
/* We do not accept renegotiations as a server or SSL 3.0. SSL 3.0 will be
* removed entirely in the future and requires retaining more data for
@@ -693,7 +701,7 @@ static int ssl_read_impl(SSL *ssl, void *buf, int num, int peek) {
/* Complete the current handshake, if any. False Start will cause
* |SSL_do_handshake| to return mid-handshake, so this may require multiple
* iterations. */
- while (SSL_in_init(ssl)) {
+ while (!ssl_can_read(ssl)) {
int ret = SSL_do_handshake(ssl);
if (ret < 0) {
return ret;
@@ -711,6 +719,12 @@ static int ssl_read_impl(SSL *ssl, void *buf, int num, int peek) {
return ret;
}
+ /* If we received an interrupt in early read (the end_of_early_data alert),
+ * loop again for the handshake to process it. */
+ if (SSL_in_init(ssl)) {
+ continue;
+ }
+
/* Handle the post-handshake message and try again. */
if (!ssl_do_post_handshake(ssl)) {
return -1;
@@ -741,7 +755,7 @@ int SSL_write(SSL *ssl, const void *buf, int num) {
}
/* If necessary, complete the handshake implicitly. */
- if (SSL_in_init(ssl) && !SSL_in_false_start(ssl)) {
+ if (!ssl_can_write(ssl)) {
int ret = SSL_do_handshake(ssl);
if (ret < 0) {
return ret;
@@ -821,6 +835,10 @@ void SSL_CTX_set_early_data_enabled(SSL_CTX *ctx, int enabled) {
ctx->enable_early_data = !!enabled;
}
+int SSL_early_data_accepted(const SSL *ssl) {
+ return ssl->early_data_accepted;
+}
+
static int bio_retry_reason_to_error(int reason) {
switch (reason) {
case BIO_RR_CONNECT:
@@ -920,6 +938,7 @@ int SSL_get_error(const SSL *ssl, int ret_code) {
static int set_min_version(const SSL_PROTOCOL_METHOD *method, uint16_t *out,
uint16_t version) {
+ /* Zero is interpreted as the default minimum version. */
if (version == 0) {
*out = method->min_version;
return 1;
@@ -934,6 +953,7 @@ static int set_min_version(const SSL_PROTOCOL_METHOD *method, uint16_t *out,
static int set_max_version(const SSL_PROTOCOL_METHOD *method, uint16_t *out,
uint16_t version) {
+ /* Zero is interpreted as the default maximum version. */
if (version == 0) {
*out = method->max_version;
/* TODO(svaldez): Enable TLS 1.3 by default once fully implemented. */
@@ -2397,8 +2417,9 @@ int SSL_is_server(const SSL *ssl) { return ssl->server; }
int SSL_is_dtls(const SSL *ssl) { return ssl->method->is_dtls; }
-void SSL_CTX_set_select_certificate_cb(SSL_CTX *ctx,
- int (*cb)(const SSL_CLIENT_HELLO *)) {
+void SSL_CTX_set_select_certificate_cb(
+ SSL_CTX *ctx,
+ enum ssl_select_cert_result_t (*cb)(const SSL_CLIENT_HELLO *)) {
ctx->select_certificate_cb = cb;
}
diff --git a/src/ssl/ssl_test.cc b/src/ssl/ssl_test.cc
index 6b150e8c..6678b577 100644
--- a/src/ssl/ssl_test.cc
+++ b/src/ssl/ssl_test.cc
@@ -122,14 +122,20 @@ static const CipherTest kCipherTests[] = {
false,
},
// - removes selected ciphers, but preserves their order for future
- // selections. Select AES_128_GCM, but order the key exchanges RSA, DHE_RSA,
+ // selections. Select AES_128_GCM, but order the key exchanges RSA,
// ECDHE_RSA.
{
- "ALL:-kECDHE:-kDHE:-kRSA:-ALL:"
+ "ALL:-kECDHE:"
+#ifdef BORINGSSL_ENABLE_DHE_TLS
+ "-kDHE:"
+#endif
+ "-kRSA:-ALL:"
"AESGCM+AES128+aRSA",
{
{TLS1_CK_RSA_WITH_AES_128_GCM_SHA256, 0},
+#ifdef BORINGSSL_ENABLE_DHE_TLS
{TLS1_CK_DHE_RSA_WITH_AES_128_GCM_SHA256, 0},
+#endif
{TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0},
},
false,
@@ -182,7 +188,10 @@ static const CipherTest kCipherTests[] = {
{
// To simplify things, banish all but {ECDHE_RSA,RSA} x
// {CHACHA20,AES_256_CBC,AES_128_CBC} x SHA1.
- "!kEDH:!AESGCM:!3DES:!SHA256:!SHA384:"
+#ifdef BORINGSSL_ENABLE_DHE_TLS
+ "!kEDH:"
+#endif
+ "!AESGCM:!3DES:!SHA256:!SHA384:"
// Order some ciphers backwards by strength.
"ALL:-CHACHA20:-AES256:-AES128:-ALL:"
// Select ECDHE ones and sort them by strength. Ties should resolve
@@ -791,9 +800,11 @@ typedef struct {
static const CIPHER_RFC_NAME_TEST kCipherRFCNameTests[] = {
{SSL3_CK_RSA_DES_192_CBC3_SHA, "TLS_RSA_WITH_3DES_EDE_CBC_SHA"},
{TLS1_CK_RSA_WITH_AES_128_SHA, "TLS_RSA_WITH_AES_128_CBC_SHA"},
+#ifdef BORINGSSL_ENABLE_DHE_TLS
{TLS1_CK_DHE_RSA_WITH_AES_256_SHA, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA"},
{TLS1_CK_DHE_RSA_WITH_AES_256_SHA256,
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA256"},
+#endif
{TLS1_CK_ECDHE_RSA_WITH_AES_128_SHA256,
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256"},
{TLS1_CK_ECDHE_RSA_WITH_AES_256_SHA384,
@@ -1837,11 +1848,17 @@ static bool TestRetainOnlySHA256OfCerts(bool is_dtls, const SSL_METHOD *method,
static bool ClientHelloMatches(uint16_t version, const uint8_t *expected,
size_t expected_len) {
bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
+ // Our default cipher list varies by CPU capabilities, so manually place the
+ // ChaCha20 ciphers in front.
+ const char* cipher_list =
+#ifdef BORINGSSL_ENABLE_DHE_TLS
+ "!DHE:CHACHA20:ALL";
+#else
+ "CHACHA20:ALL";
+#endif
if (!ctx ||
!SSL_CTX_set_max_proto_version(ctx.get(), version) ||
- // Our default cipher list varies by CPU capabilities, so manually place
- // the ChaCha20 ciphers in front.
- !SSL_CTX_set_strict_cipher_list(ctx.get(), "CHACHA20:ALL")) {
+ !SSL_CTX_set_strict_cipher_list(ctx.get(), cipher_list)) {
return false;
}
@@ -1887,22 +1904,20 @@ static bool TestClientHello() {
static const uint8_t kSSL3ClientHello[] = {
0x16,
0x03, 0x00,
- 0x00, 0x3f,
+ 0x00, 0x3b,
0x01,
- 0x00, 0x00, 0x3b,
+ 0x00, 0x00, 0x37,
0x03, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00,
- 0x00, 0x14,
+ 0x00, 0x10,
0xc0, 0x09,
0xc0, 0x13,
- 0x00, 0x33,
0xc0, 0x0a,
0xc0, 0x14,
- 0x00, 0x39,
0x00, 0x2f,
0x00, 0x35,
0x00, 0x0a,
@@ -1916,22 +1931,20 @@ static bool TestClientHello() {
static const uint8_t kTLS1ClientHello[] = {
0x16,
0x03, 0x01,
- 0x00, 0x5e,
+ 0x00, 0x5a,
0x01,
- 0x00, 0x00, 0x5a,
+ 0x00, 0x00, 0x56,
0x03, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00,
- 0x00, 0x12,
+ 0x00, 0x0e,
0xc0, 0x09,
0xc0, 0x13,
- 0x00, 0x33,
0xc0, 0x0a,
0xc0, 0x14,
- 0x00, 0x39,
0x00, 0x2f,
0x00, 0x35,
0x00, 0x0a,
@@ -1947,22 +1960,20 @@ static bool TestClientHello() {
static const uint8_t kTLS11ClientHello[] = {
0x16,
0x03, 0x01,
- 0x00, 0x5e,
+ 0x00, 0x5a,
0x01,
- 0x00, 0x00, 0x5a,
+ 0x00, 0x00, 0x56,
0x03, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00,
- 0x00, 0x12,
+ 0x00, 0x0e,
0xc0, 0x09,
0xc0, 0x13,
- 0x00, 0x33,
0xc0, 0x0a,
0xc0, 0x14,
- 0x00, 0x39,
0x00, 0x2f,
0x00, 0x35,
0x00, 0x0a,
@@ -1982,20 +1993,42 @@ static bool TestClientHello() {
#endif
static const uint8_t kTLS12ClientHello[] = {
- 0x16, 0x03, 0x01, 0x00, 0x9a, 0x01, 0x00, 0x00, 0x96, 0x03, 0x03, 0x00,
+ 0x16,
+ 0x03, 0x01,
+ 0x00, 0x8e,
+ 0x01,
+ 0x00, 0x00, 0x8a,
+ 0x03, 0x03,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0xcc, 0xa9,
- 0xcc, 0xa8, 0xc0, 0x2b, 0xc0, 0x2f, 0x00, 0x9e, 0xc0, 0x2c, 0xc0, 0x30,
- 0x00, 0x9f, 0xc0, 0x09, 0xc0, 0x23, 0xc0, 0x13, 0xc0, 0x27, 0x00, 0x33,
- 0x00, 0x67, 0xc0, 0x0a, 0xc0, 0x24, 0xc0, 0x14, 0xc0, 0x28, 0x00, 0x39,
- 0x00, 0x6b, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x2f, 0x00, 0x3c, 0x00, 0x35,
- 0x00, 0x3d, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x37, 0xff, 0x01, 0x00, 0x01,
- 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x0d, 0x00,
- 0x14, 0x00, 0x12, 0x04, 0x03, 0x08, 0x04, 0x04, 0x01, 0x05, 0x03, 0x08,
- 0x05, 0x05, 0x01, 0x08, 0x06, 0x06, 0x01, 0x02, 0x01, 0x00, 0x0b, 0x00,
- 0x02, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x06, 0x00, 0x1d, 0x00,
- 0x17, 0x00, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x2a,
+ 0xcc, 0xa9,
+ 0xcc, 0xa8,
+ 0xc0, 0x2b,
+ 0xc0, 0x2f,
+ 0xc0, 0x2c,
+ 0xc0, 0x30,
+ 0xc0, 0x09,
+ 0xc0, 0x23,
+ 0xc0, 0x13,
+ 0xc0, 0x27,
+ 0xc0, 0x0a,
+ 0xc0, 0x24,
+ 0xc0, 0x14,
+ 0xc0, 0x28,
+ 0x00, 0x9c,
+ 0x00, 0x9d,
+ 0x00, 0x2f,
+ 0x00, 0x3c,
+ 0x00, 0x35,
+ 0x00, 0x3d,
+ 0x00, 0x0a,
+ 0x01, 0x00, 0x00, 0x37, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x17, 0x00,
+ 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x14, 0x00, 0x12, 0x04,
+ 0x03, 0x08, 0x04, 0x04, 0x01, 0x05, 0x03, 0x08, 0x05, 0x05, 0x01, 0x08,
+ 0x06, 0x06, 0x01, 0x02, 0x01, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00,
+ 0x0a, 0x00, 0x08, 0x00, 0x06, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18,
};
if (!ClientHelloMatches(TLS1_2_VERSION, kTLS12ClientHello,
sizeof(kTLS12ClientHello))) {
@@ -2111,17 +2144,6 @@ static int SwitchSessionIDContextSNI(SSL *ssl, int *out_alert, void *arg) {
return SSL_TLSEXT_ERR_OK;
}
-static int SwitchSessionIDContextEarly(const SSL_CLIENT_HELLO *client_hello) {
- static const uint8_t kContext[] = {3};
-
- if (!SSL_set_session_id_context(client_hello->ssl, kContext,
- sizeof(kContext))) {
- return -1;
- }
-
- return 1;
-}
-
static bool TestSessionIDContext(bool is_dtls, const SSL_METHOD *method,
uint16_t version) {
bssl::UniquePtr<X509> cert = GetTestCertificate();
@@ -2193,8 +2215,18 @@ static bool TestSessionIDContext(bool is_dtls, const SSL_METHOD *method,
// Switch the session ID context with the early callback instead.
SSL_CTX_set_tlsext_servername_callback(server_ctx.get(), nullptr);
- SSL_CTX_set_select_certificate_cb(server_ctx.get(),
- SwitchSessionIDContextEarly);
+ SSL_CTX_set_select_certificate_cb(
+ server_ctx.get(),
+ [](const SSL_CLIENT_HELLO *client_hello) -> ssl_select_cert_result_t {
+ static const uint8_t kContext[] = {3};
+
+ if (!SSL_set_session_id_context(client_hello->ssl, kContext,
+ sizeof(kContext))) {
+ return ssl_select_cert_error;
+ }
+
+ return ssl_select_cert_success;
+ });
if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(), session.get(),
false /* expect session not reused */)) {
@@ -2581,12 +2613,13 @@ TEST(SSLTest, EarlyCallbackVersionSwitch) {
ASSERT_TRUE(SSL_CTX_set_max_proto_version(server_ctx.get(), TLS1_3_VERSION));
SSL_CTX_set_select_certificate_cb(
- server_ctx.get(), [](const SSL_CLIENT_HELLO *client_hello) -> int {
+ server_ctx.get(),
+ [](const SSL_CLIENT_HELLO *client_hello) -> ssl_select_cert_result_t {
if (!SSL_set_max_proto_version(client_hello->ssl, TLS1_2_VERSION)) {
- return -1;
+ return ssl_select_cert_error;
}
- return 1;
+ return ssl_select_cert_success;
});
bssl::UniquePtr<SSL> client, server;
diff --git a/src/ssl/t1_lib.c b/src/ssl/t1_lib.c
index 759d87bf..014432e7 100644
--- a/src/ssl/t1_lib.c
+++ b/src/ssl/t1_lib.c
@@ -719,6 +719,7 @@ static int ext_ri_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert,
CBS *contents) {
SSL *const ssl = hs->ssl;
if (contents != NULL && ssl3_protocol_version(ssl) >= TLS1_3_VERSION) {
+ *out_alert = SSL_AD_ILLEGAL_PARAMETER;
return 0;
}
@@ -2086,11 +2087,30 @@ static int ext_psk_key_exchange_modes_parse_clienthello(SSL_HANDSHAKE *hs,
* https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.8 */
static int ext_early_data_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
- /* TODO(svaldez): Support 0RTT. */
+ SSL *const ssl = hs->ssl;
+ uint16_t session_version;
+ if (ssl->session == NULL ||
+ !ssl->method->version_from_wire(&session_version,
+ ssl->session->ssl_version) ||
+ session_version < TLS1_3_VERSION ||
+ ssl->session->ticket_max_early_data == 0 ||
+ hs->received_hello_retry_request ||
+ !ssl->ctx->enable_early_data) {
+ return 1;
+ }
+
+ hs->early_data_offered = 1;
+
+ if (!CBB_add_u16(out, TLSEXT_TYPE_early_data) ||
+ !CBB_add_u16(out, 0) ||
+ !CBB_flush(out)) {
+ return 0;
+ }
+
return 1;
}
-static int ext_early_data_parse_clienthello(SSL_HANDSHAKE *hs,
+static int ext_early_data_parse_serverhello(SSL_HANDSHAKE *hs,
uint8_t *out_alert, CBS *contents) {
SSL *const ssl = hs->ssl;
if (contents == NULL) {
@@ -2102,11 +2122,44 @@ static int ext_early_data_parse_clienthello(SSL_HANDSHAKE *hs,
return 0;
}
- /* Since we don't currently accept 0-RTT, we have to skip past any early data
- * the client might have sent. */
- if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) {
- ssl->s3->skip_early_data = 1;
+ if (!ssl->s3->session_reused) {
+ *out_alert = SSL_AD_UNSUPPORTED_EXTENSION;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
+ return 0;
+ }
+
+ ssl->early_data_accepted = 1;
+ return 1;
+}
+
+static int ext_early_data_parse_clienthello(SSL_HANDSHAKE *hs,
+ uint8_t *out_alert, CBS *contents) {
+ SSL *const ssl = hs->ssl;
+ if (contents == NULL ||
+ ssl3_protocol_version(ssl) < TLS1_3_VERSION) {
+ return 1;
+ }
+
+ if (CBS_len(contents) != 0) {
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return 0;
}
+
+ hs->early_data_offered = 1;
+ return 1;
+}
+
+static int ext_early_data_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) {
+ if (!hs->ssl->early_data_accepted) {
+ return 1;
+ }
+
+ if (!CBB_add_u16(out, TLSEXT_TYPE_early_data) ||
+ !CBB_add_u16(out, 0) ||
+ !CBB_flush(out)) {
+ return 0;
+ }
+
return 1;
}
@@ -2597,9 +2650,9 @@ static const struct tls_extension kExtensions[] = {
TLSEXT_TYPE_early_data,
NULL,
ext_early_data_add_clienthello,
- forbid_parse_serverhello,
+ ext_early_data_parse_serverhello,
ext_early_data_parse_clienthello,
- dont_add_serverhello,
+ ext_early_data_add_serverhello,
},
{
TLSEXT_TYPE_supported_versions,
diff --git a/src/ssl/test/bssl_shim.cc b/src/ssl/test/bssl_shim.cc
index 804cbbb6..21497fd6 100644
--- a/src/ssl/test/bssl_shim.cc
+++ b/src/ssl/test/bssl_shim.cc
@@ -108,6 +108,7 @@ struct TestState {
bssl::UniquePtr<SSL_SESSION> new_session;
bool ticket_decrypt_done = false;
bool alpn_select_done = false;
+ bool is_resume = false;
bool early_callback_ready = false;
};
@@ -533,7 +534,8 @@ static bool InstallCertificate(SSL *ssl) {
return true;
}
-static int SelectCertificateCallback(const SSL_CLIENT_HELLO *client_hello) {
+static enum ssl_select_cert_result_t SelectCertificateCallback(
+ const SSL_CLIENT_HELLO *client_hello) {
const TestConfig *config = GetTestConfig(client_hello->ssl);
GetTestState(client_hello->ssl)->early_callback_called = true;
@@ -547,7 +549,7 @@ static int SelectCertificateCallback(const SSL_CLIENT_HELLO *client_hello) {
client_hello, TLSEXT_TYPE_server_name, &extension_data,
&extension_len)) {
fprintf(stderr, "Could not find server_name extension.\n");
- return -1;
+ return ssl_select_cert_error;
}
CBS_init(&extension, extension_data, extension_len);
@@ -558,7 +560,7 @@ static int SelectCertificateCallback(const SSL_CLIENT_HELLO *client_hello) {
!CBS_get_u16_length_prefixed(&server_name_list, &host_name) ||
CBS_len(&server_name_list) != 0) {
fprintf(stderr, "Could not decode server_name extension.\n");
- return -1;
+ return ssl_select_cert_error;
}
if (!CBS_mem_equal(&host_name,
@@ -569,7 +571,7 @@ static int SelectCertificateCallback(const SSL_CLIENT_HELLO *client_hello) {
}
if (config->fail_early_callback) {
- return -1;
+ return ssl_select_cert_error;
}
// Install the certificate in the early callback.
@@ -578,13 +580,13 @@ static int SelectCertificateCallback(const SSL_CLIENT_HELLO *client_hello) {
GetTestState(client_hello->ssl)->early_callback_ready;
if (config->async && !early_callback_ready) {
// Install the certificate asynchronously.
- return 0;
+ return ssl_select_cert_retry;
}
if (!InstallCertificate(client_hello->ssl)) {
- return -1;
+ return ssl_select_cert_error;
}
}
- return 1;
+ return ssl_select_cert_success;
}
static bool CheckCertificateRequest(SSL *ssl) {
@@ -763,6 +765,10 @@ static int AlpnSelectCallback(SSL* ssl, const uint8_t** out, uint8_t* outlen,
*out = (const uint8_t*)config->select_alpn.data();
*outlen = config->select_alpn.size();
+ if (GetTestState(ssl)->is_resume && config->select_resume_alpn.size() > 0) {
+ *out = (const uint8_t*)config->select_resume_alpn.data();
+ *outlen = config->select_resume_alpn.size();
+ }
return SSL_TLSEXT_ERR_OK;
}
@@ -1108,7 +1114,8 @@ static bssl::UniquePtr<SSL_CTX> SetupCtx(const TestConfig *config) {
NULL);
}
- if (!config->select_alpn.empty() || config->decline_alpn) {
+ if (!config->select_alpn.empty() || !config->select_resume_alpn.empty() ||
+ config->decline_alpn) {
SSL_CTX_set_alpn_select_cb(ssl_ctx.get(), AlpnSelectCallback, NULL);
}
@@ -1361,7 +1368,9 @@ static bool CheckHandshakeProperties(SSL *ssl, bool is_resume) {
return false;
}
- bool expect_handshake_done = is_resume || !config->false_start;
+ bool expect_handshake_done =
+ (is_resume || !config->false_start) &&
+ !(config->is_server && SSL_early_data_accepted(ssl));
if (expect_handshake_done != GetTestState(ssl)->handshake_done) {
fprintf(stderr, "handshake was%s completed\n",
GetTestState(ssl)->handshake_done ? "" : " not");
@@ -1421,13 +1430,22 @@ static bool CheckHandshakeProperties(SSL *ssl, bool is_resume) {
}
}
- if (!config->expected_alpn.empty()) {
+ std::string expected_alpn = config->expected_alpn;
+ if (is_resume && !config->expected_resume_alpn.empty()) {
+ expected_alpn = config->expected_resume_alpn;
+ }
+ bool expect_no_alpn = (!is_resume && config->expect_no_alpn) ||
+ (is_resume && config->expect_no_resume_alpn);
+ if (expect_no_alpn) {
+ expected_alpn.clear();
+ }
+
+ if (!expected_alpn.empty() || expect_no_alpn) {
const uint8_t *alpn_proto;
unsigned alpn_proto_len;
SSL_get0_alpn_selected(ssl, &alpn_proto, &alpn_proto_len);
- if (alpn_proto_len != config->expected_alpn.size() ||
- OPENSSL_memcmp(alpn_proto, config->expected_alpn.data(),
- alpn_proto_len) != 0) {
+ if (alpn_proto_len != expected_alpn.size() ||
+ OPENSSL_memcmp(alpn_proto, expected_alpn.data(), alpn_proto_len) != 0) {
fprintf(stderr, "negotiated alpn proto mismatch\n");
return false;
}
@@ -1539,6 +1557,15 @@ static bool CheckHandshakeProperties(SSL *ssl, bool is_resume) {
return false;
}
+ if (is_resume) {
+ if ((config->expect_accept_early_data && !SSL_early_data_accepted(ssl)) ||
+ (config->expect_reject_early_data && SSL_early_data_accepted(ssl))) {
+ fprintf(stderr,
+ "Early data was%s accepted, but we expected the opposite\n",
+ SSL_early_data_accepted(ssl) ? "" : " not");
+ return false;
+ }
+ }
if (!config->psk.empty()) {
if (SSL_get_peer_cert_chain(ssl) != nullptr) {
@@ -1628,6 +1655,10 @@ static bool CheckHandshakeProperties(SSL *ssl, bool is_resume) {
static bool DoExchange(bssl::UniquePtr<SSL_SESSION> *out_session,
SSL_CTX *ssl_ctx, const TestConfig *config,
bool is_resume, SSL_SESSION *session) {
+ if (is_resume && config->enable_resume_early_data) {
+ SSL_CTX_set_early_data_enabled(ssl_ctx, 1);
+ }
+
bssl::UniquePtr<SSL> ssl(SSL_new(ssl_ctx));
if (!ssl) {
return false;
@@ -1638,6 +1669,8 @@ static bool DoExchange(bssl::UniquePtr<SSL_SESSION> *out_session,
return false;
}
+ GetTestState(ssl.get())->is_resume = is_resume;
+
if (config->fallback_scsv &&
!SSL_set_mode(ssl.get(), SSL_MODE_SEND_FALLBACK_SCSV)) {
return false;
@@ -1834,20 +1867,16 @@ static bool DoExchange(bssl::UniquePtr<SSL_SESSION> *out_session,
return false;
}
- int ret;
- if (config->implicit_handshake) {
- if (config->is_server) {
- SSL_set_accept_state(ssl.get());
- } else {
- SSL_set_connect_state(ssl.get());
- }
+ if (config->is_server) {
+ SSL_set_accept_state(ssl.get());
} else {
+ SSL_set_connect_state(ssl.get());
+ }
+
+ int ret;
+ if (!config->implicit_handshake) {
do {
- if (config->is_server) {
- ret = SSL_accept(ssl.get());
- } else {
- ret = SSL_connect(ssl.get());
- }
+ ret = SSL_do_handshake(ssl.get());
} while (config->async && RetryAsync(ssl.get(), ret));
if (ret != 1 ||
!CheckHandshakeProperties(ssl.get(), is_resume)) {
@@ -1978,8 +2007,9 @@ static bool DoExchange(bssl::UniquePtr<SSL_SESSION> *out_session,
}
// After a successful read, with or without False Start, the handshake
- // must be complete.
- if (!GetTestState(ssl.get())->handshake_done) {
+ // must be complete unless we are doing early data.
+ if (!GetTestState(ssl.get())->handshake_done &&
+ !SSL_early_data_accepted(ssl.get())) {
fprintf(stderr, "handshake was not completed after SSL_read\n");
return false;
}
diff --git a/src/ssl/test/runner/cipher_suites.go b/src/ssl/test/runner/cipher_suites.go
index a2c6fbfc..3b2298e3 100644
--- a/src/ssl/test/runner/cipher_suites.go
+++ b/src/ssl/test/runner/cipher_suites.go
@@ -48,6 +48,8 @@ const (
// client indicates that it supports ECC with a curve and point format
// that we're happy with.
suiteECDHE = 1 << iota
+ // suiteDHE indicates that the cipher suite involves Diffie-Hellman.
+ suiteDHE
// suiteECDSA indicates that the cipher suite involves an ECDSA
// signature and therefore may only be selected when the server's
// certificate is ECDSA. If this is not set then the cipher suite is
@@ -120,12 +122,12 @@ var cipherSuites = []*cipherSuite{
{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, 32, 48, ivLenAES, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12 | suiteSHA384, cipherAES, macSHA384, nil},
{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, 32, 20, ivLenAES, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil},
{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, 32, 20, ivLenAES, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil},
- {TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, 16, 0, ivLenAESGCM, dheRSAKA, suiteTLS12, nil, nil, aeadAESGCM},
- {TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, 32, 0, ivLenAESGCM, dheRSAKA, suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
- {TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, 16, 32, ivLenAES, dheRSAKA, suiteTLS12, cipherAES, macSHA256, nil},
- {TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, 32, 32, ivLenAES, dheRSAKA, suiteTLS12, cipherAES, macSHA256, nil},
- {TLS_DHE_RSA_WITH_AES_128_CBC_SHA, 16, 20, ivLenAES, dheRSAKA, 0, cipherAES, macSHA1, nil},
- {TLS_DHE_RSA_WITH_AES_256_CBC_SHA, 32, 20, ivLenAES, dheRSAKA, 0, cipherAES, macSHA1, nil},
+ {TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, 16, 0, ivLenAESGCM, dheRSAKA, suiteTLS12 | suiteDHE, nil, nil, aeadAESGCM},
+ {TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, 32, 0, ivLenAESGCM, dheRSAKA, suiteTLS12 | suiteSHA384 | suiteDHE, nil, nil, aeadAESGCM},
+ {TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, 16, 32, ivLenAES, dheRSAKA, suiteTLS12 | suiteDHE, cipherAES, macSHA256, nil},
+ {TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, 32, 32, ivLenAES, dheRSAKA, suiteTLS12 | suiteDHE, cipherAES, macSHA256, nil},
+ {TLS_DHE_RSA_WITH_AES_128_CBC_SHA, 16, 20, ivLenAES, dheRSAKA, suiteDHE, cipherAES, macSHA1, nil},
+ {TLS_DHE_RSA_WITH_AES_256_CBC_SHA, 32, 20, ivLenAES, dheRSAKA, suiteDHE, cipherAES, macSHA1, nil},
{TLS_RSA_WITH_AES_128_GCM_SHA256, 16, 0, ivLenAESGCM, rsaKA, suiteTLS12, nil, nil, aeadAESGCM},
{TLS_RSA_WITH_AES_256_GCM_SHA384, 32, 0, ivLenAESGCM, rsaKA, suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
{TLS_RSA_WITH_RC4_128_SHA, 16, 20, noIV, rsaKA, suiteNoDTLS, cipherRC4, macSHA1, nil},
@@ -135,7 +137,7 @@ var cipherSuites = []*cipherSuite{
{TLS_RSA_WITH_AES_128_CBC_SHA, 16, 20, ivLenAES, rsaKA, 0, cipherAES, macSHA1, nil},
{TLS_RSA_WITH_AES_256_CBC_SHA, 32, 20, ivLenAES, rsaKA, 0, cipherAES, macSHA1, nil},
{TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, ivLen3DES, ecdheRSAKA, suiteECDHE, cipher3DES, macSHA1, nil},
- {TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, ivLen3DES, dheRSAKA, 0, cipher3DES, macSHA1, nil},
+ {TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, ivLen3DES, dheRSAKA, suiteDHE, cipher3DES, macSHA1, nil},
{TLS_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, ivLen3DES, rsaKA, 0, cipher3DES, macSHA1, nil},
{TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256, 32, 0, ivLenChaCha20Poly1305, ecdhePSKKA, suiteECDHE | suitePSK | suiteTLS12, nil, nil, aeadCHACHA20POLY1305},
{TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA, 16, 20, ivLenAES, ecdhePSKKA, suiteECDHE | suitePSK, cipherAES, macSHA1, nil},
diff --git a/src/ssl/test/runner/common.go b/src/ssl/test/runner/common.go
index 167e872b..95dcbd01 100644
--- a/src/ssl/test/runner/common.go
+++ b/src/ssl/test/runner/common.go
@@ -249,6 +249,7 @@ type ClientSessionState struct {
extendedMasterSecret bool // Whether an extended master secret was used to generate the session
sctList []byte
ocspResponse []byte
+ earlyALPN string
ticketCreationTime time.Time
ticketExpiration time.Time
ticketAgeAdd uint32
@@ -532,6 +533,10 @@ type ProtocolBugs struct {
// message.
SkipFinished bool
+ // SkipEndOfEarlyData causes the implementation to skip the
+ // end_of_early_data alert.
+ SkipEndOfEarlyData bool
+
// EarlyChangeCipherSpec causes the client to send an early
// ChangeCipherSpec message before the ClientKeyExchange. A value of
// zero disables this behavior. One and two configure variants for 0.9.8
@@ -1132,6 +1137,10 @@ type ProtocolBugs struct {
// send after the ClientHello.
SendFakeEarlyDataLength int
+ // SendStrayEarlyHandshake, if non-zero, causes the client to send a stray
+ // handshake record before sending end of early data.
+ SendStrayEarlyHandshake bool
+
// OmitEarlyDataExtension, if true, causes the early data extension to
// be omitted in the ClientHello.
OmitEarlyDataExtension bool
@@ -1146,10 +1155,26 @@ type ProtocolBugs struct {
// SendEarlyData causes a TLS 1.3 client to send the provided data
// in application data records immediately after the ClientHello,
- // provided that the client has a PSK that is appropriate for sending
- // early data and includes that PSK in its ClientHello.
+ // provided that the client offers a TLS 1.3 session. It will do this
+ // whether or not the server advertised early data for the ticket.
SendEarlyData [][]byte
+ // ExpectEarlyDataAccepted causes a TLS 1.3 client to check that early data
+ // was accepted by the server.
+ ExpectEarlyDataAccepted bool
+
+ // AlwaysAcceptEarlyData causes a TLS 1.3 server to always accept early data
+ // regardless of ALPN mismatch.
+ AlwaysAcceptEarlyData bool
+
+ // AlwaysRejectEarlyData causes a TLS 1.3 server to always reject early data.
+ AlwaysRejectEarlyData bool
+
+ // SendEarlyDataExtension, if true, causes a TLS 1.3 server to send the
+ // early_data extension in EncryptedExtensions, independent of whether
+ // it was accepted.
+ SendEarlyDataExtension bool
+
// ExpectEarlyData causes a TLS 1.3 server to read application
// data after the ClientHello (assuming the server is able to
// derive the key under which the data is encrypted) before it
@@ -1163,9 +1188,9 @@ type ProtocolBugs struct {
// Finished message.
SendHalfRTTData [][]byte
- // ExpectHalfRTTData causes a TLS 1.3 client to read application
- // data after reading the server's Finished message and before
- // sending any other handshake messages. It checks that the
+ // ExpectHalfRTTData causes a TLS 1.3 client, if 0-RTT was accepted, to
+ // read application data after reading the server's Finished message and
+ // before sending any subsequent handshake messages. It checks that the
// application data it reads matches what is provided in
// ExpectHalfRTTData and errors if the number of records or their
// content do not match.
diff --git a/src/ssl/test/runner/conn.go b/src/ssl/test/runner/conn.go
index 1bdca84d..830977da 100644
--- a/src/ssl/test/runner/conn.go
+++ b/src/ssl/test/runner/conn.go
@@ -1425,6 +1425,43 @@ func (c *Conn) Write(b []byte) (int, error) {
return n + m, c.out.setErrorLocked(err)
}
+func (c *Conn) processTLS13NewSessionTicket(newSessionTicket *newSessionTicketMsg, cipherSuite *cipherSuite) error {
+ if c.config.Bugs.ExpectGREASE && !newSessionTicket.hasGREASEExtension {
+ return errors.New("tls: no GREASE ticket extension found")
+ }
+
+ if c.config.Bugs.ExpectTicketEarlyDataInfo && newSessionTicket.maxEarlyDataSize == 0 {
+ return errors.New("tls: no ticket_early_data_info extension found")
+ }
+
+ if c.config.Bugs.ExpectNoNewSessionTicket {
+ return errors.New("tls: received unexpected NewSessionTicket")
+ }
+
+ if c.config.ClientSessionCache == nil || newSessionTicket.ticketLifetime == 0 {
+ return nil
+ }
+
+ session := &ClientSessionState{
+ sessionTicket: newSessionTicket.ticket,
+ vers: c.vers,
+ cipherSuite: cipherSuite.id,
+ masterSecret: c.resumptionSecret,
+ serverCertificates: c.peerCertificates,
+ sctList: c.sctList,
+ ocspResponse: c.ocspResponse,
+ ticketCreationTime: c.config.time(),
+ ticketExpiration: c.config.time().Add(time.Duration(newSessionTicket.ticketLifetime) * time.Second),
+ ticketAgeAdd: newSessionTicket.ticketAgeAdd,
+ maxEarlyDataSize: newSessionTicket.maxEarlyDataSize,
+ earlyALPN: c.clientProtocol,
+ }
+
+ cacheKey := clientSessionCacheKey(c.conn.RemoteAddr(), c.config)
+ c.config.ClientSessionCache.Put(cacheKey, session)
+ return nil
+}
+
func (c *Conn) handlePostHandshakeMessage() error {
msg, err := c.readHandshake()
if err != nil {
@@ -1449,39 +1486,7 @@ func (c *Conn) handlePostHandshakeMessage() error {
if c.isClient {
if newSessionTicket, ok := msg.(*newSessionTicketMsg); ok {
- if c.config.Bugs.ExpectGREASE && !newSessionTicket.hasGREASEExtension {
- return errors.New("tls: no GREASE ticket extension found")
- }
-
- if c.config.Bugs.ExpectTicketEarlyDataInfo && newSessionTicket.maxEarlyDataSize == 0 {
- return errors.New("tls: no ticket_early_data_info extension found")
- }
-
- if c.config.Bugs.ExpectNoNewSessionTicket {
- return errors.New("tls: received unexpected NewSessionTicket")
- }
-
- if c.config.ClientSessionCache == nil || newSessionTicket.ticketLifetime == 0 {
- return nil
- }
-
- session := &ClientSessionState{
- sessionTicket: newSessionTicket.ticket,
- vers: c.vers,
- cipherSuite: c.cipherSuite.id,
- masterSecret: c.resumptionSecret,
- serverCertificates: c.peerCertificates,
- sctList: c.sctList,
- ocspResponse: c.ocspResponse,
- ticketCreationTime: c.config.time(),
- ticketExpiration: c.config.time().Add(time.Duration(newSessionTicket.ticketLifetime) * time.Second),
- ticketAgeAdd: newSessionTicket.ticketAgeAdd,
- maxEarlyDataSize: newSessionTicket.maxEarlyDataSize,
- }
-
- cacheKey := clientSessionCacheKey(c.conn.RemoteAddr(), c.config)
- c.config.ClientSessionCache.Put(cacheKey, session)
- return nil
+ return c.processTLS13NewSessionTicket(newSessionTicket, c.cipherSuite)
}
}
@@ -1789,6 +1794,7 @@ func (c *Conn) SendNewSessionTicket() error {
ticketCreationTime: c.config.time(),
ticketExpiration: c.config.time().Add(time.Duration(m.ticketLifetime) * time.Second),
ticketAgeAdd: uint32(addBuffer[3])<<24 | uint32(addBuffer[2])<<16 | uint32(addBuffer[1])<<8 | uint32(addBuffer[0]),
+ earlyALPN: []byte(c.clientProtocol),
}
if !c.config.Bugs.SendEmptySessionTicket {
@@ -1798,7 +1804,6 @@ func (c *Conn) SendNewSessionTicket() error {
return err
}
}
-
c.out.Lock()
defer c.out.Unlock()
_, err = c.writeRecord(recordTypeHandshake, m.marshal())
diff --git a/src/ssl/test/runner/handshake_client.go b/src/ssl/test/runner/handshake_client.go
index bf38c1a7..d73722c5 100644
--- a/src/ssl/test/runner/handshake_client.go
+++ b/src/ssl/test/runner/handshake_client.go
@@ -330,7 +330,7 @@ NextCipherSuite:
}
var sendEarlyData bool
- if len(hello.pskIdentities) > 0 && session.maxEarlyDataSize > 0 && c.config.Bugs.SendEarlyData != nil {
+ if len(hello.pskIdentities) > 0 && c.config.Bugs.SendEarlyData != nil {
hello.hasEarlyData = true
sendEarlyData = true
}
@@ -392,7 +392,6 @@ NextCipherSuite:
finishedHash.Write(helloBytes)
earlyTrafficSecret := finishedHash.deriveSecret(earlyTrafficLabel)
c.out.useTrafficSecret(session.vers, pskCipherSuite, earlyTrafficSecret, clientWrite)
-
for _, earlyData := range c.config.Bugs.SendEarlyData {
if _, err := c.writeRecord(recordTypeApplicationData, earlyData); err != nil {
return err
@@ -861,20 +860,41 @@ func (hs *clientHandshakeState) doTLS13Handshake() error {
// If we're expecting 0.5-RTT messages from the server, read them
// now.
- for _, expectedMsg := range c.config.Bugs.ExpectHalfRTTData {
- if err := c.readRecord(recordTypeApplicationData); err != nil {
- return err
+ if encryptedExtensions.extensions.hasEarlyData {
+ // BoringSSL will always send two tickets half-RTT when
+ // negotiating 0-RTT.
+ for i := 0; i < shimConfig.HalfRTTTickets; i++ {
+ msg, err := c.readHandshake()
+ if err != nil {
+ return fmt.Errorf("tls: error reading half-RTT ticket: %s", err)
+ }
+ newSessionTicket, ok := msg.(*newSessionTicketMsg)
+ if !ok {
+ return errors.New("tls: expected half-RTT ticket")
+ }
+ if err := c.processTLS13NewSessionTicket(newSessionTicket, hs.suite); err != nil {
+ return err
+ }
}
- if !bytes.Equal(c.input.data[c.input.off:], expectedMsg) {
- return errors.New("ExpectHalfRTTData: did not get expected message")
+ for _, expectedMsg := range c.config.Bugs.ExpectHalfRTTData {
+ if err := c.readRecord(recordTypeApplicationData); err != nil {
+ return err
+ }
+ if !bytes.Equal(c.input.data[c.input.off:], expectedMsg) {
+ return errors.New("ExpectHalfRTTData: did not get expected message")
+ }
+ c.in.freeBlock(c.input)
+ c.input = nil
}
- c.in.freeBlock(c.input)
- c.input = nil
}
// Send EndOfEarlyData and then switch write key to handshake
// traffic key.
- if c.out.cipher != nil {
+ if c.out.cipher != nil && !c.config.Bugs.SkipEndOfEarlyData {
+ if c.config.Bugs.SendStrayEarlyHandshake {
+ helloRequest := new(helloRequestMsg)
+ c.writeRecord(recordTypeHandshake, helloRequest.marshal())
+ }
c.sendAlert(alertEndOfEarlyData)
}
c.out.useTrafficSecret(c.vers, hs.suite, clientHandshakeTrafficSecret, clientWrite)
@@ -1336,6 +1356,18 @@ func (hs *clientHandshakeState) processServerExtensions(serverExtensions *server
c.srtpProtectionProfile = serverExtensions.srtpProtectionProfile
}
+ if c.vers >= VersionTLS13 && c.didResume {
+ if c.config.Bugs.ExpectEarlyDataAccepted && !serverExtensions.hasEarlyData {
+ c.sendAlert(alertHandshakeFailure)
+ return errors.New("tls: server did not accept early data when expected")
+ }
+
+ if !c.config.Bugs.ExpectEarlyDataAccepted && serverExtensions.hasEarlyData {
+ c.sendAlert(alertHandshakeFailure)
+ return errors.New("tls: server accepted early data when not expected")
+ }
+ }
+
return nil
}
diff --git a/src/ssl/test/runner/handshake_server.go b/src/ssl/test/runner/handshake_server.go
index 64edd016..ef144c36 100644
--- a/src/ssl/test/runner/handshake_server.go
+++ b/src/ssl/test/runner/handshake_server.go
@@ -451,7 +451,7 @@ Curves:
var pskIndex int
foundKEMode := bytes.IndexByte(pskKEModes, pskDHEKEMode) >= 0
- if foundKEMode {
+ if foundKEMode && !config.SessionTicketsDisabled {
for i, pskIdentity := range pskIdentities {
// TODO(svaldez): Check the obfuscatedTicketAge before accepting 0-RTT.
sessionState, ok := c.decryptTicket(pskIdentity.ticket)
@@ -579,6 +579,10 @@ ResendHelloRetryRequest:
c.writeRecord(recordTypeHandshake, helloRetryRequest.marshal())
c.flushHandshake()
+ if hs.clientHello.hasEarlyData {
+ c.skipEarlyData = true
+ }
+
// Read new ClientHello.
newMsg, err := c.readHandshake()
if err != nil {
@@ -591,6 +595,10 @@ ResendHelloRetryRequest:
}
hs.writeClientHash(newClientHello.marshal())
+ if newClientHello.hasEarlyData {
+ return errors.New("tls: EarlyData sent in new ClientHello")
+ }
+
applyBugsToClientHello(newClientHello, config)
// Check that the new ClientHello matches the old ClientHello,
@@ -628,6 +636,7 @@ ResendHelloRetryRequest:
newClientHelloCopy.pskIdentities[i].obfuscatedTicketAge = identity.obfuscatedTicketAge
}
newClientHelloCopy.pskBinders = oldClientHelloCopy.pskBinders
+ newClientHelloCopy.hasEarlyData = oldClientHelloCopy.hasEarlyData
if !oldClientHelloCopy.equal(&newClientHelloCopy) {
return errors.New("tls: new ClientHello does not match")
@@ -650,10 +659,13 @@ ResendHelloRetryRequest:
}
// Decide whether or not to accept early data.
- // TODO(nharper): This does not check that ALPN or SNI matches.
- if hs.clientHello.hasEarlyData {
- if !sendHelloRetryRequest && hs.sessionState != nil {
- encryptedExtensions.extensions.hasEarlyData = true
+ if !sendHelloRetryRequest && hs.clientHello.hasEarlyData {
+ if !config.Bugs.AlwaysRejectEarlyData && hs.sessionState != nil {
+ if c.clientProtocol == string(hs.sessionState.earlyALPN) || config.Bugs.AlwaysAcceptEarlyData {
+ encryptedExtensions.extensions.hasEarlyData = true
+ }
+ }
+ if encryptedExtensions.extensions.hasEarlyData {
earlyTrafficSecret := hs.finishedHash.deriveSecret(earlyTrafficLabel)
c.in.useTrafficSecret(c.vers, hs.suite, earlyTrafficSecret, clientWrite)
@@ -673,6 +685,10 @@ ResendHelloRetryRequest:
}
}
+ if config.Bugs.SendEarlyDataExtension {
+ encryptedExtensions.extensions.hasEarlyData = true
+ }
+
// Resolve ECDHE and compute the handshake secret.
if hs.hello.hasKeyShare {
// Once a curve has been selected and a key share identified,
@@ -1166,6 +1182,11 @@ func (hs *serverHandshakeState) processClientExtensions(serverExtensions *server
}
if len(hs.clientHello.alpnProtocols) > 0 {
+ // We will never offer ALPN as a client on renegotiation
+ // handshakes.
+ if len(c.clientVerify) > 0 {
+ return errors.New("tls: offered ALPN on renegotiation")
+ }
if proto := c.config.Bugs.ALPNProtocol; proto != nil {
serverExtensions.alpnProtocol = *proto
serverExtensions.alpnProtocolEmpty = len(*proto) == 0
diff --git a/src/ssl/test/runner/runner.go b/src/ssl/test/runner/runner.go
index d90485c8..3aa2c464 100644
--- a/src/ssl/test/runner/runner.go
+++ b/src/ssl/test/runner/runner.go
@@ -65,6 +65,7 @@ var (
looseErrors = flag.Bool("loose-errors", false, "If true, allow shims to report an untranslated error code.")
shimConfigFile = flag.String("shim-config", "", "A config file to use to configure the tests for this shim.")
includeDisabled = flag.Bool("include-disabled", false, "If true, also runs disabled tests.")
+ includeDHE = flag.Bool("include-dhe", false, "If true, test DHE ciphersuites.")
repeatUntilFailure = flag.Bool("repeat-until-failure", false, "If true, the first selected test will be run repeatedly until failure.")
)
@@ -82,9 +83,16 @@ type ShimConfiguration struct {
// “:NO_SHARED_CIPHER:” (a BoringSSL error string) to something
// like “SSL_ERROR_NO_CYPHER_OVERLAP”.
ErrorMap map[string]string
+
+ // HalfRTTTickets is the number of half-RTT tickets the client should
+ // expect before half-RTT data when testing 0-RTT.
+ HalfRTTTickets int
}
-var shimConfig ShimConfiguration
+// Setup shimConfig defaults aligning with BoringSSL.
+var shimConfig ShimConfiguration = ShimConfiguration{
+ HalfRTTTickets: 2,
+}
type testCert int
@@ -1108,12 +1116,6 @@ var testCipherSuites = []testCipherSuite{
{"AES256-GCM", TLS_RSA_WITH_AES_256_GCM_SHA384},
{"AES256-SHA", TLS_RSA_WITH_AES_256_CBC_SHA},
{"AES256-SHA256", TLS_RSA_WITH_AES_256_CBC_SHA256},
- {"DHE-RSA-AES128-GCM", TLS_DHE_RSA_WITH_AES_128_GCM_SHA256},
- {"DHE-RSA-AES128-SHA", TLS_DHE_RSA_WITH_AES_128_CBC_SHA},
- {"DHE-RSA-AES128-SHA256", TLS_DHE_RSA_WITH_AES_128_CBC_SHA256},
- {"DHE-RSA-AES256-GCM", TLS_DHE_RSA_WITH_AES_256_GCM_SHA384},
- {"DHE-RSA-AES256-SHA", TLS_DHE_RSA_WITH_AES_256_CBC_SHA},
- {"DHE-RSA-AES256-SHA256", TLS_DHE_RSA_WITH_AES_256_CBC_SHA256},
{"ECDHE-ECDSA-AES128-GCM", TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
{"ECDHE-ECDSA-AES128-SHA", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA},
{"ECDHE-ECDSA-AES128-SHA256", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256},
@@ -1982,26 +1984,6 @@ func addBasicTests() {
expectedLocalError: "tls: peer did not false start: EOF",
},
{
- name: "NoFalseStart-DHE_RSA",
- config: Config{
- MaxVersion: VersionTLS12,
- CipherSuites: []uint16{TLS_DHE_RSA_WITH_AES_128_GCM_SHA256},
- NextProtos: []string{"foo"},
- Bugs: ProtocolBugs{
- ExpectFalseStart: true,
- AlertBeforeFalseStartTest: alertAccessDenied,
- },
- },
- flags: []string{
- "-false-start",
- "-advertise-alpn", "\x03foo",
- },
- shimWritesFirst: true,
- shouldFail: true,
- expectedError: ":TLSV1_ALERT_ACCESS_DENIED:",
- expectedLocalError: "tls: peer did not false start: EOF",
- },
- {
protocol: dtls,
name: "SendSplitAlert-Sync",
config: Config{
@@ -2465,6 +2447,29 @@ func addBasicTests() {
}
testCases = append(testCases, basicTests...)
+ if *includeDHE {
+ testCases = append(testCases, testCase{
+ name: "NoFalseStart-DHE_RSA",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_DHE_RSA_WITH_AES_128_GCM_SHA256},
+ NextProtos: []string{"foo"},
+ Bugs: ProtocolBugs{
+ ExpectFalseStart: true,
+ AlertBeforeFalseStartTest: alertAccessDenied,
+ },
+ },
+ flags: []string{
+ "-false-start",
+ "-advertise-alpn", "\x03foo",
+ },
+ shimWritesFirst: true,
+ shouldFail: true,
+ expectedError: ":TLSV1_ALERT_ACCESS_DENIED:",
+ expectedLocalError: "tls: peer did not false start: EOF",
+ })
+ }
+
// Test that very large messages can be received.
cert := rsaCertificate
for i := 0; i < 50; i++ {
@@ -2685,6 +2690,17 @@ func addTestForCipherSuite(suite testCipherSuite, ver tlsVersion, protocol proto
func addCipherSuiteTests() {
const bogusCipher = 0xfe00
+ if *includeDHE {
+ testCipherSuites = append(testCipherSuites, []testCipherSuite{
+ {"DHE-RSA-AES128-GCM", TLS_DHE_RSA_WITH_AES_128_GCM_SHA256},
+ {"DHE-RSA-AES128-SHA", TLS_DHE_RSA_WITH_AES_128_CBC_SHA},
+ {"DHE-RSA-AES128-SHA256", TLS_DHE_RSA_WITH_AES_128_CBC_SHA256},
+ {"DHE-RSA-AES256-GCM", TLS_DHE_RSA_WITH_AES_256_GCM_SHA384},
+ {"DHE-RSA-AES256-SHA", TLS_DHE_RSA_WITH_AES_256_CBC_SHA},
+ {"DHE-RSA-AES256-SHA256", TLS_DHE_RSA_WITH_AES_256_CBC_SHA256},
+ }...)
+ }
+
for _, suite := range testCipherSuites {
for _, ver := range tlsVersions {
for _, protocol := range []protocol{tls, dtls} {
@@ -2750,53 +2766,55 @@ func addCipherSuiteTests() {
expectedError: ":UNKNOWN_CIPHER_RETURNED:",
})
- testCases = append(testCases, testCase{
- name: "WeakDH",
- config: Config{
- MaxVersion: VersionTLS12,
- CipherSuites: []uint16{TLS_DHE_RSA_WITH_AES_128_GCM_SHA256},
- Bugs: ProtocolBugs{
- // This is a 1023-bit prime number, generated
- // with:
- // openssl gendh 1023 | openssl asn1parse -i
- DHGroupPrime: bigFromHex("518E9B7930CE61C6E445C8360584E5FC78D9137C0FFDC880B495D5338ADF7689951A6821C17A76B3ACB8E0156AEA607B7EC406EBEDBB84D8376EB8FE8F8BA1433488BEE0C3EDDFD3A32DBB9481980A7AF6C96BFCF490A094CFFB2B8192C1BB5510B77B658436E27C2D4D023FE3718222AB0CA1273995B51F6D625A4944D0DD4B"),
+ if *includeDHE {
+ testCases = append(testCases, testCase{
+ name: "WeakDH",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_DHE_RSA_WITH_AES_128_GCM_SHA256},
+ Bugs: ProtocolBugs{
+ // This is a 1023-bit prime number, generated
+ // with:
+ // openssl gendh 1023 | openssl asn1parse -i
+ DHGroupPrime: bigFromHex("518E9B7930CE61C6E445C8360584E5FC78D9137C0FFDC880B495D5338ADF7689951A6821C17A76B3ACB8E0156AEA607B7EC406EBEDBB84D8376EB8FE8F8BA1433488BEE0C3EDDFD3A32DBB9481980A7AF6C96BFCF490A094CFFB2B8192C1BB5510B77B658436E27C2D4D023FE3718222AB0CA1273995B51F6D625A4944D0DD4B"),
+ },
},
- },
- shouldFail: true,
- expectedError: ":BAD_DH_P_LENGTH:",
- })
+ shouldFail: true,
+ expectedError: ":BAD_DH_P_LENGTH:",
+ })
- testCases = append(testCases, testCase{
- name: "SillyDH",
- config: Config{
- MaxVersion: VersionTLS12,
- CipherSuites: []uint16{TLS_DHE_RSA_WITH_AES_128_GCM_SHA256},
- Bugs: ProtocolBugs{
- // This is a 4097-bit prime number, generated
- // with:
- // openssl gendh 4097 | openssl asn1parse -i
- DHGroupPrime: bigFromHex("01D366FA64A47419B0CD4A45918E8D8C8430F674621956A9F52B0CA592BC104C6E38D60C58F2CA66792A2B7EBDC6F8FFE75AB7D6862C261F34E96A2AEEF53AB7C21365C2E8FB0582F71EB57B1C227C0E55AE859E9904A25EFECD7B435C4D4357BD840B03649D4A1F8037D89EA4E1967DBEEF1CC17A6111C48F12E9615FFF336D3F07064CB17C0B765A012C850B9E3AA7A6984B96D8C867DDC6D0F4AB52042572244796B7ECFF681CD3B3E2E29AAECA391A775BEE94E502FB15881B0F4AC60314EA947C0C82541C3D16FD8C0E09BB7F8F786582032859D9C13187CE6C0CB6F2D3EE6C3C9727C15F14B21D3CD2E02BDB9D119959B0E03DC9E5A91E2578762300B1517D2352FC1D0BB934A4C3E1B20CE9327DB102E89A6C64A8C3148EDFC5A94913933853442FA84451B31FD21E492F92DD5488E0D871AEBFE335A4B92431DEC69591548010E76A5B365D346786E9A2D3E589867D796AA5E25211201D757560D318A87DFB27F3E625BC373DB48BF94A63161C674C3D4265CB737418441B7650EABC209CF675A439BEB3E9D1AA1B79F67198A40CEFD1C89144F7D8BAF61D6AD36F466DA546B4174A0E0CAF5BD788C8243C7C2DDDCC3DB6FC89F12F17D19FBD9B0BC76FE92891CD6BA07BEA3B66EF12D0D85E788FD58675C1B0FBD16029DCC4D34E7A1A41471BDEDF78BF591A8B4E96D88BEC8EDC093E616292BFC096E69A916E8D624B"),
+ testCases = append(testCases, testCase{
+ name: "SillyDH",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_DHE_RSA_WITH_AES_128_GCM_SHA256},
+ Bugs: ProtocolBugs{
+ // This is a 4097-bit prime number, generated
+ // with:
+ // openssl gendh 4097 | openssl asn1parse -i
+ DHGroupPrime: bigFromHex("01D366FA64A47419B0CD4A45918E8D8C8430F674621956A9F52B0CA592BC104C6E38D60C58F2CA66792A2B7EBDC6F8FFE75AB7D6862C261F34E96A2AEEF53AB7C21365C2E8FB0582F71EB57B1C227C0E55AE859E9904A25EFECD7B435C4D4357BD840B03649D4A1F8037D89EA4E1967DBEEF1CC17A6111C48F12E9615FFF336D3F07064CB17C0B765A012C850B9E3AA7A6984B96D8C867DDC6D0F4AB52042572244796B7ECFF681CD3B3E2E29AAECA391A775BEE94E502FB15881B0F4AC60314EA947C0C82541C3D16FD8C0E09BB7F8F786582032859D9C13187CE6C0CB6F2D3EE6C3C9727C15F14B21D3CD2E02BDB9D119959B0E03DC9E5A91E2578762300B1517D2352FC1D0BB934A4C3E1B20CE9327DB102E89A6C64A8C3148EDFC5A94913933853442FA84451B31FD21E492F92DD5488E0D871AEBFE335A4B92431DEC69591548010E76A5B365D346786E9A2D3E589867D796AA5E25211201D757560D318A87DFB27F3E625BC373DB48BF94A63161C674C3D4265CB737418441B7650EABC209CF675A439BEB3E9D1AA1B79F67198A40CEFD1C89144F7D8BAF61D6AD36F466DA546B4174A0E0CAF5BD788C8243C7C2DDDCC3DB6FC89F12F17D19FBD9B0BC76FE92891CD6BA07BEA3B66EF12D0D85E788FD58675C1B0FBD16029DCC4D34E7A1A41471BDEDF78BF591A8B4E96D88BEC8EDC093E616292BFC096E69A916E8D624B"),
+ },
},
- },
- shouldFail: true,
- expectedError: ":DH_P_TOO_LONG:",
- })
+ shouldFail: true,
+ expectedError: ":DH_P_TOO_LONG:",
+ })
- // This test ensures that Diffie-Hellman public values are padded with
- // zeros so that they're the same length as the prime. This is to avoid
- // hitting a bug in yaSSL.
- testCases = append(testCases, testCase{
- testType: serverTest,
- name: "DHPublicValuePadded",
- config: Config{
- MaxVersion: VersionTLS12,
- CipherSuites: []uint16{TLS_DHE_RSA_WITH_AES_128_GCM_SHA256},
- Bugs: ProtocolBugs{
- RequireDHPublicValueLen: (1025 + 7) / 8,
+ // This test ensures that Diffie-Hellman public values are padded with
+ // zeros so that they're the same length as the prime. This is to avoid
+ // hitting a bug in yaSSL.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "DHPublicValuePadded",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_DHE_RSA_WITH_AES_128_GCM_SHA256},
+ Bugs: ProtocolBugs{
+ RequireDHPublicValueLen: (1025 + 7) / 8,
+ },
},
- },
- flags: []string{"-use-sparse-dh-prime"},
- })
+ flags: []string{"-use-sparse-dh-prime"},
+ })
+ }
// The server must be tolerant to bogus ciphers.
testCases = append(testCases, testCase{
@@ -3383,9 +3401,11 @@ func addExtendedMasterSecretTests() {
}
type stateMachineTestConfig struct {
- protocol protocol
- async bool
- splitHandshake, packHandshakeFlight bool
+ protocol protocol
+ async bool
+ splitHandshake bool
+ packHandshakeFlight bool
+ implicitHandshake bool
}
// Adds tests that try to cover the range of the handshake state machine, under
@@ -3399,6 +3419,11 @@ func addAllStateMachineCoverageTests() {
async: async,
})
addStateMachineCoverageTests(stateMachineTestConfig{
+ protocol: protocol,
+ async: async,
+ implicitHandshake: true,
+ })
+ addStateMachineCoverageTests(stateMachineTestConfig{
protocol: protocol,
async: async,
splitHandshake: true,
@@ -3449,14 +3474,6 @@ func addStateMachineCoverageTests(config stateMachineTestConfig) {
resumeSession: true,
})
tests = append(tests, testCase{
- name: "Basic-Client-Implicit",
- config: Config{
- MaxVersion: VersionTLS12,
- },
- flags: []string{"-implicit-handshake"},
- resumeSession: true,
- })
- tests = append(tests, testCase{
testType: serverTest,
name: "Basic-Server",
config: Config{
@@ -3480,15 +3497,6 @@ func addStateMachineCoverageTests(config stateMachineTestConfig) {
})
tests = append(tests, testCase{
testType: serverTest,
- name: "Basic-Server-Implicit",
- config: Config{
- MaxVersion: VersionTLS12,
- },
- flags: []string{"-implicit-handshake"},
- resumeSession: true,
- })
- tests = append(tests, testCase{
- testType: serverTest,
name: "Basic-Server-EarlyCallback",
config: Config{
MaxVersion: VersionTLS12,
@@ -3551,6 +3559,43 @@ func addStateMachineCoverageTests(config stateMachineTestConfig) {
// Cover HelloRetryRequest during an ECDHE-PSK resumption.
resumeSession: true,
})
+
+ // TODO(svaldez): Send data on early data once implemented.
+ tests = append(tests, testCase{
+ testType: clientTest,
+ name: "TLS13-EarlyData-Client",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ MinVersion: VersionTLS13,
+ MaxEarlyDataSize: 16384,
+ },
+ resumeSession: true,
+ flags: []string{
+ "-enable-early-data",
+ "-expect-early-data-info",
+ "-expect-accept-early-data",
+ },
+ })
+
+ tests = append(tests, testCase{
+ testType: serverTest,
+ name: "TLS13-EarlyData-Server",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ MinVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendEarlyData: [][]byte{{1, 2, 3, 4}},
+ ExpectEarlyDataAccepted: true,
+ ExpectHalfRTTData: [][]byte{{254, 253, 252, 251}},
+ },
+ },
+ messageCount: 2,
+ resumeSession: true,
+ flags: []string{
+ "-enable-early-data",
+ "-expect-accept-early-data",
+ },
+ })
}
// TLS client auth.
@@ -4017,22 +4062,6 @@ func addStateMachineCoverageTests(config stateMachineTestConfig) {
resumeSession: true,
})
- // Client does False Start but doesn't explicitly call
- // SSL_connect.
- tests = append(tests, testCase{
- name: "FalseStart-Implicit",
- config: Config{
- MaxVersion: VersionTLS12,
- CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
- NextProtos: []string{"foo"},
- },
- flags: []string{
- "-implicit-handshake",
- "-false-start",
- "-advertise-alpn", "\x03foo",
- },
- })
-
// False Start without session tickets.
tests = append(tests, testCase{
name: "FalseStart-SessionTicketsDisabled",
@@ -4166,22 +4195,25 @@ func addStateMachineCoverageTests(config stateMachineTestConfig) {
flags: []string{"-check-close-notify"},
})
- // Bidirectional shutdown with the shim initiating. The runner,
- // in the meantime, sends garbage before the close_notify which
- // the shim must ignore.
- tests = append(tests, testCase{
- name: "Shutdown-Shim",
- config: Config{
- MaxVersion: VersionTLS12,
- Bugs: ProtocolBugs{
- ExpectCloseNotify: true,
+ if !config.implicitHandshake {
+ // Bidirectional shutdown with the shim initiating. The runner,
+ // in the meantime, sends garbage before the close_notify which
+ // the shim must ignore. This test is disabled under implicit
+ // handshake tests because the shim never reads or writes.
+ tests = append(tests, testCase{
+ name: "Shutdown-Shim",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ ExpectCloseNotify: true,
+ },
},
- },
- shimShutsDown: true,
- sendEmptyRecords: 1,
- sendWarningAlerts: 1,
- flags: []string{"-check-close-notify"},
- })
+ shimShutsDown: true,
+ sendEmptyRecords: 1,
+ sendWarningAlerts: 1,
+ flags: []string{"-check-close-notify"},
+ })
+ }
} else {
// TODO(davidben): DTLS 1.3 will want a similar thing for
// HelloRetryRequest.
@@ -4219,6 +4251,10 @@ func addStateMachineCoverageTests(config stateMachineTestConfig) {
test.name += "-PackHandshakeFlight"
test.config.Bugs.PackHandshakeFlight = true
}
+ if config.implicitHandshake {
+ test.name += "-ImplicitHandshake"
+ test.flags = append(test.flags, "-implicit-handshake")
+ }
testCases = append(testCases, test)
}
}
@@ -5946,8 +5982,8 @@ func addResumptionVersionTests() {
// In TLS 1.3, clients may advertise a cipher list which does not
// include the selected cipher. Test that we tolerate this. Servers may
- // resume at another cipher if the PRF matches, but BoringSSL will
- // always decline.
+ // resume at another cipher if the PRF matches and are not doing 0-RTT, but
+ // BoringSSL will always decline.
testCases = append(testCases, testCase{
testType: serverTest,
name: "Resume-Server-UnofferedCipher-TLS13",
@@ -6548,6 +6584,31 @@ func addRenegotiationTests() {
shouldFail: true,
expectedError: ":SERVER_CERT_CHANGED:",
})
+
+ // We do not negotiate ALPN after the initial handshake. This is
+ // error-prone and only risks bugs in consumers.
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "Renegotiation-ForbidALPN",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ // Forcibly negotiate ALPN on both initial and
+ // renegotiation handshakes. The test stack will
+ // internally check the client does not offer
+ // it.
+ SendALPN: "foo",
+ },
+ },
+ flags: []string{
+ "-advertise-alpn", "\x03foo\x03bar\x03baz",
+ "-expect-alpn", "foo",
+ "-renegotiate-freely",
+ },
+ renegotiate: 1,
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_EXTENSION:",
+ })
}
func addDTLSReplayTests() {
@@ -6624,7 +6685,9 @@ func addSignatureAlgorithmTests() {
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
- TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
+ }
+ if *includeDHE {
+ signingCiphers = append(signingCiphers, TLS_DHE_RSA_WITH_AES_128_CBC_SHA)
}
var allAlgorithms []signatureAlgorithm
@@ -6724,27 +6787,30 @@ func addSignatureAlgorithmTests() {
expectedError: verifyError,
})
- testCases = append(testCases, testCase{
- testType: serverTest,
- name: "ServerAuth-Sign" + suffix,
- config: Config{
- MaxVersion: ver.version,
- CipherSuites: signingCiphers,
- VerifySignatureAlgorithms: []signatureAlgorithm{
- fakeSigAlg1,
- alg.id,
- fakeSigAlg2,
+ // No signing cipher for SSL 3.0.
+ if *includeDHE || ver.version > VersionSSL30 {
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "ServerAuth-Sign" + suffix,
+ config: Config{
+ MaxVersion: ver.version,
+ CipherSuites: signingCiphers,
+ VerifySignatureAlgorithms: []signatureAlgorithm{
+ fakeSigAlg1,
+ alg.id,
+ fakeSigAlg2,
+ },
},
- },
- flags: []string{
- "-cert-file", path.Join(*resourceDir, getShimCertificate(alg.cert)),
- "-key-file", path.Join(*resourceDir, getShimKey(alg.cert)),
- "-enable-all-curves",
- },
- shouldFail: shouldSignFail,
- expectedError: signError,
- expectedPeerSignatureAlgorithm: alg.id,
- })
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, getShimCertificate(alg.cert)),
+ "-key-file", path.Join(*resourceDir, getShimKey(alg.cert)),
+ "-enable-all-curves",
+ },
+ shouldFail: shouldSignFail,
+ expectedError: signError,
+ expectedPeerSignatureAlgorithm: alg.id,
+ })
+ }
testCases = append(testCases, testCase{
name: "ServerAuth-Verify" + suffix,
@@ -7815,6 +7881,22 @@ func addCustomExtensionTests() {
flags: []string{flag},
})
+ // 0-RTT is not currently supported with Custom Extensions.
+ testCases = append(testCases, testCase{
+ testType: testType,
+ name: "CustomExtensions-" + suffix + "-EarlyData",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ CustomExtension: expectedContents,
+ ExpectedCustomExtension: &expectedContents,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":CUSTOM_EXTENSION_ERROR:",
+ flags: []string{flag, "-enable-early-data"},
+ })
+
// If the parse callback fails, the handshake should also fail.
testCases = append(testCases, testCase{
testType: testType,
@@ -8186,11 +8268,11 @@ func addCurveTests() {
MaxVersion: VersionTLS12,
CipherSuites: []uint16{
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
- TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_RSA_WITH_AES_128_GCM_SHA256,
},
CurvePreferences: []CurveID{CurveP224},
},
- expectedCipher: TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
+ expectedCipher: TLS_RSA_WITH_AES_128_GCM_SHA256,
})
// The client must reject bogus curves and disabled curves.
@@ -8611,7 +8693,8 @@ func addSessionTicketTests() {
SendTicketAge: 15 * time.Second,
},
},
- resumeSession: true,
+ resumeSession: true,
+ resumeRenewedSession: true,
flags: []string{
"-resumption-delay", "10",
"-expect-ticket-age-skew", "5",
@@ -8626,7 +8709,8 @@ func addSessionTicketTests() {
SendTicketAge: 5 * time.Second,
},
},
- resumeSession: true,
+ resumeSession: true,
+ resumeRenewedSession: true,
flags: []string{
"-resumption-delay", "10",
"-expect-ticket-age-skew", "-5",
@@ -9900,6 +9984,413 @@ func addTLS13HandshakeTests() {
},
},
})
+
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "TLS13-DataLessEarlyData-Reject-Client",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ MaxEarlyDataSize: 16384,
+ },
+ resumeConfig: &Config{
+ MaxVersion: VersionTLS13,
+ MaxEarlyDataSize: 16384,
+ Bugs: ProtocolBugs{
+ AlwaysRejectEarlyData: true,
+ },
+ },
+ resumeSession: true,
+ flags: []string{
+ "-enable-early-data",
+ "-expect-early-data-info",
+ "-expect-reject-early-data",
+ },
+ })
+
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "TLS13-DataLessEarlyData-HRR-Client",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ MaxEarlyDataSize: 16384,
+ },
+ resumeConfig: &Config{
+ MaxVersion: VersionTLS13,
+ MaxEarlyDataSize: 16384,
+ Bugs: ProtocolBugs{
+ SendHelloRetryRequestCookie: []byte{1, 2, 3, 4},
+ },
+ },
+ resumeSession: true,
+ flags: []string{
+ "-enable-early-data",
+ "-expect-early-data-info",
+ "-expect-reject-early-data",
+ },
+ })
+
+ // The client must check the server does not send the early_data
+ // extension while rejecting the session.
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "TLS13-EarlyDataWithoutResume-Client",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ MaxEarlyDataSize: 16384,
+ },
+ resumeConfig: &Config{
+ MaxVersion: VersionTLS13,
+ SessionTicketsDisabled: true,
+ Bugs: ProtocolBugs{
+ SendEarlyDataExtension: true,
+ },
+ },
+ resumeSession: true,
+ flags: []string{
+ "-enable-early-data",
+ "-expect-early-data-info",
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_EXTENSION:",
+ })
+
+ // The client must fail with a dedicated error code if the server
+ // responds with TLS 1.2 when offering 0-RTT.
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "TLS13-EarlyDataVersionDowngrade-Client",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ MaxEarlyDataSize: 16384,
+ },
+ resumeConfig: &Config{
+ MaxVersion: VersionTLS12,
+ },
+ resumeSession: true,
+ flags: []string{
+ "-enable-early-data",
+ "-expect-early-data-info",
+ },
+ shouldFail: true,
+ expectedError: ":WRONG_VERSION_ON_EARLY_DATA:",
+ })
+
+ // Test that the client rejects an (unsolicited) early_data extension if
+ // the server sent an HRR.
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "TLS13-ServerAcceptsEarlyDataOnHRR-Client",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ MaxEarlyDataSize: 16384,
+ },
+ resumeConfig: &Config{
+ MaxVersion: VersionTLS13,
+ MaxEarlyDataSize: 16384,
+ Bugs: ProtocolBugs{
+ SendHelloRetryRequestCookie: []byte{1, 2, 3, 4},
+ SendEarlyDataExtension: true,
+ },
+ },
+ resumeSession: true,
+ flags: []string{
+ "-enable-early-data",
+ "-expect-early-data-info",
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_EXTENSION:",
+ })
+
+ fooString := "foo"
+ barString := "bar"
+
+ // Test that the client reports the correct ALPN after a 0-RTT reject
+ // that changed it.
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "TLS13-DataLessEarlyData-ALPNMismatch-Client",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ MaxEarlyDataSize: 16384,
+ Bugs: ProtocolBugs{
+ ALPNProtocol: &fooString,
+ },
+ },
+ resumeConfig: &Config{
+ MaxVersion: VersionTLS13,
+ MaxEarlyDataSize: 16384,
+ Bugs: ProtocolBugs{
+ ALPNProtocol: &barString,
+ },
+ },
+ resumeSession: true,
+ flags: []string{
+ "-advertise-alpn", "\x03foo\x03bar",
+ "-enable-early-data",
+ "-expect-early-data-info",
+ "-expect-reject-early-data",
+ "-expect-alpn", "foo",
+ "-expect-resume-alpn", "bar",
+ },
+ })
+
+ // Test that the client reports the correct ALPN after a 0-RTT reject if
+ // ALPN was omitted from the first connection.
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "TLS13-DataLessEarlyData-ALPNOmitted1-Client",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ MaxEarlyDataSize: 16384,
+ },
+ resumeConfig: &Config{
+ MaxVersion: VersionTLS13,
+ MaxEarlyDataSize: 16384,
+ NextProtos: []string{"foo"},
+ },
+ resumeSession: true,
+ flags: []string{
+ "-advertise-alpn", "\x03foo\x03bar",
+ "-enable-early-data",
+ "-expect-early-data-info",
+ "-expect-reject-early-data",
+ "-expect-no-alpn",
+ "-expect-resume-alpn", "foo",
+ },
+ })
+
+ // Test that the client reports the correct ALPN after a 0-RTT reject if
+ // ALPN was omitted from the second connection.
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "TLS13-DataLessEarlyData-ALPNOmitted2-Client",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ MaxEarlyDataSize: 16384,
+ NextProtos: []string{"foo"},
+ },
+ resumeConfig: &Config{
+ MaxVersion: VersionTLS13,
+ MaxEarlyDataSize: 16384,
+ },
+ resumeSession: true,
+ flags: []string{
+ "-advertise-alpn", "\x03foo\x03bar",
+ "-enable-early-data",
+ "-expect-early-data-info",
+ "-expect-reject-early-data",
+ "-expect-alpn", "foo",
+ "-expect-no-resume-alpn",
+ },
+ })
+
+ // Test that the client enforces ALPN match on 0-RTT accept.
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "TLS13-DataLessEarlyData-BadALPNMismatch-Client",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ MaxEarlyDataSize: 16384,
+ Bugs: ProtocolBugs{
+ ALPNProtocol: &fooString,
+ },
+ },
+ resumeConfig: &Config{
+ MaxVersion: VersionTLS13,
+ MaxEarlyDataSize: 16384,
+ Bugs: ProtocolBugs{
+ AlwaysAcceptEarlyData: true,
+ ALPNProtocol: &barString,
+ },
+ },
+ resumeSession: true,
+ flags: []string{
+ "-advertise-alpn", "\x03foo\x03bar",
+ "-enable-early-data",
+ "-expect-early-data-info",
+ },
+ shouldFail: true,
+ expectedError: ":ALPN_MISMATCH_ON_EARLY_DATA:",
+ })
+
+ // Test that the server correctly rejects 0-RTT when the previous
+ // session did not allow early data on resumption.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "TLS13-EarlyData-NonZeroRTTSession-Server",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ },
+ resumeConfig: &Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendEarlyData: [][]byte{{1, 2, 3, 4}},
+ ExpectEarlyDataAccepted: false,
+ },
+ },
+ resumeSession: true,
+ flags: []string{
+ "-enable-resume-early-data",
+ "-expect-reject-early-data",
+ },
+ })
+
+ // Test that we reject early data where ALPN is omitted from the first
+ // connection.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "TLS13-EarlyData-ALPNOmitted1-Server",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ NextProtos: []string{},
+ },
+ resumeConfig: &Config{
+ MaxVersion: VersionTLS13,
+ NextProtos: []string{"foo"},
+ Bugs: ProtocolBugs{
+ SendEarlyData: [][]byte{{1, 2, 3, 4}},
+ ExpectEarlyDataAccepted: false,
+ },
+ },
+ resumeSession: true,
+ flags: []string{
+ "-enable-early-data",
+ "-select-alpn", "",
+ "-select-resume-alpn", "foo",
+ },
+ })
+
+ // Test that we reject early data where ALPN is omitted from the second
+ // connection.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "TLS13-EarlyData-ALPNOmitted2-Server",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ NextProtos: []string{"foo"},
+ },
+ resumeConfig: &Config{
+ MaxVersion: VersionTLS13,
+ NextProtos: []string{},
+ Bugs: ProtocolBugs{
+ SendEarlyData: [][]byte{{1, 2, 3, 4}},
+ ExpectEarlyDataAccepted: false,
+ },
+ },
+ resumeSession: true,
+ flags: []string{
+ "-enable-early-data",
+ "-select-alpn", "foo",
+ "-select-resume-alpn", "",
+ },
+ })
+
+ // Test that we reject early data with mismatched ALPN.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "TLS13-EarlyData-ALPNMismatch-Server",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ NextProtos: []string{"foo"},
+ },
+ resumeConfig: &Config{
+ MaxVersion: VersionTLS13,
+ NextProtos: []string{"bar"},
+ Bugs: ProtocolBugs{
+ SendEarlyData: [][]byte{{1, 2, 3, 4}},
+ ExpectEarlyDataAccepted: false,
+ },
+ },
+ resumeSession: true,
+ flags: []string{
+ "-enable-early-data",
+ "-select-alpn", "foo",
+ "-select-resume-alpn", "bar",
+ },
+ })
+
+ // Test that we fail on early data with Channel ID.
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "TLS13-EarlyData-ChannelID-Client",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ MaxEarlyDataSize: 16384,
+ RequestChannelID: true,
+ },
+ resumeSession: true,
+ expectChannelID: true,
+ shouldFail: true,
+ expectedError: ":CHANNEL_ID_ON_EARLY_DATA:",
+ flags: []string{
+ "-enable-early-data",
+ "-expect-early-data-info",
+ "-send-channel-id", path.Join(*resourceDir, channelIDKeyFile),
+ },
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "TLS13-EarlyData-ChannelID-Server",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ ChannelID: channelIDKey,
+ Bugs: ProtocolBugs{
+ SendEarlyData: [][]byte{{}},
+ ExpectEarlyDataAccepted: false,
+ },
+ },
+ resumeSession: true,
+ expectChannelID: true,
+ flags: []string{
+ "-enable-early-data",
+ "-expect-reject-early-data",
+ "-expect-channel-id",
+ base64.StdEncoding.EncodeToString(channelIDBytes),
+ },
+ })
+
+ // Test that the server rejects 0-RTT streams without end_of_early_data.
+ // The subsequent records should fail to decrypt.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "TLS13-EarlyData-SkipEndOfEarlyData",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendEarlyData: [][]byte{{1, 2, 3, 4}},
+ ExpectEarlyDataAccepted: true,
+ SkipEndOfEarlyData: true,
+ },
+ },
+ resumeSession: true,
+ flags: []string{"-enable-early-data"},
+ shouldFail: true,
+ expectedLocalError: "remote error: bad record MAC",
+ expectedError: ":BAD_DECRYPT:",
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "TLS13-EarlyData-UnexpectedHandshake-Server",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ },
+ resumeConfig: &Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendEarlyData: [][]byte{{1, 2, 3, 4}},
+ SendStrayEarlyHandshake: true,
+ ExpectEarlyDataAccepted: true},
+ },
+ resumeSession: true,
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_RECORD:",
+ expectedLocalError: "remote error: unexpected message",
+ flags: []string{
+ "-enable-early-data",
+ },
+ })
}
func addTLS13CipherPreferenceTests() {
diff --git a/src/ssl/test/runner/ticket.go b/src/ssl/test/runner/ticket.go
index 4a4540c5..10ac54f7 100644
--- a/src/ssl/test/runner/ticket.go
+++ b/src/ssl/test/runner/ticket.go
@@ -25,6 +25,7 @@ type sessionState struct {
handshakeHash []byte
certificates [][]byte
extendedMasterSecret bool
+ earlyALPN []byte
ticketCreationTime time.Time
ticketExpiration time.Time
ticketFlags uint32
@@ -58,6 +59,9 @@ func (s *sessionState) marshal() []byte {
msg.addU32(s.ticketAgeAdd)
}
+ earlyALPN := msg.addU16LengthPrefixed()
+ earlyALPN.addBytes(s.earlyALPN)
+
return msg.finish()
}
@@ -138,6 +142,14 @@ func (s *sessionState) unmarshal(data []byte) bool {
data = data[4:]
}
+ earlyALPNLen := int(data[0])<<8 | int(data[1])
+ data = data[2:]
+ if len(data) < earlyALPNLen {
+ return false
+ }
+ s.earlyALPN = data[:earlyALPNLen]
+ data = data[earlyALPNLen:]
+
if len(data) > 0 {
return false
}
diff --git a/src/ssl/test/test_config.cc b/src/ssl/test/test_config.cc
index e5815819..7e57543e 100644
--- a/src/ssl/test/test_config.cc
+++ b/src/ssl/test/test_config.cc
@@ -85,6 +85,7 @@ const Flag<bool> kBoolFlags[] = {
{ "-use-ticket-callback", &TestConfig::use_ticket_callback },
{ "-renew-ticket", &TestConfig::renew_ticket },
{ "-enable-early-data", &TestConfig::enable_early_data },
+ { "-enable-resume-early-data", &TestConfig::enable_resume_early_data },
{ "-enable-client-custom-extension",
&TestConfig::enable_client_custom_extension },
{ "-enable-server-custom-extension",
@@ -123,6 +124,10 @@ const Flag<bool> kBoolFlags[] = {
&TestConfig::expect_no_secure_renegotiation },
{ "-expect-session-id", &TestConfig::expect_session_id },
{ "-expect-no-session-id", &TestConfig::expect_no_session_id },
+ { "-expect-accept-early-data", &TestConfig::expect_accept_early_data },
+ { "-expect-reject-early-data", &TestConfig::expect_reject_early_data },
+ { "-expect-no-alpn", &TestConfig::expect_no_alpn },
+ { "-expect-no-resume-alpn", &TestConfig::expect_no_resume_alpn },
};
const Flag<std::string> kStringFlags[] = {
@@ -137,8 +142,10 @@ const Flag<std::string> kStringFlags[] = {
{ "-host-name", &TestConfig::host_name },
{ "-advertise-alpn", &TestConfig::advertise_alpn },
{ "-expect-alpn", &TestConfig::expected_alpn },
+ { "-expect-resume-alpn", &TestConfig::expected_resume_alpn },
{ "-expect-advertised-alpn", &TestConfig::expected_advertised_alpn },
{ "-select-alpn", &TestConfig::select_alpn },
+ { "-select-resume-alpn", &TestConfig::select_resume_alpn },
{ "-psk", &TestConfig::psk },
{ "-psk-identity", &TestConfig::psk_identity },
{ "-srtp-profiles", &TestConfig::srtp_profiles },
diff --git a/src/ssl/test/test_config.h b/src/ssl/test/test_config.h
index 7057b486..fadd05eb 100644
--- a/src/ssl/test/test_config.h
+++ b/src/ssl/test/test_config.h
@@ -52,8 +52,12 @@ struct TestConfig {
std::string host_name;
std::string advertise_alpn;
std::string expected_alpn;
+ std::string expected_resume_alpn;
+ bool expect_no_alpn = false;
+ bool expect_no_resume_alpn = false;
std::string expected_advertised_alpn;
std::string select_alpn;
+ std::string select_resume_alpn;
bool decline_alpn = false;
bool expect_session_miss = false;
bool expect_extended_master_secret = false;
@@ -84,9 +88,12 @@ struct TestConfig {
bool expect_ticket_renewal = false;
bool expect_no_session = false;
bool expect_early_data_info = false;
+ bool expect_accept_early_data = false;
+ bool expect_reject_early_data = false;
bool use_ticket_callback = false;
bool renew_ticket = false;
bool enable_early_data = false;
+ bool enable_resume_early_data = false;
bool enable_client_custom_extension = false;
bool enable_server_custom_extension = false;
bool custom_extension_skip = false;
diff --git a/src/ssl/tls13_both.c b/src/ssl/tls13_both.c
index 62439235..ec67cdc1 100644
--- a/src/ssl/tls13_both.c
+++ b/src/ssl/tls13_both.c
@@ -33,7 +33,7 @@
* without being able to return application data. */
static const uint8_t kMaxKeyUpdates = 32;
-int tls13_handshake(SSL_HANDSHAKE *hs) {
+int tls13_handshake(SSL_HANDSHAKE *hs, int *out_early_return) {
SSL *const ssl = hs->ssl;
for (;;) {
/* Resolve the operation the handshake was waiting on. */
@@ -64,6 +64,16 @@ int tls13_handshake(SSL_HANDSHAKE *hs) {
break;
}
+ case ssl_hs_read_end_of_early_data: {
+ if (ssl->s3->hs->can_early_read) {
+ /* While we are processing early data, the handshake returns early. */
+ *out_early_return = 1;
+ return 1;
+ }
+ hs->wait = ssl_hs_ok;
+ break;
+ }
+
case ssl_hs_x509_lookup:
ssl->rwstate = SSL_X509_LOOKUP;
hs->wait = ssl_hs_ok;
@@ -402,12 +412,21 @@ err:
return ret;
}
-int tls13_process_finished(SSL_HANDSHAKE *hs) {
+int tls13_process_finished(SSL_HANDSHAKE *hs, int use_saved_value) {
SSL *const ssl = hs->ssl;
- uint8_t verify_data[EVP_MAX_MD_SIZE];
+ uint8_t verify_data_buf[EVP_MAX_MD_SIZE];
+ const uint8_t *verify_data;
size_t verify_data_len;
- if (!tls13_finished_mac(hs, verify_data, &verify_data_len, !ssl->server)) {
- return 0;
+ if (use_saved_value) {
+ assert(ssl->server);
+ verify_data = hs->expected_client_finished;
+ verify_data_len = hs->hash_len;
+ } else {
+ if (!tls13_finished_mac(hs, verify_data_buf, &verify_data_len,
+ !ssl->server)) {
+ return 0;
+ }
+ verify_data = verify_data_buf;
}
int finished_ok =
diff --git a/src/ssl/tls13_client.c b/src/ssl/tls13_client.c
index f13a4f78..0d60661c 100644
--- a/src/ssl/tls13_client.c
+++ b/src/ssl/tls13_client.c
@@ -37,6 +37,7 @@ enum client_hs_state_t {
state_process_server_certificate,
state_process_server_certificate_verify,
state_process_server_finished,
+ state_send_end_of_early_data,
state_send_client_certificate,
state_send_client_certificate_verify,
state_complete_client_certificate_verify,
@@ -144,7 +145,11 @@ static enum ssl_hs_wait_t do_process_hello_retry_request(SSL_HANDSHAKE *hs) {
}
static enum ssl_hs_wait_t do_send_second_client_hello(SSL_HANDSHAKE *hs) {
- if (!ssl_write_client_hello(hs)) {
+ SSL *const ssl = hs->ssl;
+ /* TODO(svaldez): Ensure that we set can_early_write to false since 0-RTT is
+ * rejected if we receive a HelloRetryRequest. */
+ if (!ssl->method->set_write_state(ssl, NULL) ||
+ !ssl_write_client_hello(hs)) {
return ssl_hs_error;
}
@@ -254,7 +259,6 @@ static enum ssl_hs_wait_t do_process_server_hello(SSL_HANDSHAKE *hs) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
return ssl_hs_error;
}
- ssl_set_session(ssl, NULL);
/* Resumption incorporates fresh key material, so refresh the timeout. */
ssl_session_renew_timeout(ssl, hs->new_session,
@@ -267,17 +271,6 @@ static enum ssl_hs_wait_t do_process_server_hello(SSL_HANDSHAKE *hs) {
hs->new_session->cipher = cipher;
hs->new_cipher = cipher;
- /* Store the initial negotiated ALPN in the session. */
- if (ssl->s3->alpn_selected != NULL) {
- hs->new_session->early_alpn =
- BUF_memdup(ssl->s3->alpn_selected, ssl->s3->alpn_selected_len);
- if (hs->new_session->early_alpn == NULL) {
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
- return ssl_hs_error;
- }
- hs->new_session->early_alpn_len = ssl->s3->alpn_selected_len;
- }
-
/* The PRF hash is now known. Set up the key schedule. */
if (!tls13_init_key_schedule(hs)) {
return ssl_hs_error;
@@ -319,7 +312,13 @@ static enum ssl_hs_wait_t do_process_server_hello(SSL_HANDSHAKE *hs) {
if (!ssl_hash_current_message(hs) ||
!tls13_derive_handshake_secrets(hs) ||
!tls13_set_traffic_key(ssl, evp_aead_open, hs->server_handshake_secret,
- hs->hash_len) ||
+ hs->hash_len)) {
+ return ssl_hs_error;
+ }
+
+ /* If not sending early data, set client traffic keys now so that alerts are
+ * encrypted. */
+ if (!hs->early_data_offered &&
!tls13_set_traffic_key(ssl, evp_aead_seal, hs->client_handshake_secret,
hs->hash_len)) {
return ssl_hs_error;
@@ -347,6 +346,36 @@ static enum ssl_hs_wait_t do_process_encrypted_extensions(SSL_HANDSHAKE *hs) {
return ssl_hs_error;
}
+ /* Store the negotiated ALPN in the session. */
+ if (ssl->s3->alpn_selected != NULL) {
+ hs->new_session->early_alpn =
+ BUF_memdup(ssl->s3->alpn_selected, ssl->s3->alpn_selected_len);
+ if (hs->new_session->early_alpn == NULL) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ return ssl_hs_error;
+ }
+ hs->new_session->early_alpn_len = ssl->s3->alpn_selected_len;
+ }
+
+ if (ssl->early_data_accepted) {
+ if (ssl->session->cipher != hs->new_session->cipher ||
+ ssl->session->early_alpn_len != ssl->s3->alpn_selected_len ||
+ OPENSSL_memcmp(ssl->session->early_alpn, ssl->s3->alpn_selected,
+ ssl->s3->alpn_selected_len) != 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_ALPN_MISMATCH_ON_EARLY_DATA);
+ return ssl_hs_error;
+ }
+ if (ssl->s3->tlsext_channel_id_valid) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CHANNEL_ID_ON_EARLY_DATA);
+ return ssl_hs_error;
+ }
+ }
+
+ /* Release offered session now that it is no longer needed. */
+ if (ssl->s3->session_reused) {
+ ssl_set_session(ssl, NULL);
+ }
+
if (!ssl_hash_current_message(hs)) {
return ssl_hs_error;
}
@@ -441,7 +470,7 @@ static enum ssl_hs_wait_t do_process_server_certificate_verify(
static enum ssl_hs_wait_t do_process_server_finished(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
if (!ssl_check_message_type(ssl, SSL3_MT_FINISHED) ||
- !tls13_process_finished(hs) ||
+ !tls13_process_finished(hs, 0 /* don't use saved value */) ||
!ssl_hash_current_message(hs) ||
/* Update the secret to the master secret and derive traffic keys. */
!tls13_advance_key_schedule(hs, kZeroes, hs->hash_len) ||
@@ -450,12 +479,32 @@ static enum ssl_hs_wait_t do_process_server_finished(SSL_HANDSHAKE *hs) {
}
ssl->method->received_flight(ssl);
+ hs->tls13_state = state_send_end_of_early_data;
+ return ssl_hs_ok;
+}
+
+static enum ssl_hs_wait_t do_send_end_of_early_data(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ /* TODO(svaldez): Stop sending early data. */
+ if (ssl->early_data_accepted &&
+ !ssl->method->add_alert(ssl, SSL3_AL_WARNING,
+ TLS1_AD_END_OF_EARLY_DATA)) {
+ return ssl_hs_error;
+ }
+
+ if (hs->early_data_offered &&
+ !tls13_set_traffic_key(ssl, evp_aead_seal, hs->client_handshake_secret,
+ hs->hash_len)) {
+ return ssl_hs_error;
+ }
+
hs->tls13_state = state_send_client_certificate;
return ssl_hs_ok;
}
static enum ssl_hs_wait_t do_send_client_certificate(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
+
/* The peer didn't request a certificate. */
if (!hs->cert_request) {
hs->tls13_state = state_complete_second_flight;
@@ -581,6 +630,9 @@ enum ssl_hs_wait_t tls13_client_handshake(SSL_HANDSHAKE *hs) {
case state_process_server_finished:
ret = do_process_server_finished(hs);
break;
+ case state_send_end_of_early_data:
+ ret = do_send_end_of_early_data(hs);
+ break;
case state_send_client_certificate:
ret = do_send_client_certificate(hs);
break;
diff --git a/src/ssl/tls13_enc.c b/src/ssl/tls13_enc.c
index 412705da..3a7009c8 100644
--- a/src/ssl/tls13_enc.c
+++ b/src/ssl/tls13_enc.c
@@ -28,22 +28,43 @@
#include "internal.h"
-int tls13_init_key_schedule(SSL_HANDSHAKE *hs) {
- if (!SSL_TRANSCRIPT_init_hash(&hs->transcript, ssl3_protocol_version(hs->ssl),
- hs->new_cipher->algorithm_prf)) {
+static int init_key_schedule(SSL_HANDSHAKE *hs, uint16_t version,
+ int algorithm_prf) {
+ if (!SSL_TRANSCRIPT_init_hash(&hs->transcript, version, algorithm_prf)) {
return 0;
}
-
hs->hash_len = SSL_TRANSCRIPT_digest_len(&hs->transcript);
/* Initialize the secret to the zero key. */
OPENSSL_memset(hs->secret, 0, hs->hash_len);
+ return 1;
+}
+
+int tls13_init_key_schedule(SSL_HANDSHAKE *hs) {
+ if (!init_key_schedule(hs, ssl3_protocol_version(hs->ssl),
+ hs->new_cipher->algorithm_prf)) {
+ return 0;
+ }
+
SSL_TRANSCRIPT_free_buffer(&hs->transcript);
return 1;
}
+int tls13_init_early_key_schedule(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ uint16_t session_version;
+ if (!ssl->method->version_from_wire(&session_version,
+ ssl->session->ssl_version) ||
+ !init_key_schedule(hs, session_version,
+ ssl->session->cipher->algorithm_prf)) {
+ return 0;
+ }
+
+ return 1;
+}
+
int tls13_advance_key_schedule(SSL_HANDSHAKE *hs, const uint8_t *in,
size_t len) {
return HKDF_extract(hs->secret, &hs->hash_len,
@@ -100,6 +121,13 @@ static int derive_secret(SSL_HANDSHAKE *hs, uint8_t *out, size_t len,
int tls13_set_traffic_key(SSL *ssl, enum evp_aead_direction_t direction,
const uint8_t *traffic_secret,
size_t traffic_secret_len) {
+ const SSL_SESSION *session = SSL_get_session(ssl);
+ uint16_t version;
+ if (!ssl->method->version_from_wire(&version, session->ssl_version)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
if (traffic_secret_len > 0xff) {
OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
return 0;
@@ -108,14 +136,13 @@ int tls13_set_traffic_key(SSL *ssl, enum evp_aead_direction_t direction,
/* Look up cipher suite properties. */
const EVP_AEAD *aead;
size_t discard;
- if (!ssl_cipher_get_evp_aead(&aead, &discard, &discard,
- SSL_get_session(ssl)->cipher,
- ssl3_protocol_version(ssl))) {
+ if (!ssl_cipher_get_evp_aead(&aead, &discard, &discard, session->cipher,
+ version)) {
return 0;
}
const EVP_MD *digest = ssl_get_handshake_digest(
- SSL_get_session(ssl)->cipher->algorithm_prf, ssl3_protocol_version(ssl));
+ session->cipher->algorithm_prf, version);
/* Derive the key. */
size_t key_len = EVP_AEAD_key_length(aead);
@@ -134,8 +161,7 @@ int tls13_set_traffic_key(SSL *ssl, enum evp_aead_direction_t direction,
}
SSL_AEAD_CTX *traffic_aead = SSL_AEAD_CTX_new(
- direction, ssl3_protocol_version(ssl), SSL_get_session(ssl)->cipher, key,
- key_len, NULL, 0, iv, iv_len);
+ direction, version, session->cipher, key, key_len, NULL, 0, iv, iv_len);
if (traffic_aead == NULL) {
return 0;
}
@@ -164,6 +190,11 @@ int tls13_set_traffic_key(SSL *ssl, enum evp_aead_direction_t direction,
return 1;
}
+static const char kTLS13LabelExporter[] = "exporter master secret";
+static const char kTLS13LabelEarlyExporter[] = "early exporter master secret";
+
+static const char kTLS13LabelClientEarlyTraffic[] =
+ "client early traffic secret";
static const char kTLS13LabelClientHandshakeTraffic[] =
"client handshake traffic secret";
static const char kTLS13LabelServerHandshakeTraffic[] =
@@ -173,6 +204,18 @@ static const char kTLS13LabelClientApplicationTraffic[] =
static const char kTLS13LabelServerApplicationTraffic[] =
"server application traffic secret";
+int tls13_derive_early_secrets(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ return derive_secret(hs, hs->early_traffic_secret, hs->hash_len,
+ (const uint8_t *)kTLS13LabelClientEarlyTraffic,
+ strlen(kTLS13LabelClientEarlyTraffic)) &&
+ ssl_log_secret(ssl, "CLIENT_EARLY_TRAFFIC_SECRET",
+ hs->early_traffic_secret, hs->hash_len) &&
+ derive_secret(hs, ssl->s3->early_exporter_secret, hs->hash_len,
+ (const uint8_t *)kTLS13LabelEarlyExporter,
+ strlen(kTLS13LabelEarlyExporter));
+}
+
int tls13_derive_handshake_secrets(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
return derive_secret(hs, hs->client_handshake_secret, hs->hash_len,
@@ -187,8 +230,6 @@ int tls13_derive_handshake_secrets(SSL_HANDSHAKE *hs) {
hs->server_handshake_secret, hs->hash_len);
}
-static const char kTLS13LabelExporter[] = "exporter master secret";
-
int tls13_derive_application_secrets(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
ssl->s3->exporter_secret_len = hs->hash_len;
@@ -270,13 +311,11 @@ static int tls13_verify_data(const EVP_MD *digest, uint8_t *out,
int tls13_finished_mac(SSL_HANDSHAKE *hs, uint8_t *out, size_t *out_len,
int is_server) {
- SSL *const ssl = hs->ssl;
-
const uint8_t *traffic_secret;
- if (is_server == ssl->server) {
- traffic_secret = ssl->s3->write_traffic_secret;
+ if (is_server) {
+ traffic_secret = hs->server_handshake_secret;
} else {
- traffic_secret = ssl->s3->read_traffic_secret;
+ traffic_secret = hs->client_handshake_secret;
}
uint8_t context_hash[EVP_MAX_MD_SIZE];
diff --git a/src/ssl/tls13_server.c b/src/ssl/tls13_server.c
index 9c8d1a15..35ee4f74 100644
--- a/src/ssl/tls13_server.c
+++ b/src/ssl/tls13_server.c
@@ -43,6 +43,8 @@ enum server_hs_state_t {
state_send_server_certificate_verify,
state_complete_server_certificate_verify,
state_send_server_finished,
+ state_read_second_client_flight,
+ state_process_end_of_early_data,
state_process_client_certificate,
state_process_client_certificate_verify,
state_process_channel_id,
@@ -134,6 +136,68 @@ static const SSL_CIPHER *choose_tls13_cipher(
return best;
}
+static int add_new_session_tickets(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ /* TLS 1.3 recommends single-use tickets, so issue multiple tickets in case
+ * the client makes several connections before getting a renewal. */
+ static const int kNumTickets = 2;
+
+ SSL_SESSION *session = hs->new_session;
+ CBB cbb;
+ CBB_zero(&cbb);
+
+ /* Rebase the session timestamp so that it is measured from ticket
+ * issuance. */
+ ssl_session_rebase_time(ssl, session);
+
+ for (int i = 0; i < kNumTickets; i++) {
+ if (!RAND_bytes((uint8_t *)&session->ticket_age_add, 4)) {
+ goto err;
+ }
+ session->ticket_age_add_valid = 1;
+
+ CBB body, ticket, extensions;
+ if (!ssl->method->init_message(ssl, &cbb, &body,
+ SSL3_MT_NEW_SESSION_TICKET) ||
+ !CBB_add_u32(&body, session->timeout) ||
+ !CBB_add_u32(&body, session->ticket_age_add) ||
+ !CBB_add_u16_length_prefixed(&body, &ticket) ||
+ !ssl_encrypt_ticket(ssl, &ticket, session) ||
+ !CBB_add_u16_length_prefixed(&body, &extensions)) {
+ goto err;
+ }
+
+ if (ssl->ctx->enable_early_data) {
+ session->ticket_max_early_data = kMaxEarlyDataAccepted;
+
+ CBB early_data_info;
+ if (!CBB_add_u16(&extensions, TLSEXT_TYPE_ticket_early_data_info) ||
+ !CBB_add_u16_length_prefixed(&extensions, &early_data_info) ||
+ !CBB_add_u32(&early_data_info, session->ticket_max_early_data) ||
+ !CBB_flush(&extensions)) {
+ goto err;
+ }
+ }
+
+ /* Add a fake extension. See draft-davidben-tls-grease-01. */
+ if (!CBB_add_u16(&extensions,
+ ssl_get_grease_value(ssl, ssl_grease_ticket_extension)) ||
+ !CBB_add_u16(&extensions, 0 /* empty */)) {
+ goto err;
+ }
+
+ if (!ssl_add_message_cbb(ssl, &cbb)) {
+ goto err;
+ }
+ }
+
+ return 1;
+
+err:
+ CBB_cleanup(&cbb);
+ return 0;
+}
+
static enum ssl_hs_wait_t do_select_parameters(SSL_HANDSHAKE *hs) {
/* At this point, most ClientHello extensions have already been processed by
* the common handshake logic. Resolve the remaining non-PSK parameters. */
@@ -289,6 +353,21 @@ static enum ssl_hs_wait_t do_select_session(SSL_HANDSHAKE *hs) {
/* Carry over authentication information from the previous handshake into
* a fresh session. */
hs->new_session = SSL_SESSION_dup(session, SSL_SESSION_DUP_AUTH_ONLY);
+
+ if (/* Early data must be acceptable for this ticket. */
+ ssl->ctx->enable_early_data &&
+ session->ticket_max_early_data != 0 &&
+ /* The client must have offered early data. */
+ hs->early_data_offered &&
+ /* Channel ID is incompatible with 0-RTT. */
+ !ssl->s3->tlsext_channel_id_valid &&
+ /* The negotiated ALPN must match the one in the ticket. */
+ ssl->s3->alpn_selected_len == session->early_alpn_len &&
+ OPENSSL_memcmp(ssl->s3->alpn_selected, session->early_alpn,
+ ssl->s3->alpn_selected_len) == 0) {
+ ssl->early_data_accepted = 1;
+ }
+
SSL_SESSION_free(session);
if (hs->new_session == NULL) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
@@ -323,6 +402,7 @@ static enum ssl_hs_wait_t do_select_session(SSL_HANDSHAKE *hs) {
}
}
+ /* Store the initial negotiated ALPN in the session. */
if (ssl->s3->alpn_selected != NULL) {
hs->new_session->early_alpn =
BUF_memdup(ssl->s3->alpn_selected, ssl->s3->alpn_selected_len);
@@ -351,12 +431,22 @@ static enum ssl_hs_wait_t do_select_session(SSL_HANDSHAKE *hs) {
return ssl_hs_error;
}
+ if (ssl->early_data_accepted) {
+ if (!tls13_derive_early_secrets(hs)) {
+ return ssl_hs_error;
+ }
+ } else if (hs->early_data_offered) {
+ ssl->s3->skip_early_data = 1;
+ }
+
ssl->method->received_flight(ssl);
/* Resolve ECDHE and incorporate it into the secret. */
int need_retry;
if (!resolve_ecdhe_secret(hs, &need_retry, &client_hello)) {
if (need_retry) {
+ ssl->early_data_accepted = 0;
+ ssl->s3->skip_early_data = 1;
hs->tls13_state = state_send_hello_retry_request;
return ssl_hs_ok;
}
@@ -440,8 +530,6 @@ static enum ssl_hs_wait_t do_send_server_hello(SSL_HANDSHAKE *hs) {
/* Derive and enable the handshake traffic secrets. */
if (!tls13_derive_handshake_secrets(hs) ||
- !tls13_set_traffic_key(ssl, evp_aead_open, hs->client_handshake_secret,
- hs->hash_len) ||
!tls13_set_traffic_key(ssl, evp_aead_seal, hs->server_handshake_secret,
hs->hash_len)) {
goto err;
@@ -543,8 +631,66 @@ static enum ssl_hs_wait_t do_send_server_finished(SSL_HANDSHAKE *hs) {
return ssl_hs_error;
}
- hs->tls13_state = state_process_client_certificate;
- return ssl_hs_flush_and_read_message;
+ if (ssl->early_data_accepted) {
+ /* If accepting 0-RTT, we send tickets half-RTT. This gets the tickets on
+ * the wire sooner and also avoids triggering a write on |SSL_read| when
+ * processing the client Finished. This requires computing the client
+ * Finished early. See draft-ietf-tls-tls13-18, section 4.5.1. */
+ size_t finished_len;
+ if (!tls13_finished_mac(hs, hs->expected_client_finished, &finished_len,
+ 0 /* client */)) {
+ return ssl_hs_error;
+ }
+
+ if (finished_len != hs->hash_len) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return ssl_hs_error;
+ }
+
+ /* Feed the predicted Finished into the transcript. This allows us to derive
+ * the resumption secret early and send half-RTT tickets.
+ *
+ * TODO(davidben): This will need to be updated for DTLS 1.3. */
+ assert(!SSL_is_dtls(hs->ssl));
+ uint8_t header[4] = {SSL3_MT_FINISHED, 0, 0, hs->hash_len};
+ if (!SSL_TRANSCRIPT_update(&hs->transcript, header, sizeof(header)) ||
+ !SSL_TRANSCRIPT_update(&hs->transcript, hs->expected_client_finished,
+ hs->hash_len) ||
+ !tls13_derive_resumption_secret(hs) ||
+ !add_new_session_tickets(hs)) {
+ return ssl_hs_error;
+ }
+ }
+
+ hs->tls13_state = state_read_second_client_flight;
+ return ssl_hs_flush;
+}
+
+static enum ssl_hs_wait_t do_read_second_client_flight(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ if (ssl->early_data_accepted) {
+ if (!tls13_set_traffic_key(ssl, evp_aead_open, hs->early_traffic_secret,
+ hs->hash_len)) {
+ return ssl_hs_error;
+ }
+ hs->can_early_write = 1;
+ hs->can_early_read = 1;
+ hs->tls13_state = state_process_end_of_early_data;
+ return ssl_hs_read_end_of_early_data;
+ }
+ hs->tls13_state = state_process_end_of_early_data;
+ return ssl_hs_ok;
+}
+
+static enum ssl_hs_wait_t do_process_end_of_early_data(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ if (!tls13_set_traffic_key(ssl, evp_aead_open, hs->client_handshake_secret,
+ hs->hash_len)) {
+ return ssl_hs_error;
+ }
+ hs->tls13_state = ssl->early_data_accepted ? state_process_client_finished
+ : state_process_client_certificate;
+ return ssl_hs_read_message;
}
static enum ssl_hs_wait_t do_process_client_certificate(SSL_HANDSHAKE *hs) {
@@ -610,30 +756,33 @@ static enum ssl_hs_wait_t do_process_channel_id(SSL_HANDSHAKE *hs) {
static enum ssl_hs_wait_t do_process_client_finished(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
if (!ssl_check_message_type(ssl, SSL3_MT_FINISHED) ||
- !tls13_process_finished(hs) ||
- !ssl_hash_current_message(hs) ||
+ /* If early data was accepted, we've already computed the client Finished
+ * and derived the resumption secret. */
+ !tls13_process_finished(hs, ssl->early_data_accepted) ||
/* evp_aead_seal keys have already been switched. */
!tls13_set_traffic_key(ssl, evp_aead_open, hs->client_traffic_secret_0,
- hs->hash_len) ||
- !tls13_derive_resumption_secret(hs)) {
+ hs->hash_len)) {
return ssl_hs_error;
}
ssl->method->received_flight(ssl);
- /* Rebase the session timestamp so that it is measured from ticket
- * issuance. */
- ssl_session_rebase_time(ssl, hs->new_session);
- hs->tls13_state = state_send_new_session_ticket;
+ if (!ssl->early_data_accepted) {
+ if (!ssl_hash_current_message(hs) ||
+ !tls13_derive_resumption_secret(hs)) {
+ return ssl_hs_error;
+ }
+
+ /* We send post-handshake tickets as part of the handshake in 1-RTT. */
+ hs->tls13_state = state_send_new_session_ticket;
+ return ssl_hs_ok;
+ }
+
+ hs->tls13_state = state_done;
return ssl_hs_ok;
}
static enum ssl_hs_wait_t do_send_new_session_ticket(SSL_HANDSHAKE *hs) {
- /* TLS 1.3 recommends single-use tickets, so issue multiple tickets in case the
- * client makes several connections before getting a renewal. */
- static const int kNumTickets = 2;
-
- SSL *const ssl = hs->ssl;
/* If the client doesn't accept resumption with PSK_DHE_KE, don't send a
* session ticket. */
if (!hs->accept_psk_mode) {
@@ -641,58 +790,12 @@ static enum ssl_hs_wait_t do_send_new_session_ticket(SSL_HANDSHAKE *hs) {
return ssl_hs_ok;
}
- SSL_SESSION *session = hs->new_session;
- CBB cbb;
- CBB_zero(&cbb);
-
- for (int i = 0; i < kNumTickets; i++) {
- if (!RAND_bytes((uint8_t *)&session->ticket_age_add, 4)) {
- goto err;
- }
- session->ticket_age_add_valid = 1;
-
- CBB body, ticket, extensions;
- if (!ssl->method->init_message(ssl, &cbb, &body,
- SSL3_MT_NEW_SESSION_TICKET) ||
- !CBB_add_u32(&body, session->timeout) ||
- !CBB_add_u32(&body, session->ticket_age_add) ||
- !CBB_add_u16_length_prefixed(&body, &ticket) ||
- !ssl_encrypt_ticket(ssl, &ticket, session) ||
- !CBB_add_u16_length_prefixed(&body, &extensions)) {
- goto err;
- }
-
- if (ssl->ctx->enable_early_data) {
- session->ticket_max_early_data = kMaxEarlyDataAccepted;
-
- CBB early_data_info;
- if (!CBB_add_u16(&extensions, TLSEXT_TYPE_ticket_early_data_info) ||
- !CBB_add_u16_length_prefixed(&extensions, &early_data_info) ||
- !CBB_add_u32(&early_data_info, session->ticket_max_early_data) ||
- !CBB_flush(&extensions)) {
- goto err;
- }
- }
-
- /* Add a fake extension. See draft-davidben-tls-grease-01. */
- if (!CBB_add_u16(&extensions,
- ssl_get_grease_value(ssl, ssl_grease_ticket_extension)) ||
- !CBB_add_u16(&extensions, 0 /* empty */)) {
- goto err;
- }
-
- if (!ssl_add_message_cbb(ssl, &cbb)) {
- goto err;
- }
+ if (!add_new_session_tickets(hs)) {
+ return ssl_hs_error;
}
- hs->session_tickets_sent++;
hs->tls13_state = state_done;
return ssl_hs_flush;
-
-err:
- CBB_cleanup(&cbb);
- return ssl_hs_error;
}
enum ssl_hs_wait_t tls13_server_handshake(SSL_HANDSHAKE *hs) {
@@ -720,10 +823,16 @@ enum ssl_hs_wait_t tls13_server_handshake(SSL_HANDSHAKE *hs) {
break;
case state_complete_server_certificate_verify:
ret = do_send_server_certificate_verify(hs, 0 /* complete */);
- break;
+ break;
case state_send_server_finished:
ret = do_send_server_finished(hs);
break;
+ case state_read_second_client_flight:
+ ret = do_read_second_client_flight(hs);
+ break;
+ case state_process_end_of_early_data:
+ ret = do_process_end_of_early_data(hs);
+ break;
case state_process_client_certificate:
ret = do_process_client_certificate(hs);
break;
diff --git a/src/ssl/tls_record.c b/src/ssl/tls_record.c
index aafb6f51..0f9720c7 100644
--- a/src/ssl/tls_record.c
+++ b/src/ssl/tls_record.c
@@ -327,6 +327,14 @@ enum ssl_open_record_t tls_open_record(SSL *ssl, uint8_t *out_type, CBS *out,
}
if (type == SSL3_RT_ALERT) {
+ /* Return end_of_early_data alerts as-is for the caller to process. */
+ if (CBS_len(out) == 2 &&
+ CBS_data(out)[0] == SSL3_AL_WARNING &&
+ CBS_data(out)[1] == TLS1_AD_END_OF_EARLY_DATA) {
+ *out_type = type;
+ return ssl_open_record_success;
+ }
+
return ssl_process_alert(ssl, out_alert, CBS_data(out), CBS_len(out));
}
diff --git a/src/tool/client.cc b/src/tool/client.cc
index 6bc8e399..bc17426c 100644
--- a/src/tool/client.cc
+++ b/src/tool/client.cc
@@ -111,6 +111,9 @@ static const struct argument kArguments[] = {
"verification is required.",
},
{
+ "-early-data", kBooleanArgument, "Allow early data",
+ },
+ {
"", kOptionalArgument, "",
},
};
@@ -405,6 +408,10 @@ bool Client(const std::vector<std::string> &args) {
SSL_CTX_set_verify(ctx.get(), SSL_VERIFY_PEER, nullptr);
}
+ if (args_map.count("-early-data") != 0) {
+ SSL_CTX_set_early_data_enabled(ctx.get(), 1);
+ }
+
if (args_map.count("-resume") != 0 &&
!DoConnection(ctx.get(), args_map, &WaitForSession)) {
return false;
diff --git a/src/tool/server.cc b/src/tool/server.cc
index 20c913c3..1a97dff1 100644
--- a/src/tool/server.cc
+++ b/src/tool/server.cc
@@ -54,6 +54,9 @@ static const struct argument kArguments[] = {
"The server will continue accepting new sequential connections.",
},
{
+ "-early-data", kBooleanArgument, "Allow early data",
+ },
+ {
"", kOptionalArgument, "",
},
};
@@ -223,6 +226,10 @@ bool Server(const std::vector<std::string> &args) {
return false;
}
+ if (args_map.count("-early-data") != 0) {
+ SSL_CTX_set_early_data_enabled(ctx.get(), 1);
+ }
+
bool result = true;
do {
int sock = -1;
diff --git a/src/tool/transport_common.cc b/src/tool/transport_common.cc
index 5f1a366a..56bde288 100644
--- a/src/tool/transport_common.cc
+++ b/src/tool/transport_common.cc
@@ -292,6 +292,9 @@ void PrintConnectionInfo(const SSL *ssl) {
fprintf(stderr, " SCT list: %s\n", sct_list_len > 0 ? "yes" : "no");
}
+ fprintf(stderr, " Early data: %s\n",
+ SSL_early_data_accepted(ssl) ? "yes" : "no");
+
// Print the server cert subject and issuer names.
bssl::UniquePtr<X509> peer(SSL_get_peer_certificate(ssl));
if (peer != nullptr) {
diff --git a/src/util/all_tests.json b/src/util/all_tests.json
index d5c6e544..a1ce5f2d 100644
--- a/src/util/all_tests.json
+++ b/src/util/all_tests.json
@@ -1,7 +1,6 @@
[
["crypto/aes/aes_test", "crypto/aes/aes_tests.txt"],
["crypto/base64/base64_test"],
- ["crypto/bio/bio_test"],
["crypto/bn/bn_test", "crypto/bn/bn_tests.txt"],
["crypto/bytestring/bytestring_test"],
["crypto/cipher/aead_test", "aes-128-gcm", "crypto/cipher/test/aes_128_gcm_tests.txt"],
@@ -25,7 +24,6 @@
["crypto/cipher/aead_test", "aes-256-ctr-hmac-sha256", "crypto/cipher/test/aes_256_ctr_hmac_sha256.txt"],
["crypto/cipher/cipher_test", "crypto/cipher/test/cipher_tests.txt"],
["crypto/cmac/cmac_test"],
- ["crypto/constant_time_test"],
["crypto/crypto_test"],
["crypto/curve25519/ed25519_test", "crypto/curve25519/ed25519_tests.txt"],
["crypto/curve25519/spake25519_test"],