diff options
author | Robert Sloan <varomodt@google.com> | 2017-03-27 22:42:16 +0000 |
---|---|---|
committer | android-build-merger <android-build-merger@google.com> | 2017-03-27 22:42:16 +0000 |
commit | 6844d1aab02d8c732584a7e85bc92efa6c83dfef (patch) | |
tree | c478b31bb734b02e26a264d7c1b45e49c5593acc | |
parent | d540c9cbf76fdff98d32997f96e9341210744c29 (diff) | |
parent | d922d6aa2268b72362edc789c00ed3de2f99145b (diff) | |
download | boringssl-6844d1aab02d8c732584a7e85bc92efa6c83dfef.tar.gz |
external/boringssl: Sync to bbfe603519bc54fbc4c8dd87efe1ed385df550b4. am: 6d0d00e090 am: 9ef60e37fc
am: d922d6aa22
Change-Id: I50dd83aaa70fdd2abd93068cb0dd64789109992d
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 @@ -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" @@ -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", @@ -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, ¶m, CBS_ASN1_NULL) || + CBS_len(¶m) != 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, ¶m, CBS_ASN1_SEQUENCE) || !CBB_add_asn1(¶m, &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(¶m, &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, ¶m, CBS_ASN1_SEQUENCE) || !CBB_add_asn1(¶m, &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"], |