diff --git a/common/tls/ech_client.go b/common/tls/ech_client.go index c128ed69..9dc962f8 100644 --- a/common/tls/ech_client.go +++ b/common/tls/ech_client.go @@ -11,9 +11,9 @@ import ( "net/netip" "os" + cftls "github.com/sagernet/cloudflare-tls" "github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/option" - cftls "github.com/sagernet/sing-box/transport/cloudflaretls" "github.com/sagernet/sing-dns" E "github.com/sagernet/sing/common/exceptions" diff --git a/go.mod b/go.mod index 9a405014..41b709dd 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,6 @@ require ( berty.tech/go-libtor v1.0.385 github.com/Dreamacro/clash v1.11.8 github.com/caddyserver/certmagic v0.17.2 - github.com/cloudflare/circl v1.2.1-0.20220831060716-4cf0150356fc github.com/cretz/bine v0.2.0 github.com/database64128/tfo-go/v2 v2.0.2 github.com/dustin/go-humanize v1.0.0 @@ -22,9 +21,10 @@ require ( github.com/oschwald/maxminddb-golang v1.10.0 github.com/pires/go-proxyproto v0.6.2 github.com/refraction-networking/utls v1.1.5 - github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb + github.com/sagernet/cloudflare-tls v0.0.0-20221031050923-d70792f4c3a0 + github.com/sagernet/quic-go v0.0.0-20221031051350-29d8bb1c8127 github.com/sagernet/sing v0.0.0-20221008120626-60a9910eefe4 - github.com/sagernet/sing-dns v0.0.0-20221029093630-568471e6216d + github.com/sagernet/sing-dns v0.0.0-20221031055845-7de76401d403 github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6 github.com/sagernet/sing-tun v0.0.0-20221028015259-ea5c35f62f07 github.com/sagernet/sing-vmess v0.0.0-20220925083655-063bc85ea685 @@ -49,20 +49,17 @@ require ( require ( github.com/ajg/form v1.5.1 // indirect github.com/andybalholm/brotli v1.0.4 // indirect + github.com/cloudflare/circl v1.2.1-0.20221019164342-6ab4dfed8f3c // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect - github.com/golang/mock v1.6.0 // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/google/btree v1.0.1 // indirect github.com/inconshreveable/mousetrap v1.0.1 // indirect github.com/klauspost/compress v1.15.9 // indirect github.com/klauspost/cpuid/v2 v2.1.1 // indirect github.com/libdns/libdns v0.2.1 // indirect - github.com/marten-seemann/qpack v0.2.1 // indirect - github.com/marten-seemann/qtls-go1-18 v0.1.2 // indirect - github.com/marten-seemann/qtls-go1-19 v0.1.0 // indirect - github.com/nxadm/tail v1.4.8 // indirect - github.com/onsi/ginkgo v1.16.5 // indirect + github.com/marten-seemann/qpack v0.3.0 // indirect + github.com/marten-seemann/qtls-go1-18 v0.1.3 // indirect + github.com/marten-seemann/qtls-go1-19 v0.1.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/sagernet/abx-go v0.0.0-20220819185957-dba1257d738e // indirect github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect @@ -71,14 +68,13 @@ require ( github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect go.uber.org/multierr v1.6.0 // indirect go.uber.org/zap v1.23.0 // indirect - golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect - golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect + golang.org/x/exp v0.0.0-20221028150844-83b7d23a625f // indirect + golang.org/x/mod v0.6.0 // indirect golang.org/x/text v0.4.0 // indirect golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect - golang.org/x/tools v0.1.12 // indirect + golang.org/x/tools v0.2.0 // indirect golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 // indirect google.golang.org/genproto v0.0.0-20210722135532-667f2b7c528f // indirect - gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect lukechampine.com/blake3 v1.1.7 // indirect ) diff --git a/go.sum b/go.sum index a39673d2..57955ea1 100644 --- a/go.sum +++ b/go.sum @@ -16,8 +16,8 @@ github.com/caddyserver/certmagic v0.17.2 h1:o30seC1T/dBqBCNNGNHWwj2i5/I/FMjBbTAh github.com/caddyserver/certmagic v0.17.2/go.mod h1:ouWUuC490GOLJzkyN35eXfV8bSbwMwSf4bdhkIxtdQE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudflare/circl v1.2.1-0.20220831060716-4cf0150356fc h1:307gdRLiZ08dwOIKwc5lAQ19DRFaQQvdhHalyB4Asx8= -github.com/cloudflare/circl v1.2.1-0.20220831060716-4cf0150356fc/go.mod h1:+CauBF6R70Jqcyl8N2hC8pAXYbWkGIezuSbuGLtRhnw= +github.com/cloudflare/circl v1.2.1-0.20221019164342-6ab4dfed8f3c h1:K1VdSnBZiGapczwcUKnE1qcsMBclA84DUOD2NG/78VY= +github.com/cloudflare/circl v1.2.1-0.20221019164342-6ab4dfed8f3c/go.mod h1:+CauBF6R70Jqcyl8N2hC8pAXYbWkGIezuSbuGLtRhnw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= @@ -38,8 +38,6 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -49,14 +47,11 @@ github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4= github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58= github.com/go-chi/render v1.0.2 h1:4ER/udB0+fMWB2Jlf15RV3F4A2FDuYi/9f+lFttR/Lg= github.com/go-chi/render v1.0.2/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/gofrs/uuid v4.3.0+incompatible h1:CaSVZxm5B+7o45rtab4jC2G37WGYX1zQfuU2i6DSvnc= github.com/gofrs/uuid v4.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= @@ -84,7 +79,6 @@ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY= @@ -101,27 +95,18 @@ github.com/libdns/libdns v0.2.1 h1:Wu59T7wSHRgtA0cfxC+n1c/e+O3upJGWytknkmFEDis= github.com/libdns/libdns v0.2.1/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40= github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= -github.com/marten-seemann/qpack v0.2.1 h1:jvTsT/HpCn2UZJdP+UUB53FfUUgeOyG5K1ns0OJOGVs= -github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc= -github.com/marten-seemann/qtls-go1-18 v0.1.2 h1:JH6jmzbduz0ITVQ7ShevK10Av5+jBEKAHMntXmIV7kM= -github.com/marten-seemann/qtls-go1-18 v0.1.2/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4= -github.com/marten-seemann/qtls-go1-19 v0.1.0 h1:rLFKD/9mp/uq1SYGYuVZhm83wkmU95pK5df3GufyYYU= -github.com/marten-seemann/qtls-go1-19 v0.1.0/go.mod h1:5HTDWtVudo/WFsHKRNuOhWlbdjrfs5JHrYb0wIJqGpI= +github.com/marten-seemann/qpack v0.3.0 h1:UiWstOgT8+znlkDPOg2+3rIuYXJ2CnGDkGUXN6ki6hE= +github.com/marten-seemann/qpack v0.3.0/go.mod h1:cGfKPBiP4a9EQdxCwEwI/GEeWAsjSekBvx/X8mh58+g= +github.com/marten-seemann/qtls-go1-18 v0.1.3 h1:R4H2Ks8P6pAtUagjFty2p7BVHn3XiwDAl7TTQf5h7TI= +github.com/marten-seemann/qtls-go1-18 v0.1.3/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4= +github.com/marten-seemann/qtls-go1-19 v0.1.1 h1:mnbxeq3oEyQxQXwI4ReCgW9DPoPR94sNlqWoDZnjRIE= +github.com/marten-seemann/qtls-go1-19 v0.1.1/go.mod h1:5HTDWtVudo/WFsHKRNuOhWlbdjrfs5JHrYb0wIJqGpI= github.com/mholt/acmez v1.0.4 h1:N3cE4Pek+dSolbsofIkAYz6H1d3pE+2G0os7QHslf80= github.com/mholt/acmez v1.0.4/go.mod h1:qFGLZ4u+ehWINeJZjzPlsnjJBCPAADWTcIqE/7DAYQY= github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA= github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.13.0 h1:7lLHu94wT9Ij0o6EWWclhu0aOh32VxhkwEJvzuWPeak= +github.com/onsi/ginkgo/v2 v2.3.0 h1:kUMoxMoQG3ogk/QWyKh3zibV7BKZ+xBpWil1cTylVqc= +github.com/onsi/gomega v1.22.1 h1:pY8O4lBfsHKZHM/6nrxkhVPUznOlIu3quZcKP/M20KI= github.com/oschwald/maxminddb-golang v1.10.0 h1:Xp1u0ZhqkSuopaKmk1WwHtjF0H9Hd9181uj2MQ5Vndg= github.com/oschwald/maxminddb-golang v1.10.0/go.mod h1:Y2ELenReaLAZ0b400URyGwvYxHV1dLIxBuyOsyYjHK0= github.com/pires/go-proxyproto v0.6.2 h1:KAZ7UteSOt6urjme6ZldyFm4wDe/z0ZUP0Yv0Dos0d8= @@ -137,18 +122,20 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sagernet/abx-go v0.0.0-20220819185957-dba1257d738e h1:5CFRo8FJbCuf5s/eTBdZpmMbn8Fe2eSMLNAYfKanA34= github.com/sagernet/abx-go v0.0.0-20220819185957-dba1257d738e/go.mod h1:qbt0dWObotCfcjAJJ9AxtFPNSDUfZF+6dCpgKEOBn/g= +github.com/sagernet/cloudflare-tls v0.0.0-20221031050923-d70792f4c3a0 h1:KyhtFFt1Jtp5vW2ohNvstvQffTOQ/s5vENuGXzdA+TM= +github.com/sagernet/cloudflare-tls v0.0.0-20221031050923-d70792f4c3a0/go.mod h1:D4SFEOkJK+4W1v86ZhX0jPM0rAL498fyQAChqMtes/I= github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c6AkmAylhauulqN/c5dnh8/KssrE9c93TQrXldA= github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h1:QUQ4RRHD6hGGHdFMEtR8T2P6GS6R3D/CXKdaYHKKXms= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= -github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb h1:wc0yQ+SBn4TaTYRwpwvEm3nc4eRdxk6vtRbouLVZAzk= -github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb/go.mod h1:MIccjRKnPTjWwAOpl+AUGWOkzyTd9tERytudxu+1ra4= +github.com/sagernet/quic-go v0.0.0-20221031051350-29d8bb1c8127 h1:rraPfWlUy2cdZ61FLXRCFbL0lb7oocScbr4Ac0rIzTU= +github.com/sagernet/quic-go v0.0.0-20221031051350-29d8bb1c8127/go.mod h1:oWFbojDMm85/Jbm/fyWoo8Pux6dIssxGi3q1r+5642A= github.com/sagernet/sing v0.0.0-20220812082120-05f9836bff8f/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= github.com/sagernet/sing v0.0.0-20221008120626-60a9910eefe4 h1:LO7xMvMGhYmjQg2vjhTzsODyzs9/WLYu5Per+/8jIeo= github.com/sagernet/sing v0.0.0-20221008120626-60a9910eefe4/go.mod h1:zvgDYKI+vCAW9RyfyrKTgleI+DOa8lzHMPC7VZo3OL4= -github.com/sagernet/sing-dns v0.0.0-20221029093630-568471e6216d h1:U/oM43D++tdv2r9OfHbcd4Q1pMCs8+HW7hPkAD2rrvk= -github.com/sagernet/sing-dns v0.0.0-20221029093630-568471e6216d/go.mod h1:SrvWLfOSlnFmH32CWXicfilAGgIXR0VjrH6yRbuXYww= +github.com/sagernet/sing-dns v0.0.0-20221031055845-7de76401d403 h1:kKDO97rx+JVJ4HI1hTWOnCCI6um5clK1LfnIto2DY4M= +github.com/sagernet/sing-dns v0.0.0-20221031055845-7de76401d403/go.mod h1:cyL9DHbBZ0Xlt/8VD0i6yeiDayH0KzWGNQb8MYhhz7g= github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6 h1:JJfDeYYhWunvtxsU/mOVNTmFQmnzGx9dY034qG6G3g4= github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6/go.mod h1:EX3RbZvrwAkPI2nuGa78T2iQXmrkT+/VQtskjou42xM= github.com/sagernet/sing-tun v0.0.0-20221028015259-ea5c35f62f07 h1:zupkkVVFWv0QsLPjxEzlzXlLfDk1hUujK8ctJSIKFCI= @@ -175,7 +162,6 @@ github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKs github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg= github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= @@ -201,30 +187,25 @@ golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA= -golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA= +golang.org/x/exp v0.0.0-20221028150844-83b7d23a625f h1:Al51T6tzvuh3oiwX11vex3QgJ2XTedFPGmbEVh8cdoc= +golang.org/x/exp v0.0.0-20221028150844-83b7d23a625f/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I= +golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -240,24 +221,16 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde h1:ejfdSekXMDxDLbRrJMwUk6KnSLZ2McaUCVcIKM+N6jc= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -274,7 +247,6 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -290,12 +262,10 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE= +golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -338,15 +308,9 @@ google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/transport/cloudflaretls/README.md b/transport/cloudflaretls/README.md deleted file mode 100644 index f138b1a7..00000000 --- a/transport/cloudflaretls/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# cloudflare-tls - -kanged from https://github.com/cloudflare/go -branch: cf -commit: 4d2a840e50d2b4316aa19934271832d080c44f7f -go: 1.18.5 -changes: use github.com/cloudflare/circl 4cf0150356fc62a0ea5c0eec2f64b756cb404145 \ No newline at end of file diff --git a/transport/cloudflaretls/alert.go b/transport/cloudflaretls/alert.go deleted file mode 100644 index 755083b8..00000000 --- a/transport/cloudflaretls/alert.go +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package tls - -import "strconv" - -type alert uint8 - -const ( - // alert level - alertLevelWarning = 1 - alertLevelError = 2 -) - -const ( - alertCloseNotify alert = 0 - alertUnexpectedMessage alert = 10 - alertBadRecordMAC alert = 20 - alertDecryptionFailed alert = 21 - alertRecordOverflow alert = 22 - alertDecompressionFailure alert = 30 - alertHandshakeFailure alert = 40 - alertBadCertificate alert = 42 - alertUnsupportedCertificate alert = 43 - alertCertificateRevoked alert = 44 - alertCertificateExpired alert = 45 - alertCertificateUnknown alert = 46 - alertIllegalParameter alert = 47 - alertUnknownCA alert = 48 - alertAccessDenied alert = 49 - alertDecodeError alert = 50 - alertDecryptError alert = 51 - alertExportRestriction alert = 60 - alertProtocolVersion alert = 70 - alertInsufficientSecurity alert = 71 - alertInternalError alert = 80 - alertInappropriateFallback alert = 86 - alertUserCanceled alert = 90 - alertNoRenegotiation alert = 100 - alertMissingExtension alert = 109 - alertUnsupportedExtension alert = 110 - alertCertificateUnobtainable alert = 111 - alertUnrecognizedName alert = 112 - alertBadCertificateStatusResponse alert = 113 - alertBadCertificateHashValue alert = 114 - alertUnknownPSKIdentity alert = 115 - alertCertificateRequired alert = 116 - alertNoApplicationProtocol alert = 120 - alertECHRequired alert = 121 -) - -var alertText = map[alert]string{ - alertCloseNotify: "close notify", - alertUnexpectedMessage: "unexpected message", - alertBadRecordMAC: "bad record MAC", - alertDecryptionFailed: "decryption failed", - alertRecordOverflow: "record overflow", - alertDecompressionFailure: "decompression failure", - alertHandshakeFailure: "handshake failure", - alertBadCertificate: "bad certificate", - alertUnsupportedCertificate: "unsupported certificate", - alertCertificateRevoked: "revoked certificate", - alertCertificateExpired: "expired certificate", - alertCertificateUnknown: "unknown certificate", - alertIllegalParameter: "illegal parameter", - alertUnknownCA: "unknown certificate authority", - alertAccessDenied: "access denied", - alertDecodeError: "error decoding message", - alertDecryptError: "error decrypting message", - alertExportRestriction: "export restriction", - alertProtocolVersion: "protocol version not supported", - alertInsufficientSecurity: "insufficient security level", - alertInternalError: "internal error", - alertInappropriateFallback: "inappropriate fallback", - alertUserCanceled: "user canceled", - alertNoRenegotiation: "no renegotiation", - alertMissingExtension: "missing extension", - alertUnsupportedExtension: "unsupported extension", - alertCertificateUnobtainable: "certificate unobtainable", - alertUnrecognizedName: "unrecognized name", - alertBadCertificateStatusResponse: "bad certificate status response", - alertBadCertificateHashValue: "bad certificate hash value", - alertUnknownPSKIdentity: "unknown PSK identity", - alertCertificateRequired: "certificate required", - alertNoApplicationProtocol: "no application protocol", - alertECHRequired: "ECH required", -} - -func (e alert) String() string { - s, ok := alertText[e] - if ok { - return "tls: " + s - } - return "tls: alert(" + strconv.Itoa(int(e)) + ")" -} - -func (e alert) Error() string { - return e.String() -} diff --git a/transport/cloudflaretls/auth.go b/transport/cloudflaretls/auth.go deleted file mode 100644 index bb067084..00000000 --- a/transport/cloudflaretls/auth.go +++ /dev/null @@ -1,345 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package tls - -import ( - "bytes" - "crypto" - "crypto/ecdsa" - "crypto/ed25519" - "crypto/elliptic" - "crypto/rsa" - "errors" - "fmt" - "hash" - "io" - - circlPki "github.com/cloudflare/circl/pki" - circlSign "github.com/cloudflare/circl/sign" -) - -// verifyHandshakeSignature verifies a signature against pre-hashed -// (if required) handshake contents. -func verifyHandshakeSignature(sigType uint8, pubkey crypto.PublicKey, hashFunc crypto.Hash, signed, sig []byte) error { - switch sigType { - case signatureECDSA: - pubKey, ok := pubkey.(*ecdsa.PublicKey) - if !ok { - return fmt.Errorf("expected an ECDSA public key, got %T", pubkey) - } - if !ecdsa.VerifyASN1(pubKey, signed, sig) { - return errors.New("ECDSA verification failure") - } - case signatureEd25519: - pubKey, ok := pubkey.(ed25519.PublicKey) - if !ok { - return fmt.Errorf("expected an Ed25519 public key, got %T", pubkey) - } - if !ed25519.Verify(pubKey, signed, sig) { - return errors.New("Ed25519 verification failure") - } - case signaturePKCS1v15: - pubKey, ok := pubkey.(*rsa.PublicKey) - if !ok { - return fmt.Errorf("expected an RSA public key, got %T", pubkey) - } - if err := rsa.VerifyPKCS1v15(pubKey, hashFunc, signed, sig); err != nil { - return err - } - case signatureRSAPSS: - pubKey, ok := pubkey.(*rsa.PublicKey) - if !ok { - return fmt.Errorf("expected an RSA public key, got %T", pubkey) - } - signOpts := &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash} - if err := rsa.VerifyPSS(pubKey, hashFunc, signed, sig, signOpts); err != nil { - return err - } - default: - scheme := circlSchemeBySigType(sigType) - if scheme == nil { - return errors.New("internal error: unknown signature type") - } - pubKey, ok := pubkey.(circlSign.PublicKey) - if !ok { - return fmt.Errorf("expected a %s public key, got %T", scheme.Name(), pubkey) - } - if !scheme.Verify(pubKey, signed, sig, nil) { - return fmt.Errorf("%s verification failure", scheme.Name()) - } - } - return nil -} - -const ( - serverSignatureContext = "TLS 1.3, server CertificateVerify\x00" - clientSignatureContext = "TLS 1.3, client CertificateVerify\x00" -) - -var signaturePadding = []byte{ - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -} - -// signedMessage returns the pre-hashed (if necessary) message to be signed by -// certificate keys in TLS 1.3. See RFC 8446, Section 4.4.3. -func signedMessage(sigHash crypto.Hash, context string, transcript hash.Hash) []byte { - if sigHash == directSigning { - b := &bytes.Buffer{} - b.Write(signaturePadding) - io.WriteString(b, context) - b.Write(transcript.Sum(nil)) - return b.Bytes() - } - h := sigHash.New() - h.Write(signaturePadding) - io.WriteString(h, context) - h.Write(transcript.Sum(nil)) - return h.Sum(nil) -} - -// typeAndHashFromSignatureScheme returns the corresponding signature type and -// crypto.Hash for a given TLS SignatureScheme. -func typeAndHashFromSignatureScheme(signatureAlgorithm SignatureScheme) (sigType uint8, hash crypto.Hash, err error) { - switch signatureAlgorithm { - case PKCS1WithSHA1, PKCS1WithSHA256, PKCS1WithSHA384, PKCS1WithSHA512: - sigType = signaturePKCS1v15 - case PSSWithSHA256, PSSWithSHA384, PSSWithSHA512: - sigType = signatureRSAPSS - case ECDSAWithSHA1, ECDSAWithP256AndSHA256, ECDSAWithP384AndSHA384, ECDSAWithP521AndSHA512: - sigType = signatureECDSA - case Ed25519: - sigType = signatureEd25519 - default: - scheme := circlPki.SchemeByTLSID(uint(signatureAlgorithm)) - if scheme == nil { - return 0, 0, fmt.Errorf("unsupported signature algorithm: %v", signatureAlgorithm) - } - sigType = sigTypeByCirclScheme(scheme) - if sigType == 0 { - return 0, 0, fmt.Errorf("github.com/cloudflare/circl scheme %s not supported", - scheme.Name()) - } - } - switch signatureAlgorithm { - case PKCS1WithSHA1, ECDSAWithSHA1: - hash = crypto.SHA1 - case PKCS1WithSHA256, PSSWithSHA256, ECDSAWithP256AndSHA256: - hash = crypto.SHA256 - case PKCS1WithSHA384, PSSWithSHA384, ECDSAWithP384AndSHA384: - hash = crypto.SHA384 - case PKCS1WithSHA512, PSSWithSHA512, ECDSAWithP521AndSHA512: - hash = crypto.SHA512 - case Ed25519: - hash = directSigning - default: - scheme := circlPki.SchemeByTLSID(uint(signatureAlgorithm)) - if scheme == nil { - return 0, 0, fmt.Errorf("unsupported signature algorithm: %v", signatureAlgorithm) - } - hash = directSigning - } - return sigType, hash, nil -} - -// legacyTypeAndHashFromPublicKey returns the fixed signature type and crypto.Hash for -// a given public key used with TLS 1.0 and 1.1, before the introduction of -// signature algorithm negotiation. -func legacyTypeAndHashFromPublicKey(pub crypto.PublicKey) (sigType uint8, hash crypto.Hash, err error) { - switch pub.(type) { - case *rsa.PublicKey: - return signaturePKCS1v15, crypto.MD5SHA1, nil - case *ecdsa.PublicKey: - return signatureECDSA, crypto.SHA1, nil - case ed25519.PublicKey: - // RFC 8422 specifies support for Ed25519 in TLS 1.0 and 1.1, - // but it requires holding on to a handshake transcript to do a - // full signature, and not even OpenSSL bothers with the - // complexity, so we can't even test it properly. - return 0, 0, fmt.Errorf("tls: Ed25519 public keys are not supported before TLS 1.2") - case circlSign.PublicKey: - return 0, 0, fmt.Errorf("tls: circl public keys are not supported before TLS 1.2") - default: - return 0, 0, fmt.Errorf("tls: unsupported public key: %T", pub) - } -} - -var rsaSignatureSchemes = []struct { - scheme SignatureScheme - minModulusBytes int - maxVersion uint16 -}{ - // RSA-PSS is used with PSSSaltLengthEqualsHash, and requires - // emLen >= hLen + sLen + 2 - {PSSWithSHA256, crypto.SHA256.Size()*2 + 2, VersionTLS13}, - {PSSWithSHA384, crypto.SHA384.Size()*2 + 2, VersionTLS13}, - {PSSWithSHA512, crypto.SHA512.Size()*2 + 2, VersionTLS13}, - // PKCS #1 v1.5 uses prefixes from hashPrefixes in crypto/rsa, and requires - // emLen >= len(prefix) + hLen + 11 - // TLS 1.3 dropped support for PKCS #1 v1.5 in favor of RSA-PSS. - {PKCS1WithSHA256, 19 + crypto.SHA256.Size() + 11, VersionTLS12}, - {PKCS1WithSHA384, 19 + crypto.SHA384.Size() + 11, VersionTLS12}, - {PKCS1WithSHA512, 19 + crypto.SHA512.Size() + 11, VersionTLS12}, - {PKCS1WithSHA1, 15 + crypto.SHA1.Size() + 11, VersionTLS12}, -} - -// signatureSchemesForCertificate returns the list of supported SignatureSchemes -// for a given certificate, based on the public key and the protocol version, -// and optionally filtered by its explicit SupportedSignatureAlgorithms. -// -// This function must be kept in sync with supportedSignatureAlgorithms. -func signatureSchemesForCertificate(version uint16, cert *Certificate) []SignatureScheme { - priv, ok := cert.PrivateKey.(crypto.Signer) - if !ok { - return nil - } - - var sigAlgs []SignatureScheme - switch pub := priv.Public().(type) { - case *ecdsa.PublicKey: - if version != VersionTLS13 { - // In TLS 1.2 and earlier, ECDSA algorithms are not - // constrained to a single curve. - sigAlgs = []SignatureScheme{ - ECDSAWithP256AndSHA256, - ECDSAWithP384AndSHA384, - ECDSAWithP521AndSHA512, - ECDSAWithSHA1, - } - break - } - switch pub.Curve { - case elliptic.P256(): - sigAlgs = []SignatureScheme{ECDSAWithP256AndSHA256} - case elliptic.P384(): - sigAlgs = []SignatureScheme{ECDSAWithP384AndSHA384} - case elliptic.P521(): - sigAlgs = []SignatureScheme{ECDSAWithP521AndSHA512} - default: - return nil - } - case *rsa.PublicKey: - size := pub.Size() - sigAlgs = make([]SignatureScheme, 0, len(rsaSignatureSchemes)) - for _, candidate := range rsaSignatureSchemes { - if size >= candidate.minModulusBytes && version <= candidate.maxVersion { - sigAlgs = append(sigAlgs, candidate.scheme) - } - } - case ed25519.PublicKey: - sigAlgs = []SignatureScheme{Ed25519} - case circlSign.PublicKey: - scheme := pub.Scheme() - tlsScheme, ok := scheme.(circlPki.TLSScheme) - if !ok { - return nil - } - sigAlgs = []SignatureScheme{SignatureScheme(tlsScheme.TLSIdentifier())} - default: - return nil - } - - if cert.SupportedSignatureAlgorithms != nil { - var filteredSigAlgs []SignatureScheme - for _, sigAlg := range sigAlgs { - if isSupportedSignatureAlgorithm(sigAlg, cert.SupportedSignatureAlgorithms) { - filteredSigAlgs = append(filteredSigAlgs, sigAlg) - } - } - return filteredSigAlgs - } - return sigAlgs -} - -// selectSignatureSchemeDC picks a SignatureScheme from the peer's preference list -// that works with the selected delegated credential. It's only called for protocol -// versions that support delegated credential, so TLS 1.3. -func selectSignatureSchemeDC(vers uint16, dc *DelegatedCredential, peerAlgs []SignatureScheme, peerAlgsDC []SignatureScheme) (SignatureScheme, error) { - if vers != VersionTLS13 { - return 0, errors.New("unsupported TLS version for dc") - } - - if !isSupportedSignatureAlgorithm(dc.algorithm, peerAlgs) { - return undefinedSignatureScheme, errors.New("tls: peer doesn't support the delegated credential's signature") - } - - // Pick signature scheme in the peer's preference order, as our - // preference order is not configurable. - for _, preferredAlg := range peerAlgsDC { - if preferredAlg == dc.cred.expCertVerfAlgo { - return preferredAlg, nil - } - } - return 0, errors.New("tls: peer doesn't support the delegated credential's signature algorithm") -} - -// selectSignatureScheme picks a SignatureScheme from the peer's preference list -// that works with the selected certificate. It's only called for protocol -// versions that support signature algorithms, so TLS 1.2 and 1.3. -func selectSignatureScheme(vers uint16, c *Certificate, peerAlgs []SignatureScheme) (SignatureScheme, error) { - supportedAlgs := signatureSchemesForCertificate(vers, c) - if len(supportedAlgs) == 0 { - return 0, unsupportedCertificateError(c) - } - if len(peerAlgs) == 0 && vers == VersionTLS12 { - // For TLS 1.2, if the client didn't send signature_algorithms then we - // can assume that it supports SHA1. See RFC 5246, Section 7.4.1.4.1. - peerAlgs = []SignatureScheme{PKCS1WithSHA1, ECDSAWithSHA1} - } - // Pick signature scheme in the peer's preference order, as our - // preference order is not configurable. - for _, preferredAlg := range peerAlgs { - if isSupportedSignatureAlgorithm(preferredAlg, supportedAlgs) { - return preferredAlg, nil - } - } - return 0, errors.New("tls: peer doesn't support any of the certificate's signature algorithms") -} - -// unsupportedCertificateError returns a helpful error for certificates with -// an unsupported private key. -func unsupportedCertificateError(cert *Certificate) error { - switch cert.PrivateKey.(type) { - case rsa.PrivateKey, ecdsa.PrivateKey: - return fmt.Errorf("tls: unsupported certificate: private key is %T, expected *%T", - cert.PrivateKey, cert.PrivateKey) - case *ed25519.PrivateKey: - return fmt.Errorf("tls: unsupported certificate: private key is *ed25519.PrivateKey, expected ed25519.PrivateKey") - } - - signer, ok := cert.PrivateKey.(crypto.Signer) - if !ok { - return fmt.Errorf("tls: certificate private key (%T) does not implement crypto.Signer", - cert.PrivateKey) - } - - switch pub := signer.Public().(type) { - case *ecdsa.PublicKey: - switch pub.Curve { - case elliptic.P256(): - case elliptic.P384(): - case elliptic.P521(): - default: - return fmt.Errorf("tls: unsupported certificate curve (%s)", pub.Curve.Params().Name) - } - case *rsa.PublicKey: - return fmt.Errorf("tls: certificate RSA key size too small for supported signature algorithms") - case ed25519.PublicKey: - default: - return fmt.Errorf("tls: unsupported certificate key (%T)", pub) - } - - if cert.SupportedSignatureAlgorithms != nil { - return fmt.Errorf("tls: peer doesn't support the certificate custom signature algorithms") - } - - return fmt.Errorf("tls: internal error: unsupported key (%T)", cert.PrivateKey) -} diff --git a/transport/cloudflaretls/cfkem.go b/transport/cloudflaretls/cfkem.go deleted file mode 100644 index 551d6e11..00000000 --- a/transport/cloudflaretls/cfkem.go +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright 2022 Cloudflare, Inc. All rights reserved. Use of this source code -// is governed by a BSD-style license that can be found in the LICENSE file. -// -// Glue to add Circl's (post-quantum) hybrid KEMs. -// -// To enable set CurvePreferences with the desired scheme as the first element: -// -// import ( -// "github.com/cloudflare/circl/kem/tls" -// "github.com/cloudflare/circl/kem/hybrid" -// -// [...] -// -// config.CurvePreferences = []tls.CurveID{ -// hybrid.X25519Kyber512Draft00().(tls.TLSScheme).TLSCurveID(), -// tls.X25519, -// tls.P256, -// } - -package tls - -import ( - "fmt" - "io" - - "github.com/cloudflare/circl/kem" - "github.com/cloudflare/circl/kem/hybrid" -) - -// Either ecdheParameters or kem.PrivateKey -type clientKeySharePrivate interface{} - -var ( - X25519Kyber512Draft00 = CurveID(0xfe30) - X25519Kyber768Draft00 = CurveID(0xfe31) - invalidCurveID = CurveID(0) -) - -func kemSchemeKeyToCurveID(s kem.Scheme) CurveID { - switch s.Name() { - case "Kyber512-X25519": - return X25519Kyber512Draft00 - case "Kyber768-X25519": - return X25519Kyber768Draft00 - default: - return invalidCurveID - } -} - -// Extract CurveID from clientKeySharePrivate -func clientKeySharePrivateCurveID(ks clientKeySharePrivate) CurveID { - switch v := ks.(type) { - case kem.PrivateKey: - ret := kemSchemeKeyToCurveID(v.Scheme()) - if ret == invalidCurveID { - panic("cfkem: internal error: don't know CurveID for this KEM") - } - return ret - case ecdheParameters: - return v.CurveID() - default: - panic("cfkem: internal error: unknown clientKeySharePrivate") - } -} - -// Returns scheme by CurveID if supported by Circl -func curveIdToCirclScheme(id CurveID) kem.Scheme { - switch id { - case X25519Kyber512Draft00: - return hybrid.Kyber512X25519() - case X25519Kyber768Draft00: - return hybrid.Kyber768X25519() - } - return nil -} - -// Generate a new shared secret and encapsulates it for the packed -// public key in ppk using randomness from rnd. -func encapsulateForKem(scheme kem.Scheme, rnd io.Reader, ppk []byte) ( - ct, ss []byte, alert alert, err error, -) { - pk, err := scheme.UnmarshalBinaryPublicKey(ppk) - if err != nil { - return nil, nil, alertIllegalParameter, fmt.Errorf("unpack pk: %w", err) - } - seed := make([]byte, scheme.EncapsulationSeedSize()) - if _, err := io.ReadFull(rnd, seed); err != nil { - return nil, nil, alertInternalError, fmt.Errorf("random: %w", err) - } - ct, ss, err = scheme.EncapsulateDeterministically(pk, seed) - return ct, ss, alertIllegalParameter, err -} - -// Generate a new keypair using randomness from rnd. -func generateKemKeyPair(scheme kem.Scheme, rnd io.Reader) ( - kem.PublicKey, kem.PrivateKey, error, -) { - seed := make([]byte, scheme.SeedSize()) - if _, err := io.ReadFull(rnd, seed); err != nil { - return nil, nil, err - } - pk, sk := scheme.DeriveKeyPair(seed) - return pk, sk, nil -} diff --git a/transport/cloudflaretls/cipher_suites.go b/transport/cloudflaretls/cipher_suites.go deleted file mode 100644 index e9cf0715..00000000 --- a/transport/cloudflaretls/cipher_suites.go +++ /dev/null @@ -1,688 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package tls - -import ( - "crypto" - "crypto/aes" - "crypto/cipher" - "crypto/des" - "crypto/hmac" - "crypto/rc4" - "crypto/sha1" - "crypto/sha256" - "fmt" - "hash" - "runtime" - - "golang.org/x/crypto/chacha20poly1305" - "golang.org/x/sys/cpu" -) - -// CipherSuite is a TLS cipher suite. Note that most functions in this package -// accept and expose cipher suite IDs instead of this type. -type CipherSuite struct { - ID uint16 - Name string - - // Supported versions is the list of TLS protocol versions that can - // negotiate this cipher suite. - SupportedVersions []uint16 - - // Insecure is true if the cipher suite has known security issues - // due to its primitives, design, or implementation. - Insecure bool -} - -var ( - supportedUpToTLS12 = []uint16{VersionTLS10, VersionTLS11, VersionTLS12} - supportedOnlyTLS12 = []uint16{VersionTLS12} - supportedOnlyTLS13 = []uint16{VersionTLS13} -) - -// CipherSuites returns a list of cipher suites currently implemented by this -// package, excluding those with security issues, which are returned by -// InsecureCipherSuites. -// -// The list is sorted by ID. Note that the default cipher suites selected by -// this package might depend on logic that can't be captured by a static list, -// and might not match those returned by this function. -func CipherSuites() []*CipherSuite { - return []*CipherSuite{ - {TLS_RSA_WITH_AES_128_CBC_SHA, "TLS_RSA_WITH_AES_128_CBC_SHA", supportedUpToTLS12, false}, - {TLS_RSA_WITH_AES_256_CBC_SHA, "TLS_RSA_WITH_AES_256_CBC_SHA", supportedUpToTLS12, false}, - {TLS_RSA_WITH_AES_128_GCM_SHA256, "TLS_RSA_WITH_AES_128_GCM_SHA256", supportedOnlyTLS12, false}, - {TLS_RSA_WITH_AES_256_GCM_SHA384, "TLS_RSA_WITH_AES_256_GCM_SHA384", supportedOnlyTLS12, false}, - - {TLS_AES_128_GCM_SHA256, "TLS_AES_128_GCM_SHA256", supportedOnlyTLS13, false}, - {TLS_AES_256_GCM_SHA384, "TLS_AES_256_GCM_SHA384", supportedOnlyTLS13, false}, - {TLS_CHACHA20_POLY1305_SHA256, "TLS_CHACHA20_POLY1305_SHA256", supportedOnlyTLS13, false}, - - {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", supportedUpToTLS12, false}, - {TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", supportedUpToTLS12, false}, - {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", supportedUpToTLS12, false}, - {TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", supportedUpToTLS12, false}, - {TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", supportedOnlyTLS12, false}, - {TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", supportedOnlyTLS12, false}, - {TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", supportedOnlyTLS12, false}, - {TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", supportedOnlyTLS12, false}, - {TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", supportedOnlyTLS12, false}, - {TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", supportedOnlyTLS12, false}, - } -} - -// InsecureCipherSuites returns a list of cipher suites currently implemented by -// this package and which have security issues. -// -// Most applications should not use the cipher suites in this list, and should -// only use those returned by CipherSuites. -func InsecureCipherSuites() []*CipherSuite { - // This list includes RC4, CBC_SHA256, and 3DES cipher suites. See - // cipherSuitesPreferenceOrder for details. - return []*CipherSuite{ - {TLS_RSA_WITH_RC4_128_SHA, "TLS_RSA_WITH_RC4_128_SHA", supportedUpToTLS12, true}, - {TLS_RSA_WITH_3DES_EDE_CBC_SHA, "TLS_RSA_WITH_3DES_EDE_CBC_SHA", supportedUpToTLS12, true}, - {TLS_RSA_WITH_AES_128_CBC_SHA256, "TLS_RSA_WITH_AES_128_CBC_SHA256", supportedOnlyTLS12, true}, - {TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", supportedUpToTLS12, true}, - {TLS_ECDHE_RSA_WITH_RC4_128_SHA, "TLS_ECDHE_RSA_WITH_RC4_128_SHA", supportedUpToTLS12, true}, - {TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", supportedUpToTLS12, true}, - {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", supportedOnlyTLS12, true}, - {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", supportedOnlyTLS12, true}, - } -} - -// CipherSuiteName returns the standard name for the passed cipher suite ID -// (e.g. "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"), or a fallback representation -// of the ID value if the cipher suite is not implemented by this package. -func CipherSuiteName(id uint16) string { - for _, c := range CipherSuites() { - if c.ID == id { - return c.Name - } - } - for _, c := range InsecureCipherSuites() { - if c.ID == id { - return c.Name - } - } - return fmt.Sprintf("0x%04X", id) -} - -const ( - // suiteECDHE indicates that the cipher suite involves elliptic curve - // Diffie-Hellman. This means that it should only be selected when the - // client indicates that it supports ECC with a curve and point format - // that we're happy with. - suiteECDHE = 1 << iota - // suiteECSign indicates that the cipher suite involves an ECDSA or - // EdDSA signature and therefore may only be selected when the server's - // certificate is ECDSA or EdDSA. If this is not set then the cipher suite - // is RSA based. - suiteECSign - // suiteTLS12 indicates that the cipher suite should only be advertised - // and accepted when using TLS 1.2. - suiteTLS12 - // suiteSHA384 indicates that the cipher suite uses SHA384 as the - // handshake hash. - suiteSHA384 -) - -// A cipherSuite is a TLS 1.0–1.2 cipher suite, and defines the key exchange -// mechanism, as well as the cipher+MAC pair or the AEAD. -type cipherSuite struct { - id uint16 - // the lengths, in bytes, of the key material needed for each component. - keyLen int - macLen int - ivLen int - ka func(version uint16) keyAgreement - // flags is a bitmask of the suite* values, above. - flags int - cipher func(key, iv []byte, isRead bool) any - mac func(key []byte) hash.Hash - aead func(key, fixedNonce []byte) aead -} - -var cipherSuites = []*cipherSuite{ // TODO: replace with a map, since the order doesn't matter. - {TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, 32, 0, 12, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadChaCha20Poly1305}, - {TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, 32, 0, 12, ecdheECDSAKA, suiteECDHE | suiteECSign | suiteTLS12, nil, nil, aeadChaCha20Poly1305}, - {TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadAESGCM}, - {TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECSign | suiteTLS12, nil, nil, aeadAESGCM}, - {TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM}, - {TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECSign | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM}, - {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, ecdheRSAKA, suiteECDHE | suiteTLS12, cipherAES, macSHA256, nil}, - {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil}, - {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, ecdheECDSAKA, suiteECDHE | suiteECSign | suiteTLS12, cipherAES, macSHA256, nil}, - {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECSign, cipherAES, macSHA1, nil}, - {TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil}, - {TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECSign, cipherAES, macSHA1, nil}, - {TLS_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, rsaKA, suiteTLS12, nil, nil, aeadAESGCM}, - {TLS_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, rsaKA, suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM}, - {TLS_RSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, rsaKA, suiteTLS12, cipherAES, macSHA256, nil}, - {TLS_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil}, - {TLS_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil}, - {TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, ecdheRSAKA, suiteECDHE, cipher3DES, macSHA1, nil}, - {TLS_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, rsaKA, 0, cipher3DES, macSHA1, nil}, - {TLS_RSA_WITH_RC4_128_SHA, 16, 20, 0, rsaKA, 0, cipherRC4, macSHA1, nil}, - {TLS_ECDHE_RSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheRSAKA, suiteECDHE, cipherRC4, macSHA1, nil}, - {TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheECDSAKA, suiteECDHE | suiteECSign, cipherRC4, macSHA1, nil}, -} - -// selectCipherSuite returns the first TLS 1.0–1.2 cipher suite from ids which -// is also in supportedIDs and passes the ok filter. -func selectCipherSuite(ids, supportedIDs []uint16, ok func(*cipherSuite) bool) *cipherSuite { - for _, id := range ids { - candidate := cipherSuiteByID(id) - if candidate == nil || !ok(candidate) { - continue - } - - for _, suppID := range supportedIDs { - if id == suppID { - return candidate - } - } - } - return nil -} - -// A cipherSuiteTLS13 defines only the pair of the AEAD algorithm and hash -// algorithm to be used with HKDF. See RFC 8446, Appendix B.4. -type cipherSuiteTLS13 struct { - id uint16 - keyLen int - aead func(key, fixedNonce []byte) aead - hash crypto.Hash -} - -var cipherSuitesTLS13 = []*cipherSuiteTLS13{ // TODO: replace with a map. - {TLS_AES_128_GCM_SHA256, 16, aeadAESGCMTLS13, crypto.SHA256}, - {TLS_CHACHA20_POLY1305_SHA256, 32, aeadChaCha20Poly1305, crypto.SHA256}, - {TLS_AES_256_GCM_SHA384, 32, aeadAESGCMTLS13, crypto.SHA384}, -} - -// cipherSuitesPreferenceOrder is the order in which we'll select (on the -// server) or advertise (on the client) TLS 1.0–1.2 cipher suites. -// -// Cipher suites are filtered but not reordered based on the application and -// peer's preferences, meaning we'll never select a suite lower in this list if -// any higher one is available. This makes it more defensible to keep weaker -// cipher suites enabled, especially on the server side where we get the last -// word, since there are no known downgrade attacks on cipher suites selection. -// -// The list is sorted by applying the following priority rules, stopping at the -// first (most important) applicable one: -// -// - Anything else comes before RC4 -// -// RC4 has practically exploitable biases. See https://www.rc4nomore.com. -// -// - Anything else comes before CBC_SHA256 -// -// SHA-256 variants of the CBC ciphersuites don't implement any Lucky13 -// countermeasures. See http://www.isg.rhul.ac.uk/tls/Lucky13.html and -// https://www.imperialviolet.org/2013/02/04/luckythirteen.html. -// -// - Anything else comes before 3DES -// -// 3DES has 64-bit blocks, which makes it fundamentally susceptible to -// birthday attacks. See https://sweet32.info. -// -// - ECDHE comes before anything else -// -// Once we got the broken stuff out of the way, the most important -// property a cipher suite can have is forward secrecy. We don't -// implement FFDHE, so that means ECDHE. -// -// - AEADs come before CBC ciphers -// -// Even with Lucky13 countermeasures, MAC-then-Encrypt CBC cipher suites -// are fundamentally fragile, and suffered from an endless sequence of -// padding oracle attacks. See https://eprint.iacr.org/2015/1129, -// https://www.imperialviolet.org/2014/12/08/poodleagain.html, and -// https://blog.cloudflare.com/yet-another-padding-oracle-in-openssl-cbc-ciphersuites/. -// -// - AES comes before ChaCha20 -// -// When AES hardware is available, AES-128-GCM and AES-256-GCM are faster -// than ChaCha20Poly1305. -// -// When AES hardware is not available, AES-128-GCM is one or more of: much -// slower, way more complex, and less safe (because not constant time) -// than ChaCha20Poly1305. -// -// We use this list if we think both peers have AES hardware, and -// cipherSuitesPreferenceOrderNoAES otherwise. -// -// - AES-128 comes before AES-256 -// -// The only potential advantages of AES-256 are better multi-target -// margins, and hypothetical post-quantum properties. Neither apply to -// TLS, and AES-256 is slower due to its four extra rounds (which don't -// contribute to the advantages above). -// -// - ECDSA comes before RSA -// -// The relative order of ECDSA and RSA cipher suites doesn't matter, -// as they depend on the certificate. Pick one to get a stable order. -var cipherSuitesPreferenceOrder = []uint16{ - // AEADs w/ ECDHE - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, - - // CBC w/ ECDHE - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, - TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, - - // AEADs w/o ECDHE - TLS_RSA_WITH_AES_128_GCM_SHA256, - TLS_RSA_WITH_AES_256_GCM_SHA384, - - // CBC w/o ECDHE - TLS_RSA_WITH_AES_128_CBC_SHA, - TLS_RSA_WITH_AES_256_CBC_SHA, - - // 3DES - TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, - TLS_RSA_WITH_3DES_EDE_CBC_SHA, - - // CBC_SHA256 - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, - TLS_RSA_WITH_AES_128_CBC_SHA256, - - // RC4 - TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA, - TLS_RSA_WITH_RC4_128_SHA, -} - -var cipherSuitesPreferenceOrderNoAES = []uint16{ - // ChaCha20Poly1305 - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, - - // AES-GCM w/ ECDHE - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, - - // The rest of cipherSuitesPreferenceOrder. - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, - TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, - TLS_RSA_WITH_AES_128_GCM_SHA256, - TLS_RSA_WITH_AES_256_GCM_SHA384, - TLS_RSA_WITH_AES_128_CBC_SHA, - TLS_RSA_WITH_AES_256_CBC_SHA, - TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, - TLS_RSA_WITH_3DES_EDE_CBC_SHA, - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, - TLS_RSA_WITH_AES_128_CBC_SHA256, - TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA, - TLS_RSA_WITH_RC4_128_SHA, -} - -// disabledCipherSuites are not used unless explicitly listed in -// Config.CipherSuites. They MUST be at the end of cipherSuitesPreferenceOrder. -var disabledCipherSuites = []uint16{ - // CBC_SHA256 - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, - TLS_RSA_WITH_AES_128_CBC_SHA256, - - // RC4 - TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA, - TLS_RSA_WITH_RC4_128_SHA, -} - -var ( - defaultCipherSuitesLen = len(cipherSuitesPreferenceOrder) - len(disabledCipherSuites) - defaultCipherSuites = cipherSuitesPreferenceOrder[:defaultCipherSuitesLen] -) - -// defaultCipherSuitesTLS13 is also the preference order, since there are no -// disabled by default TLS 1.3 cipher suites. The same AES vs ChaCha20 logic as -// cipherSuitesPreferenceOrder applies. -var defaultCipherSuitesTLS13 = []uint16{ - TLS_AES_128_GCM_SHA256, - TLS_AES_256_GCM_SHA384, - TLS_CHACHA20_POLY1305_SHA256, -} - -var defaultCipherSuitesTLS13NoAES = []uint16{ - TLS_CHACHA20_POLY1305_SHA256, - TLS_AES_128_GCM_SHA256, - TLS_AES_256_GCM_SHA384, -} - -var ( - hasGCMAsmAMD64 = cpu.X86.HasAES && cpu.X86.HasPCLMULQDQ - hasGCMAsmARM64 = cpu.ARM64.HasAES && cpu.ARM64.HasPMULL - // Keep in sync with crypto/aes/cipher_s390x.go. - hasGCMAsmS390X = cpu.S390X.HasAES && cpu.S390X.HasAESCBC && cpu.S390X.HasAESCTR && - (cpu.S390X.HasGHASH || cpu.S390X.HasAESGCM) - - hasAESGCMHardwareSupport = runtime.GOARCH == "amd64" && hasGCMAsmAMD64 || - runtime.GOARCH == "arm64" && hasGCMAsmARM64 || - runtime.GOARCH == "s390x" && hasGCMAsmS390X -) - -var aesgcmCiphers = map[uint16]bool{ - // TLS 1.2 - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: true, - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: true, - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: true, - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: true, - // TLS 1.3 - TLS_AES_128_GCM_SHA256: true, - TLS_AES_256_GCM_SHA384: true, -} - -var nonAESGCMAEADCiphers = map[uint16]bool{ - // TLS 1.2 - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305: true, - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305: true, - // TLS 1.3 - TLS_CHACHA20_POLY1305_SHA256: true, -} - -// aesgcmPreferred returns whether the first known cipher in the preference list -// is an AES-GCM cipher, implying the peer has hardware support for it. -func aesgcmPreferred(ciphers []uint16) bool { - for _, cID := range ciphers { - if c := cipherSuiteByID(cID); c != nil { - return aesgcmCiphers[cID] - } - if c := cipherSuiteTLS13ByID(cID); c != nil { - return aesgcmCiphers[cID] - } - } - return false -} - -func cipherRC4(key, iv []byte, isRead bool) any { - cipher, _ := rc4.NewCipher(key) - return cipher -} - -func cipher3DES(key, iv []byte, isRead bool) any { - block, _ := des.NewTripleDESCipher(key) - if isRead { - return cipher.NewCBCDecrypter(block, iv) - } - return cipher.NewCBCEncrypter(block, iv) -} - -func cipherAES(key, iv []byte, isRead bool) any { - block, _ := aes.NewCipher(key) - if isRead { - return cipher.NewCBCDecrypter(block, iv) - } - return cipher.NewCBCEncrypter(block, iv) -} - -// macSHA1 returns a SHA-1 based constant time MAC. -func macSHA1(key []byte) hash.Hash { - return hmac.New(newConstantTimeHash(sha1.New), key) -} - -// macSHA256 returns a SHA-256 based MAC. This is only supported in TLS 1.2 and -// is currently only used in disabled-by-default cipher suites. -func macSHA256(key []byte) hash.Hash { - return hmac.New(sha256.New, key) -} - -type aead interface { - cipher.AEAD - - // explicitNonceLen returns the number of bytes of explicit nonce - // included in each record. This is eight for older AEADs and - // zero for modern ones. - explicitNonceLen() int -} - -const ( - aeadNonceLength = 12 - noncePrefixLength = 4 -) - -// prefixNonceAEAD wraps an AEAD and prefixes a fixed portion of the nonce to -// each call. -type prefixNonceAEAD struct { - // nonce contains the fixed part of the nonce in the first four bytes. - nonce [aeadNonceLength]byte - aead cipher.AEAD -} - -func (f *prefixNonceAEAD) NonceSize() int { return aeadNonceLength - noncePrefixLength } -func (f *prefixNonceAEAD) Overhead() int { return f.aead.Overhead() } -func (f *prefixNonceAEAD) explicitNonceLen() int { return f.NonceSize() } - -func (f *prefixNonceAEAD) Seal(out, nonce, plaintext, additionalData []byte) []byte { - copy(f.nonce[4:], nonce) - return f.aead.Seal(out, f.nonce[:], plaintext, additionalData) -} - -func (f *prefixNonceAEAD) Open(out, nonce, ciphertext, additionalData []byte) ([]byte, error) { - copy(f.nonce[4:], nonce) - return f.aead.Open(out, f.nonce[:], ciphertext, additionalData) -} - -// xoredNonceAEAD wraps an AEAD by XORing in a fixed pattern to the nonce -// before each call. -type xorNonceAEAD struct { - nonceMask [aeadNonceLength]byte - aead cipher.AEAD -} - -func (f *xorNonceAEAD) NonceSize() int { return 8 } // 64-bit sequence number -func (f *xorNonceAEAD) Overhead() int { return f.aead.Overhead() } -func (f *xorNonceAEAD) explicitNonceLen() int { return 0 } - -func (f *xorNonceAEAD) Seal(out, nonce, plaintext, additionalData []byte) []byte { - for i, b := range nonce { - f.nonceMask[4+i] ^= b - } - result := f.aead.Seal(out, f.nonceMask[:], plaintext, additionalData) - for i, b := range nonce { - f.nonceMask[4+i] ^= b - } - - return result -} - -func (f *xorNonceAEAD) Open(out, nonce, ciphertext, additionalData []byte) ([]byte, error) { - for i, b := range nonce { - f.nonceMask[4+i] ^= b - } - result, err := f.aead.Open(out, f.nonceMask[:], ciphertext, additionalData) - for i, b := range nonce { - f.nonceMask[4+i] ^= b - } - - return result, err -} - -func aeadAESGCM(key, noncePrefix []byte) aead { - if len(noncePrefix) != noncePrefixLength { - panic("tls: internal error: wrong nonce length") - } - aes, err := aes.NewCipher(key) - if err != nil { - panic(err) - } - aead, err := cipher.NewGCM(aes) - if err != nil { - panic(err) - } - - ret := &prefixNonceAEAD{aead: aead} - copy(ret.nonce[:], noncePrefix) - return ret -} - -func aeadAESGCMTLS13(key, nonceMask []byte) aead { - if len(nonceMask) != aeadNonceLength { - panic("tls: internal error: wrong nonce length") - } - aes, err := aes.NewCipher(key) - if err != nil { - panic(err) - } - aead, err := cipher.NewGCM(aes) - if err != nil { - panic(err) - } - - ret := &xorNonceAEAD{aead: aead} - copy(ret.nonceMask[:], nonceMask) - return ret -} - -func aeadChaCha20Poly1305(key, nonceMask []byte) aead { - if len(nonceMask) != aeadNonceLength { - panic("tls: internal error: wrong nonce length") - } - aead, err := chacha20poly1305.New(key) - if err != nil { - panic(err) - } - - ret := &xorNonceAEAD{aead: aead} - copy(ret.nonceMask[:], nonceMask) - return ret -} - -type constantTimeHash interface { - hash.Hash - ConstantTimeSum(b []byte) []byte -} - -// cthWrapper wraps any hash.Hash that implements ConstantTimeSum, and replaces -// with that all calls to Sum. It's used to obtain a ConstantTimeSum-based HMAC. -type cthWrapper struct { - h constantTimeHash -} - -func (c *cthWrapper) Size() int { return c.h.Size() } -func (c *cthWrapper) BlockSize() int { return c.h.BlockSize() } -func (c *cthWrapper) Reset() { c.h.Reset() } -func (c *cthWrapper) Write(p []byte) (int, error) { return c.h.Write(p) } -func (c *cthWrapper) Sum(b []byte) []byte { return c.h.ConstantTimeSum(b) } - -func newConstantTimeHash(h func() hash.Hash) func() hash.Hash { - return func() hash.Hash { - return &cthWrapper{h().(constantTimeHash)} - } -} - -// tls10MAC implements the TLS 1.0 MAC function. RFC 2246, Section 6.2.3. -func tls10MAC(h hash.Hash, out, seq, header, data, extra []byte) []byte { - h.Reset() - h.Write(seq) - h.Write(header) - h.Write(data) - res := h.Sum(out) - if extra != nil { - h.Write(extra) - } - return res -} - -func rsaKA(version uint16) keyAgreement { - return rsaKeyAgreement{} -} - -func ecdheECDSAKA(version uint16) keyAgreement { - return &ecdheKeyAgreement{ - isRSA: false, - version: version, - } -} - -func ecdheRSAKA(version uint16) keyAgreement { - return &ecdheKeyAgreement{ - isRSA: true, - version: version, - } -} - -// mutualCipherSuite returns a cipherSuite given a list of supported -// ciphersuites and the id requested by the peer. -func mutualCipherSuite(have []uint16, want uint16) *cipherSuite { - for _, id := range have { - if id == want { - return cipherSuiteByID(id) - } - } - return nil -} - -func cipherSuiteByID(id uint16) *cipherSuite { - for _, cipherSuite := range cipherSuites { - if cipherSuite.id == id { - return cipherSuite - } - } - return nil -} - -func mutualCipherSuiteTLS13(have []uint16, want uint16) *cipherSuiteTLS13 { - for _, id := range have { - if id == want { - return cipherSuiteTLS13ByID(id) - } - } - return nil -} - -func cipherSuiteTLS13ByID(id uint16) *cipherSuiteTLS13 { - for _, cipherSuite := range cipherSuitesTLS13 { - if cipherSuite.id == id { - return cipherSuite - } - } - return nil -} - -// A list of cipher suite IDs that are, or have been, implemented by this -// package. -// -// See https://www.iana.org/assignments/tls-parameters/tls-parameters.xml -const ( - // TLS 1.0 - 1.2 cipher suites. - TLS_RSA_WITH_RC4_128_SHA uint16 = 0x0005 - TLS_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0x000a - TLS_RSA_WITH_AES_128_CBC_SHA uint16 = 0x002f - TLS_RSA_WITH_AES_256_CBC_SHA uint16 = 0x0035 - TLS_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0x003c - TLS_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0x009c - TLS_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0x009d - TLS_ECDHE_ECDSA_WITH_RC4_128_SHA uint16 = 0xc007 - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA uint16 = 0xc009 - TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA uint16 = 0xc00a - TLS_ECDHE_RSA_WITH_RC4_128_SHA uint16 = 0xc011 - TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0xc012 - TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA uint16 = 0xc013 - TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA uint16 = 0xc014 - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 uint16 = 0xc023 - TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0xc027 - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0xc02f - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 uint16 = 0xc02b - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0xc030 - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 uint16 = 0xc02c - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xcca8 - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xcca9 - - // TLS 1.3 cipher suites. - TLS_AES_128_GCM_SHA256 uint16 = 0x1301 - TLS_AES_256_GCM_SHA384 uint16 = 0x1302 - TLS_CHACHA20_POLY1305_SHA256 uint16 = 0x1303 - - // TLS_FALLBACK_SCSV isn't a standard cipher suite but an indicator - // that the client is doing version fallback. See RFC 7507. - TLS_FALLBACK_SCSV uint16 = 0x5600 - - // Legacy names for the corresponding cipher suites with the correct _SHA256 - // suffix, retained for backward compatibility. - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305 = TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 = TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 -) diff --git a/transport/cloudflaretls/common.go b/transport/cloudflaretls/common.go deleted file mode 100644 index 09d023f5..00000000 --- a/transport/cloudflaretls/common.go +++ /dev/null @@ -1,1668 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package tls - -import ( - "bytes" - "container/list" - "context" - "crypto" - "crypto/ecdsa" - "crypto/ed25519" - "crypto/elliptic" - "crypto/rand" - "crypto/rsa" - "crypto/sha512" - "crypto/x509" - "errors" - "fmt" - "io" - "net" - "strings" - "sync" - "time" -) - -const ( - VersionTLS10 = 0x0301 - VersionTLS11 = 0x0302 - VersionTLS12 = 0x0303 - VersionTLS13 = 0x0304 - - // Deprecated: SSLv3 is cryptographically broken, and is no longer - // supported by this package. See golang.org/issue/32716. - VersionSSL30 = 0x0300 -) - -const ( - maxPlaintext = 16384 // maximum plaintext payload length - maxCiphertext = 16384 + 2048 // maximum ciphertext payload length - maxCiphertextTLS13 = 16384 + 256 // maximum ciphertext length in TLS 1.3 - recordHeaderLen = 5 // record header length - maxHandshake = 65536 // maximum handshake we support (protocol max is 16 MB) - maxUselessRecords = 16 // maximum number of consecutive non-advancing records -) - -// TLS record types. -type recordType uint8 - -const ( - recordTypeChangeCipherSpec recordType = 20 - recordTypeAlert recordType = 21 - recordTypeHandshake recordType = 22 - recordTypeApplicationData recordType = 23 -) - -// TLS handshake message types. -const ( - typeHelloRequest uint8 = 0 - typeClientHello uint8 = 1 - typeServerHello uint8 = 2 - typeNewSessionTicket uint8 = 4 - typeEndOfEarlyData uint8 = 5 - typeEncryptedExtensions uint8 = 8 - typeCertificate uint8 = 11 - typeServerKeyExchange uint8 = 12 - typeCertificateRequest uint8 = 13 - typeServerHelloDone uint8 = 14 - typeCertificateVerify uint8 = 15 - typeClientKeyExchange uint8 = 16 - typeFinished uint8 = 20 - typeCertificateStatus uint8 = 22 - typeKeyUpdate uint8 = 24 - typeNextProtocol uint8 = 67 // Not IANA assigned - typeMessageHash uint8 = 254 // synthetic message -) - -// TLS compression types. -const ( - compressionNone uint8 = 0 -) - -// TLS extension numbers -const ( - extensionServerName uint16 = 0 - extensionStatusRequest uint16 = 5 - extensionSupportedCurves uint16 = 10 // supported_groups in TLS 1.3, see RFC 8446, Section 4.2.7 - extensionSupportedPoints uint16 = 11 - extensionSignatureAlgorithms uint16 = 13 - extensionALPN uint16 = 16 - extensionSCT uint16 = 18 - extensionDelegatedCredentials uint16 = 34 - extensionSessionTicket uint16 = 35 - extensionPreSharedKey uint16 = 41 - extensionEarlyData uint16 = 42 - extensionSupportedVersions uint16 = 43 - extensionCookie uint16 = 44 - extensionPSKModes uint16 = 45 - extensionCertificateAuthorities uint16 = 47 - extensionSignatureAlgorithmsCert uint16 = 50 - extensionKeyShare uint16 = 51 - extensionRenegotiationInfo uint16 = 0xff01 - extensionECH uint16 = 0xfe0d // draft-ietf-tls-esni-13 - extensionECHOuterExtensions uint16 = 0xfd00 // draft-ietf-tls-esni-13 -) - -// TLS signaling cipher suite values -const ( - scsvRenegotiation uint16 = 0x00ff -) - -// CurveID is the type of a TLS identifier for an elliptic curve. See -// https://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-8. -// -// In TLS 1.3, this type is called NamedGroup, but at this time this library -// only supports Elliptic Curve based groups. See RFC 8446, Section 4.2.7. -type CurveID uint16 - -const ( - CurveP256 CurveID = 23 - CurveP384 CurveID = 24 - CurveP521 CurveID = 25 - X25519 CurveID = 29 -) - -// TLS 1.3 Key Share. See RFC 8446, Section 4.2.8. -type keyShare struct { - group CurveID - data []byte -} - -// TLS 1.3 PSK Key Exchange Modes. See RFC 8446, Section 4.2.9. -const ( - pskModePlain uint8 = 0 - pskModeDHE uint8 = 1 -) - -// TLS 1.3 PSK Identity. Can be a Session Ticket, or a reference to a saved -// session. See RFC 8446, Section 4.2.11. -type pskIdentity struct { - label []byte - obfuscatedTicketAge uint32 -} - -// TLS Elliptic Curve Point Formats -// https://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-9 -const ( - pointFormatUncompressed uint8 = 0 -) - -// TLS CertificateStatusType (RFC 3546) -const ( - statusTypeOCSP uint8 = 1 -) - -// Certificate types (for certificateRequestMsg) -const ( - certTypeRSASign = 1 - certTypeECDSASign = 64 // ECDSA or EdDSA keys, see RFC 8422, Section 3. -) - -// Signature algorithms (for internal signaling use). Starting at 225 to avoid overlap with -// TLS 1.2 codepoints (RFC 5246, Appendix A.4.1), with which these have nothing to do. -const ( - signaturePKCS1v15 uint8 = iota + 225 - signatureRSAPSS - signatureECDSA - signatureEd25519 - signatureEdDilithium3 -) - -// directSigning is a standard Hash value that signals that no pre-hashing -// should be performed, and that the input should be signed directly. It is the -// hash function associated with the Ed25519 signature scheme. -var directSigning crypto.Hash = 0 - -// supportedSignatureAlgorithms contains the signature and hash algorithms that -// the code advertises as supported in a TLS 1.2+ ClientHello and in a TLS 1.2+ -// CertificateRequest. The two fields are merged to match with TLS 1.3. -// Note that in TLS 1.2, the ECDSA algorithms are not constrained to P-256, etc. -var supportedSignatureAlgorithms = []SignatureScheme{ - PSSWithSHA256, - ECDSAWithP256AndSHA256, - Ed25519, - PSSWithSHA384, - PSSWithSHA512, - PKCS1WithSHA256, - PKCS1WithSHA384, - PKCS1WithSHA512, - ECDSAWithP384AndSHA384, - ECDSAWithP521AndSHA512, - PKCS1WithSHA1, - ECDSAWithSHA1, -} - -// supportedSignatureAlgorithmsDC contains the signature and hash algorithms that -// the code advertises as supported in a TLS 1.3 ClientHello and in a TLS 1.3 -// CertificateRequest. This excludes 'rsa_pss_rsae_' algorithms. -var supportedSignatureAlgorithmsDC = []SignatureScheme{ - ECDSAWithP256AndSHA256, - Ed25519, - ECDSAWithP384AndSHA384, - ECDSAWithP521AndSHA512, -} - -// helloRetryRequestRandom is set as the Random value of a ServerHello -// to signal that the message is actually a HelloRetryRequest. -var helloRetryRequestRandom = []byte{ // See RFC 8446, Section 4.1.3. - 0xCF, 0x21, 0xAD, 0x74, 0xE5, 0x9A, 0x61, 0x11, - 0xBE, 0x1D, 0x8C, 0x02, 0x1E, 0x65, 0xB8, 0x91, - 0xC2, 0xA2, 0x11, 0x16, 0x7A, 0xBB, 0x8C, 0x5E, - 0x07, 0x9E, 0x09, 0xE2, 0xC8, 0xA8, 0x33, 0x9C, -} - -const ( - // downgradeCanaryTLS12 or downgradeCanaryTLS11 is embedded in the server - // random as a downgrade protection if the server would be capable of - // negotiating a higher version. See RFC 8446, Section 4.1.3. - downgradeCanaryTLS12 = "DOWNGRD\x01" - downgradeCanaryTLS11 = "DOWNGRD\x00" -) - -// testingOnlyForceDowngradeCanary is set in tests to force the server side to -// include downgrade canaries even if it's using its highers supported version. -var testingOnlyForceDowngradeCanary bool - -// testingTriggerHRR causes the server to intentionally trigger a -// HelloRetryRequest (HRR). This is useful for testing new TLS features that -// change the HRR codepath. -var testingTriggerHRR bool - -// testingECHTriggerBypassAfterHRR causes the client to bypass ECH after HRR. -// If available, the client will offer ECH in the first CH only. -var testingECHTriggerBypassAfterHRR bool - -// testingECHTriggerBypassBeforeHRR causes the client to bypass ECH before HRR. -// The client will offer ECH in the second CH only. -var testingECHTriggerBypassBeforeHRR bool - -// testingECHIllegalHandleAfterHRR causes the client to illegally change the ECH -// extension after HRR. -var testingECHIllegalHandleAfterHRR bool - -// testingECHTriggerPayloadDecryptError causes the client to to send an -// inauthentic payload. -var testingECHTriggerPayloadDecryptError bool - -// testingECHOuterExtMany causes a client to incorporate a sequence of -// outer extensions into the ClientHelloInner when it offers the ECH extension. -// The "key_share" extension is the only incorporated extension by default. -var testingECHOuterExtMany bool - -// testingECHOuterExtNone causes a client to not use the "outer_extension" -// mechanism for ECH. The "key_shares" extension is incorporated by default. -var testingECHOuterExtNone bool - -// testingECHOuterExtIncorrectOrder causes the client to send the -// "outer_extension" extension in the wrong order when offering the ECH -// extension. -var testingECHOuterExtIncorrectOrder bool - -// testingECHOuterExtIllegal causes the client to send in its -// "outer_extension" extension the codepoint for the ECH extension. -var testingECHOuterExtIllegal bool - -// ConnectionState records basic TLS details about the connection. -type ConnectionState struct { - // Version is the TLS version used by the connection (e.g. VersionTLS12). - Version uint16 - - // HandshakeComplete is true if the handshake has concluded. - HandshakeComplete bool - - // DidResume is true if this connection was successfully resumed from a - // previous session with a session ticket or similar mechanism. - DidResume bool - - // CipherSuite is the cipher suite negotiated for the connection (e.g. - // TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_AES_128_GCM_SHA256). - CipherSuite uint16 - - // NegotiatedProtocol is the application protocol negotiated with ALPN. - NegotiatedProtocol string - - // NegotiatedProtocolIsMutual used to indicate a mutual NPN negotiation. - // - // Deprecated: this value is always true. - NegotiatedProtocolIsMutual bool - - // ServerName is the value of the Server Name Indication extension sent by - // the client. It's available both on the server and on the client side. - ServerName string - - // PeerCertificates are the parsed certificates sent by the peer, in the - // order in which they were sent. The first element is the leaf certificate - // that the connection is verified against. - // - // On the client side, it can't be empty. On the server side, it can be - // empty if Config.ClientAuth is not RequireAnyClientCert or - // RequireAndVerifyClientCert. - PeerCertificates []*x509.Certificate - - // VerifiedChains is a list of one or more chains where the first element is - // PeerCertificates[0] and the last element is from Config.RootCAs (on the - // client side) or Config.ClientCAs (on the server side). - // - // On the client side, it's set if Config.InsecureSkipVerify is false. On - // the server side, it's set if Config.ClientAuth is VerifyClientCertIfGiven - // (and the peer provided a certificate) or RequireAndVerifyClientCert. - VerifiedChains [][]*x509.Certificate - - // VerifiedDC indicates that the Delegated Credential sent by the peer (if advertised - // and correctly processed), which has been verified against the leaf certificate, - // has been used. - VerifiedDC bool - - // SignedCertificateTimestamps is a list of SCTs provided by the peer - // through the TLS handshake for the leaf certificate, if any. - SignedCertificateTimestamps [][]byte - - // OCSPResponse is a stapled Online Certificate Status Protocol (OCSP) - // response provided by the peer for the leaf certificate, if any. - OCSPResponse []byte - - // TLSUnique contains the "tls-unique" channel binding value (see RFC 5929, - // Section 3). This value will be nil for TLS 1.3 connections and for all - // resumed connections. - // - // Deprecated: there are conditions in which this value might not be unique - // to a connection. See the Security Considerations sections of RFC 5705 and - // RFC 7627, and https://mitls.org/pages/attacks/3SHAKE#channelbindings. - TLSUnique []byte - - // ECHAccepted is set if the ECH extension was offered by the client and - // accepted by the server. - ECHAccepted bool - - // ECHOffered is set if the ECH extension is present in the ClientHello. - // This means the client has offered ECH or sent GREASE ECH. - ECHOffered bool - - // CFControl is used to pass additional TLS configuration information to - // HTTP requests. - // - // NOTE: This feature is used to implement Cloudflare-internal features. - // This feature is unstable and applications MUST NOT depend on it. - CFControl interface{} - - // ekm is a closure exposed via ExportKeyingMaterial. - ekm func(label string, context []byte, length int) ([]byte, error) -} - -// ExportKeyingMaterial returns length bytes of exported key material in a new -// slice as defined in RFC 5705. If context is nil, it is not used as part of -// the seed. If the connection was set to allow renegotiation via -// Config.Renegotiation, this function will return an error. -func (cs *ConnectionState) ExportKeyingMaterial(label string, context []byte, length int) ([]byte, error) { - return cs.ekm(label, context, length) -} - -// ClientAuthType declares the policy the server will follow for -// TLS Client Authentication. -type ClientAuthType int - -const ( - // NoClientCert indicates that no client certificate should be requested - // during the handshake, and if any certificates are sent they will not - // be verified. - NoClientCert ClientAuthType = iota - // RequestClientCert indicates that a client certificate should be requested - // during the handshake, but does not require that the client send any - // certificates. - RequestClientCert - // RequireAnyClientCert indicates that a client certificate should be requested - // during the handshake, and that at least one certificate is required to be - // sent by the client, but that certificate is not required to be valid. - RequireAnyClientCert - // VerifyClientCertIfGiven indicates that a client certificate should be requested - // during the handshake, but does not require that the client sends a - // certificate. If the client does send a certificate it is required to be - // valid. - VerifyClientCertIfGiven - // RequireAndVerifyClientCert indicates that a client certificate should be requested - // during the handshake, and that at least one valid certificate is required - // to be sent by the client. - RequireAndVerifyClientCert -) - -// requiresClientCert reports whether the ClientAuthType requires a client -// certificate to be provided. -func requiresClientCert(c ClientAuthType) bool { - switch c { - case RequireAnyClientCert, RequireAndVerifyClientCert: - return true - default: - return false - } -} - -// ClientSessionState contains the state needed by clients to resume TLS -// sessions. -type ClientSessionState struct { - sessionTicket []uint8 // Encrypted ticket used for session resumption with server - vers uint16 // TLS version negotiated for the session - cipherSuite uint16 // Ciphersuite negotiated for the session - masterSecret []byte // Full handshake MasterSecret, or TLS 1.3 resumption_master_secret - serverCertificates []*x509.Certificate // Certificate chain presented by the server - verifiedChains [][]*x509.Certificate // Certificate chains we built for verification - receivedAt time.Time // When the session ticket was received from the server - ocspResponse []byte // Stapled OCSP response presented by the server - scts [][]byte // SCTs presented by the server - - // TLS 1.3 fields. - nonce []byte // Ticket nonce sent by the server, to derive PSK - useBy time.Time // Expiration of the ticket lifetime as set by the server - ageAdd uint32 // Random obfuscation factor for sending the ticket age -} - -// ClientSessionCache is a cache of ClientSessionState objects that can be used -// by a client to resume a TLS session with a given server. ClientSessionCache -// implementations should expect to be called concurrently from different -// goroutines. Up to TLS 1.2, only ticket-based resumption is supported, not -// SessionID-based resumption. In TLS 1.3 they were merged into PSK modes, which -// are supported via this interface. -type ClientSessionCache interface { - // Get searches for a ClientSessionState associated with the given key. - // On return, ok is true if one was found. - Get(sessionKey string) (session *ClientSessionState, ok bool) - - // Put adds the ClientSessionState to the cache with the given key. It might - // get called multiple times in a connection if a TLS 1.3 server provides - // more than one session ticket. If called with a nil *ClientSessionState, - // it should remove the cache entry. - Put(sessionKey string, cs *ClientSessionState) -} - -//go:generate stringer -type=SignatureScheme,CurveID,ClientAuthType -output=common_string.go - -// SignatureScheme identifies a signature algorithm supported by TLS. See -// RFC 8446, Section 4.2.3. -type SignatureScheme uint16 - -const ( - // RSASSA-PKCS1-v1_5 algorithms. - PKCS1WithSHA256 SignatureScheme = 0x0401 - PKCS1WithSHA384 SignatureScheme = 0x0501 - PKCS1WithSHA512 SignatureScheme = 0x0601 - - // RSASSA-PSS algorithms with public key OID rsaEncryption. - PSSWithSHA256 SignatureScheme = 0x0804 - PSSWithSHA384 SignatureScheme = 0x0805 - PSSWithSHA512 SignatureScheme = 0x0806 - - // ECDSA algorithms. Only constrained to a specific curve in TLS 1.3. - ECDSAWithP256AndSHA256 SignatureScheme = 0x0403 - ECDSAWithP384AndSHA384 SignatureScheme = 0x0503 - ECDSAWithP521AndSHA512 SignatureScheme = 0x0603 - - // EdDSA algorithms. - Ed25519 SignatureScheme = 0x0807 - - // Legacy signature and hash algorithms for TLS 1.2. - PKCS1WithSHA1 SignatureScheme = 0x0201 - ECDSAWithSHA1 SignatureScheme = 0x0203 -) - -// ClientHelloInfo contains information from a ClientHello message in order to -// guide application logic in the GetCertificate and GetConfigForClient callbacks. -type ClientHelloInfo struct { - // CipherSuites lists the CipherSuites supported by the client (e.g. - // TLS_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256). - CipherSuites []uint16 - - // ServerName indicates the name of the server requested by the client - // in order to support virtual hosting. ServerName is only set if the - // client is using SNI (see RFC 4366, Section 3.1). - ServerName string - - // SupportedCurves lists the elliptic curves supported by the client. - // SupportedCurves is set only if the Supported Elliptic Curves - // Extension is being used (see RFC 4492, Section 5.1.1). - SupportedCurves []CurveID - - // SupportedPoints lists the point formats supported by the client. - // SupportedPoints is set only if the Supported Point Formats Extension - // is being used (see RFC 4492, Section 5.1.2). - SupportedPoints []uint8 - - // SignatureSchemes lists the signature and hash schemes that the client - // is willing to verify. SignatureSchemes is set only if the Signature - // Algorithms Extension is being used (see RFC 5246, Section 7.4.1.4.1). - SignatureSchemes []SignatureScheme - - // SignatureSchemesDC lists the signature schemes that the client - // is willing to verify when using Delegated Credentials. - // This is and can be different from SignatureSchemes. SignatureSchemesDC - // is set only if the DelegatedCredentials Extension is being used. - // If Delegated Credentials are supported, this list should not be nil. - SignatureSchemesDC []SignatureScheme - - // SupportedProtos lists the application protocols supported by the client. - // SupportedProtos is set only if the Application-Layer Protocol - // Negotiation Extension is being used (see RFC 7301, Section 3.1). - // - // Servers can select a protocol by setting Config.NextProtos in a - // GetConfigForClient return value. - SupportedProtos []string - - // SupportedVersions lists the TLS versions supported by the client. - // For TLS versions less than 1.3, this is extrapolated from the max - // version advertised by the client, so values other than the greatest - // might be rejected if used. - SupportedVersions []uint16 - - // SupportDelegatedCredential is true if the client indicated willingness - // to negotiate the Delegated Credential extension. - SupportsDelegatedCredential bool - - // Conn is the underlying net.Conn for the connection. Do not read - // from, or write to, this connection; that will cause the TLS - // connection to fail. - Conn net.Conn - - // config is embedded by the GetCertificate or GetConfigForClient caller, - // for use with SupportsCertificate. - config *Config - - // ctx is the context of the handshake that is in progress. - ctx context.Context -} - -// Context returns the context of the handshake that is in progress. -// This context is a child of the context passed to HandshakeContext, -// if any, and is canceled when the handshake concludes. -func (c *ClientHelloInfo) Context() context.Context { - return c.ctx -} - -// CertificateRequestInfo contains information from a server's -// CertificateRequest message, which is used to demand a certificate and proof -// of control from a client. -type CertificateRequestInfo struct { - // AcceptableCAs contains zero or more, DER-encoded, X.501 - // Distinguished Names. These are the names of root or intermediate CAs - // that the server wishes the returned certificate to be signed by. An - // empty slice indicates that the server has no preference. - AcceptableCAs [][]byte - - // SupportDelegatedCredential is true if the server indicated willingness - // to negotiate the Delegated Credential extension. - SupportsDelegatedCredential bool - - // SignatureSchemes lists the signature schemes that the server is - // willing to verify. - SignatureSchemes []SignatureScheme - - // SignatureSchemesDC lists the signature schemes that the server - // is willing to verify when using Delegated Credentials. - // This is and can be different from SignatureSchemes. SignatureSchemesDC - // is set only if the DelegatedCredentials Extension is being used. - // If Delegated Credentials are supported, this list should not be nil. - SignatureSchemesDC []SignatureScheme - - // Version is the TLS version that was negotiated for this connection. - Version uint16 - - // ctx is the context of the handshake that is in progress. - ctx context.Context -} - -// Context returns the context of the handshake that is in progress. -// This context is a child of the context passed to HandshakeContext, -// if any, and is canceled when the handshake concludes. -func (c *CertificateRequestInfo) Context() context.Context { - return c.ctx -} - -// RenegotiationSupport enumerates the different levels of support for TLS -// renegotiation. TLS renegotiation is the act of performing subsequent -// handshakes on a connection after the first. This significantly complicates -// the state machine and has been the source of numerous, subtle security -// issues. Initiating a renegotiation is not supported, but support for -// accepting renegotiation requests may be enabled. -// -// Even when enabled, the server may not change its identity between handshakes -// (i.e. the leaf certificate must be the same). Additionally, concurrent -// handshake and application data flow is not permitted so renegotiation can -// only be used with protocols that synchronise with the renegotiation, such as -// HTTPS. -// -// Renegotiation is not defined in TLS 1.3. -type RenegotiationSupport int - -const ( - // RenegotiateNever disables renegotiation. - RenegotiateNever RenegotiationSupport = iota - - // RenegotiateOnceAsClient allows a remote server to request - // renegotiation once per connection. - RenegotiateOnceAsClient - - // RenegotiateFreelyAsClient allows a remote server to repeatedly - // request renegotiation. - RenegotiateFreelyAsClient -) - -// A Config structure is used to configure a TLS client or server. -// After one has been passed to a TLS function it must not be -// modified. A Config may be reused; the tls package will also not -// modify it. -type Config struct { - // Rand provides the source of entropy for nonces and RSA blinding. - // If Rand is nil, TLS uses the cryptographic random reader in package - // crypto/rand. - // The Reader must be safe for use by multiple goroutines. - Rand io.Reader - - // Time returns the current time as the number of seconds since the epoch. - // If Time is nil, TLS uses time.Now. - Time func() time.Time - - // Certificates contains one or more certificate chains to present to the - // other side of the connection. The first certificate compatible with the - // peer's requirements is selected automatically. - // - // Server configurations must set one of Certificates, GetCertificate or - // GetConfigForClient. Clients doing client-authentication may set either - // Certificates or GetClientCertificate. - // - // Note: if there are multiple Certificates, and they don't have the - // optional field Leaf set, certificate selection will incur a significant - // per-handshake performance cost. - Certificates []Certificate - - // NameToCertificate maps from a certificate name to an element of - // Certificates. Note that a certificate name can be of the form - // '*.example.com' and so doesn't have to be a domain name as such. - // - // Deprecated: NameToCertificate only allows associating a single - // certificate with a given name. Leave this field nil to let the library - // select the first compatible chain from Certificates. - NameToCertificate map[string]*Certificate - - // GetCertificate returns a Certificate based on the given - // ClientHelloInfo. It will only be called if the client supplies SNI - // information or if Certificates is empty. - // - // If GetCertificate is nil or returns nil, then the certificate is - // retrieved from NameToCertificate. If NameToCertificate is nil, the - // best element of Certificates will be used. - GetCertificate func(*ClientHelloInfo) (*Certificate, error) - - // GetClientCertificate, if not nil, is called when a server requests a - // certificate from a client. If set, the contents of Certificates will - // be ignored. - // - // If GetClientCertificate returns an error, the handshake will be - // aborted and that error will be returned. Otherwise - // GetClientCertificate must return a non-nil Certificate. If - // Certificate.Certificate is empty then no certificate will be sent to - // the server. If this is unacceptable to the server then it may abort - // the handshake. - // - // GetClientCertificate may be called multiple times for the same - // connection if renegotiation occurs or if TLS 1.3 is in use. - GetClientCertificate func(*CertificateRequestInfo) (*Certificate, error) - - // GetConfigForClient, if not nil, is called after a ClientHello is - // received from a client. It may return a non-nil Config in order to - // change the Config that will be used to handle this connection. If - // the returned Config is nil, the original Config will be used. The - // Config returned by this callback may not be subsequently modified. - // - // If GetConfigForClient is nil, the Config passed to Server() will be - // used for all connections. - // - // If SessionTicketKey was explicitly set on the returned Config, or if - // SetSessionTicketKeys was called on the returned Config, those keys will - // be used. Otherwise, the original Config keys will be used (and possibly - // rotated if they are automatically managed). - GetConfigForClient func(*ClientHelloInfo) (*Config, error) - - // VerifyPeerCertificate, if not nil, is called after normal - // certificate verification by either a TLS client or server. It - // receives the raw ASN.1 certificates provided by the peer and also - // any verified chains that normal processing found. If it returns a - // non-nil error, the handshake is aborted and that error results. - // - // If normal verification fails then the handshake will abort before - // considering this callback. If normal verification is disabled by - // setting InsecureSkipVerify, or (for a server) when ClientAuth is - // RequestClientCert or RequireAnyClientCert, then this callback will - // be considered but the verifiedChains argument will always be nil. - VerifyPeerCertificate func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error - - // VerifyConnection, if not nil, is called after normal certificate - // verification and after VerifyPeerCertificate by either a TLS client - // or server. If it returns a non-nil error, the handshake is aborted - // and that error results. - // - // If normal verification fails then the handshake will abort before - // considering this callback. This callback will run for all connections - // regardless of InsecureSkipVerify or ClientAuth settings. - VerifyConnection func(ConnectionState) error - - // RootCAs defines the set of root certificate authorities - // that clients use when verifying server certificates. - // If RootCAs is nil, TLS uses the host's root CA set. - RootCAs *x509.CertPool - - // NextProtos is a list of supported application level protocols, in - // order of preference. If both peers support ALPN, the selected - // protocol will be one from this list, and the connection will fail - // if there is no mutually supported protocol. If NextProtos is empty - // or the peer doesn't support ALPN, the connection will succeed and - // ConnectionState.NegotiatedProtocol will be empty. - NextProtos []string - - // ServerName is used to verify the hostname on the returned - // certificates unless InsecureSkipVerify is given. It is also included - // in the client's handshake to support virtual hosting unless it is - // an IP address. - ServerName string - - // ClientAuth determines the server's policy for - // TLS Client Authentication. The default is NoClientCert. - ClientAuth ClientAuthType - - // ClientCAs defines the set of root certificate authorities - // that servers use if required to verify a client certificate - // by the policy in ClientAuth. - ClientCAs *x509.CertPool - - // InsecureSkipVerify controls whether a client verifies the server's - // certificate chain and host name. If InsecureSkipVerify is true, crypto/tls - // accepts any certificate presented by the server and any host name in that - // certificate. In this mode, TLS is susceptible to machine-in-the-middle - // attacks unless custom verification is used. This should be used only for - // testing or in combination with VerifyConnection or VerifyPeerCertificate. - InsecureSkipVerify bool - - // CipherSuites is a list of enabled TLS 1.0–1.2 cipher suites. The order of - // the list is ignored. Note that TLS 1.3 ciphersuites are not configurable. - // - // If CipherSuites is nil, a safe default list is used. The default cipher - // suites might change over time. - CipherSuites []uint16 - - // PreferServerCipherSuites is a legacy field and has no effect. - // - // It used to control whether the server would follow the client's or the - // server's preference. Servers now select the best mutually supported - // cipher suite based on logic that takes into account inferred client - // hardware, server hardware, and security. - // - // Deprecated: PreferServerCipherSuites is ignored. - PreferServerCipherSuites bool - - // SessionTicketsDisabled may be set to true to disable session ticket and - // PSK (resumption) support. Note that on clients, session ticket support is - // also disabled if ClientSessionCache is nil. On clients or servers, - // support is disabled if the ECH extension is enabled. - SessionTicketsDisabled bool - - // SessionTicketKey is used by TLS servers to provide session resumption. - // See RFC 5077 and the PSK mode of RFC 8446. If zero, it will be filled - // with random data before the first server handshake. - // - // Deprecated: if this field is left at zero, session ticket keys will be - // automatically rotated every day and dropped after seven days. For - // customizing the rotation schedule or synchronizing servers that are - // terminating connections for the same host, use SetSessionTicketKeys. - SessionTicketKey [32]byte - - // ClientSessionCache is a cache of ClientSessionState entries for TLS - // session resumption. It is only used by clients. - ClientSessionCache ClientSessionCache - - // MinVersion contains the minimum TLS version that is acceptable. - // - // By default, TLS 1.2 is currently used as the minimum when acting as a - // client, and TLS 1.0 when acting as a server. TLS 1.0 is the minimum - // supported by this package, both as a client and as a server. - // - // The client-side default can temporarily be reverted to TLS 1.0 by - // including the value "x509sha1=1" in the GODEBUG environment variable. - // Note that this option will be removed in Go 1.19 (but it will still be - // possible to set this field to VersionTLS10 explicitly). - MinVersion uint16 - - // MaxVersion contains the maximum TLS version that is acceptable. - // - // By default, the maximum version supported by this package is used, - // which is currently TLS 1.3. - MaxVersion uint16 - - // CurvePreferences contains the elliptic curves that will be used in - // an ECDHE handshake, in preference order. If empty, the default will - // be used. The client will use the first preference as the type for - // its key share in TLS 1.3. This may change in the future. - CurvePreferences []CurveID - - // PQSignatureSchemesEnabled controls whether additional post-quantum - // signature schemes are supported for peer certificates. For available - // signature schemes, see tls_cf.go. - PQSignatureSchemesEnabled bool - - // DynamicRecordSizingDisabled disables adaptive sizing of TLS records. - // When true, the largest possible TLS record size is always used. When - // false, the size of TLS records may be adjusted in an attempt to - // improve latency. - DynamicRecordSizingDisabled bool - - // Renegotiation controls what types of renegotiation are supported. - // The default, none, is correct for the vast majority of applications. - Renegotiation RenegotiationSupport - - // KeyLogWriter optionally specifies a destination for TLS master secrets - // in NSS key log format that can be used to allow external programs - // such as Wireshark to decrypt TLS connections. - // See https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format. - // Use of KeyLogWriter compromises security and should only be - // used for debugging. - KeyLogWriter io.Writer - - // ECHEnabled determines whether the ECH extension is enabled for this - // connection. - ECHEnabled bool - - // ClientECHConfigs are the parameters used by the client when it offers the - // ECH extension. If ECH is enabled, a suitable configuration is found, and - // the client supports TLS 1.3, then it will offer ECH in this handshake. - // Otherwise, if ECH is enabled, it will send a dummy ECH extension. - ClientECHConfigs []ECHConfig - - GetClientECHConfigs func(ctx context.Context, serverName string) ([]ECHConfig, error) - - // ServerECHProvider is the ECH provider used by the client-facing server - // for the ECH extension. If the client offers ECH and TLS 1.3 is - // negotiated, then the provider is used to compute the HPKE context - // (draft-irtf-cfrg-hpke-07), which in turn is used to decrypt the extension - // payload. - ServerECHProvider ECHProvider - - // CFEventHandler, if set, is called by the client and server at various - // points during the handshake to handle specific events. This is used - // primarily for collecting metrics. - // - // NOTE: This feature is used to implement Cloudflare-internal features. - // This feature is unstable and applications MUST NOT depend on it. - CFEventHandler func(event CFEvent) - - // CFControl is used to pass additional TLS configuration information to - // HTTP requests via ConnectionState. - // - // NOTE: This feature is used to implement Cloudflare-internal features. - // This feature is unstable and applications MUST NOT depend on it. - CFControl interface{} - - // SupportDelegatedCredential is true if the client or server is willing - // to negotiate the delegated credential extension. - // This can only be used with TLS 1.3. - // - // See https://tools.ietf.org/html/draft-ietf-tls-subcerts. - SupportDelegatedCredential bool - - // mutex protects sessionTicketKeys and autoSessionTicketKeys. - mutex sync.RWMutex - // sessionTicketKeys contains zero or more ticket keys. If set, it means the - // the keys were set with SessionTicketKey or SetSessionTicketKeys. The - // first key is used for new tickets and any subsequent keys can be used to - // decrypt old tickets. The slice contents are not protected by the mutex - // and are immutable. - sessionTicketKeys []ticketKey - // autoSessionTicketKeys is like sessionTicketKeys but is owned by the - // auto-rotation logic. See Config.ticketKeys. - autoSessionTicketKeys []ticketKey -} - -const ( - // ticketKeyNameLen is the number of bytes of identifier that is prepended to - // an encrypted session ticket in order to identify the key used to encrypt it. - ticketKeyNameLen = 16 - - // ticketKeyLifetime is how long a ticket key remains valid and can be used to - // resume a client connection. - ticketKeyLifetime = 7 * 24 * time.Hour // 7 days - - // ticketKeyRotation is how often the server should rotate the session ticket key - // that is used for new tickets. - ticketKeyRotation = 24 * time.Hour -) - -// ticketKey is the internal representation of a session ticket key. -type ticketKey struct { - // keyName is an opaque byte string that serves to identify the session - // ticket key. It's exposed as plaintext in every session ticket. - keyName [ticketKeyNameLen]byte - aesKey [16]byte - hmacKey [16]byte - // created is the time at which this ticket key was created. See Config.ticketKeys. - created time.Time -} - -// ticketKeyFromBytes converts from the external representation of a session -// ticket key to a ticketKey. Externally, session ticket keys are 32 random -// bytes and this function expands that into sufficient name and key material. -func (c *Config) ticketKeyFromBytes(b [32]byte) (key ticketKey) { - hashed := sha512.Sum512(b[:]) - copy(key.keyName[:], hashed[:ticketKeyNameLen]) - copy(key.aesKey[:], hashed[ticketKeyNameLen:ticketKeyNameLen+16]) - copy(key.hmacKey[:], hashed[ticketKeyNameLen+16:ticketKeyNameLen+32]) - key.created = c.time() - return key -} - -// maxSessionTicketLifetime is the maximum allowed lifetime of a TLS 1.3 session -// ticket, and the lifetime we set for tickets we send. -const maxSessionTicketLifetime = 7 * 24 * time.Hour - -// Clone returns a shallow clone of c or nil if c is nil. It is safe to clone a Config that is -// being used concurrently by a TLS client or server. -func (c *Config) Clone() *Config { - if c == nil { - return nil - } - c.mutex.RLock() - defer c.mutex.RUnlock() - return &Config{ - Rand: c.Rand, - Time: c.Time, - Certificates: c.Certificates, - NameToCertificate: c.NameToCertificate, - GetCertificate: c.GetCertificate, - GetClientCertificate: c.GetClientCertificate, - GetConfigForClient: c.GetConfigForClient, - VerifyPeerCertificate: c.VerifyPeerCertificate, - VerifyConnection: c.VerifyConnection, - RootCAs: c.RootCAs, - NextProtos: c.NextProtos, - ServerName: c.ServerName, - ClientAuth: c.ClientAuth, - ClientCAs: c.ClientCAs, - InsecureSkipVerify: c.InsecureSkipVerify, - CipherSuites: c.CipherSuites, - PreferServerCipherSuites: c.PreferServerCipherSuites, - SessionTicketsDisabled: c.SessionTicketsDisabled, - SessionTicketKey: c.SessionTicketKey, - ClientSessionCache: c.ClientSessionCache, - MinVersion: c.MinVersion, - MaxVersion: c.MaxVersion, - CurvePreferences: c.CurvePreferences, - PQSignatureSchemesEnabled: c.PQSignatureSchemesEnabled, - DynamicRecordSizingDisabled: c.DynamicRecordSizingDisabled, - Renegotiation: c.Renegotiation, - KeyLogWriter: c.KeyLogWriter, - SupportDelegatedCredential: c.SupportDelegatedCredential, - ECHEnabled: c.ECHEnabled, - ClientECHConfigs: c.ClientECHConfigs, - ServerECHProvider: c.ServerECHProvider, - CFEventHandler: c.CFEventHandler, - CFControl: c.CFControl, - sessionTicketKeys: c.sessionTicketKeys, - autoSessionTicketKeys: c.autoSessionTicketKeys, - } -} - -// deprecatedSessionTicketKey is set as the prefix of SessionTicketKey if it was -// randomized for backwards compatibility but is not in use. -var deprecatedSessionTicketKey = []byte("DEPRECATED") - -// initLegacySessionTicketKeyRLocked ensures the legacy SessionTicketKey field is -// randomized if empty, and that sessionTicketKeys is populated from it otherwise. -func (c *Config) initLegacySessionTicketKeyRLocked() { - // Don't write if SessionTicketKey is already defined as our deprecated string, - // or if it is defined by the user but sessionTicketKeys is already set. - if c.SessionTicketKey != [32]byte{} && - (bytes.HasPrefix(c.SessionTicketKey[:], deprecatedSessionTicketKey) || len(c.sessionTicketKeys) > 0) { - return - } - - // We need to write some data, so get an exclusive lock and re-check any conditions. - c.mutex.RUnlock() - defer c.mutex.RLock() - c.mutex.Lock() - defer c.mutex.Unlock() - if c.SessionTicketKey == [32]byte{} { - if _, err := io.ReadFull(c.rand(), c.SessionTicketKey[:]); err != nil { - panic(fmt.Sprintf("tls: unable to generate random session ticket key: %v", err)) - } - // Write the deprecated prefix at the beginning so we know we created - // it. This key with the DEPRECATED prefix isn't used as an actual - // session ticket key, and is only randomized in case the application - // reuses it for some reason. - copy(c.SessionTicketKey[:], deprecatedSessionTicketKey) - } else if !bytes.HasPrefix(c.SessionTicketKey[:], deprecatedSessionTicketKey) && len(c.sessionTicketKeys) == 0 { - c.sessionTicketKeys = []ticketKey{c.ticketKeyFromBytes(c.SessionTicketKey)} - } -} - -// ticketKeys returns the ticketKeys for this connection. -// If configForClient has explicitly set keys, those will -// be returned. Otherwise, the keys on c will be used and -// may be rotated if auto-managed. -// During rotation, any expired session ticket keys are deleted from -// c.sessionTicketKeys. If the session ticket key that is currently -// encrypting tickets (ie. the first ticketKey in c.sessionTicketKeys) -// is not fresh, then a new session ticket key will be -// created and prepended to c.sessionTicketKeys. -func (c *Config) ticketKeys(configForClient *Config) []ticketKey { - // If the ConfigForClient callback returned a Config with explicitly set - // keys, use those, otherwise just use the original Config. - if configForClient != nil { - configForClient.mutex.RLock() - if configForClient.SessionTicketsDisabled { - return nil - } - configForClient.initLegacySessionTicketKeyRLocked() - if len(configForClient.sessionTicketKeys) != 0 { - ret := configForClient.sessionTicketKeys - configForClient.mutex.RUnlock() - return ret - } - configForClient.mutex.RUnlock() - } - - c.mutex.RLock() - defer c.mutex.RUnlock() - if c.SessionTicketsDisabled { - return nil - } - c.initLegacySessionTicketKeyRLocked() - if len(c.sessionTicketKeys) != 0 { - return c.sessionTicketKeys - } - // Fast path for the common case where the key is fresh enough. - if len(c.autoSessionTicketKeys) > 0 && c.time().Sub(c.autoSessionTicketKeys[0].created) < ticketKeyRotation { - return c.autoSessionTicketKeys - } - - // autoSessionTicketKeys are managed by auto-rotation. - c.mutex.RUnlock() - defer c.mutex.RLock() - c.mutex.Lock() - defer c.mutex.Unlock() - // Re-check the condition in case it changed since obtaining the new lock. - if len(c.autoSessionTicketKeys) == 0 || c.time().Sub(c.autoSessionTicketKeys[0].created) >= ticketKeyRotation { - var newKey [32]byte - if _, err := io.ReadFull(c.rand(), newKey[:]); err != nil { - panic(fmt.Sprintf("unable to generate random session ticket key: %v", err)) - } - valid := make([]ticketKey, 0, len(c.autoSessionTicketKeys)+1) - valid = append(valid, c.ticketKeyFromBytes(newKey)) - for _, k := range c.autoSessionTicketKeys { - // While rotating the current key, also remove any expired ones. - if c.time().Sub(k.created) < ticketKeyLifetime { - valid = append(valid, k) - } - } - c.autoSessionTicketKeys = valid - } - return c.autoSessionTicketKeys -} - -// SetSessionTicketKeys updates the session ticket keys for a server. -// -// The first key will be used when creating new tickets, while all keys can be -// used for decrypting tickets. It is safe to call this function while the -// server is running in order to rotate the session ticket keys. The function -// will panic if keys is empty. -// -// Calling this function will turn off automatic session ticket key rotation. -// -// If multiple servers are terminating connections for the same host they should -// all have the same session ticket keys. If the session ticket keys leaks, -// previously recorded and future TLS connections using those keys might be -// compromised. -func (c *Config) SetSessionTicketKeys(keys [][32]byte) { - if len(keys) == 0 { - panic("tls: keys must have at least one key") - } - - newKeys := make([]ticketKey, len(keys)) - for i, bytes := range keys { - newKeys[i] = c.ticketKeyFromBytes(bytes) - } - - c.mutex.Lock() - c.sessionTicketKeys = newKeys - c.mutex.Unlock() -} - -func (c *Config) rand() io.Reader { - r := c.Rand - if r == nil { - return rand.Reader - } - return r -} - -func (c *Config) time() time.Time { - t := c.Time - if t == nil { - t = time.Now - } - return t() -} - -func (c *Config) cipherSuites() []uint16 { - if c.CipherSuites != nil { - return c.CipherSuites - } - return defaultCipherSuites -} - -var supportedVersions = []uint16{ - VersionTLS13, - VersionTLS12, - VersionTLS11, - VersionTLS10, -} - -// debugEnableTLS10 enables TLS 1.0. See issue 45428. -var debugEnableTLS10 = false - -// roleClient and roleServer are meant to call supportedVersions and parents -// with more readability at the callsite. -const roleClient = true -const roleServer = false - -func (c *Config) supportedVersions(isClient bool) []uint16 { - versions := make([]uint16, 0, len(supportedVersions)) - for _, v := range supportedVersions { - if (c == nil || c.MinVersion == 0) && !debugEnableTLS10 && - isClient && v < VersionTLS12 { - continue - } - if c != nil && c.MinVersion != 0 && v < c.MinVersion { - continue - } - if c != nil && c.MaxVersion != 0 && v > c.MaxVersion { - continue - } - versions = append(versions, v) - } - return versions -} - -func (c *Config) supportedVersionsFromMin(isClient bool, minVersion uint16) []uint16 { - versions := make([]uint16, 0, len(supportedVersions)) - for _, v := range supportedVersions { - if (c == nil || c.MinVersion == 0) && !debugEnableTLS10 && - isClient && v < VersionTLS12 { - continue - } - if c != nil && c.MinVersion != 0 && v < c.MinVersion { - continue - } - if c != nil && c.MaxVersion != 0 && v > c.MaxVersion { - continue - } - if v < minVersion { - continue - } - versions = append(versions, v) - } - return versions -} - -func (c *Config) maxSupportedVersion(isClient bool) uint16 { - supportedVersions := c.supportedVersions(isClient) - if len(supportedVersions) == 0 { - return 0 - } - return supportedVersions[0] -} - -// supportedVersionsFromMax returns a list of supported versions derived from a -// legacy maximum version value. Note that only versions supported by this -// library are returned. Any newer peer will use supportedVersions anyway. -func supportedVersionsFromMax(maxVersion uint16) []uint16 { - versions := make([]uint16, 0, len(supportedVersions)) - for _, v := range supportedVersions { - if v > maxVersion { - continue - } - versions = append(versions, v) - } - return versions -} - -var defaultCurvePreferences = []CurveID{X25519, CurveP256, CurveP384, CurveP521} - -func (c *Config) curvePreferences() []CurveID { - if c == nil || len(c.CurvePreferences) == 0 { - return defaultCurvePreferences - } - return c.CurvePreferences -} - -func (c *Config) supportsCurve(curve CurveID) bool { - for _, cc := range c.curvePreferences() { - if cc == curve { - return true - } - } - return false -} - -// mutualVersion returns the protocol version to use given the advertised -// versions of the peer. Priority is given to the peer preference order. -func (c *Config) mutualVersion(isClient bool, peerVersions []uint16) (uint16, bool) { - supportedVersions := c.supportedVersions(isClient) - for _, peerVersion := range peerVersions { - for _, v := range supportedVersions { - if v == peerVersion { - return v, true - } - } - } - return 0, false -} - -var errNoCertificates = errors.New("tls: no certificates configured") - -// getCertificate returns the best certificate for the given ClientHelloInfo, -// defaulting to the first element of c.Certificates. -func (c *Config) getCertificate(clientHello *ClientHelloInfo) (*Certificate, error) { - if c.GetCertificate != nil && - (len(c.Certificates) == 0 || len(clientHello.ServerName) > 0) { - cert, err := c.GetCertificate(clientHello) - if cert != nil || err != nil { - return cert, err - } - } - - if len(c.Certificates) == 0 { - return nil, errNoCertificates - } - - if len(c.Certificates) == 1 { - // There's only one choice, so no point doing any work. - return &c.Certificates[0], nil - } - - if c.NameToCertificate != nil { - name := strings.ToLower(clientHello.ServerName) - if cert, ok := c.NameToCertificate[name]; ok { - return cert, nil - } - if len(name) > 0 { - labels := strings.Split(name, ".") - labels[0] = "*" - wildcardName := strings.Join(labels, ".") - if cert, ok := c.NameToCertificate[wildcardName]; ok { - return cert, nil - } - } - } - - for _, cert := range c.Certificates { - if err := clientHello.SupportsCertificate(&cert); err == nil { - return &cert, nil - } - } - - // If nothing matches, return the first certificate. - return &c.Certificates[0], nil -} - -// SupportsCertificate returns nil if the provided certificate is supported by -// the client that sent the ClientHello. Otherwise, it returns an error -// describing the reason for the incompatibility. -// -// If this ClientHelloInfo was passed to a GetConfigForClient or GetCertificate -// callback, this method will take into account the associated Config. Note that -// if GetConfigForClient returns a different Config, the change can't be -// accounted for by this method. -// -// This function will call x509.ParseCertificate unless c.Leaf is set, which can -// incur a significant performance cost. -func (chi *ClientHelloInfo) SupportsCertificate(c *Certificate) error { - // Note we don't currently support certificate_authorities nor - // signature_algorithms_cert, and don't check the algorithms of the - // signatures on the chain (which anyway are a SHOULD, see RFC 8446, - // Section 4.4.2.2). - - config := chi.config - if config == nil { - config = &Config{} - } - vers, ok := config.mutualVersion(roleServer, chi.SupportedVersions) - if !ok { - return errors.New("no mutually supported protocol versions") - } - - // If the client specified the name they are trying to connect to, the - // certificate needs to be valid for it. - if chi.ServerName != "" { - x509Cert, err := c.leaf() - if err != nil { - return fmt.Errorf("failed to parse certificate: %w", err) - } - if err := x509Cert.VerifyHostname(chi.ServerName); err != nil { - return fmt.Errorf("certificate is not valid for requested server name: %w", err) - } - } - - // supportsRSAFallback returns nil if the certificate and connection support - // the static RSA key exchange, and unsupported otherwise. The logic for - // supporting static RSA is completely disjoint from the logic for - // supporting signed key exchanges, so we just check it as a fallback. - supportsRSAFallback := func(unsupported error) error { - // TLS 1.3 dropped support for the static RSA key exchange. - if vers == VersionTLS13 { - return unsupported - } - // The static RSA key exchange works by decrypting a challenge with the - // RSA private key, not by signing, so check the PrivateKey implements - // crypto.Decrypter, like *rsa.PrivateKey does. - if priv, ok := c.PrivateKey.(crypto.Decrypter); ok { - if _, ok := priv.Public().(*rsa.PublicKey); !ok { - return unsupported - } - } else { - return unsupported - } - // Finally, there needs to be a mutual cipher suite that uses the static - // RSA key exchange instead of ECDHE. - rsaCipherSuite := selectCipherSuite(chi.CipherSuites, config.cipherSuites(), func(c *cipherSuite) bool { - if c.flags&suiteECDHE != 0 { - return false - } - if vers < VersionTLS12 && c.flags&suiteTLS12 != 0 { - return false - } - return true - }) - if rsaCipherSuite == nil { - return unsupported - } - return nil - } - - // If the client sent the signature_algorithms extension, ensure it supports - // schemes we can use with this certificate and TLS version. - if len(chi.SignatureSchemes) > 0 { - if _, err := selectSignatureScheme(vers, c, chi.SignatureSchemes); err != nil { - return supportsRSAFallback(err) - } - } - - // In TLS 1.3 we are done because supported_groups is only relevant to the - // ECDHE computation, point format negotiation is removed, cipher suites are - // only relevant to the AEAD choice, and static RSA does not exist. - if vers == VersionTLS13 { - return nil - } - - // The only signed key exchange we support is ECDHE. - if !supportsECDHE(config, chi.SupportedCurves, chi.SupportedPoints) { - return supportsRSAFallback(errors.New("client doesn't support ECDHE, can only use legacy RSA key exchange")) - } - - var ecdsaCipherSuite bool - if priv, ok := c.PrivateKey.(crypto.Signer); ok { - switch pub := priv.Public().(type) { - case *ecdsa.PublicKey: - var curve CurveID - switch pub.Curve { - case elliptic.P256(): - curve = CurveP256 - case elliptic.P384(): - curve = CurveP384 - case elliptic.P521(): - curve = CurveP521 - default: - return supportsRSAFallback(unsupportedCertificateError(c)) - } - var curveOk bool - for _, c := range chi.SupportedCurves { - if c == curve && config.supportsCurve(c) { - curveOk = true - break - } - } - if !curveOk { - return errors.New("client doesn't support certificate curve") - } - ecdsaCipherSuite = true - case ed25519.PublicKey: - if vers < VersionTLS12 || len(chi.SignatureSchemes) == 0 { - return errors.New("connection doesn't support Ed25519") - } - ecdsaCipherSuite = true - case *rsa.PublicKey: - default: - return supportsRSAFallback(unsupportedCertificateError(c)) - } - } else { - return supportsRSAFallback(unsupportedCertificateError(c)) - } - - // Make sure that there is a mutually supported cipher suite that works with - // this certificate. Cipher suite selection will then apply the logic in - // reverse to pick it. See also serverHandshakeState.cipherSuiteOk. - cipherSuite := selectCipherSuite(chi.CipherSuites, config.cipherSuites(), func(c *cipherSuite) bool { - if c.flags&suiteECDHE == 0 { - return false - } - if c.flags&suiteECSign != 0 { - if !ecdsaCipherSuite { - return false - } - } else { - if ecdsaCipherSuite { - return false - } - } - if vers < VersionTLS12 && c.flags&suiteTLS12 != 0 { - return false - } - return true - }) - if cipherSuite == nil { - return supportsRSAFallback(errors.New("client doesn't support any cipher suites compatible with the certificate")) - } - - return nil -} - -// SupportsCertificate returns nil if the provided certificate is supported by -// the server that sent the CertificateRequest. Otherwise, it returns an error -// describing the reason for the incompatibility. -func (cri *CertificateRequestInfo) SupportsCertificate(c *Certificate) error { - if _, err := selectSignatureScheme(cri.Version, c, cri.SignatureSchemes); err != nil { - return err - } - - if len(cri.AcceptableCAs) == 0 { - return nil - } - - for j, cert := range c.Certificate { - x509Cert := c.Leaf - // Parse the certificate if this isn't the leaf node, or if - // chain.Leaf was nil. - if j != 0 || x509Cert == nil { - var err error - if x509Cert, err = x509.ParseCertificate(cert); err != nil { - return fmt.Errorf("failed to parse certificate #%d in the chain: %w", j, err) - } - } - - for _, ca := range cri.AcceptableCAs { - if bytes.Equal(x509Cert.RawIssuer, ca) { - return nil - } - } - } - return errors.New("chain is not signed by an acceptable CA") -} - -// BuildNameToCertificate parses c.Certificates and builds c.NameToCertificate -// from the CommonName and SubjectAlternateName fields of each of the leaf -// certificates. -// -// Deprecated: NameToCertificate only allows associating a single certificate -// with a given name. Leave that field nil to let the library select the first -// compatible chain from Certificates. -func (c *Config) BuildNameToCertificate() { - c.NameToCertificate = make(map[string]*Certificate) - for i := range c.Certificates { - cert := &c.Certificates[i] - x509Cert, err := cert.leaf() - if err != nil { - continue - } - // If SANs are *not* present, some clients will consider the certificate - // valid for the name in the Common Name. - if x509Cert.Subject.CommonName != "" && len(x509Cert.DNSNames) == 0 { - c.NameToCertificate[x509Cert.Subject.CommonName] = cert - } - for _, san := range x509Cert.DNSNames { - c.NameToCertificate[san] = cert - } - } -} - -const ( - keyLogLabelTLS12 = "CLIENT_RANDOM" - keyLogLabelClientHandshake = "CLIENT_HANDSHAKE_TRAFFIC_SECRET" - keyLogLabelServerHandshake = "SERVER_HANDSHAKE_TRAFFIC_SECRET" - keyLogLabelClientTraffic = "CLIENT_TRAFFIC_SECRET_0" - keyLogLabelServerTraffic = "SERVER_TRAFFIC_SECRET_0" -) - -func (c *Config) writeKeyLog(label string, clientRandom, secret []byte) error { - if c.KeyLogWriter == nil { - return nil - } - - logLine := []byte(fmt.Sprintf("%s %x %x\n", label, clientRandom, secret)) - - writerMutex.Lock() - _, err := c.KeyLogWriter.Write(logLine) - writerMutex.Unlock() - - return err -} - -// writerMutex protects all KeyLogWriters globally. It is rarely enabled, -// and is only for debugging, so a global mutex saves space. -var writerMutex sync.Mutex - -// A DelegatedCredentialPair contains a Delegated Credential and its -// associated private key. -type DelegatedCredentialPair struct { - // DC is the delegated credential. - DC *DelegatedCredential - // PrivateKey is the private key used to derive the public key of - // contained in DC. PrivateKey must implement crypto.Signer. - PrivateKey crypto.PrivateKey -} - -// A Certificate is a chain of one or more certificates, leaf first. -type Certificate struct { - Certificate [][]byte - // PrivateKey contains the private key corresponding to the public key in - // Leaf. This must implement crypto.Signer with an RSA, ECDSA or Ed25519 PublicKey. - // For a server up to TLS 1.2, it can also implement crypto.Decrypter with - // an RSA PublicKey. - PrivateKey crypto.PrivateKey - // SupportedSignatureAlgorithms is an optional list restricting what - // signature algorithms the PrivateKey can be used for. - SupportedSignatureAlgorithms []SignatureScheme - // OCSPStaple contains an optional OCSP response which will be served - // to clients that request it. - OCSPStaple []byte - // SignedCertificateTimestamps contains an optional list of Signed - // Certificate Timestamps which will be served to clients that request it. - SignedCertificateTimestamps [][]byte - // DelegatedCredentials are a list of Delegated Credentials with their - // corresponding private keys, signed by the leaf certificate. - // If there are no delegated credentials, this field is nil. - DelegatedCredentials []DelegatedCredentialPair - // DelegatedCredential is the delegated credential to be used in the - // handshake. - // If there are no delegated credentials, this field is nil. - // NOTE: Do not fill this field, as it will be filled depending on - // the provided list of delegated credentials. - DelegatedCredential []byte - // Leaf is the parsed form of the leaf certificate, which may be initialized - // using x509.ParseCertificate to reduce per-handshake processing. If nil, - // the leaf certificate will be parsed as needed. - Leaf *x509.Certificate -} - -// leaf returns the parsed leaf certificate, either from c.Leaf or by parsing -// the corresponding c.Certificate[0]. -func (c *Certificate) leaf() (*x509.Certificate, error) { - if c.Leaf != nil { - return c.Leaf, nil - } - return x509.ParseCertificate(c.Certificate[0]) -} - -type handshakeMessage interface { - marshal() []byte - unmarshal([]byte) bool -} - -// lruSessionCache is a ClientSessionCache implementation that uses an LRU -// caching strategy. -type lruSessionCache struct { - sync.Mutex - - m map[string]*list.Element - q *list.List - capacity int -} - -type lruSessionCacheEntry struct { - sessionKey string - state *ClientSessionState -} - -// NewLRUClientSessionCache returns a ClientSessionCache with the given -// capacity that uses an LRU strategy. If capacity is < 1, a default capacity -// is used instead. -func NewLRUClientSessionCache(capacity int) ClientSessionCache { - const defaultSessionCacheCapacity = 64 - - if capacity < 1 { - capacity = defaultSessionCacheCapacity - } - return &lruSessionCache{ - m: make(map[string]*list.Element), - q: list.New(), - capacity: capacity, - } -} - -// Put adds the provided (sessionKey, cs) pair to the cache. If cs is nil, the entry -// corresponding to sessionKey is removed from the cache instead. -func (c *lruSessionCache) Put(sessionKey string, cs *ClientSessionState) { - c.Lock() - defer c.Unlock() - - if elem, ok := c.m[sessionKey]; ok { - if cs == nil { - c.q.Remove(elem) - delete(c.m, sessionKey) - } else { - entry := elem.Value.(*lruSessionCacheEntry) - entry.state = cs - c.q.MoveToFront(elem) - } - return - } - - if c.q.Len() < c.capacity { - entry := &lruSessionCacheEntry{sessionKey, cs} - c.m[sessionKey] = c.q.PushFront(entry) - return - } - - elem := c.q.Back() - entry := elem.Value.(*lruSessionCacheEntry) - delete(c.m, entry.sessionKey) - entry.sessionKey = sessionKey - entry.state = cs - c.q.MoveToFront(elem) - c.m[sessionKey] = elem -} - -// Get returns the ClientSessionState value associated with a given key. It -// returns (nil, false) if no value is found. -func (c *lruSessionCache) Get(sessionKey string) (*ClientSessionState, bool) { - c.Lock() - defer c.Unlock() - - if elem, ok := c.m[sessionKey]; ok { - c.q.MoveToFront(elem) - return elem.Value.(*lruSessionCacheEntry).state, true - } - return nil, false -} - -var emptyConfig Config - -func defaultConfig() *Config { - return &emptyConfig -} - -func unexpectedMessageError(wanted, got any) error { - return fmt.Errorf("tls: received unexpected handshake message of type %T when waiting for %T", got, wanted) -} - -func isSupportedSignatureAlgorithm(sigAlg SignatureScheme, supportedSignatureAlgorithms []SignatureScheme) bool { - for _, s := range supportedSignatureAlgorithms { - if s == sigAlg { - return true - } - } - return false -} diff --git a/transport/cloudflaretls/common_string.go b/transport/cloudflaretls/common_string.go deleted file mode 100644 index 23810881..00000000 --- a/transport/cloudflaretls/common_string.go +++ /dev/null @@ -1,116 +0,0 @@ -// Code generated by "stringer -type=SignatureScheme,CurveID,ClientAuthType -output=common_string.go"; DO NOT EDIT. - -package tls - -import "strconv" - -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[PKCS1WithSHA256-1025] - _ = x[PKCS1WithSHA384-1281] - _ = x[PKCS1WithSHA512-1537] - _ = x[PSSWithSHA256-2052] - _ = x[PSSWithSHA384-2053] - _ = x[PSSWithSHA512-2054] - _ = x[ECDSAWithP256AndSHA256-1027] - _ = x[ECDSAWithP384AndSHA384-1283] - _ = x[ECDSAWithP521AndSHA512-1539] - _ = x[Ed25519-2055] - _ = x[PKCS1WithSHA1-513] - _ = x[ECDSAWithSHA1-515] -} - -const ( - _SignatureScheme_name_0 = "PKCS1WithSHA1" - _SignatureScheme_name_1 = "ECDSAWithSHA1" - _SignatureScheme_name_2 = "PKCS1WithSHA256" - _SignatureScheme_name_3 = "ECDSAWithP256AndSHA256" - _SignatureScheme_name_4 = "PKCS1WithSHA384" - _SignatureScheme_name_5 = "ECDSAWithP384AndSHA384" - _SignatureScheme_name_6 = "PKCS1WithSHA512" - _SignatureScheme_name_7 = "ECDSAWithP521AndSHA512" - _SignatureScheme_name_8 = "PSSWithSHA256PSSWithSHA384PSSWithSHA512Ed25519" -) - -var ( - _SignatureScheme_index_8 = [...]uint8{0, 13, 26, 39, 46} -) - -func (i SignatureScheme) String() string { - switch { - case i == 513: - return _SignatureScheme_name_0 - case i == 515: - return _SignatureScheme_name_1 - case i == 1025: - return _SignatureScheme_name_2 - case i == 1027: - return _SignatureScheme_name_3 - case i == 1281: - return _SignatureScheme_name_4 - case i == 1283: - return _SignatureScheme_name_5 - case i == 1537: - return _SignatureScheme_name_6 - case i == 1539: - return _SignatureScheme_name_7 - case 2052 <= i && i <= 2055: - i -= 2052 - return _SignatureScheme_name_8[_SignatureScheme_index_8[i]:_SignatureScheme_index_8[i+1]] - default: - return "SignatureScheme(" + strconv.FormatInt(int64(i), 10) + ")" - } -} -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[CurveP256-23] - _ = x[CurveP384-24] - _ = x[CurveP521-25] - _ = x[X25519-29] -} - -const ( - _CurveID_name_0 = "CurveP256CurveP384CurveP521" - _CurveID_name_1 = "X25519" -) - -var ( - _CurveID_index_0 = [...]uint8{0, 9, 18, 27} -) - -func (i CurveID) String() string { - switch { - case 23 <= i && i <= 25: - i -= 23 - return _CurveID_name_0[_CurveID_index_0[i]:_CurveID_index_0[i+1]] - case i == 29: - return _CurveID_name_1 - default: - return "CurveID(" + strconv.FormatInt(int64(i), 10) + ")" - } -} -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[NoClientCert-0] - _ = x[RequestClientCert-1] - _ = x[RequireAnyClientCert-2] - _ = x[VerifyClientCertIfGiven-3] - _ = x[RequireAndVerifyClientCert-4] -} - -const _ClientAuthType_name = "NoClientCertRequestClientCertRequireAnyClientCertVerifyClientCertIfGivenRequireAndVerifyClientCert" - -var _ClientAuthType_index = [...]uint8{0, 12, 29, 49, 72, 98} - -func (i ClientAuthType) String() string { - if i < 0 || i >= ClientAuthType(len(_ClientAuthType_index)-1) { - return "ClientAuthType(" + strconv.FormatInt(int64(i), 10) + ")" - } - return _ClientAuthType_name[_ClientAuthType_index[i]:_ClientAuthType_index[i+1]] -} diff --git a/transport/cloudflaretls/conn.go b/transport/cloudflaretls/conn.go deleted file mode 100644 index e814e7a9..00000000 --- a/transport/cloudflaretls/conn.go +++ /dev/null @@ -1,1603 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// TLS low level connection and record layer - -package tls - -import ( - "bytes" - "context" - "crypto/cipher" - "crypto/subtle" - "crypto/x509" - "errors" - "fmt" - "hash" - "io" - "net" - "sync" - "sync/atomic" - "time" - - "github.com/cloudflare/circl/hpke" -) - -// A Conn represents a secured connection. -// It implements the net.Conn interface. -type Conn struct { - // constant - conn net.Conn - isClient bool - handshakeFn func(context.Context) error // (*Conn).clientHandshake or serverHandshake - - // handshakeStatus is 1 if the connection is currently transferring - // application data (i.e. is not currently processing a handshake). - // handshakeStatus == 1 implies handshakeErr == nil. - // This field is only to be accessed with sync/atomic. - handshakeStatus uint32 - // constant after handshake; protected by handshakeMutex - handshakeMutex sync.Mutex - handshakeErr error // error resulting from handshake - vers uint16 // TLS version - haveVers bool // version has been negotiated - config *Config // configuration passed to constructor - // handshakes counts the number of handshakes performed on the - // connection so far. If renegotiation is disabled then this is either - // zero or one. - handshakes int - didResume bool // whether this connection was a session resumption - cipherSuite uint16 - ocspResponse []byte // stapled OCSP response - scts [][]byte // signed certificate timestamps from server - peerCertificates []*x509.Certificate - // verifiedChains contains the certificate chains that we built, as - // opposed to the ones presented by the server. - verifiedChains [][]*x509.Certificate - // verifiedDC contains the Delegated Credential sent by the peer (if advertised - // and correctly processed), which has been verified against the leaf certificate. - verifiedDC *DelegatedCredential - // serverName contains the server name indicated by the client, if any. - serverName string - // secureRenegotiation is true if the server echoed the secure - // renegotiation extension. (This is meaningless as a server because - // renegotiation is not supported in that case.) - secureRenegotiation bool - // ekm is a closure for exporting keying material. - ekm func(label string, context []byte, length int) ([]byte, error) - // resumptionSecret is the resumption_master_secret for handling - // NewSessionTicket messages. nil if config.SessionTicketsDisabled. - resumptionSecret []byte - - // ticketKeys is the set of active session ticket keys for this - // connection. The first one is used to encrypt new tickets and - // all are tried to decrypt tickets. - ticketKeys []ticketKey - - // clientFinishedIsFirst is true if the client sent the first Finished - // message during the most recent handshake. This is recorded because - // the first transmitted Finished message is the tls-unique - // channel-binding value. - clientFinishedIsFirst bool - - // closeNotifyErr is any error from sending the alertCloseNotify record. - closeNotifyErr error - // closeNotifySent is true if the Conn attempted to send an - // alertCloseNotify record. - closeNotifySent bool - - // clientFinished and serverFinished contain the Finished message sent - // by the client or server in the most recent handshake. This is - // retained to support the renegotiation extension and tls-unique - // channel-binding. - clientFinished [12]byte - serverFinished [12]byte - - // clientProtocol is the negotiated ALPN protocol. - clientProtocol string - - // input/output - in, out halfConn - rawInput bytes.Buffer // raw input, starting with a record header - input bytes.Reader // application data waiting to be read, from rawInput.Next - hand bytes.Buffer // handshake data waiting to be read - buffering bool // whether records are buffered in sendBuf - sendBuf []byte // a buffer of records waiting to be sent - - // bytesSent counts the bytes of application data sent. - // packetsSent counts packets. - bytesSent int64 - packetsSent int64 - - // retryCount counts the number of consecutive non-advancing records - // received by Conn.readRecord. That is, records that neither advance the - // handshake, nor deliver application data. Protected by in.Mutex. - retryCount int - - // activeCall is an atomic int32; the low bit is whether Close has - // been called. the rest of the bits are the number of goroutines - // in Conn.Write. - activeCall int32 - - tmp [16]byte - - // State used for the ECH extension. - ech struct { - sealer hpke.Sealer // The client's HPKE context - opener hpke.Opener // The server's HPKE context - - // The state shared by the client and server. - offered bool // Client offered ECH - greased bool // Client greased ECH - accepted bool // Server accepted ECH - retryConfigs []byte // The retry configurations - configId uint8 // The ECH config id - maxNameLen int // maximum_name_len indicated by the ECH config - } -} - -// Access to net.Conn methods. -// Cannot just embed net.Conn because that would -// export the struct field too. - -// LocalAddr returns the local network address. -func (c *Conn) LocalAddr() net.Addr { - return c.conn.LocalAddr() -} - -// RemoteAddr returns the remote network address. -func (c *Conn) RemoteAddr() net.Addr { - return c.conn.RemoteAddr() -} - -// SetDeadline sets the read and write deadlines associated with the connection. -// A zero value for t means Read and Write will not time out. -// After a Write has timed out, the TLS state is corrupt and all future writes will return the same error. -func (c *Conn) SetDeadline(t time.Time) error { - return c.conn.SetDeadline(t) -} - -// SetReadDeadline sets the read deadline on the underlying connection. -// A zero value for t means Read will not time out. -func (c *Conn) SetReadDeadline(t time.Time) error { - return c.conn.SetReadDeadline(t) -} - -// SetWriteDeadline sets the write deadline on the underlying connection. -// A zero value for t means Write will not time out. -// After a Write has timed out, the TLS state is corrupt and all future writes will return the same error. -func (c *Conn) SetWriteDeadline(t time.Time) error { - return c.conn.SetWriteDeadline(t) -} - -// NetConn returns the underlying connection that is wrapped by c. -// Note that writing to or reading from this connection directly will corrupt the -// TLS session. -func (c *Conn) NetConn() net.Conn { - return c.conn -} - -// A halfConn represents one direction of the record layer -// connection, either sending or receiving. -type halfConn struct { - sync.Mutex - - err error // first permanent error - version uint16 // protocol version - cipher any // cipher algorithm - mac hash.Hash - seq [8]byte // 64-bit sequence number - - scratchBuf [13]byte // to avoid allocs; interface method args escape - - nextCipher any // next encryption state - nextMac hash.Hash // next MAC algorithm - - trafficSecret []byte // current TLS 1.3 traffic secret -} - -type permanentError struct { - err net.Error -} - -func (e *permanentError) Error() string { return e.err.Error() } -func (e *permanentError) Unwrap() error { return e.err } -func (e *permanentError) Timeout() bool { return e.err.Timeout() } -func (e *permanentError) Temporary() bool { return false } - -func (hc *halfConn) setErrorLocked(err error) error { - if e, ok := err.(net.Error); ok { - hc.err = &permanentError{err: e} - } else { - hc.err = err - } - return hc.err -} - -// prepareCipherSpec sets the encryption and MAC states -// that a subsequent changeCipherSpec will use. -func (hc *halfConn) prepareCipherSpec(version uint16, cipher any, mac hash.Hash) { - hc.version = version - hc.nextCipher = cipher - hc.nextMac = mac -} - -// changeCipherSpec changes the encryption and MAC states -// to the ones previously passed to prepareCipherSpec. -func (hc *halfConn) changeCipherSpec() error { - if hc.nextCipher == nil || hc.version == VersionTLS13 { - return alertInternalError - } - hc.cipher = hc.nextCipher - hc.mac = hc.nextMac - hc.nextCipher = nil - hc.nextMac = nil - for i := range hc.seq { - hc.seq[i] = 0 - } - return nil -} - -func (hc *halfConn) setTrafficSecret(suite *cipherSuiteTLS13, secret []byte) { - hc.trafficSecret = secret - key, iv := suite.trafficKey(secret) - hc.cipher = suite.aead(key, iv) - for i := range hc.seq { - hc.seq[i] = 0 - } -} - -// incSeq increments the sequence number. -func (hc *halfConn) incSeq() { - for i := 7; i >= 0; i-- { - hc.seq[i]++ - if hc.seq[i] != 0 { - return - } - } - - // Not allowed to let sequence number wrap. - // Instead, must renegotiate before it does. - // Not likely enough to bother. - panic("TLS: sequence number wraparound") -} - -// explicitNonceLen returns the number of bytes of explicit nonce or IV included -// in each record. Explicit nonces are present only in CBC modes after TLS 1.0 -// and in certain AEAD modes in TLS 1.2. -func (hc *halfConn) explicitNonceLen() int { - if hc.cipher == nil { - return 0 - } - - switch c := hc.cipher.(type) { - case cipher.Stream: - return 0 - case aead: - return c.explicitNonceLen() - case cbcMode: - // TLS 1.1 introduced a per-record explicit IV to fix the BEAST attack. - if hc.version >= VersionTLS11 { - return c.BlockSize() - } - return 0 - default: - panic("unknown cipher type") - } -} - -// extractPadding returns, in constant time, the length of the padding to remove -// from the end of payload. It also returns a byte which is equal to 255 if the -// padding was valid and 0 otherwise. See RFC 2246, Section 6.2.3.2. -func extractPadding(payload []byte) (toRemove int, good byte) { - if len(payload) < 1 { - return 0, 0 - } - - paddingLen := payload[len(payload)-1] - t := uint(len(payload)-1) - uint(paddingLen) - // if len(payload) >= (paddingLen - 1) then the MSB of t is zero - good = byte(int32(^t) >> 31) - - // The maximum possible padding length plus the actual length field - toCheck := 256 - // The length of the padded data is public, so we can use an if here - if toCheck > len(payload) { - toCheck = len(payload) - } - - for i := 0; i < toCheck; i++ { - t := uint(paddingLen) - uint(i) - // if i <= paddingLen then the MSB of t is zero - mask := byte(int32(^t) >> 31) - b := payload[len(payload)-1-i] - good &^= mask&paddingLen ^ mask&b - } - - // We AND together the bits of good and replicate the result across - // all the bits. - good &= good << 4 - good &= good << 2 - good &= good << 1 - good = uint8(int8(good) >> 7) - - // Zero the padding length on error. This ensures any unchecked bytes - // are included in the MAC. Otherwise, an attacker that could - // distinguish MAC failures from padding failures could mount an attack - // similar to POODLE in SSL 3.0: given a good ciphertext that uses a - // full block's worth of padding, replace the final block with another - // block. If the MAC check passed but the padding check failed, the - // last byte of that block decrypted to the block size. - // - // See also macAndPaddingGood logic below. - paddingLen &= good - - toRemove = int(paddingLen) + 1 - return -} - -func roundUp(a, b int) int { - return a + (b-a%b)%b -} - -// cbcMode is an interface for block ciphers using cipher block chaining. -type cbcMode interface { - cipher.BlockMode - SetIV([]byte) -} - -// decrypt authenticates and decrypts the record if protection is active at -// this stage. The returned plaintext might overlap with the input. -func (hc *halfConn) decrypt(record []byte) ([]byte, recordType, error) { - var plaintext []byte - typ := recordType(record[0]) - payload := record[recordHeaderLen:] - - // In TLS 1.3, change_cipher_spec messages are to be ignored without being - // decrypted. See RFC 8446, Appendix D.4. - if hc.version == VersionTLS13 && typ == recordTypeChangeCipherSpec { - return payload, typ, nil - } - - paddingGood := byte(255) - paddingLen := 0 - - explicitNonceLen := hc.explicitNonceLen() - - if hc.cipher != nil { - switch c := hc.cipher.(type) { - case cipher.Stream: - c.XORKeyStream(payload, payload) - case aead: - if len(payload) < explicitNonceLen { - return nil, 0, alertBadRecordMAC - } - nonce := payload[:explicitNonceLen] - if len(nonce) == 0 { - nonce = hc.seq[:] - } - payload = payload[explicitNonceLen:] - - var additionalData []byte - if hc.version == VersionTLS13 { - additionalData = record[:recordHeaderLen] - } else { - additionalData = append(hc.scratchBuf[:0], hc.seq[:]...) - additionalData = append(additionalData, record[:3]...) - n := len(payload) - c.Overhead() - additionalData = append(additionalData, byte(n>>8), byte(n)) - } - - var err error - plaintext, err = c.Open(payload[:0], nonce, payload, additionalData) - if err != nil { - return nil, 0, alertBadRecordMAC - } - case cbcMode: - blockSize := c.BlockSize() - minPayload := explicitNonceLen + roundUp(hc.mac.Size()+1, blockSize) - if len(payload)%blockSize != 0 || len(payload) < minPayload { - return nil, 0, alertBadRecordMAC - } - - if explicitNonceLen > 0 { - c.SetIV(payload[:explicitNonceLen]) - payload = payload[explicitNonceLen:] - } - c.CryptBlocks(payload, payload) - - // In a limited attempt to protect against CBC padding oracles like - // Lucky13, the data past paddingLen (which is secret) is passed to - // the MAC function as extra data, to be fed into the HMAC after - // computing the digest. This makes the MAC roughly constant time as - // long as the digest computation is constant time and does not - // affect the subsequent write, modulo cache effects. - paddingLen, paddingGood = extractPadding(payload) - default: - panic("unknown cipher type") - } - - if hc.version == VersionTLS13 { - if typ != recordTypeApplicationData { - return nil, 0, alertUnexpectedMessage - } - if len(plaintext) > maxPlaintext+1 { - return nil, 0, alertRecordOverflow - } - // Remove padding and find the ContentType scanning from the end. - for i := len(plaintext) - 1; i >= 0; i-- { - if plaintext[i] != 0 { - typ = recordType(plaintext[i]) - plaintext = plaintext[:i] - break - } - if i == 0 { - return nil, 0, alertUnexpectedMessage - } - } - } - } else { - plaintext = payload - } - - if hc.mac != nil { - macSize := hc.mac.Size() - if len(payload) < macSize { - return nil, 0, alertBadRecordMAC - } - - n := len(payload) - macSize - paddingLen - n = subtle.ConstantTimeSelect(int(uint32(n)>>31), 0, n) // if n < 0 { n = 0 } - record[3] = byte(n >> 8) - record[4] = byte(n) - remoteMAC := payload[n : n+macSize] - localMAC := tls10MAC(hc.mac, hc.scratchBuf[:0], hc.seq[:], record[:recordHeaderLen], payload[:n], payload[n+macSize:]) - - // This is equivalent to checking the MACs and paddingGood - // separately, but in constant-time to prevent distinguishing - // padding failures from MAC failures. Depending on what value - // of paddingLen was returned on bad padding, distinguishing - // bad MAC from bad padding can lead to an attack. - // - // See also the logic at the end of extractPadding. - macAndPaddingGood := subtle.ConstantTimeCompare(localMAC, remoteMAC) & int(paddingGood) - if macAndPaddingGood != 1 { - return nil, 0, alertBadRecordMAC - } - - plaintext = payload[:n] - } - - hc.incSeq() - return plaintext, typ, nil -} - -// sliceForAppend extends the input slice by n bytes. head is the full extended -// slice, while tail is the appended part. If the original slice has sufficient -// capacity no allocation is performed. -func sliceForAppend(in []byte, n int) (head, tail []byte) { - if total := len(in) + n; cap(in) >= total { - head = in[:total] - } else { - head = make([]byte, total) - copy(head, in) - } - tail = head[len(in):] - return -} - -// encrypt encrypts payload, adding the appropriate nonce and/or MAC, and -// appends it to record, which must already contain the record header. -func (hc *halfConn) encrypt(record, payload []byte, rand io.Reader) ([]byte, error) { - if hc.cipher == nil { - return append(record, payload...), nil - } - - var explicitNonce []byte - if explicitNonceLen := hc.explicitNonceLen(); explicitNonceLen > 0 { - record, explicitNonce = sliceForAppend(record, explicitNonceLen) - if _, isCBC := hc.cipher.(cbcMode); !isCBC && explicitNonceLen < 16 { - // The AES-GCM construction in TLS has an explicit nonce so that the - // nonce can be random. However, the nonce is only 8 bytes which is - // too small for a secure, random nonce. Therefore we use the - // sequence number as the nonce. The 3DES-CBC construction also has - // an 8 bytes nonce but its nonces must be unpredictable (see RFC - // 5246, Appendix F.3), forcing us to use randomness. That's not - // 3DES' biggest problem anyway because the birthday bound on block - // collision is reached first due to its similarly small block size - // (see the Sweet32 attack). - copy(explicitNonce, hc.seq[:]) - } else { - if _, err := io.ReadFull(rand, explicitNonce); err != nil { - return nil, err - } - } - } - - var dst []byte - switch c := hc.cipher.(type) { - case cipher.Stream: - mac := tls10MAC(hc.mac, hc.scratchBuf[:0], hc.seq[:], record[:recordHeaderLen], payload, nil) - record, dst = sliceForAppend(record, len(payload)+len(mac)) - c.XORKeyStream(dst[:len(payload)], payload) - c.XORKeyStream(dst[len(payload):], mac) - case aead: - nonce := explicitNonce - if len(nonce) == 0 { - nonce = hc.seq[:] - } - - if hc.version == VersionTLS13 { - record = append(record, payload...) - - // Encrypt the actual ContentType and replace the plaintext one. - record = append(record, record[0]) - record[0] = byte(recordTypeApplicationData) - - n := len(payload) + 1 + c.Overhead() - record[3] = byte(n >> 8) - record[4] = byte(n) - - record = c.Seal(record[:recordHeaderLen], - nonce, record[recordHeaderLen:], record[:recordHeaderLen]) - } else { - additionalData := append(hc.scratchBuf[:0], hc.seq[:]...) - additionalData = append(additionalData, record[:recordHeaderLen]...) - record = c.Seal(record, nonce, payload, additionalData) - } - case cbcMode: - mac := tls10MAC(hc.mac, hc.scratchBuf[:0], hc.seq[:], record[:recordHeaderLen], payload, nil) - blockSize := c.BlockSize() - plaintextLen := len(payload) + len(mac) - paddingLen := blockSize - plaintextLen%blockSize - record, dst = sliceForAppend(record, plaintextLen+paddingLen) - copy(dst, payload) - copy(dst[len(payload):], mac) - for i := plaintextLen; i < len(dst); i++ { - dst[i] = byte(paddingLen - 1) - } - if len(explicitNonce) > 0 { - c.SetIV(explicitNonce) - } - c.CryptBlocks(dst, dst) - default: - panic("unknown cipher type") - } - - // Update length to include nonce, MAC and any block padding needed. - n := len(record) - recordHeaderLen - record[3] = byte(n >> 8) - record[4] = byte(n) - hc.incSeq() - - return record, nil -} - -// RecordHeaderError is returned when a TLS record header is invalid. -type RecordHeaderError struct { - // Msg contains a human readable string that describes the error. - Msg string - // RecordHeader contains the five bytes of TLS record header that - // triggered the error. - RecordHeader [5]byte - // Conn provides the underlying net.Conn in the case that a client - // sent an initial handshake that didn't look like TLS. - // It is nil if there's already been a handshake or a TLS alert has - // been written to the connection. - Conn net.Conn -} - -func (e RecordHeaderError) Error() string { return "tls: " + e.Msg } - -func (c *Conn) newRecordHeaderError(conn net.Conn, msg string) (err RecordHeaderError) { - err.Msg = msg - err.Conn = conn - copy(err.RecordHeader[:], c.rawInput.Bytes()) - return err -} - -func (c *Conn) readRecord() error { - return c.readRecordOrCCS(false) -} - -func (c *Conn) readChangeCipherSpec() error { - return c.readRecordOrCCS(true) -} - -// readRecordOrCCS reads one or more TLS records from the connection and -// updates the record layer state. Some invariants: -// - c.in must be locked -// - c.input must be empty -// -// During the handshake one and only one of the following will happen: -// - c.hand grows -// - c.in.changeCipherSpec is called -// - an error is returned -// -// After the handshake one and only one of the following will happen: -// - c.hand grows -// - c.input is set -// - an error is returned -func (c *Conn) readRecordOrCCS(expectChangeCipherSpec bool) error { - if c.in.err != nil { - return c.in.err - } - handshakeComplete := c.handshakeComplete() - - // This function modifies c.rawInput, which owns the c.input memory. - if c.input.Len() != 0 { - return c.in.setErrorLocked(errors.New("tls: internal error: attempted to read record with pending application data")) - } - c.input.Reset(nil) - - // Read header, payload. - if err := c.readFromUntil(c.conn, recordHeaderLen); err != nil { - // RFC 8446, Section 6.1 suggests that EOF without an alertCloseNotify - // is an error, but popular web sites seem to do this, so we accept it - // if and only if at the record boundary. - if err == io.ErrUnexpectedEOF && c.rawInput.Len() == 0 { - err = io.EOF - } - if e, ok := err.(net.Error); !ok || !e.Temporary() { - c.in.setErrorLocked(err) - } - return err - } - hdr := c.rawInput.Bytes()[:recordHeaderLen] - typ := recordType(hdr[0]) - - // No valid TLS record has a type of 0x80, however SSLv2 handshakes - // start with a uint16 length where the MSB is set and the first record - // is always < 256 bytes long. Therefore typ == 0x80 strongly suggests - // an SSLv2 client. - if !handshakeComplete && typ == 0x80 { - c.sendAlert(alertProtocolVersion) - return c.in.setErrorLocked(c.newRecordHeaderError(nil, "unsupported SSLv2 handshake received")) - } - - vers := uint16(hdr[1])<<8 | uint16(hdr[2]) - n := int(hdr[3])<<8 | int(hdr[4]) - if c.haveVers && c.vers != VersionTLS13 && vers != c.vers { - c.sendAlert(alertProtocolVersion) - msg := fmt.Sprintf("received record with version %x when expecting version %x", vers, c.vers) - return c.in.setErrorLocked(c.newRecordHeaderError(nil, msg)) - } - if !c.haveVers { - // First message, be extra suspicious: this might not be a TLS - // client. Bail out before reading a full 'body', if possible. - // The current max version is 3.3 so if the version is >= 16.0, - // it's probably not real. - if (typ != recordTypeAlert && typ != recordTypeHandshake) || vers >= 0x1000 { - return c.in.setErrorLocked(c.newRecordHeaderError(c.conn, "first record does not look like a TLS handshake")) - } - } - if c.vers == VersionTLS13 && n > maxCiphertextTLS13 || n > maxCiphertext { - c.sendAlert(alertRecordOverflow) - msg := fmt.Sprintf("oversized record received with length %d", n) - return c.in.setErrorLocked(c.newRecordHeaderError(nil, msg)) - } - if err := c.readFromUntil(c.conn, recordHeaderLen+n); err != nil { - if e, ok := err.(net.Error); !ok || !e.Temporary() { - c.in.setErrorLocked(err) - } - return err - } - - // Process message. - record := c.rawInput.Next(recordHeaderLen + n) - data, typ, err := c.in.decrypt(record) - if err != nil { - return c.in.setErrorLocked(c.sendAlert(err.(alert))) - } - if len(data) > maxPlaintext { - return c.in.setErrorLocked(c.sendAlert(alertRecordOverflow)) - } - - // Application Data messages are always protected. - if c.in.cipher == nil && typ == recordTypeApplicationData { - return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) - } - - if typ != recordTypeAlert && typ != recordTypeChangeCipherSpec && len(data) > 0 { - // This is a state-advancing message: reset the retry count. - c.retryCount = 0 - } - - // Handshake messages MUST NOT be interleaved with other record types in TLS 1.3. - if c.vers == VersionTLS13 && typ != recordTypeHandshake && c.hand.Len() > 0 { - return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) - } - - switch typ { - default: - return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) - - case recordTypeAlert: - if len(data) != 2 { - return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) - } - if alert(data[1]) == alertCloseNotify { - return c.in.setErrorLocked(io.EOF) - } - if c.vers == VersionTLS13 { - if !c.isClient && c.ech.greased && alert(data[1]) == alertECHRequired { - // This condition indicates that the client intended to offer - // ECH, but did not use a known ECH config. - c.ech.offered = true - c.ech.greased = false - } - return c.in.setErrorLocked(&net.OpError{Op: "remote error", Err: alert(data[1])}) - } - switch data[0] { - case alertLevelWarning: - // Drop the record on the floor and retry. - return c.retryReadRecord(expectChangeCipherSpec) - case alertLevelError: - return c.in.setErrorLocked(&net.OpError{Op: "remote error", Err: alert(data[1])}) - default: - return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) - } - - case recordTypeChangeCipherSpec: - if len(data) != 1 || data[0] != 1 { - return c.in.setErrorLocked(c.sendAlert(alertDecodeError)) - } - // Handshake messages are not allowed to fragment across the CCS. - if c.hand.Len() > 0 { - return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) - } - // In TLS 1.3, change_cipher_spec records are ignored until the - // Finished. See RFC 8446, Appendix D.4. Note that according to Section - // 5, a server can send a ChangeCipherSpec before its ServerHello, when - // c.vers is still unset. That's not useful though and suspicious if the - // server then selects a lower protocol version, so don't allow that. - if c.vers == VersionTLS13 { - return c.retryReadRecord(expectChangeCipherSpec) - } - if !expectChangeCipherSpec { - return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) - } - if err := c.in.changeCipherSpec(); err != nil { - return c.in.setErrorLocked(c.sendAlert(err.(alert))) - } - - case recordTypeApplicationData: - if !handshakeComplete || expectChangeCipherSpec { - return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) - } - // Some OpenSSL servers send empty records in order to randomize the - // CBC IV. Ignore a limited number of empty records. - if len(data) == 0 { - return c.retryReadRecord(expectChangeCipherSpec) - } - // Note that data is owned by c.rawInput, following the Next call above, - // to avoid copying the plaintext. This is safe because c.rawInput is - // not read from or written to until c.input is drained. - c.input.Reset(data) - - case recordTypeHandshake: - if len(data) == 0 || expectChangeCipherSpec { - return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) - } - c.hand.Write(data) - } - - return nil -} - -// retryReadRecord recurses into readRecordOrCCS to drop a non-advancing record, like -// a warning alert, empty application_data, or a change_cipher_spec in TLS 1.3. -func (c *Conn) retryReadRecord(expectChangeCipherSpec bool) error { - c.retryCount++ - if c.retryCount > maxUselessRecords { - c.sendAlert(alertUnexpectedMessage) - return c.in.setErrorLocked(errors.New("tls: too many ignored records")) - } - return c.readRecordOrCCS(expectChangeCipherSpec) -} - -// atLeastReader reads from R, stopping with EOF once at least N bytes have been -// read. It is different from an io.LimitedReader in that it doesn't cut short -// the last Read call, and in that it considers an early EOF an error. -type atLeastReader struct { - R io.Reader - N int64 -} - -func (r *atLeastReader) Read(p []byte) (int, error) { - if r.N <= 0 { - return 0, io.EOF - } - n, err := r.R.Read(p) - r.N -= int64(n) // won't underflow unless len(p) >= n > 9223372036854775809 - if r.N > 0 && err == io.EOF { - return n, io.ErrUnexpectedEOF - } - if r.N <= 0 && err == nil { - return n, io.EOF - } - return n, err -} - -// readFromUntil reads from r into c.rawInput until c.rawInput contains -// at least n bytes or else returns an error. -func (c *Conn) readFromUntil(r io.Reader, n int) error { - if c.rawInput.Len() >= n { - return nil - } - needs := n - c.rawInput.Len() - // There might be extra input waiting on the wire. Make a best effort - // attempt to fetch it so that it can be used in (*Conn).Read to - // "predict" closeNotify alerts. - c.rawInput.Grow(needs + bytes.MinRead) - _, err := c.rawInput.ReadFrom(&atLeastReader{r, int64(needs)}) - return err -} - -// sendAlert sends a TLS alert message. -func (c *Conn) sendAlertLocked(err alert) error { - switch err { - case alertNoRenegotiation, alertCloseNotify: - c.tmp[0] = alertLevelWarning - default: - c.tmp[0] = alertLevelError - } - c.tmp[1] = byte(err) - - _, writeErr := c.writeRecordLocked(recordTypeAlert, c.tmp[0:2]) - if err == alertCloseNotify { - // closeNotify is a special case in that it isn't an error. - return writeErr - } - - return c.out.setErrorLocked(&net.OpError{Op: "local error", Err: err}) -} - -// sendAlert sends a TLS alert message. -func (c *Conn) sendAlert(err alert) error { - c.out.Lock() - defer c.out.Unlock() - return c.sendAlertLocked(err) -} - -const ( - // tcpMSSEstimate is a conservative estimate of the TCP maximum segment - // size (MSS). A constant is used, rather than querying the kernel for - // the actual MSS, to avoid complexity. The value here is the IPv6 - // minimum MTU (1280 bytes) minus the overhead of an IPv6 header (40 - // bytes) and a TCP header with timestamps (32 bytes). - tcpMSSEstimate = 1208 - - // recordSizeBoostThreshold is the number of bytes of application data - // sent after which the TLS record size will be increased to the - // maximum. - recordSizeBoostThreshold = 128 * 1024 -) - -// maxPayloadSizeForWrite returns the maximum TLS payload size to use for the -// next application data record. There is the following trade-off: -// -// - For latency-sensitive applications, such as web browsing, each TLS -// record should fit in one TCP segment. -// - For throughput-sensitive applications, such as large file transfers, -// larger TLS records better amortize framing and encryption overheads. -// -// A simple heuristic that works well in practice is to use small records for -// the first 1MB of data, then use larger records for subsequent data, and -// reset back to smaller records after the connection becomes idle. See "High -// Performance Web Networking", Chapter 4, or: -// https://www.igvita.com/2013/10/24/optimizing-tls-record-size-and-buffering-latency/ -// -// In the interests of simplicity and determinism, this code does not attempt -// to reset the record size once the connection is idle, however. -func (c *Conn) maxPayloadSizeForWrite(typ recordType) int { - if c.config.DynamicRecordSizingDisabled || typ != recordTypeApplicationData { - return maxPlaintext - } - - if c.bytesSent >= recordSizeBoostThreshold { - return maxPlaintext - } - - // Subtract TLS overheads to get the maximum payload size. - payloadBytes := tcpMSSEstimate - recordHeaderLen - c.out.explicitNonceLen() - if c.out.cipher != nil { - switch ciph := c.out.cipher.(type) { - case cipher.Stream: - payloadBytes -= c.out.mac.Size() - case cipher.AEAD: - payloadBytes -= ciph.Overhead() - case cbcMode: - blockSize := ciph.BlockSize() - // The payload must fit in a multiple of blockSize, with - // room for at least one padding byte. - payloadBytes = (payloadBytes & ^(blockSize - 1)) - 1 - // The MAC is appended before padding so affects the - // payload size directly. - payloadBytes -= c.out.mac.Size() - default: - panic("unknown cipher type") - } - } - if c.vers == VersionTLS13 { - payloadBytes-- // encrypted ContentType - } - - // Allow packet growth in arithmetic progression up to max. - pkt := c.packetsSent - c.packetsSent++ - if pkt > 1000 { - return maxPlaintext // avoid overflow in multiply below - } - - n := payloadBytes * int(pkt+1) - if n > maxPlaintext { - n = maxPlaintext - } - return n -} - -func (c *Conn) write(data []byte) (int, error) { - if c.buffering { - c.sendBuf = append(c.sendBuf, data...) - return len(data), nil - } - - n, err := c.conn.Write(data) - c.bytesSent += int64(n) - return n, err -} - -func (c *Conn) flush() (int, error) { - if len(c.sendBuf) == 0 { - return 0, nil - } - - n, err := c.conn.Write(c.sendBuf) - c.bytesSent += int64(n) - c.sendBuf = nil - c.buffering = false - return n, err -} - -// outBufPool pools the record-sized scratch buffers used by writeRecordLocked. -var outBufPool = sync.Pool{ - New: func() any { - return new([]byte) - }, -} - -// writeRecordLocked writes a TLS record with the given type and payload to the -// connection and updates the record layer state. -func (c *Conn) writeRecordLocked(typ recordType, data []byte) (int, error) { - outBufPtr := outBufPool.Get().(*[]byte) - outBuf := *outBufPtr - defer func() { - // You might be tempted to simplify this by just passing &outBuf to Put, - // but that would make the local copy of the outBuf slice header escape - // to the heap, causing an allocation. Instead, we keep around the - // pointer to the slice header returned by Get, which is already on the - // heap, and overwrite and return that. - *outBufPtr = outBuf - outBufPool.Put(outBufPtr) - }() - - var n int - for len(data) > 0 { - m := len(data) - if maxPayload := c.maxPayloadSizeForWrite(typ); m > maxPayload { - m = maxPayload - } - - _, outBuf = sliceForAppend(outBuf[:0], recordHeaderLen) - outBuf[0] = byte(typ) - vers := c.vers - if vers == 0 { - // Some TLS servers fail if the record version is - // greater than TLS 1.0 for the initial ClientHello. - vers = VersionTLS10 - } else if vers == VersionTLS13 { - // TLS 1.3 froze the record layer version to 1.2. - // See RFC 8446, Section 5.1. - vers = VersionTLS12 - } - outBuf[1] = byte(vers >> 8) - outBuf[2] = byte(vers) - outBuf[3] = byte(m >> 8) - outBuf[4] = byte(m) - - var err error - outBuf, err = c.out.encrypt(outBuf, data[:m], c.config.rand()) - if err != nil { - return n, err - } - if _, err := c.write(outBuf); err != nil { - return n, err - } - n += m - data = data[m:] - } - - if typ == recordTypeChangeCipherSpec && c.vers != VersionTLS13 { - if err := c.out.changeCipherSpec(); err != nil { - return n, c.sendAlertLocked(err.(alert)) - } - } - - return n, nil -} - -// writeRecord writes a TLS record with the given type and payload to the -// connection and updates the record layer state. -func (c *Conn) writeRecord(typ recordType, data []byte) (int, error) { - c.out.Lock() - defer c.out.Unlock() - - return c.writeRecordLocked(typ, data) -} - -// readHandshake reads the next handshake message from -// the record layer. -func (c *Conn) readHandshake() (any, error) { - for c.hand.Len() < 4 { - if err := c.readRecord(); err != nil { - return nil, err - } - } - - data := c.hand.Bytes() - n := int(data[1])<<16 | int(data[2])<<8 | int(data[3]) - if n > maxHandshake { - c.sendAlertLocked(alertInternalError) - return nil, c.in.setErrorLocked(fmt.Errorf("tls: handshake message of length %d bytes exceeds maximum of %d bytes", n, maxHandshake)) - } - for c.hand.Len() < 4+n { - if err := c.readRecord(); err != nil { - return nil, err - } - } - data = c.hand.Next(4 + n) - var m handshakeMessage - switch data[0] { - case typeHelloRequest: - m = new(helloRequestMsg) - case typeClientHello: - m = new(clientHelloMsg) - case typeServerHello: - m = new(serverHelloMsg) - case typeNewSessionTicket: - if c.vers == VersionTLS13 { - m = new(newSessionTicketMsgTLS13) - } else { - m = new(newSessionTicketMsg) - } - case typeCertificate: - if c.vers == VersionTLS13 { - m = new(certificateMsgTLS13) - } else { - m = new(certificateMsg) - } - case typeCertificateRequest: - if c.vers == VersionTLS13 { - m = new(certificateRequestMsgTLS13) - } else { - m = &certificateRequestMsg{ - hasSignatureAlgorithm: c.vers >= VersionTLS12, - } - } - case typeCertificateStatus: - m = new(certificateStatusMsg) - case typeServerKeyExchange: - m = new(serverKeyExchangeMsg) - case typeServerHelloDone: - m = new(serverHelloDoneMsg) - case typeClientKeyExchange: - m = new(clientKeyExchangeMsg) - case typeCertificateVerify: - m = &certificateVerifyMsg{ - hasSignatureAlgorithm: c.vers >= VersionTLS12, - } - case typeFinished: - m = new(finishedMsg) - case typeEncryptedExtensions: - m = new(encryptedExtensionsMsg) - case typeEndOfEarlyData: - m = new(endOfEarlyDataMsg) - case typeKeyUpdate: - m = new(keyUpdateMsg) - default: - return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) - } - - // The handshake message unmarshalers - // expect to be able to keep references to data, - // so pass in a fresh copy that won't be overwritten. - data = append([]byte(nil), data...) - - if !m.unmarshal(data) { - return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) - } - return m, nil -} - -var errShutdown = errors.New("tls: protocol is shutdown") - -// Write writes data to the connection. -// -// As Write calls Handshake, in order to prevent indefinite blocking a deadline -// must be set for both Read and Write before Write is called when the handshake -// has not yet completed. See SetDeadline, SetReadDeadline, and -// SetWriteDeadline. -func (c *Conn) Write(b []byte) (int, error) { - // interlock with Close below - for { - x := atomic.LoadInt32(&c.activeCall) - if x&1 != 0 { - return 0, net.ErrClosed - } - if atomic.CompareAndSwapInt32(&c.activeCall, x, x+2) { - break - } - } - defer atomic.AddInt32(&c.activeCall, -2) - - if err := c.Handshake(); err != nil { - return 0, err - } - - c.out.Lock() - defer c.out.Unlock() - - if err := c.out.err; err != nil { - return 0, err - } - - if !c.handshakeComplete() { - return 0, alertInternalError - } - - if c.closeNotifySent { - return 0, errShutdown - } - - // TLS 1.0 is susceptible to a chosen-plaintext - // attack when using block mode ciphers due to predictable IVs. - // This can be prevented by splitting each Application Data - // record into two records, effectively randomizing the IV. - // - // https://www.openssl.org/~bodo/tls-cbc.txt - // https://bugzilla.mozilla.org/show_bug.cgi?id=665814 - // https://www.imperialviolet.org/2012/01/15/beastfollowup.html - - var m int - if len(b) > 1 && c.vers == VersionTLS10 { - if _, ok := c.out.cipher.(cipher.BlockMode); ok { - n, err := c.writeRecordLocked(recordTypeApplicationData, b[:1]) - if err != nil { - return n, c.out.setErrorLocked(err) - } - m, b = 1, b[1:] - } - } - - n, err := c.writeRecordLocked(recordTypeApplicationData, b) - return n + m, c.out.setErrorLocked(err) -} - -// handleRenegotiation processes a HelloRequest handshake message. -func (c *Conn) handleRenegotiation() error { - if c.vers == VersionTLS13 { - return errors.New("tls: internal error: unexpected renegotiation") - } - - msg, err := c.readHandshake() - if err != nil { - return err - } - - helloReq, ok := msg.(*helloRequestMsg) - if !ok { - c.sendAlert(alertUnexpectedMessage) - return unexpectedMessageError(helloReq, msg) - } - - if !c.isClient { - return c.sendAlert(alertNoRenegotiation) - } - - switch c.config.Renegotiation { - case RenegotiateNever: - return c.sendAlert(alertNoRenegotiation) - case RenegotiateOnceAsClient: - if c.handshakes > 1 { - return c.sendAlert(alertNoRenegotiation) - } - case RenegotiateFreelyAsClient: - // Ok. - default: - c.sendAlert(alertInternalError) - return errors.New("tls: unknown Renegotiation value") - } - - c.handshakeMutex.Lock() - defer c.handshakeMutex.Unlock() - - atomic.StoreUint32(&c.handshakeStatus, 0) - if c.handshakeErr = c.clientHandshake(context.Background()); c.handshakeErr == nil { - c.handshakes++ - } - return c.handshakeErr -} - -// handlePostHandshakeMessage processes a handshake message arrived after the -// handshake is complete. Up to TLS 1.2, it indicates the start of a renegotiation. -func (c *Conn) handlePostHandshakeMessage() error { - if c.vers != VersionTLS13 { - return c.handleRenegotiation() - } - - msg, err := c.readHandshake() - if err != nil { - return err - } - - c.retryCount++ - if c.retryCount > maxUselessRecords { - c.sendAlert(alertUnexpectedMessage) - return c.in.setErrorLocked(errors.New("tls: too many non-advancing records")) - } - - switch msg := msg.(type) { - case *newSessionTicketMsgTLS13: - return c.handleNewSessionTicket(msg) - case *keyUpdateMsg: - return c.handleKeyUpdate(msg) - default: - c.sendAlert(alertUnexpectedMessage) - return fmt.Errorf("tls: received unexpected handshake message of type %T", msg) - } -} - -func (c *Conn) handleKeyUpdate(keyUpdate *keyUpdateMsg) error { - cipherSuite := cipherSuiteTLS13ByID(c.cipherSuite) - if cipherSuite == nil { - return c.in.setErrorLocked(c.sendAlert(alertInternalError)) - } - - newSecret := cipherSuite.nextTrafficSecret(c.in.trafficSecret) - c.in.setTrafficSecret(cipherSuite, newSecret) - - if keyUpdate.updateRequested { - c.out.Lock() - defer c.out.Unlock() - - msg := &keyUpdateMsg{} - _, err := c.writeRecordLocked(recordTypeHandshake, msg.marshal()) - if err != nil { - // Surface the error at the next write. - c.out.setErrorLocked(err) - return nil - } - - newSecret := cipherSuite.nextTrafficSecret(c.out.trafficSecret) - c.out.setTrafficSecret(cipherSuite, newSecret) - } - - return nil -} - -// Read reads data from the connection. -// -// As Read calls Handshake, in order to prevent indefinite blocking a deadline -// must be set for both Read and Write before Read is called when the handshake -// has not yet completed. See SetDeadline, SetReadDeadline, and -// SetWriteDeadline. -func (c *Conn) Read(b []byte) (int, error) { - if err := c.Handshake(); err != nil { - return 0, err - } - if len(b) == 0 { - // Put this after Handshake, in case people were calling - // Read(nil) for the side effect of the Handshake. - return 0, nil - } - - c.in.Lock() - defer c.in.Unlock() - - for c.input.Len() == 0 { - if err := c.readRecord(); err != nil { - return 0, err - } - for c.hand.Len() > 0 { - if err := c.handlePostHandshakeMessage(); err != nil { - return 0, err - } - } - } - - n, _ := c.input.Read(b) - - // If a close-notify alert is waiting, read it so that we can return (n, - // EOF) instead of (n, nil), to signal to the HTTP response reading - // goroutine that the connection is now closed. This eliminates a race - // where the HTTP response reading goroutine would otherwise not observe - // the EOF until its next read, by which time a client goroutine might - // have already tried to reuse the HTTP connection for a new request. - // See https://golang.org/cl/76400046 and https://golang.org/issue/3514 - if n != 0 && c.input.Len() == 0 && c.rawInput.Len() > 0 && - recordType(c.rawInput.Bytes()[0]) == recordTypeAlert { - if err := c.readRecord(); err != nil { - return n, err // will be io.EOF on closeNotify - } - } - - return n, nil -} - -// Close closes the connection. -func (c *Conn) Close() error { - // Interlock with Conn.Write above. - var x int32 - for { - x = atomic.LoadInt32(&c.activeCall) - if x&1 != 0 { - return net.ErrClosed - } - if atomic.CompareAndSwapInt32(&c.activeCall, x, x|1) { - break - } - } - if x != 0 { - // io.Writer and io.Closer should not be used concurrently. - // If Close is called while a Write is currently in-flight, - // interpret that as a sign that this Close is really just - // being used to break the Write and/or clean up resources and - // avoid sending the alertCloseNotify, which may block - // waiting on handshakeMutex or the c.out mutex. - return c.conn.Close() - } - - var alertErr error - if c.handshakeComplete() { - if err := c.closeNotify(); err != nil { - alertErr = fmt.Errorf("tls: failed to send closeNotify alert (but connection was closed anyway): %w", err) - } - } - - if err := c.conn.Close(); err != nil { - return err - } - - // Resolve ECH status. - if !c.isClient && c.config.MaxVersion < VersionTLS13 { - c.handleCFEvent(CFEventECHServerStatus(echStatusBypassed)) - } else if !c.ech.offered { - if !c.ech.greased { - c.handleCFEvent(CFEventECHClientStatus(echStatusBypassed)) - } else { - c.handleCFEvent(CFEventECHClientStatus(echStatusOuter)) - } - } else { - c.handleCFEvent(CFEventECHClientStatus(echStatusInner)) - if !c.ech.accepted { - if len(c.ech.retryConfigs) > 0 { - c.handleCFEvent(CFEventECHServerStatus(echStatusOuter)) - } else { - c.handleCFEvent(CFEventECHServerStatus(echStatusBypassed)) - } - } else { - c.handleCFEvent(CFEventECHServerStatus(echStatusInner)) - } - } - - return alertErr -} - -var errEarlyCloseWrite = errors.New("tls: CloseWrite called before handshake complete") - -// CloseWrite shuts down the writing side of the connection. It should only be -// called once the handshake has completed and does not call CloseWrite on the -// underlying connection. Most callers should just use Close. -func (c *Conn) CloseWrite() error { - if !c.handshakeComplete() { - return errEarlyCloseWrite - } - - return c.closeNotify() -} - -func (c *Conn) closeNotify() error { - c.out.Lock() - defer c.out.Unlock() - - if !c.closeNotifySent { - // Set a Write Deadline to prevent possibly blocking forever. - c.SetWriteDeadline(time.Now().Add(time.Second * 5)) - c.closeNotifyErr = c.sendAlertLocked(alertCloseNotify) - c.closeNotifySent = true - // Any subsequent writes will fail. - c.SetWriteDeadline(time.Now()) - } - return c.closeNotifyErr -} - -// Handshake runs the client or server handshake -// protocol if it has not yet been run. -// -// Most uses of this package need not call Handshake explicitly: the -// first Read or Write will call it automatically. -// -// For control over canceling or setting a timeout on a handshake, use -// HandshakeContext or the Dialer's DialContext method instead. -func (c *Conn) Handshake() error { - return c.HandshakeContext(context.Background()) -} - -// HandshakeContext runs the client or server handshake -// protocol if it has not yet been run. -// -// The provided Context must be non-nil. If the context is canceled before -// the handshake is complete, the handshake is interrupted and an error is returned. -// Once the handshake has completed, cancellation of the context will not affect the -// connection. -// -// Most uses of this package need not call HandshakeContext explicitly: the -// first Read or Write will call it automatically. -func (c *Conn) HandshakeContext(ctx context.Context) error { - // Delegate to unexported method for named return - // without confusing documented signature. - return c.handshakeContext(ctx) -} - -func (c *Conn) handshakeContext(ctx context.Context) (ret error) { - // Fast sync/atomic-based exit if there is no handshake in flight and the - // last one succeeded without an error. Avoids the expensive context setup - // and mutex for most Read and Write calls. - if c.handshakeComplete() { - return nil - } - - handshakeCtx, cancel := context.WithCancel(ctx) - // Note: defer this before starting the "interrupter" goroutine - // so that we can tell the difference between the input being canceled and - // this cancellation. In the former case, we need to close the connection. - defer cancel() - - // Start the "interrupter" goroutine, if this context might be canceled. - // (The background context cannot). - // - // The interrupter goroutine waits for the input context to be done and - // closes the connection if this happens before the function returns. - if ctx.Done() != nil { - done := make(chan struct{}) - interruptRes := make(chan error, 1) - defer func() { - close(done) - if ctxErr := <-interruptRes; ctxErr != nil { - // Return context error to user. - ret = ctxErr - } - }() - go func() { - select { - case <-handshakeCtx.Done(): - // Close the connection, discarding the error - _ = c.conn.Close() - interruptRes <- handshakeCtx.Err() - case <-done: - interruptRes <- nil - } - }() - } - - c.handshakeMutex.Lock() - defer c.handshakeMutex.Unlock() - - if err := c.handshakeErr; err != nil { - return err - } - if c.handshakeComplete() { - return nil - } - - c.in.Lock() - defer c.in.Unlock() - - c.handshakeErr = c.handshakeFn(handshakeCtx) - if c.handshakeErr == nil { - c.handshakes++ - } else { - // If an error occurred during the handshake try to flush the - // alert that might be left in the buffer. - c.flush() - } - - if c.handshakeErr == nil && !c.handshakeComplete() { - c.handshakeErr = errors.New("tls: internal error: handshake should have had a result") - } - if c.handshakeErr != nil && c.handshakeComplete() { - panic("tls: internal error: handshake returned an error but is marked successful") - } - - return c.handshakeErr -} - -// ConnectionState returns basic TLS details about the connection. -func (c *Conn) ConnectionState() ConnectionState { - c.handshakeMutex.Lock() - defer c.handshakeMutex.Unlock() - return c.connectionStateLocked() -} - -func (c *Conn) connectionStateLocked() ConnectionState { - var state ConnectionState - state.HandshakeComplete = c.handshakeComplete() - state.Version = c.vers - state.NegotiatedProtocol = c.clientProtocol - state.DidResume = c.didResume - state.NegotiatedProtocolIsMutual = true - state.ServerName = c.serverName - state.CipherSuite = c.cipherSuite - state.PeerCertificates = c.peerCertificates - state.VerifiedChains = c.verifiedChains - if c.verifiedDC != nil { - state.VerifiedDC = true - } - state.SignedCertificateTimestamps = c.scts - state.OCSPResponse = c.ocspResponse - state.ECHAccepted = c.ech.accepted - state.ECHOffered = c.ech.offered || c.ech.greased - state.CFControl = c.config.CFControl - if !c.didResume && c.vers != VersionTLS13 { - if c.clientFinishedIsFirst { - state.TLSUnique = c.clientFinished[:] - } else { - state.TLSUnique = c.serverFinished[:] - } - } - if c.config.Renegotiation != RenegotiateNever { - state.ekm = noExportedKeyingMaterial - } else { - state.ekm = c.ekm - } - return state -} - -// OCSPResponse returns the stapled OCSP response from the TLS server, if -// any. (Only valid for client connections.) -func (c *Conn) OCSPResponse() []byte { - c.handshakeMutex.Lock() - defer c.handshakeMutex.Unlock() - - return c.ocspResponse -} - -// VerifyHostname checks that the peer certificate chain is valid for -// connecting to host. If so, it returns nil; if not, it returns an error -// describing the problem. -func (c *Conn) VerifyHostname(host string) error { - c.handshakeMutex.Lock() - defer c.handshakeMutex.Unlock() - if !c.isClient { - return errors.New("tls: VerifyHostname called on TLS server connection") - } - if !c.handshakeComplete() { - return errors.New("tls: handshake has not yet been performed") - } - if len(c.verifiedChains) == 0 { - return errors.New("tls: handshake did not verify certificate chain") - } - return c.peerCertificates[0].VerifyHostname(host) -} - -func (c *Conn) handshakeComplete() bool { - return atomic.LoadUint32(&c.handshakeStatus) == 1 -} - -func (c *Conn) handleCFEvent(event CFEvent) { - if c.config.CFEventHandler != nil { - c.config.CFEventHandler(event) - } -} diff --git a/transport/cloudflaretls/delegated_credentials.go b/transport/cloudflaretls/delegated_credentials.go deleted file mode 100644 index 711f1d8c..00000000 --- a/transport/cloudflaretls/delegated_credentials.go +++ /dev/null @@ -1,550 +0,0 @@ -// Copyright 2020-2021 Cloudflare, Inc. All rights reserved. Use of this source code -// is governed by a BSD-style license that can be found in the LICENSE file. - -package tls - -// Delegated Credentials for TLS -// (https://tools.ietf.org/html/draft-ietf-tls-subcerts) is an IETF Internet -// draft and proposed TLS extension. If the client or server supports this -// extension, then the server or client may use a "delegated credential" as the -// signing key in the handshake. A delegated credential is a short lived -// public/secret key pair delegated to the peer by an entity trusted by the -// corresponding peer. This allows a reverse proxy to terminate a TLS connection -// on behalf of the entity. Credentials can't be revoked; in order to -// mitigate risk in case the reverse proxy is compromised, the credential is only -// valid for a short time (days, hours, or even minutes). - -import ( - "bytes" - "crypto" - "crypto/ecdsa" - "crypto/ed25519" - "crypto/elliptic" - "crypto/rand" - "crypto/rsa" - "crypto/x509" - "encoding/binary" - "errors" - "fmt" - "io" - "time" - - "golang.org/x/crypto/cryptobyte" -) - -const ( - // In the absence of an application profile standard specifying otherwise, - // the maximum validity period is set to 7 days. - dcMaxTTLSeconds = 60 * 60 * 24 * 7 - dcMaxTTL = time.Duration(dcMaxTTLSeconds * time.Second) - dcMaxPubLen = (1 << 24) - 1 // Bytes - dcMaxSignatureLen = (1 << 16) - 1 // Bytes -) - -const ( - undefinedSignatureScheme SignatureScheme = 0x0000 -) - -var extensionDelegatedCredential = []int{1, 3, 6, 1, 4, 1, 44363, 44} - -// isValidForDelegation returns true if a certificate can be used for Delegated -// Credentials. -func isValidForDelegation(cert *x509.Certificate) bool { - // Check that the digitalSignature key usage is set. - // The certificate must contains the digitalSignature KeyUsage. - if (cert.KeyUsage & x509.KeyUsageDigitalSignature) == 0 { - return false - } - - // Check that the certificate has the DelegationUsage extension and that - // it's marked as non-critical (See Section 4.2 of RFC5280). - for _, extension := range cert.Extensions { - if extension.Id.Equal(extensionDelegatedCredential) { - if extension.Critical { - return false - } - return true - } - } - return false -} - -// isExpired returns true if the credential has expired. The end of the validity -// interval is defined as the delegator certificate's notBefore field ('start') -// plus dc.cred.validTime seconds. This function simply checks that the current time -// ('now') is before the end of the validity interval. -func (dc *DelegatedCredential) isExpired(start, now time.Time) bool { - end := start.Add(dc.cred.validTime) - return !now.Before(end) -} - -// invalidTTL returns true if the credential's validity period is longer than the -// maximum permitted. This is defined by the certificate's notBefore field -// ('start') plus the dc.validTime, minus the current time ('now'). -func (dc *DelegatedCredential) invalidTTL(start, now time.Time) bool { - return dc.cred.validTime > (now.Sub(start) + dcMaxTTL).Round(time.Second) -} - -// credential stores the public components of a Delegated Credential. -type credential struct { - // The amount of time for which the credential is valid. Specifically, the - // the credential expires 'validTime' seconds after the 'notBefore' of the - // delegation certificate. The delegator shall not issue Delegated - // Credentials that are valid for more than 7 days from the current time. - // - // When this data structure is serialized, this value is converted to a - // uint32 representing the duration in seconds. - validTime time.Duration - // The signature scheme associated with the credential public key. - // This is expected to be the same as the CertificateVerify.algorithm - // sent by the client or server. - expCertVerfAlgo SignatureScheme - // The credential's public key. - publicKey crypto.PublicKey -} - -// DelegatedCredential stores a Delegated Credential with the credential and its -// signature. -type DelegatedCredential struct { - // The serialized form of the Delegated Credential. - raw []byte - - // Cred stores the public components of a Delegated Credential. - cred *credential - - // The signature scheme used to sign the Delegated Credential. - algorithm SignatureScheme - - // The Credential's delegation: a signature that binds the credential to - // the end-entity certificate's public key. - signature []byte -} - -// marshalPublicKeyInfo returns a DER encoded PublicKeyInfo -// from a Delegated Credential (as defined in the X.509 standard). -// The following key types are currently supported: *ecdsa.PublicKey -// and ed25519.PublicKey. Unsupported key types result in an error. -// rsa.PublicKey is not supported as defined by the draft. -func (cred *credential) marshalPublicKeyInfo() ([]byte, error) { - switch cred.expCertVerfAlgo { - case ECDSAWithP256AndSHA256, - ECDSAWithP384AndSHA384, - ECDSAWithP521AndSHA512, - Ed25519: - rawPub, err := x509.MarshalPKIXPublicKey(cred.publicKey) - if err != nil { - return nil, err - } - - return rawPub, nil - - default: - return nil, fmt.Errorf("tls: unsupported signature scheme: 0x%04x", cred.expCertVerfAlgo) - } -} - -// marshal encodes the credential struct of the Delegated Credential. -func (cred *credential) marshal() ([]byte, error) { - var b cryptobyte.Builder - - b.AddUint32(uint32(cred.validTime / time.Second)) - b.AddUint16(uint16(cred.expCertVerfAlgo)) - - // Encode the public key - rawPub, err := cred.marshalPublicKeyInfo() - if err != nil { - return nil, err - } - // Assert that the public key encoding is no longer than 2^24-1 bytes. - if len(rawPub) > dcMaxPubLen { - return nil, errors.New("tls: public key length exceeds 2^24-1 limit") - } - - b.AddUint24(uint32(len(rawPub))) - b.AddBytes(rawPub) - - raw := b.BytesOrPanic() - return raw, nil -} - -// unmarshalCredential decodes serialized bytes and returns a credential, if possible. -func unmarshalCredential(raw []byte) (*credential, error) { - if len(raw) < 10 { - return nil, errors.New("tls: Delegated Credential is not valid: invalid length") - } - - s := cryptobyte.String(raw) - var t uint32 - if !s.ReadUint32(&t) { - return nil, errors.New("tls: Delegated Credential is not valid") - } - validTime := time.Duration(t) * time.Second - - var pubAlgo uint16 - if !s.ReadUint16(&pubAlgo) { - return nil, errors.New("tls: Delegated Credential is not valid") - } - algo := SignatureScheme(pubAlgo) - - var pubLen uint32 - s.ReadUint24(&pubLen) - - pubKey, err := x509.ParsePKIXPublicKey(s) - if err != nil { - return nil, err - } - - return &credential{validTime, algo, pubKey}, nil -} - -// getCredentialLen returns the number of bytes comprising the serialized -// credential struct inside the Delegated Credential. -func getCredentialLen(raw []byte) (int, error) { - if len(raw) < 10 { - return 0, errors.New("tls: Delegated Credential is not valid") - } - - var read []byte - s := cryptobyte.String(raw) - s.ReadBytes(&read, 6) - - var pubLen uint32 - s.ReadUint24(&pubLen) - if !(pubLen > 0) { - return 0, errors.New("tls: Delegated Credential is not valid") - } - - raw = raw[6:] - if len(raw) < int(pubLen) { - return 0, errors.New("tls: Delegated Credential is not valid") - } - - return 9 + int(pubLen), nil -} - -// getHash maps the SignatureScheme to its corresponding hash function. -func getHash(scheme SignatureScheme) crypto.Hash { - switch scheme { - case ECDSAWithP256AndSHA256: - return crypto.SHA256 - case ECDSAWithP384AndSHA384: - return crypto.SHA384 - case ECDSAWithP521AndSHA512: - return crypto.SHA512 - case Ed25519: - return directSigning - case PKCS1WithSHA256, PSSWithSHA256: - return crypto.SHA256 - case PSSWithSHA384: - return crypto.SHA384 - case PSSWithSHA512: - return crypto.SHA512 - default: - return 0 // Unknown hash function - } -} - -// getECDSACurve maps the SignatureScheme to its corresponding ecdsa elliptic.Curve. -func getECDSACurve(scheme SignatureScheme) elliptic.Curve { - switch scheme { - case ECDSAWithP256AndSHA256: - return elliptic.P256() - case ECDSAWithP384AndSHA384: - return elliptic.P384() - case ECDSAWithP521AndSHA512: - return elliptic.P521() - default: - return nil - } -} - -// prepareDelegationSignatureInput returns the message that the delegator is going to sign. -func prepareDelegationSignatureInput(hash crypto.Hash, cred *credential, dCert []byte, algo SignatureScheme, isClient bool) ([]byte, error) { - header := make([]byte, 64) - for i := range header { - header[i] = 0x20 - } - - var context string - if !isClient { - context = "TLS, server delegated credentials\x00" - } else { - context = "TLS, client delegated credentials\x00" - } - - rawCred, err := cred.marshal() - if err != nil { - return nil, err - } - - var rawAlgo [2]byte - binary.BigEndian.PutUint16(rawAlgo[:], uint16(algo)) - - if hash == directSigning { - b := &bytes.Buffer{} - b.Write(header) - io.WriteString(b, context) - b.Write(dCert) - b.Write(rawCred) - b.Write(rawAlgo[:]) - return b.Bytes(), nil - } - - h := hash.New() - h.Write(header) - io.WriteString(h, context) - h.Write(dCert) - h.Write(rawCred) - h.Write(rawAlgo[:]) - return h.Sum(nil), nil -} - -// Extract the algorithm used to sign the Delegated Credential from the -// end-entity (leaf) certificate. -func getSignatureAlgorithm(cert *Certificate) (SignatureScheme, error) { - switch sk := cert.PrivateKey.(type) { - case *ecdsa.PrivateKey: - pk := sk.Public().(*ecdsa.PublicKey) - curveName := pk.Curve.Params().Name - certAlg := cert.Leaf.PublicKeyAlgorithm - if certAlg == x509.ECDSA && curveName == "P-256" { - return ECDSAWithP256AndSHA256, nil - } else if certAlg == x509.ECDSA && curveName == "P-384" { - return ECDSAWithP384AndSHA384, nil - } else if certAlg == x509.ECDSA && curveName == "P-521" { - return ECDSAWithP521AndSHA512, nil - } else { - return undefinedSignatureScheme, fmt.Errorf("using curve %s for %s is not supported", curveName, cert.Leaf.SignatureAlgorithm) - } - case ed25519.PrivateKey: - return Ed25519, nil - case *rsa.PrivateKey: - // If the certificate has the RSAEncryption OID there are a number of valid signature schemes that may sign the DC. - // In the absence of better information, we make a reasonable choice. - return PSSWithSHA256, nil - default: - return undefinedSignatureScheme, fmt.Errorf("tls: unsupported algorithm for signing Delegated Credential") - } -} - -// NewDelegatedCredential creates a new Delegated Credential using 'cert' for -// delegation, depending if the caller is the client or the server (defined by -// 'isClient'). It generates a public/private key pair for the provided signature -// algorithm ('pubAlgo') and it defines a validity interval (defined -// by 'cert.Leaf.notBefore' and 'validTime'). It signs the Delegated Credential -// using 'cert.PrivateKey'. -func NewDelegatedCredential(cert *Certificate, pubAlgo SignatureScheme, validTime time.Duration, isClient bool) (*DelegatedCredential, crypto.PrivateKey, error) { - // The granularity of DC validity is seconds. - validTime = validTime.Round(time.Second) - - // Parse the leaf certificate if needed. - var err error - if cert.Leaf == nil { - if len(cert.Certificate[0]) == 0 { - return nil, nil, errors.New("tls: missing leaf certificate for Delegated Credential") - } - cert.Leaf, err = x509.ParseCertificate(cert.Certificate[0]) - if err != nil { - return nil, nil, err - } - } - - // Check that the leaf certificate can be used for delegation. - if !isValidForDelegation(cert.Leaf) { - return nil, nil, errors.New("tls: certificate not authorized for delegation") - } - - sigAlgo, err := getSignatureAlgorithm(cert) - if err != nil { - return nil, nil, err - } - - // Generate the Delegated Credential key pair based on the provided scheme - var privK crypto.PrivateKey - var pubK crypto.PublicKey - switch pubAlgo { - case ECDSAWithP256AndSHA256, - ECDSAWithP384AndSHA384, - ECDSAWithP521AndSHA512: - privK, err = ecdsa.GenerateKey(getECDSACurve(pubAlgo), rand.Reader) - if err != nil { - return nil, nil, err - } - pubK = privK.(*ecdsa.PrivateKey).Public() - case Ed25519: - pubK, privK, err = ed25519.GenerateKey(rand.Reader) - if err != nil { - return nil, nil, err - } - default: - return nil, nil, fmt.Errorf("tls: unsupported algorithm for Delegated Credential: %s", pubAlgo) - } - - // Prepare the credential for signing - hash := getHash(sigAlgo) - credential := &credential{validTime, pubAlgo, pubK} - values, err := prepareDelegationSignatureInput(hash, credential, cert.Leaf.Raw, sigAlgo, isClient) - if err != nil { - return nil, nil, err - } - - var sig []byte - switch sk := cert.PrivateKey.(type) { - case *ecdsa.PrivateKey: - opts := crypto.SignerOpts(hash) - sig, err = sk.Sign(rand.Reader, values, opts) - if err != nil { - return nil, nil, err - } - case ed25519.PrivateKey: - opts := crypto.SignerOpts(hash) - sig, err = sk.Sign(rand.Reader, values, opts) - if err != nil { - return nil, nil, err - } - case *rsa.PrivateKey: - opts := &rsa.PSSOptions{ - SaltLength: rsa.PSSSaltLengthEqualsHash, - Hash: hash, - } - sig, err = rsa.SignPSS(rand.Reader, sk, hash, values, opts) - if err != nil { - return nil, nil, err - } - default: - return nil, nil, fmt.Errorf("tls: unsupported key type for Delegated Credential") - } - - if len(sig) > dcMaxSignatureLen { - return nil, nil, errors.New("tls: unable to create a Delegated Credential") - } - - return &DelegatedCredential{ - cred: credential, - algorithm: sigAlgo, - signature: sig, - }, privK, nil -} - -// Validate validates the Delegated Credential by checking that the signature is -// valid, that it hasn't expired, and that the TTL is valid. It also checks that -// certificate can be used for delegation. -func (dc *DelegatedCredential) Validate(cert *x509.Certificate, isClient bool, now time.Time, certVerifyMsg *certificateVerifyMsg) bool { - if dc.isExpired(cert.NotBefore, now) { - return false - } - - if dc.invalidTTL(cert.NotBefore, now) { - return false - } - - if dc.cred.expCertVerfAlgo != certVerifyMsg.signatureAlgorithm { - return false - } - - if !isValidForDelegation(cert) { - return false - } - - hash := getHash(dc.algorithm) - in, err := prepareDelegationSignatureInput(hash, dc.cred, cert.Raw, dc.algorithm, isClient) - if err != nil { - return false - } - - switch dc.algorithm { - case ECDSAWithP256AndSHA256, - ECDSAWithP384AndSHA384, - ECDSAWithP521AndSHA512: - pk, ok := cert.PublicKey.(*ecdsa.PublicKey) - if !ok { - return false - } - - return ecdsa.VerifyASN1(pk, in, dc.signature) - case Ed25519: - pk, ok := cert.PublicKey.(ed25519.PublicKey) - if !ok { - return false - } - - return ed25519.Verify(pk, in, dc.signature) - case PSSWithSHA256, - PSSWithSHA384, - PSSWithSHA512: - pk, ok := cert.PublicKey.(*rsa.PublicKey) - if !ok { - return false - } - hash := getHash(dc.algorithm) - return rsa.VerifyPSS(pk, hash, in, dc.signature, nil) == nil - default: - return false - } -} - -// Marshal encodes a DelegatedCredential structure. It also sets dc.Raw to that -// encoding. -func (dc *DelegatedCredential) Marshal() ([]byte, error) { - if len(dc.signature) > dcMaxSignatureLen { - return nil, errors.New("tls: delegated credential is not valid") - } - if len(dc.signature) == 0 { - return nil, errors.New("tls: delegated credential has no signature") - } - - raw, err := dc.cred.marshal() - if err != nil { - return nil, err - } - - var b cryptobyte.Builder - b.AddBytes(raw) - b.AddUint16(uint16(dc.algorithm)) - b.AddUint16(uint16(len(dc.signature))) - b.AddBytes(dc.signature) - - dc.raw = b.BytesOrPanic() - return dc.raw, nil -} - -// UnmarshalDelegatedCredential decodes a DelegatedCredential structure. -func UnmarshalDelegatedCredential(raw []byte) (*DelegatedCredential, error) { - rawCredentialLen, err := getCredentialLen(raw) - if err != nil { - return nil, err - } - - credential, err := unmarshalCredential(raw[:rawCredentialLen]) - if err != nil { - return nil, err - } - - raw = raw[rawCredentialLen:] - if len(raw) < 4 { - return nil, errors.New("tls: Delegated Credential is not valid") - } - - s := cryptobyte.String(raw) - - var algo uint16 - if !s.ReadUint16(&algo) { - return nil, errors.New("tls: Delegated Credential is not valid") - } - - var rawSignatureLen uint16 - if !s.ReadUint16(&rawSignatureLen) { - return nil, errors.New("tls: Delegated Credential is not valid") - } - - var sig []byte - if !s.ReadBytes(&sig, int(rawSignatureLen)) { - return nil, errors.New("tls: Delegated Credential is not valid") - } - - return &DelegatedCredential{ - cred: credential, - algorithm: SignatureScheme(algo), - signature: sig, - }, nil -} diff --git a/transport/cloudflaretls/ech.go b/transport/cloudflaretls/ech.go deleted file mode 100644 index 42c5f53c..00000000 --- a/transport/cloudflaretls/ech.go +++ /dev/null @@ -1,1094 +0,0 @@ -// Copyright 2020 Cloudflare, Inc. All rights reserved. Use of this source code -// is governed by a BSD-style license that can be found in the LICENSE file. - -package tls - -import ( - "context" - "errors" - "fmt" - "io" - - "github.com/cloudflare/circl/hpke" - "golang.org/x/crypto/cryptobyte" -) - -const ( - // Constants for TLS operations - echAcceptConfLabel = "ech accept confirmation" - echAcceptConfHRRLabel = "hrr ech accept confirmation" - - // Constants for HPKE operations - echHpkeInfoSetup = "tls ech" - - // When sent in the ClientHello, the first byte of the payload of the ECH - // extension indicates whether the message is the ClientHelloOuter or - // ClientHelloInner. - echClientHelloOuterVariant uint8 = 0 - echClientHelloInnerVariant uint8 = 1 -) - -var zeros = [8]byte{} - -// echOfferOrGrease is called by the client after generating its ClientHello -// message to decide if it will offer or GREASE ECH. It does neither if ECH is -// disabled. Returns a pair of ClientHello messages, hello and helloInner. If -// offering ECH, these are the ClienthelloOuter and ClientHelloInner -// respectively. Otherwise, hello is the ClientHello and helloInner == nil. -// -// TODO(cjpatton): "[When offering ECH, the client] MUST NOT offer to resume any -// session for TLS 1.2 and below [in ClientHelloInner]." -func (c *Conn) echOfferOrGrease(ctx context.Context, helloBase *clientHelloMsg) (hello, helloInner *clientHelloMsg, err error) { - config := c.config - - if !config.ECHEnabled || testingECHTriggerBypassBeforeHRR { - // Bypass ECH. - return helloBase, nil, nil - } - - // Choose the ECHConfig to use for this connection. If none is available, or - // if we're not offering TLS 1.3 or above, then GREASE. - echConfig, err := config.echSelectConfig(ctx, helloBase.serverName) - if err != nil { - return nil, nil, fmt.Errorf("tls: ech: fetch ech config: %s", err) - } - if echConfig == nil || config.maxSupportedVersion(roleClient) < VersionTLS13 { - var err error - - // Generate a dummy ClientECH. - helloBase.ech, err = echGenerateGreaseExt(config.rand()) - if err != nil { - return nil, nil, fmt.Errorf("tls: ech: failed to generate grease ECH: %s", err) - } - - // GREASE ECH. - c.ech.offered = false - c.ech.greased = true - helloBase.raw = nil - return helloBase, nil, nil - } - - // Store the ECH config parameters that are needed later. - c.ech.configId = echConfig.configId - c.ech.maxNameLen = int(echConfig.maxNameLen) - - // Generate the HPKE context. Store it in case of HRR. - var enc []byte - enc, c.ech.sealer, err = echConfig.setupSealer(config.rand()) - if err != nil { - return nil, nil, fmt.Errorf("tls: ech: %s", err) - } - - // ClientHelloInner is constructed from the base ClientHello. The payload of - // the "encrypted_client_hello" extension is a single 1 byte indicating that - // this is the ClientHelloInner. - helloInner = helloBase - helloInner.ech = []byte{echClientHelloInnerVariant} - - // Ensure that only TLS 1.3 and above are offered in the inner handshake. - if v := helloInner.supportedVersions; len(v) == 0 || v[len(v)-1] < VersionTLS13 { - return nil, nil, errors.New("tls: ech: only TLS 1.3 is allowed in ClientHelloInner") - } - - // ClientHelloOuter is constructed by generating a fresh ClientHello and - // copying "session_id" from ClientHelloInner, setting "server_name" to the - // client-facing server, and adding the "encrypted_client_hello" extension. - // - // In addition, we discard the "key_share" and instead use the one from - // ClientHelloInner. - hello, _, err = c.makeClientHello(config.MinVersion) - if err != nil { - return nil, nil, fmt.Errorf("tls: ech: %s", err) - } - hello.sessionId = helloBase.sessionId - hello.serverName = hostnameInSNI(string(echConfig.rawPublicName)) - if err := c.echUpdateClientHelloOuter(hello, helloInner, enc); err != nil { - return nil, nil, err - } - - // Offer ECH. - c.ech.offered = true - helloInner.raw = nil - hello.raw = nil - return hello, helloInner, nil -} - -// echUpdateClientHelloOuter is called by the client to construct the payload of -// the ECH extension in the outer handshake. -func (c *Conn) echUpdateClientHelloOuter(hello, helloInner *clientHelloMsg, enc []byte) error { - var ( - ech echClientOuter - err error - ) - - // Copy all compressed extensions from ClientHelloInner into - // ClientHelloOuter. - for _, ext := range echOuterExtensions() { - echCopyExtensionFromClientHelloInner(hello, helloInner, ext) - } - - // Always copy the "key_shares" extension from ClientHelloInner, regardless - // of whether it gets compressed. - hello.keyShares = helloInner.keyShares - - _, kdf, aead := c.ech.sealer.Suite().Params() - ech.handle.suite.kdfId = uint16(kdf) - ech.handle.suite.aeadId = uint16(aead) - ech.handle.configId = c.ech.configId - ech.handle.enc = enc - - // EncodedClientHelloInner - helloInner.raw = nil - encodedHelloInner := echEncodeClientHelloInner( - helloInner.marshal(), - len(helloInner.serverName), - c.ech.maxNameLen) - if encodedHelloInner == nil { - return errors.New("tls: ech: encoding of EncodedClientHelloInner failed") - } - - // ClientHelloOuterAAD - hello.raw = nil - hello.ech = ech.marshal() - helloOuterAad := echEncodeClientHelloOuterAAD(hello.marshal(), - aead.CipherLen(uint(len(encodedHelloInner)))) - if helloOuterAad == nil { - return errors.New("tls: ech: encoding of ClientHelloOuterAAD failed") - } - - ech.payload, err = c.ech.sealer.Seal(encodedHelloInner, helloOuterAad) - if err != nil { - return fmt.Errorf("tls: ech: seal failed: %s", err) - } - if testingECHTriggerPayloadDecryptError { - ech.payload[0] ^= 0xff // Inauthentic ciphertext - } - ech.raw = nil - hello.ech = ech.marshal() - - helloInner.raw = nil - hello.raw = nil - return nil -} - -// echAcceptOrReject is called by the client-facing server to determine whether -// ECH was offered by the client, and if so, whether to accept or reject. The -// return value is the ClientHello that will be used for the connection. -// -// This function is called prior to processing the ClientHello. In case of -// HelloRetryRequest, it is also called before processing the second -// ClientHello. This is indicated by the afterHRR flag. -func (c *Conn) echAcceptOrReject(hello *clientHelloMsg, afterHRR bool) (*clientHelloMsg, error) { - config := c.config - p := config.ServerECHProvider - - if !config.echCanAccept() { - // Bypass ECH. - return hello, nil - } - - if len(hello.ech) > 0 { // The ECH extension is present - switch hello.ech[0] { - case echClientHelloInnerVariant: // inner handshake - if len(hello.ech) > 1 { - c.sendAlert(alertIllegalParameter) - return nil, errors.New("ech: inner handshake has non-empty payload") - } - - // Continue as the backend server. - return hello, nil - case echClientHelloOuterVariant: // outer handshake - default: - c.sendAlert(alertIllegalParameter) - return nil, errors.New("ech: inner handshake has non-empty payload") - } - } else { - if c.ech.offered { - // This occurs if the server accepted prior to HRR, but the client - // failed to send the ECH extension in the second ClientHelloOuter. This - // would cause ClientHelloOuter to be used after ClientHelloInner, which - // is illegal. - c.sendAlert(alertMissingExtension) - return nil, errors.New("ech: hrr: bypass after offer") - } - - // Bypass ECH. - return hello, nil - } - - if afterHRR && !c.ech.offered && !c.ech.greased { - // The client bypassed ECH prior to HRR, but not after. This could - // cause ClientHelloInner to be used after ClientHelloOuter, which is - // illegal. - c.sendAlert(alertIllegalParameter) - return nil, errors.New("ech: hrr: offer or grease after bypass") - } - - // Parse ClientECH. - ech, err := echUnmarshalClientOuter(hello.ech) - if err != nil { - c.sendAlert(alertIllegalParameter) - return nil, fmt.Errorf("ech: failed to parse extension: %s", err) - } - - // Make sure that the HPKE suite and config id don't change across HRR and - // that the encapsulated key is not present after HRR. - if afterHRR && c.ech.offered { - _, kdf, aead := c.ech.opener.Suite().Params() - if ech.handle.suite.kdfId != uint16(kdf) || - ech.handle.suite.aeadId != uint16(aead) || - ech.handle.configId != c.ech.configId || - len(ech.handle.enc) > 0 { - c.sendAlert(alertIllegalParameter) - return nil, errors.New("ech: hrr: illegal handle in second hello") - } - } - - // Store the config id in case of HRR. - c.ech.configId = ech.handle.configId - - // Ask the ECH provider for the HPKE context. - if c.ech.opener == nil { - res := p.GetDecryptionContext(ech.handle.marshal(), extensionECH) - - // Compute retry configurations, skipping those indicating an - // unsupported version. - if len(res.RetryConfigs) > 0 { - configs, err := UnmarshalECHConfigs(res.RetryConfigs) // skips unrecognized versions - if err != nil { - c.sendAlert(alertInternalError) - return nil, fmt.Errorf("ech: %s", err) - } - - if len(configs) > 0 { - c.ech.retryConfigs, err = echMarshalConfigs(configs) - if err != nil { - c.sendAlert(alertInternalError) - return nil, fmt.Errorf("ech: %s", err) - } - } - - // Check if the outer SNI matches the public name of any ECH config - // advertised by the client-facing server. As of - // draft-ietf-tls-esni-10, the client is required to use the ECH - // config's public name as the outer SNI. Although there's no real - // reason for the server to enforce this, it's worth noting it when - // it happens. - pubNameMatches := false - for _, config := range configs { - if hello.serverName == string(config.rawPublicName) { - pubNameMatches = true - } - } - if !pubNameMatches { - c.handleCFEvent(CFEventECHPublicNameMismatch{}) - } - } - - switch res.Status { - case ECHProviderSuccess: - c.ech.opener, err = hpke.UnmarshalOpener(res.Context) - if err != nil { - c.sendAlert(alertInternalError) - return nil, fmt.Errorf("ech: %s", err) - } - case ECHProviderReject: - // Reject ECH. We do not know at this point whether the client - // intended to offer or grease ECH, so we presume grease until the - // client indicates rejection by sending an "ech_required" alert. - c.ech.greased = true - return hello, nil - case ECHProviderAbort: - c.sendAlert(alert(res.Alert)) - return nil, fmt.Errorf("ech: provider aborted: %s", res.Error) - default: - c.sendAlert(alertInternalError) - return nil, errors.New("ech: unexpected provider status") - } - } - - // ClientHelloOuterAAD - rawHelloOuterAad := echEncodeClientHelloOuterAAD(hello.marshal(), uint(len(ech.payload))) - if rawHelloOuterAad == nil { - // This occurs if the ClientHelloOuter is malformed. This values was - // already parsed into `hello`, so this should not happen. - c.sendAlert(alertInternalError) - return nil, fmt.Errorf("ech: failed to encode ClientHelloOuterAAD") - } - - // EncodedClientHelloInner - rawEncodedHelloInner, err := c.ech.opener.Open(ech.payload, rawHelloOuterAad) - if err != nil { - if afterHRR && c.ech.accepted { - // Don't reject after accept, as this would result in processing the - // ClientHelloOuter after processing the ClientHelloInner. - c.sendAlert(alertDecryptError) - return nil, fmt.Errorf("ech: hrr: reject after accept: %s", err) - } - - // Reject ECH. We do not know at this point whether the client - // intended to offer or grease ECH, so we presume grease until the - // client indicates rejection by sending an "ech_required" alert. - c.ech.greased = true - return hello, nil - } - - // ClientHelloInner - rawHelloInner := echDecodeClientHelloInner(rawEncodedHelloInner, hello.marshal(), hello.sessionId) - if rawHelloInner == nil { - c.sendAlert(alertIllegalParameter) - return nil, fmt.Errorf("ech: failed to decode EncodedClientHelloInner") - } - helloInner := new(clientHelloMsg) - if !helloInner.unmarshal(rawHelloInner) { - c.sendAlert(alertIllegalParameter) - return nil, fmt.Errorf("ech: failed to parse ClientHelloInner") - } - - // Check for a well-formed ECH extension. - if len(helloInner.ech) != 1 || - helloInner.ech[0] != echClientHelloInnerVariant { - c.sendAlert(alertIllegalParameter) - return nil, fmt.Errorf("ech: ClientHelloInner does not have a well-formed ECH extension") - } - - // Check that the client did not offer TLS 1.2 or below in the inner - // handshake. - helloInnerSupportsTLS12OrBelow := len(helloInner.supportedVersions) == 0 - for _, v := range helloInner.supportedVersions { - if v < VersionTLS13 { - helloInnerSupportsTLS12OrBelow = true - } - } - if helloInnerSupportsTLS12OrBelow { - c.sendAlert(alertIllegalParameter) - return nil, errors.New("ech: ClientHelloInner offers TLS 1.2 or below") - } - - // Accept ECH. - c.ech.offered = true - c.ech.accepted = true - return helloInner, nil -} - -// echClientOuter represents a ClientECH structure, the payload of the client's -// "encrypted_client_hello" extension that appears in the outer handshake. -type echClientOuter struct { - raw []byte - - // Parsed from raw - handle echContextHandle - payload []byte -} - -// echUnmarshalClientOuter parses a ClientECH structure. The caller provides the -// ECH version indicated by the client. -func echUnmarshalClientOuter(raw []byte) (*echClientOuter, error) { - s := cryptobyte.String(raw) - ech := new(echClientOuter) - ech.raw = raw - - // Make sure this is the outer handshake. - var variant uint8 - if !s.ReadUint8(&variant) { - return nil, fmt.Errorf("error parsing ClientECH.type") - } - if variant != echClientHelloOuterVariant { - return nil, fmt.Errorf("unexpected ClientECH.type (want outer (0))") - } - - // Parse the context handle. - if !echReadContextHandle(&s, &ech.handle) { - return nil, fmt.Errorf("error parsing context handle") - } - endOfContextHandle := len(raw) - len(s) - ech.handle.raw = raw[1:endOfContextHandle] - - // Parse the payload. - var t cryptobyte.String - if !s.ReadUint16LengthPrefixed(&t) || - !t.ReadBytes(&ech.payload, len(t)) || !s.Empty() { - return nil, fmt.Errorf("error parsing payload") - } - - return ech, nil -} - -func (ech *echClientOuter) marshal() []byte { - if ech.raw != nil { - return ech.raw - } - var b cryptobyte.Builder - b.AddUint8(echClientHelloOuterVariant) - b.AddBytes(ech.handle.marshal()) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(ech.payload) - }) - return b.BytesOrPanic() -} - -// echContextHandle represents the prefix of a ClientECH structure used by -// the server to compute the HPKE context. -type echContextHandle struct { - raw []byte - - // Parsed from raw - suite hpkeSymmetricCipherSuite - configId uint8 - enc []byte -} - -func (handle *echContextHandle) marshal() []byte { - if handle.raw != nil { - return handle.raw - } - var b cryptobyte.Builder - b.AddUint16(handle.suite.kdfId) - b.AddUint16(handle.suite.aeadId) - b.AddUint8(handle.configId) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(handle.enc) - }) - return b.BytesOrPanic() -} - -func echReadContextHandle(s *cryptobyte.String, handle *echContextHandle) bool { - var t cryptobyte.String - if !s.ReadUint16(&handle.suite.kdfId) || // cipher_suite.kdf_id - !s.ReadUint16(&handle.suite.aeadId) || // cipher_suite.aead_id - !s.ReadUint8(&handle.configId) || // config_id - !s.ReadUint16LengthPrefixed(&t) || // enc - !t.ReadBytes(&handle.enc, len(t)) { - return false - } - return true -} - -// hpkeSymmetricCipherSuite represents an ECH ciphersuite, a KDF/AEAD algorithm pair. This -// is different from an HPKE ciphersuite, which represents a KEM/KDF/AEAD -// triple. -type hpkeSymmetricCipherSuite struct { - kdfId, aeadId uint16 -} - -// Generates a grease ECH extension using a hard-coded KEM public key. -func echGenerateGreaseExt(rand io.Reader) ([]byte, error) { - var err error - dummyX25519PublicKey := []byte{ - 143, 38, 37, 36, 12, 6, 229, 30, 140, 27, 167, 73, 26, 100, 203, 107, 216, - 81, 163, 222, 52, 211, 54, 210, 46, 37, 78, 216, 157, 97, 241, 244, - } - dummyEncodedHelloInnerLen := 100 // TODO(cjpatton): Compute this correctly. - kem, kdf, aead := defaultHPKESuite.Params() - - pk, err := kem.Scheme().UnmarshalBinaryPublicKey(dummyX25519PublicKey) - if err != nil { - return nil, fmt.Errorf("tls: grease ech: failed to parse dummy public key: %s", err) - } - sender, err := defaultHPKESuite.NewSender(pk, nil) - if err != nil { - return nil, fmt.Errorf("tls: grease ech: failed to create sender: %s", err) - } - - var ech echClientOuter - ech.handle.suite.kdfId = uint16(kdf) - ech.handle.suite.aeadId = uint16(aead) - randomByte := make([]byte, 1) - _, err = io.ReadFull(rand, randomByte) - if err != nil { - return nil, fmt.Errorf("tls: grease ech: %s", err) - } - ech.handle.configId = randomByte[0] - ech.handle.enc, _, err = sender.Setup(rand) - if err != nil { - return nil, fmt.Errorf("tls: grease ech: %s", err) - } - ech.payload = make([]byte, - int(aead.CipherLen(uint(dummyEncodedHelloInnerLen)))) - if _, err = io.ReadFull(rand, ech.payload); err != nil { - return nil, fmt.Errorf("tls: grease ech: %s", err) - } - return ech.marshal(), nil -} - -// echEncodeClientHelloInner interprets innerData as a ClientHelloInner message -// and transforms it into an EncodedClientHelloInner. Returns nil if parsing -// innerData fails. -func echEncodeClientHelloInner(innerData []byte, serverNameLen, maxNameLen int) []byte { - var ( - errIllegalParameter = errors.New("illegal parameter") - outerExtensions = echOuterExtensions() - msgType uint8 - legacyVersion uint16 - random []byte - legacySessionId cryptobyte.String - cipherSuites cryptobyte.String - legacyCompressionMethods cryptobyte.String - extensions cryptobyte.String - s cryptobyte.String - b cryptobyte.Builder - ) - - u := cryptobyte.String(innerData) - if !u.ReadUint8(&msgType) || - !u.ReadUint24LengthPrefixed(&s) || !u.Empty() { - return nil - } - - if !s.ReadUint16(&legacyVersion) || - !s.ReadBytes(&random, 32) || - !s.ReadUint8LengthPrefixed(&legacySessionId) || - !s.ReadUint16LengthPrefixed(&cipherSuites) || - !s.ReadUint8LengthPrefixed(&legacyCompressionMethods) { - return nil - } - - if s.Empty() { - // Extensions field must be present in TLS 1.3. - return nil - } - - if !s.ReadUint16LengthPrefixed(&extensions) || !s.Empty() { - return nil - } - - b.AddUint16(legacyVersion) - b.AddBytes(random) - b.AddUint8(0) // 0-length legacy_session_id - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(cipherSuites) - }) - b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(legacyCompressionMethods) - }) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - if testingECHOuterExtIncorrectOrder { - // Replace outer extensions with "outer_extension" extension, but in - // the incorrect order. - echAddOuterExtensions(b, outerExtensions) - } - - for !extensions.Empty() { - var ext uint16 - var extData cryptobyte.String - if !extensions.ReadUint16(&ext) || - !extensions.ReadUint16LengthPrefixed(&extData) { - panic(cryptobyte.BuildError{Err: errIllegalParameter}) - } - - if len(outerExtensions) > 0 && ext == outerExtensions[0] { - if !testingECHOuterExtIncorrectOrder { - // Replace outer extensions with "outer_extension" extension. - echAddOuterExtensions(b, outerExtensions) - } - - // Consume the remaining outer extensions. - for _, outerExt := range outerExtensions[1:] { - if !extensions.ReadUint16(&ext) || - !extensions.ReadUint16LengthPrefixed(&extData) { - panic(cryptobyte.BuildError{Err: errIllegalParameter}) - } - if ext != outerExt { - panic("internal error: malformed ClientHelloInner") - } - } - - } else { - b.AddUint16(ext) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(extData) - }) - } - } - }) - - encodedData, err := b.Bytes() - if err == errIllegalParameter { - return nil // Input malformed - } else if err != nil { - panic(err) // Host encountered internal error - } - - // Add padding. - paddingLen := 0 - if serverNameLen > 0 { - // draft-ietf-tls-esni-13, Section 6.1.3: - // - // If the ClientHelloInner contained a "server_name" extension with a - // name of length D, add max(0, L - D) bytes of padding. - if n := maxNameLen - serverNameLen; n > 0 { - paddingLen += n - } - } else { - // draft-ietf-tls-esni-13, Section 6.1.3: - // - // If the ClientHelloInner did not contain a "server_name" extension - // (e.g., if the client is connecting to an IP address), add L + 9 bytes - // of padding. This is the length of a "server_name" extension with an - // L-byte name. - const sniPaddingLen = 9 - paddingLen += sniPaddingLen + maxNameLen - } - paddingLen = 31 - ((len(encodedData) + paddingLen - 1) % 32) - for i := 0; i < paddingLen; i++ { - encodedData = append(encodedData, 0) - } - - return encodedData -} - -func echAddOuterExtensions(b *cryptobyte.Builder, outerExtensions []uint16) { - b.AddUint16(extensionECHOuterExtensions) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { - for _, outerExt := range outerExtensions { - b.AddUint16(outerExt) - } - if testingECHOuterExtIllegal { - // This is not allowed. - b.AddUint16(extensionECH) - } - }) - }) -} - -// echDecodeClientHelloInner interprets encodedData as an EncodedClientHelloInner -// message and substitutes the "outer_extension" extension with extensions from -// outerData, interpreted as the ClientHelloOuter message. Returns nil if -// parsing encodedData fails. -func echDecodeClientHelloInner(encodedData, outerData, outerSessionId []byte) []byte { - var ( - errIllegalParameter = errors.New("illegal parameter") - legacyVersion uint16 - random []byte - legacySessionId cryptobyte.String - cipherSuites cryptobyte.String - legacyCompressionMethods cryptobyte.String - extensions cryptobyte.String - b cryptobyte.Builder - ) - - s := cryptobyte.String(encodedData) - if !s.ReadUint16(&legacyVersion) || - !s.ReadBytes(&random, 32) || - !s.ReadUint8LengthPrefixed(&legacySessionId) || - !s.ReadUint16LengthPrefixed(&cipherSuites) || - !s.ReadUint8LengthPrefixed(&legacyCompressionMethods) { - return nil - } - - if len(legacySessionId) > 0 { - return nil - } - - if s.Empty() { - // Extensions field must be present in TLS 1.3. - return nil - } - - if !s.ReadUint16LengthPrefixed(&extensions) { - return nil - } - - b.AddUint8(typeClientHello) - b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddUint16(legacyVersion) - b.AddBytes(random) - b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(outerSessionId) // ClientHelloOuter.legacy_session_id - }) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(cipherSuites) - }) - b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(legacyCompressionMethods) - }) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - var handledOuterExtensions bool - for !extensions.Empty() { - var ext uint16 - var extData cryptobyte.String - if !extensions.ReadUint16(&ext) || - !extensions.ReadUint16LengthPrefixed(&extData) { - panic(cryptobyte.BuildError{Err: errIllegalParameter}) - } - - if ext == extensionECHOuterExtensions { - if handledOuterExtensions { - // It is an error to send any extension more than once in a - // single message. - panic(cryptobyte.BuildError{Err: errIllegalParameter}) - } - handledOuterExtensions = true - - // Read the referenced outer extensions. - referencedExts := make([]uint16, 0, 10) - var outerExtData cryptobyte.String - if !extData.ReadUint8LengthPrefixed(&outerExtData) || - len(outerExtData)%2 != 0 || - !extData.Empty() { - panic(cryptobyte.BuildError{Err: errIllegalParameter}) - } - for !outerExtData.Empty() { - if !outerExtData.ReadUint16(&ext) || - ext == extensionECH { - panic(cryptobyte.BuildError{Err: errIllegalParameter}) - } - referencedExts = append(referencedExts, ext) - } - - // Add the outer extensions from the ClientHelloOuter into the - // ClientHelloInner. - outerCt := 0 - r := processClientHelloExtensions(outerData, func(ext uint16, extData cryptobyte.String) bool { - if outerCt < len(referencedExts) && ext == referencedExts[outerCt] { - outerCt++ - b.AddUint16(ext) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(extData) - }) - } - return true - }) - - // Ensure that all outer extensions have been incorporated - // exactly once, and in the correct order. - if !r || outerCt != len(referencedExts) { - panic(cryptobyte.BuildError{Err: errIllegalParameter}) - } - } else { - b.AddUint16(ext) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(extData) - }) - } - } - }) - }) - - innerData, err := b.Bytes() - if err == errIllegalParameter { - return nil // Input malformed - } else if err != nil { - panic(err) // Host encountered internal error - } - - // Read the padding. - for !s.Empty() { - var zero uint8 - if !s.ReadUint8(&zero) || zero != 0 { - return nil - } - } - - return innerData -} - -// echEncodeClientHelloOuterAAD interprets outerData as ClientHelloOuter and -// constructs a ClientHelloOuterAAD. The output doesn't have the 4-byte prefix -// that indicates the handshake message type and its length. -func echEncodeClientHelloOuterAAD(outerData []byte, payloadLen uint) []byte { - var ( - errIllegalParameter = errors.New("illegal parameter") - msgType uint8 - legacyVersion uint16 - random []byte - legacySessionId cryptobyte.String - cipherSuites cryptobyte.String - legacyCompressionMethods cryptobyte.String - extensions cryptobyte.String - s cryptobyte.String - b cryptobyte.Builder - ) - - u := cryptobyte.String(outerData) - if !u.ReadUint8(&msgType) || - !u.ReadUint24LengthPrefixed(&s) || !u.Empty() { - return nil - } - - if !s.ReadUint16(&legacyVersion) || - !s.ReadBytes(&random, 32) || - !s.ReadUint8LengthPrefixed(&legacySessionId) || - !s.ReadUint16LengthPrefixed(&cipherSuites) || - !s.ReadUint8LengthPrefixed(&legacyCompressionMethods) { - return nil - } - - if s.Empty() { - // Extensions field must be present in TLS 1.3. - return nil - } - - if !s.ReadUint16LengthPrefixed(&extensions) || !s.Empty() { - return nil - } - - b.AddUint16(legacyVersion) - b.AddBytes(random) - b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(legacySessionId) - }) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(cipherSuites) - }) - b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(legacyCompressionMethods) - }) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - for !extensions.Empty() { - var ext uint16 - var extData cryptobyte.String - if !extensions.ReadUint16(&ext) || - !extensions.ReadUint16LengthPrefixed(&extData) { - panic(cryptobyte.BuildError{Err: errIllegalParameter}) - } - - // If this is the ECH extension and the payload is the outer variant - // of ClientECH, then replace the payloadLen 0 bytes. - if ext == extensionECH { - ech, err := echUnmarshalClientOuter(extData) - if err != nil { - panic(cryptobyte.BuildError{Err: errIllegalParameter}) - } - ech.payload = make([]byte, payloadLen) - ech.raw = nil - extData = ech.marshal() - } - - b.AddUint16(ext) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(extData) - }) - } - }) - - outerAadData, err := b.Bytes() - if err == errIllegalParameter { - return nil // Input malformed - } else if err != nil { - panic(err) // Host encountered internal error - } - - return outerAadData -} - -// echEncodeAcceptConfHelloRetryRequest interprets data as a ServerHello message -// and replaces the payload of the ECH extension with 8 zero bytes. The output -// includes the 4-byte prefix that indicates the message type and its length. -func echEncodeAcceptConfHelloRetryRequest(data []byte) []byte { - var ( - errIllegalParameter = errors.New("illegal parameter") - vers uint16 - random []byte - sessionId []byte - cipherSuite uint16 - compressionMethod uint8 - s cryptobyte.String - b cryptobyte.Builder - ) - - s = cryptobyte.String(data) - if !s.Skip(4) || // message type and uint24 length field - !s.ReadUint16(&vers) || !s.ReadBytes(&random, 32) || - !readUint8LengthPrefixed(&s, &sessionId) || - !s.ReadUint16(&cipherSuite) || - !s.ReadUint8(&compressionMethod) { - return nil - } - - if s.Empty() { - // ServerHello is optionally followed by extension data - return nil - } - - var extensions cryptobyte.String - if !s.ReadUint16LengthPrefixed(&extensions) || !s.Empty() { - return nil - } - - b.AddUint8(typeServerHello) - b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddUint16(vers) - b.AddBytes(random) - b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(sessionId) - }) - b.AddUint16(cipherSuite) - b.AddUint8(compressionMethod) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - for !extensions.Empty() { - var extension uint16 - var extData cryptobyte.String - if !extensions.ReadUint16(&extension) || - !extensions.ReadUint16LengthPrefixed(&extData) { - panic(cryptobyte.BuildError{Err: errIllegalParameter}) - } - - b.AddUint16(extension) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - if extension == extensionECH { - b.AddBytes(zeros[:8]) - } else { - b.AddBytes(extData) - } - }) - } - }) - }) - - encodedData, err := b.Bytes() - if err == errIllegalParameter { - return nil // Input malformed - } else if err != nil { - panic(err) // Host encountered internal error - } - - return encodedData -} - -// processClientHelloExtensions interprets data as a ClientHello and applies a -// function proc to each extension. Returns a bool indicating whether parsing -// succeeded. -func processClientHelloExtensions(data []byte, proc func(ext uint16, extData cryptobyte.String) bool) bool { - _, extensionsData := splitClientHelloExtensions(data) - if extensionsData == nil { - return false - } - - s := cryptobyte.String(extensionsData) - if s.Empty() { - // Extensions field not present. - return true - } - - var extensions cryptobyte.String - if !s.ReadUint16LengthPrefixed(&extensions) || !s.Empty() { - return false - } - - for !extensions.Empty() { - var ext uint16 - var extData cryptobyte.String - if !extensions.ReadUint16(&ext) || - !extensions.ReadUint16LengthPrefixed(&extData) { - return false - } - if ok := proc(ext, extData); !ok { - return false - } - } - return true -} - -// splitClientHelloExtensions interprets data as a ClientHello message and -// returns two strings: the first contains the start of the ClientHello up to -// the start of the extensions; and the second is the length-prefixed -// extensions. Returns (nil, nil) if parsing of data fails. -func splitClientHelloExtensions(data []byte) ([]byte, []byte) { - s := cryptobyte.String(data) - - var ignored uint16 - var t cryptobyte.String - if !s.Skip(4) || // message type and uint24 length field - !s.ReadUint16(&ignored) || !s.Skip(32) || // vers, random - !s.ReadUint8LengthPrefixed(&t) { // session_id - return nil, nil - } - - if !s.ReadUint16LengthPrefixed(&t) { // cipher_suites - return nil, nil - } - - if !s.ReadUint8LengthPrefixed(&t) { // compression_methods - return nil, nil - } - - return data[:len(data)-len(s)], s -} - -// TODO(cjpatton): Handle public name as described in draft-ietf-tls-esni-13, -// Section 4. -// -// TODO(cjpatton): Implement ECH config extensions as described in -// draft-ietf-tls-esni-13, Section 4.1. -func (c *Config) echSelectConfig(ctx context.Context, serverName string) (*ECHConfig, error) { - for _, echConfig := range c.ClientECHConfigs { - if _, err := echConfig.selectSuite(); err == nil && - echConfig.version == extensionECH { - return &echConfig, nil - } - } - if c.GetClientECHConfigs != nil { - echConfigs, err := c.GetClientECHConfigs(ctx, serverName) - if err != nil { - return nil, err - } - for _, echConfig := range echConfigs { - if _, err = echConfig.selectSuite(); err == nil && - echConfig.version == extensionECH { - return &echConfig, nil - } - } - } - return nil, nil -} - -func (c *Config) echCanOffer() bool { - if c == nil { - return false - } - return c.ECHEnabled && - c.maxSupportedVersion(roleClient) >= VersionTLS13 -} - -func (c *Config) echCanAccept() bool { - if c == nil { - return false - } - return c.ECHEnabled && - c.ServerECHProvider != nil && - c.maxSupportedVersion(roleServer) >= VersionTLS13 -} - -// echOuterExtensions returns the list of extensions of the ClientHelloOuter -// that will be incorporated into the CleintHelloInner. -func echOuterExtensions() []uint16 { - // NOTE(cjpatton): It would be nice to incorporate more extensions, but - // "key_share" is the last extension to appear in the ClientHello before - // "pre_shared_key". As a result, the only contiguous sequence of outer - // extensions that contains "key_share" is "key_share" itself. Note that - // we cannot change the order of extensions in the ClientHello, as the - // unit tests expect "key_share" to be the second to last extension. - outerExtensions := []uint16{extensionKeyShare} - if testingECHOuterExtMany { - // NOTE(cjpatton): Incorporating this particular sequence does not - // yield significant savings. However, it's useful to test that our - // server correctly handles a sequence of compressed extensions and - // not just one. - outerExtensions = []uint16{ - extensionStatusRequest, - extensionSupportedCurves, - extensionSupportedPoints, - } - } else if testingECHOuterExtNone { - outerExtensions = []uint16{} - } - - return outerExtensions -} - -func echCopyExtensionFromClientHelloInner(hello, helloInner *clientHelloMsg, ext uint16) { - switch ext { - case extensionStatusRequest: - hello.ocspStapling = helloInner.ocspStapling - case extensionSupportedCurves: - hello.supportedCurves = helloInner.supportedCurves - case extensionSupportedPoints: - hello.supportedPoints = helloInner.supportedPoints - case extensionKeyShare: - hello.keyShares = helloInner.keyShares - default: - panic(fmt.Errorf("tried to copy unrecognized extension: %04x", ext)) - } -} diff --git a/transport/cloudflaretls/ech_config.go b/transport/cloudflaretls/ech_config.go deleted file mode 100644 index 29e46987..00000000 --- a/transport/cloudflaretls/ech_config.go +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright 2020 Cloudflare, Inc. All rights reserved. Use of this source code -// is governed by a BSD-style license that can be found in the LICENSE file. - -package tls - -import ( - "errors" - "fmt" - "io" - - "github.com/cloudflare/circl/hpke" - "github.com/cloudflare/circl/kem" - "golang.org/x/crypto/cryptobyte" -) - -// ECHConfig represents an ECH configuration. -type ECHConfig struct { - pk kem.PublicKey - raw []byte - - // Parsed from raw - version uint16 - configId uint8 - rawPublicName []byte - rawPublicKey []byte - kemId uint16 - suites []hpkeSymmetricCipherSuite - maxNameLen uint8 - ignoredExtensions []byte -} - -// UnmarshalECHConfigs parses a sequence of ECH configurations. -func UnmarshalECHConfigs(raw []byte) ([]ECHConfig, error) { - var ( - err error - config ECHConfig - t, contents cryptobyte.String - ) - configs := make([]ECHConfig, 0) - s := cryptobyte.String(raw) - if !s.ReadUint16LengthPrefixed(&t) || !s.Empty() { - return configs, errors.New("error parsing configs") - } - raw = raw[2:] -ConfigsLoop: - for !t.Empty() { - l := len(t) - if !t.ReadUint16(&config.version) || - !t.ReadUint16LengthPrefixed(&contents) { - return nil, errors.New("error parsing config") - } - n := l - len(t) - config.raw = raw[:n] - raw = raw[n:] - - if config.version != extensionECH { - continue ConfigsLoop - } - if !readConfigContents(&contents, &config) { - return nil, errors.New("error parsing config contents") - } - - kem := hpke.KEM(config.kemId) - if !kem.IsValid() { - continue ConfigsLoop - } - config.pk, err = kem.Scheme().UnmarshalBinaryPublicKey(config.rawPublicKey) - if err != nil { - return nil, fmt.Errorf("error parsing public key: %s", err) - } - configs = append(configs, config) - } - return configs, nil -} - -func echMarshalConfigs(configs []ECHConfig) ([]byte, error) { - var b cryptobyte.Builder - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - for _, config := range configs { - if config.raw == nil { - panic("config.raw not set") - } - b.AddBytes(config.raw) - } - }) - return b.Bytes() -} - -func readConfigContents(contents *cryptobyte.String, config *ECHConfig) bool { - var t cryptobyte.String - if !contents.ReadUint8(&config.configId) || - !contents.ReadUint16(&config.kemId) || - !contents.ReadUint16LengthPrefixed(&t) || - !t.ReadBytes(&config.rawPublicKey, len(t)) || - !contents.ReadUint16LengthPrefixed(&t) || - len(t)%4 != 0 { - return false - } - - config.suites = nil - for !t.Empty() { - var kdfId, aeadId uint16 - if !t.ReadUint16(&kdfId) || !t.ReadUint16(&aeadId) { - // This indicates an internal bug. - panic("internal error while parsing contents.cipher_suites") - } - config.suites = append(config.suites, hpkeSymmetricCipherSuite{kdfId, aeadId}) - } - - if !contents.ReadUint8(&config.maxNameLen) || - !contents.ReadUint8LengthPrefixed(&t) || - !t.ReadBytes(&config.rawPublicName, len(t)) || - !contents.ReadUint16LengthPrefixed(&t) || - !t.ReadBytes(&config.ignoredExtensions, len(t)) || - !contents.Empty() { - return false - } - return true -} - -// setupSealer generates the client's HPKE context for use with the ECH -// extension. It returns the context and corresponding encapsulated key. -func (config *ECHConfig) setupSealer(rand io.Reader) (enc []byte, sealer hpke.Sealer, err error) { - if config.raw == nil { - panic("config.raw not set") - } - hpkeSuite, err := config.selectSuite() - if err != nil { - return nil, nil, err - } - info := append(append([]byte(echHpkeInfoSetup), 0), config.raw...) - sender, err := hpkeSuite.NewSender(config.pk, info) - if err != nil { - return nil, nil, err - } - return sender.Setup(rand) -} - -// isPeerCipherSuiteSupported returns true if this configuration indicates -// support for the given ciphersuite. -func (config *ECHConfig) isPeerCipherSuiteSupported(suite hpkeSymmetricCipherSuite) bool { - for _, configSuite := range config.suites { - if suite == configSuite { - return true - } - } - return false -} - -// selectSuite returns the first ciphersuite indicated by this -// configuration that is supported by the caller. -func (config *ECHConfig) selectSuite() (hpke.Suite, error) { - for _, suite := range config.suites { - hpkeSuite, err := hpkeAssembleSuite( - config.kemId, - suite.kdfId, - suite.aeadId, - ) - if err == nil { - return hpkeSuite, nil - } - } - return hpke.Suite{}, errors.New("could not negotiate a ciphersuite") -} diff --git a/transport/cloudflaretls/ech_provider.go b/transport/cloudflaretls/ech_provider.go deleted file mode 100644 index 1cc01c8a..00000000 --- a/transport/cloudflaretls/ech_provider.go +++ /dev/null @@ -1,302 +0,0 @@ -// Copyright 2020 Cloudflare, Inc. All rights reserved. Use of this source code -// is governed by a BSD-style license that can be found in the LICENSE file. - -package tls - -import ( - "errors" - "fmt" - - "github.com/cloudflare/circl/hpke" - "github.com/cloudflare/circl/kem" - "golang.org/x/crypto/cryptobyte" -) - -// ECHProvider specifies the interface of an ECH service provider that decrypts -// the ECH payload on behalf of the client-facing server. It also defines the -// set of acceptable ECH configurations. -type ECHProvider interface { - // GetDecryptionContext attempts to construct the HPKE context used by the - // client-facing server for decryption. (See draft-irtf-cfrg-hpke-07, - // Section 5.2.) - // - // handle encodes the parameters of the client's "encrypted_client_hello" - // extension that are needed to construct the context. Since - // draft-ietf-tls-esni-10 these are the ECH cipher suite, the identity of - // the ECH configuration, and the encapsulated key. - // - // version is the version of ECH indicated by the client. - // - // res.Status == ECHProviderStatusSuccess indicates the call was successful - // and the caller may proceed. res.Context is set. - // - // res.Status == ECHProviderStatusReject indicates the caller must reject - // ECH. res.RetryConfigs may be set. - // - // res.Status == ECHProviderStatusAbort indicates the caller should abort - // the handshake. Note that, in some cases, it's appropriate to reject - // rather than abort. In particular, aborting with "illegal_parameter" might - // "stick out". res.Alert and res.Error are set. - GetDecryptionContext(handle []byte, version uint16) (res ECHProviderResult) -} - -// ECHProviderStatus is the status of the ECH provider's response. -type ECHProviderStatus uint - -const ( - ECHProviderSuccess ECHProviderStatus = 0 - ECHProviderReject = 1 - ECHProviderAbort = 2 - - errHPKEInvalidPublicKey = "hpke: invalid KEM public key" -) - -// ECHProviderResult represents the result of invoking the ECH provider. -type ECHProviderResult struct { - Status ECHProviderStatus - - // Alert is the TLS alert sent by the caller when aborting the handshake. - Alert uint8 - - // Error is the error propagated by the caller when aborting the handshake. - Error error - - // RetryConfigs is the sequence of ECH configs to offer to the client for - // retrying the handshake. This may be set in case of success or rejection. - RetryConfigs []byte - - // Context is the server's HPKE context. This is set if ECH is not rejected - // by the provider and no error was reported. The data has the following - // format (in TLS syntax): - // - // enum { sealer(0), opener(1) } HpkeRole; - // - // struct { - // HpkeRole role; - // HpkeKemId kem_id; // as defined in draft-irtf-cfrg-hpke-07 - // HpkeKdfId kdf_id; // as defined in draft-irtf-cfrg-hpke-07 - // HpkeAeadId aead_id; // as defined in draft-irtf-cfrg-hpke-07 - // opaque exporter_secret<0..255>; - // opaque key<0..255>; - // opaque base_nonce<0..255>; - // opaque seq<0..255>; - // } HpkeContext; - Context []byte -} - -// EXP_ECHKeySet implements the ECHProvider interface for a sequence of ECH keys. -// -// NOTE: This API is EXPERIMENTAL and subject to change. -type EXP_ECHKeySet struct { - // The serialized ECHConfigs, in order of the server's preference. - configs []byte - - // Maps a configuration identifier to its secret key. - sk map[uint8]EXP_ECHKey -} - -// EXP_NewECHKeySet constructs an EXP_ECHKeySet. -func EXP_NewECHKeySet(keys []EXP_ECHKey) (*EXP_ECHKeySet, error) { - if len(keys) > 255 { - return nil, fmt.Errorf("tls: ech provider: unable to support more than 255 ECH configurations at once") - } - - keySet := new(EXP_ECHKeySet) - keySet.sk = make(map[uint8]EXP_ECHKey) - configs := make([]byte, 0) - for _, key := range keys { - if _, ok := keySet.sk[key.config.configId]; ok { - return nil, fmt.Errorf("tls: ech provider: ECH config conflict for configId %d", key.config.configId) - } - - keySet.sk[key.config.configId] = key - configs = append(configs, key.config.raw...) - } - - var b cryptobyte.Builder - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(configs) - }) - keySet.configs = b.BytesOrPanic() - - return keySet, nil -} - -// GetDecryptionContext is required by the ECHProvider interface. -func (keySet *EXP_ECHKeySet) GetDecryptionContext(rawHandle []byte, version uint16) (res ECHProviderResult) { - // Propagate retry configurations regardless of the result. The caller sends - // these to the clients only if it rejects. - res.RetryConfigs = keySet.configs - - // Ensure we know how to proceed, i.e., the caller has indicated a supported - // version of ECH. Currently only draft-ietf-tls-esni-13 is supported. - if version != extensionECH { - res.Status = ECHProviderAbort - res.Alert = uint8(alertInternalError) - res.Error = errors.New("version not supported") - return // Abort - } - - // Parse the handle. - s := cryptobyte.String(rawHandle) - handle := new(echContextHandle) - if !echReadContextHandle(&s, handle) || !s.Empty() { - // This is the result of a client-side error. However, aborting with - // "illegal_parameter" would stick out, so we reject instead. - res.Status = ECHProviderReject - res.RetryConfigs = keySet.configs - return // Reject - } - handle.raw = rawHandle - - // Look up the secret key for the configuration indicated by the client. - key, ok := keySet.sk[handle.configId] - if !ok { - res.Status = ECHProviderReject - res.RetryConfigs = keySet.configs - return // Reject - } - - // Ensure that support for the selected ciphersuite is indicated by the - // configuration. - suite := handle.suite - if !key.config.isPeerCipherSuiteSupported(suite) { - // This is the result of a client-side error. However, aborting with - // "illegal_parameter" would stick out, so we reject instead. - res.Status = ECHProviderReject - res.RetryConfigs = keySet.configs - return // Reject - } - - // Ensure the version indicated by the client matches the version supported - // by the configuration. - if version != key.config.version { - // This is the result of a client-side error. However, aborting with - // "illegal_parameter" would stick out, so we reject instead. - res.Status = ECHProviderReject - res.RetryConfigs = keySet.configs - return // Reject - } - - // Compute the decryption context. - opener, err := key.setupOpener(handle.enc, suite) - if err != nil { - if err.Error() == errHPKEInvalidPublicKey { - // This occurs if the KEM algorithm used to generate handle.enc is - // not the same as the KEM algorithm of the key. One way this can - // happen is if the client sent a GREASE ECH extension with a - // config_id that happens to match a known config, but which uses a - // different KEM algorithm. - res.Status = ECHProviderReject - res.RetryConfigs = keySet.configs - return // Reject - } - - res.Status = ECHProviderAbort - res.Alert = uint8(alertInternalError) - res.Error = err - return // Abort - } - - // Serialize the decryption context. - res.Context, err = opener.MarshalBinary() - if err != nil { - res.Status = ECHProviderAbort - res.Alert = uint8(alertInternalError) - res.Error = err - return // Abort - } - - res.Status = ECHProviderSuccess - return // Success -} - -// EXP_ECHKey represents an ECH key and its corresponding configuration. The -// encoding of an ECH Key has the format defined below (in TLS syntax). Note -// that the ECH standard does not specify this format. -// -// struct { -// opaque sk<0..2^16-1>; -// ECHConfig config<0..2^16>; // draft-ietf-tls-esni-13 -// } ECHKey; -type EXP_ECHKey struct { - sk kem.PrivateKey - config ECHConfig -} - -// EXP_UnmarshalECHKeys parses a sequence of ECH keys. -func EXP_UnmarshalECHKeys(raw []byte) ([]EXP_ECHKey, error) { - var ( - err error - key EXP_ECHKey - sk, config, contents cryptobyte.String - ) - s := cryptobyte.String(raw) - keys := make([]EXP_ECHKey, 0) -KeysLoop: - for !s.Empty() { - if !s.ReadUint16LengthPrefixed(&sk) || - !s.ReadUint16LengthPrefixed(&config) { - return nil, errors.New("error parsing key") - } - - key.config.raw = config - if !config.ReadUint16(&key.config.version) || - !config.ReadUint16LengthPrefixed(&contents) || - !config.Empty() { - return nil, errors.New("error parsing config") - } - - if key.config.version != extensionECH { - continue KeysLoop - } - if !readConfigContents(&contents, &key.config) { - return nil, errors.New("error parsing config contents") - } - - for _, suite := range key.config.suites { - if !hpke.KDF(suite.kdfId).IsValid() || - !hpke.AEAD(suite.aeadId).IsValid() { - continue KeysLoop - } - } - - kem := hpke.KEM(key.config.kemId) - if !kem.IsValid() { - continue KeysLoop - } - key.config.pk, err = kem.Scheme().UnmarshalBinaryPublicKey(key.config.rawPublicKey) - if err != nil { - return nil, fmt.Errorf("error parsing public key: %s", err) - } - key.sk, err = kem.Scheme().UnmarshalBinaryPrivateKey(sk) - if err != nil { - return nil, fmt.Errorf("error parsing secret key: %s", err) - } - - keys = append(keys, key) - } - return keys, nil -} - -// setupOpener computes the HPKE context used by the server in the ECH -// extension.i -func (key *EXP_ECHKey) setupOpener(enc []byte, suite hpkeSymmetricCipherSuite) (hpke.Opener, error) { - if key.config.raw == nil { - panic("raw config not set") - } - hpkeSuite, err := hpkeAssembleSuite( - key.config.kemId, - suite.kdfId, - suite.aeadId, - ) - if err != nil { - return nil, err - } - info := append(append([]byte(echHpkeInfoSetup), 0), key.config.raw...) - receiver, err := hpkeSuite.NewReceiver(key.sk, info) - if err != nil { - return nil, err - } - return receiver.Setup(enc) -} diff --git a/transport/cloudflaretls/generate_cert.go b/transport/cloudflaretls/generate_cert.go deleted file mode 100644 index 7dc4904f..00000000 --- a/transport/cloudflaretls/generate_cert.go +++ /dev/null @@ -1,194 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build ignore - -// Generate a self-signed X.509 certificate for a TLS server. Outputs to -// 'cert.pem' and 'key.pem' and will overwrite existing files. - -package main - -import ( - "crypto/ecdsa" - "crypto/ed25519" - "crypto/elliptic" - "crypto/rand" - "crypto/rsa" - "crypto/x509" - "crypto/x509/pkix" - "encoding/pem" - "flag" - "log" - "math/big" - "net" - "os" - "strings" - "time" - - circlSign "github.com/cloudflare/circl/sign" - circlSchemes "github.com/cloudflare/circl/sign/schemes" -) - -var ( - host = flag.String("host", "", "Comma-separated hostnames and IPs to generate a certificate for") - validFrom = flag.String("start-date", "", "Creation date formatted as Jan 1 15:04:05 2011") - validFor = flag.Duration("duration", 365*24*time.Hour, "Duration that certificate is valid for") - isCA = flag.Bool("ca", false, "whether this cert should be its own Certificate Authority") - allowDC = flag.Bool("allowDC", false, "whether this cert can be used with Delegated Credentials") - rsaBits = flag.Int("rsa-bits", 2048, "Size of RSA key to generate. Ignored if --ecdsa-curve is set") - ecdsaCurve = flag.String("ecdsa-curve", "", "ECDSA curve to use to generate a key. Valid values are P224, P256 (recommended), P384, P521") - ed25519Key = flag.Bool("ed25519", false, "Generate an Ed25519 key") - circlKey = flag.String("github.com/cloudflare/circl", "", "Generate a key supported by Circl") -) - -func publicKey(priv any) any { - switch k := priv.(type) { - case *rsa.PrivateKey: - return &k.PublicKey - case *ecdsa.PrivateKey: - return &k.PublicKey - case ed25519.PrivateKey: - return k.Public().(ed25519.PublicKey) - case circlSign.PrivateKey: - return k.Public() - default: - return nil - } -} - -func main() { - flag.Parse() - - if len(*host) == 0 { - log.Fatalf("Missing required --host parameter") - } - - var priv any - var err error - switch *ecdsaCurve { - case "": - if *ed25519Key { - _, priv, err = ed25519.GenerateKey(rand.Reader) - } else if *circlKey != "" { - scheme := circlSchemes.ByName(*circlKey) - if scheme == nil { - log.Fatalf("No such Circl scheme: %s", *circlKey) - } - _, priv, err = scheme.GenerateKey() - } else { - priv, err = rsa.GenerateKey(rand.Reader, *rsaBits) - } - case "P224": - priv, err = ecdsa.GenerateKey(elliptic.P224(), rand.Reader) - case "P256": - priv, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader) - case "P384": - priv, err = ecdsa.GenerateKey(elliptic.P384(), rand.Reader) - case "P521": - priv, err = ecdsa.GenerateKey(elliptic.P521(), rand.Reader) - default: - log.Fatalf("Unrecognized elliptic curve: %q", *ecdsaCurve) - } - if err != nil { - log.Fatalf("Failed to generate private key: %v", err) - } - - // ECDSA, ED25519 and RSA subject keys should have the DigitalSignature - // KeyUsage bits set in the x509.Certificate template - keyUsage := x509.KeyUsageDigitalSignature - // Only RSA subject keys should have the KeyEncipherment KeyUsage bits set. In - // the context of TLS this KeyUsage is particular to RSA key exchange and - // authentication. - if _, isRSA := priv.(*rsa.PrivateKey); isRSA { - keyUsage |= x509.KeyUsageKeyEncipherment - } - - var notBefore time.Time - if len(*validFrom) == 0 { - notBefore = time.Now() - } else { - notBefore, err = time.Parse("Jan 2 15:04:05 2006", *validFrom) - if err != nil { - log.Fatalf("Failed to parse creation date: %v", err) - } - } - - notAfter := notBefore.Add(*validFor) - - serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) - serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) - if err != nil { - log.Fatalf("Failed to generate serial number: %v", err) - } - - template := x509.Certificate{ - SerialNumber: serialNumber, - Subject: pkix.Name{ - Organization: []string{"Acme Co"}, - }, - NotBefore: notBefore, - NotAfter: notAfter, - - KeyUsage: keyUsage, - ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, - BasicConstraintsValid: true, - } - - hosts := strings.Split(*host, ",") - for _, h := range hosts { - if ip := net.ParseIP(h); ip != nil { - template.IPAddresses = append(template.IPAddresses, ip) - } else { - template.DNSNames = append(template.DNSNames, h) - } - } - - if *isCA { - if *allowDC { - log.Fatal("Failed to create certificate: ca is not allowed with the dc flag") - } - - template.IsCA = true - template.KeyUsage |= x509.KeyUsageCertSign - } - - if *allowDC { - template.AllowDC = true - template.KeyUsage |= x509.KeyUsageDigitalSignature - } - - derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey(priv), priv) - if err != nil { - log.Fatalf("Failed to create certificate: %v", err) - } - - certOut, err := os.Create("cert.pem") - if err != nil { - log.Fatalf("Failed to open cert.pem for writing: %v", err) - } - if err := pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil { - log.Fatalf("Failed to write data to cert.pem: %v", err) - } - if err := certOut.Close(); err != nil { - log.Fatalf("Error closing cert.pem: %v", err) - } - log.Print("wrote cert.pem\n") - - keyOut, err := os.OpenFile("key.pem", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o600) - if err != nil { - log.Fatalf("Failed to open key.pem for writing: %v", err) - return - } - privBytes, err := x509.MarshalPKCS8PrivateKey(priv) - if err != nil { - log.Fatalf("Unable to marshal private key: %v", err) - } - if err := pem.Encode(keyOut, &pem.Block{Type: "PRIVATE KEY", Bytes: privBytes}); err != nil { - log.Fatalf("Failed to write data to key.pem: %v", err) - } - if err := keyOut.Close(); err != nil { - log.Fatalf("Error closing key.pem: %v", err) - } - log.Print("wrote key.pem\n") -} diff --git a/transport/cloudflaretls/generate_delegated_credential.go b/transport/cloudflaretls/generate_delegated_credential.go deleted file mode 100644 index 1b72b414..00000000 --- a/transport/cloudflaretls/generate_delegated_credential.go +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright 2022 Cloudflare, Inc. All rights reserved. Use of this source code -// is governed by a BSD-style license that can be found in the LICENSE file. - -//go:build ignore - -// Generate a delegated credential with the given signature scheme, signed with -// the given x.509 key pair. Outputs to 'dc.cred' and 'dckey.pem' and will -// overwrite existing files. - -// Example usage: -// generate_delegated_credential -cert-path cert.pem -key-path key.pem -signature-scheme Ed25519 -duration 24h - -package main - -import ( - "crypto" - "crypto/ecdsa" - "crypto/ed25519" - "crypto/rsa" - "crypto/tls" - "crypto/x509" - "encoding/pem" - "errors" - "flag" - "fmt" - "log" - "os" - "path/filepath" - "time" - - circlSign "github.com/cloudflare/circl/sign" -) - -var ( - validFor = flag.Duration("duration", 5*24*time.Hour, "Duration that credential is valid for") - signatureScheme = flag.String("signature-scheme", "", "The signature scheme used by the DC") - certPath = flag.String("cert-path", "./cert.pem", "Path to signing cert") - keyPath = flag.String("key-path", "./key.pem", "Path to signing key") - isClient = flag.Bool("client-dc", false, "Create a client Delegated Credential") - outPath = flag.String("out-path", "./", "Path to output directory") -) - -var SigStringMap = map[string]tls.SignatureScheme{ - // ECDSA algorithms. Only constrained to a specific curve in TLS 1.3. - "ECDSAWithP256AndSHA256": tls.ECDSAWithP256AndSHA256, - "ECDSAWithP384AndSHA384": tls.ECDSAWithP384AndSHA384, - "ECDSAWithP521AndSHA512": tls.ECDSAWithP521AndSHA512, - - // EdDSA algorithms. - "Ed25519": tls.Ed25519, -} - -func main() { - flag.Parse() - sa := SigStringMap[*signatureScheme] - - cert, err := tls.LoadX509KeyPair(*certPath, *keyPath) - if err != nil { - log.Fatalf("Failed to load certificate and key: %v", err) - } - cert.Leaf, err = x509.ParseCertificate(cert.Certificate[0]) - if err != nil { - log.Fatalf("Failed to parse leaf certificate: %v", err) - } - - validTime := time.Since(cert.Leaf.NotBefore) + *validFor - dc, priv, err := tls.NewDelegatedCredential(&cert, sa, validTime, *isClient) - if err != nil { - log.Fatalf("Failed to create a DC: %v\n", err) - } - dcBytes, err := dc.Marshal() - if err != nil { - log.Fatalf("Failed to marshal DC: %v\n", err) - } - - DCOut, err := os.Create(filepath.Join(*outPath, "dc.cred")) - if err != nil { - log.Fatalf("Failed to open dc.cred for writing: %v", err) - } - - DCOut.Write(dcBytes) - if err := DCOut.Close(); err != nil { - log.Fatalf("Error closing dc.cred: %v", err) - } - log.Print("wrote dc.cred\n") - - derBytes, err := x509.MarshalPKCS8PrivateKey(priv) - if err != nil { - log.Fatalf("Failed to marshal DC private key: %v\n", err) - } - - DCKeyOut, err := os.Create(filepath.Join(*outPath, "dckey.pem")) - if err != nil { - log.Fatalf("Failed to open dckey.pem for writing: %v", err) - } - - if err := pem.Encode(DCKeyOut, &pem.Block{Type: "PRIVATE KEY", Bytes: derBytes}); err != nil { - log.Fatalf("Failed to write data to dckey.pem: %v\n", err) - } - if err := DCKeyOut.Close(); err != nil { - log.Fatalf("Error closing dckey.pem: %v\n", err) - } - log.Print("wrote dckey.pem\n") - - fmt.Println("Success") -} - -// Copied from tls.go, because it's private. -func parsePrivateKey(der []byte) (crypto.PrivateKey, error) { - if key, err := x509.ParsePKCS1PrivateKey(der); err == nil { - return key, nil - } - if key, err := x509.ParsePKCS8PrivateKey(der); err == nil { - switch key := key.(type) { - case *rsa.PrivateKey, *ecdsa.PrivateKey, ed25519.PrivateKey, circlSign.PrivateKey: - return key, nil - default: - return nil, errors.New("tls: found unknown private key type in PKCS#8 wrapping") - } - } - if key, err := x509.ParseECPrivateKey(der); err == nil { - return key, nil - } - - return nil, errors.New("tls: failed to parse private key") -} diff --git a/transport/cloudflaretls/handshake_client.go b/transport/cloudflaretls/handshake_client.go deleted file mode 100644 index d79824d2..00000000 --- a/transport/cloudflaretls/handshake_client.go +++ /dev/null @@ -1,1069 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package tls - -import ( - "bytes" - "context" - "crypto" - "crypto/ecdsa" - "crypto/ed25519" - "crypto/rsa" - "crypto/subtle" - "crypto/x509" - "errors" - "fmt" - "hash" - "io" - "net" - "strings" - "sync/atomic" - "time" - - circlSign "github.com/cloudflare/circl/sign" -) - -type clientHandshakeState struct { - c *Conn - ctx context.Context - serverHello *serverHelloMsg - hello *clientHelloMsg - suite *cipherSuite - finishedHash finishedHash - masterSecret []byte - session *ClientSessionState -} - -func (c *Conn) makeClientHello(minVersion uint16) (*clientHelloMsg, clientKeySharePrivate, error) { - config := c.config - if len(config.ServerName) == 0 && !config.InsecureSkipVerify { - return nil, nil, errors.New("tls: either ServerName or InsecureSkipVerify must be specified in the tls.Config") - } - - nextProtosLength := 0 - for _, proto := range config.NextProtos { - if l := len(proto); l == 0 || l > 255 { - return nil, nil, errors.New("tls: invalid NextProtos value") - } else { - nextProtosLength += 1 + l - } - } - if nextProtosLength > 0xffff { - return nil, nil, errors.New("tls: NextProtos values too large") - } - - supportedVersions := config.supportedVersionsFromMin(roleClient, minVersion) - if len(supportedVersions) == 0 { - return nil, nil, errors.New("tls: no supported versions satisfy MinVersion and MaxVersion") - } - - clientHelloVersion := config.maxSupportedVersion(roleClient) - // The version at the beginning of the ClientHello was capped at TLS 1.2 - // for compatibility reasons. The supported_versions extension is used - // to negotiate versions now. See RFC 8446, Section 4.2.1. - if clientHelloVersion > VersionTLS12 { - clientHelloVersion = VersionTLS12 - } - - hello := &clientHelloMsg{ - vers: clientHelloVersion, - compressionMethods: []uint8{compressionNone}, - random: make([]byte, 32), - sessionId: make([]byte, 32), - ocspStapling: true, - scts: true, - serverName: hostnameInSNI(config.ServerName), - supportedCurves: config.curvePreferences(), - supportedPoints: []uint8{pointFormatUncompressed}, - secureRenegotiationSupported: true, - alpnProtocols: config.NextProtos, - supportedVersions: supportedVersions, - } - - if c.handshakes > 0 { - hello.secureRenegotiation = c.clientFinished[:] - } - - preferenceOrder := cipherSuitesPreferenceOrder - if !hasAESGCMHardwareSupport { - preferenceOrder = cipherSuitesPreferenceOrderNoAES - } - configCipherSuites := config.cipherSuites() - hello.cipherSuites = make([]uint16, 0, len(configCipherSuites)) - - for _, suiteId := range preferenceOrder { - suite := mutualCipherSuite(configCipherSuites, suiteId) - if suite == nil { - continue - } - // Don't advertise TLS 1.2-only cipher suites unless - // we're attempting TLS 1.2. - if hello.vers < VersionTLS12 && suite.flags&suiteTLS12 != 0 { - continue - } - hello.cipherSuites = append(hello.cipherSuites, suiteId) - } - - _, err := io.ReadFull(config.rand(), hello.random) - if err != nil { - return nil, nil, errors.New("tls: short read from Rand: " + err.Error()) - } - - // A random session ID is used to detect when the server accepted a ticket - // and is resuming a session (see RFC 5077). In TLS 1.3, it's always set as - // a compatibility measure (see RFC 8446, Section 4.1.2). - if _, err := io.ReadFull(config.rand(), hello.sessionId); err != nil { - return nil, nil, errors.New("tls: short read from Rand: " + err.Error()) - } - - if hello.vers >= VersionTLS12 { - hello.supportedSignatureAlgorithms = config.supportedSignatureAlgorithms() - } - - var secret clientKeySharePrivate - if hello.supportedVersions[0] == VersionTLS13 { - if hasAESGCMHardwareSupport { - hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13...) - } else { - hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13NoAES...) - } - - curveID := config.curvePreferences()[0] - if scheme := curveIdToCirclScheme(curveID); scheme != nil { - pk, sk, err := generateKemKeyPair(scheme, config.rand()) - if err != nil { - return nil, nil, fmt.Errorf("generateKemKeyPair %s: %w", - scheme.Name(), err) - } - packedPk, err := pk.MarshalBinary() - if err != nil { - return nil, nil, fmt.Errorf("pack circl public key %s: %w", - scheme.Name(), err) - } - hello.keyShares = []keyShare{{group: curveID, data: packedPk}} - secret = sk - } else { - if _, ok := curveForCurveID(curveID); curveID != X25519 && !ok { - return nil, nil, errors.New("tls: CurvePreferences includes unsupported curve") - } - params, err := generateECDHEParameters(config.rand(), curveID) - if err != nil { - return nil, nil, err - } - hello.keyShares = []keyShare{{group: curveID, data: params.PublicKey()}} - secret = params - } - - hello.delegatedCredentialSupported = config.SupportDelegatedCredential - hello.supportedSignatureAlgorithmsDC = supportedSignatureAlgorithmsDC - } - - return hello, secret, nil -} - -func (c *Conn) clientHandshake(ctx context.Context) (err error) { - if c.config == nil { - c.config = defaultConfig() - } - - hsTimings := createTLS13ClientHandshakeTimingInfo(c.config.Time) - - // This may be a renegotiation handshake, in which case some fields - // need to be reset. - c.didResume = false - - // Determine the minimum required version for this handshake. - minVersion := c.config.MinVersion - if c.config.echCanOffer() { - // If the ECH extension will be offered in this handshake, then the - // ClientHelloInner must not offer TLS 1.2 or below. - minVersion = VersionTLS13 - } - - helloBase, ecdheParams, err := c.makeClientHello(minVersion) - if err != nil { - return err - } - - hello, helloInner, err := c.echOfferOrGrease(ctx, helloBase) - if err != nil { - return err - } - - helloResumed := hello - if c.ech.offered { - helloResumed = helloInner - } - - cacheKey, session, earlySecret, binderKey := c.loadSession(helloResumed) - if cacheKey != "" && session != nil { - defer func() { - // If we got a handshake failure when resuming a session, throw away - // the session ticket. See RFC 5077, Section 3.2. - // - // RFC 8446 makes no mention of dropping tickets on failure, but it - // does require servers to abort on invalid binders, so we need to - // delete tickets to recover from a corrupted PSK. - if err != nil { - c.config.ClientSessionCache.Put(cacheKey, nil) - } - }() - } - - if _, err := c.writeRecord(recordTypeHandshake, hello.marshal()); err != nil { - return err - } - - hsTimings.WriteClientHello = hsTimings.elapsedTime() - - msg, err := c.readHandshake() - if err != nil { - return err - } - - serverHello, ok := msg.(*serverHelloMsg) - if !ok { - c.sendAlert(alertUnexpectedMessage) - return unexpectedMessageError(serverHello, msg) - } - - if err := c.pickTLSVersion(serverHello); err != nil { - return err - } - - // If we are negotiating a protocol version that's lower than what we - // support, check for the server downgrade canaries. - // See RFC 8446, Section 4.1.3. - maxVers := c.config.maxSupportedVersion(roleClient) - tls12Downgrade := string(serverHello.random[24:]) == downgradeCanaryTLS12 - tls11Downgrade := string(serverHello.random[24:]) == downgradeCanaryTLS11 - if maxVers == VersionTLS13 && c.vers <= VersionTLS12 && (tls12Downgrade || tls11Downgrade) || - maxVers == VersionTLS12 && c.vers <= VersionTLS11 && tls11Downgrade { - c.sendAlert(alertIllegalParameter) - return errors.New("tls: downgrade attempt detected, possibly due to a MitM attack or a broken middlebox") - } - - if c.vers == VersionTLS13 { - hs := &clientHandshakeStateTLS13{ - c: c, - ctx: ctx, - serverHello: serverHello, - hello: hello, - helloInner: helloInner, - keySharePrivate: ecdheParams, - session: session, - earlySecret: earlySecret, - binderKey: binderKey, - hsTimings: hsTimings, - } - - // In TLS 1.3, session tickets are delivered after the handshake. - return hs.handshake() - } - - c.serverName = hello.serverName - hs := &clientHandshakeState{ - c: c, - ctx: ctx, - serverHello: serverHello, - hello: hello, - session: session, - } - - if err := hs.handshake(); err != nil { - return err - } - - // If we had a successful handshake and hs.session is different from - // the one already cached - cache a new one. - if cacheKey != "" && hs.session != nil && session != hs.session { - c.config.ClientSessionCache.Put(cacheKey, hs.session) - } - - return nil -} - -func (c *Conn) loadSession(hello *clientHelloMsg) (cacheKey string, - session *ClientSessionState, earlySecret, binderKey []byte, -) { - if c.config.SessionTicketsDisabled || c.config.ClientSessionCache == nil || c.config.ECHEnabled { - return "", nil, nil, nil - } - - hello.ticketSupported = true - - if hello.supportedVersions[0] == VersionTLS13 { - // Require DHE on resumption as it guarantees forward secrecy against - // compromise of the session ticket key. See RFC 8446, Section 4.2.9. - hello.pskModes = []uint8{pskModeDHE} - } - - // Session resumption is not allowed if renegotiating because - // renegotiation is primarily used to allow a client to send a client - // certificate, which would be skipped if session resumption occurred. - if c.handshakes != 0 { - return "", nil, nil, nil - } - - // Try to resume a previously negotiated TLS session, if available. - cacheKey = clientSessionCacheKey(c.conn.RemoteAddr(), c.config) - session, ok := c.config.ClientSessionCache.Get(cacheKey) - if !ok || session == nil { - return cacheKey, nil, nil, nil - } - - // Check that version used for the previous session is still valid. - versOk := false - for _, v := range hello.supportedVersions { - if v == session.vers { - versOk = true - break - } - } - if !versOk { - return cacheKey, nil, nil, nil - } - - // Check that the cached server certificate is not expired, and that it's - // valid for the ServerName. This should be ensured by the cache key, but - // protect the application from a faulty ClientSessionCache implementation. - if !c.config.InsecureSkipVerify { - if len(session.verifiedChains) == 0 { - // The original connection had InsecureSkipVerify, while this doesn't. - return cacheKey, nil, nil, nil - } - serverCert := session.serverCertificates[0] - if c.config.time().After(serverCert.NotAfter) { - // Expired certificate, delete the entry. - c.config.ClientSessionCache.Put(cacheKey, nil) - return cacheKey, nil, nil, nil - } - if err := serverCert.VerifyHostname(c.config.ServerName); err != nil { - return cacheKey, nil, nil, nil - } - } - - if session.vers != VersionTLS13 { - // In TLS 1.2 the cipher suite must match the resumed session. Ensure we - // are still offering it. - if mutualCipherSuite(hello.cipherSuites, session.cipherSuite) == nil { - return cacheKey, nil, nil, nil - } - - hello.sessionTicket = session.sessionTicket - return - } - - // Check that the session ticket is not expired. - if c.config.time().After(session.useBy) { - c.config.ClientSessionCache.Put(cacheKey, nil) - return cacheKey, nil, nil, nil - } - - // In TLS 1.3 the KDF hash must match the resumed session. Ensure we - // offer at least one cipher suite with that hash. - cipherSuite := cipherSuiteTLS13ByID(session.cipherSuite) - if cipherSuite == nil { - return cacheKey, nil, nil, nil - } - cipherSuiteOk := false - for _, offeredID := range hello.cipherSuites { - offeredSuite := cipherSuiteTLS13ByID(offeredID) - if offeredSuite != nil && offeredSuite.hash == cipherSuite.hash { - cipherSuiteOk = true - break - } - } - if !cipherSuiteOk { - return cacheKey, nil, nil, nil - } - - // Set the pre_shared_key extension. See RFC 8446, Section 4.2.11.1. - ticketAge := uint32(c.config.time().Sub(session.receivedAt) / time.Millisecond) - identity := pskIdentity{ - label: session.sessionTicket, - obfuscatedTicketAge: ticketAge + session.ageAdd, - } - hello.pskIdentities = []pskIdentity{identity} - hello.pskBinders = [][]byte{make([]byte, cipherSuite.hash.Size())} - - // Compute the PSK binders. See RFC 8446, Section 4.2.11.2. - psk := cipherSuite.expandLabel(session.masterSecret, "resumption", - session.nonce, cipherSuite.hash.Size()) - earlySecret = cipherSuite.extract(psk, nil) - binderKey = cipherSuite.deriveSecret(earlySecret, resumptionBinderLabel, nil) - transcript := cipherSuite.hash.New() - transcript.Write(hello.marshalWithoutBinders()) - pskBinders := [][]byte{cipherSuite.finishedHash(binderKey, transcript)} - hello.updateBinders(pskBinders) - - return -} - -func (c *Conn) pickTLSVersion(serverHello *serverHelloMsg) error { - peerVersion := serverHello.vers - if serverHello.supportedVersion != 0 { - peerVersion = serverHello.supportedVersion - } - - vers, ok := c.config.mutualVersion(roleClient, []uint16{peerVersion}) - if !ok { - c.sendAlert(alertProtocolVersion) - return fmt.Errorf("tls: server selected unsupported protocol version %x", peerVersion) - } - - c.vers = vers - c.haveVers = true - c.in.version = vers - c.out.version = vers - - return nil -} - -// Does the handshake, either a full one or resumes old session. Requires hs.c, -// hs.hello, hs.serverHello, and, optionally, hs.session to be set. -func (hs *clientHandshakeState) handshake() error { - c := hs.c - - isResume, err := hs.processServerHello() - if err != nil { - return err - } - - hs.finishedHash = newFinishedHash(c.vers, hs.suite) - - // No signatures of the handshake are needed in a resumption. - // Otherwise, in a full handshake, if we don't have any certificates - // configured then we will never send a CertificateVerify message and - // thus no signatures are needed in that case either. - if isResume || (len(c.config.Certificates) == 0 && c.config.GetClientCertificate == nil) { - hs.finishedHash.discardHandshakeBuffer() - } - - hs.finishedHash.Write(hs.hello.marshal()) - hs.finishedHash.Write(hs.serverHello.marshal()) - - c.buffering = true - c.didResume = isResume - if isResume { - if err := hs.establishKeys(); err != nil { - return err - } - if err := hs.readSessionTicket(); err != nil { - return err - } - if err := hs.readFinished(c.serverFinished[:]); err != nil { - return err - } - c.clientFinishedIsFirst = false - // Make sure the connection is still being verified whether or not this - // is a resumption. Resumptions currently don't reverify certificates so - // they don't call verifyServerCertificate. See Issue 31641. - if c.config.VerifyConnection != nil { - if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil { - c.sendAlert(alertBadCertificate) - return err - } - } - if err := hs.sendFinished(c.clientFinished[:]); err != nil { - return err - } - if _, err := c.flush(); err != nil { - return err - } - } else { - if err := hs.doFullHandshake(); err != nil { - return err - } - if err := hs.establishKeys(); err != nil { - return err - } - if err := hs.sendFinished(c.clientFinished[:]); err != nil { - return err - } - if _, err := c.flush(); err != nil { - return err - } - c.clientFinishedIsFirst = true - if err := hs.readSessionTicket(); err != nil { - return err - } - if err := hs.readFinished(c.serverFinished[:]); err != nil { - return err - } - } - - c.ekm = ekmFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.hello.random, hs.serverHello.random) - atomic.StoreUint32(&c.handshakeStatus, 1) - - return nil -} - -func (hs *clientHandshakeState) pickCipherSuite() error { - if hs.suite = mutualCipherSuite(hs.hello.cipherSuites, hs.serverHello.cipherSuite); hs.suite == nil { - hs.c.sendAlert(alertHandshakeFailure) - return errors.New("tls: server chose an unconfigured cipher suite") - } - - hs.c.cipherSuite = hs.suite.id - return nil -} - -func (hs *clientHandshakeState) doFullHandshake() error { - c := hs.c - - msg, err := c.readHandshake() - if err != nil { - return err - } - certMsg, ok := msg.(*certificateMsg) - if !ok || len(certMsg.certificates) == 0 { - c.sendAlert(alertUnexpectedMessage) - return unexpectedMessageError(certMsg, msg) - } - hs.finishedHash.Write(certMsg.marshal()) - - msg, err = c.readHandshake() - if err != nil { - return err - } - - cs, ok := msg.(*certificateStatusMsg) - if ok { - // RFC4366 on Certificate Status Request: - // The server MAY return a "certificate_status" message. - - if !hs.serverHello.ocspStapling { - // If a server returns a "CertificateStatus" message, then the - // server MUST have included an extension of type "status_request" - // with empty "extension_data" in the extended server hello. - - c.sendAlert(alertUnexpectedMessage) - return errors.New("tls: received unexpected CertificateStatus message") - } - hs.finishedHash.Write(cs.marshal()) - - c.ocspResponse = cs.response - - msg, err = c.readHandshake() - if err != nil { - return err - } - } - - if c.handshakes == 0 { - // If this is the first handshake on a connection, process and - // (optionally) verify the server's certificates. - if err := c.verifyServerCertificate(certMsg.certificates); err != nil { - return err - } - } else { - // This is a renegotiation handshake. We require that the - // server's identity (i.e. leaf certificate) is unchanged and - // thus any previous trust decision is still valid. - // - // See https://mitls.org/pages/attacks/3SHAKE for the - // motivation behind this requirement. - if !bytes.Equal(c.peerCertificates[0].Raw, certMsg.certificates[0]) { - c.sendAlert(alertBadCertificate) - return errors.New("tls: server's identity changed during renegotiation") - } - } - - keyAgreement := hs.suite.ka(c.vers) - - skx, ok := msg.(*serverKeyExchangeMsg) - if ok { - hs.finishedHash.Write(skx.marshal()) - err = keyAgreement.processServerKeyExchange(c.config, hs.hello, hs.serverHello, c.peerCertificates[0], skx) - if err != nil { - c.sendAlert(alertUnexpectedMessage) - return err - } - - if eccKex, ok := keyAgreement.(*ecdheKeyAgreement); ok { - c.handleCFEvent(CFEventTLSNegotiatedNamedKEX{ - KEX: eccKex.params.CurveID(), - }) - } - - msg, err = c.readHandshake() - if err != nil { - return err - } - } - - var chainToSend *Certificate - var certRequested bool - certReq, ok := msg.(*certificateRequestMsg) - if ok { - certRequested = true - hs.finishedHash.Write(certReq.marshal()) - - cri := certificateRequestInfoFromMsg(hs.ctx, c.vers, certReq) - if chainToSend, err = c.getClientCertificate(cri); err != nil { - c.sendAlert(alertInternalError) - return err - } - - msg, err = c.readHandshake() - if err != nil { - return err - } - } - - shd, ok := msg.(*serverHelloDoneMsg) - if !ok { - c.sendAlert(alertUnexpectedMessage) - return unexpectedMessageError(shd, msg) - } - hs.finishedHash.Write(shd.marshal()) - - // If the server requested a certificate then we have to send a - // Certificate message, even if it's empty because we don't have a - // certificate to send. - if certRequested { - certMsg = new(certificateMsg) - certMsg.certificates = chainToSend.Certificate - hs.finishedHash.Write(certMsg.marshal()) - if _, err := c.writeRecord(recordTypeHandshake, certMsg.marshal()); err != nil { - return err - } - } - - preMasterSecret, ckx, err := keyAgreement.generateClientKeyExchange(c.config, hs.hello, c.peerCertificates[0]) - if err != nil { - c.sendAlert(alertInternalError) - return err - } - if ckx != nil { - hs.finishedHash.Write(ckx.marshal()) - if _, err := c.writeRecord(recordTypeHandshake, ckx.marshal()); err != nil { - return err - } - } - - if chainToSend != nil && len(chainToSend.Certificate) > 0 { - certVerify := &certificateVerifyMsg{} - - key, ok := chainToSend.PrivateKey.(crypto.Signer) - if !ok { - c.sendAlert(alertInternalError) - return fmt.Errorf("tls: client certificate private key of type %T does not implement crypto.Signer", chainToSend.PrivateKey) - } - - var sigType uint8 - var sigHash crypto.Hash - if c.vers >= VersionTLS12 { - signatureAlgorithm, err := selectSignatureScheme(c.vers, chainToSend, certReq.supportedSignatureAlgorithms) - if err != nil { - c.sendAlert(alertIllegalParameter) - return err - } - sigType, sigHash, err = typeAndHashFromSignatureScheme(signatureAlgorithm) - if err != nil { - return c.sendAlert(alertInternalError) - } - certVerify.hasSignatureAlgorithm = true - certVerify.signatureAlgorithm = signatureAlgorithm - } else { - sigType, sigHash, err = legacyTypeAndHashFromPublicKey(key.Public()) - if err != nil { - c.sendAlert(alertIllegalParameter) - return err - } - } - - signed := hs.finishedHash.hashForClientCertificate(sigType, sigHash, hs.masterSecret) - signOpts := crypto.SignerOpts(sigHash) - if sigType == signatureRSAPSS { - signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: sigHash} - } - certVerify.signature, err = key.Sign(c.config.rand(), signed, signOpts) - if err != nil { - c.sendAlert(alertInternalError) - return err - } - - hs.finishedHash.Write(certVerify.marshal()) - if _, err := c.writeRecord(recordTypeHandshake, certVerify.marshal()); err != nil { - return err - } - } - - hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.hello.random, hs.serverHello.random) - if err := c.config.writeKeyLog(keyLogLabelTLS12, hs.hello.random, hs.masterSecret); err != nil { - c.sendAlert(alertInternalError) - return errors.New("tls: failed to write to key log: " + err.Error()) - } - - hs.finishedHash.discardHandshakeBuffer() - - return nil -} - -func (hs *clientHandshakeState) establishKeys() error { - c := hs.c - - clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV := keysFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.hello.random, hs.serverHello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen) - var clientCipher, serverCipher any - var clientHash, serverHash hash.Hash - if hs.suite.cipher != nil { - clientCipher = hs.suite.cipher(clientKey, clientIV, false /* not for reading */) - clientHash = hs.suite.mac(clientMAC) - serverCipher = hs.suite.cipher(serverKey, serverIV, true /* for reading */) - serverHash = hs.suite.mac(serverMAC) - } else { - clientCipher = hs.suite.aead(clientKey, clientIV) - serverCipher = hs.suite.aead(serverKey, serverIV) - } - - c.in.prepareCipherSpec(c.vers, serverCipher, serverHash) - c.out.prepareCipherSpec(c.vers, clientCipher, clientHash) - return nil -} - -func (hs *clientHandshakeState) serverResumedSession() bool { - // If the server responded with the same sessionId then it means the - // sessionTicket is being used to resume a TLS session. - return hs.session != nil && hs.hello.sessionId != nil && - bytes.Equal(hs.serverHello.sessionId, hs.hello.sessionId) -} - -func (hs *clientHandshakeState) processServerHello() (bool, error) { - c := hs.c - - if err := hs.pickCipherSuite(); err != nil { - return false, err - } - - if hs.serverHello.compressionMethod != compressionNone { - c.sendAlert(alertUnexpectedMessage) - return false, errors.New("tls: server selected unsupported compression format") - } - - if c.handshakes == 0 && hs.serverHello.secureRenegotiationSupported { - c.secureRenegotiation = true - if len(hs.serverHello.secureRenegotiation) != 0 { - c.sendAlert(alertHandshakeFailure) - return false, errors.New("tls: initial handshake had non-empty renegotiation extension") - } - } - - if c.handshakes > 0 && c.secureRenegotiation { - var expectedSecureRenegotiation [24]byte - copy(expectedSecureRenegotiation[:], c.clientFinished[:]) - copy(expectedSecureRenegotiation[12:], c.serverFinished[:]) - if !bytes.Equal(hs.serverHello.secureRenegotiation, expectedSecureRenegotiation[:]) { - c.sendAlert(alertHandshakeFailure) - return false, errors.New("tls: incorrect renegotiation extension contents") - } - } - - if err := checkALPN(hs.hello.alpnProtocols, hs.serverHello.alpnProtocol); err != nil { - c.sendAlert(alertUnsupportedExtension) - return false, err - } - c.clientProtocol = hs.serverHello.alpnProtocol - - c.scts = hs.serverHello.scts - - if !hs.serverResumedSession() { - return false, nil - } - - if hs.session.vers != c.vers { - c.sendAlert(alertHandshakeFailure) - return false, errors.New("tls: server resumed a session with a different version") - } - - if hs.session.cipherSuite != hs.suite.id { - c.sendAlert(alertHandshakeFailure) - return false, errors.New("tls: server resumed a session with a different cipher suite") - } - - // Restore masterSecret, peerCerts, and ocspResponse from previous state - hs.masterSecret = hs.session.masterSecret - c.peerCertificates = hs.session.serverCertificates - c.verifiedChains = hs.session.verifiedChains - c.ocspResponse = hs.session.ocspResponse - // Let the ServerHello SCTs override the session SCTs from the original - // connection, if any are provided - if len(c.scts) == 0 && len(hs.session.scts) != 0 { - c.scts = hs.session.scts - } - - return true, nil -} - -// checkALPN ensure that the server's choice of ALPN protocol is compatible with -// the protocols that we advertised in the Client Hello. -func checkALPN(clientProtos []string, serverProto string) error { - if serverProto == "" { - return nil - } - if len(clientProtos) == 0 { - return errors.New("tls: server advertised unrequested ALPN extension") - } - for _, proto := range clientProtos { - if proto == serverProto { - return nil - } - } - return errors.New("tls: server selected unadvertised ALPN protocol") -} - -func (hs *clientHandshakeState) readFinished(out []byte) error { - c := hs.c - - if err := c.readChangeCipherSpec(); err != nil { - return err - } - - msg, err := c.readHandshake() - if err != nil { - return err - } - serverFinished, ok := msg.(*finishedMsg) - if !ok { - c.sendAlert(alertUnexpectedMessage) - return unexpectedMessageError(serverFinished, msg) - } - - verify := hs.finishedHash.serverSum(hs.masterSecret) - if len(verify) != len(serverFinished.verifyData) || - subtle.ConstantTimeCompare(verify, serverFinished.verifyData) != 1 { - c.sendAlert(alertHandshakeFailure) - return errors.New("tls: server's Finished message was incorrect") - } - hs.finishedHash.Write(serverFinished.marshal()) - copy(out, verify) - return nil -} - -func (hs *clientHandshakeState) readSessionTicket() error { - if !hs.serverHello.ticketSupported { - return nil - } - - c := hs.c - msg, err := c.readHandshake() - if err != nil { - return err - } - sessionTicketMsg, ok := msg.(*newSessionTicketMsg) - if !ok { - c.sendAlert(alertUnexpectedMessage) - return unexpectedMessageError(sessionTicketMsg, msg) - } - hs.finishedHash.Write(sessionTicketMsg.marshal()) - - hs.session = &ClientSessionState{ - sessionTicket: sessionTicketMsg.ticket, - vers: c.vers, - cipherSuite: hs.suite.id, - masterSecret: hs.masterSecret, - serverCertificates: c.peerCertificates, - verifiedChains: c.verifiedChains, - receivedAt: c.config.time(), - ocspResponse: c.ocspResponse, - scts: c.scts, - } - - return nil -} - -func (hs *clientHandshakeState) sendFinished(out []byte) error { - c := hs.c - - if _, err := c.writeRecord(recordTypeChangeCipherSpec, []byte{1}); err != nil { - return err - } - - finished := new(finishedMsg) - finished.verifyData = hs.finishedHash.clientSum(hs.masterSecret) - hs.finishedHash.Write(finished.marshal()) - if _, err := c.writeRecord(recordTypeHandshake, finished.marshal()); err != nil { - return err - } - copy(out, finished.verifyData) - return nil -} - -// verifyServerCertificate parses and verifies the provided chain, setting -// c.verifiedChains and c.peerCertificates or sending the appropriate alert. -func (c *Conn) verifyServerCertificate(certificates [][]byte) error { - certs := make([]*x509.Certificate, len(certificates)) - for i, asn1Data := range certificates { - cert, err := x509.ParseCertificate(asn1Data) - if err != nil { - c.sendAlert(alertBadCertificate) - return errors.New("tls: failed to parse certificate from server: " + err.Error()) - } - certs[i] = cert - } - - if !c.config.InsecureSkipVerify { - dnsName := c.config.ServerName - if c.ech.offered && !c.ech.accepted { - dnsName = c.serverName - } - opts := x509.VerifyOptions{ - Roots: c.config.RootCAs, - CurrentTime: c.config.time(), - DNSName: dnsName, - Intermediates: x509.NewCertPool(), - } - for _, cert := range certs[1:] { - opts.Intermediates.AddCert(cert) - } - var err error - c.verifiedChains, err = certs[0].Verify(opts) - if err != nil { - c.sendAlert(alertBadCertificate) - return err - } - } - - switch certs[0].PublicKey.(type) { - case *rsa.PublicKey, *ecdsa.PublicKey, ed25519.PublicKey, circlSign.PublicKey: - break - default: - c.sendAlert(alertUnsupportedCertificate) - return fmt.Errorf("tls: server's certificate contains an unsupported type of public key: %T", certs[0].PublicKey) - } - - c.peerCertificates = certs - - if c.config.VerifyPeerCertificate != nil { - if err := c.config.VerifyPeerCertificate(certificates, c.verifiedChains); err != nil { - c.sendAlert(alertBadCertificate) - return err - } - } - - if c.config.VerifyConnection != nil { - if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil { - c.sendAlert(alertBadCertificate) - return err - } - } - - return nil -} - -// certificateRequestInfoFromMsg generates a CertificateRequestInfo from a TLS -// <= 1.2 CertificateRequest, making an effort to fill in missing information. -func certificateRequestInfoFromMsg(ctx context.Context, vers uint16, certReq *certificateRequestMsg) *CertificateRequestInfo { - cri := &CertificateRequestInfo{ - AcceptableCAs: certReq.certificateAuthorities, - Version: vers, - ctx: ctx, - - SupportsDelegatedCredential: false, // Not supported in TLS <= 1.2 - SignatureSchemesDC: nil, // Not supported in TLS <= 1.2 - } - - var rsaAvail, ecAvail bool - for _, certType := range certReq.certificateTypes { - switch certType { - case certTypeRSASign: - rsaAvail = true - case certTypeECDSASign: - ecAvail = true - } - } - - if !certReq.hasSignatureAlgorithm { - // Prior to TLS 1.2, signature schemes did not exist. In this case we - // make up a list based on the acceptable certificate types, to help - // GetClientCertificate and SupportsCertificate select the right certificate. - // The hash part of the SignatureScheme is a lie here, because - // TLS 1.0 and 1.1 always use MD5+SHA1 for RSA and SHA1 for ECDSA. - switch { - case rsaAvail && ecAvail: - cri.SignatureSchemes = []SignatureScheme{ - ECDSAWithP256AndSHA256, ECDSAWithP384AndSHA384, ECDSAWithP521AndSHA512, - PKCS1WithSHA256, PKCS1WithSHA384, PKCS1WithSHA512, PKCS1WithSHA1, - } - case rsaAvail: - cri.SignatureSchemes = []SignatureScheme{ - PKCS1WithSHA256, PKCS1WithSHA384, PKCS1WithSHA512, PKCS1WithSHA1, - } - case ecAvail: - cri.SignatureSchemes = []SignatureScheme{ - ECDSAWithP256AndSHA256, ECDSAWithP384AndSHA384, ECDSAWithP521AndSHA512, - } - } - return cri - } - - // Filter the signature schemes based on the certificate types. - // See RFC 5246, Section 7.4.4 (where it calls this "somewhat complicated"). - cri.SignatureSchemes = make([]SignatureScheme, 0, len(certReq.supportedSignatureAlgorithms)) - for _, sigScheme := range certReq.supportedSignatureAlgorithms { - sigType, _, err := typeAndHashFromSignatureScheme(sigScheme) - if err != nil { - continue - } - switch sigType { - case signatureECDSA, signatureEd25519: - if ecAvail { - cri.SignatureSchemes = append(cri.SignatureSchemes, sigScheme) - } - case signatureRSAPSS, signaturePKCS1v15: - if rsaAvail { - cri.SignatureSchemes = append(cri.SignatureSchemes, sigScheme) - } - } - } - - return cri -} - -func (c *Conn) getClientCertificate(cri *CertificateRequestInfo) (*Certificate, error) { - if c.config.GetClientCertificate != nil { - return c.config.GetClientCertificate(cri) - } - - for _, chain := range c.config.Certificates { - if err := cri.SupportsCertificate(&chain); err != nil { - continue - } - return &chain, nil - } - - // No acceptable certificate found. Don't send a certificate. - return new(Certificate), nil -} - -// clientSessionCacheKey returns a key used to cache sessionTickets that could -// be used to resume previously negotiated TLS sessions with a server. -func clientSessionCacheKey(serverAddr net.Addr, config *Config) string { - if len(config.ServerName) > 0 { - return config.ServerName - } - return serverAddr.String() -} - -// hostnameInSNI converts name into an appropriate hostname for SNI. -// Literal IP addresses and absolute FQDNs are not permitted as SNI values. -// See RFC 6066, Section 3. -func hostnameInSNI(name string) string { - host := name - if len(host) > 0 && host[0] == '[' && host[len(host)-1] == ']' { - host = host[1 : len(host)-1] - } - if i := strings.LastIndex(host, "%"); i > 0 { - host = host[:i] - } - if net.ParseIP(host) != nil { - return "" - } - for len(name) > 0 && name[len(name)-1] == '.' { - name = name[:len(name)-1] - } - return name -} diff --git a/transport/cloudflaretls/handshake_client_tls13.go b/transport/cloudflaretls/handshake_client_tls13.go deleted file mode 100644 index 8ae5e617..00000000 --- a/transport/cloudflaretls/handshake_client_tls13.go +++ /dev/null @@ -1,1032 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package tls - -import ( - "bytes" - "context" - "crypto" - "crypto/hmac" - "crypto/rsa" - "crypto/subtle" - "errors" - "fmt" - "hash" - "sync/atomic" - "time" - - circlKem "github.com/cloudflare/circl/kem" -) - -type clientHandshakeStateTLS13 struct { - c *Conn - ctx context.Context - serverHello *serverHelloMsg - hello *clientHelloMsg - helloInner *clientHelloMsg - keySharePrivate clientKeySharePrivate - - session *ClientSessionState - earlySecret []byte - binderKey []byte - selectedGroup CurveID - - certReq *certificateRequestMsgTLS13 - usingPSK bool - sentDummyCCS bool - suite *cipherSuiteTLS13 - transcript hash.Hash - transcriptInner hash.Hash - masterSecret []byte - trafficSecret []byte // client_application_traffic_secret_0 - - hsTimings CFEventTLS13ClientHandshakeTimingInfo -} - -// processDelegatedCredentialFromServer unmarshals the DelegatedCredential -// offered by the server (if present) and validates it using the peer's -// certificate. -func (hs *clientHandshakeStateTLS13) processDelegatedCredentialFromServer(rawDC []byte, certVerifyMsg *certificateVerifyMsg) error { - c := hs.c - - var dc *DelegatedCredential - var err error - if rawDC != nil { - // Assert that support for the DC extension was indicated by the client. - if !hs.hello.delegatedCredentialSupported { - c.sendAlert(alertUnexpectedMessage) - return errors.New("tls: got Delegated Credential extension without indication") - } - - dc, err = UnmarshalDelegatedCredential(rawDC) - if err != nil { - c.sendAlert(alertDecodeError) - return fmt.Errorf("tls: Delegated Credential: %s", err) - } - - if !isSupportedSignatureAlgorithm(dc.cred.expCertVerfAlgo, supportedSignatureAlgorithmsDC) { - c.sendAlert(alertIllegalParameter) - return errors.New("tls: Delegated Credential used with invalid signature algorithm") - } - if !isSupportedSignatureAlgorithm(dc.algorithm, c.config.supportedSignatureAlgorithms()) { - c.sendAlert(alertIllegalParameter) - return errors.New("tls: Delegated Credential signed with unsupported signature algorithm") - } - } - - if dc != nil { - if !dc.Validate(c.peerCertificates[0], false, c.config.time(), certVerifyMsg) { - c.sendAlert(alertIllegalParameter) - return errors.New("tls: invalid Delegated Credential") - } - } - - c.verifiedDC = dc - - return nil -} - -// handshake requires hs.c, hs.hello, hs.serverHello, hs.ecdheParams, and, -// optionally, hs.session, hs.earlySecret and hs.binderKey to be set. -func (hs *clientHandshakeStateTLS13) handshake() error { - c := hs.c - - // The server must not select TLS 1.3 in a renegotiation. See RFC 8446, - // sections 4.1.2 and 4.1.3. - if c.handshakes > 0 { - c.sendAlert(alertProtocolVersion) - return errors.New("tls: server selected TLS 1.3 in a renegotiation") - } - - // Consistency check on the presence of a keyShare and its parameters. - if hs.keySharePrivate == nil || len(hs.hello.keyShares) != 1 { - return c.sendAlert(alertInternalError) - } - - if err := hs.checkServerHelloOrHRR(); err != nil { - return err - } - - hs.transcript = hs.suite.hash.New() - hs.transcript.Write(hs.hello.marshal()) - - // When offering ECH, we don't know whether ECH was accepted or rejected - // until we get the server's response. Compute the transcript of both the - // inner and outer handshake until we know. - if c.ech.offered { - hs.transcriptInner = hs.suite.hash.New() - hs.transcriptInner.Write(hs.helloInner.marshal()) - } - - if bytes.Equal(hs.serverHello.random, helloRetryRequestRandom) { - if err := hs.sendDummyChangeCipherSpec(); err != nil { - return err - } - if err := hs.processHelloRetryRequest(); err != nil { - return err - } - } - - // Check for ECH acceptance confirmation. - if c.ech.offered { - echAcceptConfTranscript := cloneHash(hs.transcriptInner, hs.suite.hash) - if echAcceptConfTranscript == nil { - c.sendAlert(alertInternalError) - return errors.New("tls: internal error: failed to clone hash") - } - - sh := hs.serverHello.marshal() - echAcceptConfTranscript.Write(sh[:30]) - echAcceptConfTranscript.Write(zeros[:8]) - echAcceptConfTranscript.Write(sh[38:]) - echAcceptConf := hs.suite.expandLabel( - hs.suite.extract(hs.helloInner.random, nil), - echAcceptConfLabel, - echAcceptConfTranscript.Sum(nil), - 8) - - if subtle.ConstantTimeCompare(hs.serverHello.random[24:], echAcceptConf) == 1 { - c.ech.accepted = true - hs.hello = hs.helloInner - hs.transcript = hs.transcriptInner - } - } - - hs.transcript.Write(hs.serverHello.marshal()) - - // Resolve the server name now that ECH acceptance has been determined. - // - // NOTE(cjpatton): Currently the client sends the same ALPN extension in the - // ClientHelloInner and ClientHelloOuter. If that changes, then we'll need - // to resolve ALPN here as well. - c.serverName = hs.hello.serverName - - c.buffering = true - if err := hs.processServerHello(); err != nil { - return err - } - if err := hs.sendDummyChangeCipherSpec(); err != nil { - return err - } - if err := hs.establishHandshakeKeys(); err != nil { - return err - } - if err := hs.readServerParameters(); err != nil { - return err - } - if err := hs.readServerCertificate(); err != nil { - return err - } - if err := hs.readServerFinished(); err != nil { - return err - } - if err := hs.sendClientCertificate(); err != nil { - return err - } - if err := hs.sendClientFinished(); err != nil { - return err - } - if err := hs.abortIfRequired(); err != nil { - return err - } - if _, err := c.flush(); err != nil { - return err - } - - c.handleCFEvent(hs.hsTimings) - atomic.StoreUint32(&c.handshakeStatus, 1) - - return nil -} - -// checkServerHelloOrHRR does validity checks that apply to both ServerHello and -// HelloRetryRequest messages. It sets hs.suite. -func (hs *clientHandshakeStateTLS13) checkServerHelloOrHRR() error { - c := hs.c - - if hs.serverHello.supportedVersion == 0 { - c.sendAlert(alertMissingExtension) - return errors.New("tls: server selected TLS 1.3 using the legacy version field") - } - - if hs.serverHello.supportedVersion != VersionTLS13 { - c.sendAlert(alertIllegalParameter) - return errors.New("tls: server selected an invalid version after a HelloRetryRequest") - } - - if hs.serverHello.vers != VersionTLS12 { - c.sendAlert(alertIllegalParameter) - return errors.New("tls: server sent an incorrect legacy version") - } - - if hs.serverHello.ocspStapling || - hs.serverHello.ticketSupported || - hs.serverHello.secureRenegotiationSupported || - len(hs.serverHello.secureRenegotiation) != 0 || - len(hs.serverHello.alpnProtocol) != 0 || - len(hs.serverHello.scts) != 0 { - c.sendAlert(alertUnsupportedExtension) - return errors.New("tls: server sent a ServerHello extension forbidden in TLS 1.3") - } - - if !bytes.Equal(hs.hello.sessionId, hs.serverHello.sessionId) { - c.sendAlert(alertIllegalParameter) - return errors.New("tls: server did not echo the legacy session ID") - } - - if hs.serverHello.compressionMethod != compressionNone { - c.sendAlert(alertIllegalParameter) - return errors.New("tls: server selected unsupported compression format") - } - - selectedSuite := mutualCipherSuiteTLS13(hs.hello.cipherSuites, hs.serverHello.cipherSuite) - if hs.suite != nil && selectedSuite != hs.suite { - c.sendAlert(alertIllegalParameter) - return errors.New("tls: server changed cipher suite after a HelloRetryRequest") - } - if selectedSuite == nil { - c.sendAlert(alertIllegalParameter) - return errors.New("tls: server chose an unconfigured cipher suite") - } - hs.suite = selectedSuite - c.cipherSuite = hs.suite.id - - return nil -} - -// sendDummyChangeCipherSpec sends a ChangeCipherSpec record for compatibility -// with middleboxes that didn't implement TLS correctly. See RFC 8446, Appendix D.4. -func (hs *clientHandshakeStateTLS13) sendDummyChangeCipherSpec() error { - if hs.sentDummyCCS { - return nil - } - hs.sentDummyCCS = true - - _, err := hs.c.writeRecord(recordTypeChangeCipherSpec, []byte{1}) - return err -} - -// processHelloRetryRequest handles the HRR in hs.serverHello, modifies and -// resends hs.hello, and reads the new ServerHello into hs.serverHello. -func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error { - c := hs.c - - c.handleCFEvent(CFEventTLS13HRR{}) - - // The first ClientHello gets double-hashed into the transcript upon a - // HelloRetryRequest. (The idea is that the server might offload transcript - // storage to the client in the cookie.) See RFC 8446, Section 4.4.1. - chHash := hs.transcript.Sum(nil) - hs.transcript.Reset() - hs.transcript.Write([]byte{typeMessageHash, 0, 0, uint8(len(chHash))}) - hs.transcript.Write(chHash) - hs.transcript.Write(hs.serverHello.marshal()) - - // Determine which ClientHello message was consumed by the server. If ECH - // was offered, this may be the ClientHelloInner or ClientHelloOuter. - hello := hs.hello - isInner := false - if c.ech.offered { - chHash = hs.transcriptInner.Sum(nil) - hs.transcriptInner.Reset() - hs.transcriptInner.Write([]byte{typeMessageHash, 0, 0, uint8(len(chHash))}) - hs.transcriptInner.Write(chHash) - - // Check for ECH acceptance confirmation. - if hs.serverHello.ech != nil { - if len(hs.serverHello.ech) != 8 { - c.sendAlert(alertDecodeError) - return errors.New("tls: ech: hrr: malformed acceptance signal") - } - - echAcceptConfHRRTranscript := cloneHash(hs.transcriptInner, hs.suite.hash) - if echAcceptConfHRRTranscript == nil { - c.sendAlert(alertInternalError) - return errors.New("tls: internal error: failed to clone hash") - } - - echAcceptConfHRR := echEncodeAcceptConfHelloRetryRequest(hs.serverHello.marshal()) - echAcceptConfHRRTranscript.Write(echAcceptConfHRR) - echAcceptConfHRRSignal := hs.suite.expandLabel( - hs.suite.extract(hs.helloInner.random, nil), - echAcceptConfHRRLabel, - echAcceptConfHRRTranscript.Sum(nil), - 8) - - if subtle.ConstantTimeCompare(hs.serverHello.ech, echAcceptConfHRRSignal) == 1 { - hello = hs.helloInner - isInner = true - } - } - - hs.transcriptInner.Write(hs.serverHello.marshal()) - } - - // The only HelloRetryRequest extensions we support are key_share and - // cookie, and clients must abort the handshake if the HRR would not result - // in any change in the ClientHello. - if hs.serverHello.selectedGroup == 0 && hs.serverHello.cookie == nil { - c.sendAlert(alertIllegalParameter) - return errors.New("tls: server sent an unnecessary HelloRetryRequest message") - } - - if hs.serverHello.cookie != nil { - hello.cookie = hs.serverHello.cookie - } - - if hs.serverHello.serverShare.group != 0 { - c.sendAlert(alertDecodeError) - return errors.New("tls: received malformed key_share extension") - } - - // If the server sent a key_share extension selecting a group, ensure it's - // a group we advertised but did not send a key share for, and send a key - // share for it this time. - if curveID := hs.serverHello.selectedGroup; curveID != 0 { - curveOK := false - for _, id := range hello.supportedCurves { - if id == curveID { - curveOK = true - break - } - } - if !curveOK { - c.sendAlert(alertIllegalParameter) - return errors.New("tls: server selected unsupported group") - } - if clientKeySharePrivateCurveID(hs.keySharePrivate) == curveID { - c.sendAlert(alertIllegalParameter) - return errors.New("tls: server sent an unnecessary HelloRetryRequest key_share") - } - if scheme := curveIdToCirclScheme(curveID); scheme != nil { - pk, sk, err := generateKemKeyPair(scheme, c.config.rand()) - if err != nil { - c.sendAlert(alertInternalError) - return fmt.Errorf("HRR generateKemKeyPair %s: %w", - scheme.Name(), err) - } - packedPk, err := pk.MarshalBinary() - if err != nil { - c.sendAlert(alertInternalError) - return fmt.Errorf("HRR pack circl public key %s: %w", - scheme.Name(), err) - } - hs.keySharePrivate = sk - hello.keyShares = []keyShare{{group: curveID, data: packedPk}} - } else { - if _, ok := curveForCurveID(curveID); curveID != X25519 && !ok { - c.sendAlert(alertInternalError) - return errors.New("tls: CurvePreferences includes unsupported curve") - } - params, err := generateECDHEParameters(c.config.rand(), curveID) - if err != nil { - c.sendAlert(alertInternalError) - return err - } - hs.keySharePrivate = params - hello.keyShares = []keyShare{{group: curveID, data: params.PublicKey()}} - } - } - - hello.raw = nil - if len(hello.pskIdentities) > 0 { - pskSuite := cipherSuiteTLS13ByID(hs.session.cipherSuite) - if pskSuite == nil { - return c.sendAlert(alertInternalError) - } - if pskSuite.hash == hs.suite.hash { - // Update binders and obfuscated_ticket_age. - ticketAge := uint32(c.config.time().Sub(hs.session.receivedAt) / time.Millisecond) - hello.pskIdentities[0].obfuscatedTicketAge = ticketAge + hs.session.ageAdd - - transcript := hs.suite.hash.New() - transcript.Write([]byte{typeMessageHash, 0, 0, uint8(len(chHash))}) - transcript.Write(chHash) - transcript.Write(hs.serverHello.marshal()) - transcript.Write(hello.marshalWithoutBinders()) - pskBinders := [][]byte{hs.suite.finishedHash(hs.binderKey, transcript)} - hello.updateBinders(pskBinders) - } else { - // Server selected a cipher suite incompatible with the PSK. - hello.pskIdentities = nil - hello.pskBinders = nil - } - } - - if isInner { - hs.helloInner = hello - hs.transcriptInner.Write(hs.helloInner.marshal()) - if err := c.echUpdateClientHelloOuter(hs.hello, hs.helloInner, nil); err != nil { - return err - } - } else { - hs.hello = hello - } - - if c.ech.offered && testingECHIllegalHandleAfterHRR { - hs.hello.raw = nil - - // Change the cipher suite and config id and set an encapsulated key in - // the updated ClientHello. This will trigger a server abort because the - // cipher suite and config id are supposed to match the previous - // ClientHello and the encapsulated key is supposed to be empty. - var ech echClientOuter - _, kdf, aead := c.ech.sealer.Suite().Params() - ech.handle.suite.kdfId = uint16(kdf) ^ 0xff - ech.handle.suite.aeadId = uint16(aead) ^ 0xff - ech.handle.configId = c.ech.configId ^ 0xff - ech.handle.enc = []byte{1, 2, 3, 4, 5} - ech.payload = []byte{1, 2, 3, 4, 5} - hs.hello.ech = ech.marshal() - } - - if testingECHTriggerBypassAfterHRR { - hs.hello.raw = nil - - // Don't send the ECH extension in the updated ClientHello. This will - // trigger a server abort, since this is illegal. - hs.hello.ech = nil - } - - if testingECHTriggerBypassBeforeHRR { - hs.hello.raw = nil - - // Send a dummy ECH extension in the updated ClientHello. This will - // trigger a server abort, since no ECH extension was sent in the - // previous ClientHello. - var err error - hs.hello.ech, err = echGenerateGreaseExt(c.config.rand()) - if err != nil { - return fmt.Errorf("tls: ech: failed to generate grease ECH: %s", err) - } - } - - if _, err := c.writeRecord(recordTypeHandshake, hs.hello.marshal()); err != nil { - return err - } - - msg, err := c.readHandshake() - if err != nil { - return err - } - - serverHello, ok := msg.(*serverHelloMsg) - if !ok { - c.sendAlert(alertUnexpectedMessage) - return unexpectedMessageError(serverHello, msg) - } - hs.serverHello = serverHello - - if err := hs.checkServerHelloOrHRR(); err != nil { - return err - } - - hs.transcript.Write(hs.hello.marshal()) - return nil -} - -func (hs *clientHandshakeStateTLS13) processServerHello() error { - c := hs.c - - defer func() { - hs.hsTimings.ProcessServerHello = hs.hsTimings.elapsedTime() - }() - - if bytes.Equal(hs.serverHello.random, helloRetryRequestRandom) { - c.sendAlert(alertUnexpectedMessage) - return errors.New("tls: server sent two HelloRetryRequest messages") - } - - if len(hs.serverHello.cookie) != 0 { - c.sendAlert(alertUnsupportedExtension) - return errors.New("tls: server sent a cookie in a normal ServerHello") - } - - if hs.serverHello.selectedGroup != 0 { - c.sendAlert(alertDecodeError) - return errors.New("tls: malformed key_share extension") - } - - if hs.serverHello.serverShare.group == 0 { - c.sendAlert(alertIllegalParameter) - return errors.New("tls: server did not send a key share") - } - if hs.serverHello.serverShare.group != clientKeySharePrivateCurveID(hs.keySharePrivate) { - c.sendAlert(alertIllegalParameter) - return errors.New("tls: server selected unsupported group") - } - - c.handleCFEvent(CFEventTLSNegotiatedNamedKEX{ - KEX: hs.serverHello.serverShare.group, - }) - - if !hs.serverHello.selectedIdentityPresent { - return nil - } - - // Per the rules of draft-ietf-tls-esni-13, Section 6.1, the server is not - // permitted to resume a connection connection in the outer handshake. If - // ECH is rejected and the client-facing server replies with a - // "pre_shared_key" extension in its ServerHello, then the client MUST abort - // the handshake with an "illegal_parameter" alert. - if c.ech.offered && !c.ech.accepted { - c.sendAlert(alertIllegalParameter) - return errors.New("tls: ech: client-facing server offered PSK after ECH rejection") - } - - if int(hs.serverHello.selectedIdentity) >= len(hs.hello.pskIdentities) { - c.sendAlert(alertIllegalParameter) - return errors.New("tls: server selected an invalid PSK") - } - - if len(hs.hello.pskIdentities) != 1 || hs.session == nil { - return c.sendAlert(alertInternalError) - } - pskSuite := cipherSuiteTLS13ByID(hs.session.cipherSuite) - if pskSuite == nil { - return c.sendAlert(alertInternalError) - } - if pskSuite.hash != hs.suite.hash { - c.sendAlert(alertIllegalParameter) - return errors.New("tls: server selected an invalid PSK and cipher suite pair") - } - - hs.usingPSK = true - c.didResume = true - c.peerCertificates = hs.session.serverCertificates - c.verifiedChains = hs.session.verifiedChains - c.ocspResponse = hs.session.ocspResponse - c.scts = hs.session.scts - return nil -} - -func (hs *clientHandshakeStateTLS13) establishHandshakeKeys() error { - c := hs.c - - var sharedKey []byte - if params, ok := hs.keySharePrivate.(ecdheParameters); ok { - sharedKey = params.SharedKey(hs.serverHello.serverShare.data) - } else if sk, ok := hs.keySharePrivate.(circlKem.PrivateKey); ok { - var err error - sharedKey, err = sk.Scheme().Decapsulate(sk, hs.serverHello.serverShare.data) - if err != nil { - c.sendAlert(alertIllegalParameter) - return fmt.Errorf("%s decaps: %w", sk.Scheme().Name(), err) - } - } - - if sharedKey == nil { - c.sendAlert(alertIllegalParameter) - return fmt.Errorf("tls: invalid server key share") - } - - earlySecret := hs.earlySecret - if !hs.usingPSK { - earlySecret = hs.suite.extract(nil, nil) - } - handshakeSecret := hs.suite.extract(sharedKey, - hs.suite.deriveSecret(earlySecret, "derived", nil)) - - clientSecret := hs.suite.deriveSecret(handshakeSecret, - clientHandshakeTrafficLabel, hs.transcript) - c.out.setTrafficSecret(hs.suite, clientSecret) - serverSecret := hs.suite.deriveSecret(handshakeSecret, - serverHandshakeTrafficLabel, hs.transcript) - c.in.setTrafficSecret(hs.suite, serverSecret) - - err := c.config.writeKeyLog(keyLogLabelClientHandshake, hs.hello.random, clientSecret) - if err != nil { - c.sendAlert(alertInternalError) - return err - } - err = c.config.writeKeyLog(keyLogLabelServerHandshake, hs.hello.random, serverSecret) - if err != nil { - c.sendAlert(alertInternalError) - return err - } - - hs.masterSecret = hs.suite.extract(nil, - hs.suite.deriveSecret(handshakeSecret, "derived", nil)) - - return nil -} - -func (hs *clientHandshakeStateTLS13) readServerParameters() error { - c := hs.c - - msg, err := c.readHandshake() - if err != nil { - return err - } - - encryptedExtensions, ok := msg.(*encryptedExtensionsMsg) - if !ok { - c.sendAlert(alertUnexpectedMessage) - return unexpectedMessageError(encryptedExtensions, msg) - } - hs.transcript.Write(encryptedExtensions.marshal()) - - if err := checkALPN(hs.hello.alpnProtocols, encryptedExtensions.alpnProtocol); err != nil { - c.sendAlert(alertUnsupportedExtension) - return err - } - c.clientProtocol = encryptedExtensions.alpnProtocol - - if c.ech.offered && len(encryptedExtensions.ech) > 0 { - if !c.ech.accepted { - // If the server rejects ECH, then it may send retry configurations. - // If present, we must check them for syntactic correctness and - // abort if they are not correct. - c.ech.retryConfigs = encryptedExtensions.ech - if _, err = UnmarshalECHConfigs(c.ech.retryConfigs); err != nil { - c.sendAlert(alertDecodeError) - return fmt.Errorf("tls: ech: failed to parse retry configs: %s", err) - } - } else { - // Retry configs must not be sent in the inner handshake. - c.sendAlert(alertUnsupportedExtension) - return errors.New("tls: ech: got retry configs after ECH acceptance") - } - } - - hs.hsTimings.ReadEncryptedExtensions = hs.hsTimings.elapsedTime() - - return nil -} - -func (hs *clientHandshakeStateTLS13) readServerCertificate() error { - c := hs.c - - // Either a PSK or a certificate is always used, but not both. - // See RFC 8446, Section 4.1.1. - if hs.usingPSK { - // Make sure the connection is still being verified whether or not this - // is a resumption. Resumptions currently don't reverify certificates so - // they don't call verifyServerCertificate. See Issue 31641. - if c.config.VerifyConnection != nil { - if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil { - c.sendAlert(alertBadCertificate) - return err - } - } - return nil - } - - msg, err := c.readHandshake() - if err != nil { - return err - } - - certReq, ok := msg.(*certificateRequestMsgTLS13) - if ok { - hs.transcript.Write(certReq.marshal()) - - hs.certReq = certReq - - msg, err = c.readHandshake() - if err != nil { - return err - } - } - - certMsg, ok := msg.(*certificateMsgTLS13) - if !ok { - c.sendAlert(alertUnexpectedMessage) - return unexpectedMessageError(certMsg, msg) - } - if len(certMsg.certificate.Certificate) == 0 { - c.sendAlert(alertDecodeError) - return errors.New("tls: received empty certificates message") - } - hs.transcript.Write(certMsg.marshal()) - - hs.hsTimings.ReadCertificate = hs.hsTimings.elapsedTime() - - c.scts = certMsg.certificate.SignedCertificateTimestamps - c.ocspResponse = certMsg.certificate.OCSPStaple - - if err := c.verifyServerCertificate(certMsg.certificate.Certificate); err != nil { - return err - } - - msg, err = c.readHandshake() - if err != nil { - return err - } - - certVerify, ok := msg.(*certificateVerifyMsg) - if !ok { - c.sendAlert(alertUnexpectedMessage) - return unexpectedMessageError(certVerify, msg) - } - - // See RFC 8446, Section 4.4.3. - if !isSupportedSignatureAlgorithm(certVerify.signatureAlgorithm, c.config.supportedSignatureAlgorithms()) { - c.sendAlert(alertIllegalParameter) - return errors.New("tls: certificate used with invalid signature algorithm") - } - - sigType, sigHash, err := typeAndHashFromSignatureScheme(certVerify.signatureAlgorithm) - if err != nil { - return c.sendAlert(alertInternalError) - } - if sigType == signaturePKCS1v15 || sigHash == crypto.SHA1 { - c.sendAlert(alertIllegalParameter) - return errors.New("tls: certificate used with invalid signature algorithm") - } - if certMsg.delegatedCredential { - if err := hs.processDelegatedCredentialFromServer(certMsg.certificate.DelegatedCredential, certVerify); err != nil { - return err // alert sent - } - } - - pk := c.peerCertificates[0].PublicKey - if c.verifiedDC != nil { - pk = c.verifiedDC.cred.publicKey - } - - signed := signedMessage(sigHash, serverSignatureContext, hs.transcript) - if err := verifyHandshakeSignature(sigType, pk, - sigHash, signed, certVerify.signature); err != nil { - c.sendAlert(alertDecryptError) - return errors.New("tls: invalid signature by the server certificate: " + err.Error()) - } - - hs.transcript.Write(certVerify.marshal()) - - hs.hsTimings.ReadCertificateVerify = hs.hsTimings.elapsedTime() - - return nil -} - -func (hs *clientHandshakeStateTLS13) readServerFinished() error { - c := hs.c - - msg, err := c.readHandshake() - if err != nil { - return err - } - - finished, ok := msg.(*finishedMsg) - if !ok { - c.sendAlert(alertUnexpectedMessage) - return unexpectedMessageError(finished, msg) - } - - hs.hsTimings.ReadServerFinished = hs.hsTimings.elapsedTime() - - expectedMAC := hs.suite.finishedHash(c.in.trafficSecret, hs.transcript) - if !hmac.Equal(expectedMAC, finished.verifyData) { - c.sendAlert(alertDecryptError) - return errors.New("tls: invalid server finished hash") - } - - hs.transcript.Write(finished.marshal()) - - // Derive secrets that take context through the server Finished. - - hs.trafficSecret = hs.suite.deriveSecret(hs.masterSecret, - clientApplicationTrafficLabel, hs.transcript) - serverSecret := hs.suite.deriveSecret(hs.masterSecret, - serverApplicationTrafficLabel, hs.transcript) - c.in.setTrafficSecret(hs.suite, serverSecret) - - err = c.config.writeKeyLog(keyLogLabelClientTraffic, hs.hello.random, hs.trafficSecret) - if err != nil { - c.sendAlert(alertInternalError) - return err - } - err = c.config.writeKeyLog(keyLogLabelServerTraffic, hs.hello.random, serverSecret) - if err != nil { - c.sendAlert(alertInternalError) - return err - } - - c.ekm = hs.suite.exportKeyingMaterial(hs.masterSecret, hs.transcript) - - return nil -} - -func certificateRequestInfo(certReq *certificateRequestMsgTLS13, vers uint16, ctx context.Context) *CertificateRequestInfo { - cri := &CertificateRequestInfo{ - SupportsDelegatedCredential: certReq.supportDelegatedCredential, - SignatureSchemes: certReq.supportedSignatureAlgorithms, - SignatureSchemesDC: certReq.supportedSignatureAlgorithmsDC, - AcceptableCAs: certReq.certificateAuthorities, - Version: vers, - ctx: ctx, - } - - return cri -} - -// getClientDelegatedCredential will return a Delegated Credential pair (a -// Delegated Credential and its private key) for the given CertificateRequestInfo, -// defaulting to the first element of cert.DelegatedCredentialPair. -// The returned Delegated Credential could be invalid for usage in the handshake. -// Returns an error if there are no delegated credentials or if the one found -// cannot be used for the current connection. -func getClientDelegatedCredential(cri *CertificateRequestInfo, cert *Certificate) (*DelegatedCredentialPair, error) { - if len(cert.DelegatedCredentials) == 0 { - return nil, errors.New("no Delegated Credential found") - } - - for _, dcPair := range cert.DelegatedCredentials { - // If the client sent the signature_algorithms in the DC extension, ensure it supports - // schemes we can use with this delegated credential. - if len(cri.SignatureSchemesDC) > 0 { - if _, err := selectSignatureSchemeDC(VersionTLS13, dcPair.DC, cri.SignatureSchemes, cri.SignatureSchemesDC); err == nil { - return &dcPair, nil - } - } - } - - // No delegated credential can be returned. - return nil, errors.New("no valid Delegated Credential found") -} - -func (hs *clientHandshakeStateTLS13) sendClientCertificate() error { - c := hs.c - - if hs.certReq == nil { - return nil - } - - cri := certificateRequestInfo(hs.certReq, c.vers, hs.ctx) - - cert, err := c.getClientCertificate(cri) - if err != nil { - return err - } - - var dcPair *DelegatedCredentialPair - if hs.certReq.supportDelegatedCredential && len(hs.certReq.supportedSignatureAlgorithmsDC) > 0 { - // getClientDelegatedCredential selects a delegated credential that the server has advertised support for, if possible. - if delegatedCredentialPair, err := getClientDelegatedCredential(cri, cert); err == nil { - if delegatedCredentialPair.DC != nil && delegatedCredentialPair.PrivateKey != nil { - var err error - // Even if the Delegated Credential has already been marshalled, be sure it is the correct one. - if delegatedCredentialPair.DC.raw, err = delegatedCredentialPair.DC.Marshal(); err == nil { - dcPair = delegatedCredentialPair - cert.DelegatedCredential = dcPair.DC.raw - } - } - } - } - - certMsg := new(certificateMsgTLS13) - - certMsg.certificate = *cert - certMsg.scts = hs.certReq.scts && len(cert.SignedCertificateTimestamps) > 0 - certMsg.ocspStapling = hs.certReq.ocspStapling && len(cert.OCSPStaple) > 0 - certMsg.delegatedCredential = hs.certReq.supportDelegatedCredential && len(cert.DelegatedCredential) > 0 - - hs.transcript.Write(certMsg.marshal()) - if _, err := c.writeRecord(recordTypeHandshake, certMsg.marshal()); err != nil { - return err - } - - hs.hsTimings.WriteCertificate = hs.hsTimings.elapsedTime() - - // If we sent an empty certificate message, skip the CertificateVerify. - if len(cert.Certificate) == 0 { - return nil - } - - certVerifyMsg := new(certificateVerifyMsg) - certVerifyMsg.hasSignatureAlgorithm = true - - var sigAlgorithm SignatureScheme - suppSigAlgo := hs.certReq.supportedSignatureAlgorithms - sigAlgorithm, err = selectSignatureScheme(c.vers, cert, suppSigAlgo) - if err != nil { - // getClientCertificate returned a certificate incompatible with the - // CertificateRequestInfo supported signature algorithms. - c.sendAlert(alertHandshakeFailure) - return err - } - - if certMsg.delegatedCredential { - suppSigAlgo = hs.certReq.supportedSignatureAlgorithmsDC - if dcPair == nil || dcPair.DC == nil { - cert.DelegatedCredential = nil - } else { - sigAlgorithm = dcPair.DC.cred.expCertVerfAlgo - cert.PrivateKey = dcPair.PrivateKey - } - } - - certVerifyMsg.signatureAlgorithm = sigAlgorithm - - sigType, sigHash, err := typeAndHashFromSignatureScheme(certVerifyMsg.signatureAlgorithm) - if err != nil { - return c.sendAlert(alertInternalError) - } - - signed := signedMessage(sigHash, clientSignatureContext, hs.transcript) - signOpts := crypto.SignerOpts(sigHash) - if sigType == signatureRSAPSS { - signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: sigHash} - } - sig, err := cert.PrivateKey.(crypto.Signer).Sign(c.config.rand(), signed, signOpts) - if err != nil { - c.sendAlert(alertInternalError) - return errors.New("tls: failed to sign handshake: " + err.Error()) - } - certVerifyMsg.signature = sig - - hs.transcript.Write(certVerifyMsg.marshal()) - if _, err := c.writeRecord(recordTypeHandshake, certVerifyMsg.marshal()); err != nil { - return err - } - - hs.hsTimings.WriteCertificateVerify = hs.hsTimings.elapsedTime() - - return nil -} - -func (hs *clientHandshakeStateTLS13) sendClientFinished() error { - c := hs.c - - finished := &finishedMsg{ - verifyData: hs.suite.finishedHash(c.out.trafficSecret, hs.transcript), - } - - hs.transcript.Write(finished.marshal()) - if _, err := c.writeRecord(recordTypeHandshake, finished.marshal()); err != nil { - return err - } - - hs.hsTimings.WriteClientFinished = hs.hsTimings.elapsedTime() - - c.out.setTrafficSecret(hs.suite, hs.trafficSecret) - - if !c.config.SessionTicketsDisabled && c.config.ClientSessionCache != nil && !c.config.ECHEnabled { - c.resumptionSecret = hs.suite.deriveSecret(hs.masterSecret, - resumptionLabel, hs.transcript) - } - - return nil -} - -func (c *Conn) handleNewSessionTicket(msg *newSessionTicketMsgTLS13) error { - if !c.isClient { - c.sendAlert(alertUnexpectedMessage) - return errors.New("tls: received new session ticket from a client") - } - - if c.config.SessionTicketsDisabled || c.config.ClientSessionCache == nil || c.config.ECHEnabled { - return nil - } - - // See RFC 8446, Section 4.6.1. - if msg.lifetime == 0 { - return nil - } - lifetime := time.Duration(msg.lifetime) * time.Second - if lifetime > maxSessionTicketLifetime { - c.sendAlert(alertIllegalParameter) - return errors.New("tls: received a session ticket with invalid lifetime") - } - - cipherSuite := cipherSuiteTLS13ByID(c.cipherSuite) - if cipherSuite == nil || c.resumptionSecret == nil { - return c.sendAlert(alertInternalError) - } - - // Save the resumption_master_secret and nonce instead of deriving the PSK - // to do the least amount of work on NewSessionTicket messages before we - // know if the ticket will be used. Forward secrecy of resumed connections - // is guaranteed by the requirement for pskModeDHE. - session := &ClientSessionState{ - sessionTicket: msg.label, - vers: c.vers, - cipherSuite: c.cipherSuite, - masterSecret: c.resumptionSecret, - serverCertificates: c.peerCertificates, - verifiedChains: c.verifiedChains, - receivedAt: c.config.time(), - nonce: msg.nonce, - useBy: c.config.time().Add(lifetime), - ageAdd: msg.ageAdd, - ocspResponse: c.ocspResponse, - scts: c.scts, - } - - cacheKey := clientSessionCacheKey(c.conn.RemoteAddr(), c.config) - c.config.ClientSessionCache.Put(cacheKey, session) - - return nil -} - -func (hs *clientHandshakeStateTLS13) abortIfRequired() error { - c := hs.c - if c.ech.offered && !c.ech.accepted { - // If ECH was rejected, then abort the handshake. - c.sendAlert(alertECHRequired) - return errors.New("tls: ech: rejected") - } - return nil -} diff --git a/transport/cloudflaretls/handshake_messages.go b/transport/cloudflaretls/handshake_messages.go deleted file mode 100644 index 07b24d80..00000000 --- a/transport/cloudflaretls/handshake_messages.go +++ /dev/null @@ -1,1927 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package tls - -import ( - "fmt" - "strings" - - "golang.org/x/crypto/cryptobyte" -) - -// The marshalingFunction type is an adapter to allow the use of ordinary -// functions as cryptobyte.MarshalingValue. -type marshalingFunction func(b *cryptobyte.Builder) error - -func (f marshalingFunction) Marshal(b *cryptobyte.Builder) error { - return f(b) -} - -// addBytesWithLength appends a sequence of bytes to the cryptobyte.Builder. If -// the length of the sequence is not the value specified, it produces an error. -func addBytesWithLength(b *cryptobyte.Builder, v []byte, n int) { - b.AddValue(marshalingFunction(func(b *cryptobyte.Builder) error { - if len(v) != n { - return fmt.Errorf("invalid value length: expected %d, got %d", n, len(v)) - } - b.AddBytes(v) - return nil - })) -} - -// addUint64 appends a big-endian, 64-bit value to the cryptobyte.Builder. -func addUint64(b *cryptobyte.Builder, v uint64) { - b.AddUint32(uint32(v >> 32)) - b.AddUint32(uint32(v)) -} - -// readUint64 decodes a big-endian, 64-bit value into out and advances over it. -// It reports whether the read was successful. -func readUint64(s *cryptobyte.String, out *uint64) bool { - var hi, lo uint32 - if !s.ReadUint32(&hi) || !s.ReadUint32(&lo) { - return false - } - *out = uint64(hi)<<32 | uint64(lo) - return true -} - -// readUint8LengthPrefixed acts like s.ReadUint8LengthPrefixed, but targets a -// []byte instead of a cryptobyte.String. -func readUint8LengthPrefixed(s *cryptobyte.String, out *[]byte) bool { - return s.ReadUint8LengthPrefixed((*cryptobyte.String)(out)) -} - -// readUint16LengthPrefixed acts like s.ReadUint16LengthPrefixed, but targets a -// []byte instead of a cryptobyte.String. -func readUint16LengthPrefixed(s *cryptobyte.String, out *[]byte) bool { - return s.ReadUint16LengthPrefixed((*cryptobyte.String)(out)) -} - -// readUint24LengthPrefixed acts like s.ReadUint24LengthPrefixed, but targets a -// []byte instead of a cryptobyte.String. -func readUint24LengthPrefixed(s *cryptobyte.String, out *[]byte) bool { - return s.ReadUint24LengthPrefixed((*cryptobyte.String)(out)) -} - -type clientHelloMsg struct { - raw []byte - vers uint16 - random []byte - sessionId []byte - cipherSuites []uint16 - compressionMethods []uint8 - serverName string - ocspStapling bool - supportedCurves []CurveID - supportedPoints []uint8 - ticketSupported bool - sessionTicket []uint8 - supportedSignatureAlgorithms []SignatureScheme - supportedSignatureAlgorithmsCert []SignatureScheme - supportedSignatureAlgorithmsDC []SignatureScheme - secureRenegotiationSupported bool - secureRenegotiation []byte - delegatedCredentialSupported bool - alpnProtocols []string - scts bool - supportedVersions []uint16 - cookie []byte - keyShares []keyShare - earlyData bool - pskModes []uint8 - pskIdentities []pskIdentity - pskBinders [][]byte - ech []byte -} - -func (m *clientHelloMsg) marshal() []byte { - if m.raw != nil { - return m.raw - } - - var b cryptobyte.Builder - b.AddUint8(typeClientHello) - b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddUint16(m.vers) - addBytesWithLength(b, m.random, 32) - b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(m.sessionId) - }) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - for _, suite := range m.cipherSuites { - b.AddUint16(suite) - } - }) - b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(m.compressionMethods) - }) - - // If extensions aren't present, omit them. - var extensionsPresent bool - bWithoutExtensions := *b - - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - if len(m.ech) > 0 { - // draft-ietf-tls-esni-13, "encrypted_client_hello" - b.AddUint16(extensionECH) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(m.ech) - }) - } - if len(m.serverName) > 0 { - // RFC 6066, Section 3 - b.AddUint16(extensionServerName) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddUint8(0) // name_type = host_name - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes([]byte(m.serverName)) - }) - }) - }) - } - if m.ocspStapling { - // RFC 4366, Section 3.6 - b.AddUint16(extensionStatusRequest) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddUint8(1) // status_type = ocsp - b.AddUint16(0) // empty responder_id_list - b.AddUint16(0) // empty request_extensions - }) - } - if len(m.supportedCurves) > 0 { - // RFC 4492, sections 5.1.1 and RFC 8446, Section 4.2.7 - b.AddUint16(extensionSupportedCurves) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - for _, curve := range m.supportedCurves { - b.AddUint16(uint16(curve)) - } - }) - }) - } - if len(m.supportedPoints) > 0 { - // RFC 4492, Section 5.1.2 - b.AddUint16(extensionSupportedPoints) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(m.supportedPoints) - }) - }) - } - if m.ticketSupported { - // RFC 5077, Section 3.2 - b.AddUint16(extensionSessionTicket) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(m.sessionTicket) - }) - } - if len(m.supportedSignatureAlgorithms) > 0 { - // RFC 5246, Section 7.4.1.4.1 - b.AddUint16(extensionSignatureAlgorithms) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - for _, sigAlgo := range m.supportedSignatureAlgorithms { - b.AddUint16(uint16(sigAlgo)) - } - }) - }) - } - if len(m.supportedSignatureAlgorithmsCert) > 0 { - // RFC 8446, Section 4.2.3 - b.AddUint16(extensionSignatureAlgorithmsCert) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - for _, sigAlgo := range m.supportedSignatureAlgorithmsCert { - b.AddUint16(uint16(sigAlgo)) - } - }) - }) - } - if m.secureRenegotiationSupported { - // RFC 5746, Section 3.2 - b.AddUint16(extensionRenegotiationInfo) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(m.secureRenegotiation) - }) - }) - } - if m.delegatedCredentialSupported { - if len(m.supportedSignatureAlgorithmsDC) > 0 { - // Draft: https://tools.ietf.org/html/draft-ietf-tls-subcerts-10 - b.AddUint16(extensionDelegatedCredentials) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - for _, sigAlgo := range m.supportedSignatureAlgorithmsDC { - b.AddUint16(uint16(sigAlgo)) - } - }) - }) - } - } - if len(m.alpnProtocols) > 0 { - // RFC 7301, Section 3.1 - b.AddUint16(extensionALPN) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - for _, proto := range m.alpnProtocols { - b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes([]byte(proto)) - }) - } - }) - }) - } - if m.scts { - // RFC 6962, Section 3.3.1 - b.AddUint16(extensionSCT) - b.AddUint16(0) // empty extension_data - } - if len(m.supportedVersions) > 0 { - // RFC 8446, Section 4.2.1 - b.AddUint16(extensionSupportedVersions) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { - for _, vers := range m.supportedVersions { - b.AddUint16(vers) - } - }) - }) - } - if len(m.cookie) > 0 { - // RFC 8446, Section 4.2.2 - b.AddUint16(extensionCookie) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(m.cookie) - }) - }) - } - if len(m.keyShares) > 0 { - // RFC 8446, Section 4.2.8 - b.AddUint16(extensionKeyShare) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - for _, ks := range m.keyShares { - b.AddUint16(uint16(ks.group)) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(ks.data) - }) - } - }) - }) - } - if m.earlyData { - // RFC 8446, Section 4.2.10 - b.AddUint16(extensionEarlyData) - b.AddUint16(0) // empty extension_data - } - if len(m.pskModes) > 0 { - // RFC 8446, Section 4.2.9 - b.AddUint16(extensionPSKModes) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(m.pskModes) - }) - }) - } - if len(m.pskIdentities) > 0 { // pre_shared_key must be the last extension - // RFC 8446, Section 4.2.11 - b.AddUint16(extensionPreSharedKey) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - for _, psk := range m.pskIdentities { - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(psk.label) - }) - b.AddUint32(psk.obfuscatedTicketAge) - } - }) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - for _, binder := range m.pskBinders { - b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(binder) - }) - } - }) - }) - } - - extensionsPresent = len(b.BytesOrPanic()) > 2 - }) - - if !extensionsPresent { - *b = bWithoutExtensions - } - }) - - m.raw = b.BytesOrPanic() - return m.raw -} - -// marshalWithoutBinders returns the ClientHello through the -// PreSharedKeyExtension.identities field, according to RFC 8446, Section -// 4.2.11.2. Note that m.pskBinders must be set to slices of the correct length. -func (m *clientHelloMsg) marshalWithoutBinders() []byte { - bindersLen := 2 // uint16 length prefix - for _, binder := range m.pskBinders { - bindersLen += 1 // uint8 length prefix - bindersLen += len(binder) - } - - fullMessage := m.marshal() - return fullMessage[:len(fullMessage)-bindersLen] -} - -// updateBinders updates the m.pskBinders field, if necessary updating the -// cached marshaled representation. The supplied binders must have the same -// length as the current m.pskBinders. -func (m *clientHelloMsg) updateBinders(pskBinders [][]byte) { - if len(pskBinders) != len(m.pskBinders) { - panic("tls: internal error: pskBinders length mismatch") - } - for i := range m.pskBinders { - if len(pskBinders[i]) != len(m.pskBinders[i]) { - panic("tls: internal error: pskBinders length mismatch") - } - } - m.pskBinders = pskBinders - if m.raw != nil { - lenWithoutBinders := len(m.marshalWithoutBinders()) - b := cryptobyte.NewFixedBuilder(m.raw[:lenWithoutBinders]) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - for _, binder := range m.pskBinders { - b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(binder) - }) - } - }) - if out, err := b.Bytes(); err != nil || len(out) != len(m.raw) { - panic("tls: internal error: failed to update binders") - } - } -} - -func (m *clientHelloMsg) unmarshal(data []byte) bool { - *m = clientHelloMsg{raw: data} - s := cryptobyte.String(data) - - if !s.Skip(4) || // message type and uint24 length field - !s.ReadUint16(&m.vers) || !s.ReadBytes(&m.random, 32) || - !readUint8LengthPrefixed(&s, &m.sessionId) { - return false - } - - var cipherSuites cryptobyte.String - if !s.ReadUint16LengthPrefixed(&cipherSuites) { - return false - } - m.cipherSuites = []uint16{} - m.secureRenegotiationSupported = false - for !cipherSuites.Empty() { - var suite uint16 - if !cipherSuites.ReadUint16(&suite) { - return false - } - if suite == scsvRenegotiation { - m.secureRenegotiationSupported = true - } - m.cipherSuites = append(m.cipherSuites, suite) - } - - if !readUint8LengthPrefixed(&s, &m.compressionMethods) { - return false - } - - if s.Empty() { - // ClientHello is optionally followed by extension data - return true - } - - var extensions cryptobyte.String - if !s.ReadUint16LengthPrefixed(&extensions) || !s.Empty() { - return false - } - - for !extensions.Empty() { - var extension uint16 - var extData cryptobyte.String - if !extensions.ReadUint16(&extension) || - !extensions.ReadUint16LengthPrefixed(&extData) { - return false - } - - switch extension { - case extensionECH: - // draft-ietf-tls-esni-13, "encrypted_client_hello" - if len(extData) == 0 || - !extData.ReadBytes(&m.ech, len(extData)) { - return false - } - case extensionServerName: - // RFC 6066, Section 3 - var nameList cryptobyte.String - if !extData.ReadUint16LengthPrefixed(&nameList) || nameList.Empty() { - return false - } - for !nameList.Empty() { - var nameType uint8 - var serverName cryptobyte.String - if !nameList.ReadUint8(&nameType) || - !nameList.ReadUint16LengthPrefixed(&serverName) || - serverName.Empty() { - return false - } - if nameType != 0 { - continue - } - if len(m.serverName) != 0 { - // Multiple names of the same name_type are prohibited. - return false - } - m.serverName = string(serverName) - // An SNI value may not include a trailing dot. - if strings.HasSuffix(m.serverName, ".") { - return false - } - } - case extensionStatusRequest: - // RFC 4366, Section 3.6 - var statusType uint8 - var ignored cryptobyte.String - if !extData.ReadUint8(&statusType) || - !extData.ReadUint16LengthPrefixed(&ignored) || - !extData.ReadUint16LengthPrefixed(&ignored) { - return false - } - m.ocspStapling = statusType == statusTypeOCSP - case extensionSupportedCurves: - // RFC 4492, sections 5.1.1 and RFC 8446, Section 4.2.7 - var curves cryptobyte.String - if !extData.ReadUint16LengthPrefixed(&curves) || curves.Empty() { - return false - } - for !curves.Empty() { - var curve uint16 - if !curves.ReadUint16(&curve) { - return false - } - m.supportedCurves = append(m.supportedCurves, CurveID(curve)) - } - case extensionSupportedPoints: - // RFC 4492, Section 5.1.2 - if !readUint8LengthPrefixed(&extData, &m.supportedPoints) || - len(m.supportedPoints) == 0 { - return false - } - case extensionSessionTicket: - // RFC 5077, Section 3.2 - m.ticketSupported = true - extData.ReadBytes(&m.sessionTicket, len(extData)) - case extensionSignatureAlgorithms: - // RFC 5246, Section 7.4.1.4.1 - var sigAndAlgs cryptobyte.String - if !extData.ReadUint16LengthPrefixed(&sigAndAlgs) || sigAndAlgs.Empty() { - return false - } - for !sigAndAlgs.Empty() { - var sigAndAlg uint16 - if !sigAndAlgs.ReadUint16(&sigAndAlg) { - return false - } - m.supportedSignatureAlgorithms = append( - m.supportedSignatureAlgorithms, SignatureScheme(sigAndAlg)) - } - case extensionSignatureAlgorithmsCert: - // RFC 8446, Section 4.2.3 - var sigAndAlgs cryptobyte.String - if !extData.ReadUint16LengthPrefixed(&sigAndAlgs) || sigAndAlgs.Empty() { - return false - } - for !sigAndAlgs.Empty() { - var sigAndAlg uint16 - if !sigAndAlgs.ReadUint16(&sigAndAlg) { - return false - } - m.supportedSignatureAlgorithmsCert = append( - m.supportedSignatureAlgorithmsCert, SignatureScheme(sigAndAlg)) - } - case extensionRenegotiationInfo: - // RFC 5746, Section 3.2 - if !readUint8LengthPrefixed(&extData, &m.secureRenegotiation) { - return false - } - m.secureRenegotiationSupported = true - case extensionALPN: - // RFC 7301, Section 3.1 - var protoList cryptobyte.String - if !extData.ReadUint16LengthPrefixed(&protoList) || protoList.Empty() { - return false - } - for !protoList.Empty() { - var proto cryptobyte.String - if !protoList.ReadUint8LengthPrefixed(&proto) || proto.Empty() { - return false - } - m.alpnProtocols = append(m.alpnProtocols, string(proto)) - } - case extensionSCT: - // RFC 6962, Section 3.3.1 - m.scts = true - case extensionSupportedVersions: - // RFC 8446, Section 4.2.1 - var versList cryptobyte.String - if !extData.ReadUint8LengthPrefixed(&versList) || versList.Empty() { - return false - } - for !versList.Empty() { - var vers uint16 - if !versList.ReadUint16(&vers) { - return false - } - m.supportedVersions = append(m.supportedVersions, vers) - } - case extensionCookie: - // RFC 8446, Section 4.2.2 - if !readUint16LengthPrefixed(&extData, &m.cookie) || - len(m.cookie) == 0 { - return false - } - case extensionDelegatedCredentials: - var sigAndAlgs cryptobyte.String - if !extData.ReadUint16LengthPrefixed(&sigAndAlgs) || sigAndAlgs.Empty() { - return false - } - for !sigAndAlgs.Empty() { - var sigAndAlg uint16 - if !sigAndAlgs.ReadUint16(&sigAndAlg) { - return false - } - m.supportedSignatureAlgorithmsDC = append( - m.supportedSignatureAlgorithmsDC, SignatureScheme(sigAndAlg)) - } - m.delegatedCredentialSupported = true - case extensionKeyShare: - // RFC 8446, Section 4.2.8 - var clientShares cryptobyte.String - if !extData.ReadUint16LengthPrefixed(&clientShares) { - return false - } - for !clientShares.Empty() { - var ks keyShare - if !clientShares.ReadUint16((*uint16)(&ks.group)) || - !readUint16LengthPrefixed(&clientShares, &ks.data) || - len(ks.data) == 0 { - return false - } - m.keyShares = append(m.keyShares, ks) - } - case extensionEarlyData: - // RFC 8446, Section 4.2.10 - m.earlyData = true - case extensionPSKModes: - // RFC 8446, Section 4.2.9 - if !readUint8LengthPrefixed(&extData, &m.pskModes) { - return false - } - case extensionPreSharedKey: - // RFC 8446, Section 4.2.11 - if !extensions.Empty() { - return false // pre_shared_key must be the last extension - } - var identities cryptobyte.String - if !extData.ReadUint16LengthPrefixed(&identities) || identities.Empty() { - return false - } - for !identities.Empty() { - var psk pskIdentity - if !readUint16LengthPrefixed(&identities, &psk.label) || - !identities.ReadUint32(&psk.obfuscatedTicketAge) || - len(psk.label) == 0 { - return false - } - m.pskIdentities = append(m.pskIdentities, psk) - } - var binders cryptobyte.String - if !extData.ReadUint16LengthPrefixed(&binders) || binders.Empty() { - return false - } - for !binders.Empty() { - var binder []byte - if !readUint8LengthPrefixed(&binders, &binder) || - len(binder) == 0 { - return false - } - m.pskBinders = append(m.pskBinders, binder) - } - default: - // Ignore unknown extensions. - continue - } - - if !extData.Empty() { - return false - } - } - - return true -} - -type serverHelloMsg struct { - raw []byte - vers uint16 - random []byte - sessionId []byte - cipherSuite uint16 - compressionMethod uint8 - ocspStapling bool - ticketSupported bool - secureRenegotiationSupported bool - secureRenegotiation []byte - alpnProtocol string - scts [][]byte - supportedVersion uint16 - serverShare keyShare - selectedIdentityPresent bool - selectedIdentity uint16 - supportedPoints []uint8 - - // HelloRetryRequest extensions - cookie []byte - selectedGroup CurveID - ech []byte -} - -func (m *serverHelloMsg) marshal() []byte { - if m.raw != nil { - return m.raw - } - - var b cryptobyte.Builder - b.AddUint8(typeServerHello) - b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddUint16(m.vers) - addBytesWithLength(b, m.random, 32) - b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(m.sessionId) - }) - b.AddUint16(m.cipherSuite) - b.AddUint8(m.compressionMethod) - - // If extensions aren't present, omit them. - var extensionsPresent bool - bWithoutExtensions := *b - - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - if m.ocspStapling { - b.AddUint16(extensionStatusRequest) - b.AddUint16(0) // empty extension_data - } - if m.ticketSupported { - b.AddUint16(extensionSessionTicket) - b.AddUint16(0) // empty extension_data - } - if m.secureRenegotiationSupported { - b.AddUint16(extensionRenegotiationInfo) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(m.secureRenegotiation) - }) - }) - } - if len(m.alpnProtocol) > 0 { - b.AddUint16(extensionALPN) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes([]byte(m.alpnProtocol)) - }) - }) - }) - } - if len(m.scts) > 0 { - b.AddUint16(extensionSCT) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - for _, sct := range m.scts { - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(sct) - }) - } - }) - }) - } - if m.supportedVersion != 0 { - b.AddUint16(extensionSupportedVersions) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddUint16(m.supportedVersion) - }) - } - if m.serverShare.group != 0 { - b.AddUint16(extensionKeyShare) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddUint16(uint16(m.serverShare.group)) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(m.serverShare.data) - }) - }) - } - if m.selectedIdentityPresent { - b.AddUint16(extensionPreSharedKey) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddUint16(m.selectedIdentity) - }) - } - - if len(m.cookie) > 0 { - b.AddUint16(extensionCookie) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(m.cookie) - }) - }) - } - if m.selectedGroup != 0 { - b.AddUint16(extensionKeyShare) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddUint16(uint16(m.selectedGroup)) - }) - } - if len(m.supportedPoints) > 0 { - b.AddUint16(extensionSupportedPoints) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(m.supportedPoints) - }) - }) - } - if len(m.ech) > 0 { - // draft-ietf-tls-esni-13, "encrypted_client_hello" - b.AddUint16(extensionECH) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(m.ech) - }) - } - - extensionsPresent = len(b.BytesOrPanic()) > 2 - }) - - if !extensionsPresent { - *b = bWithoutExtensions - } - }) - - m.raw = b.BytesOrPanic() - return m.raw -} - -func (m *serverHelloMsg) unmarshal(data []byte) bool { - *m = serverHelloMsg{raw: data} - s := cryptobyte.String(data) - - if !s.Skip(4) || // message type and uint24 length field - !s.ReadUint16(&m.vers) || !s.ReadBytes(&m.random, 32) || - !readUint8LengthPrefixed(&s, &m.sessionId) || - !s.ReadUint16(&m.cipherSuite) || - !s.ReadUint8(&m.compressionMethod) { - return false - } - - if s.Empty() { - // ServerHello is optionally followed by extension data - return true - } - - var extensions cryptobyte.String - if !s.ReadUint16LengthPrefixed(&extensions) || !s.Empty() { - return false - } - - for !extensions.Empty() { - var extension uint16 - var extData cryptobyte.String - if !extensions.ReadUint16(&extension) || - !extensions.ReadUint16LengthPrefixed(&extData) { - return false - } - - switch extension { - case extensionStatusRequest: - m.ocspStapling = true - case extensionSessionTicket: - m.ticketSupported = true - case extensionRenegotiationInfo: - if !readUint8LengthPrefixed(&extData, &m.secureRenegotiation) { - return false - } - m.secureRenegotiationSupported = true - case extensionALPN: - var protoList cryptobyte.String - if !extData.ReadUint16LengthPrefixed(&protoList) || protoList.Empty() { - return false - } - var proto cryptobyte.String - if !protoList.ReadUint8LengthPrefixed(&proto) || - proto.Empty() || !protoList.Empty() { - return false - } - m.alpnProtocol = string(proto) - case extensionSCT: - var sctList cryptobyte.String - if !extData.ReadUint16LengthPrefixed(&sctList) || sctList.Empty() { - return false - } - for !sctList.Empty() { - var sct []byte - if !readUint16LengthPrefixed(&sctList, &sct) || - len(sct) == 0 { - return false - } - m.scts = append(m.scts, sct) - } - case extensionSupportedVersions: - if !extData.ReadUint16(&m.supportedVersion) { - return false - } - case extensionCookie: - if !readUint16LengthPrefixed(&extData, &m.cookie) || - len(m.cookie) == 0 { - return false - } - case extensionKeyShare: - // This extension has different formats in SH and HRR, accept either - // and let the handshake logic decide. See RFC 8446, Section 4.2.8. - if len(extData) == 2 { - if !extData.ReadUint16((*uint16)(&m.selectedGroup)) { - return false - } - } else { - if !extData.ReadUint16((*uint16)(&m.serverShare.group)) || - !readUint16LengthPrefixed(&extData, &m.serverShare.data) { - return false - } - } - case extensionPreSharedKey: - m.selectedIdentityPresent = true - if !extData.ReadUint16(&m.selectedIdentity) { - return false - } - case extensionSupportedPoints: - // RFC 4492, Section 5.1.2 - if !readUint8LengthPrefixed(&extData, &m.supportedPoints) || - len(m.supportedPoints) == 0 { - return false - } - case extensionECH: - // draft-ietf-tls-esni-13, "encrypted_client_hello" - if !extData.ReadBytes(&m.ech, len(extData)) { - return false - } - default: - // Ignore unknown extensions. - continue - } - - if !extData.Empty() { - return false - } - } - - return true -} - -type encryptedExtensionsMsg struct { - raw []byte - alpnProtocol string - ech []byte -} - -func (m *encryptedExtensionsMsg) marshal() []byte { - if m.raw != nil { - return m.raw - } - - var b cryptobyte.Builder - b.AddUint8(typeEncryptedExtensions) - b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - if len(m.alpnProtocol) > 0 { - b.AddUint16(extensionALPN) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes([]byte(m.alpnProtocol)) - }) - }) - }) - } - if len(m.ech) > 0 { - // draft-ietf-tls-esni-13, "encrypted_client_hello" - b.AddUint16(extensionECH) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - // If the client-facing server rejects ECH, then it may - // sends retry configurations here. - b.AddBytes(m.ech) - }) - } - }) - }) - - m.raw = b.BytesOrPanic() - return m.raw -} - -func (m *encryptedExtensionsMsg) unmarshal(data []byte) bool { - *m = encryptedExtensionsMsg{raw: data} - s := cryptobyte.String(data) - - var extensions cryptobyte.String - if !s.Skip(4) || // message type and uint24 length field - !s.ReadUint16LengthPrefixed(&extensions) || !s.Empty() { - return false - } - - for !extensions.Empty() { - var extension uint16 - var extData cryptobyte.String - if !extensions.ReadUint16(&extension) || - !extensions.ReadUint16LengthPrefixed(&extData) { - return false - } - - switch extension { - case extensionALPN: - var protoList cryptobyte.String - if !extData.ReadUint16LengthPrefixed(&protoList) || protoList.Empty() { - return false - } - var proto cryptobyte.String - if !protoList.ReadUint8LengthPrefixed(&proto) || - proto.Empty() || !protoList.Empty() { - return false - } - m.alpnProtocol = string(proto) - case extensionECH: - // draft-ietf-tls-esni-13 - if !extData.ReadBytes(&m.ech, len(extData)) { - return false - } - default: - // Ignore unknown extensions. - continue - } - - if !extData.Empty() { - return false - } - } - - return true -} - -type endOfEarlyDataMsg struct{} - -func (m *endOfEarlyDataMsg) marshal() []byte { - x := make([]byte, 4) - x[0] = typeEndOfEarlyData - return x -} - -func (m *endOfEarlyDataMsg) unmarshal(data []byte) bool { - return len(data) == 4 -} - -type keyUpdateMsg struct { - raw []byte - updateRequested bool -} - -func (m *keyUpdateMsg) marshal() []byte { - if m.raw != nil { - return m.raw - } - - var b cryptobyte.Builder - b.AddUint8(typeKeyUpdate) - b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { - if m.updateRequested { - b.AddUint8(1) - } else { - b.AddUint8(0) - } - }) - - m.raw = b.BytesOrPanic() - return m.raw -} - -func (m *keyUpdateMsg) unmarshal(data []byte) bool { - m.raw = data - s := cryptobyte.String(data) - - var updateRequested uint8 - if !s.Skip(4) || // message type and uint24 length field - !s.ReadUint8(&updateRequested) || !s.Empty() { - return false - } - switch updateRequested { - case 0: - m.updateRequested = false - case 1: - m.updateRequested = true - default: - return false - } - return true -} - -type newSessionTicketMsgTLS13 struct { - raw []byte - lifetime uint32 - ageAdd uint32 - nonce []byte - label []byte - maxEarlyData uint32 -} - -func (m *newSessionTicketMsgTLS13) marshal() []byte { - if m.raw != nil { - return m.raw - } - - var b cryptobyte.Builder - b.AddUint8(typeNewSessionTicket) - b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddUint32(m.lifetime) - b.AddUint32(m.ageAdd) - b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(m.nonce) - }) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(m.label) - }) - - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - if m.maxEarlyData > 0 { - b.AddUint16(extensionEarlyData) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddUint32(m.maxEarlyData) - }) - } - }) - }) - - m.raw = b.BytesOrPanic() - return m.raw -} - -func (m *newSessionTicketMsgTLS13) unmarshal(data []byte) bool { - *m = newSessionTicketMsgTLS13{raw: data} - s := cryptobyte.String(data) - - var extensions cryptobyte.String - if !s.Skip(4) || // message type and uint24 length field - !s.ReadUint32(&m.lifetime) || - !s.ReadUint32(&m.ageAdd) || - !readUint8LengthPrefixed(&s, &m.nonce) || - !readUint16LengthPrefixed(&s, &m.label) || - !s.ReadUint16LengthPrefixed(&extensions) || - !s.Empty() { - return false - } - - for !extensions.Empty() { - var extension uint16 - var extData cryptobyte.String - if !extensions.ReadUint16(&extension) || - !extensions.ReadUint16LengthPrefixed(&extData) { - return false - } - - switch extension { - case extensionEarlyData: - if !extData.ReadUint32(&m.maxEarlyData) { - return false - } - default: - // Ignore unknown extensions. - continue - } - - if !extData.Empty() { - return false - } - } - - return true -} - -type certificateRequestMsgTLS13 struct { - raw []byte - ocspStapling bool - scts bool - supportDelegatedCredential bool - supportedSignatureAlgorithms []SignatureScheme - supportedSignatureAlgorithmsDC []SignatureScheme - supportedSignatureAlgorithmsCert []SignatureScheme - certificateAuthorities [][]byte -} - -func (m *certificateRequestMsgTLS13) marshal() []byte { - if m.raw != nil { - return m.raw - } - - var b cryptobyte.Builder - b.AddUint8(typeCertificateRequest) - b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { - // certificate_request_context (SHALL be zero length unless used for - // post-handshake authentication) - b.AddUint8(0) - - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - if m.ocspStapling { - b.AddUint16(extensionStatusRequest) - b.AddUint16(0) // empty extension_data - } - if m.scts { - // RFC 8446, Section 4.4.2.1 makes no mention of - // signed_certificate_timestamp in CertificateRequest, but - // "Extensions in the Certificate message from the client MUST - // correspond to extensions in the CertificateRequest message - // from the server." and it appears in the table in Section 4.2. - b.AddUint16(extensionSCT) - b.AddUint16(0) // empty extension_data - } - if m.supportDelegatedCredential { - if len(m.supportedSignatureAlgorithmsDC) > 0 { - // Draft: https://tools.ietf.org/html/draft-ietf-tls-subcerts-10 - b.AddUint16(extensionDelegatedCredentials) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - for _, sigAlgo := range m.supportedSignatureAlgorithmsDC { - b.AddUint16(uint16(sigAlgo)) - } - }) - }) - } - } - if len(m.supportedSignatureAlgorithms) > 0 { - b.AddUint16(extensionSignatureAlgorithms) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - for _, sigAlgo := range m.supportedSignatureAlgorithms { - b.AddUint16(uint16(sigAlgo)) - } - }) - }) - } - if len(m.supportedSignatureAlgorithmsCert) > 0 { - b.AddUint16(extensionSignatureAlgorithmsCert) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - for _, sigAlgo := range m.supportedSignatureAlgorithmsCert { - b.AddUint16(uint16(sigAlgo)) - } - }) - }) - } - if len(m.certificateAuthorities) > 0 { - b.AddUint16(extensionCertificateAuthorities) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - for _, ca := range m.certificateAuthorities { - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(ca) - }) - } - }) - }) - } - }) - }) - - m.raw = b.BytesOrPanic() - return m.raw -} - -func (m *certificateRequestMsgTLS13) unmarshal(data []byte) bool { - *m = certificateRequestMsgTLS13{raw: data} - s := cryptobyte.String(data) - - var context, extensions cryptobyte.String - if !s.Skip(4) || // message type and uint24 length field - !s.ReadUint8LengthPrefixed(&context) || !context.Empty() || - !s.ReadUint16LengthPrefixed(&extensions) || - !s.Empty() { - return false - } - - for !extensions.Empty() { - var extension uint16 - var extData cryptobyte.String - if !extensions.ReadUint16(&extension) || - !extensions.ReadUint16LengthPrefixed(&extData) { - return false - } - - switch extension { - case extensionStatusRequest: - m.ocspStapling = true - case extensionSCT: - m.scts = true - case extensionDelegatedCredentials: - var sigAndAlgs cryptobyte.String - if !extData.ReadUint16LengthPrefixed(&sigAndAlgs) || sigAndAlgs.Empty() { - return false - } - for !sigAndAlgs.Empty() { - var sigAndAlg uint16 - if !sigAndAlgs.ReadUint16(&sigAndAlg) { - return false - } - m.supportedSignatureAlgorithmsDC = append( - m.supportedSignatureAlgorithmsDC, SignatureScheme(sigAndAlg)) - } - m.supportDelegatedCredential = true - case extensionSignatureAlgorithms: - var sigAndAlgs cryptobyte.String - if !extData.ReadUint16LengthPrefixed(&sigAndAlgs) || sigAndAlgs.Empty() { - return false - } - for !sigAndAlgs.Empty() { - var sigAndAlg uint16 - if !sigAndAlgs.ReadUint16(&sigAndAlg) { - return false - } - m.supportedSignatureAlgorithms = append( - m.supportedSignatureAlgorithms, SignatureScheme(sigAndAlg)) - } - case extensionSignatureAlgorithmsCert: - var sigAndAlgs cryptobyte.String - if !extData.ReadUint16LengthPrefixed(&sigAndAlgs) || sigAndAlgs.Empty() { - return false - } - for !sigAndAlgs.Empty() { - var sigAndAlg uint16 - if !sigAndAlgs.ReadUint16(&sigAndAlg) { - return false - } - m.supportedSignatureAlgorithmsCert = append( - m.supportedSignatureAlgorithmsCert, SignatureScheme(sigAndAlg)) - } - case extensionCertificateAuthorities: - var auths cryptobyte.String - if !extData.ReadUint16LengthPrefixed(&auths) || auths.Empty() { - return false - } - for !auths.Empty() { - var ca []byte - if !readUint16LengthPrefixed(&auths, &ca) || len(ca) == 0 { - return false - } - m.certificateAuthorities = append(m.certificateAuthorities, ca) - } - default: - // Ignore unknown extensions. - continue - } - - if !extData.Empty() { - return false - } - } - - return true -} - -type certificateMsg struct { - raw []byte - certificates [][]byte -} - -func (m *certificateMsg) marshal() (x []byte) { - if m.raw != nil { - return m.raw - } - - var i int - for _, slice := range m.certificates { - i += len(slice) - } - - length := 3 + 3*len(m.certificates) + i - x = make([]byte, 4+length) - x[0] = typeCertificate - x[1] = uint8(length >> 16) - x[2] = uint8(length >> 8) - x[3] = uint8(length) - - certificateOctets := length - 3 - x[4] = uint8(certificateOctets >> 16) - x[5] = uint8(certificateOctets >> 8) - x[6] = uint8(certificateOctets) - - y := x[7:] - for _, slice := range m.certificates { - y[0] = uint8(len(slice) >> 16) - y[1] = uint8(len(slice) >> 8) - y[2] = uint8(len(slice)) - copy(y[3:], slice) - y = y[3+len(slice):] - } - - m.raw = x - return -} - -func (m *certificateMsg) unmarshal(data []byte) bool { - if len(data) < 7 { - return false - } - - m.raw = data - certsLen := uint32(data[4])<<16 | uint32(data[5])<<8 | uint32(data[6]) - if uint32(len(data)) != certsLen+7 { - return false - } - - numCerts := 0 - d := data[7:] - for certsLen > 0 { - if len(d) < 4 { - return false - } - certLen := uint32(d[0])<<16 | uint32(d[1])<<8 | uint32(d[2]) - if uint32(len(d)) < 3+certLen { - return false - } - d = d[3+certLen:] - certsLen -= 3 + certLen - numCerts++ - } - - m.certificates = make([][]byte, numCerts) - d = data[7:] - for i := 0; i < numCerts; i++ { - certLen := uint32(d[0])<<16 | uint32(d[1])<<8 | uint32(d[2]) - m.certificates[i] = d[3 : 3+certLen] - d = d[3+certLen:] - } - - return true -} - -type certificateMsgTLS13 struct { - raw []byte - certificate Certificate - ocspStapling bool - scts bool - delegatedCredential bool -} - -func (m *certificateMsgTLS13) marshal() []byte { - if m.raw != nil { - return m.raw - } - - var b cryptobyte.Builder - b.AddUint8(typeCertificate) - b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddUint8(0) // certificate_request_context - - certificate := m.certificate - if !m.ocspStapling { - certificate.OCSPStaple = nil - } - if !m.scts { - certificate.SignedCertificateTimestamps = nil - } - if !m.delegatedCredential { - certificate.DelegatedCredential = nil - } - marshalCertificate(b, certificate) - }) - - m.raw = b.BytesOrPanic() - - return m.raw -} - -func marshalCertificate(b *cryptobyte.Builder, certificate Certificate) { - b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { - for i, cert := range certificate.Certificate { - b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(cert) - }) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - if i > 0 { - // This library only supports OCSP, SCT and Delegated Credentials for leaf certificates. - // Delegated Credentials are only supported on the leaf/end-entity certificate. - return - } - if certificate.OCSPStaple != nil { - b.AddUint16(extensionStatusRequest) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddUint8(statusTypeOCSP) - b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(certificate.OCSPStaple) - }) - }) - } - if certificate.SignedCertificateTimestamps != nil { - b.AddUint16(extensionSCT) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - for _, sct := range certificate.SignedCertificateTimestamps { - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(sct) - }) - } - }) - }) - } - if certificate.DelegatedCredential != nil { - b.AddUint16(extensionDelegatedCredentials) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(certificate.DelegatedCredential) - }) - } - }) - } - }) -} - -func (m *certificateMsgTLS13) unmarshal(data []byte) bool { - *m = certificateMsgTLS13{raw: data} - s := cryptobyte.String(data) - - var context cryptobyte.String - if !s.Skip(4) || // message type and uint24 length field - !s.ReadUint8LengthPrefixed(&context) || !context.Empty() || - !unmarshalCertificate(&s, &m.certificate) || - !s.Empty() { - return false - } - - m.scts = m.certificate.SignedCertificateTimestamps != nil - m.ocspStapling = m.certificate.OCSPStaple != nil - m.delegatedCredential = m.certificate.DelegatedCredential != nil - - return true -} - -func unmarshalCertificate(s *cryptobyte.String, certificate *Certificate) bool { - var certList cryptobyte.String - if !s.ReadUint24LengthPrefixed(&certList) { - return false - } - for !certList.Empty() { - var cert []byte - var extensions cryptobyte.String - if !readUint24LengthPrefixed(&certList, &cert) || - !certList.ReadUint16LengthPrefixed(&extensions) { - return false - } - certificate.Certificate = append(certificate.Certificate, cert) - for !extensions.Empty() { - var extension uint16 - var extData cryptobyte.String - if !extensions.ReadUint16(&extension) || - !extensions.ReadUint16LengthPrefixed(&extData) { - return false - } - if len(certificate.Certificate) > 1 { - // This library only supports OCSP and SCT for leaf certificates. - continue - } - - switch extension { - case extensionStatusRequest: - var statusType uint8 - if !extData.ReadUint8(&statusType) || statusType != statusTypeOCSP || - !readUint24LengthPrefixed(&extData, &certificate.OCSPStaple) || - len(certificate.OCSPStaple) == 0 { - return false - } - case extensionSCT: - var sctList cryptobyte.String - if !extData.ReadUint16LengthPrefixed(&sctList) || sctList.Empty() { - return false - } - for !sctList.Empty() { - var sct []byte - if !readUint16LengthPrefixed(&sctList, &sct) || - len(sct) == 0 { - return false - } - certificate.SignedCertificateTimestamps = append( - certificate.SignedCertificateTimestamps, sct) - } - case extensionDelegatedCredentials: - if !extData.ReadBytes(&certificate.DelegatedCredential, len(extData)) { - return false - } - if len(certificate.DelegatedCredential) == 0 { - return false - } - default: - // Ignore unknown extensions. - continue - } - - if !extData.Empty() { - return false - } - } - } - return true -} - -type serverKeyExchangeMsg struct { - raw []byte - key []byte -} - -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 -} - -func (m *serverKeyExchangeMsg) unmarshal(data []byte) bool { - m.raw = data - if len(data) < 4 { - return false - } - m.key = data[4:] - return true -} - -type certificateStatusMsg struct { - raw []byte - response []byte -} - -func (m *certificateStatusMsg) marshal() []byte { - if m.raw != nil { - return m.raw - } - - var b cryptobyte.Builder - b.AddUint8(typeCertificateStatus) - b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddUint8(statusTypeOCSP) - b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(m.response) - }) - }) - - m.raw = b.BytesOrPanic() - return m.raw -} - -func (m *certificateStatusMsg) unmarshal(data []byte) bool { - m.raw = data - s := cryptobyte.String(data) - - var statusType uint8 - if !s.Skip(4) || // message type and uint24 length field - !s.ReadUint8(&statusType) || statusType != statusTypeOCSP || - !readUint24LengthPrefixed(&s, &m.response) || - len(m.response) == 0 || !s.Empty() { - return false - } - return true -} - -type serverHelloDoneMsg struct{} - -func (m *serverHelloDoneMsg) marshal() []byte { - x := make([]byte, 4) - x[0] = typeServerHelloDone - return x -} - -func (m *serverHelloDoneMsg) unmarshal(data []byte) bool { - return len(data) == 4 -} - -type clientKeyExchangeMsg struct { - raw []byte - ciphertext []byte -} - -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 -} - -func (m *clientKeyExchangeMsg) unmarshal(data []byte) bool { - m.raw = data - if len(data) < 4 { - return false - } - l := int(data[1])<<16 | int(data[2])<<8 | int(data[3]) - if l != len(data)-4 { - return false - } - m.ciphertext = data[4:] - return true -} - -type finishedMsg struct { - raw []byte - verifyData []byte -} - -func (m *finishedMsg) marshal() []byte { - if m.raw != nil { - return m.raw - } - - var b cryptobyte.Builder - b.AddUint8(typeFinished) - b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(m.verifyData) - }) - - m.raw = b.BytesOrPanic() - return m.raw -} - -func (m *finishedMsg) unmarshal(data []byte) bool { - m.raw = data - s := cryptobyte.String(data) - return s.Skip(1) && - readUint24LengthPrefixed(&s, &m.verifyData) && - s.Empty() -} - -type certificateRequestMsg struct { - raw []byte - // hasSignatureAlgorithm indicates whether this message includes a list of - // supported signature algorithms. This change was introduced with TLS 1.2. - hasSignatureAlgorithm bool - - certificateTypes []byte - supportedSignatureAlgorithms []SignatureScheme - certificateAuthorities [][]byte -} - -func (m *certificateRequestMsg) marshal() (x []byte) { - if m.raw != nil { - return m.raw - } - - // See RFC 4346, Section 7.4.4. - length := 1 + len(m.certificateTypes) + 2 - casLength := 0 - for _, ca := range m.certificateAuthorities { - casLength += 2 + len(ca) - } - length += casLength - - if m.hasSignatureAlgorithm { - length += 2 + 2*len(m.supportedSignatureAlgorithms) - } - - x = make([]byte, 4+length) - x[0] = typeCertificateRequest - x[1] = uint8(length >> 16) - x[2] = uint8(length >> 8) - x[3] = uint8(length) - - x[4] = uint8(len(m.certificateTypes)) - - copy(x[5:], m.certificateTypes) - y := x[5+len(m.certificateTypes):] - - if m.hasSignatureAlgorithm { - n := len(m.supportedSignatureAlgorithms) * 2 - y[0] = uint8(n >> 8) - y[1] = uint8(n) - y = y[2:] - for _, sigAlgo := range m.supportedSignatureAlgorithms { - y[0] = uint8(sigAlgo >> 8) - y[1] = uint8(sigAlgo) - y = y[2:] - } - } - - y[0] = uint8(casLength >> 8) - y[1] = uint8(casLength) - y = y[2:] - for _, ca := range m.certificateAuthorities { - y[0] = uint8(len(ca) >> 8) - y[1] = uint8(len(ca)) - y = y[2:] - copy(y, ca) - y = y[len(ca):] - } - - m.raw = x - return -} - -func (m *certificateRequestMsg) unmarshal(data []byte) bool { - m.raw = data - - if len(data) < 5 { - return false - } - - length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3]) - if uint32(len(data))-4 != length { - return false - } - - numCertTypes := int(data[4]) - data = data[5:] - if numCertTypes == 0 || len(data) <= numCertTypes { - return false - } - - m.certificateTypes = make([]byte, numCertTypes) - if copy(m.certificateTypes, data) != numCertTypes { - return false - } - - data = data[numCertTypes:] - - if m.hasSignatureAlgorithm { - if len(data) < 2 { - return false - } - sigAndHashLen := uint16(data[0])<<8 | uint16(data[1]) - data = data[2:] - if sigAndHashLen&1 != 0 { - return false - } - if len(data) < int(sigAndHashLen) { - return false - } - numSigAlgos := sigAndHashLen / 2 - m.supportedSignatureAlgorithms = make([]SignatureScheme, numSigAlgos) - for i := range m.supportedSignatureAlgorithms { - m.supportedSignatureAlgorithms[i] = SignatureScheme(data[0])<<8 | SignatureScheme(data[1]) - data = data[2:] - } - } - - if len(data) < 2 { - return false - } - casLength := uint16(data[0])<<8 | uint16(data[1]) - data = data[2:] - if len(data) < int(casLength) { - return false - } - cas := make([]byte, casLength) - copy(cas, data) - data = data[casLength:] - - m.certificateAuthorities = nil - for len(cas) > 0 { - if len(cas) < 2 { - return false - } - caLen := uint16(cas[0])<<8 | uint16(cas[1]) - cas = cas[2:] - - if len(cas) < int(caLen) { - return false - } - - m.certificateAuthorities = append(m.certificateAuthorities, cas[:caLen]) - cas = cas[caLen:] - } - - return len(data) == 0 -} - -type certificateVerifyMsg struct { - raw []byte - hasSignatureAlgorithm bool // format change introduced in TLS 1.2 - signatureAlgorithm SignatureScheme - signature []byte -} - -func (m *certificateVerifyMsg) marshal() (x []byte) { - if m.raw != nil { - return m.raw - } - - var b cryptobyte.Builder - b.AddUint8(typeCertificateVerify) - b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { - if m.hasSignatureAlgorithm { - b.AddUint16(uint16(m.signatureAlgorithm)) - } - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(m.signature) - }) - }) - - m.raw = b.BytesOrPanic() - return m.raw -} - -func (m *certificateVerifyMsg) unmarshal(data []byte) bool { - m.raw = data - s := cryptobyte.String(data) - - if !s.Skip(4) { // message type and uint24 length field - return false - } - if m.hasSignatureAlgorithm { - if !s.ReadUint16((*uint16)(&m.signatureAlgorithm)) { - return false - } - } - return readUint16LengthPrefixed(&s, &m.signature) && s.Empty() -} - -type newSessionTicketMsg struct { - raw []byte - ticket []byte -} - -func (m *newSessionTicketMsg) marshal() (x []byte) { - if m.raw != nil { - return m.raw - } - - // See RFC 5077, Section 3.3. - ticketLen := len(m.ticket) - length := 2 + 4 + ticketLen - x = make([]byte, 4+length) - x[0] = typeNewSessionTicket - x[1] = uint8(length >> 16) - x[2] = uint8(length >> 8) - x[3] = uint8(length) - x[8] = uint8(ticketLen >> 8) - x[9] = uint8(ticketLen) - copy(x[10:], m.ticket) - - m.raw = x - - return -} - -func (m *newSessionTicketMsg) unmarshal(data []byte) bool { - m.raw = data - - if len(data) < 10 { - return false - } - - length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3]) - if uint32(len(data))-4 != length { - return false - } - - ticketLen := int(data[8])<<8 + int(data[9]) - if len(data)-10 != ticketLen { - return false - } - - m.ticket = data[10:] - - return true -} - -type helloRequestMsg struct{} - -func (*helloRequestMsg) marshal() []byte { - return []byte{typeHelloRequest, 0, 0, 0} -} - -func (*helloRequestMsg) unmarshal(data []byte) bool { - return len(data) == 4 -} diff --git a/transport/cloudflaretls/handshake_server.go b/transport/cloudflaretls/handshake_server.go deleted file mode 100644 index f8c317f8..00000000 --- a/transport/cloudflaretls/handshake_server.go +++ /dev/null @@ -1,893 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package tls - -import ( - "context" - "crypto" - "crypto/ecdsa" - "crypto/ed25519" - "crypto/rsa" - "crypto/subtle" - "crypto/x509" - "errors" - "fmt" - "hash" - "io" - "sync/atomic" - "time" - - circlSign "github.com/cloudflare/circl/sign" -) - -// serverHandshakeState contains details of a server handshake in progress. -// It's discarded once the handshake has completed. -type serverHandshakeState struct { - c *Conn - ctx context.Context - clientHello *clientHelloMsg - hello *serverHelloMsg - suite *cipherSuite - ecdheOk bool - ecSignOk bool - rsaDecryptOk bool - rsaSignOk bool - sessionState *sessionState - finishedHash finishedHash - masterSecret []byte - cert *Certificate -} - -// serverHandshake performs a TLS handshake as a server. -func (c *Conn) serverHandshake(ctx context.Context) error { - clientHello, err := c.readClientHello(ctx) - if err != nil { - return err - } - - if c.vers == VersionTLS13 { - hs := serverHandshakeStateTLS13{ - c: c, - ctx: ctx, - clientHello: clientHello, - hsTimings: createTLS13ServerHandshakeTimingInfo(c.config.Time), - } - return hs.handshake() - } - - hs := serverHandshakeState{ - c: c, - ctx: ctx, - clientHello: clientHello, - } - return hs.handshake() -} - -func (hs *serverHandshakeState) handshake() error { - c := hs.c - - if err := hs.processClientHello(); err != nil { - return err - } - - // For an overview of TLS handshaking, see RFC 5246, Section 7.3. - c.buffering = true - if hs.checkForResumption() { - // The client has included a session ticket and so we do an abbreviated handshake. - c.didResume = true - if err := hs.doResumeHandshake(); err != nil { - return err - } - if err := hs.establishKeys(); err != nil { - return err - } - if err := hs.sendSessionTicket(); err != nil { - return err - } - if err := hs.sendFinished(c.serverFinished[:]); err != nil { - return err - } - if _, err := c.flush(); err != nil { - return err - } - c.clientFinishedIsFirst = false - if err := hs.readFinished(nil); err != nil { - return err - } - } else { - // The client didn't include a session ticket, or it wasn't - // valid so we do a full handshake. - if err := hs.pickCipherSuite(); err != nil { - return err - } - if err := hs.doFullHandshake(); err != nil { - return err - } - if err := hs.establishKeys(); err != nil { - return err - } - if err := hs.readFinished(c.clientFinished[:]); err != nil { - return err - } - c.clientFinishedIsFirst = true - c.buffering = true - if err := hs.sendSessionTicket(); err != nil { - return err - } - if err := hs.sendFinished(nil); err != nil { - return err - } - if _, err := c.flush(); err != nil { - return err - } - } - - c.ekm = ekmFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.clientHello.random, hs.hello.random) - atomic.StoreUint32(&c.handshakeStatus, 1) - - return nil -} - -// readClientHello reads a ClientHello message and selects the protocol version. -func (c *Conn) readClientHello(ctx context.Context) (*clientHelloMsg, error) { - msg, err := c.readHandshake() - if err != nil { - return nil, err - } - clientHello, ok := msg.(*clientHelloMsg) - if !ok { - c.sendAlert(alertUnexpectedMessage) - return nil, unexpectedMessageError(clientHello, msg) - } - - // NOTE(cjpatton): ECH usage is resolved before calling GetConfigForClient() - // or GetCertifciate(). Hence, it is not currently possible to reject ECH if - // we don't recognize the inner SNI. This may or may not be desirable in the - // future. - clientHello, err = c.echAcceptOrReject(clientHello, false) // afterHRR == false - if err != nil { - return nil, fmt.Errorf("tls: %s", err) // Alert sent. - } - - var configForClient *Config - originalConfig := c.config - if c.config.GetConfigForClient != nil { - chi := clientHelloInfo(ctx, c, clientHello) - if configForClient, err = c.config.GetConfigForClient(chi); err != nil { - c.sendAlert(alertInternalError) - return nil, err - } else if configForClient != nil { - c.config = configForClient - } - } - c.ticketKeys = originalConfig.ticketKeys(configForClient) - - clientVersions := clientHello.supportedVersions - if len(clientHello.supportedVersions) == 0 { - clientVersions = supportedVersionsFromMax(clientHello.vers) - } - c.vers, ok = c.config.mutualVersion(roleServer, clientVersions) - if !ok { - c.sendAlert(alertProtocolVersion) - return nil, fmt.Errorf("tls: client offered only unsupported versions: %x", clientVersions) - } - c.haveVers = true - c.in.version = c.vers - c.out.version = c.vers - - return clientHello, nil -} - -func (hs *serverHandshakeState) processClientHello() error { - c := hs.c - - hs.hello = new(serverHelloMsg) - hs.hello.vers = c.vers - - foundCompression := false - // We only support null compression, so check that the client offered it. - for _, compression := range hs.clientHello.compressionMethods { - if compression == compressionNone { - foundCompression = true - break - } - } - - if !foundCompression { - c.sendAlert(alertHandshakeFailure) - return errors.New("tls: client does not support uncompressed connections") - } - - hs.hello.random = make([]byte, 32) - serverRandom := hs.hello.random - // Downgrade protection canaries. See RFC 8446, Section 4.1.3. - maxVers := c.config.maxSupportedVersion(roleServer) - if maxVers >= VersionTLS12 && c.vers < maxVers || testingOnlyForceDowngradeCanary { - if c.vers == VersionTLS12 { - copy(serverRandom[24:], downgradeCanaryTLS12) - } else { - copy(serverRandom[24:], downgradeCanaryTLS11) - } - serverRandom = serverRandom[:24] - } - _, err := io.ReadFull(c.config.rand(), serverRandom) - if err != nil { - c.sendAlert(alertInternalError) - return err - } - - if len(hs.clientHello.secureRenegotiation) != 0 { - c.sendAlert(alertHandshakeFailure) - return errors.New("tls: initial handshake had non-empty renegotiation extension") - } - - hs.hello.secureRenegotiationSupported = hs.clientHello.secureRenegotiationSupported - hs.hello.compressionMethod = compressionNone - if len(hs.clientHello.serverName) > 0 { - c.serverName = hs.clientHello.serverName - } - - selectedProto, err := negotiateALPN(c.config.NextProtos, hs.clientHello.alpnProtocols) - if err != nil { - c.sendAlert(alertNoApplicationProtocol) - return err - } - hs.hello.alpnProtocol = selectedProto - c.clientProtocol = selectedProto - - hs.cert, err = c.config.getCertificate(clientHelloInfo(hs.ctx, c, hs.clientHello)) - if err != nil { - if err == errNoCertificates { - c.sendAlert(alertUnrecognizedName) - } else { - c.sendAlert(alertInternalError) - } - return err - } - if hs.clientHello.scts { - hs.hello.scts = hs.cert.SignedCertificateTimestamps - } - - hs.ecdheOk = supportsECDHE(c.config, hs.clientHello.supportedCurves, hs.clientHello.supportedPoints) - - if hs.ecdheOk { - // Although omitting the ec_point_formats extension is permitted, some - // old OpenSSL version will refuse to handshake if not present. - // - // Per RFC 4492, section 5.1.2, implementations MUST support the - // uncompressed point format. See golang.org/issue/31943. - hs.hello.supportedPoints = []uint8{pointFormatUncompressed} - } - - if priv, ok := hs.cert.PrivateKey.(crypto.Signer); ok { - switch priv.Public().(type) { - case *ecdsa.PublicKey: - hs.ecSignOk = true - case ed25519.PublicKey: - hs.ecSignOk = true - case *rsa.PublicKey: - hs.rsaSignOk = true - default: - c.sendAlert(alertInternalError) - return fmt.Errorf("tls: unsupported signing key type (%T)", priv.Public()) - } - } - if priv, ok := hs.cert.PrivateKey.(crypto.Decrypter); ok { - switch priv.Public().(type) { - case *rsa.PublicKey: - hs.rsaDecryptOk = true - default: - c.sendAlert(alertInternalError) - return fmt.Errorf("tls: unsupported decryption key type (%T)", priv.Public()) - } - } - - return nil -} - -// negotiateALPN picks a shared ALPN protocol that both sides support in server -// preference order. If ALPN is not configured or the peer doesn't support it, -// it returns "" and no error. -func negotiateALPN(serverProtos, clientProtos []string) (string, error) { - if len(serverProtos) == 0 || len(clientProtos) == 0 { - return "", nil - } - var http11fallback bool - for _, s := range serverProtos { - for _, c := range clientProtos { - if s == c { - return s, nil - } - if s == "h2" && c == "http/1.1" { - http11fallback = true - } - } - } - // As a special case, let http/1.1 clients connect to h2 servers as if they - // didn't support ALPN. We used not to enforce protocol overlap, so over - // time a number of HTTP servers were configured with only "h2", but - // expected to accept connections from "http/1.1" clients. See Issue 46310. - if http11fallback { - return "", nil - } - return "", fmt.Errorf("tls: client requested unsupported application protocols (%s)", clientProtos) -} - -// supportsECDHE returns whether ECDHE key exchanges can be used with this -// pre-TLS 1.3 client. -func supportsECDHE(c *Config, supportedCurves []CurveID, supportedPoints []uint8) bool { - supportsCurve := false - for _, curve := range supportedCurves { - if c.supportsCurve(curve) { - supportsCurve = true - break - } - } - - supportsPointFormat := false - for _, pointFormat := range supportedPoints { - if pointFormat == pointFormatUncompressed { - supportsPointFormat = true - break - } - } - - return supportsCurve && supportsPointFormat -} - -func (hs *serverHandshakeState) pickCipherSuite() error { - c := hs.c - - preferenceOrder := cipherSuitesPreferenceOrder - if !hasAESGCMHardwareSupport || !aesgcmPreferred(hs.clientHello.cipherSuites) { - preferenceOrder = cipherSuitesPreferenceOrderNoAES - } - - configCipherSuites := c.config.cipherSuites() - preferenceList := make([]uint16, 0, len(configCipherSuites)) - for _, suiteID := range preferenceOrder { - for _, id := range configCipherSuites { - if id == suiteID { - preferenceList = append(preferenceList, id) - break - } - } - } - - hs.suite = selectCipherSuite(preferenceList, hs.clientHello.cipherSuites, hs.cipherSuiteOk) - if hs.suite == nil { - c.sendAlert(alertHandshakeFailure) - return errors.New("tls: no cipher suite supported by both client and server") - } - c.cipherSuite = hs.suite.id - - for _, id := range hs.clientHello.cipherSuites { - if id == TLS_FALLBACK_SCSV { - // The client is doing a fallback connection. See RFC 7507. - if hs.clientHello.vers < c.config.maxSupportedVersion(roleServer) { - c.sendAlert(alertInappropriateFallback) - return errors.New("tls: client using inappropriate protocol fallback") - } - break - } - } - - return nil -} - -func (hs *serverHandshakeState) cipherSuiteOk(c *cipherSuite) bool { - if c.flags&suiteECDHE != 0 { - if !hs.ecdheOk { - return false - } - if c.flags&suiteECSign != 0 { - if !hs.ecSignOk { - return false - } - } else if !hs.rsaSignOk { - return false - } - } else if !hs.rsaDecryptOk { - return false - } - if hs.c.vers < VersionTLS12 && c.flags&suiteTLS12 != 0 { - return false - } - return true -} - -// checkForResumption reports whether we should perform resumption on this connection. -func (hs *serverHandshakeState) checkForResumption() bool { - c := hs.c - - if c.config.SessionTicketsDisabled || c.config.ECHEnabled { - return false - } - - plaintext, usedOldKey := c.decryptTicket(hs.clientHello.sessionTicket) - if plaintext == nil { - return false - } - hs.sessionState = &sessionState{usedOldKey: usedOldKey} - ok := hs.sessionState.unmarshal(plaintext) - if !ok { - return false - } - - createdAt := time.Unix(int64(hs.sessionState.createdAt), 0) - if c.config.time().Sub(createdAt) > maxSessionTicketLifetime { - return false - } - - // Never resume a session for a different TLS version. - if c.vers != hs.sessionState.vers { - return false - } - - cipherSuiteOk := false - // Check that the client is still offering the ciphersuite in the session. - for _, id := range hs.clientHello.cipherSuites { - if id == hs.sessionState.cipherSuite { - cipherSuiteOk = true - break - } - } - if !cipherSuiteOk { - return false - } - - // Check that we also support the ciphersuite from the session. - hs.suite = selectCipherSuite([]uint16{hs.sessionState.cipherSuite}, - c.config.cipherSuites(), hs.cipherSuiteOk) - if hs.suite == nil { - return false - } - - sessionHasClientCerts := len(hs.sessionState.certificates) != 0 - needClientCerts := requiresClientCert(c.config.ClientAuth) - if needClientCerts && !sessionHasClientCerts { - return false - } - if sessionHasClientCerts && c.config.ClientAuth == NoClientCert { - return false - } - - return true -} - -func (hs *serverHandshakeState) doResumeHandshake() error { - c := hs.c - - hs.hello.cipherSuite = hs.suite.id - c.cipherSuite = hs.suite.id - // We echo the client's session ID in the ServerHello to let it know - // that we're doing a resumption. - hs.hello.sessionId = hs.clientHello.sessionId - hs.hello.ticketSupported = hs.sessionState.usedOldKey - hs.finishedHash = newFinishedHash(c.vers, hs.suite) - hs.finishedHash.discardHandshakeBuffer() - hs.finishedHash.Write(hs.clientHello.marshal()) - hs.finishedHash.Write(hs.hello.marshal()) - if _, err := c.writeRecord(recordTypeHandshake, hs.hello.marshal()); err != nil { - return err - } - - if err := c.processCertsFromClient(Certificate{ - Certificate: hs.sessionState.certificates, - }); err != nil { - return err - } - - if c.config.VerifyConnection != nil { - if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil { - c.sendAlert(alertBadCertificate) - return err - } - } - - hs.masterSecret = hs.sessionState.masterSecret - - return nil -} - -func (hs *serverHandshakeState) doFullHandshake() error { - c := hs.c - - if hs.clientHello.ocspStapling && len(hs.cert.OCSPStaple) > 0 { - hs.hello.ocspStapling = true - } - - hs.hello.ticketSupported = hs.clientHello.ticketSupported && !c.config.SessionTicketsDisabled && !c.config.ECHEnabled - hs.hello.cipherSuite = hs.suite.id - - hs.finishedHash = newFinishedHash(hs.c.vers, hs.suite) - if c.config.ClientAuth == NoClientCert { - // No need to keep a full record of the handshake if client - // certificates won't be used. - hs.finishedHash.discardHandshakeBuffer() - } - hs.finishedHash.Write(hs.clientHello.marshal()) - hs.finishedHash.Write(hs.hello.marshal()) - if _, err := c.writeRecord(recordTypeHandshake, hs.hello.marshal()); err != nil { - return err - } - - certMsg := new(certificateMsg) - certMsg.certificates = hs.cert.Certificate - hs.finishedHash.Write(certMsg.marshal()) - if _, err := c.writeRecord(recordTypeHandshake, certMsg.marshal()); err != nil { - return err - } - - if hs.hello.ocspStapling { - certStatus := new(certificateStatusMsg) - certStatus.response = hs.cert.OCSPStaple - hs.finishedHash.Write(certStatus.marshal()) - if _, err := c.writeRecord(recordTypeHandshake, certStatus.marshal()); err != nil { - return err - } - } - - keyAgreement := hs.suite.ka(c.vers) - skx, err := keyAgreement.generateServerKeyExchange(c.config, hs.cert, hs.clientHello, hs.hello) - if err != nil { - c.sendAlert(alertHandshakeFailure) - return err - } - if skx != nil { - hs.finishedHash.Write(skx.marshal()) - if _, err := c.writeRecord(recordTypeHandshake, skx.marshal()); err != nil { - return err - } - } - - var certReq *certificateRequestMsg - if c.config.ClientAuth >= RequestClientCert { - // Request a client certificate - certReq = new(certificateRequestMsg) - certReq.certificateTypes = []byte{ - byte(certTypeRSASign), - byte(certTypeECDSASign), - } - if c.vers >= VersionTLS12 { - certReq.hasSignatureAlgorithm = true - certReq.supportedSignatureAlgorithms = c.config.supportedSignatureAlgorithms() - } - - // An empty list of certificateAuthorities signals to - // the client that it may send any certificate in response - // to our request. When we know the CAs we trust, then - // we can send them down, so that the client can choose - // an appropriate certificate to give to us. - if c.config.ClientCAs != nil { - certReq.certificateAuthorities = c.config.ClientCAs.Subjects() - } - hs.finishedHash.Write(certReq.marshal()) - if _, err := c.writeRecord(recordTypeHandshake, certReq.marshal()); err != nil { - return err - } - } - - helloDone := new(serverHelloDoneMsg) - hs.finishedHash.Write(helloDone.marshal()) - if _, err := c.writeRecord(recordTypeHandshake, helloDone.marshal()); err != nil { - return err - } - - if _, err := c.flush(); err != nil { - return err - } - - var pub crypto.PublicKey // public key for client auth, if any - - msg, err := c.readHandshake() - if err != nil { - return err - } - - // If we requested a client certificate, then the client must send a - // certificate message, even if it's empty. - if c.config.ClientAuth >= RequestClientCert { - certMsg, ok := msg.(*certificateMsg) - if !ok { - c.sendAlert(alertUnexpectedMessage) - return unexpectedMessageError(certMsg, msg) - } - hs.finishedHash.Write(certMsg.marshal()) - - if err := c.processCertsFromClient(Certificate{ - Certificate: certMsg.certificates, - }); err != nil { - return err - } - if len(certMsg.certificates) != 0 { - pub = c.peerCertificates[0].PublicKey - } - - msg, err = c.readHandshake() - if err != nil { - return err - } - } - if c.config.VerifyConnection != nil { - if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil { - c.sendAlert(alertBadCertificate) - return err - } - } - - // Get client key exchange - ckx, ok := msg.(*clientKeyExchangeMsg) - if !ok { - c.sendAlert(alertUnexpectedMessage) - return unexpectedMessageError(ckx, msg) - } - hs.finishedHash.Write(ckx.marshal()) - - preMasterSecret, err := keyAgreement.processClientKeyExchange(c.config, hs.cert, ckx, c.vers) - if err != nil { - c.sendAlert(alertHandshakeFailure) - return err - } - if eccKex, ok := keyAgreement.(*ecdheKeyAgreement); ok { - c.handleCFEvent(CFEventTLSNegotiatedNamedKEX{ - KEX: eccKex.params.CurveID(), - }) - } - hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.clientHello.random, hs.hello.random) - if err := c.config.writeKeyLog(keyLogLabelTLS12, hs.clientHello.random, hs.masterSecret); err != nil { - c.sendAlert(alertInternalError) - return err - } - - // If we received a client cert in response to our certificate request message, - // the client will send us a certificateVerifyMsg immediately after the - // clientKeyExchangeMsg. This message is a digest of all preceding - // handshake-layer messages that is signed using the private key corresponding - // to the client's certificate. This allows us to verify that the client is in - // possession of the private key of the certificate. - if len(c.peerCertificates) > 0 { - msg, err = c.readHandshake() - if err != nil { - return err - } - certVerify, ok := msg.(*certificateVerifyMsg) - if !ok { - c.sendAlert(alertUnexpectedMessage) - return unexpectedMessageError(certVerify, msg) - } - - var sigType uint8 - var sigHash crypto.Hash - if c.vers >= VersionTLS12 { - if !isSupportedSignatureAlgorithm(certVerify.signatureAlgorithm, certReq.supportedSignatureAlgorithms) { - c.sendAlert(alertIllegalParameter) - return errors.New("tls: client certificate used with invalid signature algorithm") - } - sigType, sigHash, err = typeAndHashFromSignatureScheme(certVerify.signatureAlgorithm) - if err != nil { - return c.sendAlert(alertInternalError) - } - } else { - sigType, sigHash, err = legacyTypeAndHashFromPublicKey(pub) - if err != nil { - c.sendAlert(alertIllegalParameter) - return err - } - } - - signed := hs.finishedHash.hashForClientCertificate(sigType, sigHash, hs.masterSecret) - if err := verifyHandshakeSignature(sigType, pub, sigHash, signed, certVerify.signature); err != nil { - c.sendAlert(alertDecryptError) - return errors.New("tls: invalid signature by the client certificate: " + err.Error()) - } - - hs.finishedHash.Write(certVerify.marshal()) - } - - hs.finishedHash.discardHandshakeBuffer() - - return nil -} - -func (hs *serverHandshakeState) establishKeys() error { - c := hs.c - - clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV := keysFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.clientHello.random, hs.hello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen) - - var clientCipher, serverCipher any - var clientHash, serverHash hash.Hash - - if hs.suite.aead == nil { - clientCipher = hs.suite.cipher(clientKey, clientIV, true /* for reading */) - clientHash = hs.suite.mac(clientMAC) - serverCipher = hs.suite.cipher(serverKey, serverIV, false /* not for reading */) - serverHash = hs.suite.mac(serverMAC) - } else { - clientCipher = hs.suite.aead(clientKey, clientIV) - serverCipher = hs.suite.aead(serverKey, serverIV) - } - - c.in.prepareCipherSpec(c.vers, clientCipher, clientHash) - c.out.prepareCipherSpec(c.vers, serverCipher, serverHash) - - return nil -} - -func (hs *serverHandshakeState) readFinished(out []byte) error { - c := hs.c - - if err := c.readChangeCipherSpec(); err != nil { - return err - } - - msg, err := c.readHandshake() - if err != nil { - return err - } - clientFinished, ok := msg.(*finishedMsg) - if !ok { - c.sendAlert(alertUnexpectedMessage) - return unexpectedMessageError(clientFinished, msg) - } - - verify := hs.finishedHash.clientSum(hs.masterSecret) - if len(verify) != len(clientFinished.verifyData) || - subtle.ConstantTimeCompare(verify, clientFinished.verifyData) != 1 { - c.sendAlert(alertHandshakeFailure) - return errors.New("tls: client's Finished message is incorrect") - } - - hs.finishedHash.Write(clientFinished.marshal()) - copy(out, verify) - return nil -} - -func (hs *serverHandshakeState) sendSessionTicket() error { - // ticketSupported is set in a resumption handshake if the - // ticket from the client was encrypted with an old session - // ticket key and thus a refreshed ticket should be sent. - if !hs.hello.ticketSupported { - return nil - } - - c := hs.c - m := new(newSessionTicketMsg) - - createdAt := uint64(c.config.time().Unix()) - if hs.sessionState != nil { - // If this is re-wrapping an old key, then keep - // the original time it was created. - createdAt = hs.sessionState.createdAt - } - - var certsFromClient [][]byte - for _, cert := range c.peerCertificates { - certsFromClient = append(certsFromClient, cert.Raw) - } - state := sessionState{ - vers: c.vers, - cipherSuite: hs.suite.id, - createdAt: createdAt, - masterSecret: hs.masterSecret, - certificates: certsFromClient, - } - var err error - m.ticket, err = c.encryptTicket(state.marshal()) - if err != nil { - return err - } - - hs.finishedHash.Write(m.marshal()) - if _, err := c.writeRecord(recordTypeHandshake, m.marshal()); err != nil { - return err - } - - return nil -} - -func (hs *serverHandshakeState) sendFinished(out []byte) error { - c := hs.c - - if _, err := c.writeRecord(recordTypeChangeCipherSpec, []byte{1}); err != nil { - return err - } - - finished := new(finishedMsg) - finished.verifyData = hs.finishedHash.serverSum(hs.masterSecret) - hs.finishedHash.Write(finished.marshal()) - if _, err := c.writeRecord(recordTypeHandshake, finished.marshal()); err != nil { - return err - } - - copy(out, finished.verifyData) - - return nil -} - -// processCertsFromClient takes a chain of client certificates either from a -// Certificates message or from a sessionState and verifies them. It returns -// the public key of the leaf certificate. -func (c *Conn) processCertsFromClient(certificate Certificate) error { - certificates := certificate.Certificate - certs := make([]*x509.Certificate, len(certificates)) - var err error - for i, asn1Data := range certificates { - if certs[i], err = x509.ParseCertificate(asn1Data); err != nil { - c.sendAlert(alertBadCertificate) - return errors.New("tls: failed to parse client certificate: " + err.Error()) - } - } - - if len(certs) == 0 && requiresClientCert(c.config.ClientAuth) { - c.sendAlert(alertBadCertificate) - return errors.New("tls: client didn't provide a certificate") - } - - if c.config.ClientAuth >= VerifyClientCertIfGiven && len(certs) > 0 { - opts := x509.VerifyOptions{ - Roots: c.config.ClientCAs, - CurrentTime: c.config.time(), - Intermediates: x509.NewCertPool(), - KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}, - } - - for _, cert := range certs[1:] { - opts.Intermediates.AddCert(cert) - } - - chains, err := certs[0].Verify(opts) - if err != nil { - c.sendAlert(alertBadCertificate) - return errors.New("tls: failed to verify client certificate: " + err.Error()) - } - - c.verifiedChains = chains - } - - c.peerCertificates = certs - c.ocspResponse = certificate.OCSPStaple - c.scts = certificate.SignedCertificateTimestamps - - if len(certs) > 0 { - switch certs[0].PublicKey.(type) { - case *ecdsa.PublicKey, *rsa.PublicKey, ed25519.PublicKey, circlSign.PublicKey: - default: - c.sendAlert(alertUnsupportedCertificate) - return fmt.Errorf("tls: client certificate contains an unsupported public key of type %T", certs[0].PublicKey) - } - } - - if c.config.VerifyPeerCertificate != nil { - if err := c.config.VerifyPeerCertificate(certificates, c.verifiedChains); err != nil { - c.sendAlert(alertBadCertificate) - return err - } - } - - return nil -} - -func clientHelloInfo(ctx context.Context, c *Conn, clientHello *clientHelloMsg) *ClientHelloInfo { - supportedVersions := clientHello.supportedVersions - if len(clientHello.supportedVersions) == 0 { - supportedVersions = supportedVersionsFromMax(clientHello.vers) - } - - return &ClientHelloInfo{ - CipherSuites: clientHello.cipherSuites, - ServerName: clientHello.serverName, - SupportedCurves: clientHello.supportedCurves, - SupportedPoints: clientHello.supportedPoints, - SignatureSchemes: clientHello.supportedSignatureAlgorithms, - SupportedProtos: clientHello.alpnProtocols, - SupportedVersions: supportedVersions, - SupportsDelegatedCredential: clientHello.delegatedCredentialSupported, - SignatureSchemesDC: clientHello.supportedSignatureAlgorithmsDC, - Conn: c.conn, - config: c.config, - ctx: ctx, - } -} diff --git a/transport/cloudflaretls/handshake_server_tls13.go b/transport/cloudflaretls/handshake_server_tls13.go deleted file mode 100644 index 904aa61c..00000000 --- a/transport/cloudflaretls/handshake_server_tls13.go +++ /dev/null @@ -1,1121 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package tls - -import ( - "bytes" - "context" - "crypto" - "crypto/hmac" - "crypto/rsa" - "encoding/binary" - "errors" - "fmt" - "hash" - "io" - "sync/atomic" - "time" -) - -// maxClientPSKIdentities is the number of client PSK identities the server will -// attempt to validate. It will ignore the rest not to let cheap ClientHello -// messages cause too much work in session ticket decryption attempts. -const maxClientPSKIdentities = 5 - -type serverHandshakeStateTLS13 struct { - c *Conn - ctx context.Context - clientHello *clientHelloMsg - hello *serverHelloMsg - sentDummyCCS bool - usingPSK bool - suite *cipherSuiteTLS13 - cert *Certificate - sigAlg SignatureScheme - selectedGroup CurveID - earlySecret []byte - sharedKey []byte - handshakeSecret []byte - masterSecret []byte - trafficSecret []byte // client_application_traffic_secret_0 - transcript hash.Hash - clientFinished []byte - certReq *certificateRequestMsgTLS13 - - hsTimings CFEventTLS13ServerHandshakeTimingInfo -} - -func (hs *serverHandshakeStateTLS13) echIsInner() bool { - return len(hs.clientHello.ech) == 1 && hs.clientHello.ech[0] == echClientHelloInnerVariant -} - -// processDelegatedCredentialFromClient unmarshals the DelegatedCredential -// offered by the client (if present) and validates it using the peer's -// certificate. -func (hs *serverHandshakeStateTLS13) processDelegatedCredentialFromClient(rawDC []byte, certVerifyMsg *certificateVerifyMsg) error { - c := hs.c - - var dc *DelegatedCredential - var err error - if rawDC != nil { - // Assert that the DC extension was indicated by the client. - if !hs.certReq.supportDelegatedCredential { - c.sendAlert(alertUnexpectedMessage) - return errors.New("tls: got Delegated Credential extension without indication") - } - - dc, err = UnmarshalDelegatedCredential(rawDC) - if err != nil { - c.sendAlert(alertDecodeError) - return fmt.Errorf("tls: Delegated Credential: %s", err) - } - - if !isSupportedSignatureAlgorithm(dc.cred.expCertVerfAlgo, supportedSignatureAlgorithmsDC) { - c.sendAlert(alertIllegalParameter) - return errors.New("tls: Delegated Credential used with invalid signature algorithm") - } - } - - if dc != nil { - if !dc.Validate(c.peerCertificates[0], true, c.config.time(), certVerifyMsg) { - c.sendAlert(alertIllegalParameter) - return errors.New("tls: invalid Delegated Credential") - } - } - - c.verifiedDC = dc - - return nil -} - -func (hs *serverHandshakeStateTLS13) handshake() error { - c := hs.c - - // For an overview of the TLS 1.3 handshake, see RFC 8446, Section 2. - if err := hs.processClientHello(); err != nil { - return err - } - if err := hs.checkForResumption(); err != nil { - return err - } - if err := hs.pickCertificate(); err != nil { - return err - } - c.buffering = true - if err := hs.sendServerParameters(); err != nil { - return err - } - if err := hs.sendServerCertificate(); err != nil { - return err - } - if err := hs.sendServerFinished(); err != nil { - return err - } - // Note that at this point we could start sending application data without - // waiting for the client's second flight, but the application might not - // expect the lack of replay protection of the ClientHello parameters. - if _, err := c.flush(); err != nil { - return err - } - if err := hs.readClientCertificate(); err != nil { - return err - } - if err := hs.readClientFinished(); err != nil { - return err - } - - c.handleCFEvent(hs.hsTimings) - atomic.StoreUint32(&c.handshakeStatus, 1) - - return nil -} - -func (hs *serverHandshakeStateTLS13) processClientHello() error { - c := hs.c - - hs.hello = new(serverHelloMsg) - - // TLS 1.3 froze the ServerHello.legacy_version field, and uses - // supported_versions instead. See RFC 8446, sections 4.1.3 and 4.2.1. - hs.hello.vers = VersionTLS12 - hs.hello.supportedVersion = c.vers - - if len(hs.clientHello.supportedVersions) == 0 { - c.sendAlert(alertIllegalParameter) - return errors.New("tls: client used the legacy version field to negotiate TLS 1.3") - } - - // Abort if the client is doing a fallback and landing lower than what we - // support. See RFC 7507, which however does not specify the interaction - // with supported_versions. The only difference is that with - // supported_versions a client has a chance to attempt a [TLS 1.2, TLS 1.4] - // handshake in case TLS 1.3 is broken but 1.2 is not. Alas, in that case, - // it will have to drop the TLS_FALLBACK_SCSV protection if it falls back to - // TLS 1.2, because a TLS 1.3 server would abort here. The situation before - // supported_versions was not better because there was just no way to do a - // TLS 1.4 handshake without risking the server selecting TLS 1.3. - for _, id := range hs.clientHello.cipherSuites { - if id == TLS_FALLBACK_SCSV { - // Use c.vers instead of max(supported_versions) because an attacker - // could defeat this by adding an arbitrary high version otherwise. - if c.vers < c.config.maxSupportedVersion(roleServer) { - c.sendAlert(alertInappropriateFallback) - return errors.New("tls: client using inappropriate protocol fallback") - } - break - } - } - - if len(hs.clientHello.compressionMethods) != 1 || - hs.clientHello.compressionMethods[0] != compressionNone { - c.sendAlert(alertIllegalParameter) - return errors.New("tls: TLS 1.3 client supports illegal compression methods") - } - - hs.hello.random = make([]byte, 32) - if _, err := io.ReadFull(c.config.rand(), hs.hello.random); err != nil { - c.sendAlert(alertInternalError) - return err - } - - if len(hs.clientHello.secureRenegotiation) != 0 { - c.sendAlert(alertHandshakeFailure) - return errors.New("tls: initial handshake had non-empty renegotiation extension") - } - - if hs.clientHello.earlyData { - // See RFC 8446, Section 4.2.10 for the complicated behavior required - // here. The scenario is that a different server at our address offered - // to accept early data in the past, which we can't handle. For now, all - // 0-RTT enabled session tickets need to expire before a Go server can - // replace a server or join a pool. That's the same requirement that - // applies to mixing or replacing with any TLS 1.2 server. - c.sendAlert(alertUnsupportedExtension) - return errors.New("tls: client sent unexpected early data") - } - - hs.hello.sessionId = hs.clientHello.sessionId - hs.hello.compressionMethod = compressionNone - - preferenceList := defaultCipherSuitesTLS13 - if !hasAESGCMHardwareSupport || !aesgcmPreferred(hs.clientHello.cipherSuites) { - preferenceList = defaultCipherSuitesTLS13NoAES - } - for _, suiteID := range preferenceList { - hs.suite = mutualCipherSuiteTLS13(hs.clientHello.cipherSuites, suiteID) - if hs.suite != nil { - break - } - } - if hs.suite == nil { - c.sendAlert(alertHandshakeFailure) - return errors.New("tls: no cipher suite supported by both client and server") - } - c.cipherSuite = hs.suite.id - hs.hello.cipherSuite = hs.suite.id - hs.transcript = hs.suite.hash.New() - - // Resolve the server's preference for the ECDHE group. - supportedCurves := c.config.curvePreferences() - if testingTriggerHRR { - // A HelloRetryRequest (HRR) is sent if the client does not offer a key - // share for a curve supported by the server. To trigger this condition - // intentionally, we compute the set of ECDHE groups supported by both - // the client and server but for which the client did not offer a key - // share. - m := make(map[CurveID]bool) - for _, serverGroup := range c.config.curvePreferences() { - for _, clientGroup := range hs.clientHello.supportedCurves { - if clientGroup == serverGroup { - m[clientGroup] = true - } - } - } - for _, ks := range hs.clientHello.keyShares { - delete(m, ks.group) - } - supportedCurves = nil - for group := range m { - supportedCurves = append(supportedCurves, group) - } - if len(supportedCurves) == 0 { - // This occurs if the client offered a key share for each mutually - // supported group. - panic("failed to trigger HelloRetryRequest") - } - } - - // Pick the ECDHE group in server preference order, but give priority to - // groups with a key share, to avoid a HelloRetryRequest round-trip. - var selectedGroup CurveID - var clientKeyShare *keyShare -GroupSelection: - for _, preferredGroup := range supportedCurves { - for _, ks := range hs.clientHello.keyShares { - if ks.group == preferredGroup { - selectedGroup = ks.group - clientKeyShare = &ks - break GroupSelection - } - } - if selectedGroup != 0 { - continue - } - for _, group := range hs.clientHello.supportedCurves { - if group == preferredGroup { - selectedGroup = group - break - } - } - } - if selectedGroup == 0 { - c.sendAlert(alertHandshakeFailure) - return errors.New("tls: no ECDHE curve supported by both client and server") - } - if clientKeyShare == nil { - if err := hs.doHelloRetryRequest(selectedGroup); err != nil { - return err - } - clientKeyShare = &hs.clientHello.keyShares[0] - } - - if _, ok := curveForCurveID(selectedGroup); selectedGroup != X25519 && curveIdToCirclScheme(selectedGroup) == nil && !ok { - c.sendAlert(alertInternalError) - return errors.New("tls: CurvePreferences includes unsupported curve") - } - if kem := curveIdToCirclScheme(selectedGroup); kem != nil { - ct, ss, alert, err := encapsulateForKem(kem, c.config.rand(), clientKeyShare.data) - if err != nil { - c.sendAlert(alert) - return fmt.Errorf("%s encap: %w", kem.Name(), err) - } - hs.hello.serverShare = keyShare{group: selectedGroup, data: ct} - hs.sharedKey = ss - } else { - params, err := generateECDHEParameters(c.config.rand(), selectedGroup) - if err != nil { - c.sendAlert(alertInternalError) - return err - } - hs.hello.serverShare = keyShare{group: selectedGroup, data: params.PublicKey()} - hs.sharedKey = params.SharedKey(clientKeyShare.data) - } - if hs.sharedKey == nil { - c.sendAlert(alertIllegalParameter) - return errors.New("tls: invalid client key share") - } - - c.serverName = hs.clientHello.serverName - c.handleCFEvent(CFEventTLSNegotiatedNamedKEX{ - KEX: selectedGroup, - }) - - hs.hsTimings.ProcessClientHello = hs.hsTimings.elapsedTime() - - return nil -} - -func (hs *serverHandshakeStateTLS13) checkForResumption() error { - c := hs.c - - if c.config.SessionTicketsDisabled || c.config.ECHEnabled { - return nil - } - - modeOK := false - for _, mode := range hs.clientHello.pskModes { - if mode == pskModeDHE { - modeOK = true - break - } - } - if !modeOK { - return nil - } - - if len(hs.clientHello.pskIdentities) != len(hs.clientHello.pskBinders) { - c.sendAlert(alertIllegalParameter) - return errors.New("tls: invalid or missing PSK binders") - } - if len(hs.clientHello.pskIdentities) == 0 { - return nil - } - - for i, identity := range hs.clientHello.pskIdentities { - if i >= maxClientPSKIdentities { - break - } - - plaintext, _ := c.decryptTicket(identity.label) - if plaintext == nil { - continue - } - sessionState := new(sessionStateTLS13) - if ok := sessionState.unmarshal(plaintext); !ok { - continue - } - - createdAt := time.Unix(int64(sessionState.createdAt), 0) - if c.config.time().Sub(createdAt) > maxSessionTicketLifetime { - continue - } - - // We don't check the obfuscated ticket age because it's affected by - // clock skew and it's only a freshness signal useful for shrinking the - // window for replay attacks, which don't affect us as we don't do 0-RTT. - - pskSuite := cipherSuiteTLS13ByID(sessionState.cipherSuite) - if pskSuite == nil || pskSuite.hash != hs.suite.hash { - continue - } - - // PSK connections don't re-establish client certificates, but carry - // them over in the session ticket. Ensure the presence of client certs - // in the ticket is consistent with the configured requirements. - sessionHasClientCerts := len(sessionState.certificate.Certificate) != 0 - needClientCerts := requiresClientCert(c.config.ClientAuth) - if needClientCerts && !sessionHasClientCerts { - continue - } - if sessionHasClientCerts && c.config.ClientAuth == NoClientCert { - continue - } - - psk := hs.suite.expandLabel(sessionState.resumptionSecret, "resumption", - nil, hs.suite.hash.Size()) - hs.earlySecret = hs.suite.extract(psk, nil) - binderKey := hs.suite.deriveSecret(hs.earlySecret, resumptionBinderLabel, nil) - // Clone the transcript in case a HelloRetryRequest was recorded. - transcript := cloneHash(hs.transcript, hs.suite.hash) - if transcript == nil { - c.sendAlert(alertInternalError) - return errors.New("tls: internal error: failed to clone hash") - } - transcript.Write(hs.clientHello.marshalWithoutBinders()) - pskBinder := hs.suite.finishedHash(binderKey, transcript) - if !hmac.Equal(hs.clientHello.pskBinders[i], pskBinder) { - c.sendAlert(alertDecryptError) - return errors.New("tls: invalid PSK binder") - } - - c.didResume = true - if err := c.processCertsFromClient(sessionState.certificate); err != nil { - return err - } - - hs.hello.selectedIdentityPresent = true - hs.hello.selectedIdentity = uint16(i) - hs.usingPSK = true - return nil - } - - return nil -} - -// cloneHash uses the encoding.BinaryMarshaler and encoding.BinaryUnmarshaler -// interfaces implemented by standard library hashes to clone the state of in -// to a new instance of h. It returns nil if the operation fails. -func cloneHash(in hash.Hash, h crypto.Hash) hash.Hash { - // Recreate the interface to avoid importing encoding. - type binaryMarshaler interface { - MarshalBinary() (data []byte, err error) - UnmarshalBinary(data []byte) error - } - marshaler, ok := in.(binaryMarshaler) - if !ok { - return nil - } - state, err := marshaler.MarshalBinary() - if err != nil { - return nil - } - out := h.New() - unmarshaler, ok := out.(binaryMarshaler) - if !ok { - return nil - } - if err := unmarshaler.UnmarshalBinary(state); err != nil { - return nil - } - return out -} - -// getDelegatedCredential will return a Delegated Credential pair (a Delegated -// Credential and its private key) for the given ClientHelloInfo, defaulting to -// the first element of cert.DelegatedCredentialPair. -// The returned Delegated Credential could be invalid for usage in the handshake. -// Returns an error if there are no delegated credentials or if the one found -// cannot be used for the current connection. -func getDelegatedCredential(clientHello *ClientHelloInfo, cert *Certificate) (*DelegatedCredentialPair, error) { - if len(cert.DelegatedCredentials) == 0 { - return nil, errors.New("no Delegated Credential found") - } - - for _, dcPair := range cert.DelegatedCredentials { - // The client must have sent the signature_algorithms in the DC extension: ensure it supports - // schemes we can use with this delegated credential. - if len(clientHello.SignatureSchemesDC) > 0 { - if _, err := selectSignatureSchemeDC(VersionTLS13, dcPair.DC, clientHello.SignatureSchemes, clientHello.SignatureSchemesDC); err == nil { - return &dcPair, nil - } - } - } - - // No delegated credential can be returned. - return nil, errors.New("no valid Delegated Credential found") -} - -func (hs *serverHandshakeStateTLS13) pickCertificate() error { - c := hs.c - - // Only one of PSK and certificates are used at a time. - if hs.usingPSK { - return nil - } - - // signature_algorithms is required in TLS 1.3. See RFC 8446, Section 4.2.3. - if len(hs.clientHello.supportedSignatureAlgorithms) == 0 { - return c.sendAlert(alertMissingExtension) - } - - certificate, err := c.config.getCertificate(clientHelloInfo(hs.ctx, c, hs.clientHello)) - if err != nil { - if err == errNoCertificates { - c.sendAlert(alertUnrecognizedName) - } else { - c.sendAlert(alertInternalError) - } - return err - } - - hs.sigAlg, err = selectSignatureScheme(c.vers, certificate, hs.clientHello.supportedSignatureAlgorithms) - if err != nil { - // getCertificate returned a certificate that is unsupported or - // incompatible with the client's signature algorithms. - c.sendAlert(alertHandshakeFailure) - return err - } - - hs.cert = certificate - - if hs.clientHello.delegatedCredentialSupported && len(hs.clientHello.supportedSignatureAlgorithmsDC) > 0 { - // getDelegatedCredential selects a delegated credential that the client has advertised support for, if possible. - delegatedCredentialPair, err := getDelegatedCredential(clientHelloInfo(hs.ctx, c, hs.clientHello), hs.cert) - if err != nil { - // a Delegated Credential was not found. Fallback to the certificate. - return nil - } - if delegatedCredentialPair.DC != nil && delegatedCredentialPair.PrivateKey != nil { - // Even if the Delegated Credential has already been marshalled, be sure it is the correct one. - delegatedCredentialPair.DC.raw, err = delegatedCredentialPair.DC.Marshal() - if err != nil { - // invalid Delegated Credential. Fallback to the certificate. - return nil - } - hs.sigAlg = delegatedCredentialPair.DC.cred.expCertVerfAlgo - - hs.cert.PrivateKey = delegatedCredentialPair.PrivateKey - hs.cert.DelegatedCredential = delegatedCredentialPair.DC.raw - } - } - return nil -} - -// sendDummyChangeCipherSpec sends a ChangeCipherSpec record for compatibility -// with middleboxes that didn't implement TLS correctly. See RFC 8446, Appendix D.4. -func (hs *serverHandshakeStateTLS13) sendDummyChangeCipherSpec() error { - if hs.sentDummyCCS { - return nil - } - hs.sentDummyCCS = true - - _, err := hs.c.writeRecord(recordTypeChangeCipherSpec, []byte{1}) - return err -} - -func (hs *serverHandshakeStateTLS13) doHelloRetryRequest(selectedGroup CurveID) error { - c := hs.c - - c.handleCFEvent(CFEventTLS13HRR{}) - - // The first ClientHello gets double-hashed into the transcript upon a - // HelloRetryRequest. See RFC 8446, Section 4.4.1. - hs.transcript.Write(hs.clientHello.marshal()) - chHash := hs.transcript.Sum(nil) - hs.transcript.Reset() - hs.transcript.Write([]byte{typeMessageHash, 0, 0, uint8(len(chHash))}) - hs.transcript.Write(chHash) - - helloRetryRequest := &serverHelloMsg{ - vers: hs.hello.vers, - random: helloRetryRequestRandom, - sessionId: hs.hello.sessionId, - cipherSuite: hs.hello.cipherSuite, - compressionMethod: hs.hello.compressionMethod, - supportedVersion: hs.hello.supportedVersion, - selectedGroup: selectedGroup, - } - - // Decide whether to send "encrypted_client_hello" extension. - if hs.echIsInner() { - // Confirm ECH acceptance if this is the inner handshake. - echAcceptConfHRRTranscript := cloneHash(hs.transcript, hs.suite.hash) - if echAcceptConfHRRTranscript == nil { - c.sendAlert(alertInternalError) - return errors.New("tls: internal error: failed to clone hash") - } - - helloRetryRequest.ech = zeros[:8] - echAcceptConfHRR := helloRetryRequest.marshal() - echAcceptConfHRRTranscript.Write(echAcceptConfHRR) - echAcceptConfHRRSignal := hs.suite.expandLabel( - hs.suite.extract(hs.clientHello.random, nil), - echAcceptConfHRRLabel, - echAcceptConfHRRTranscript.Sum(nil), - 8) - - helloRetryRequest.ech = echAcceptConfHRRSignal - helloRetryRequest.raw = nil - } else if c.ech.greased { - // draft-ietf-tls-esni-13, Section 7.1: - // - // If sending a HelloRetryRequest, the server MAY include an - // "encrypted_client_hello" extension with a payload of 8 random bytes; - // see Section 10.9.4 for details. - helloRetryRequest.ech = make([]byte, 8) - if _, err := io.ReadFull(c.config.rand(), helloRetryRequest.ech); err != nil { - c.sendAlert(alertInternalError) - return fmt.Errorf("tls: internal error: rng failure: %s", err) - } - } - - hs.transcript.Write(helloRetryRequest.marshal()) - if _, err := c.writeRecord(recordTypeHandshake, helloRetryRequest.marshal()); err != nil { - return err - } - - if err := hs.sendDummyChangeCipherSpec(); err != nil { - return err - } - - msg, err := c.readHandshake() - if err != nil { - return err - } - - clientHello, ok := msg.(*clientHelloMsg) - if !ok { - c.sendAlert(alertUnexpectedMessage) - return unexpectedMessageError(clientHello, msg) - } - - clientHello, err = c.echAcceptOrReject(clientHello, true) // afterHRR == true - if err != nil { - return fmt.Errorf("tls: %s", err) // Alert sent - } - - if len(clientHello.keyShares) != 1 || clientHello.keyShares[0].group != selectedGroup { - c.sendAlert(alertIllegalParameter) - return errors.New("tls: client sent invalid key share in second ClientHello") - } - - if clientHello.earlyData { - c.sendAlert(alertIllegalParameter) - return errors.New("tls: client indicated early data in second ClientHello") - } - - if illegalClientHelloChange(clientHello, hs.clientHello) { - c.sendAlert(alertIllegalParameter) - return errors.New("tls: client illegally modified second ClientHello") - } - - hs.clientHello = clientHello - return nil -} - -// illegalClientHelloChange reports whether the two ClientHello messages are -// different, with the exception of the changes allowed before and after a -// HelloRetryRequest. See RFC 8446, Section 4.1.2. -func illegalClientHelloChange(ch, ch1 *clientHelloMsg) bool { - if len(ch.supportedVersions) != len(ch1.supportedVersions) || - len(ch.cipherSuites) != len(ch1.cipherSuites) || - len(ch.supportedCurves) != len(ch1.supportedCurves) || - len(ch.supportedSignatureAlgorithms) != len(ch1.supportedSignatureAlgorithms) || - len(ch.supportedSignatureAlgorithmsCert) != len(ch1.supportedSignatureAlgorithmsCert) || - len(ch.supportedSignatureAlgorithmsDC) != len(ch1.supportedSignatureAlgorithmsDC) || - len(ch.alpnProtocols) != len(ch1.alpnProtocols) { - return true - } - for i := range ch.supportedVersions { - if ch.supportedVersions[i] != ch1.supportedVersions[i] { - return true - } - } - for i := range ch.cipherSuites { - if ch.cipherSuites[i] != ch1.cipherSuites[i] { - return true - } - } - for i := range ch.supportedCurves { - if ch.supportedCurves[i] != ch1.supportedCurves[i] { - return true - } - } - for i := range ch.supportedSignatureAlgorithms { - if ch.supportedSignatureAlgorithms[i] != ch1.supportedSignatureAlgorithms[i] { - return true - } - } - for i := range ch.supportedSignatureAlgorithmsCert { - if ch.supportedSignatureAlgorithmsCert[i] != ch1.supportedSignatureAlgorithmsCert[i] { - return true - } - } - for i := range ch.supportedSignatureAlgorithmsDC { - if ch.supportedSignatureAlgorithmsDC[i] != ch1.supportedSignatureAlgorithmsDC[i] { - return true - } - } - for i := range ch.alpnProtocols { - if ch.alpnProtocols[i] != ch1.alpnProtocols[i] { - return true - } - } - return ch.vers != ch1.vers || - !bytes.Equal(ch.random, ch1.random) || - !bytes.Equal(ch.sessionId, ch1.sessionId) || - !bytes.Equal(ch.compressionMethods, ch1.compressionMethods) || - ch.serverName != ch1.serverName || - ch.ocspStapling != ch1.ocspStapling || - !bytes.Equal(ch.supportedPoints, ch1.supportedPoints) || - ch.ticketSupported != ch1.ticketSupported || - !bytes.Equal(ch.sessionTicket, ch1.sessionTicket) || - ch.secureRenegotiationSupported != ch1.secureRenegotiationSupported || - !bytes.Equal(ch.secureRenegotiation, ch1.secureRenegotiation) || - ch.delegatedCredentialSupported != ch1.delegatedCredentialSupported || - ch.scts != ch1.scts || - !bytes.Equal(ch.cookie, ch1.cookie) || - !bytes.Equal(ch.pskModes, ch1.pskModes) -} - -func (hs *serverHandshakeStateTLS13) sendServerParameters() error { - c := hs.c - - // Confirm ECH acceptance. - if hs.echIsInner() { - // Clear the last 8 bytes of the ServerHello.random in preparation for - // computing the confirmation hint. - copy(hs.hello.random[24:], zeros[:8]) - - // Set the last 8 bytes of ServerHello.random to a string derived from - // the inner handshake. - echAcceptConfTranscript := cloneHash(hs.transcript, hs.suite.hash) - if echAcceptConfTranscript == nil { - c.sendAlert(alertInternalError) - return errors.New("tls: internal error: failed to clone hash") - } - echAcceptConfTranscript.Write(hs.clientHello.marshal()) - echAcceptConfTranscript.Write(hs.hello.marshal()) - - echAcceptConf := hs.suite.expandLabel( - hs.suite.extract(hs.clientHello.random, nil), - echAcceptConfLabel, - echAcceptConfTranscript.Sum(nil), - 8) - - copy(hs.hello.random[24:], echAcceptConf) - hs.hello.raw = nil - } - - hs.transcript.Write(hs.clientHello.marshal()) - hs.transcript.Write(hs.hello.marshal()) - if _, err := c.writeRecord(recordTypeHandshake, hs.hello.marshal()); err != nil { - return err - } - - hs.hsTimings.WriteServerHello = hs.hsTimings.elapsedTime() - - if err := hs.sendDummyChangeCipherSpec(); err != nil { - return err - } - - earlySecret := hs.earlySecret - if earlySecret == nil { - earlySecret = hs.suite.extract(nil, nil) - } - hs.handshakeSecret = hs.suite.extract(hs.sharedKey, - hs.suite.deriveSecret(earlySecret, "derived", nil)) - - clientSecret := hs.suite.deriveSecret(hs.handshakeSecret, - clientHandshakeTrafficLabel, hs.transcript) - c.in.setTrafficSecret(hs.suite, clientSecret) - serverSecret := hs.suite.deriveSecret(hs.handshakeSecret, - serverHandshakeTrafficLabel, hs.transcript) - c.out.setTrafficSecret(hs.suite, serverSecret) - - err := c.config.writeKeyLog(keyLogLabelClientHandshake, hs.clientHello.random, clientSecret) - if err != nil { - c.sendAlert(alertInternalError) - return err - } - err = c.config.writeKeyLog(keyLogLabelServerHandshake, hs.clientHello.random, serverSecret) - if err != nil { - c.sendAlert(alertInternalError) - return err - } - - encryptedExtensions := new(encryptedExtensionsMsg) - - selectedProto, err := negotiateALPN(c.config.NextProtos, hs.clientHello.alpnProtocols) - if err != nil { - c.sendAlert(alertNoApplicationProtocol) - return err - } - encryptedExtensions.alpnProtocol = selectedProto - c.clientProtocol = selectedProto - - if !c.ech.accepted && len(c.ech.retryConfigs) > 0 { - encryptedExtensions.ech = c.ech.retryConfigs - } - - hs.transcript.Write(encryptedExtensions.marshal()) - if _, err := c.writeRecord(recordTypeHandshake, encryptedExtensions.marshal()); err != nil { - return err - } - - hs.hsTimings.WriteEncryptedExtensions = hs.hsTimings.elapsedTime() - - return nil -} - -func (hs *serverHandshakeStateTLS13) requestClientCert() bool { - return hs.c.config.ClientAuth >= RequestClientCert && !hs.usingPSK -} - -func (hs *serverHandshakeStateTLS13) sendServerCertificate() error { - c := hs.c - - // Only one of PSK and certificates are used at a time. - if hs.usingPSK { - return nil - } - - if hs.requestClientCert() { - // Request a client certificate - certReq := new(certificateRequestMsgTLS13) - certReq.ocspStapling = true - certReq.scts = true - certReq.supportedSignatureAlgorithms = c.config.supportedSignatureAlgorithms() - certReq.supportDelegatedCredential = c.config.SupportDelegatedCredential - certReq.supportedSignatureAlgorithmsDC = supportedSignatureAlgorithmsDC - if c.config.ClientCAs != nil { - certReq.certificateAuthorities = c.config.ClientCAs.Subjects() - } - - hs.certReq = certReq - hs.transcript.Write(certReq.marshal()) - if _, err := c.writeRecord(recordTypeHandshake, certReq.marshal()); err != nil { - return err - } - } - - certMsg := new(certificateMsgTLS13) - - certMsg.certificate = *hs.cert - certMsg.scts = hs.clientHello.scts && len(hs.cert.SignedCertificateTimestamps) > 0 - certMsg.ocspStapling = hs.clientHello.ocspStapling && len(hs.cert.OCSPStaple) > 0 - certMsg.delegatedCredential = hs.clientHello.delegatedCredentialSupported && len(hs.cert.DelegatedCredential) > 0 - - hs.transcript.Write(certMsg.marshal()) - if _, err := c.writeRecord(recordTypeHandshake, certMsg.marshal()); err != nil { - return err - } - - hs.hsTimings.WriteCertificate = hs.hsTimings.elapsedTime() - - certVerifyMsg := new(certificateVerifyMsg) - certVerifyMsg.hasSignatureAlgorithm = true - certVerifyMsg.signatureAlgorithm = hs.sigAlg - sigType, sigHash, err := typeAndHashFromSignatureScheme(certVerifyMsg.signatureAlgorithm) - if err != nil { - return c.sendAlert(alertInternalError) - } - - signed := signedMessage(sigHash, serverSignatureContext, hs.transcript) - signOpts := crypto.SignerOpts(sigHash) - if sigType == signatureRSAPSS { - signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: sigHash} - } - sig, err := hs.cert.PrivateKey.(crypto.Signer).Sign(c.config.rand(), signed, signOpts) - if err != nil { - public := hs.cert.PrivateKey.(crypto.Signer).Public() - if rsaKey, ok := public.(*rsa.PublicKey); ok && sigType == signatureRSAPSS && - rsaKey.N.BitLen()/8 < sigHash.Size()*2+2 { // key too small for RSA-PSS - c.sendAlert(alertHandshakeFailure) - } else { - c.sendAlert(alertInternalError) - } - return errors.New("tls: failed to sign handshake: " + err.Error()) - } - certVerifyMsg.signature = sig - - hs.transcript.Write(certVerifyMsg.marshal()) - if _, err := c.writeRecord(recordTypeHandshake, certVerifyMsg.marshal()); err != nil { - return err - } - - hs.hsTimings.WriteCertificateVerify = hs.hsTimings.elapsedTime() - - return nil -} - -func (hs *serverHandshakeStateTLS13) sendServerFinished() error { - c := hs.c - - finished := &finishedMsg{ - verifyData: hs.suite.finishedHash(c.out.trafficSecret, hs.transcript), - } - - hs.transcript.Write(finished.marshal()) - if _, err := c.writeRecord(recordTypeHandshake, finished.marshal()); err != nil { - return err - } - - hs.hsTimings.WriteServerFinished = hs.hsTimings.elapsedTime() - - // Derive secrets that take context through the server Finished. - - hs.masterSecret = hs.suite.extract(nil, - hs.suite.deriveSecret(hs.handshakeSecret, "derived", nil)) - - hs.trafficSecret = hs.suite.deriveSecret(hs.masterSecret, - clientApplicationTrafficLabel, hs.transcript) - serverSecret := hs.suite.deriveSecret(hs.masterSecret, - serverApplicationTrafficLabel, hs.transcript) - c.out.setTrafficSecret(hs.suite, serverSecret) - - err := c.config.writeKeyLog(keyLogLabelClientTraffic, hs.clientHello.random, hs.trafficSecret) - if err != nil { - c.sendAlert(alertInternalError) - return err - } - err = c.config.writeKeyLog(keyLogLabelServerTraffic, hs.clientHello.random, serverSecret) - if err != nil { - c.sendAlert(alertInternalError) - return err - } - - c.ekm = hs.suite.exportKeyingMaterial(hs.masterSecret, hs.transcript) - - // If we did not request client certificates, at this point we can - // precompute the client finished and roll the transcript forward to send - // session tickets in our first flight. - if !hs.requestClientCert() { - if err := hs.sendSessionTickets(); err != nil { - return err - } - } - - return nil -} - -func (hs *serverHandshakeStateTLS13) shouldSendSessionTickets() bool { - if hs.c.config.SessionTicketsDisabled || hs.c.config.ECHEnabled { - return false - } - - // Don't send tickets the client wouldn't use. See RFC 8446, Section 4.2.9. - for _, pskMode := range hs.clientHello.pskModes { - if pskMode == pskModeDHE { - return true - } - } - return false -} - -func (hs *serverHandshakeStateTLS13) sendSessionTickets() error { - c := hs.c - - hs.clientFinished = hs.suite.finishedHash(c.in.trafficSecret, hs.transcript) - finishedMsg := &finishedMsg{ - verifyData: hs.clientFinished, - } - hs.transcript.Write(finishedMsg.marshal()) - - if !hs.shouldSendSessionTickets() { - return nil - } - - resumptionSecret := hs.suite.deriveSecret(hs.masterSecret, - resumptionLabel, hs.transcript) - - m := new(newSessionTicketMsgTLS13) - - var certsFromClient [][]byte - for _, cert := range c.peerCertificates { - certsFromClient = append(certsFromClient, cert.Raw) - } - state := sessionStateTLS13{ - cipherSuite: hs.suite.id, - createdAt: uint64(c.config.time().Unix()), - resumptionSecret: resumptionSecret, - certificate: Certificate{ - Certificate: certsFromClient, - OCSPStaple: c.ocspResponse, - SignedCertificateTimestamps: c.scts, - }, - } - var err error - m.label, err = c.encryptTicket(state.marshal()) - if err != nil { - return err - } - m.lifetime = uint32(maxSessionTicketLifetime / time.Second) - - // ticket_age_add is a random 32-bit value. See RFC 8446, section 4.6.1 - // The value is not stored anywhere; we never need to check the ticket age - // because 0-RTT is not supported. - ageAdd := make([]byte, 4) - _, err = hs.c.config.rand().Read(ageAdd) - if err != nil { - return err - } - m.ageAdd = binary.LittleEndian.Uint32(ageAdd) - - // ticket_nonce, which must be unique per connection, is always left at - // zero because we only ever send one ticket per connection. - - if _, err := c.writeRecord(recordTypeHandshake, m.marshal()); err != nil { - return err - } - - return nil -} - -func (hs *serverHandshakeStateTLS13) readClientCertificate() error { - c := hs.c - - if !hs.requestClientCert() { - // Make sure the connection is still being verified whether or not - // the server requested a client certificate. - if c.config.VerifyConnection != nil { - if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil { - c.sendAlert(alertBadCertificate) - return err - } - } - return nil - } - - // If we requested a client certificate, then the client must send a - // certificate message. If it's empty, no CertificateVerify is sent. - - msg, err := c.readHandshake() - if err != nil { - return err - } - - certMsg, ok := msg.(*certificateMsgTLS13) - if !ok { - c.sendAlert(alertUnexpectedMessage) - return unexpectedMessageError(certMsg, msg) - } - hs.transcript.Write(certMsg.marshal()) - - if err := c.processCertsFromClient(certMsg.certificate); err != nil { - return err - } - - if c.config.VerifyConnection != nil { - if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil { - c.sendAlert(alertBadCertificate) - return err - } - } - - hs.hsTimings.ReadCertificate = hs.hsTimings.elapsedTime() - - if len(certMsg.certificate.Certificate) != 0 { - msg, err = c.readHandshake() - if err != nil { - return err - } - - certVerify, ok := msg.(*certificateVerifyMsg) - if !ok { - c.sendAlert(alertUnexpectedMessage) - return unexpectedMessageError(certVerify, msg) - } - - // See RFC 8446, Section 4.4.3. - if !isSupportedSignatureAlgorithm(certVerify.signatureAlgorithm, c.config.supportedSignatureAlgorithms()) { - c.sendAlert(alertIllegalParameter) - return errors.New("tls: client certificate used with invalid signature algorithm") - } - sigType, sigHash, err := typeAndHashFromSignatureScheme(certVerify.signatureAlgorithm) - if err != nil { - return c.sendAlert(alertInternalError) - } - if sigType == signaturePKCS1v15 || sigHash == crypto.SHA1 { - c.sendAlert(alertIllegalParameter) - return errors.New("tls: client certificate used with invalid signature algorithm") - } - - if certMsg.delegatedCredential { - if err := hs.processDelegatedCredentialFromClient(certMsg.certificate.DelegatedCredential, certVerify); err != nil { - return err - } - } - - pk := c.peerCertificates[0].PublicKey - if c.verifiedDC != nil { - pk = c.verifiedDC.cred.publicKey - } - - signed := signedMessage(sigHash, clientSignatureContext, hs.transcript) - if err := verifyHandshakeSignature(sigType, pk, sigHash, signed, certVerify.signature); err != nil { - c.sendAlert(alertDecryptError) - return errors.New("tls: invalid signature by the client certificate: " + err.Error()) - } - - hs.transcript.Write(certVerify.marshal()) - } - - hs.hsTimings.ReadCertificateVerify = hs.hsTimings.elapsedTime() - - // If we waited until the client certificates to send session tickets, we - // are ready to do it now. - if err := hs.sendSessionTickets(); err != nil { - return err - } - - return nil -} - -func (hs *serverHandshakeStateTLS13) readClientFinished() error { - c := hs.c - - msg, err := c.readHandshake() - if err != nil { - return err - } - - finished, ok := msg.(*finishedMsg) - if !ok { - c.sendAlert(alertUnexpectedMessage) - return unexpectedMessageError(finished, msg) - } - - if !hmac.Equal(hs.clientFinished, finished.verifyData) { - c.sendAlert(alertDecryptError) - return errors.New("tls: invalid client finished hash") - } - - hs.hsTimings.ReadClientFinished = hs.hsTimings.elapsedTime() - - c.in.setTrafficSecret(hs.suite, hs.trafficSecret) - - return nil -} diff --git a/transport/cloudflaretls/hpke.go b/transport/cloudflaretls/hpke.go deleted file mode 100644 index b3861d09..00000000 --- a/transport/cloudflaretls/hpke.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2020 Cloudflare, Inc. All rights reserved. Use of this source code -// is governed by a BSD-style license that can be found in the LICENSE file. - -package tls - -import ( - "errors" - "fmt" - - "github.com/cloudflare/circl/hpke" -) - -// The mandatory-to-implement HPKE cipher suite for use with the ECH extension. -var defaultHPKESuite hpke.Suite - -func init() { - var err error - defaultHPKESuite, err = hpkeAssembleSuite( - uint16(hpke.KEM_X25519_HKDF_SHA256), - uint16(hpke.KDF_HKDF_SHA256), - uint16(hpke.AEAD_AES128GCM), - ) - if err != nil { - panic(fmt.Sprintf("hpke: mandatory-to-implement cipher suite not supported: %s", err)) - } -} - -func hpkeAssembleSuite(kemId, kdfId, aeadId uint16) (hpke.Suite, error) { - kem := hpke.KEM(kemId) - if !kem.IsValid() { - return hpke.Suite{}, errors.New("KEM is not supported") - } - kdf := hpke.KDF(kdfId) - if !kdf.IsValid() { - return hpke.Suite{}, errors.New("KDF is not supported") - } - aead := hpke.AEAD(aeadId) - if !aead.IsValid() { - return hpke.Suite{}, errors.New("AEAD is not supported") - } - return hpke.NewSuite(kem, kdf, aead), nil -} diff --git a/transport/cloudflaretls/key_agreement.go b/transport/cloudflaretls/key_agreement.go deleted file mode 100644 index 77846092..00000000 --- a/transport/cloudflaretls/key_agreement.go +++ /dev/null @@ -1,359 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package tls - -import ( - "crypto" - "crypto/md5" - "crypto/rsa" - "crypto/sha1" - "crypto/x509" - "errors" - "fmt" - "io" -) - -// a keyAgreement implements the client and server side of a TLS key agreement -// protocol by generating and processing key exchange messages. -type keyAgreement interface { - // On the server side, the first two methods are called in order. - - // In the case that the key agreement protocol doesn't use a - // ServerKeyExchange message, generateServerKeyExchange can return nil, - // nil. - generateServerKeyExchange(*Config, *Certificate, *clientHelloMsg, *serverHelloMsg) (*serverKeyExchangeMsg, error) - processClientKeyExchange(*Config, *Certificate, *clientKeyExchangeMsg, uint16) ([]byte, error) - - // On the client side, the next two methods are called in order. - - // This method may not be called if the server doesn't send a - // ServerKeyExchange message. - processServerKeyExchange(*Config, *clientHelloMsg, *serverHelloMsg, *x509.Certificate, *serverKeyExchangeMsg) error - generateClientKeyExchange(*Config, *clientHelloMsg, *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) -} - -var ( - errClientKeyExchange = errors.New("tls: invalid ClientKeyExchange message") - errServerKeyExchange = errors.New("tls: invalid ServerKeyExchange message") -) - -// rsaKeyAgreement implements the standard TLS key agreement where the client -// encrypts the pre-master secret to the server's public key. -type rsaKeyAgreement struct{} - -func (ka rsaKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) { - return nil, nil -} - -func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) { - if len(ckx.ciphertext) < 2 { - return nil, errClientKeyExchange - } - ciphertextLen := int(ckx.ciphertext[0])<<8 | int(ckx.ciphertext[1]) - if ciphertextLen != len(ckx.ciphertext)-2 { - return nil, errClientKeyExchange - } - ciphertext := ckx.ciphertext[2:] - - priv, ok := cert.PrivateKey.(crypto.Decrypter) - if !ok { - return nil, errors.New("tls: certificate private key does not implement crypto.Decrypter") - } - // Perform constant time RSA PKCS #1 v1.5 decryption - preMasterSecret, err := priv.Decrypt(config.rand(), ciphertext, &rsa.PKCS1v15DecryptOptions{SessionKeyLen: 48}) - if err != nil { - return nil, err - } - // We don't check the version number in the premaster secret. For one, - // by checking it, we would leak information about the validity of the - // encrypted pre-master secret. Secondly, it provides only a small - // benefit against a downgrade attack and some implementations send the - // wrong version anyway. See the discussion at the end of section - // 7.4.7.1 of RFC 4346. - return preMasterSecret, nil -} - -func (ka rsaKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error { - return errors.New("tls: unexpected ServerKeyExchange") -} - -func (ka rsaKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) { - preMasterSecret := make([]byte, 48) - preMasterSecret[0] = byte(clientHello.vers >> 8) - preMasterSecret[1] = byte(clientHello.vers) - _, err := io.ReadFull(config.rand(), preMasterSecret[2:]) - if err != nil { - return nil, nil, err - } - - rsaKey, ok := cert.PublicKey.(*rsa.PublicKey) - if !ok { - return nil, nil, errors.New("tls: server certificate contains incorrect key type for selected ciphersuite") - } - encrypted, err := rsa.EncryptPKCS1v15(config.rand(), rsaKey, preMasterSecret) - if err != nil { - return nil, nil, err - } - ckx := new(clientKeyExchangeMsg) - ckx.ciphertext = make([]byte, len(encrypted)+2) - ckx.ciphertext[0] = byte(len(encrypted) >> 8) - ckx.ciphertext[1] = byte(len(encrypted)) - copy(ckx.ciphertext[2:], encrypted) - return preMasterSecret, ckx, nil -} - -// sha1Hash calculates a SHA1 hash over the given byte slices. -func sha1Hash(slices [][]byte) []byte { - hsha1 := sha1.New() - for _, slice := range slices { - hsha1.Write(slice) - } - return hsha1.Sum(nil) -} - -// md5SHA1Hash implements TLS 1.0's hybrid hash function which consists of the -// concatenation of an MD5 and SHA1 hash. -func md5SHA1Hash(slices [][]byte) []byte { - md5sha1 := make([]byte, md5.Size+sha1.Size) - hmd5 := md5.New() - for _, slice := range slices { - hmd5.Write(slice) - } - copy(md5sha1, hmd5.Sum(nil)) - copy(md5sha1[md5.Size:], sha1Hash(slices)) - return md5sha1 -} - -// hashForServerKeyExchange hashes the given slices and returns their digest -// using the given hash function (for >= TLS 1.2) or using a default based on -// the sigType (for earlier TLS versions). For Ed25519 signatures, which don't -// do pre-hashing, it returns the concatenation of the slices. -func hashForServerKeyExchange(sigType uint8, hashFunc crypto.Hash, version uint16, slices ...[]byte) []byte { - if sigType == signatureEd25519 || circlSchemeBySigType(sigType) != nil { - var signed []byte - for _, slice := range slices { - signed = append(signed, slice...) - } - return signed - } - if version >= VersionTLS12 { - h := hashFunc.New() - for _, slice := range slices { - h.Write(slice) - } - digest := h.Sum(nil) - return digest - } - if sigType == signatureECDSA { - return sha1Hash(slices) - } - return md5SHA1Hash(slices) -} - -// ecdheKeyAgreement implements a TLS key agreement where the server -// generates an ephemeral EC public/private key pair and signs it. The -// pre-master secret is then calculated using ECDH. The signature may -// be ECDSA, Ed25519 or RSA. -type ecdheKeyAgreement struct { - version uint16 - isRSA bool - params ecdheParameters - - // ckx and preMasterSecret are generated in processServerKeyExchange - // and returned in generateClientKeyExchange. - ckx *clientKeyExchangeMsg - preMasterSecret []byte -} - -func (ka *ecdheKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) { - var curveID CurveID - for _, c := range clientHello.supportedCurves { - if config.supportsCurve(c) && curveIdToCirclScheme(c) == nil { - curveID = c - break - } - } - - if curveID == 0 { - return nil, errors.New("tls: no supported elliptic curves offered") - } - if _, ok := curveForCurveID(curveID); curveID != X25519 && !ok { - return nil, errors.New("tls: CurvePreferences includes unsupported curve") - } - - params, err := generateECDHEParameters(config.rand(), curveID) - if err != nil { - return nil, err - } - ka.params = params - - // See RFC 4492, Section 5.4. - ecdhePublic := params.PublicKey() - serverECDHEParams := make([]byte, 1+2+1+len(ecdhePublic)) - serverECDHEParams[0] = 3 // named curve - serverECDHEParams[1] = byte(curveID >> 8) - serverECDHEParams[2] = byte(curveID) - serverECDHEParams[3] = byte(len(ecdhePublic)) - copy(serverECDHEParams[4:], ecdhePublic) - - priv, ok := cert.PrivateKey.(crypto.Signer) - if !ok { - return nil, fmt.Errorf("tls: certificate private key of type %T does not implement crypto.Signer", cert.PrivateKey) - } - - var signatureAlgorithm SignatureScheme - var sigType uint8 - var sigHash crypto.Hash - if ka.version >= VersionTLS12 { - signatureAlgorithm, err = selectSignatureScheme(ka.version, cert, clientHello.supportedSignatureAlgorithms) - if err != nil { - return nil, err - } - sigType, sigHash, err = typeAndHashFromSignatureScheme(signatureAlgorithm) - if err != nil { - return nil, err - } - } else { - sigType, sigHash, err = legacyTypeAndHashFromPublicKey(priv.Public()) - if err != nil { - return nil, err - } - } - if (sigType == signaturePKCS1v15 || sigType == signatureRSAPSS) != ka.isRSA { - return nil, errors.New("tls: certificate cannot be used with the selected cipher suite") - } - - signed := hashForServerKeyExchange(sigType, sigHash, ka.version, clientHello.random, hello.random, serverECDHEParams) - - signOpts := crypto.SignerOpts(sigHash) - if sigType == signatureRSAPSS { - signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: sigHash} - } - sig, err := priv.Sign(config.rand(), signed, signOpts) - if err != nil { - return nil, errors.New("tls: failed to sign ECDHE parameters: " + err.Error()) - } - - skx := new(serverKeyExchangeMsg) - sigAndHashLen := 0 - if ka.version >= VersionTLS12 { - sigAndHashLen = 2 - } - skx.key = make([]byte, len(serverECDHEParams)+sigAndHashLen+2+len(sig)) - copy(skx.key, serverECDHEParams) - k := skx.key[len(serverECDHEParams):] - if ka.version >= VersionTLS12 { - k[0] = byte(signatureAlgorithm >> 8) - k[1] = byte(signatureAlgorithm) - k = k[2:] - } - k[0] = byte(len(sig) >> 8) - k[1] = byte(len(sig)) - copy(k[2:], sig) - - return skx, nil -} - -func (ka *ecdheKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) { - if len(ckx.ciphertext) == 0 || int(ckx.ciphertext[0]) != len(ckx.ciphertext)-1 { - return nil, errClientKeyExchange - } - - preMasterSecret := ka.params.SharedKey(ckx.ciphertext[1:]) - if preMasterSecret == nil { - return nil, errClientKeyExchange - } - - return preMasterSecret, nil -} - -func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error { - if len(skx.key) < 4 { - return errServerKeyExchange - } - if skx.key[0] != 3 { // named curve - return errors.New("tls: server selected unsupported curve") - } - curveID := CurveID(skx.key[1])<<8 | CurveID(skx.key[2]) - - publicLen := int(skx.key[3]) - if publicLen+4 > len(skx.key) { - return errServerKeyExchange - } - serverECDHEParams := skx.key[:4+publicLen] - publicKey := serverECDHEParams[4:] - - sig := skx.key[4+publicLen:] - if len(sig) < 2 { - return errServerKeyExchange - } - - if _, ok := curveForCurveID(curveID); curveID != X25519 && !ok { - return errors.New("tls: server selected unsupported curve") - } - - params, err := generateECDHEParameters(config.rand(), curveID) - if err != nil { - return err - } - ka.params = params - - ka.preMasterSecret = params.SharedKey(publicKey) - if ka.preMasterSecret == nil { - return errServerKeyExchange - } - - ourPublicKey := params.PublicKey() - ka.ckx = new(clientKeyExchangeMsg) - ka.ckx.ciphertext = make([]byte, 1+len(ourPublicKey)) - ka.ckx.ciphertext[0] = byte(len(ourPublicKey)) - copy(ka.ckx.ciphertext[1:], ourPublicKey) - - var sigType uint8 - var sigHash crypto.Hash - if ka.version >= VersionTLS12 { - signatureAlgorithm := SignatureScheme(sig[0])<<8 | SignatureScheme(sig[1]) - sig = sig[2:] - if len(sig) < 2 { - return errServerKeyExchange - } - - if !isSupportedSignatureAlgorithm(signatureAlgorithm, clientHello.supportedSignatureAlgorithms) { - return errors.New("tls: certificate used with invalid signature algorithm") - } - sigType, sigHash, err = typeAndHashFromSignatureScheme(signatureAlgorithm) - if err != nil { - return err - } - } else { - sigType, sigHash, err = legacyTypeAndHashFromPublicKey(cert.PublicKey) - if err != nil { - return err - } - } - if (sigType == signaturePKCS1v15 || sigType == signatureRSAPSS) != ka.isRSA { - return errServerKeyExchange - } - - sigLen := int(sig[0])<<8 | int(sig[1]) - if sigLen+2 != len(sig) { - return errServerKeyExchange - } - sig = sig[2:] - - signed := hashForServerKeyExchange(sigType, sigHash, ka.version, clientHello.random, serverHello.random, serverECDHEParams) - if err := verifyHandshakeSignature(sigType, cert.PublicKey, sigHash, signed, sig); err != nil { - return errors.New("tls: invalid signature by the server certificate: " + err.Error()) - } - return nil -} - -func (ka *ecdheKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) { - if ka.ckx == nil { - return nil, nil, errors.New("tls: missing ServerKeyExchange message") - } - - return ka.preMasterSecret, ka.ckx, nil -} diff --git a/transport/cloudflaretls/key_schedule.go b/transport/cloudflaretls/key_schedule.go deleted file mode 100644 index 31401697..00000000 --- a/transport/cloudflaretls/key_schedule.go +++ /dev/null @@ -1,199 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package tls - -import ( - "crypto/elliptic" - "crypto/hmac" - "errors" - "hash" - "io" - "math/big" - - "golang.org/x/crypto/cryptobyte" - "golang.org/x/crypto/curve25519" - "golang.org/x/crypto/hkdf" -) - -// This file contains the functions necessary to compute the TLS 1.3 key -// schedule. See RFC 8446, Section 7. - -const ( - resumptionBinderLabel = "res binder" - clientHandshakeTrafficLabel = "c hs traffic" - serverHandshakeTrafficLabel = "s hs traffic" - clientApplicationTrafficLabel = "c ap traffic" - serverApplicationTrafficLabel = "s ap traffic" - exporterLabel = "exp master" - resumptionLabel = "res master" - trafficUpdateLabel = "traffic upd" -) - -// expandLabel implements HKDF-Expand-Label from RFC 8446, Section 7.1. -func (c *cipherSuiteTLS13) expandLabel(secret []byte, label string, context []byte, length int) []byte { - var hkdfLabel cryptobyte.Builder - hkdfLabel.AddUint16(uint16(length)) - hkdfLabel.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes([]byte("tls13 ")) - b.AddBytes([]byte(label)) - }) - hkdfLabel.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(context) - }) - out := make([]byte, length) - n, err := hkdf.Expand(c.hash.New, secret, hkdfLabel.BytesOrPanic()).Read(out) - if err != nil || n != length { - panic("tls: HKDF-Expand-Label invocation failed unexpectedly") - } - return out -} - -// deriveSecret implements Derive-Secret from RFC 8446, Section 7.1. -func (c *cipherSuiteTLS13) deriveSecret(secret []byte, label string, transcript hash.Hash) []byte { - if transcript == nil { - transcript = c.hash.New() - } - return c.expandLabel(secret, label, transcript.Sum(nil), c.hash.Size()) -} - -// extract implements HKDF-Extract with the cipher suite hash. -func (c *cipherSuiteTLS13) extract(newSecret, currentSecret []byte) []byte { - if newSecret == nil { - newSecret = make([]byte, c.hash.Size()) - } - return hkdf.Extract(c.hash.New, newSecret, currentSecret) -} - -// nextTrafficSecret generates the next traffic secret, given the current one, -// according to RFC 8446, Section 7.2. -func (c *cipherSuiteTLS13) nextTrafficSecret(trafficSecret []byte) []byte { - return c.expandLabel(trafficSecret, trafficUpdateLabel, nil, c.hash.Size()) -} - -// trafficKey generates traffic keys according to RFC 8446, Section 7.3. -func (c *cipherSuiteTLS13) trafficKey(trafficSecret []byte) (key, iv []byte) { - key = c.expandLabel(trafficSecret, "key", nil, c.keyLen) - iv = c.expandLabel(trafficSecret, "iv", nil, aeadNonceLength) - return -} - -// finishedHash generates the Finished verify_data or PskBinderEntry according -// to RFC 8446, Section 4.4.4. See sections 4.4 and 4.2.11.2 for the baseKey -// selection. -func (c *cipherSuiteTLS13) finishedHash(baseKey []byte, transcript hash.Hash) []byte { - finishedKey := c.expandLabel(baseKey, "finished", nil, c.hash.Size()) - verifyData := hmac.New(c.hash.New, finishedKey) - verifyData.Write(transcript.Sum(nil)) - return verifyData.Sum(nil) -} - -// exportKeyingMaterial implements RFC5705 exporters for TLS 1.3 according to -// RFC 8446, Section 7.5. -func (c *cipherSuiteTLS13) exportKeyingMaterial(masterSecret []byte, transcript hash.Hash) func(string, []byte, int) ([]byte, error) { - expMasterSecret := c.deriveSecret(masterSecret, exporterLabel, transcript) - return func(label string, context []byte, length int) ([]byte, error) { - secret := c.deriveSecret(expMasterSecret, label, nil) - h := c.hash.New() - h.Write(context) - return c.expandLabel(secret, "exporter", h.Sum(nil), length), nil - } -} - -// ecdheParameters implements Diffie-Hellman with either NIST curves or X25519, -// according to RFC 8446, Section 4.2.8.2. -type ecdheParameters interface { - CurveID() CurveID - PublicKey() []byte - SharedKey(peerPublicKey []byte) []byte -} - -func generateECDHEParameters(rand io.Reader, curveID CurveID) (ecdheParameters, error) { - if curveID == X25519 { - privateKey := make([]byte, curve25519.ScalarSize) - if _, err := io.ReadFull(rand, privateKey); err != nil { - return nil, err - } - publicKey, err := curve25519.X25519(privateKey, curve25519.Basepoint) - if err != nil { - return nil, err - } - return &x25519Parameters{privateKey: privateKey, publicKey: publicKey}, nil - } - - curve, ok := curveForCurveID(curveID) - if !ok { - return nil, errors.New("tls: internal error: unsupported curve") - } - - p := &nistParameters{curveID: curveID} - var err error - p.privateKey, p.x, p.y, err = elliptic.GenerateKey(curve, rand) - if err != nil { - return nil, err - } - return p, nil -} - -func curveForCurveID(id CurveID) (elliptic.Curve, bool) { - switch id { - case CurveP256: - return elliptic.P256(), true - case CurveP384: - return elliptic.P384(), true - case CurveP521: - return elliptic.P521(), true - default: - return nil, false - } -} - -type nistParameters struct { - privateKey []byte - x, y *big.Int // public key - curveID CurveID -} - -func (p *nistParameters) CurveID() CurveID { - return p.curveID -} - -func (p *nistParameters) PublicKey() []byte { - curve, _ := curveForCurveID(p.curveID) - return elliptic.Marshal(curve, p.x, p.y) -} - -func (p *nistParameters) SharedKey(peerPublicKey []byte) []byte { - curve, _ := curveForCurveID(p.curveID) - // Unmarshal also checks whether the given point is on the curve. - x, y := elliptic.Unmarshal(curve, peerPublicKey) - if x == nil { - return nil - } - - xShared, _ := curve.ScalarMult(x, y, p.privateKey) - sharedKey := make([]byte, (curve.Params().BitSize+7)/8) - return xShared.FillBytes(sharedKey) -} - -type x25519Parameters struct { - privateKey []byte - publicKey []byte -} - -func (p *x25519Parameters) CurveID() CurveID { - return X25519 -} - -func (p *x25519Parameters) PublicKey() []byte { - return p.publicKey[:] -} - -func (p *x25519Parameters) SharedKey(peerPublicKey []byte) []byte { - sharedKey, err := curve25519.X25519(p.privateKey, peerPublicKey) - if err != nil { - return nil - } - return sharedKey -} diff --git a/transport/cloudflaretls/prf.go b/transport/cloudflaretls/prf.go deleted file mode 100644 index abac3ce7..00000000 --- a/transport/cloudflaretls/prf.go +++ /dev/null @@ -1,285 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package tls - -import ( - "crypto" - "crypto/hmac" - "crypto/md5" - "crypto/sha1" - "crypto/sha256" - "crypto/sha512" - "errors" - "fmt" - "hash" -) - -// Split a premaster secret in two as specified in RFC 4346, Section 5. -func splitPreMasterSecret(secret []byte) (s1, s2 []byte) { - s1 = secret[0 : (len(secret)+1)/2] - s2 = secret[len(secret)/2:] - return -} - -// pHash implements the P_hash function, as defined in RFC 4346, Section 5. -func pHash(result, secret, seed []byte, hash func() hash.Hash) { - h := hmac.New(hash, secret) - h.Write(seed) - a := h.Sum(nil) - - j := 0 - for j < len(result) { - h.Reset() - h.Write(a) - h.Write(seed) - b := h.Sum(nil) - copy(result[j:], b) - j += len(b) - - h.Reset() - h.Write(a) - a = h.Sum(nil) - } -} - -// prf10 implements the TLS 1.0 pseudo-random function, as defined in RFC 2246, Section 5. -func prf10(result, secret, label, seed []byte) { - hashSHA1 := sha1.New - hashMD5 := md5.New - - labelAndSeed := make([]byte, len(label)+len(seed)) - copy(labelAndSeed, label) - copy(labelAndSeed[len(label):], seed) - - s1, s2 := splitPreMasterSecret(secret) - pHash(result, s1, labelAndSeed, hashMD5) - result2 := make([]byte, len(result)) - pHash(result2, s2, labelAndSeed, hashSHA1) - - for i, b := range result2 { - result[i] ^= b - } -} - -// prf12 implements the TLS 1.2 pseudo-random function, as defined in RFC 5246, Section 5. -func prf12(hashFunc func() hash.Hash) func(result, secret, label, seed []byte) { - return func(result, secret, label, seed []byte) { - labelAndSeed := make([]byte, len(label)+len(seed)) - copy(labelAndSeed, label) - copy(labelAndSeed[len(label):], seed) - - pHash(result, secret, labelAndSeed, hashFunc) - } -} - -const ( - masterSecretLength = 48 // Length of a master secret in TLS 1.1. - finishedVerifyLength = 12 // Length of verify_data in a Finished message. -) - -var ( - masterSecretLabel = []byte("master secret") - keyExpansionLabel = []byte("key expansion") - clientFinishedLabel = []byte("client finished") - serverFinishedLabel = []byte("server finished") -) - -func prfAndHashForVersion(version uint16, suite *cipherSuite) (func(result, secret, label, seed []byte), crypto.Hash) { - switch version { - case VersionTLS10, VersionTLS11: - return prf10, crypto.Hash(0) - case VersionTLS12: - if suite.flags&suiteSHA384 != 0 { - return prf12(sha512.New384), crypto.SHA384 - } - return prf12(sha256.New), crypto.SHA256 - default: - panic("unknown version") - } -} - -func prfForVersion(version uint16, suite *cipherSuite) func(result, secret, label, seed []byte) { - prf, _ := prfAndHashForVersion(version, suite) - return prf -} - -// masterFromPreMasterSecret generates the master secret from the pre-master -// secret. See RFC 5246, Section 8.1. -func masterFromPreMasterSecret(version uint16, suite *cipherSuite, preMasterSecret, clientRandom, serverRandom []byte) []byte { - seed := make([]byte, 0, len(clientRandom)+len(serverRandom)) - seed = append(seed, clientRandom...) - seed = append(seed, serverRandom...) - - masterSecret := make([]byte, masterSecretLength) - prfForVersion(version, suite)(masterSecret, preMasterSecret, masterSecretLabel, seed) - return masterSecret -} - -// keysFromMasterSecret generates the connection keys from the master -// secret, given the lengths of the MAC key, cipher key and IV, as defined in -// RFC 2246, Section 6.3. -func keysFromMasterSecret(version uint16, suite *cipherSuite, masterSecret, clientRandom, serverRandom []byte, macLen, keyLen, ivLen int) (clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV []byte) { - seed := make([]byte, 0, len(serverRandom)+len(clientRandom)) - seed = append(seed, serverRandom...) - seed = append(seed, clientRandom...) - - n := 2*macLen + 2*keyLen + 2*ivLen - keyMaterial := make([]byte, n) - prfForVersion(version, suite)(keyMaterial, masterSecret, keyExpansionLabel, seed) - clientMAC = keyMaterial[:macLen] - keyMaterial = keyMaterial[macLen:] - serverMAC = keyMaterial[:macLen] - keyMaterial = keyMaterial[macLen:] - clientKey = keyMaterial[:keyLen] - keyMaterial = keyMaterial[keyLen:] - serverKey = keyMaterial[:keyLen] - keyMaterial = keyMaterial[keyLen:] - clientIV = keyMaterial[:ivLen] - keyMaterial = keyMaterial[ivLen:] - serverIV = keyMaterial[:ivLen] - return -} - -func newFinishedHash(version uint16, cipherSuite *cipherSuite) finishedHash { - var buffer []byte - if version >= VersionTLS12 { - buffer = []byte{} - } - - prf, hash := prfAndHashForVersion(version, cipherSuite) - if hash != 0 { - return finishedHash{hash.New(), hash.New(), nil, nil, buffer, version, prf} - } - - return finishedHash{sha1.New(), sha1.New(), md5.New(), md5.New(), buffer, version, prf} -} - -// A finishedHash calculates the hash of a set of handshake messages suitable -// for including in a Finished message. -type finishedHash struct { - client hash.Hash - server hash.Hash - - // Prior to TLS 1.2, an additional MD5 hash is required. - clientMD5 hash.Hash - serverMD5 hash.Hash - - // In TLS 1.2, a full buffer is sadly required. - buffer []byte - - version uint16 - prf func(result, secret, label, seed []byte) -} - -func (h *finishedHash) Write(msg []byte) (n int, err error) { - h.client.Write(msg) - h.server.Write(msg) - - if h.version < VersionTLS12 { - h.clientMD5.Write(msg) - h.serverMD5.Write(msg) - } - - if h.buffer != nil { - h.buffer = append(h.buffer, msg...) - } - - return len(msg), nil -} - -func (h finishedHash) Sum() []byte { - if h.version >= VersionTLS12 { - return h.client.Sum(nil) - } - - out := make([]byte, 0, md5.Size+sha1.Size) - out = h.clientMD5.Sum(out) - return h.client.Sum(out) -} - -// clientSum returns the contents of the verify_data member of a client's -// Finished message. -func (h finishedHash) clientSum(masterSecret []byte) []byte { - out := make([]byte, finishedVerifyLength) - h.prf(out, masterSecret, clientFinishedLabel, h.Sum()) - return out -} - -// serverSum returns the contents of the verify_data member of a server's -// Finished message. -func (h finishedHash) serverSum(masterSecret []byte) []byte { - out := make([]byte, finishedVerifyLength) - h.prf(out, masterSecret, serverFinishedLabel, h.Sum()) - return out -} - -// hashForClientCertificate returns the handshake messages so far, pre-hashed if -// necessary, suitable for signing by a TLS client certificate. -func (h finishedHash) hashForClientCertificate(sigType uint8, hashAlg crypto.Hash, masterSecret []byte) []byte { - if (h.version >= VersionTLS12 || sigType == signatureEd25519 || circlSchemeBySigType(sigType) != nil) && h.buffer == nil { - panic("tls: handshake hash for a client certificate requested after discarding the handshake buffer") - } - - if sigType == signatureEd25519 || circlSchemeBySigType(sigType) != nil { - return h.buffer - } - - if h.version >= VersionTLS12 { - hash := hashAlg.New() - hash.Write(h.buffer) - return hash.Sum(nil) - } - - if sigType == signatureECDSA { - return h.server.Sum(nil) - } - - return h.Sum() -} - -// discardHandshakeBuffer is called when there is no more need to -// buffer the entirety of the handshake messages. -func (h *finishedHash) discardHandshakeBuffer() { - h.buffer = nil -} - -// noExportedKeyingMaterial is used as a value of -// ConnectionState.ekm when renegotiation is enabled and thus -// we wish to fail all key-material export requests. -func noExportedKeyingMaterial(label string, context []byte, length int) ([]byte, error) { - return nil, errors.New("crypto/tls: ExportKeyingMaterial is unavailable when renegotiation is enabled") -} - -// ekmFromMasterSecret generates exported keying material as defined in RFC 5705. -func ekmFromMasterSecret(version uint16, suite *cipherSuite, masterSecret, clientRandom, serverRandom []byte) func(string, []byte, int) ([]byte, error) { - return func(label string, context []byte, length int) ([]byte, error) { - switch label { - case "client finished", "server finished", "master secret", "key expansion": - // These values are reserved and may not be used. - return nil, fmt.Errorf("crypto/tls: reserved ExportKeyingMaterial label: %s", label) - } - - seedLen := len(serverRandom) + len(clientRandom) - if context != nil { - seedLen += 2 + len(context) - } - seed := make([]byte, 0, seedLen) - - seed = append(seed, clientRandom...) - seed = append(seed, serverRandom...) - - if context != nil { - if len(context) >= 1<<16 { - return nil, fmt.Errorf("crypto/tls: ExportKeyingMaterial context too long") - } - seed = append(seed, byte(len(context)>>8), byte(len(context))) - seed = append(seed, context...) - } - - keyMaterial := make([]byte, length) - prfForVersion(version, suite)(keyMaterial, masterSecret, []byte(label), seed) - return keyMaterial, nil - } -} diff --git a/transport/cloudflaretls/ticket.go b/transport/cloudflaretls/ticket.go deleted file mode 100644 index 6c1d20da..00000000 --- a/transport/cloudflaretls/ticket.go +++ /dev/null @@ -1,185 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package tls - -import ( - "bytes" - "crypto/aes" - "crypto/cipher" - "crypto/hmac" - "crypto/sha256" - "crypto/subtle" - "errors" - "io" - - "golang.org/x/crypto/cryptobyte" -) - -// sessionState contains the information that is serialized into a session -// ticket in order to later resume a connection. -type sessionState struct { - vers uint16 - cipherSuite uint16 - createdAt uint64 - masterSecret []byte // opaque master_secret<1..2^16-1>; - // struct { opaque certificate<1..2^24-1> } Certificate; - certificates [][]byte // Certificate certificate_list<0..2^24-1>; - - // usedOldKey is true if the ticket from which this session came from - // was encrypted with an older key and thus should be refreshed. - usedOldKey bool -} - -func (m *sessionState) marshal() []byte { - var b cryptobyte.Builder - b.AddUint16(m.vers) - b.AddUint16(m.cipherSuite) - addUint64(&b, m.createdAt) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(m.masterSecret) - }) - b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { - for _, cert := range m.certificates { - b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(cert) - }) - } - }) - return b.BytesOrPanic() -} - -func (m *sessionState) unmarshal(data []byte) bool { - *m = sessionState{usedOldKey: m.usedOldKey} - s := cryptobyte.String(data) - if ok := s.ReadUint16(&m.vers) && - s.ReadUint16(&m.cipherSuite) && - readUint64(&s, &m.createdAt) && - readUint16LengthPrefixed(&s, &m.masterSecret) && - len(m.masterSecret) != 0; !ok { - return false - } - var certList cryptobyte.String - if !s.ReadUint24LengthPrefixed(&certList) { - return false - } - for !certList.Empty() { - var cert []byte - if !readUint24LengthPrefixed(&certList, &cert) { - return false - } - m.certificates = append(m.certificates, cert) - } - return s.Empty() -} - -// sessionStateTLS13 is the content of a TLS 1.3 session ticket. Its first -// version (revision = 0) doesn't carry any of the information needed for 0-RTT -// validation and the nonce is always empty. -type sessionStateTLS13 struct { - // uint8 version = 0x0304; - // uint8 revision = 0; - cipherSuite uint16 - createdAt uint64 - resumptionSecret []byte // opaque resumption_master_secret<1..2^8-1>; - certificate Certificate // CertificateEntry certificate_list<0..2^24-1>; -} - -func (m *sessionStateTLS13) marshal() []byte { - var b cryptobyte.Builder - b.AddUint16(VersionTLS13) - b.AddUint8(0) // revision - b.AddUint16(m.cipherSuite) - addUint64(&b, m.createdAt) - b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(m.resumptionSecret) - }) - marshalCertificate(&b, m.certificate) - return b.BytesOrPanic() -} - -func (m *sessionStateTLS13) unmarshal(data []byte) bool { - *m = sessionStateTLS13{} - s := cryptobyte.String(data) - var version uint16 - var revision uint8 - return s.ReadUint16(&version) && - version == VersionTLS13 && - s.ReadUint8(&revision) && - revision == 0 && - s.ReadUint16(&m.cipherSuite) && - readUint64(&s, &m.createdAt) && - readUint8LengthPrefixed(&s, &m.resumptionSecret) && - len(m.resumptionSecret) != 0 && - unmarshalCertificate(&s, &m.certificate) && - s.Empty() -} - -func (c *Conn) encryptTicket(state []byte) ([]byte, error) { - if len(c.ticketKeys) == 0 { - return nil, errors.New("tls: internal error: session ticket keys unavailable") - } - - encrypted := make([]byte, ticketKeyNameLen+aes.BlockSize+len(state)+sha256.Size) - keyName := encrypted[:ticketKeyNameLen] - iv := encrypted[ticketKeyNameLen : ticketKeyNameLen+aes.BlockSize] - macBytes := encrypted[len(encrypted)-sha256.Size:] - - if _, err := io.ReadFull(c.config.rand(), iv); err != nil { - return nil, err - } - key := c.ticketKeys[0] - copy(keyName, key.keyName[:]) - block, err := aes.NewCipher(key.aesKey[:]) - if err != nil { - return nil, errors.New("tls: failed to create cipher while encrypting ticket: " + err.Error()) - } - cipher.NewCTR(block, iv).XORKeyStream(encrypted[ticketKeyNameLen+aes.BlockSize:], state) - - mac := hmac.New(sha256.New, key.hmacKey[:]) - mac.Write(encrypted[:len(encrypted)-sha256.Size]) - mac.Sum(macBytes[:0]) - - return encrypted, nil -} - -func (c *Conn) decryptTicket(encrypted []byte) (plaintext []byte, usedOldKey bool) { - if len(encrypted) < ticketKeyNameLen+aes.BlockSize+sha256.Size { - return nil, false - } - - keyName := encrypted[:ticketKeyNameLen] - iv := encrypted[ticketKeyNameLen : ticketKeyNameLen+aes.BlockSize] - macBytes := encrypted[len(encrypted)-sha256.Size:] - ciphertext := encrypted[ticketKeyNameLen+aes.BlockSize : len(encrypted)-sha256.Size] - - keyIndex := -1 - for i, candidateKey := range c.ticketKeys { - if bytes.Equal(keyName, candidateKey.keyName[:]) { - keyIndex = i - break - } - } - if keyIndex == -1 { - return nil, false - } - key := &c.ticketKeys[keyIndex] - - mac := hmac.New(sha256.New, key.hmacKey[:]) - mac.Write(encrypted[:len(encrypted)-sha256.Size]) - expected := mac.Sum(nil) - - if subtle.ConstantTimeCompare(macBytes, expected) != 1 { - return nil, false - } - - block, err := aes.NewCipher(key.aesKey[:]) - if err != nil { - return nil, false - } - plaintext = make([]byte, len(ciphertext)) - cipher.NewCTR(block, iv).XORKeyStream(plaintext, ciphertext) - - return plaintext, keyIndex > 0 -} diff --git a/transport/cloudflaretls/tls.go b/transport/cloudflaretls/tls.go deleted file mode 100644 index 973aac43..00000000 --- a/transport/cloudflaretls/tls.go +++ /dev/null @@ -1,410 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package tls partially implements TLS 1.2, as specified in RFC 5246, -// and TLS 1.3, as specified in RFC 8446. -// -// This package implements the "Encrypted ClientHello (ECH)" extension, as -// specified by draft-ietf-tls-esni-13. This extension allows the client to -// encrypt its ClientHello to the public key of an ECH-service provider, known -// as the client-facing server. If successful, then the client-facing server -// forwards the decrypted ClientHello to the intended recipient, known as the -// backend server. The goal of this mechanism is to ensure that connections made -// to backend servers are indistinguishable from one another. -// -// This package implements the "Delegated Credentials" extension, as -// specified by draft-ietf-tls-subcerts-10. This extension allows the usage -// of a limited delegation mechanism that allows a TLS peer to issue its own -// credentials within the scope of a certificate issued by an external -// CA. These credentials only enable the recipient of the delegation to -// speak for names that the CA has authorized. If the client or server supports -// this extension, then the server or client may use a "delegated credential" -// as the signing key in the handshake. A delegated credential is a short lived -// public/secret key pair delegated to the peer by an entity trusted by the -// corresponding peer. This allows a reverse proxy to terminate a TLS connection -// on behalf of the entity. Credentials can't be revoked; in order to -// mitigate risk in case the reverse proxy is compromised, the credential is only -// valid for a short time (days, hours, or even minutes). -package tls - -// BUG(cjpatton): In order to achieve its security goal, the ECH extension -// requires padding in order to ensure that the length of handshake messages -// doesn't depend on who terminates the connection. This package does not yet -// implement server-side padding: see -// https://github.com/tlswg/draft-ietf-tls-esni/issues/264. - -// BUG(cjpatton): The interaction of the ECH extension with PSK has not yet been -// fully vetted. For now, the server disables session tickets if ECH is enabled. - -// BUG(cjpatton): Upon ECH rejection, if retry configurations are provided, then -// the client is expected to retry the connection. Otherwise, it may regard ECH -// as being securely disabled by the client-facing server. The client in this -// package does not attempt to retry the handshake. - -// BUG(cjpatton): If the client offers the ECH extension and the client-facing -// server rejects it, then only the client-facing server is authenticated. In -// particular, the client is expected to respond to a CertificateRequest with an -// empty certificate. This package does not yet implement this behavior. - -// BUG(agl): The crypto/tls package only implements some countermeasures -// against Lucky13 attacks on CBC-mode encryption, and only on SHA1 -// variants. See http://www.isg.rhul.ac.uk/tls/TLStiming.pdf and -// https://www.imperialviolet.org/2013/02/04/luckythirteen.html. - -import ( - "bytes" - "context" - "crypto" - "crypto/ecdsa" - "crypto/ed25519" - "crypto/rsa" - "crypto/x509" - "encoding/pem" - "errors" - "fmt" - "net" - "os" - "strings" - - circlSign "github.com/cloudflare/circl/sign" -) - -// Server returns a new TLS server side connection -// using conn as the underlying transport. -// The configuration config must be non-nil and must include -// at least one certificate or else set GetCertificate. -func Server(conn net.Conn, config *Config) *Conn { - c := &Conn{ - conn: conn, - config: config, - } - c.handshakeFn = c.serverHandshake - return c -} - -// Client returns a new TLS client side connection -// using conn as the underlying transport. -// The config cannot be nil: users must set either ServerName or -// InsecureSkipVerify in the config. -func Client(conn net.Conn, config *Config) *Conn { - c := &Conn{ - conn: conn, - config: config, - isClient: true, - } - c.handshakeFn = c.clientHandshake - return c -} - -// A listener implements a network listener (net.Listener) for TLS connections. -type listener struct { - net.Listener - config *Config -} - -// Accept waits for and returns the next incoming TLS connection. -// The returned connection is of type *Conn. -func (l *listener) Accept() (net.Conn, error) { - c, err := l.Listener.Accept() - if err != nil { - return nil, err - } - return Server(c, l.config), nil -} - -// NewListener creates a Listener which accepts connections from an inner -// Listener and wraps each connection with Server. -// The configuration config must be non-nil and must include -// at least one certificate or else set GetCertificate. -func NewListener(inner net.Listener, config *Config) net.Listener { - l := new(listener) - l.Listener = inner - l.config = config - return l -} - -// Listen creates a TLS listener accepting connections on the -// given network address using net.Listen. -// The configuration config must be non-nil and must include -// at least one certificate or else set GetCertificate. -func Listen(network, laddr string, config *Config) (net.Listener, error) { - if config == nil || len(config.Certificates) == 0 && - config.GetCertificate == nil && config.GetConfigForClient == nil { - return nil, errors.New("tls: neither Certificates, GetCertificate, nor GetConfigForClient set in Config") - } - l, err := net.Listen(network, laddr) - if err != nil { - return nil, err - } - return NewListener(l, config), nil -} - -type timeoutError struct{} - -func (timeoutError) Error() string { return "tls: DialWithDialer timed out" } -func (timeoutError) Timeout() bool { return true } -func (timeoutError) Temporary() bool { return true } - -// DialWithDialer connects to the given network address using dialer.Dial and -// then initiates a TLS handshake, returning the resulting TLS connection. Any -// timeout or deadline given in the dialer apply to connection and TLS -// handshake as a whole. -// -// DialWithDialer interprets a nil configuration as equivalent to the zero -// configuration; see the documentation of Config for the defaults. -// -// DialWithDialer uses context.Background internally; to specify the context, -// use Dialer.DialContext with NetDialer set to the desired dialer. -func DialWithDialer(dialer *net.Dialer, network, addr string, config *Config) (*Conn, error) { - return dial(context.Background(), dialer, network, addr, config) -} - -func dial(ctx context.Context, netDialer *net.Dialer, network, addr string, config *Config) (*Conn, error) { - if netDialer.Timeout != 0 { - var cancel context.CancelFunc - ctx, cancel = context.WithTimeout(ctx, netDialer.Timeout) - defer cancel() - } - - if !netDialer.Deadline.IsZero() { - var cancel context.CancelFunc - ctx, cancel = context.WithDeadline(ctx, netDialer.Deadline) - defer cancel() - } - - rawConn, err := netDialer.DialContext(ctx, network, addr) - if err != nil { - return nil, err - } - - colonPos := strings.LastIndex(addr, ":") - if colonPos == -1 { - colonPos = len(addr) - } - hostname := addr[:colonPos] - - if config == nil { - config = defaultConfig() - } - // If no ServerName is set, infer the ServerName - // from the hostname we're connecting to. - if config.ServerName == "" { - // Make a copy to avoid polluting argument or default. - c := config.Clone() - c.ServerName = hostname - config = c - } - - conn := Client(rawConn, config) - if err := conn.HandshakeContext(ctx); err != nil { - rawConn.Close() - return nil, err - } - return conn, nil -} - -// Dial connects to the given network address using net.Dial -// and then initiates a TLS handshake, returning the resulting -// TLS connection. -// Dial interprets a nil configuration as equivalent to -// the zero configuration; see the documentation of Config -// for the defaults. -func Dial(network, addr string, config *Config) (*Conn, error) { - return DialWithDialer(new(net.Dialer), network, addr, config) -} - -// Dialer dials TLS connections given a configuration and a Dialer for the -// underlying connection. -type Dialer struct { - // NetDialer is the optional dialer to use for the TLS connections' - // underlying TCP connections. - // A nil NetDialer is equivalent to the net.Dialer zero value. - NetDialer *net.Dialer - - // Config is the TLS configuration to use for new connections. - // A nil configuration is equivalent to the zero - // configuration; see the documentation of Config for the - // defaults. - Config *Config -} - -// Dial connects to the given network address and initiates a TLS -// handshake, returning the resulting TLS connection. -// -// The returned Conn, if any, will always be of type *Conn. -// -// Dial uses context.Background internally; to specify the context, -// use DialContext. -func (d *Dialer) Dial(network, addr string) (net.Conn, error) { - return d.DialContext(context.Background(), network, addr) -} - -func (d *Dialer) netDialer() *net.Dialer { - if d.NetDialer != nil { - return d.NetDialer - } - return new(net.Dialer) -} - -// DialContext connects to the given network address and initiates a TLS -// handshake, returning the resulting TLS connection. -// -// The provided Context must be non-nil. If the context expires before -// the connection is complete, an error is returned. Once successfully -// connected, any expiration of the context will not affect the -// connection. -// -// The returned Conn, if any, will always be of type *Conn. -func (d *Dialer) DialContext(ctx context.Context, network, addr string) (net.Conn, error) { - c, err := dial(ctx, d.netDialer(), network, addr, d.Config) - if err != nil { - // Don't return c (a typed nil) in an interface. - return nil, err - } - return c, nil -} - -// LoadX509KeyPair reads and parses a public/private key pair from a pair -// of files. The files must contain PEM encoded data. The certificate file -// may contain intermediate certificates following the leaf certificate to -// form a certificate chain. On successful return, Certificate.Leaf will -// be nil because the parsed form of the certificate is not retained. -func LoadX509KeyPair(certFile, keyFile string) (Certificate, error) { - certPEMBlock, err := os.ReadFile(certFile) - if err != nil { - return Certificate{}, err - } - keyPEMBlock, err := os.ReadFile(keyFile) - if err != nil { - return Certificate{}, err - } - return X509KeyPair(certPEMBlock, keyPEMBlock) -} - -// X509KeyPair parses a public/private key pair from a pair of -// PEM encoded data. On successful return, Certificate.Leaf will be nil because -// the parsed form of the certificate is not retained. -func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (Certificate, error) { - fail := func(err error) (Certificate, error) { return Certificate{}, err } - - var cert Certificate - var skippedBlockTypes []string - for { - var certDERBlock *pem.Block - certDERBlock, certPEMBlock = pem.Decode(certPEMBlock) - if certDERBlock == nil { - break - } - if certDERBlock.Type == "CERTIFICATE" { - cert.Certificate = append(cert.Certificate, certDERBlock.Bytes) - } else { - skippedBlockTypes = append(skippedBlockTypes, certDERBlock.Type) - } - } - - if len(cert.Certificate) == 0 { - if len(skippedBlockTypes) == 0 { - return fail(errors.New("tls: failed to find any PEM data in certificate input")) - } - if len(skippedBlockTypes) == 1 && strings.HasSuffix(skippedBlockTypes[0], "PRIVATE KEY") { - return fail(errors.New("tls: failed to find certificate PEM data in certificate input, but did find a private key; PEM inputs may have been switched")) - } - return fail(fmt.Errorf("tls: failed to find \"CERTIFICATE\" PEM block in certificate input after skipping PEM blocks of the following types: %v", skippedBlockTypes)) - } - - skippedBlockTypes = skippedBlockTypes[:0] - var keyDERBlock *pem.Block - for { - keyDERBlock, keyPEMBlock = pem.Decode(keyPEMBlock) - if keyDERBlock == nil { - if len(skippedBlockTypes) == 0 { - return fail(errors.New("tls: failed to find any PEM data in key input")) - } - if len(skippedBlockTypes) == 1 && skippedBlockTypes[0] == "CERTIFICATE" { - return fail(errors.New("tls: found a certificate rather than a key in the PEM for the private key")) - } - return fail(fmt.Errorf("tls: failed to find PEM block with type ending in \"PRIVATE KEY\" in key input after skipping PEM blocks of the following types: %v", skippedBlockTypes)) - } - if keyDERBlock.Type == "PRIVATE KEY" || strings.HasSuffix(keyDERBlock.Type, " PRIVATE KEY") { - break - } - skippedBlockTypes = append(skippedBlockTypes, keyDERBlock.Type) - } - - // We don't need to parse the public key for TLS, but we so do anyway - // to check that it looks sane and matches the private key. - x509Cert, err := x509.ParseCertificate(cert.Certificate[0]) - if err != nil { - return fail(err) - } - - cert.PrivateKey, err = parsePrivateKey(keyDERBlock.Bytes) - if err != nil { - return fail(err) - } - - switch pub := x509Cert.PublicKey.(type) { - case *rsa.PublicKey: - priv, ok := cert.PrivateKey.(*rsa.PrivateKey) - if !ok { - return fail(errors.New("tls: private key type does not match public key type")) - } - if pub.N.Cmp(priv.N) != 0 { - return fail(errors.New("tls: private key does not match public key")) - } - case *ecdsa.PublicKey: - priv, ok := cert.PrivateKey.(*ecdsa.PrivateKey) - if !ok { - return fail(errors.New("tls: private key type does not match public key type")) - } - if pub.X.Cmp(priv.X) != 0 || pub.Y.Cmp(priv.Y) != 0 { - return fail(errors.New("tls: private key does not match public key")) - } - case ed25519.PublicKey: - priv, ok := cert.PrivateKey.(ed25519.PrivateKey) - if !ok { - return fail(errors.New("tls: private key type does not match public key type")) - } - if !bytes.Equal(priv.Public().(ed25519.PublicKey), pub) { - return fail(errors.New("tls: private key does not match public key")) - } - case circlSign.PublicKey: - priv, ok := cert.PrivateKey.(circlSign.PrivateKey) - if !ok { - return fail(errors.New("tls: private key type does not match public key type")) - } - pkBytes, err := priv.Public().(circlSign.PublicKey).MarshalBinary() - pkBytes2, err2 := pub.MarshalBinary() - - if err != nil || err2 != nil || !bytes.Equal(pkBytes, pkBytes2) { - return fail(errors.New("tls: private key does not match public key")) - } - default: - return fail(errors.New("tls: unknown public key algorithm")) - } - - return cert, nil -} - -// Attempt to parse the given private key DER block. OpenSSL 0.9.8 generates -// PKCS #1 private keys by default, while OpenSSL 1.0.0 generates PKCS #8 keys. -// OpenSSL ecparam generates SEC1 EC private keys for ECDSA. We try all three. -func parsePrivateKey(der []byte) (crypto.PrivateKey, error) { - if key, err := x509.ParsePKCS1PrivateKey(der); err == nil { - return key, nil - } - if key, err := x509.ParsePKCS8PrivateKey(der); err == nil { - switch key := key.(type) { - case *rsa.PrivateKey, *ecdsa.PrivateKey, ed25519.PrivateKey, circlSign.PrivateKey: - return key, nil - default: - return nil, errors.New("tls: found unknown private key type in PKCS#8 wrapping") - } - } - if key, err := x509.ParseECPrivateKey(der); err == nil { - return key, nil - } - - return nil, errors.New("tls: failed to parse private key") -} diff --git a/transport/cloudflaretls/tls_cf.go b/transport/cloudflaretls/tls_cf.go deleted file mode 100644 index ac83fa4b..00000000 --- a/transport/cloudflaretls/tls_cf.go +++ /dev/null @@ -1,241 +0,0 @@ -// Copyright 2021 Cloudflare, Inc. All rights reserved. Use of this source code -// is governed by a BSD-style license that can be found in the LICENSE file. - -package tls - -import ( - "time" - - circlPki "github.com/cloudflare/circl/pki" - circlSign "github.com/cloudflare/circl/sign" - "github.com/cloudflare/circl/sign/eddilithium3" -) - -const ( - // Constants for ECH status events. - echStatusBypassed = 1 + iota - echStatusInner - echStatusOuter -) - -// To add a signature scheme from Circl -// -// 1. make sure it implements TLSScheme and CertificateScheme, -// 2. follow the instructions in crypto/x509/x509_cf.go -// 3. add a signature to the iota in common.go -// 4. add row in the circlSchemes lists below - -var circlSchemes = [...]struct { - sigType uint8 - scheme circlSign.Scheme -}{ - {signatureEdDilithium3, eddilithium3.Scheme()}, -} - -func circlSchemeBySigType(sigType uint8) circlSign.Scheme { - for _, cs := range circlSchemes { - if cs.sigType == sigType { - return cs.scheme - } - } - return nil -} - -func sigTypeByCirclScheme(scheme circlSign.Scheme) uint8 { - for _, cs := range circlSchemes { - if cs.scheme == scheme { - return cs.sigType - } - } - return 0 -} - -var supportedSignatureAlgorithmsWithCircl []SignatureScheme - -// supportedSignatureAlgorithms returns enabled signature schemes. PQ signature -// schemes are only included when tls.Config#PQSignatureSchemesEnabled is set. -func (c *Config) supportedSignatureAlgorithms() []SignatureScheme { - if c != nil && c.PQSignatureSchemesEnabled { - return supportedSignatureAlgorithmsWithCircl - } - return supportedSignatureAlgorithms -} - -func init() { - supportedSignatureAlgorithmsWithCircl = append([]SignatureScheme{}, supportedSignatureAlgorithms...) - for _, cs := range circlSchemes { - supportedSignatureAlgorithmsWithCircl = append(supportedSignatureAlgorithmsWithCircl, - SignatureScheme(cs.scheme.(circlPki.TLSScheme).TLSIdentifier())) - } -} - -// CFEvent is a value emitted at various points in the handshake that is -// handled by the callback Config.CFEventHandler. -type CFEvent interface { - Name() string -} - -// CFEventTLS13ClientHandshakeTimingInfo carries intra-stack time durations for -// TLS 1.3 client-state machine changes. It can be used for tracking metrics -// during a connection. Some durations may be sensitive, such as the amount of -// time to process a particular handshake message, so this event should only be -// used for experimental purposes. -type CFEventTLS13ClientHandshakeTimingInfo struct { - timer func() time.Time - start time.Time - WriteClientHello time.Duration - ProcessServerHello time.Duration - ReadEncryptedExtensions time.Duration - ReadCertificate time.Duration - ReadCertificateVerify time.Duration - ReadServerFinished time.Duration - WriteCertificate time.Duration - WriteCertificateVerify time.Duration - WriteClientFinished time.Duration -} - -// Name is required by the CFEvent interface. -func (e CFEventTLS13ClientHandshakeTimingInfo) Name() string { - return "TLS13ClientHandshakeTimingInfo" -} - -func (e CFEventTLS13ClientHandshakeTimingInfo) elapsedTime() time.Duration { - if e.timer == nil { - return 0 - } - return e.timer().Sub(e.start) -} - -func createTLS13ClientHandshakeTimingInfo(timerFunc func() time.Time) CFEventTLS13ClientHandshakeTimingInfo { - timer := time.Now - if timerFunc != nil { - timer = timerFunc - } - - return CFEventTLS13ClientHandshakeTimingInfo{ - timer: timer, - start: timer(), - } -} - -// CFEventTLS13ServerHandshakeTimingInfo carries intra-stack time durations -// for TLS 1.3 state machine changes. It can be used for tracking metrics during a -// connection. Some durations may be sensitive, such as the amount of time to -// process a particular handshake message, so this event should only be used -// for experimental purposes. -type CFEventTLS13ServerHandshakeTimingInfo struct { - timer func() time.Time - start time.Time - ProcessClientHello time.Duration - WriteServerHello time.Duration - WriteEncryptedExtensions time.Duration - WriteCertificate time.Duration - WriteCertificateVerify time.Duration - WriteServerFinished time.Duration - ReadCertificate time.Duration - ReadCertificateVerify time.Duration - ReadClientFinished time.Duration -} - -// Name is required by the CFEvent interface. -func (e CFEventTLS13ServerHandshakeTimingInfo) Name() string { - return "TLS13ServerHandshakeTimingInfo" -} - -func (e CFEventTLS13ServerHandshakeTimingInfo) elapsedTime() time.Duration { - if e.timer == nil { - return 0 - } - return e.timer().Sub(e.start) -} - -func createTLS13ServerHandshakeTimingInfo(timerFunc func() time.Time) CFEventTLS13ServerHandshakeTimingInfo { - timer := time.Now - if timerFunc != nil { - timer = timerFunc - } - - return CFEventTLS13ServerHandshakeTimingInfo{ - timer: timer, - start: timer(), - } -} - -// CFEventECHClientStatus is emitted once it is known whether the client -// bypassed, offered, or greased ECH. -type CFEventECHClientStatus int - -// Bypassed returns true if the client bypassed ECH. -func (e CFEventECHClientStatus) Bypassed() bool { - return e == echStatusBypassed -} - -// Offered returns true if the client offered ECH. -func (e CFEventECHClientStatus) Offered() bool { - return e == echStatusInner -} - -// Greased returns true if the client greased ECH. -func (e CFEventECHClientStatus) Greased() bool { - return e == echStatusOuter -} - -// Name is required by the CFEvent interface. -func (e CFEventECHClientStatus) Name() string { - return "ech client status" -} - -// CFEventECHServerStatus is emitted once it is known whether the client -// bypassed, offered, or greased ECH. -type CFEventECHServerStatus int - -// Bypassed returns true if the client bypassed ECH. -func (e CFEventECHServerStatus) Bypassed() bool { - return e == echStatusBypassed -} - -// Accepted returns true if the client offered ECH. -func (e CFEventECHServerStatus) Accepted() bool { - return e == echStatusInner -} - -// Rejected returns true if the client greased ECH. -func (e CFEventECHServerStatus) Rejected() bool { - return e == echStatusOuter -} - -// Name is required by the CFEvent interface. -func (e CFEventECHServerStatus) Name() string { - return "ech server status" -} - -// CFEventECHPublicNameMismatch is emitted if the outer SNI does not match -// match the public name of the ECH configuration. Note that we do not record -// the outer SNI in order to avoid collecting this potentially sensitive data. -type CFEventECHPublicNameMismatch struct{} - -// Name is required by the CFEvent interface. -func (e CFEventECHPublicNameMismatch) Name() string { - return "ech public name does not match outer sni" -} - -// For backwards compatibility. -type CFEventTLS13NegotiatedKEX = CFEventTLSNegotiatedNamedKEX - -// CFEventTLSNegotiatedNamedKEX is emitted when a key agreement mechanism has been -// established that uses a named group. This includes all key agreements -// in TLSv1.3, but excludes RSA and DH in TLS 1.2 and earlier. -type CFEventTLSNegotiatedNamedKEX struct { - KEX CurveID -} - -func (e CFEventTLSNegotiatedNamedKEX) Name() string { - return "CFEventTLSNegotiatedNamedKEX" -} - -// CFEventTLS13HRR is emitted when a HRR is sent or received -type CFEventTLS13HRR struct{} - -func (e CFEventTLS13HRR) Name() string { - return "CFEventTLS13HRR" -}