diff options
author | Robert Sloan <varomodt@google.com> | 2017-12-05 09:14:02 +0000 |
---|---|---|
committer | android-build-merger <android-build-merger@google.com> | 2017-12-05 09:14:02 +0000 |
commit | cd32b5c799ac5f2267a1c741e02ee32413a036c2 (patch) | |
tree | 4ed7eaa0852af5b2ee35d5ceb5f1b84edb3bfe4c | |
parent | 5a5292f2fe6b8dea52bb657333f3047b55b0ec03 (diff) | |
parent | a815d5abd1078d03df3278e5e3d512c7f6a11f9a (diff) | |
download | boringssl-cd32b5c799ac5f2267a1c741e02ee32413a036c2.tar.gz |
external/boringssl: Sync to a5462d3050ac6a68ab488450bf5856475dbef992.
am: a815d5abd1
Change-Id: I060857e7baeb865e77e53c18971811da0edf8989
31 files changed, 1523 insertions, 1648 deletions
diff --git a/BORINGSSL_REVISION b/BORINGSSL_REVISION index 66ca33f8..192ac7d5 100644 --- a/BORINGSSL_REVISION +++ b/BORINGSSL_REVISION @@ -1 +1 @@ -27bc0f26c8d132df04f5b0b173aefeb8aaa13c33 +a5462d3050ac6a68ab488450bf5856475dbef992 @@ -75,51 +75,51 @@ const uint32_t kOpenSSLReasonValues[] = { 0xc3b00ea, 0xc3b88d4, 0x10320845, - 0x10329522, - 0x1033152e, - 0x10339547, - 0x1034155a, + 0x10329535, + 0x10331541, + 0x1033955a, + 0x1034156d, 0x10348efc, 0x10350c5e, - 0x1035956d, - 0x10361582, - 0x10369595, - 0x103715b4, - 0x103795cd, - 0x103815e2, - 0x10389600, - 0x1039160f, - 0x1039962b, - 0x103a1646, - 0x103a9655, - 0x103b1671, - 0x103b968c, - 0x103c16a3, + 0x10359580, + 0x10361595, + 0x103695a8, + 0x103715c7, + 0x103795e0, + 0x103815f5, + 0x10389613, + 0x10391622, + 0x1039963e, + 0x103a1659, + 0x103a9668, + 0x103b1684, + 0x103b969f, + 0x103c16b6, 0x103c80ea, - 0x103d16b4, - 0x103d96c8, - 0x103e16e7, - 0x103e96f6, - 0x103f170d, - 0x103f9720, + 0x103d16c7, + 0x103d96db, + 0x103e16fa, + 0x103e9709, + 0x103f1720, + 0x103f9733, 0x10400c22, - 0x10409733, - 0x10411751, - 0x10419764, - 0x1042177e, - 0x1042978e, - 0x104317a2, - 0x104397b8, - 0x104417d0, - 0x104497e5, - 0x104517f9, - 0x1045980b, + 0x10409746, + 0x10411764, + 0x10419777, + 0x10421791, + 0x104297a1, + 0x104317b5, + 0x104397cb, + 0x104417e3, + 0x104497f8, + 0x1045180c, + 0x1045981e, 0x104605fb, 0x1046894d, - 0x10471820, - 0x10479837, - 0x1048184c, - 0x1048985a, + 0x10471833, + 0x1047984a, + 0x1048185f, + 0x1048986d, 0x10490e5e, 0x14320c05, 0x14328c13, @@ -161,22 +161,23 @@ const uint32_t kOpenSSLReasonValues[] = { 0x1841907c, 0x1842109b, 0x18429055, - 0x203211a5, - 0x243211b1, + 0x203211b8, + 0x203291a5, + 0x243211c4, 0x24328993, - 0x243311c3, - 0x243391d0, - 0x243411dd, - 0x243491ef, - 0x243511fe, - 0x2435921b, - 0x24361228, - 0x24369236, - 0x24371244, - 0x24379252, - 0x2438125b, - 0x24389268, - 0x2439127b, + 0x243311d6, + 0x243391e3, + 0x243411f0, + 0x24349202, + 0x24351211, + 0x2435922e, + 0x2436123b, + 0x24369249, + 0x24371257, + 0x24379265, + 0x2438126e, + 0x2438927b, + 0x2439128e, 0x28320c52, 0x28328c6a, 0x28330c22, @@ -184,43 +185,43 @@ const uint32_t kOpenSSLReasonValues[] = { 0x28340c5e, 0x283480ac, 0x283500ea, - 0x2c322c59, - 0x2c329292, - 0x2c332c67, - 0x2c33ac79, - 0x2c342c8d, - 0x2c34ac9f, - 0x2c352cba, - 0x2c35accc, - 0x2c362cdf, + 0x2c322c6c, + 0x2c3292a5, + 0x2c332c7a, + 0x2c33ac8c, + 0x2c342ca0, + 0x2c34acb2, + 0x2c352ccd, + 0x2c35acdf, + 0x2c362cf2, 0x2c36832d, - 0x2c372cec, - 0x2c37acfe, - 0x2c382d23, - 0x2c38ad3a, - 0x2c392d48, - 0x2c39ad58, - 0x2c3a2d6a, - 0x2c3aad7e, - 0x2c3b2d8f, - 0x2c3badae, - 0x2c3c12a4, - 0x2c3c92ba, - 0x2c3d2dc2, - 0x2c3d92d3, - 0x2c3e2ddf, - 0x2c3eaded, - 0x2c3f2e05, - 0x2c3fae1d, - 0x2c402e2a, - 0x2c4091a5, - 0x2c412e3b, - 0x2c41ae4e, + 0x2c372cff, + 0x2c37ad11, + 0x2c382d36, + 0x2c38ad4d, + 0x2c392d5b, + 0x2c39ad6b, + 0x2c3a2d7d, + 0x2c3aad91, + 0x2c3b2da2, + 0x2c3badc1, + 0x2c3c12b7, + 0x2c3c92cd, + 0x2c3d2dd5, + 0x2c3d92e6, + 0x2c3e2df2, + 0x2c3eae00, + 0x2c3f2e18, + 0x2c3fae30, + 0x2c402e3d, + 0x2c4091b8, + 0x2c412e4e, + 0x2c41ae61, 0x2c42117e, - 0x2c42ae5f, + 0x2c42ae72, 0x2c430720, - 0x2c43ada0, - 0x2c442d11, + 0x2c43adb3, + 0x2c442d24, 0x30320000, 0x30328015, 0x3033001f, @@ -354,221 +355,221 @@ const uint32_t kOpenSSLReasonValues[] = { 0x3c418d52, 0x3c420e5e, 0x3c428de8, - 0x403218b3, - 0x403298c9, - 0x403318f7, - 0x40339901, - 0x40341918, - 0x40349936, - 0x40351946, - 0x40359958, - 0x40361965, - 0x40369971, - 0x40371986, - 0x40379998, - 0x403819a3, - 0x403899b5, + 0x403218c6, + 0x403298dc, + 0x4033190a, + 0x40339914, + 0x4034192b, + 0x40349949, + 0x40351959, + 0x4035996b, + 0x40361978, + 0x40369984, + 0x40371999, + 0x403799ab, + 0x403819b6, + 0x403899c8, 0x40390efc, - 0x403999c5, - 0x403a19d8, - 0x403a99f9, - 0x403b1a0a, - 0x403b9a1a, + 0x403999d8, + 0x403a19eb, + 0x403a9a0c, + 0x403b1a1d, + 0x403b9a2d, 0x403c0064, 0x403c8083, - 0x403d1a9e, - 0x403d9ab4, - 0x403e1ac3, - 0x403e9afb, - 0x403f1b15, - 0x403f9b23, - 0x40401b38, - 0x40409b4c, - 0x40411b69, - 0x40419b84, - 0x40421b9d, - 0x40429bb0, - 0x40431bc4, - 0x40439bdc, - 0x40441bf3, + 0x403d1ab1, + 0x403d9ac7, + 0x403e1ad6, + 0x403e9b0e, + 0x403f1b28, + 0x403f9b36, + 0x40401b4b, + 0x40409b5f, + 0x40411b7c, + 0x40419b97, + 0x40421bb0, + 0x40429bc3, + 0x40431bd7, + 0x40439bef, + 0x40441c06, 0x404480ac, - 0x40451c08, - 0x40459c1a, - 0x40461c3e, - 0x40469c5e, - 0x40471c6c, - 0x40479c93, - 0x40481cd0, - 0x40489d03, - 0x40491d1a, - 0x40499d34, - 0x404a1d4b, - 0x404a9d69, - 0x404b1d81, - 0x404b9d98, - 0x404c1dae, - 0x404c9dc0, - 0x404d1de1, - 0x404d9e03, - 0x404e1e17, - 0x404e9e24, - 0x404f1e51, - 0x404f9e7a, - 0x40501eb5, - 0x40509ec9, - 0x40511ee4, - 0x40521ef4, - 0x40529f18, - 0x40531f30, - 0x40539f43, - 0x40541f58, - 0x40549f7b, - 0x40551f89, - 0x40559fa6, - 0x40561fb3, - 0x40569fcc, - 0x40571fe4, - 0x40579ff7, - 0x4058200c, - 0x4058a033, - 0x40592062, - 0x4059a08f, - 0x405a20a3, - 0x405aa0b3, - 0x405b20cb, - 0x405ba0dc, - 0x405c20ef, - 0x405ca12e, - 0x405d213b, - 0x405da152, - 0x405e2190, + 0x40451c1b, + 0x40459c2d, + 0x40461c51, + 0x40469c71, + 0x40471c7f, + 0x40479ca6, + 0x40481ce3, + 0x40489d16, + 0x40491d2d, + 0x40499d47, + 0x404a1d5e, + 0x404a9d7c, + 0x404b1d94, + 0x404b9dab, + 0x404c1dc1, + 0x404c9dd3, + 0x404d1df4, + 0x404d9e16, + 0x404e1e2a, + 0x404e9e37, + 0x404f1e64, + 0x404f9e8d, + 0x40501ec8, + 0x40509edc, + 0x40511ef7, + 0x40521f07, + 0x40529f2b, + 0x40531f43, + 0x40539f56, + 0x40541f6b, + 0x40549f8e, + 0x40551f9c, + 0x40559fb9, + 0x40561fc6, + 0x40569fdf, + 0x40571ff7, + 0x4057a00a, + 0x4058201f, + 0x4058a046, + 0x40592075, + 0x4059a0a2, + 0x405a20b6, + 0x405aa0c6, + 0x405b20de, + 0x405ba0ef, + 0x405c2102, + 0x405ca141, + 0x405d214e, + 0x405da165, + 0x405e21a3, 0x405e8ab1, - 0x405f21b1, - 0x405fa1be, - 0x406021cc, - 0x4060a1ee, - 0x40612232, - 0x4061a26a, - 0x40622281, - 0x4062a292, - 0x406322a3, - 0x4063a2b8, - 0x406422cf, - 0x4064a2fb, - 0x40652316, - 0x4065a32d, - 0x40662345, - 0x4066a36f, - 0x4067239a, - 0x4067a3bb, - 0x406823e2, - 0x4068a403, - 0x40692435, - 0x4069a463, - 0x406a2484, - 0x406aa4a4, - 0x406b262c, - 0x406ba64f, - 0x406c2665, - 0x406ca8e0, - 0x406d290f, - 0x406da937, - 0x406e2965, - 0x406ea9b2, - 0x406f29d1, - 0x406faa09, - 0x40702a1c, - 0x4070aa39, + 0x405f21c4, + 0x405fa1d1, + 0x406021df, + 0x4060a201, + 0x40612245, + 0x4061a27d, + 0x40622294, + 0x4062a2a5, + 0x406322b6, + 0x4063a2cb, + 0x406422e2, + 0x4064a30e, + 0x40652329, + 0x4065a340, + 0x40662358, + 0x4066a382, + 0x406723ad, + 0x4067a3ce, + 0x406823f5, + 0x4068a416, + 0x40692448, + 0x4069a476, + 0x406a2497, + 0x406aa4b7, + 0x406b263f, + 0x406ba662, + 0x406c2678, + 0x406ca8f3, + 0x406d2922, + 0x406da94a, + 0x406e2978, + 0x406ea9c5, + 0x406f29e4, + 0x406faa1c, + 0x40702a2f, + 0x4070aa4c, 0x40710800, - 0x4071aa4b, - 0x40722a5e, - 0x4072aa77, - 0x40732a8f, - 0x40739491, - 0x40742aa3, - 0x4074aabd, - 0x40752ace, - 0x4075aae2, - 0x40762af0, - 0x40769268, - 0x40772b15, - 0x4077ab37, - 0x40782b52, - 0x4078ab8b, - 0x40792ba2, - 0x4079abb8, - 0x407a2bc4, - 0x407aabd7, - 0x407b2bec, - 0x407babfe, - 0x407c2c2f, - 0x407cac38, - 0x407d241e, - 0x407d9e8a, - 0x407e2b67, - 0x407ea043, - 0x407f1c80, - 0x407f9a40, - 0x40801e61, - 0x40809ca8, - 0x40811f06, - 0x40819e3b, - 0x40822950, - 0x40829a26, - 0x4083201e, - 0x4083a2e0, - 0x40841cbc, - 0x4084a07b, - 0x40852100, - 0x4085a216, - 0x40862172, - 0x40869ea4, - 0x40872996, - 0x4087a247, - 0x40881a87, - 0x4088a3ce, - 0x40891ad6, - 0x40899a63, - 0x408a2685, - 0x408a9871, - 0x408b2c13, - 0x408ba9e6, - 0x408c2110, - 0x408c988d, - 0x408d1ce9, - 0x41f42557, - 0x41f925e9, - 0x41fe24dc, - 0x41fea6d1, - 0x41ff27c2, - 0x42032570, - 0x42082592, - 0x4208a5ce, - 0x420924c0, - 0x4209a608, - 0x420a2517, - 0x420aa4f7, - 0x420b2537, - 0x420ba5b0, - 0x420c27de, - 0x420ca69e, - 0x420d26b8, - 0x420da6ef, - 0x42122709, - 0x421727a5, - 0x4217a74b, - 0x421c276d, - 0x421f2728, - 0x422127f5, - 0x42262788, - 0x422b28c4, - 0x422ba872, - 0x422c28ac, - 0x422ca831, - 0x422d2810, - 0x422da891, - 0x422e2857, - 0x422ea97d, + 0x4071aa5e, + 0x40722a71, + 0x4072aa8a, + 0x40732aa2, + 0x407394a4, + 0x40742ab6, + 0x4074aad0, + 0x40752ae1, + 0x4075aaf5, + 0x40762b03, + 0x4076927b, + 0x40772b28, + 0x4077ab4a, + 0x40782b65, + 0x4078ab9e, + 0x40792bb5, + 0x4079abcb, + 0x407a2bd7, + 0x407aabea, + 0x407b2bff, + 0x407bac11, + 0x407c2c42, + 0x407cac4b, + 0x407d2431, + 0x407d9e9d, + 0x407e2b7a, + 0x407ea056, + 0x407f1c93, + 0x407f9a53, + 0x40801e74, + 0x40809cbb, + 0x40811f19, + 0x40819e4e, + 0x40822963, + 0x40829a39, + 0x40832031, + 0x4083a2f3, + 0x40841ccf, + 0x4084a08e, + 0x40852113, + 0x4085a229, + 0x40862185, + 0x40869eb7, + 0x408729a9, + 0x4087a25a, + 0x40881a9a, + 0x4088a3e1, + 0x40891ae9, + 0x40899a76, + 0x408a2698, + 0x408a9884, + 0x408b2c26, + 0x408ba9f9, + 0x408c2123, + 0x408c98a0, + 0x408d1cfc, + 0x41f4256a, + 0x41f925fc, + 0x41fe24ef, + 0x41fea6e4, + 0x41ff27d5, + 0x42032583, + 0x420825a5, + 0x4208a5e1, + 0x420924d3, + 0x4209a61b, + 0x420a252a, + 0x420aa50a, + 0x420b254a, + 0x420ba5c3, + 0x420c27f1, + 0x420ca6b1, + 0x420d26cb, + 0x420da702, + 0x4212271c, + 0x421727b8, + 0x4217a75e, + 0x421c2780, + 0x421f273b, + 0x42212808, + 0x4226279b, + 0x422b28d7, + 0x422ba885, + 0x422c28bf, + 0x422ca844, + 0x422d2823, + 0x422da8a4, + 0x422e286a, + 0x422ea990, 0x4432072b, 0x4432873a, 0x44330746, @@ -586,104 +587,104 @@ const uint32_t kOpenSSLReasonValues[] = { 0x44390800, 0x4439880e, 0x443a0821, - 0x48321292, - 0x483292a4, - 0x483312ba, - 0x483392d3, - 0x4c3212f8, - 0x4c329308, - 0x4c33131b, - 0x4c33933b, + 0x483212a5, + 0x483292b7, + 0x483312cd, + 0x483392e6, + 0x4c32130b, + 0x4c32931b, + 0x4c33132e, + 0x4c33934e, 0x4c3400ac, 0x4c3480ea, - 0x4c351347, - 0x4c359355, - 0x4c361371, - 0x4c369384, - 0x4c371393, - 0x4c3793a1, - 0x4c3813b6, - 0x4c3893c2, - 0x4c3913e2, - 0x4c39940c, - 0x4c3a1425, - 0x4c3a943e, + 0x4c35135a, + 0x4c359368, + 0x4c361384, + 0x4c369397, + 0x4c3713a6, + 0x4c3793b4, + 0x4c3813c9, + 0x4c3893d5, + 0x4c3913f5, + 0x4c39941f, + 0x4c3a1438, + 0x4c3a9451, 0x4c3b05fb, - 0x4c3b9457, - 0x4c3c1469, - 0x4c3c9478, - 0x4c3d1491, + 0x4c3b946a, + 0x4c3c147c, + 0x4c3c948b, + 0x4c3d14a4, 0x4c3d8c45, - 0x4c3e14ea, - 0x4c3e94a0, - 0x4c3f150c, - 0x4c3f9268, - 0x4c4014b6, - 0x4c4092e4, - 0x4c4114da, - 0x50322e71, - 0x5032ae80, - 0x50332e8b, - 0x5033ae9b, - 0x50342eb4, - 0x5034aece, - 0x50352edc, - 0x5035aef2, - 0x50362f04, - 0x5036af1a, - 0x50372f33, - 0x5037af46, - 0x50382f5e, - 0x5038af6f, - 0x50392f84, - 0x5039af98, - 0x503a2fb8, - 0x503aafce, - 0x503b2fe6, - 0x503baff8, - 0x503c3014, - 0x503cb02b, - 0x503d3044, - 0x503db05a, - 0x503e3067, - 0x503eb07d, - 0x503f308f, + 0x4c3e14fd, + 0x4c3e94b3, + 0x4c3f151f, + 0x4c3f927b, + 0x4c4014c9, + 0x4c4092f7, + 0x4c4114ed, + 0x50322e84, + 0x5032ae93, + 0x50332e9e, + 0x5033aeae, + 0x50342ec7, + 0x5034aee1, + 0x50352eef, + 0x5035af05, + 0x50362f17, + 0x5036af2d, + 0x50372f46, + 0x5037af59, + 0x50382f71, + 0x5038af82, + 0x50392f97, + 0x5039afab, + 0x503a2fcb, + 0x503aafe1, + 0x503b2ff9, + 0x503bb00b, + 0x503c3027, + 0x503cb03e, + 0x503d3057, + 0x503db06d, + 0x503e307a, + 0x503eb090, + 0x503f30a2, 0x503f8382, - 0x504030a2, - 0x5040b0b2, - 0x504130cc, - 0x5041b0db, - 0x504230f5, - 0x5042b112, - 0x50433122, - 0x5043b132, - 0x50443141, + 0x504030b5, + 0x5040b0c5, + 0x504130df, + 0x5041b0ee, + 0x50423108, + 0x5042b125, + 0x50433135, + 0x5043b145, + 0x50443154, 0x5044843f, - 0x50453155, - 0x5045b173, - 0x50463186, - 0x5046b19c, - 0x504731ae, - 0x5047b1c3, - 0x504831e9, - 0x5048b1f7, - 0x5049320a, - 0x5049b21f, - 0x504a3235, - 0x504ab245, - 0x504b3265, - 0x504bb278, - 0x504c329b, - 0x504cb2c9, - 0x504d32db, - 0x504db2f8, - 0x504e3313, - 0x504eb32f, - 0x504f3341, - 0x504fb358, - 0x50503367, + 0x50453168, + 0x5045b186, + 0x50463199, + 0x5046b1af, + 0x504731c1, + 0x5047b1d6, + 0x504831fc, + 0x5048b20a, + 0x5049321d, + 0x5049b232, + 0x504a3248, + 0x504ab258, + 0x504b3278, + 0x504bb28b, + 0x504c32ae, + 0x504cb2dc, + 0x504d32ee, + 0x504db30b, + 0x504e3326, + 0x504eb342, + 0x504f3354, + 0x504fb36b, + 0x5050337a, 0x505086ef, - 0x5051337a, + 0x5051338d, 0x58320f3a, 0x68320efc, 0x68328c6a, @@ -962,6 +963,7 @@ const char kOpenSSLReasonStringData[] = "UNKNOWN_PUBLIC_KEY_TYPE\0" "UNSUPPORTED_ALGORITHM\0" "OUTPUT_TOO_LARGE\0" + "INVALID_OID_STRING\0" "UNKNOWN_NID\0" "BAD_BASE64_DECODE\0" "BAD_END_LINE\0" diff --git a/src/crypto/asn1/a_object.c b/src/crypto/asn1/a_object.c index a710addd..005e37d5 100644 --- a/src/crypto/asn1/a_object.c +++ b/src/crypto/asn1/a_object.c @@ -87,134 +87,6 @@ int i2d_ASN1_OBJECT(ASN1_OBJECT *a, unsigned char **pp) return (objsize); } -int a2d_ASN1_OBJECT(unsigned char *out, int olen, const char *buf, int num) -{ - int i, first, len = 0, c, use_bn; - char ftmp[24], *tmp = ftmp; - int tmpsize = sizeof ftmp; - const char *p; - unsigned long l; - BIGNUM *bl = NULL; - - if (num == 0) - return (0); - else if (num == -1) - num = strlen(buf); - - p = buf; - c = *(p++); - num--; - if ((c >= '0') && (c <= '2')) { - first = c - '0'; - } else { - OPENSSL_PUT_ERROR(ASN1, ASN1_R_FIRST_NUM_TOO_LARGE); - goto err; - } - - if (num <= 0) { - OPENSSL_PUT_ERROR(ASN1, ASN1_R_MISSING_SECOND_NUMBER); - goto err; - } - c = *(p++); - num--; - for (;;) { - if (num <= 0) - break; - if ((c != '.') && (c != ' ')) { - OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_SEPARATOR); - goto err; - } - l = 0; - use_bn = 0; - for (;;) { - if (num <= 0) - break; - num--; - c = *(p++); - if ((c == ' ') || (c == '.')) - break; - if ((c < '0') || (c > '9')) { - OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_DIGIT); - goto err; - } - if (!use_bn && l >= ((ULONG_MAX - 80) / 10L)) { - use_bn = 1; - if (!bl) - bl = BN_new(); - if (!bl || !BN_set_word(bl, l)) - goto err; - } - if (use_bn) { - if (!BN_mul_word(bl, 10L) - || !BN_add_word(bl, c - '0')) - goto err; - } else - l = l * 10L + (long)(c - '0'); - } - if (len == 0) { - if ((first < 2) && (l >= 40)) { - OPENSSL_PUT_ERROR(ASN1, ASN1_R_SECOND_NUMBER_TOO_LARGE); - goto err; - } - if (use_bn) { - if (!BN_add_word(bl, first * 40)) - goto err; - } else - l += (long)first *40; - } - i = 0; - if (use_bn) { - int blsize; - blsize = BN_num_bits(bl); - blsize = (blsize + 6) / 7; - if (blsize > tmpsize) { - if (tmp != ftmp) - OPENSSL_free(tmp); - tmpsize = blsize + 32; - tmp = OPENSSL_malloc(tmpsize); - if (!tmp) - goto err; - } - while (blsize--) { - BN_ULONG t = BN_div_word(bl, 0x80L); - if (t == (BN_ULONG)-1) - goto err; - tmp[i++] = (unsigned char)t; - } - } else { - - for (;;) { - tmp[i++] = (unsigned char)l & 0x7f; - l >>= 7L; - if (l == 0L) - break; - } - - } - if (out != NULL) { - if (len + i > olen) { - OPENSSL_PUT_ERROR(ASN1, ASN1_R_BUFFER_TOO_SMALL); - goto err; - } - while (--i > 0) - out[len++] = tmp[i] | 0x80; - out[len++] = tmp[0]; - } else - len += i; - } - if (tmp != ftmp) - OPENSSL_free(tmp); - if (bl) - BN_free(bl); - return (len); - err: - if (tmp != ftmp) - OPENSSL_free(tmp); - if (bl) - BN_free(bl); - return (0); -} - int i2t_ASN1_OBJECT(char *buf, int buf_len, ASN1_OBJECT *a) { return OBJ_obj2txt(buf, buf_len, a, 0); diff --git a/src/crypto/bio/bio_test.cc b/src/crypto/bio/bio_test.cc index eb54f7e1..8479c8e8 100644 --- a/src/crypto/bio/bio_test.cc +++ b/src/crypto/bio/bio_test.cc @@ -27,6 +27,7 @@ #if !defined(OPENSSL_WINDOWS) #include <arpa/inet.h> +#include <errno.h> #include <fcntl.h> #include <netinet/in.h> #include <string.h> diff --git a/src/crypto/bytestring/ber.c b/src/crypto/bytestring/ber.c index bb5e17c4..4dc94f6f 100644 --- a/src/crypto/bytestring/ber.c +++ b/src/crypto/bytestring/ber.c @@ -29,7 +29,10 @@ static const unsigned kMaxDepth = 2048; // is_string_type returns one if |tag| is a string type and zero otherwise. It // ignores the constructed bit. static int is_string_type(unsigned tag) { - switch (tag & ~CBS_ASN1_CONSTRUCTED) { + if ((tag & 0xc0) != 0) { + return 0; + } + switch (tag & 0x1f) { case CBS_ASN1_BITSTRING: case CBS_ASN1_OCTETSTRING: case CBS_ASN1_UTF8STRING: diff --git a/src/crypto/bytestring/bytestring_test.cc b/src/crypto/bytestring/bytestring_test.cc index 7e3d453d..5a6a5c18 100644 --- a/src/crypto/bytestring/bytestring_test.cc +++ b/src/crypto/bytestring/bytestring_test.cc @@ -123,27 +123,27 @@ TEST(CBSTest, GetASN1) { uint64_t value; CBS_init(&data, kData1, sizeof(kData1)); - EXPECT_FALSE(CBS_peek_asn1_tag(&data, CBS_ASN1_BOOLEAN)); - EXPECT_TRUE(CBS_peek_asn1_tag(&data, CBS_ASN1_SEQUENCE)); + EXPECT_FALSE(CBS_peek_asn1_tag(&data, 0x1)); + EXPECT_TRUE(CBS_peek_asn1_tag(&data, 0x30)); - ASSERT_TRUE(CBS_get_asn1(&data, &contents, CBS_ASN1_SEQUENCE)); + ASSERT_TRUE(CBS_get_asn1(&data, &contents, 0x30)); EXPECT_EQ(Bytes("\x01\x02"), Bytes(CBS_data(&contents), CBS_len(&contents))); CBS_init(&data, kData2, sizeof(kData2)); // data is truncated - EXPECT_FALSE(CBS_get_asn1(&data, &contents, CBS_ASN1_SEQUENCE)); + EXPECT_FALSE(CBS_get_asn1(&data, &contents, 0x30)); CBS_init(&data, kData3, sizeof(kData3)); // zero byte length of length - EXPECT_FALSE(CBS_get_asn1(&data, &contents, CBS_ASN1_SEQUENCE)); + EXPECT_FALSE(CBS_get_asn1(&data, &contents, 0x30)); CBS_init(&data, kData4, sizeof(kData4)); // long form mistakenly used. - EXPECT_FALSE(CBS_get_asn1(&data, &contents, CBS_ASN1_SEQUENCE)); + EXPECT_FALSE(CBS_get_asn1(&data, &contents, 0x30)); CBS_init(&data, kData5, sizeof(kData5)); // length takes too many bytes. - EXPECT_FALSE(CBS_get_asn1(&data, &contents, CBS_ASN1_SEQUENCE)); + EXPECT_FALSE(CBS_get_asn1(&data, &contents, 0x30)); CBS_init(&data, kData1, sizeof(kData1)); // wrong tag. @@ -151,72 +151,56 @@ TEST(CBSTest, GetASN1) { CBS_init(&data, NULL, 0); // peek at empty data. - EXPECT_FALSE(CBS_peek_asn1_tag(&data, CBS_ASN1_SEQUENCE)); + EXPECT_FALSE(CBS_peek_asn1_tag(&data, 0x30)); CBS_init(&data, NULL, 0); // optional elements at empty data. - ASSERT_TRUE(CBS_get_optional_asn1( - &data, &contents, &present, - CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)); + ASSERT_TRUE(CBS_get_optional_asn1(&data, &contents, &present, 0xa0)); EXPECT_FALSE(present); - ASSERT_TRUE(CBS_get_optional_asn1_octet_string( - &data, &contents, &present, - CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)); + ASSERT_TRUE( + CBS_get_optional_asn1_octet_string(&data, &contents, &present, 0xa0)); EXPECT_FALSE(present); EXPECT_EQ(0u, CBS_len(&contents)); - ASSERT_TRUE(CBS_get_optional_asn1_octet_string( - &data, &contents, NULL, - CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)); + ASSERT_TRUE(CBS_get_optional_asn1_octet_string(&data, &contents, NULL, 0xa0)); EXPECT_EQ(0u, CBS_len(&contents)); - ASSERT_TRUE(CBS_get_optional_asn1_uint64( - &data, &value, CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0, 42)); + ASSERT_TRUE(CBS_get_optional_asn1_uint64(&data, &value, 0xa0, 42)); EXPECT_EQ(42u, value); CBS_init(&data, kData6, sizeof(kData6)); // optional element. - ASSERT_TRUE(CBS_get_optional_asn1( - &data, &contents, &present, - CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)); + ASSERT_TRUE(CBS_get_optional_asn1(&data, &contents, &present, 0xa0)); EXPECT_FALSE(present); - ASSERT_TRUE(CBS_get_optional_asn1( - &data, &contents, &present, - CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 1)); + ASSERT_TRUE(CBS_get_optional_asn1(&data, &contents, &present, 0xa1)); EXPECT_TRUE(present); EXPECT_EQ(Bytes("\x04\x01\x01"), Bytes(CBS_data(&contents), CBS_len(&contents))); CBS_init(&data, kData6, sizeof(kData6)); // optional octet string. - ASSERT_TRUE(CBS_get_optional_asn1_octet_string( - &data, &contents, &present, - CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)); + ASSERT_TRUE( + CBS_get_optional_asn1_octet_string(&data, &contents, &present, 0xa0)); EXPECT_FALSE(present); EXPECT_EQ(0u, CBS_len(&contents)); - ASSERT_TRUE(CBS_get_optional_asn1_octet_string( - &data, &contents, &present, - CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 1)); + ASSERT_TRUE( + CBS_get_optional_asn1_octet_string(&data, &contents, &present, 0xa1)); EXPECT_TRUE(present); EXPECT_EQ(Bytes("\x01"), Bytes(CBS_data(&contents), CBS_len(&contents))); CBS_init(&data, kData7, sizeof(kData7)); // invalid optional octet string. - EXPECT_FALSE(CBS_get_optional_asn1_octet_string( - &data, &contents, &present, - CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 1)); + EXPECT_FALSE( + CBS_get_optional_asn1_octet_string(&data, &contents, &present, 0xa1)); CBS_init(&data, kData8, sizeof(kData8)); // optional integer. - ASSERT_TRUE(CBS_get_optional_asn1_uint64( - &data, &value, CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0, 42)); + ASSERT_TRUE(CBS_get_optional_asn1_uint64(&data, &value, 0xa0, 42)); EXPECT_EQ(42u, value); - ASSERT_TRUE(CBS_get_optional_asn1_uint64( - &data, &value, CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 1, 42)); + ASSERT_TRUE(CBS_get_optional_asn1_uint64(&data, &value, 0xa1, 42)); EXPECT_EQ(1u, value); CBS_init(&data, kData9, sizeof(kData9)); // invalid optional integer. - EXPECT_FALSE(CBS_get_optional_asn1_uint64( - &data, &value, CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 1, 42)); + EXPECT_FALSE(CBS_get_optional_asn1_uint64(&data, &value, 0xa1, 42)); unsigned tag; CBS_init(&data, kData1, sizeof(kData1)); @@ -233,54 +217,6 @@ TEST(CBSTest, GetASN1) { Bytes(CBS_data(&contents), CBS_len(&contents))); } -TEST(CBSTest, ParseASN1Tag) { - const struct { - bool ok; - unsigned tag; - std::vector<uint8_t> in; - } kTests[] = { - {true, CBS_ASN1_SEQUENCE, {0x30, 0}}, - {true, CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 4, {0xa4, 0}}, - {true, CBS_ASN1_APPLICATION | 30, {0x5e, 0}}, - {true, CBS_ASN1_APPLICATION | 31, {0x5f, 0x1f, 0}}, - {true, CBS_ASN1_APPLICATION | 32, {0x5f, 0x20, 0}}, - {true, - CBS_ASN1_PRIVATE | CBS_ASN1_CONSTRUCTED | 0x1fffffff, - {0xff, 0x81, 0xff, 0xff, 0xff, 0x7f, 0}}, - // Tag number fits in unsigned but not |CBS_ASN1_TAG_NUMBER_MASK|. - {false, 0, {0xff, 0x82, 0xff, 0xff, 0xff, 0x7f, 0}}, - // Tag number does not fit in unsigned. - {false, 0, {0xff, 0x90, 0x80, 0x80, 0x80, 0, 0}}, - // Tag number is not minimally-encoded - {false, 0, {0x5f, 0x80, 0x1f, 0}}, - // Tag number should have used short form. - {false, 0, {0x5f, 0x80, 0x1e, 0}}, - }; - for (const auto &t : kTests) { - SCOPED_TRACE(Bytes(t.in)); - unsigned tag; - CBS cbs, child; - CBS_init(&cbs, t.in.data(), t.in.size()); - ASSERT_EQ(t.ok, !!CBS_get_any_asn1(&cbs, &child, &tag)); - if (t.ok) { - EXPECT_EQ(t.tag, tag); - EXPECT_EQ(0u, CBS_len(&child)); - EXPECT_EQ(0u, CBS_len(&cbs)); - - CBS_init(&cbs, t.in.data(), t.in.size()); - EXPECT_TRUE(CBS_peek_asn1_tag(&cbs, t.tag)); - EXPECT_FALSE(CBS_peek_asn1_tag(&cbs, t.tag + 1)); - - EXPECT_TRUE(CBS_get_asn1(&cbs, &child, t.tag)); - EXPECT_EQ(0u, CBS_len(&child)); - EXPECT_EQ(0u, CBS_len(&cbs)); - - CBS_init(&cbs, t.in.data(), t.in.size()); - EXPECT_FALSE(CBS_get_asn1(&cbs, &child, t.tag + 1)); - } - } -} - TEST(CBSTest, GetOptionalASN1Bool) { static const uint8_t kTrue[] = {0x0a, 3, CBS_ASN1_BOOLEAN, 1, 0xff}; static const uint8_t kFalse[] = {0x0a, 3, CBS_ASN1_BOOLEAN, 1, 0x00}; @@ -480,42 +416,15 @@ TEST(CBBTest, Misuse) { } TEST(CBBTest, ASN1) { - static const uint8_t kExpected[] = { - // SEQUENCE { 1 2 3 } - 0x30, 3, 1, 2, 3, - // [4 CONSTRUCTED] { 4 5 6 } - 0xa4, 3, 4, 5, 6, - // [APPLICATION 30 PRIMITIVE] { 7 8 9 } - 0x5e, 3, 7, 8, 9, - // [APPLICATION 31 PRIMITIVE] { 10 11 12 } - 0x5f, 0x1f, 3, 10, 11, 12, - // [PRIVATE 2^29-1 CONSTRUCTED] { 13 14 15 } - 0xff, 0x81, 0xff, 0xff, 0xff, 0x7f, 3, 13, 14, 15, - }; + static const uint8_t kExpected[] = {0x30, 3, 1, 2, 3}; uint8_t *buf; size_t buf_len; bssl::ScopedCBB cbb; CBB contents, inner_contents; ASSERT_TRUE(CBB_init(cbb.get(), 0)); - ASSERT_TRUE(CBB_add_asn1(cbb.get(), &contents, CBS_ASN1_SEQUENCE)); + ASSERT_TRUE(CBB_add_asn1(cbb.get(), &contents, 0x30)); ASSERT_TRUE(CBB_add_bytes(&contents, (const uint8_t *)"\x01\x02\x03", 3)); - ASSERT_TRUE( - CBB_add_asn1(cbb.get(), &contents, - CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 4)); - ASSERT_TRUE(CBB_add_bytes(&contents, (const uint8_t *)"\x04\x05\x06", 3)); - ASSERT_TRUE( - CBB_add_asn1(cbb.get(), &contents, - CBS_ASN1_APPLICATION | 30)); - ASSERT_TRUE(CBB_add_bytes(&contents, (const uint8_t *)"\x07\x08\x09", 3)); - ASSERT_TRUE( - CBB_add_asn1(cbb.get(), &contents, - CBS_ASN1_APPLICATION | 31)); - ASSERT_TRUE(CBB_add_bytes(&contents, (const uint8_t *)"\x0a\x0b\x0c", 3)); - ASSERT_TRUE( - CBB_add_asn1(cbb.get(), &contents, - CBS_ASN1_PRIVATE | CBS_ASN1_CONSTRUCTED | 0x1fffffff)); - ASSERT_TRUE(CBB_add_bytes(&contents, (const uint8_t *)"\x0d\x0e\x0f", 3)); ASSERT_TRUE(CBB_finish(cbb.get(), &buf, &buf_len)); bssl::UniquePtr<uint8_t> scoper(buf); @@ -523,7 +432,7 @@ TEST(CBBTest, ASN1) { std::vector<uint8_t> test_data(100000, 0x42); ASSERT_TRUE(CBB_init(cbb.get(), 0)); - ASSERT_TRUE(CBB_add_asn1(cbb.get(), &contents, CBS_ASN1_SEQUENCE)); + ASSERT_TRUE(CBB_add_asn1(cbb.get(), &contents, 0x30)); ASSERT_TRUE(CBB_add_bytes(&contents, test_data.data(), 130)); ASSERT_TRUE(CBB_finish(cbb.get(), &buf, &buf_len)); scoper.reset(buf); @@ -533,7 +442,7 @@ TEST(CBBTest, ASN1) { EXPECT_EQ(Bytes(test_data.data(), 130), Bytes(buf + 3, 130)); ASSERT_TRUE(CBB_init(cbb.get(), 0)); - ASSERT_TRUE(CBB_add_asn1(cbb.get(), &contents, CBS_ASN1_SEQUENCE)); + ASSERT_TRUE(CBB_add_asn1(cbb.get(), &contents, 0x30)); ASSERT_TRUE(CBB_add_bytes(&contents, test_data.data(), 1000)); ASSERT_TRUE(CBB_finish(cbb.get(), &buf, &buf_len)); scoper.reset(buf); @@ -543,8 +452,8 @@ TEST(CBBTest, ASN1) { EXPECT_EQ(Bytes(test_data.data(), 1000), Bytes(buf + 4, 1000)); ASSERT_TRUE(CBB_init(cbb.get(), 0)); - ASSERT_TRUE(CBB_add_asn1(cbb.get(), &contents, CBS_ASN1_SEQUENCE)); - ASSERT_TRUE(CBB_add_asn1(&contents, &inner_contents, CBS_ASN1_SEQUENCE)); + ASSERT_TRUE(CBB_add_asn1(cbb.get(), &contents, 0x30)); + ASSERT_TRUE(CBB_add_asn1(&contents, &inner_contents, 0x30)); ASSERT_TRUE(CBB_add_bytes(&inner_contents, test_data.data(), 100000)); ASSERT_TRUE(CBB_finish(cbb.get(), &buf, &buf_len)); scoper.reset(buf); @@ -581,12 +490,6 @@ TEST(CBSTest, BerConvert) { static const uint8_t kIndefBER[] = {0x30, 0x80, 0x01, 0x01, 0x02, 0x00, 0x00}; static const uint8_t kIndefDER[] = {0x30, 0x03, 0x01, 0x01, 0x02}; - // kIndefBER2 contains a constructed [APPLICATION 31] with an indefinite - // length. - static const uint8_t kIndefBER2[] = {0x7f, 0x1f, 0x80, 0x01, - 0x01, 0x02, 0x00, 0x00}; - static const uint8_t kIndefDER2[] = {0x7f, 0x1f, 0x03, 0x01, 0x01, 0x02}; - // kOctetStringBER contains an indefinite length OCTET STRING with two parts. // These parts need to be concatenated in DER form. static const uint8_t kOctetStringBER[] = {0x24, 0x80, 0x04, 0x02, 0, 1, @@ -631,8 +534,6 @@ TEST(CBSTest, BerConvert) { sizeof(kSimpleBER)); ExpectBerConvert("kIndefBER", kIndefDER, sizeof(kIndefDER), kIndefBER, sizeof(kIndefBER)); - ExpectBerConvert("kIndefBER2", kIndefDER2, sizeof(kIndefDER2), kIndefBER2, - sizeof(kIndefBER2)); ExpectBerConvert("kOctetStringBER", kOctetStringDER, sizeof(kOctetStringDER), kOctetStringBER, sizeof(kOctetStringBER)); ExpectBerConvert("kNSSBER", kNSSDER, sizeof(kNSSDER), kNSSBER, @@ -886,3 +787,98 @@ TEST(CBSTest, BitString) { CBS_asn1_bitstring_has_bit(&cbs, test.bit)); } } + +TEST(CBBTest, AddOIDFromText) { + const struct { + const char *text; + std::vector<uint8_t> der; + } kValidOIDs[] = { + // Some valid values. + {"0.0", {0x00}}, + {"0.2.3.4", {0x2, 0x3, 0x4}}, + {"1.2.3.4", {0x2a, 0x3, 0x4}}, + {"2.2.3.4", {0x52, 0x3, 0x4}}, + {"1.2.840.113554.4.1.72585", + {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x04, 0x01, 0x84, 0xb7, 0x09}}, + // Test edge cases around the first component. + {"0.39", {0x27}}, + {"1.0", {0x28}}, + {"1.39", {0x4f}}, + {"2.0", {0x50}}, + {"2.1", {0x51}}, + {"2.40", {0x78}}, + // Edge cases near an overflow. + {"1.2.18446744073709551615", + {0x2a, 0x81, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f}}, + {"2.18446744073709551535", + {0x81, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f}}, + }; + + const char *kInvalidTexts[] = { + // Invalid second component. + "0.40", + "1.40", + // Invalid first component. + "3.1", + // The empty string is not an OID. + "", + // No empty components. + ".1.2.3.4.5", + "1..2.3.4.5", + "1.2.3.4.5.", + // There must be at least two components. + "1", + // No extra leading zeros. + "00.1.2.3.4", + "01.1.2.3.4", + // Overflow for both components or 40*A + B. + "1.2.18446744073709551616", + "2.18446744073709551536", + }; + + const std::vector<uint8_t> kInvalidDER[] = { + // The empty string is not an OID. + {}, + // Non-minimal representation. + {0x80, 0x01}, + // Overflow. This is the DER representation of + // 1.2.840.113554.4.1.72585.18446744073709551616. (The final value is + // 2^64.) + {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x04, 0x01, 0x84, 0xb7, 0x09, + 0x82, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00}, + }; + + for (const auto &t : kValidOIDs) { + SCOPED_TRACE(t.text); + + bssl::ScopedCBB cbb; + ASSERT_TRUE(CBB_init(cbb.get(), 0)); + ASSERT_TRUE(CBB_add_asn1_oid_from_text(cbb.get(), t.text, strlen(t.text))); + uint8_t *out; + size_t len; + ASSERT_TRUE(CBB_finish(cbb.get(), &out, &len)); + bssl::UniquePtr<uint8_t> free_out(out); + EXPECT_EQ(Bytes(t.der), Bytes(out, len)); + + CBS cbs; + CBS_init(&cbs, t.der.data(), t.der.size()); + bssl::UniquePtr<char> text(CBS_asn1_oid_to_text(&cbs)); + ASSERT_TRUE(text.get()); + EXPECT_STREQ(t.text, text.get()); + } + + for (const char *t : kInvalidTexts) { + SCOPED_TRACE(t); + bssl::ScopedCBB cbb; + ASSERT_TRUE(CBB_init(cbb.get(), 0)); + EXPECT_FALSE(CBB_add_asn1_oid_from_text(cbb.get(), t, strlen(t))); + } + + for (const auto &t : kInvalidDER) { + SCOPED_TRACE(Bytes(t)); + CBS cbs; + CBS_init(&cbs, t.data(), t.size()); + bssl::UniquePtr<char> text(CBS_asn1_oid_to_text(&cbs)); + EXPECT_FALSE(text); + } +} diff --git a/src/crypto/bytestring/cbb.c b/src/crypto/bytestring/cbb.c index b1afe7d5..f8f5e0f1 100644 --- a/src/crypto/bytestring/cbb.c +++ b/src/crypto/bytestring/cbb.c @@ -15,6 +15,7 @@ #include <openssl/bytestring.h> #include <assert.h> +#include <limits.h> #include <string.h> #include <openssl/mem.h> @@ -328,37 +329,44 @@ int CBB_add_u24_length_prefixed(CBB *cbb, CBB *out_contents) { return cbb_add_length_prefixed(cbb, out_contents, 3); } -int CBB_add_asn1(CBB *cbb, CBB *out_contents, unsigned tag) { - if (!CBB_flush(cbb)) { - return 0; +// add_base128_integer encodes |v| as a big-endian base-128 integer where the +// high bit of each byte indicates where there is more data. This is the +// encoding used in DER for both high tag number form and OID components. +static int add_base128_integer(CBB *cbb, uint64_t v) { + unsigned len_len = 0; + uint64_t copy = v; + while (copy > 0) { + len_len++; + copy >>= 7; } - - // Split the tag into leading bits and tag number. - uint8_t tag_bits = (tag >> CBS_ASN1_TAG_SHIFT) & 0xe0; - unsigned tag_number = tag & CBS_ASN1_TAG_NUMBER_MASK; - if (tag_number >= 0x1f) { - // Set all the bits in the tag number to signal high tag number form. - if (!CBB_add_u8(cbb, tag_bits | 0x1f)) { + if (len_len == 0) { + len_len = 1; // Zero is encoded with one byte. + } + for (unsigned i = len_len - 1; i < len_len; i--) { + uint8_t byte = (v >> (7 * i)) & 0x7f; + if (i != 0) { + // The high bit denotes whether there is more data. + byte |= 0x80; + } + if (!CBB_add_u8(cbb, byte)) { return 0; } + } + return 1; +} - unsigned len_len = 0; - unsigned copy = tag_number; - while (copy > 0) { - len_len++; - copy >>= 7; - } - for (unsigned i = len_len - 1; i < len_len; i--) { - uint8_t byte = (tag_number >> (7 * i)) & 0x7f; - if (i != 0) { - // The high bit denotes whether there is more data. - byte |= 0x80; - } - if (!CBB_add_u8(cbb, byte)) { - return 0; - } - } - } else if (!CBB_add_u8(cbb, tag_bits | tag_number)) { +int CBB_add_asn1(CBB *cbb, CBB *out_contents, unsigned tag) { + if (tag > 0xff || + (tag & 0x1f) == 0x1f) { + // Long form identifier octets are not supported. Further, all current valid + // tag serializations are 8 bits. + cbb->base->error = 1; + return 0; + } + + if (!CBB_flush(cbb) || + // |tag|'s representation matches the DER encoding. + !CBB_add_u8(cbb, (uint8_t)tag)) { return 0; } @@ -492,3 +500,69 @@ int CBB_add_asn1_uint64(CBB *cbb, uint64_t value) { return CBB_flush(cbb); } + +// parse_dotted_decimal parses one decimal component from |cbs|, where |cbs| is +// an OID literal, e.g., "1.2.840.113554.4.1.72585". It consumes both the +// component and the dot, so |cbs| may be passed into the function again for the +// next value. +static int parse_dotted_decimal(CBS *cbs, uint64_t *out) { + *out = 0; + int seen_digit = 0; + for (;;) { + // Valid terminators for a component are the end of the string or a + // non-terminal dot. If the string ends with a dot, this is not a valid OID + // string. + uint8_t u; + if (!CBS_get_u8(cbs, &u) || + (u == '.' && CBS_len(cbs) > 0)) { + break; + } + if (u < '0' || u > '9' || + // Forbid stray leading zeros. + (seen_digit && *out == 0) || + // Check for overflow. + *out > UINT64_MAX / 10 || + *out * 10 > UINT64_MAX - (u - '0')) { + return 0; + } + *out = *out * 10 + (u - '0'); + seen_digit = 1; + } + // The empty string is not a legal OID component. + return seen_digit; +} + +int CBB_add_asn1_oid_from_text(CBB *cbb, const char *text, size_t len) { + if (!CBB_flush(cbb)) { + return 0; + } + + CBS cbs; + CBS_init(&cbs, (const uint8_t *)text, len); + + // OIDs must have at least two components. + uint64_t a, b; + if (!parse_dotted_decimal(&cbs, &a) || + !parse_dotted_decimal(&cbs, &b)) { + return 0; + } + + // The first component is encoded as 40 * |a| + |b|. This assumes that |a| is + // 0, 1, or 2 and that, when it is 0 or 1, |b| is at most 39. + if (a > 2 || + (a < 2 && b > 39) || + b > UINT64_MAX - 80 || + !add_base128_integer(cbb, 40u * a + b)) { + return 0; + } + + // The remaining components are encoded unmodified. + while (CBS_len(&cbs) > 0) { + if (!parse_dotted_decimal(&cbs, &a) || + !add_base128_integer(cbb, a)) { + return 0; + } + } + + return 1; +} diff --git a/src/crypto/bytestring/cbs.c b/src/crypto/bytestring/cbs.c index d96371ce..f3fc8636 100644 --- a/src/crypto/bytestring/cbs.c +++ b/src/crypto/bytestring/cbs.c @@ -12,11 +12,16 @@ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#if !defined(__STDC_FORMAT_MACROS) +#define __STDC_FORMAT_MACROS +#endif + #include <openssl/buf.h> #include <openssl/mem.h> #include <openssl/bytestring.h> #include <assert.h> +#include <inttypes.h> #include <string.h> #include "internal.h" @@ -175,53 +180,36 @@ int CBS_get_u24_length_prefixed(CBS *cbs, CBS *out) { return cbs_get_length_prefixed(cbs, out, 3); } -static int parse_asn1_tag(CBS *cbs, unsigned *out) { - uint8_t tag_byte; - if (!CBS_get_u8(cbs, &tag_byte)) { - return 0; - } - - // ITU-T X.690 section 8.1.2.3 specifies the format for identifiers with a tag - // number no greater than 30. - // - // If the number portion is 31 (0x1f, the largest value that fits in the - // allotted bits), then the tag is more than one byte long and the - // continuation bytes contain the tag number. This parser only supports tag - // numbers less than 31 (and thus single-byte tags). - unsigned tag = ((unsigned)tag_byte & 0xe0) << CBS_ASN1_TAG_SHIFT; - unsigned tag_number = tag_byte & 0x1f; - if (tag_number == 0x1f) { - tag_number = 0; - for (;;) { - if (!CBS_get_u8(cbs, &tag_byte) || - ((tag_number << 7) >> 7) != tag_number) { - return 0; - } - tag_number = (tag_number << 7) | (tag_byte & 0x7f); - // The tag must be represented in the minimal number of bytes. - if (tag_number == 0) { - return 0; - } - if ((tag_byte & 0x80) == 0) { - break; - } +// parse_base128_integer reads a big-endian base-128 integer from |cbs| and sets +// |*out| to the result. This is the encoding used in DER for both high tag +// number form and OID components. +static int parse_base128_integer(CBS *cbs, uint64_t *out) { + uint64_t v = 0; + uint8_t b; + do { + if (!CBS_get_u8(cbs, &b)) { + return 0; } - if (// Check the tag number is within our supported bounds. - tag_number > CBS_ASN1_TAG_NUMBER_MASK || - // Small tag numbers should have used low tag number form. - tag_number < 0x1f) { + if ((v >> (64 - 7)) != 0) { + // The value is too large. return 0; } - } + if (v == 0 && b == 0x80) { + // The value must be minimally encoded. + return 0; + } + v = (v << 7) | (b & 0x7f); - tag |= tag_number; + // Values end at an octet with the high bit cleared. + } while (b & 0x80); - *out = tag; + *out = v; return 1; } static int cbs_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag, size_t *out_header_len, int ber_ok) { + uint8_t tag, length_byte; CBS header = *cbs; CBS throwaway; @@ -229,29 +217,34 @@ static int cbs_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag, out = &throwaway; } - unsigned tag; - if (!parse_asn1_tag(&header, &tag)) { + if (!CBS_get_u8(&header, &tag) || + !CBS_get_u8(&header, &length_byte)) { return 0; } - if (out_tag != NULL) { - *out_tag = tag; - } - uint8_t length_byte; - if (!CBS_get_u8(&header, &length_byte)) { + // ITU-T X.690 section 8.1.2.3 specifies the format for identifiers with a tag + // number no greater than 30. + // + // If the number portion is 31 (0x1f, the largest value that fits in the + // allotted bits), then the tag is more than one byte long and the + // continuation bytes contain the tag number. This parser only supports tag + // numbers less than 31 (and thus single-byte tags). + if ((tag & 0x1f) == 0x1f) { return 0; } - size_t header_len = CBS_len(cbs) - CBS_len(&header); + if (out_tag != NULL) { + *out_tag = tag; + } size_t len; // The format for the length encoding is specified in ITU-T X.690 section // 8.1.3. if ((length_byte & 0x80) == 0) { // Short form length. - len = ((size_t) length_byte) + header_len; + len = ((size_t) length_byte) + 2; if (out_header_len != NULL) { - *out_header_len = header_len; + *out_header_len = 2; } } else { // The high bit indicate that this is the long form, while the next 7 bits @@ -263,9 +256,9 @@ static int cbs_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag, if (ber_ok && (tag & CBS_ASN1_CONSTRUCTED) != 0 && num_bytes == 0) { // indefinite length if (out_header_len != NULL) { - *out_header_len = header_len; + *out_header_len = 2; } - return CBS_get_bytes(cbs, out, header_len); + return CBS_get_bytes(cbs, out, 2); } // ITU-T X.690 clause 8.1.3.5.c specifies that the value 0xff shall not be @@ -288,13 +281,13 @@ static int cbs_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag, return 0; } len = len32; - if (len + header_len + num_bytes < len) { + if (len + 2 + num_bytes < len) { // Overflow. return 0; } - len += header_len + num_bytes; + len += 2 + num_bytes; if (out_header_len != NULL) { - *out_header_len = header_len + num_bytes; + *out_header_len = 2 + num_bytes; } } @@ -362,10 +355,7 @@ int CBS_peek_asn1_tag(const CBS *cbs, unsigned tag_value) { if (CBS_len(cbs) < 1) { return 0; } - - CBS copy = *cbs; - unsigned actual_tag; - return parse_asn1_tag(©, &actual_tag) && tag_value == actual_tag; + return CBS_data(cbs)[0] == tag_value; } int CBS_get_asn1_uint64(CBS *cbs, uint64_t *out) { @@ -527,3 +517,55 @@ int CBS_asn1_bitstring_has_bit(const CBS *cbs, unsigned bit) { return byte_num < CBS_len(cbs) && (CBS_data(cbs)[byte_num] & (1 << bit_num)) != 0; } + +static int add_decimal(CBB *out, uint64_t v) { + char buf[DECIMAL_SIZE(uint64_t) + 1]; + BIO_snprintf(buf, sizeof(buf), "%" PRIu64, v); + return CBB_add_bytes(out, (const uint8_t *)buf, strlen(buf)); +} + +char *CBS_asn1_oid_to_text(const CBS *cbs) { + CBB cbb; + if (!CBB_init(&cbb, 32)) { + goto err; + } + + CBS copy = *cbs; + // The first component is 40 * value1 + value2, where value1 is 0, 1, or 2. + uint64_t v; + if (!parse_base128_integer(©, &v)) { + goto err; + } + + if (v >= 80) { + if (!CBB_add_bytes(&cbb, (const uint8_t *)"2.", 2) || + !add_decimal(&cbb, v - 80)) { + goto err; + } + } else if (!add_decimal(&cbb, v / 40) || + !CBB_add_u8(&cbb, '.') || + !add_decimal(&cbb, v % 40)) { + goto err; + } + + while (CBS_len(©) != 0) { + if (!parse_base128_integer(©, &v) || + !CBB_add_u8(&cbb, '.') || + !add_decimal(&cbb, v)) { + goto err; + } + } + + uint8_t *txt; + size_t txt_len; + if (!CBB_add_u8(&cbb, '\0') || + !CBB_finish(&cbb, &txt, &txt_len)) { + goto err; + } + + return (char *)txt; + +err: + CBB_cleanup(&cbb); + return NULL; +} diff --git a/src/crypto/err/obj.errordata b/src/crypto/err/obj.errordata index c54435ea..be134516 100644 --- a/src/crypto/err/obj.errordata +++ b/src/crypto/err/obj.errordata @@ -1 +1,2 @@ +OBJ,101,INVALID_OID_STRING OBJ,100,UNKNOWN_NID diff --git a/src/crypto/fipsmodule/bn/rsaz_exp.c b/src/crypto/fipsmodule/bn/rsaz_exp.c index d0090a66..cb9a233e 100644 --- a/src/crypto/fipsmodule/bn/rsaz_exp.c +++ b/src/crypto/fipsmodule/bn/rsaz_exp.c @@ -227,7 +227,9 @@ void RSAZ_1024_mod_exp_avx2(BN_ULONG result_norm[16], rsaz_1024_sqr_avx2(result, result, m, k0, 5); - wvalue = *((const unsigned short*)&p_str[index / 8]); + uint16_t wvalue_16; + memcpy(&wvalue_16, &p_str[index / 8], sizeof(wvalue_16)); + wvalue = wvalue_16; wvalue = (wvalue>> (index%8)) & 31; index-=5; diff --git a/src/crypto/fipsmodule/ec/ec.c b/src/crypto/fipsmodule/ec/ec.c index 977cd265..266baa24 100644 --- a/src/crypto/fipsmodule/ec/ec.c +++ b/src/crypto/fipsmodule/ec/ec.c @@ -817,6 +817,24 @@ int EC_POINT_invert(const EC_GROUP *group, EC_POINT *a, BN_CTX *ctx) { return ec_GFp_simple_invert(group, a, ctx); } +static int arbitrary_bignum_to_scalar(const EC_GROUP *group, EC_SCALAR *out, + const BIGNUM *in, BN_CTX *ctx) { + const BIGNUM *order = EC_GROUP_get0_order(group); + if (BN_is_negative(in) || BN_num_bits(in) > BN_num_bits(order)) { + // This is an unusual input, so we do not guarantee constant-time + // processing, even ignoring |bn_correct_top|. + BN_CTX_start(ctx); + BIGNUM *tmp = BN_CTX_get(ctx); + int ok = tmp != NULL && + BN_nnmod(tmp, in, order, ctx) && + ec_bignum_to_scalar(group, out, tmp); + BN_CTX_end(ctx); + return ok; + } + + return ec_bignum_to_scalar(group, out, in); +} + int EC_POINT_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar, const EC_POINT *p, const BIGNUM *p_scalar, BN_CTX *ctx) { // Previously, this function set |r| to the point at infinity if there was @@ -828,30 +846,27 @@ int EC_POINT_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar, return 0; } - // We cannot easily process arbitrary scalars in constant-time, and there is - // no need to do so. Require that scalars be the same size as the order. - // - // One could require they be fully reduced, but some consumers try to check - // that |order| * |pubkey| is the identity. This comes from following NIST SP - // 800-56A section 5.6.2.3.2. (Though all our curves have cofactor one, so - // this check isn't useful.) int ret = 0; EC_SCALAR g_scalar_storage, p_scalar_storage; EC_SCALAR *g_scalar_arg = NULL, *p_scalar_arg = NULL; - unsigned order_bits = BN_num_bits(&group->order); + BN_CTX *new_ctx = NULL; + if (ctx == NULL) { + new_ctx = BN_CTX_new(); + if (new_ctx == NULL) { + goto err; + } + ctx = new_ctx; + } + if (g_scalar != NULL) { - if (BN_is_negative(g_scalar) || BN_num_bits(g_scalar) > order_bits || - !ec_bignum_to_scalar(group, &g_scalar_storage, g_scalar)) { - OPENSSL_PUT_ERROR(EC, EC_R_INVALID_SCALAR); + if (!arbitrary_bignum_to_scalar(group, &g_scalar_storage, g_scalar, ctx)) { goto err; } g_scalar_arg = &g_scalar_storage; } if (p_scalar != NULL) { - if (BN_is_negative(p_scalar) || BN_num_bits(p_scalar) > order_bits || - !ec_bignum_to_scalar(group, &p_scalar_storage, p_scalar)) { - OPENSSL_PUT_ERROR(EC, EC_R_INVALID_SCALAR); + if (!arbitrary_bignum_to_scalar(group, &p_scalar_storage, p_scalar, ctx)) { goto err; } p_scalar_arg = &p_scalar_storage; @@ -860,6 +875,7 @@ int EC_POINT_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar, ret = ec_point_mul_scalar(group, r, g_scalar_arg, p, p_scalar_arg, ctx); err: + BN_CTX_free(new_ctx); OPENSSL_cleanse(&g_scalar_storage, sizeof(g_scalar_storage)); OPENSSL_cleanse(&p_scalar_storage, sizeof(p_scalar_storage)); return ret; diff --git a/src/crypto/fipsmodule/ec/ec_test.cc b/src/crypto/fipsmodule/ec/ec_test.cc index 5e5ce948..139840e5 100644 --- a/src/crypto/fipsmodule/ec/ec_test.cc +++ b/src/crypto/fipsmodule/ec/ec_test.cc @@ -439,6 +439,52 @@ TEST_P(ECCurveTest, MulOrder) { << "p * order did not return point at infinity."; } +// Test that |EC_POINT_mul| works with out-of-range scalars. Even beyond the +// usual |bn_correct_top| disclaimer, we completely disclaim all hope here as a +// reduction is needed, but we'll compute the right answer. +TEST_P(ECCurveTest, MulOutOfRange) { + bssl::UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(GetParam().nid)); + ASSERT_TRUE(group); + + bssl::UniquePtr<BIGNUM> n_minus_one(BN_dup(EC_GROUP_get0_order(group.get()))); + ASSERT_TRUE(n_minus_one); + ASSERT_TRUE(BN_sub_word(n_minus_one.get(), 1)); + + bssl::UniquePtr<BIGNUM> minus_one(BN_new()); + ASSERT_TRUE(minus_one); + ASSERT_TRUE(BN_one(minus_one.get())); + BN_set_negative(minus_one.get(), 1); + + bssl::UniquePtr<BIGNUM> seven(BN_new()); + ASSERT_TRUE(seven); + ASSERT_TRUE(BN_set_word(seven.get(), 7)); + + bssl::UniquePtr<BIGNUM> ten_n_plus_seven( + BN_dup(EC_GROUP_get0_order(group.get()))); + ASSERT_TRUE(ten_n_plus_seven); + ASSERT_TRUE(BN_mul_word(ten_n_plus_seven.get(), 10)); + ASSERT_TRUE(BN_add_word(ten_n_plus_seven.get(), 7)); + + bssl::UniquePtr<EC_POINT> point1(EC_POINT_new(group.get())), + point2(EC_POINT_new(group.get())); + ASSERT_TRUE(point1); + ASSERT_TRUE(point2); + + ASSERT_TRUE(EC_POINT_mul(group.get(), point1.get(), n_minus_one.get(), + nullptr, nullptr, nullptr)); + ASSERT_TRUE(EC_POINT_mul(group.get(), point2.get(), minus_one.get(), nullptr, + nullptr, nullptr)); + EXPECT_EQ(0, EC_POINT_cmp(group.get(), point1.get(), point2.get(), nullptr)) + << "-1 * G and (n-1) * G did not give the same result"; + + ASSERT_TRUE(EC_POINT_mul(group.get(), point1.get(), seven.get(), nullptr, + nullptr, nullptr)); + ASSERT_TRUE(EC_POINT_mul(group.get(), point2.get(), ten_n_plus_seven.get(), + nullptr, nullptr, nullptr)); + EXPECT_EQ(0, EC_POINT_cmp(group.get(), point1.get(), point2.get(), nullptr)) + << "7 * G and (10n + 7) * G did not give the same result"; +} + // Test that 10×∞ + G = G. TEST_P(ECCurveTest, Mul) { bssl::UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(GetParam().nid)); diff --git a/src/crypto/obj/obj.c b/src/crypto/obj/obj.c index 52e265b0..a34d6dc0 100644 --- a/src/crypto/obj/obj.c +++ b/src/crypto/obj/obj.c @@ -389,16 +389,30 @@ const char *OBJ_nid2ln(int nid) { return obj->ln; } -ASN1_OBJECT *OBJ_txt2obj(const char *s, int dont_search_names) { - int nid = NID_undef; - ASN1_OBJECT *op = NULL; - unsigned char *buf; - unsigned char *p; - const unsigned char *bufp; - int contents_len, total_len; +static ASN1_OBJECT *create_object_with_text_oid(int (*get_nid)(void), + const char *oid, + const char *short_name, + const char *long_name) { + uint8_t *buf; + size_t len; + CBB cbb; + if (!CBB_init(&cbb, 32) || + !CBB_add_asn1_oid_from_text(&cbb, oid, strlen(oid)) || + !CBB_finish(&cbb, &buf, &len)) { + OPENSSL_PUT_ERROR(OBJ, OBJ_R_INVALID_OID_STRING); + CBB_cleanup(&cbb); + return NULL; + } + ASN1_OBJECT *ret = ASN1_OBJECT_create(get_nid ? get_nid() : NID_undef, buf, + len, short_name, long_name); + OPENSSL_free(buf); + return ret; +} + +ASN1_OBJECT *OBJ_txt2obj(const char *s, int dont_search_names) { if (!dont_search_names) { - nid = OBJ_sn2nid(s); + int nid = OBJ_sn2nid(s); if (nid == NID_undef) { nid = OBJ_ln2nid(s); } @@ -408,31 +422,7 @@ ASN1_OBJECT *OBJ_txt2obj(const char *s, int dont_search_names) { } } - // Work out size of content octets - contents_len = a2d_ASN1_OBJECT(NULL, 0, s, -1); - if (contents_len <= 0) { - return NULL; - } - // Work out total size - total_len = ASN1_object_size(0, contents_len, V_ASN1_OBJECT); - - buf = OPENSSL_malloc(total_len); - if (buf == NULL) { - OPENSSL_PUT_ERROR(OBJ, ERR_R_MALLOC_FAILURE); - return NULL; - } - - p = buf; - // Write out tag+length - ASN1_put_object(&p, 0, contents_len, V_ASN1_OBJECT, V_ASN1_UNIVERSAL); - // Write out contents - a2d_ASN1_OBJECT(p, contents_len, s, -1); - - bufp = buf; - op = d2i_ASN1_OBJECT(NULL, &bufp, total_len); - OPENSSL_free(buf); - - return op; + return create_object_with_text_oid(NULL, s, NULL, NULL); } static int strlcpy_int(char *dst, const char *src, int dst_size) { @@ -444,36 +434,6 @@ static int strlcpy_int(char *dst, const char *src, int dst_size) { return (int)ret; } -static int parse_oid_component(CBS *cbs, uint64_t *out) { - uint64_t v = 0; - uint8_t b; - do { - if (!CBS_get_u8(cbs, &b)) { - return 0; - } - if ((v >> (64 - 7)) != 0) { - // The component is too large. - return 0; - } - if (v == 0 && b == 0x80) { - // The component must be minimally encoded. - return 0; - } - v = (v << 7) | (b & 0x7f); - - // Components end at an octet with the high bit cleared. - } while (b & 0x80); - - *out = v; - return 1; -} - -static int add_decimal(CBB *out, uint64_t v) { - char buf[DECIMAL_SIZE(uint64_t) + 1]; - BIO_snprintf(buf, sizeof(buf), "%" PRIu64, v); - return CBB_add_bytes(out, (const uint8_t *)buf, strlen(buf)); -} - int OBJ_obj2txt(char *out, int out_len, const ASN1_OBJECT *obj, int always_return_oid) { // Python depends on the empty OID successfully encoding as the empty @@ -495,56 +455,19 @@ int OBJ_obj2txt(char *out, int out_len, const ASN1_OBJECT *obj, } } - CBB cbb; - if (!CBB_init(&cbb, 32)) { - goto err; - } - CBS cbs; CBS_init(&cbs, obj->data, obj->length); - - // The first component is 40 * value1 + value2, where value1 is 0, 1, or 2. - uint64_t v; - if (!parse_oid_component(&cbs, &v)) { - goto err; - } - - if (v >= 80) { - if (!CBB_add_bytes(&cbb, (const uint8_t *)"2.", 2) || - !add_decimal(&cbb, v - 80)) { - goto err; + char *txt = CBS_asn1_oid_to_text(&cbs); + if (txt == NULL) { + if (out_len > 0) { + out[0] = '\0'; } - } else if (!add_decimal(&cbb, v / 40) || - !CBB_add_u8(&cbb, '.') || - !add_decimal(&cbb, v % 40)) { - goto err; - } - - while (CBS_len(&cbs) != 0) { - if (!parse_oid_component(&cbs, &v) || - !CBB_add_u8(&cbb, '.') || - !add_decimal(&cbb, v)) { - goto err; - } - } - - uint8_t *txt; - size_t txt_len; - if (!CBB_add_u8(&cbb, '\0') || - !CBB_finish(&cbb, &txt, &txt_len)) { - goto err; + return -1; } - int ret = strlcpy_int(out, (const char *)txt, out_len); + int ret = strlcpy_int(out, txt, out_len); OPENSSL_free(txt); return ret; - -err: - CBB_cleanup(&cbb); - if (out_len > 0) { - out[0] = '\0'; - } - return -1; } static uint32_t hash_nid(const ASN1_OBJECT *obj) { @@ -621,41 +544,11 @@ static int obj_add_object(ASN1_OBJECT *obj) { } int OBJ_create(const char *oid, const char *short_name, const char *long_name) { - int ret = NID_undef; - ASN1_OBJECT *op = NULL; - unsigned char *buf = NULL; - int len; - - len = a2d_ASN1_OBJECT(NULL, 0, oid, -1); - if (len <= 0) { - goto err; - } - - buf = OPENSSL_malloc(len); - if (buf == NULL) { - OPENSSL_PUT_ERROR(OBJ, ERR_R_MALLOC_FAILURE); - goto err; - } - - len = a2d_ASN1_OBJECT(buf, len, oid, -1); - if (len == 0) { - goto err; - } - - op = (ASN1_OBJECT *)ASN1_OBJECT_create(obj_next_nid(), buf, len, short_name, - long_name); - if (op == NULL) { - goto err; - } - - if (obj_add_object(op)) { - ret = op->nid; + ASN1_OBJECT *op = + create_object_with_text_oid(obj_next_nid, oid, short_name, long_name); + if (op == NULL || + !obj_add_object(op)) { + return NID_undef; } - op = NULL; - -err: - ASN1_OBJECT_free(op); - OPENSSL_free(buf); - - return ret; + return op->nid; } diff --git a/src/crypto/x509/x509_test.cc b/src/crypto/x509/x509_test.cc index cd4e61d7..158fd458 100644 --- a/src/crypto/x509/x509_test.cc +++ b/src/crypto/x509/x509_test.cc @@ -26,6 +26,7 @@ #include <openssl/pem.h> #include <openssl/pool.h> #include <openssl/x509.h> +#include <openssl/x509v3.h> #include "../internal.h" @@ -834,7 +835,7 @@ TEST(X509Test, TestFromBuffer) { /* This ensures the X509 took a reference to |buf|, otherwise this will be a * reference to free memory and ASAN should notice. */ - ASSERT_EQ(0x30, enc_pointer[0]); + ASSERT_EQ(CBS_ASN1_SEQUENCE, enc_pointer[0]); } TEST(X509Test, TestFromBufferWithTrailingData) { @@ -996,3 +997,41 @@ TEST(X509Test, TestPrintUTCTIME) { std::string(reinterpret_cast<const char *>(contents), len)); } } + +TEST(X509Test, PrettyPrintIntegers) { + static const char *kTests[] = { + // Small numbers are pretty-printed in decimal. + "0", + "-1", + "1", + "42", + "-42", + "256", + "-256", + // Large numbers are pretty-printed in hex to avoid taking quadratic time. + "0x0123456789", + "-0x0123456789", + }; + for (const char *in : kTests) { + SCOPED_TRACE(in); + BIGNUM *bn = nullptr; + ASSERT_TRUE(BN_asc2bn(&bn, in)); + bssl::UniquePtr<BIGNUM> free_bn(bn); + + { + bssl::UniquePtr<ASN1_INTEGER> asn1(BN_to_ASN1_INTEGER(bn, nullptr)); + ASSERT_TRUE(asn1); + bssl::UniquePtr<char> out(i2s_ASN1_INTEGER(nullptr, asn1.get())); + ASSERT_TRUE(out.get()); + EXPECT_STREQ(in, out.get()); + } + + { + bssl::UniquePtr<ASN1_ENUMERATED> asn1(BN_to_ASN1_ENUMERATED(bn, nullptr)); + ASSERT_TRUE(asn1); + bssl::UniquePtr<char> out(i2s_ASN1_ENUMERATED(nullptr, asn1.get())); + ASSERT_TRUE(out.get()); + EXPECT_STREQ(in, out.get()); + } + } +} diff --git a/src/crypto/x509v3/v3_utl.c b/src/crypto/x509v3/v3_utl.c index feb3dc6a..7d109ee6 100644 --- a/src/crypto/x509v3/v3_utl.c +++ b/src/crypto/x509v3/v3_utl.c @@ -155,6 +155,45 @@ int X509V3_add_value_bool_nf(char *name, int asn1_bool, return 1; } +static char *bignum_to_string(const BIGNUM *bn) +{ + char *tmp, *ret; + size_t len; + + /* + * Display large numbers in hex and small numbers in decimal. Converting to + * decimal takes quadratic time and is no more useful than hex for large + * numbers. + */ + if (BN_num_bits(bn) < 32) { + return BN_bn2dec(bn); + } + + tmp = BN_bn2hex(bn); + if (tmp == NULL) { + return NULL; + } + + len = strlen(tmp) + 3; + ret = OPENSSL_malloc(len); + if (ret == NULL) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + OPENSSL_free(tmp); + return NULL; + } + + /* Prepend "0x", but place it after the "-" if negative. */ + if (tmp[0] == '-') { + BUF_strlcpy(ret, "-0x", len); + BUF_strlcat(ret, tmp + 1, len); + } else { + BUF_strlcpy(ret, "0x", len); + BUF_strlcat(ret, tmp, len); + } + OPENSSL_free(tmp); + return ret; +} + char *i2s_ASN1_ENUMERATED(X509V3_EXT_METHOD *method, ASN1_ENUMERATED *a) { BIGNUM *bntmp = NULL; @@ -162,7 +201,7 @@ char *i2s_ASN1_ENUMERATED(X509V3_EXT_METHOD *method, ASN1_ENUMERATED *a) if (!a) return NULL; if (!(bntmp = ASN1_ENUMERATED_to_BN(a, NULL)) || - !(strtmp = BN_bn2dec(bntmp))) + !(strtmp = bignum_to_string(bntmp))) OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); BN_free(bntmp); return strtmp; @@ -175,7 +214,7 @@ char *i2s_ASN1_INTEGER(X509V3_EXT_METHOD *method, ASN1_INTEGER *a) if (!a) return NULL; if (!(bntmp = ASN1_INTEGER_to_BN(a, NULL)) || - !(strtmp = BN_bn2dec(bntmp))) + !(strtmp = bignum_to_string(bntmp))) OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); BN_free(bntmp); return strtmp; diff --git a/src/include/openssl/asn1.h b/src/include/openssl/asn1.h index 2ef4c97e..5c8bf4cd 100644 --- a/src/include/openssl/asn1.h +++ b/src/include/openssl/asn1.h @@ -737,7 +737,6 @@ OPENSSL_EXPORT int i2a_ASN1_OBJECT(BIO *bp,ASN1_OBJECT *a); OPENSSL_EXPORT int i2a_ASN1_STRING(BIO *bp, ASN1_STRING *a, int type); OPENSSL_EXPORT int i2t_ASN1_OBJECT(char *buf,int buf_len,ASN1_OBJECT *a); -OPENSSL_EXPORT int a2d_ASN1_OBJECT(unsigned char *out,int olen, const char *buf, int num); OPENSSL_EXPORT ASN1_OBJECT *ASN1_OBJECT_create(int nid, unsigned char *data,int len, const char *sn, const char *ln); OPENSSL_EXPORT int ASN1_INTEGER_set(ASN1_INTEGER *a, long v); diff --git a/src/include/openssl/bytestring.h b/src/include/openssl/bytestring.h index 39068096..25411c71 100644 --- a/src/include/openssl/bytestring.h +++ b/src/include/openssl/bytestring.h @@ -164,36 +164,34 @@ OPENSSL_EXPORT int CBS_get_u24_length_prefixed(CBS *cbs, CBS *out); #define CBS_ASN1_UNIVERSALSTRING 0x1cu #define CBS_ASN1_BMPSTRING 0x1eu -// CBS_ASN1_TAG_SHIFT is how much the in-memory representation shifts the class -// and constructed bits from the DER serialization. This allows representing tag -// numbers beyond 31. -// -// Consumers must use the following constants to decompose or assemble tags. -#define CBS_ASN1_TAG_SHIFT 24 - // CBS_ASN1_CONSTRUCTED may be ORed into a tag to toggle the constructed // bit. |CBS| and |CBB| APIs consider the constructed bit to be part of the // tag. -#define CBS_ASN1_CONSTRUCTED (0x20u << CBS_ASN1_TAG_SHIFT) +#define CBS_ASN1_CONSTRUCTED 0x20u -// The following values specify the tag class and may be ORed into a tag number -// to produce the final tag. If none is used, the tag will be UNIVERSAL. -#define CBS_ASN1_UNIVERSAL (0u << CBS_ASN1_TAG_SHIFT) -#define CBS_ASN1_APPLICATION (0x40u << CBS_ASN1_TAG_SHIFT) -#define CBS_ASN1_CONTEXT_SPECIFIC (0x80u << CBS_ASN1_TAG_SHIFT) -#define CBS_ASN1_PRIVATE (0xc0u << CBS_ASN1_TAG_SHIFT) +// The following values specify the constructed bit or tag class and may be ORed +// into a tag number to produce the final tag. If none is used, the tag will be +// UNIVERSAL. +// +// Note that although they currently match the DER serialization, consumers must +// use these bits rather than make assumptions about the representation. This is +// to allow for tag numbers beyond 31 in the future. +#define CBS_ASN1_APPLICATION 0x40u +#define CBS_ASN1_CONTEXT_SPECIFIC 0x80u +#define CBS_ASN1_PRIVATE 0xc0u -// CBS_ASN1_CLASS_MASK may be ANDed with a tag to query its class. This will -// give one of the four values above. -#define CBS_ASN1_CLASS_MASK (0xc0u << CBS_ASN1_TAG_SHIFT) +// CBS_ASN1_CLASS_MASK may be ANDed with a tag to query its class. +#define CBS_ASN1_CLASS_MASK 0xc0u // CBS_ASN1_TAG_NUMBER_MASK may be ANDed with a tag to query its number. -#define CBS_ASN1_TAG_NUMBER_MASK ((1u << (5 + CBS_ASN1_TAG_SHIFT)) - 1) +#define CBS_ASN1_TAG_NUMBER_MASK 0x1fu // CBS_get_asn1 sets |*out| to the contents of DER-encoded, ASN.1 element (not // including tag and length bytes) and advances |cbs| over it. The ASN.1 // element must match |tag_value|. It returns one on success and zero // on error. +// +// Tag numbers greater than 30 are not supported (i.e. short form only). OPENSSL_EXPORT int CBS_get_asn1(CBS *cbs, CBS *out, unsigned tag_value); // CBS_get_asn1_element acts like |CBS_get_asn1| but |out| will include the @@ -211,12 +209,16 @@ OPENSSL_EXPORT int CBS_peek_asn1_tag(const CBS *cbs, unsigned tag_value); // (not including tag and length bytes), sets |*out_tag| to the tag number, and // advances |*cbs|. It returns one on success and zero on error. Either of |out| // and |out_tag| may be NULL to ignore the value. +// +// Tag numbers greater than 30 are not supported (i.e. short form only). OPENSSL_EXPORT int CBS_get_any_asn1(CBS *cbs, CBS *out, unsigned *out_tag); // CBS_get_any_asn1_element sets |*out| to contain the next ASN.1 element from // |*cbs| (including header bytes) and advances |*cbs|. It sets |*out_tag| to // the tag number and |*out_header_len| to the length of the ASN.1 header. Each // of |out|, |out_tag|, and |out_header_len| may be NULL to ignore the value. +// +// Tag numbers greater than 30 are not supported (i.e. short form only). OPENSSL_EXPORT int CBS_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag, size_t *out_header_len); @@ -279,6 +281,13 @@ OPENSSL_EXPORT int CBS_is_valid_asn1_bitstring(const CBS *cbs); // is indexed starting from zero. OPENSSL_EXPORT int CBS_asn1_bitstring_has_bit(const CBS *cbs, unsigned bit); +// CBS_asn1_oid_to_text interprets |cbs| as DER-encoded ASN.1 OBJECT IDENTIFIER +// contents (not including the element framing) and returns the ASCII +// representation (e.g., "1.2.840.113554.4.1.72585") in a newly-allocated +// string, or NULL on failure. The caller must release the result with +// |OPENSSL_free|. +OPENSSL_EXPORT char *CBS_asn1_oid_to_text(const CBS *cbs); + // CRYPTO ByteBuilder. // @@ -394,7 +403,9 @@ OPENSSL_EXPORT int CBB_add_u24_length_prefixed(CBB *cbb, CBB *out_contents); // CBB_add_asn1 sets |*out_contents| to a |CBB| into which the contents of an // ASN.1 object can be written. The |tag| argument will be used as the tag for -// the object. It returns one on success or zero on error. +// the object. Passing in |tag| number 31 will return in an error since only +// single octet identifiers are supported. It returns one on success or zero +// on error. OPENSSL_EXPORT int CBB_add_asn1(CBB *cbb, CBB *out_contents, unsigned tag); // CBB_add_bytes appends |len| bytes from |data| to |cbb|. It returns one on @@ -443,6 +454,17 @@ OPENSSL_EXPORT void CBB_discard_child(CBB *cbb); // error. OPENSSL_EXPORT int CBB_add_asn1_uint64(CBB *cbb, uint64_t value); +// CBB_add_asn1_oid_from_text decodes |len| bytes from |text| as an ASCII OID +// representation, e.g. "1.2.840.113554.4.1.72585", and writes the DER-encoded +// contents to |cbb|. It returns one on success and zero on malloc failure or if +// |text| was invalid. It does not include the OBJECT IDENTIFER framing, only +// the element's contents. +// +// This function considers OID strings with components which do not fit in a +// |uint64_t| to be invalid. +OPENSSL_EXPORT int CBB_add_asn1_oid_from_text(CBB *cbb, const char *text, + size_t len); + #if defined(__cplusplus) } // extern C diff --git a/src/include/openssl/err.h b/src/include/openssl/err.h index 9a65ffb6..920c3066 100644 --- a/src/include/openssl/err.h +++ b/src/include/openssl/err.h @@ -262,14 +262,6 @@ OPENSSL_EXPORT void ERR_print_errors_fp(FILE *file); // ERR_clear_error clears the error queue for the current thread. OPENSSL_EXPORT void ERR_clear_error(void); -// ERR_remove_thread_state clears the error queue for the current thread if -// |tid| is NULL. Otherwise it calls |assert(0)|, because it's no longer -// possible to delete the error queue for other threads. -// -// Error queues are thread-local data and are deleted automatically. You do not -// need to call this function. Use |ERR_clear_error|. -OPENSSL_EXPORT void ERR_remove_thread_state(const CRYPTO_THREADID *tid); - // ERR_set_mark "marks" the most recent error for use with |ERR_pop_to_mark|. // It returns one if an error was marked and zero if there are no errors. OPENSSL_EXPORT int ERR_set_mark(void); @@ -382,6 +374,14 @@ enum { // ERR_remove_state calls |ERR_clear_error|. OPENSSL_EXPORT void ERR_remove_state(unsigned long pid); +// ERR_remove_thread_state clears the error queue for the current thread if +// |tid| is NULL. Otherwise it calls |assert(0)|, because it's no longer +// possible to delete the error queue for other threads. +// +// Use |ERR_clear_error| instead. Note error queues are deleted automatically on +// thread exit. You do not need to call this function to release memory. +OPENSSL_EXPORT void ERR_remove_thread_state(const CRYPTO_THREADID *tid); + // ERR_func_error_string returns the string "OPENSSL_internal". OPENSSL_EXPORT const char *ERR_func_error_string(uint32_t packed_error); diff --git a/src/include/openssl/obj.h b/src/include/openssl/obj.h index 2bdc3b7a..374658ea 100644 --- a/src/include/openssl/obj.h +++ b/src/include/openssl/obj.h @@ -228,5 +228,6 @@ OPENSSL_EXPORT void OBJ_NAME_do_all(int type, void (*callback)(const OBJ_NAME *, #endif #define OBJ_R_UNKNOWN_NID 100 +#define OBJ_R_INVALID_OID_STRING 101 #endif // OPENSSL_HEADER_OBJ_H diff --git a/src/include/openssl/ssl.h b/src/include/openssl/ssl.h index 53a8eb51..cdf68a12 100644 --- a/src/include/openssl/ssl.h +++ b/src/include/openssl/ssl.h @@ -593,7 +593,7 @@ OPENSSL_EXPORT int DTLSv1_handle_timeout(SSL *ssl); #define TLS1_3_DRAFT_VERSION 0x7f12 #define TLS1_3_DRAFT21_VERSION 0x7f15 -#define TLS1_3_DRAFT22_VERSION 0x7e04 +#define TLS1_3_DRAFT22_VERSION 0x7f16 #define TLS1_3_EXPERIMENT_VERSION 0x7e01 #define TLS1_3_EXPERIMENT2_VERSION 0x7e02 #define TLS1_3_EXPERIMENT3_VERSION 0x7e03 diff --git a/src/ssl/handshake_client.cc b/src/ssl/handshake_client.cc index 583acebb..53adba61 100644 --- a/src/ssl/handshake_client.cc +++ b/src/ssl/handshake_client.cc @@ -295,11 +295,6 @@ int ssl_write_client_hello(SSL_HANDSHAKE *hs) { return 0; } - // Renegotiations do not participate in session resumption. - int has_session_id = ssl->session != NULL && - !ssl->s3->initial_handshake_complete && - ssl->session->session_id_length > 0; - CBB child; if (!CBB_add_u16(&body, hs->client_version) || !CBB_add_bytes(&body, ssl->s3->client_random, SSL3_RANDOM_SIZE) || @@ -307,19 +302,10 @@ int ssl_write_client_hello(SSL_HANDSHAKE *hs) { return 0; } - if (has_session_id) { - if (!CBB_add_bytes(&child, ssl->session->session_id, - ssl->session->session_id_length)) { - return 0; - } - } else { - // In TLS 1.3 experimental encodings, send a fake placeholder session ID - // when we do not otherwise have one to send. - if (hs->max_version >= TLS1_3_VERSION && - ssl_is_resumption_variant(ssl->tls13_variant) && - !CBB_add_bytes(&child, hs->session_id, hs->session_id_len)) { - return 0; - } + // Do not send a session ID on renegotiation. + if (!ssl->s3->initial_handshake_complete && + !CBB_add_bytes(&child, hs->session_id, hs->session_id_len)) { + return 0; } if (SSL_is_dtls(ssl)) { @@ -472,7 +458,13 @@ static enum ssl_hs_wait_t do_start_connect(SSL_HANDSHAKE *hs) { // Initialize a random session ID for the experimental TLS 1.3 variant // requiring a session id. - if (ssl_is_resumption_variant(ssl->tls13_variant)) { + if (ssl->session != nullptr && + !ssl->s3->initial_handshake_complete && + ssl->session->session_id_length > 0) { + hs->session_id_len = ssl->session->session_id_length; + OPENSSL_memcpy(hs->session_id, ssl->session->session_id, + hs->session_id_len); + } else if (ssl_is_resumption_variant(ssl->tls13_variant)) { hs->session_id_len = sizeof(hs->session_id); if (!RAND_bytes(hs->session_id, hs->session_id_len)) { return ssl_hs_error; diff --git a/src/ssl/test/runner/common.go b/src/ssl/test/runner/common.go index 02164017..53433463 100644 --- a/src/ssl/test/runner/common.go +++ b/src/ssl/test/runner/common.go @@ -38,7 +38,7 @@ const ( tls13ExperimentVersion = 0x7e01 tls13Experiment2Version = 0x7e02 tls13Experiment3Version = 0x7e03 - tls13Draft22Version = 0x7e04 + tls13Draft22Version = 0x7f16 ) const ( diff --git a/src/ssl/test/runner/conn.go b/src/ssl/test/runner/conn.go index 21f491a9..ec320aeb 100644 --- a/src/ssl/test/runner/conn.go +++ b/src/ssl/test/runner/conn.go @@ -1383,7 +1383,7 @@ func (c *Conn) readHandshake() (interface{}, error) { } if !m.unmarshal(data) { - return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) + return nil, c.in.setErrorLocked(c.sendAlert(alertDecodeError)) } return m, nil } diff --git a/src/ssl/test/runner/handshake_messages.go b/src/ssl/test/runner/handshake_messages.go index 93da1217..93d02e1b 100644 --- a/src/ssl/test/runner/handshake_messages.go +++ b/src/ssl/test/runner/handshake_messages.go @@ -125,6 +125,121 @@ func (bb *byteBuilder) discardChild() { bb.child = nil } +type byteReader []byte + +func (br *byteReader) readInternal(out *byteReader, n int) bool { + if len(*br) < n { + return false + } + *out = (*br)[:n] + *br = (*br)[n:] + return true +} + +func (br *byteReader) readBytes(out *[]byte, n int) bool { + var child byteReader + if !br.readInternal(&child, n) { + return false + } + *out = []byte(child) + return true +} + +func (br *byteReader) readUint(out *uint64, n int) bool { + var b []byte + if !br.readBytes(&b, n) { + return false + } + *out = 0 + for _, v := range b { + *out <<= 8 + *out |= uint64(v) + } + return true +} + +func (br *byteReader) readU8(out *uint8) bool { + var b []byte + if !br.readBytes(&b, 1) { + return false + } + *out = b[0] + return true +} + +func (br *byteReader) readU16(out *uint16) bool { + var v uint64 + if !br.readUint(&v, 2) { + return false + } + *out = uint16(v) + return true +} + +func (br *byteReader) readU24(out *uint32) bool { + var v uint64 + if !br.readUint(&v, 3) { + return false + } + *out = uint32(v) + return true +} + +func (br *byteReader) readU32(out *uint32) bool { + var v uint64 + if !br.readUint(&v, 4) { + return false + } + *out = uint32(v) + return true +} + +func (br *byteReader) readU64(out *uint64) bool { + return br.readUint(out, 8) +} + +func (br *byteReader) readLengthPrefixed(out *byteReader, n int) bool { + var length uint64 + return br.readUint(&length, n) && + uint64(len(*br)) >= length && + br.readInternal(out, int(length)) +} + +func (br *byteReader) readLengthPrefixedBytes(out *[]byte, n int) bool { + var length uint64 + return br.readUint(&length, n) && + uint64(len(*br)) >= length && + br.readBytes(out, int(length)) +} + +func (br *byteReader) readU8LengthPrefixed(out *byteReader) bool { + return br.readLengthPrefixed(out, 1) +} +func (br *byteReader) readU8LengthPrefixedBytes(out *[]byte) bool { + return br.readLengthPrefixedBytes(out, 1) +} + +func (br *byteReader) readU16LengthPrefixed(out *byteReader) bool { + return br.readLengthPrefixed(out, 2) +} +func (br *byteReader) readU16LengthPrefixedBytes(out *[]byte) bool { + return br.readLengthPrefixedBytes(out, 2) +} + +func (br *byteReader) readU24LengthPrefixed(out *byteReader) bool { + return br.readLengthPrefixed(out, 3) +} +func (br *byteReader) readU24LengthPrefixedBytes(out *[]byte) bool { + return br.readLengthPrefixedBytes(out, 3) +} + +func (br *byteReader) readU32LengthPrefixed(out *byteReader) bool { + return br.readLengthPrefixed(out, 4) +} +func (br *byteReader) readU32LengthPrefixedBytes(out *[]byte) bool { + return br.readLengthPrefixedBytes(out, 4) +} + type keyShareEntry struct { group CurveID keyExchange []byte @@ -422,11 +537,7 @@ func (m *clientHelloMsg) marshal() []byte { srtpProtectionProfiles := useSrtpExt.addU16LengthPrefixed() for _, p := range m.srtpProtectionProfiles { - // An SRTPProtectionProfile is defined as uint8[2], - // not uint16. For some reason, we're storing it - // as a uint16. - srtpProtectionProfiles.addU8(byte(p >> 8)) - srtpProtectionProfiles.addU8(byte(p)) + srtpProtectionProfiles.addU16(p) } srtpMki := useSrtpExt.addU8LengthPrefixed() srtpMki.addBytes([]byte(m.srtpMasterKeyIdentifier)) @@ -482,58 +593,54 @@ func (m *clientHelloMsg) marshal() []byte { return m.raw } -func (m *clientHelloMsg) unmarshal(data []byte) bool { - if len(data) < 42 { +func parseSignatureAlgorithms(reader *byteReader, out *[]signatureAlgorithm) bool { + var sigAlgs byteReader + if !reader.readU16LengthPrefixed(&sigAlgs) { return false } + *out = make([]signatureAlgorithm, 0, len(sigAlgs)/2) + for len(sigAlgs) > 0 { + var v uint16 + if !sigAlgs.readU16(&v) { + return false + } + *out = append(*out, signatureAlgorithm(v)) + } + return true +} + +func (m *clientHelloMsg) unmarshal(data []byte) bool { m.raw = data - m.vers = uint16(data[4])<<8 | uint16(data[5]) - m.random = data[6:38] - sessionIdLen := int(data[38]) - if sessionIdLen > 32 || len(data) < 39+sessionIdLen { + reader := byteReader(data[4:]) + if !reader.readU16(&m.vers) || + !reader.readBytes(&m.random, 32) || + !reader.readU8LengthPrefixedBytes(&m.sessionId) || + len(m.sessionId) > 32 { return false } - m.sessionId = data[39 : 39+sessionIdLen] - data = data[39+sessionIdLen:] if m.isDTLS { - if len(data) < 1 { + if !reader.readU8LengthPrefixedBytes(&m.cookie) || + len(m.cookie) > 32 { return false } - cookieLen := int(data[0]) - if cookieLen > 32 || len(data) < 1+cookieLen { - return false - } - m.cookie = data[1 : 1+cookieLen] - data = data[1+cookieLen:] - } - if len(data) < 2 { - return false } - // cipherSuiteLen is the number of bytes of cipher suite numbers. Since - // they are uint16s, the number must be even. - cipherSuiteLen := int(data[0])<<8 | int(data[1]) - if cipherSuiteLen%2 == 1 || len(data) < 2+cipherSuiteLen { + var cipherSuites byteReader + if !reader.readU16LengthPrefixed(&cipherSuites) || + !reader.readU8LengthPrefixedBytes(&m.compressionMethods) { return false } - numCipherSuites := cipherSuiteLen / 2 - m.cipherSuites = make([]uint16, numCipherSuites) - for i := 0; i < numCipherSuites; i++ { - m.cipherSuites[i] = uint16(data[2+2*i])<<8 | uint16(data[3+2*i]) - if m.cipherSuites[i] == scsvRenegotiation { + + m.cipherSuites = make([]uint16, 0, len(cipherSuites)/2) + for len(cipherSuites) > 0 { + var v uint16 + if !cipherSuites.readU16(&v) { + return false + } + m.cipherSuites = append(m.cipherSuites, v) + if v == scsvRenegotiation { m.secureRenegotiation = []byte{} } } - data = data[2+cipherSuiteLen:] - if len(data) < 1 { - return false - } - compressionMethodsLen := int(data[0]) - if len(data) < 1+compressionMethodsLen { - return false - } - m.compressionMethods = data[1 : 1+compressionMethodsLen] - - data = data[1+compressionMethodsLen:] m.nextProtoNeg = false m.serverName = "" @@ -549,167 +656,108 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool { m.extendedMasterSecret = false m.customExtension = "" - if len(data) == 0 { + if len(reader) == 0 { // ClientHello is optionally followed by extension data return true } - if len(data) < 2 { - return false - } - extensionsLength := int(data[0])<<8 | int(data[1]) - data = data[2:] - if extensionsLength != len(data) { + var extensions byteReader + if !reader.readU16LengthPrefixed(&extensions) || len(reader) != 0 { return false } - - for len(data) != 0 { - if len(data) < 4 { - return false - } - extension := uint16(data[0])<<8 | uint16(data[1]) - length := int(data[2])<<8 | int(data[3]) - data = data[4:] - if len(data) < length { + for len(extensions) > 0 { + var extension uint16 + var body byteReader + if !extensions.readU16(&extension) || + !extensions.readU16LengthPrefixed(&body) { return false } - switch extension { case extensionServerName: - if length < 2 { + var names byteReader + if !body.readU16LengthPrefixed(&names) || len(body) != 0 { return false } - numNames := int(data[0])<<8 | int(data[1]) - d := data[2:] - for i := 0; i < numNames; i++ { - if len(d) < 3 { - return false - } - nameType := d[0] - nameLen := int(d[1])<<8 | int(d[2]) - d = d[3:] - if len(d) < nameLen { + for len(names) > 0 { + var nameType byte + var name []byte + if !names.readU8(&nameType) || + !names.readU16LengthPrefixedBytes(&name) { return false } if nameType == 0 { - m.serverName = string(d[0:nameLen]) - break + m.serverName = string(name) } - d = d[nameLen:] } case extensionNextProtoNeg: - if length > 0 { + if len(body) != 0 { return false } m.nextProtoNeg = true case extensionStatusRequest: - m.ocspStapling = length > 0 && data[0] == statusTypeOCSP + m.ocspStapling = len(body) > 0 && body[0] == statusTypeOCSP case extensionSupportedCurves: // http://tools.ietf.org/html/rfc4492#section-5.5.1 - if length < 2 { - return false - } - l := int(data[0])<<8 | int(data[1]) - if l%2 == 1 || length != l+2 { + var curves byteReader + if !body.readU16LengthPrefixed(&curves) || len(body) != 0 { return false } - numCurves := l / 2 - m.supportedCurves = make([]CurveID, numCurves) - d := data[2:] - for i := 0; i < numCurves; i++ { - m.supportedCurves[i] = CurveID(d[0])<<8 | CurveID(d[1]) - d = d[2:] + m.supportedCurves = make([]CurveID, 0, len(curves)/2) + for len(curves) > 0 { + var v uint16 + if !curves.readU16(&v) { + return false + } + m.supportedCurves = append(m.supportedCurves, CurveID(v)) } case extensionSupportedPoints: // http://tools.ietf.org/html/rfc4492#section-5.5.2 - if length < 1 { + if !body.readU8LengthPrefixedBytes(&m.supportedPoints) || len(body) != 0 { return false } - l := int(data[0]) - if length != l+1 { - return false - } - m.supportedPoints = data[1 : 1+l] case extensionSessionTicket: // http://tools.ietf.org/html/rfc5077#section-3.2 m.ticketSupported = true - m.sessionTicket = data[:length] + m.sessionTicket = []byte(body) case extensionKeyShare: // draft-ietf-tls-tls13 section 6.3.2.3 - if length < 2 { + var keyShares byteReader + if !body.readU16LengthPrefixed(&keyShares) || len(body) != 0 { return false } - l := int(data[0])<<8 | int(data[1]) - if l != length-2 { - return false - } - d := data[2:length] m.hasKeyShares = true - for len(d) > 0 { - // The next KeyShareEntry contains a NamedGroup (2 bytes) and a - // key_exchange (2-byte length prefix with at least 1 byte of content). - if len(d) < 5 { - return false - } - entry := keyShareEntry{} - entry.group = CurveID(d[0])<<8 | CurveID(d[1]) - keyExchLen := int(d[2])<<8 | int(d[3]) - d = d[4:] - if len(d) < keyExchLen { + for len(keyShares) > 0 { + var entry keyShareEntry + var group uint16 + if !keyShares.readU16(&group) || + !keyShares.readU16LengthPrefixedBytes(&entry.keyExchange) { return false } - entry.keyExchange = d[:keyExchLen] - d = d[keyExchLen:] + entry.group = CurveID(group) m.keyShares = append(m.keyShares, entry) } case extensionPreSharedKey: // draft-ietf-tls-tls13-18 section 4.2.6 - if length < 2 { + var psks, binders byteReader + if !body.readU16LengthPrefixed(&psks) || + !body.readU16LengthPrefixed(&binders) || + len(body) != 0 { return false } - l := int(data[0])<<8 | int(data[1]) - d := data[2 : l+2] - // Parse PSK identities. - for len(d) > 0 { - if len(d) < 2 { + for len(psks) > 0 { + var psk pskIdentity + if !psks.readU16LengthPrefixedBytes(&psk.ticket) || + !psks.readU32(&psk.obfuscatedTicketAge) { return false } - pskLen := int(d[0])<<8 | int(d[1]) - d = d[2:] - - if len(d) < pskLen+4 { - return false - } - ticket := d[:pskLen] - obfuscatedTicketAge := uint32(d[pskLen])<<24 | uint32(d[pskLen+1])<<16 | uint32(d[pskLen+2])<<8 | uint32(d[pskLen+3]) - psk := pskIdentity{ - ticket: ticket, - obfuscatedTicketAge: obfuscatedTicketAge, - } m.pskIdentities = append(m.pskIdentities, psk) - d = d[pskLen+4:] } - d = data[l+2:] - if len(d) < 2 { - return false - } - l = int(d[0])<<8 | int(d[1]) - d = d[2:] - if l != len(d) { - return false - } - // Parse PSK binders. - for len(d) > 0 { - if len(d) < 1 { - return false - } - binderLen := int(d[0]) - d = d[1:] - if binderLen > len(d) { + for len(binders) > 0 { + var binder []byte + if !binders.readU8LengthPrefixedBytes(&binder) { return false } - m.pskBinders = append(m.pskBinders, d[:binderLen]) - d = d[binderLen:] + m.pskBinders = append(m.pskBinders, binder) } // There must be the same number of identities as binders. @@ -718,121 +766,88 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool { } case extensionPSKKeyExchangeModes: // draft-ietf-tls-tls13-18 section 4.2.7 - if length < 1 { - return false - } - l := int(data[0]) - if l != length-1 { + if !body.readU8LengthPrefixedBytes(&m.pskKEModes) || len(body) != 0 { return false } - m.pskKEModes = data[1:length] case extensionEarlyData: // draft-ietf-tls-tls13 section 6.3.2.5 - if length != 0 { + if len(body) != 0 { return false } m.hasEarlyData = true case extensionCookie: - if length < 2 { - return false - } - l := int(data[0])<<8 | int(data[1]) - if l != length-2 || l == 0 { + if !body.readU16LengthPrefixedBytes(&m.tls13Cookie) || len(body) != 0 { return false } - m.tls13Cookie = data[2 : 2+l] case extensionSignatureAlgorithms: // https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 - if length < 2 || length&1 != 0 { + if !parseSignatureAlgorithms(&body, &m.signatureAlgorithms) || len(body) != 0 { return false } - l := int(data[0])<<8 | int(data[1]) - if l != length-2 { - return false - } - n := l / 2 - d := data[2:] - m.signatureAlgorithms = make([]signatureAlgorithm, n) - for i := range m.signatureAlgorithms { - m.signatureAlgorithms[i] = signatureAlgorithm(d[0])<<8 | signatureAlgorithm(d[1]) - d = d[2:] - } case extensionSupportedVersions: - if length < 1+2 { - return false - } - l := int(data[0]) - if l != length-1 || l%2 == 1 || l < 2 { + var versions byteReader + if !body.readU8LengthPrefixed(&versions) || len(body) != 0 { return false } - n := l / 2 - d := data[1:] - m.supportedVersions = make([]uint16, n) - for i := range m.supportedVersions { - m.supportedVersions[i] = uint16(d[0])<<8 | uint16(d[1]) - d = d[2:] + m.supportedVersions = make([]uint16, 0, len(versions)/2) + for len(versions) > 0 { + var v uint16 + if !versions.readU16(&v) { + return false + } + m.supportedVersions = append(m.supportedVersions, v) } case extensionRenegotiationInfo: - if length < 1 || length != int(data[0])+1 { + if !body.readU8LengthPrefixedBytes(&m.secureRenegotiation) || len(body) != 0 { return false } - m.secureRenegotiation = data[1:length] case extensionALPN: - if length < 2 { + var protocols byteReader + if !body.readU16LengthPrefixed(&protocols) || len(body) != 0 { return false } - l := int(data[0])<<8 | int(data[1]) - if l != length-2 { - return false - } - d := data[2:length] - for len(d) != 0 { - stringLen := int(d[0]) - d = d[1:] - if stringLen == 0 || stringLen > len(d) { + for len(protocols) > 0 { + var protocol []byte + if !protocols.readU8LengthPrefixedBytes(&protocol) { return false } - m.alpnProtocols = append(m.alpnProtocols, string(d[:stringLen])) - d = d[stringLen:] + m.alpnProtocols = append(m.alpnProtocols, string(protocol)) } case extensionChannelID: - if length > 0 { + if len(body) != 0 { return false } m.channelIDSupported = true case extensionExtendedMasterSecret: - if length != 0 { + if len(body) != 0 { return false } m.extendedMasterSecret = true case extensionUseSRTP: - if length < 2 { + var profiles byteReader + var mki []byte + if !body.readU16LengthPrefixed(&profiles) || + !body.readU8LengthPrefixedBytes(&mki) || + len(body) != 0 { return false } - l := int(data[0])<<8 | int(data[1]) - if l > length-2 || l%2 != 0 { - return false - } - n := l / 2 - m.srtpProtectionProfiles = make([]uint16, n) - d := data[2:length] - for i := 0; i < n; i++ { - m.srtpProtectionProfiles[i] = uint16(d[0])<<8 | uint16(d[1]) - d = d[2:] - } - if len(d) < 1 || int(d[0]) != len(d)-1 { - return false + m.srtpProtectionProfiles = make([]uint16, 0, len(profiles)/2) + for len(profiles) > 0 { + var v uint16 + if !profiles.readU16(&v) { + return false + } + m.srtpProtectionProfiles = append(m.srtpProtectionProfiles, v) } - m.srtpMasterKeyIdentifier = string(d[1:]) + m.srtpMasterKeyIdentifier = string(mki) case extensionSignedCertificateTimestamp: - if length != 0 { + if len(body) != 0 { return false } m.sctListSupported = true case extensionCustom: - m.customExtension = string(data[:length]) + m.customExtension = string(body) } - data = data[length:] if isGREASEValue(extension) { m.hasGREASEExtension = true @@ -955,76 +970,56 @@ func (m *serverHelloMsg) marshal() []byte { } func (m *serverHelloMsg) unmarshal(data []byte) bool { - if len(data) < 42 { + m.raw = data + reader := byteReader(data[4:]) + if !reader.readU16(&m.vers) || + !reader.readBytes(&m.random, 32) { return false } - m.raw = data - m.vers = uint16(data[4])<<8 | uint16(data[5]) vers, ok := wireToVersion(m.vers, m.isDTLS) if !ok { return false } - m.random = data[6:38] - data = data[38:] if vers < VersionTLS13 || isResumptionExperiment(m.vers) { - sessionIdLen := int(data[0]) - if sessionIdLen > 32 || len(data) < 1+sessionIdLen { + if !reader.readU8LengthPrefixedBytes(&m.sessionId) { return false } - m.sessionId = data[1 : 1+sessionIdLen] - data = data[1+sessionIdLen:] } - if len(data) < 2 { + if !reader.readU16(&m.cipherSuite) { return false } - m.cipherSuite = uint16(data[0])<<8 | uint16(data[1]) - data = data[2:] if vers < VersionTLS13 || isResumptionExperiment(m.vers) { - if len(data) < 1 { + if !reader.readU8(&m.compressionMethod) { return false } - m.compressionMethod = data[0] - data = data[1:] } - if len(data) == 0 && m.vers < VersionTLS13 { + if len(reader) == 0 && m.vers < VersionTLS13 { // Extension data is optional before TLS 1.3. m.extensions = serverExtensions{} m.omitExtensions = true return true } - if len(data) < 2 { - return false - } - extensionsLength := int(data[0])<<8 | int(data[1]) - data = data[2:] - if len(data) != extensionsLength { + var extensions byteReader + if !reader.readU16LengthPrefixed(&extensions) || len(reader) != 0 { return false } // Parse out the version from supported_versions if available. if m.vers == VersionTLS12 { - vdata := data - for len(vdata) != 0 { - if len(vdata) < 4 { - return false - } - extension := uint16(vdata[0])<<8 | uint16(vdata[1]) - length := int(vdata[2])<<8 | int(vdata[3]) - vdata = vdata[4:] - - if len(vdata) < length { + extensionsCopy := extensions + for len(extensionsCopy) > 0 { + var extension uint16 + var body byteReader + if !extensionsCopy.readU16(&extension) || + !extensionsCopy.readU16LengthPrefixed(&body) { return false } - d := vdata[:length] - vdata = vdata[length:] - if extension == extensionSupportedVersions { - if len(d) < 2 { + if !body.readU16(&m.vers) || len(body) != 0 { return false } - m.vers = uint16(d[0])<<8 | uint16(d[1]) vers, ok = wireToVersion(m.vers, m.isDTLS) if !ok { return false @@ -1034,38 +1029,27 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool { } if vers >= VersionTLS13 { - for len(data) != 0 { - if len(data) < 4 { + for len(extensions) > 0 { + var extension uint16 + var body byteReader + if !extensions.readU16(&extension) || + !extensions.readU16LengthPrefixed(&body) { return false } - extension := uint16(data[0])<<8 | uint16(data[1]) - length := int(data[2])<<8 | int(data[3]) - data = data[4:] - - if len(data) < length { - return false - } - d := data[:length] - data = data[length:] - switch extension { case extensionKeyShare: m.hasKeyShare = true - if len(d) < 4 { - return false - } - m.keyShare.group = CurveID(uint16(d[0])<<8 | uint16(d[1])) - keyExchLen := int(d[2])<<8 | int(d[3]) - if keyExchLen != len(d)-4 { + var group uint16 + if !body.readU16(&group) || + !body.readU16LengthPrefixedBytes(&m.keyShare.keyExchange) || + len(body) != 0 { return false } - m.keyShare.keyExchange = make([]byte, keyExchLen) - copy(m.keyShare.keyExchange, d[4:]) + m.keyShare.group = CurveID(group) case extensionPreSharedKey: - if len(d) != 2 { + if !body.readU16(&m.pskIdentity) || len(body) != 0 { return false } - m.pskIdentity = uint16(d[0])<<8 | uint16(d[1]) m.hasPSKIdentity = true case extensionSupportedVersions: if !isResumptionExperiment(m.vers) { @@ -1077,7 +1061,7 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool { return false } } - } else if !m.extensions.unmarshal(data, vers) { + } else if !m.extensions.unmarshal(extensions, vers) { return false } @@ -1109,23 +1093,12 @@ func (m *encryptedExtensionsMsg) marshal() []byte { func (m *encryptedExtensionsMsg) unmarshal(data []byte) bool { m.raw = data - if len(data) < 6 { - return false - } - if data[0] != typeEncryptedExtensions { - return false - } - msgLen := int(data[1])<<16 | int(data[2])<<8 | int(data[3]) - data = data[4:] - if len(data) != msgLen { - return false - } - extLen := int(data[0])<<8 | int(data[1]) - data = data[2:] - if extLen != len(data) { + reader := byteReader(data[4:]) + var extensions byteReader + if !reader.readU16LengthPrefixed(&extensions) || len(reader) != 0 { return false } - return m.extensions.unmarshal(data, VersionTLS13) + return m.extensions.unmarshal(extensions, VersionTLS13) } type serverExtensions struct { @@ -1211,8 +1184,7 @@ func (m *serverExtensions) marshal(extensions *byteBuilder) { extension := extensions.addU16LengthPrefixed() srtpProtectionProfiles := extension.addU16LengthPrefixed() - srtpProtectionProfiles.addU8(byte(m.srtpProtectionProfile >> 8)) - srtpProtectionProfiles.addU8(byte(m.srtpProtectionProfile)) + srtpProtectionProfiles.addU16(m.srtpProtectionProfile) srtpMki := extension.addU8LengthPrefixed() srtpMki.addBytes([]byte(m.srtpMasterKeyIdentifier)) } @@ -1276,96 +1248,77 @@ func (m *serverExtensions) marshal(extensions *byteBuilder) { } } -func (m *serverExtensions) unmarshal(data []byte, version uint16) bool { +func (m *serverExtensions) unmarshal(data byteReader, version uint16) bool { // Reset all fields. *m = serverExtensions{} - for len(data) != 0 { - if len(data) < 4 { - return false - } - extension := uint16(data[0])<<8 | uint16(data[1]) - length := int(data[2])<<8 | int(data[3]) - data = data[4:] - if len(data) < length { + for len(data) > 0 { + var extension uint16 + var body byteReader + if !data.readU16(&extension) || + !data.readU16LengthPrefixed(&body) { return false } - switch extension { case extensionNextProtoNeg: m.nextProtoNeg = true - d := data[:length] - for len(d) > 0 { - l := int(d[0]) - d = d[1:] - if l == 0 || l > len(d) { + for len(body) > 0 { + var protocol []byte + if !body.readU8LengthPrefixedBytes(&protocol) { return false } - m.nextProtos = append(m.nextProtos, string(d[:l])) - d = d[l:] + m.nextProtos = append(m.nextProtos, string(protocol)) } case extensionStatusRequest: - if length > 0 { + if len(body) != 0 { return false } m.ocspStapling = true case extensionSessionTicket: - if length > 0 { + if len(body) != 0 { return false } m.ticketSupported = true case extensionRenegotiationInfo: - if length < 1 || length != int(data[0])+1 { + if !body.readU8LengthPrefixedBytes(&m.secureRenegotiation) || len(body) != 0 { return false } - m.secureRenegotiation = data[1:length] case extensionALPN: - d := data[:length] - if len(d) < 3 { + var protocols, protocol byteReader + if !body.readU16LengthPrefixed(&protocols) || + len(body) != 0 || + !protocols.readU8LengthPrefixed(&protocol) || + len(protocols) != 0 { return false } - l := int(d[0])<<8 | int(d[1]) - if l != len(d)-2 { - return false - } - d = d[2:] - l = int(d[0]) - if l != len(d)-1 { - return false - } - d = d[1:] - m.alpnProtocol = string(d) - m.alpnProtocolEmpty = len(d) == 0 + m.alpnProtocol = string(protocol) + m.alpnProtocolEmpty = len(protocol) == 0 case extensionChannelID: - if length > 0 { + if len(body) != 0 { return false } m.channelIDRequested = true case extensionExtendedMasterSecret: - if length != 0 { + if len(body) != 0 { return false } m.extendedMasterSecret = true case extensionUseSRTP: - if length < 2+2+1 { + var profiles, mki byteReader + if !body.readU16LengthPrefixed(&profiles) || + !profiles.readU16(&m.srtpProtectionProfile) || + len(profiles) != 0 || + !body.readU8LengthPrefixed(&mki) || + len(body) != 0 { return false } - if data[0] != 0 || data[1] != 2 { - return false - } - m.srtpProtectionProfile = uint16(data[2])<<8 | uint16(data[3]) - d := data[4:length] - l := int(d[0]) - if l != len(d)-1 { - return false - } - m.srtpMasterKeyIdentifier = string(d[1:]) + m.srtpMasterKeyIdentifier = string(mki) case extensionSignedCertificateTimestamp: - m.sctList = data[:length] + m.sctList = []byte(body) case extensionCustom: - m.customExtension = string(data[:length]) + m.customExtension = string(body) case extensionServerName: - if length != 0 { + if len(body) != 0 { return false } m.serverNameAck = true @@ -1375,21 +1328,16 @@ func (m *serverExtensions) unmarshal(data []byte, version uint16) bool { return false } // http://tools.ietf.org/html/rfc4492#section-5.5.2 - if length < 1 { - return false - } - l := int(data[0]) - if length != l+1 { + if !body.readU8LengthPrefixedBytes(&m.supportedPoints) || len(body) != 0 { return false } - m.supportedPoints = data[1 : 1+l] case extensionSupportedCurves: // The server can only send supported_curves in TLS 1.3. if version < VersionTLS13 { return false } case extensionEarlyData: - if version < VersionTLS13 || length != 0 { + if version < VersionTLS13 || len(body) != 0 { return false } m.hasEarlyData = true @@ -1397,7 +1345,6 @@ func (m *serverExtensions) unmarshal(data []byte, version uint16) bool { // Unknown extensions are illegal from the server. return false } - data = data[length:] } return true @@ -1409,6 +1356,7 @@ type helloRetryRequestMsg struct { isServerHello bool sessionId []byte cipherSuite uint16 + compressionMethod uint8 hasSelectedGroup bool selectedGroup CurveID cookie []byte @@ -1435,7 +1383,7 @@ func (m *helloRetryRequestMsg) marshal() []byte { sessionId := retryRequest.addU8LengthPrefixed() sessionId.addBytes(m.sessionId) retryRequest.addU16(m.cipherSuite) - retryRequest.addU8(0) + retryRequest.addU8(m.compressionMethod) } else { retryRequest.addU16(m.vers) if isDraft21(m.vers) { @@ -1478,73 +1426,56 @@ func (m *helloRetryRequestMsg) marshal() []byte { func (m *helloRetryRequestMsg) unmarshal(data []byte) bool { m.raw = data - if len(data) < 8 { + reader := byteReader(data[4:]) + if !reader.readU16(&m.vers) { return false } - m.vers = uint16(data[4])<<8 | uint16(data[5]) - data = data[6:] if m.isServerHello { - if len(data) < 33 { + var random []byte + var compressionMethod byte + if !reader.readBytes(&random, 32) || + !reader.readU8LengthPrefixedBytes(&m.sessionId) || + !reader.readU16(&m.cipherSuite) || + !reader.readU8(&compressionMethod) || + compressionMethod != 0 { return false } - data = data[32:] // Random - sessionIdLen := int(data[0]) - if sessionIdLen > 32 || len(data) < 1+sessionIdLen+3 { - return false - } - m.sessionId = data[1 : 1+sessionIdLen] - data = data[1+sessionIdLen:] - m.cipherSuite = uint16(data[0])<<8 | uint16(data[1]) - data = data[2:] - data = data[1:] // Compression Method - } else { - if isDraft21(m.vers) { - m.cipherSuite = uint16(data[0])<<8 | uint16(data[1]) - data = data[2:] - } + } else if isDraft21(m.vers) && !reader.readU16(&m.cipherSuite) { + return false } - extLen := int(data[0])<<8 | int(data[1]) - data = data[2:] - if len(data) != extLen || len(data) == 0 { + var extensions byteReader + if !reader.readU16LengthPrefixed(&extensions) || len(reader) != 0 { return false } - for len(data) > 0 { - if len(data) < 4 { - return false - } - extension := uint16(data[0])<<8 | uint16(data[1]) - length := int(data[2])<<8 | int(data[3]) - data = data[4:] - if len(data) < length { + for len(extensions) > 0 { + var extension uint16 + var body byteReader + if !extensions.readU16(&extension) || + !extensions.readU16LengthPrefixed(&body) { return false } - switch extension { case extensionSupportedVersions: - if length != 2 || !m.isServerHello { + if !m.isServerHello || + !body.readU16(&m.vers) || + len(body) != 0 { return false } - m.vers = uint16(data[0])<<8 | uint16(data[1]) case extensionKeyShare: - if length != 2 { + var v uint16 + if !body.readU16(&v) || len(body) != 0 { return false } m.hasSelectedGroup = true - m.selectedGroup = CurveID(data[0])<<8 | CurveID(data[1]) + m.selectedGroup = CurveID(v) case extensionCookie: - if length < 2 { - return false - } - cookieLen := int(data[0])<<8 | int(data[1]) - if 2+cookieLen != length { + if !body.readU16LengthPrefixedBytes(&m.cookie) || len(body) != 0 { return false } - m.cookie = data[2 : 2+cookieLen] default: // Unknown extensions are illegal from the server. return false } - data = data[length:] } return true } @@ -1613,85 +1544,46 @@ func (m *certificateMsg) marshal() (x []byte) { } func (m *certificateMsg) unmarshal(data []byte) bool { - if len(data) < 4 { - return false - } - m.raw = data - data = data[4:] - - if m.hasRequestContext { - if len(data) == 0 { - return false - } - contextLen := int(data[0]) - if len(data) < 1+contextLen { - return false - } - m.requestContext = make([]byte, contextLen) - copy(m.requestContext, data[1:]) - data = data[1+contextLen:] - } + reader := byteReader(data[4:]) - if len(data) < 3 { + if m.hasRequestContext && !reader.readU8LengthPrefixedBytes(&m.requestContext) { return false } - certsLen := int(data[0])<<16 | int(data[1])<<8 | int(data[2]) - data = data[3:] - if len(data) != certsLen { + + var certs byteReader + if !reader.readU24LengthPrefixed(&certs) || len(reader) != 0 { return false } - m.certificates = nil - for len(data) != 0 { - if len(data) < 3 { - return false - } - certLen := int(data[0])<<16 | int(data[1])<<8 | int(data[2]) - if len(data) < 3+certLen { + for len(certs) > 0 { + var cert certificateEntry + if !certs.readU24LengthPrefixedBytes(&cert.data) { return false } - cert := certificateEntry{ - data: data[3 : 3+certLen], - } - data = data[3+certLen:] if m.hasRequestContext { - if len(data) < 2 { + var extensions byteReader + if !certs.readU16LengthPrefixed(&extensions) { return false } - extensionsLen := int(data[0])<<8 | int(data[1]) - if len(data) < 2+extensionsLen { - return false - } - extensions := data[2 : 2+extensionsLen] - data = data[2+extensionsLen:] - for len(extensions) != 0 { - if len(extensions) < 4 { - return false - } - extension := uint16(extensions[0])<<8 | uint16(extensions[1]) - length := int(extensions[2])<<8 | int(extensions[3]) - if len(extensions) < 4+length { + for len(extensions) > 0 { + var extension uint16 + var body byteReader + if !extensions.readU16(&extension) || + !extensions.readU16LengthPrefixed(&body) { return false } - contents := extensions[4 : 4+length] - extensions = extensions[4+length:] - switch extension { case extensionStatusRequest: - if length < 4 { - return false - } - if contents[0] != statusTypeOCSP { - return false - } - respLen := int(contents[1])<<16 | int(contents[2])<<8 | int(contents[3]) - if respLen+4 != len(contents) || respLen == 0 { + var statusType byte + if !body.readU8(&statusType) || + statusType != statusTypeOCSP || + !body.readU24LengthPrefixedBytes(&cert.ocspResponse) || + len(body) != 0 { return false } - cert.ocspResponse = contents[4:] case extensionSignedCertificateTimestamp: - cert.sctList = contents + cert.sctList = []byte(body) default: return false } @@ -1712,16 +1604,11 @@ func (m *serverKeyExchangeMsg) marshal() []byte { if m.raw != nil { return m.raw } - length := len(m.key) - x := make([]byte, length+4) - x[0] = typeServerKeyExchange - x[1] = uint8(length >> 16) - x[2] = uint8(length >> 8) - x[3] = uint8(length) - copy(x[4:], m.key) - - m.raw = x - return x + msg := newByteBuilder() + msg.addU8(typeServerKeyExchange) + msg.addU24LengthPrefixed().addBytes(m.key) + m.raw = msg.finish() + return m.raw } func (m *serverKeyExchangeMsg) unmarshal(data []byte) bool { @@ -1746,19 +1633,12 @@ func (m *certificateStatusMsg) marshal() []byte { var x []byte if m.statusType == statusTypeOCSP { - x = make([]byte, 4+4+len(m.response)) - x[0] = typeCertificateStatus - l := len(m.response) + 4 - x[1] = byte(l >> 16) - x[2] = byte(l >> 8) - x[3] = byte(l) - x[4] = statusTypeOCSP - - l -= 4 - x[5] = byte(l >> 16) - x[6] = byte(l >> 8) - x[7] = byte(l) - copy(x[8:], m.response) + msg := newByteBuilder() + msg.addU8(typeCertificateStatus) + body := msg.addU24LengthPrefixed() + body.addU8(statusTypeOCSP) + body.addU24LengthPrefixed().addBytes(m.response) + x = msg.finish() } else { x = []byte{typeCertificateStatus, 0, 0, 1, m.statusType} } @@ -1769,22 +1649,13 @@ func (m *certificateStatusMsg) marshal() []byte { func (m *certificateStatusMsg) unmarshal(data []byte) bool { m.raw = data - if len(data) < 5 { + reader := byteReader(data[4:]) + if !reader.readU8(&m.statusType) || + m.statusType != statusTypeOCSP || + !reader.readU24LengthPrefixedBytes(&m.response) || + len(reader) != 0 { return false } - m.statusType = data[4] - - m.response = nil - if m.statusType == statusTypeOCSP { - if len(data) < 8 { - return false - } - respLen := uint32(data[5])<<16 | uint32(data[6])<<8 | uint32(data[7]) - if uint32(len(data)) != 4+4+respLen { - return false - } - m.response = data[8:] - } return true } @@ -1809,16 +1680,11 @@ func (m *clientKeyExchangeMsg) marshal() []byte { if m.raw != nil { return m.raw } - length := len(m.ciphertext) - x := make([]byte, length+4) - x[0] = typeClientKeyExchange - x[1] = uint8(length >> 16) - x[2] = uint8(length >> 8) - x[3] = uint8(length) - copy(x[4:], m.ciphertext) - - m.raw = x - return x + msg := newByteBuilder() + msg.addU8(typeClientKeyExchange) + msg.addU24LengthPrefixed().addBytes(m.ciphertext) + m.raw = msg.finish() + return m.raw } func (m *clientKeyExchangeMsg) unmarshal(data []byte) bool { @@ -1839,17 +1705,16 @@ type finishedMsg struct { verifyData []byte } -func (m *finishedMsg) marshal() (x []byte) { +func (m *finishedMsg) marshal() []byte { if m.raw != nil { return m.raw } - x = make([]byte, 4+len(m.verifyData)) - x[0] = typeFinished - x[3] = byte(len(m.verifyData)) - copy(x[4:], m.verifyData) - m.raw = x - return + msg := newByteBuilder() + msg.addU8(typeFinished) + msg.addU24LengthPrefixed().addBytes(m.verifyData) + m.raw = msg.finish() + return m.raw } func (m *finishedMsg) unmarshal(data []byte) bool { @@ -1870,52 +1735,38 @@ func (m *nextProtoMsg) marshal() []byte { if m.raw != nil { return m.raw } - l := len(m.proto) - if l > 255 { - l = 255 - } - padding := 32 - (l+2)%32 - length := l + padding + 2 - x := make([]byte, length+4) - x[0] = typeNextProtocol - x[1] = uint8(length >> 16) - x[2] = uint8(length >> 8) - x[3] = uint8(length) + padding := 32 - (len(m.proto)+2)%32 - y := x[4:] - y[0] = byte(l) - copy(y[1:], []byte(m.proto[0:l])) - y = y[1+l:] - y[0] = byte(padding) - - m.raw = x - - return x + msg := newByteBuilder() + msg.addU8(typeNextProtocol) + body := msg.addU24LengthPrefixed() + body.addU8LengthPrefixed().addBytes([]byte(m.proto)) + body.addU8LengthPrefixed().addBytes(make([]byte, padding)) + m.raw = msg.finish() + return m.raw } func (m *nextProtoMsg) unmarshal(data []byte) bool { m.raw = data - - if len(data) < 5 { - return false - } - data = data[4:] - protoLen := int(data[0]) - data = data[1:] - if len(data) < protoLen { + reader := byteReader(data[4:]) + var proto, padding []byte + if !reader.readU8LengthPrefixedBytes(&proto) || + !reader.readU8LengthPrefixedBytes(&padding) || + len(reader) != 0 { return false } - m.proto = string(data[0:protoLen]) - data = data[protoLen:] + m.proto = string(proto) - if len(data) < 1 { + // Padding is not meant to be checked normally, but as this is a testing + // implementation, we check the padding is as expected. + if len(padding) != 32-(len(m.proto)+2)%32 { return false } - paddingLen := int(data[0]) - data = data[1:] - if len(data) != paddingLen { - return false + for _, v := range padding { + if v != 0 { + return false + } } return true @@ -2014,167 +1865,72 @@ func (m *certificateRequestMsg) marshal() []byte { return m.raw } -func parseSignatureAlgorithms(data []byte) ([]signatureAlgorithm, []byte, bool) { - if len(data) < 2 { - return nil, nil, false - } - sigAlgsLen := int(data[0])<<8 | int(data[1]) - data = data[2:] - if sigAlgsLen&1 != 0 { - return nil, nil, false - } - if len(data) < int(sigAlgsLen) { - return nil, nil, false - } - numSigAlgs := sigAlgsLen / 2 - signatureAlgorithms := make([]signatureAlgorithm, numSigAlgs) - for i := range signatureAlgorithms { - signatureAlgorithms[i] = signatureAlgorithm(data[0])<<8 | signatureAlgorithm(data[1]) - data = data[2:] - } - - return signatureAlgorithms, data, true -} - -func parseCAs(data []byte) ([][]byte, []byte, bool) { - if len(data) < 2 { - return nil, nil, false - } - casLength := uint16(data[0])<<8 | uint16(data[1]) - data = data[2:] - if len(data) < int(casLength) { - return nil, nil, false +func parseCAs(reader *byteReader, out *[][]byte) bool { + var cas byteReader + if !reader.readU16LengthPrefixed(&cas) { + return false } - - cas := data[:casLength] - data = data[casLength:] - - var certificateAuthorities [][]byte for len(cas) > 0 { - if len(cas) < 2 { - return nil, nil, false - } - caLen := uint16(cas[0])<<8 | uint16(cas[1]) - cas = cas[2:] - - if len(cas) < int(caLen) { - return nil, nil, false + var ca []byte + if !cas.readU16LengthPrefixedBytes(&ca) { + return false } - - certificateAuthorities = append(certificateAuthorities, cas[:caLen]) - cas = cas[caLen:] + *out = append(*out, ca) } - return certificateAuthorities, data, true + return true } func (m *certificateRequestMsg) unmarshal(data []byte) bool { m.raw = data + reader := byteReader(data[4:]) - if len(data) < 5 { - return false - } - data = data[4:] - - if m.hasRequestContext { - contextLen := int(data[0]) - if len(data) < 1+contextLen { + if isDraft21(m.vers) { + var extensions byteReader + if !reader.readU8LengthPrefixedBytes(&m.requestContext) || + !reader.readU16LengthPrefixed(&extensions) || + len(reader) != 0 { return false } - m.requestContext = make([]byte, contextLen) - copy(m.requestContext, data[1:]) - data = data[1+contextLen:] - if isDraft21(m.vers) { - if len(data) < 2 { + for len(extensions) > 0 { + var extension uint16 + var body byteReader + if !extensions.readU16(&extension) || + !extensions.readU16LengthPrefixed(&body) { return false } - extensionsLen := int(data[0])<<8 | int(data[1]) - if len(data) < 2+extensionsLen { - return false - } - extensions := data[2 : 2+extensionsLen] - data = data[2+extensionsLen:] - for len(extensions) != 0 { - if len(extensions) < 4 { - return false - } - extension := uint16(extensions[0])<<8 | uint16(extensions[1]) - length := int(extensions[2])<<8 | int(extensions[3]) - if len(extensions) < 4+length { + switch extension { + case extensionSignatureAlgorithms: + if !parseSignatureAlgorithms(&body, &m.signatureAlgorithms) || len(body) != 0 { return false } - contents := extensions[4 : 4+length] - extensions = extensions[4+length:] - switch extension { - case extensionSignatureAlgorithms: - sigAlgs, rest, ok := parseSignatureAlgorithms(contents) - if !ok || len(rest) != 0 { - return false - } - m.signatureAlgorithms = sigAlgs - case extensionCertificateAuthorities: - cas, rest, ok := parseCAs(contents) - if !ok || len(rest) != 0 { - return false - } - m.hasCAExtension = true - m.certificateAuthorities = cas - } - } - } else { - if m.hasSignatureAlgorithm { - sigAlgs, rest, ok := parseSignatureAlgorithms(data) - if !ok { + case extensionCertificateAuthorities: + if !parseCAs(&body, &m.certificateAuthorities) || len(body) != 0 { return false } - m.signatureAlgorithms = sigAlgs - data = rest + m.hasCAExtension = true } - - cas, rest, ok := parseCAs(data) - if !ok { - return false - } - m.certificateAuthorities = cas - data = rest - - // Ignore certificate extensions. - if len(data) < 2 { - return false - } - extsLength := int(data[0])<<8 | int(data[1]) - if len(data) < 2+extsLength { - return false - } - data = data[2+extsLength:] } + } else if m.hasRequestContext { + var extensions byteReader + if !reader.readU8LengthPrefixedBytes(&m.requestContext) || + !parseSignatureAlgorithms(&reader, &m.signatureAlgorithms) || + !parseCAs(&reader, &m.certificateAuthorities) || + !reader.readU16LengthPrefixed(&extensions) || + len(reader) != 0 { + return false + } + // Ignore certificate extensions. } else { - numCertTypes := int(data[0]) - if len(data) < 1+numCertTypes { + if !reader.readU8LengthPrefixedBytes(&m.certificateTypes) { return false } - m.certificateTypes = make([]byte, numCertTypes) - copy(m.certificateTypes, data[1:]) - data = data[1+numCertTypes:] - - if m.hasSignatureAlgorithm { - sigAlgs, rest, ok := parseSignatureAlgorithms(data) - if !ok { - return false - } - m.signatureAlgorithms = sigAlgs - data = rest + if m.hasSignatureAlgorithm && !parseSignatureAlgorithms(&reader, &m.signatureAlgorithms) { + return false } - - cas, rest, ok := parseCAs(data) - if !ok { + if !parseCAs(&reader, &m.certificateAuthorities) || + len(reader) != 0 { return false } - m.certificateAuthorities = cas - data = rest - } - - if len(data) > 0 { - return false } return true diff --git a/src/ssl/test/runner/handshake_server.go b/src/ssl/test/runner/handshake_server.go index 4286911c..595f8daa 100644 --- a/src/ssl/test/runner/handshake_server.go +++ b/src/ssl/test/runner/handshake_server.go @@ -368,6 +368,7 @@ func (hs *serverHandshakeState) doTLS13Handshake() error { isDTLS: c.isDTLS, vers: c.wireVersion, sessionId: hs.clientHello.sessionId, + compressionMethod: config.Bugs.SendCompressionMethod, versOverride: config.Bugs.SendServerHelloVersion, supportedVersOverride: config.Bugs.SendServerSupportedExtensionVersion, customExtension: config.Bugs.CustomUnencryptedExtension, @@ -534,6 +535,7 @@ ResendHelloRetryRequest: vers: c.wireVersion, sessionId: hs.clientHello.sessionId, cipherSuite: cipherSuite, + compressionMethod: config.Bugs.SendCompressionMethod, duplicateExtensions: config.Bugs.DuplicateHelloRetryRequestExtensions, } diff --git a/src/ssl/test/runner/runner.go b/src/ssl/test/runner/runner.go index 8700af2c..66c13fc9 100644 --- a/src/ssl/test/runner/runner.go +++ b/src/ssl/test/runner/runner.go @@ -2785,6 +2785,34 @@ read alert 1 0 expectedLocalError: "remote error: illegal parameter", }, { + testType: clientTest, + name: "TLS13Draft22-InvalidCompressionMethod", + config: Config{ + MaxVersion: VersionTLS13, + Bugs: ProtocolBugs{ + SendCompressionMethod: 1, + }, + }, + tls13Variant: TLS13Draft22, + shouldFail: true, + expectedError: ":DECODE_ERROR:", + }, + { + testType: clientTest, + name: "TLS13Draft22-HRR-InvalidCompressionMethod", + config: Config{ + MaxVersion: VersionTLS13, + CurvePreferences: []CurveID{CurveP384}, + Bugs: ProtocolBugs{ + SendCompressionMethod: 1, + }, + }, + tls13Variant: TLS13Draft22, + shouldFail: true, + expectedError: ":DECODE_ERROR:", + expectedLocalError: "remote error: error decoding message", + }, + { name: "GREASE-Client-TLS12", config: Config{ MaxVersion: VersionTLS12, @@ -7268,6 +7296,25 @@ func addRenegotiationTests() { }, }) testCases = append(testCases, testCase{ + name: "Renegotiate-Client-TLS13Draft22", + config: Config{ + MaxVersion: VersionTLS12, + Bugs: ProtocolBugs{ + FailIfResumeOnRenego: true, + }, + }, + tls13Variant: TLS13Draft22, + renegotiate: 1, + // Test renegotiation after both an initial and resumption + // handshake. + resumeSession: true, + flags: []string{ + "-renegotiate-freely", + "-expect-total-renegotiations", "1", + "-expect-secure-renegotiation", + }, + }) + testCases = append(testCases, testCase{ name: "Renegotiate-Client-EmptyExt", renegotiate: 1, config: Config{ @@ -11017,6 +11064,23 @@ func addTLS13HandshakeTests() { resumeSession: true, }) + // Test that the client correctly handles a TLS 1.3 ServerHello which echoes + // a TLS 1.2 session ID. + testCases = append(testCases, testCase{ + testType: clientTest, + name: "TLS12SessionID-" + name, + config: Config{ + MaxVersion: VersionTLS12, + SessionTicketsDisabled: true, + }, + resumeConfig: &Config{ + MaxVersion: VersionTLS13, + }, + tls13Variant: variant, + resumeSession: true, + expectResumeRejected: true, + }) + // Test that the server correctly echoes back session IDs of // various lengths. testCases = append(testCases, testCase{ diff --git a/src/ssl/tls13_client.cc b/src/ssl/tls13_client.cc index 688fa061..f471a4e9 100644 --- a/src/ssl/tls13_client.cc +++ b/src/ssl/tls13_client.cc @@ -75,11 +75,14 @@ static enum ssl_hs_wait_t do_read_hello_retry_request(SSL_HANDSHAKE *hs) { CBS body = msg.body, server_random, session_id; uint16_t server_version; + uint8_t compression_method; if (!CBS_get_u16(&body, &server_version) || !CBS_get_bytes(&body, &server_random, SSL3_RANDOM_SIZE) || !CBS_get_u8_length_prefixed(&body, &session_id) || + !CBS_mem_equal(&session_id, hs->session_id, hs->session_id_len) || !CBS_get_u16(&body, &cipher_suite) || - !CBS_skip(&body, 1) || + !CBS_get_u8(&body, &compression_method) || + compression_method != 0 || !CBS_get_u16_length_prefixed(&body, &extensions) || CBS_len(&extensions) == 0 || CBS_len(&body) != 0) { @@ -251,7 +254,8 @@ static enum ssl_hs_wait_t do_read_server_hello(SSL_HANDSHAKE *hs) { if (!CBS_get_u16(&body, &server_version) || !CBS_get_bytes(&body, &server_random, SSL3_RANDOM_SIZE) || (ssl_is_resumption_experiment(ssl->version) && - !CBS_get_u8_length_prefixed(&body, &session_id)) || + (!CBS_get_u8_length_prefixed(&body, &session_id) || + !CBS_mem_equal(&session_id, hs->session_id, hs->session_id_len))) || !CBS_get_u16(&body, &cipher_suite) || (ssl_is_resumption_experiment(ssl->version) && (!CBS_get_u8(&body, &compression_method) || compression_method != 0)) || diff --git a/src/tool/client.cc b/src/tool/client.cc index 57e1b6e6..fa279ae5 100644 --- a/src/tool/client.cc +++ b/src/tool/client.cc @@ -122,7 +122,8 @@ static const struct argument kArguments[] = { }, { "-early-data", kOptionalArgument, "Enable early data. The argument to " - "this flag is the early data to send.", + "this flag is the early data to send or if it starts with '@', the " + "file to read from for early data.", }, { "-tls13-variant", kOptionalArgument, @@ -299,8 +300,19 @@ static bool DoConnection(SSL_CTX *ctx, } if (args_map.count("-early-data") != 0 && SSL_in_early_data(ssl.get())) { - int ed_size = args_map["-early-data"].size(); - int ssl_ret = SSL_write(ssl.get(), args_map["-early-data"].data(), ed_size); + std::string early_data = args_map["-early-data"]; + if (early_data.size() > 0 && early_data[0] == '@') { + const char *filename = early_data.c_str() + 1; + std::vector<uint8_t> data; + ScopedFILE f(fopen(filename, "rb")); + if (f == nullptr || !ReadAll(&data, f.get())) { + fprintf(stderr, "Error reading %s.\n", filename); + return false; + } + early_data = std::string(data.begin(), data.end()); + } + int ed_size = early_data.size(); + int ssl_ret = SSL_write(ssl.get(), early_data.data(), ed_size); if (ssl_ret <= 0) { int ssl_err = SSL_get_error(ssl.get(), ssl_ret); fprintf(stderr, "Error while writing: %d\n", ssl_err); diff --git a/src/tool/generate_ed25519.cc b/src/tool/generate_ed25519.cc index 35b57b99..6499dbea 100644 --- a/src/tool/generate_ed25519.cc +++ b/src/tool/generate_ed25519.cc @@ -21,14 +21,6 @@ #include "internal.h" -struct FileCloser { - void operator()(FILE *file) { - fclose(file); - } -}; - -using ScopedFILE = std::unique_ptr<FILE, FileCloser>; - static const struct argument kArguments[] = { { "-out-public", kRequiredArgument, "The file to write the public key to", diff --git a/src/tool/internal.h b/src/tool/internal.h index a6c8ecab..b626270f 100644 --- a/src/tool/internal.h +++ b/src/tool/internal.h @@ -44,6 +44,14 @@ OPENSSL_MSVC_PRAGMA(warning(pop)) #define BORINGSSL_WRITE write #endif +struct FileCloser { + void operator()(FILE *file) { + fclose(file); + } +}; + +using ScopedFILE = std::unique_ptr<FILE, FileCloser>; + enum ArgumentType { kRequiredArgument, kOptionalArgument, diff --git a/src/tool/server.cc b/src/tool/server.cc index 0061cb34..99638852 100644 --- a/src/tool/server.cc +++ b/src/tool/server.cc @@ -71,6 +71,9 @@ static const struct argument kArguments[] = { "-tls13-variant", kBooleanArgument, "Enable TLS 1.3 variants", }, { + "-tls13-draft22-variant", kBooleanArgument, "Enable TLS 1.3 Draft 22.", + }, + { "-www", kBooleanArgument, "The server will print connection information in response to a " "HTTP GET request.", @@ -88,14 +91,6 @@ static const struct argument kArguments[] = { }, }; -struct FileCloser { - void operator()(FILE *file) { - fclose(file); - } -}; - -using ScopedFILE = std::unique_ptr<FILE, FileCloser>; - static bool LoadOCSPResponse(SSL_CTX *ctx, const char *filename) { ScopedFILE f(fopen(filename, "rb")); std::vector<uint8_t> data; @@ -315,8 +310,10 @@ bool Server(const std::vector<std::string> &args) { SSL_CTX_set_early_data_enabled(ctx.get(), 1); } - // Enabling any TLS 1.3 variant on the server enables all of them. - if (args_map.count("-tls13-variant") != 0) { + // Draft 22 variants need to be explicitly enabled. + if (args_map.count("-tls13-draft22-variant") != 0) { + SSL_CTX_set_tls13_variant(ctx.get(), tls13_draft22); + } else if (args_map.count("-tls13-variant") != 0) { SSL_CTX_set_tls13_variant(ctx.get(), tls13_experiment); } |