Skip to content

Instantly share code, notes, and snippets.

@kayrus
Last active October 21, 2022 13:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kayrus/096e129bd4f6a5cf9f41bff06c7eeb83 to your computer and use it in GitHub Desktop.
Save kayrus/096e129bd4f6a5cf9f41bff06c7eeb83 to your computer and use it in GitHub Desktop.
tls v1.3 client auth bug
package main
import (
"crypto/tls"
"crypto/x509"
"errors"
"io"
"log"
"net"
"os"
"sync"
)
const (
listenAddr = ":1025"
caCert = `-----BEGIN CERTIFICATE-----
MIIDbTCCAlWgAwIBAgIUVwNm5lbANEdm2vAdgvghqryM49gwDQYJKoZIhvcNAQEL
BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAgFw0yMjEwMjExMDIyNTVaGA8yMDUw
MDMwODEwMjI1NVowRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUx
ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcN
AQEBBQADggEPADCCAQoCggEBAJmqwNp4DPcK+APrULug5CsvOwmdFAtINUsVOXVC
3n3cVn0HVkBB5xEcFfw/2XM+4CY9HgQVYkxcQGnIH+54EYbBZdMf+JE/KmTinGIM
lSyweWlkH2vV+5X1qvmEKTXFnDnR3xH+X8yKhvmhq8jaLzSrIP7NWWVxaBwFCeiU
sRuwAckpyXhSADEtpNAWmual65zTLaWfwpzPU1Ho9eRQaJWRl74KkehtYQEAngcH
zTTyCgVD/ULa7EqNMWenQI7M0N7lytALLfbXMtYzPdYuZlffXxvoGVSrdSe5903H
bTmYSS32Rjnj+cAiZhGh7KiW82Pt5fqylff9vOo7x3Dq5OkCAwEAAaNTMFEwHQYD
VR0OBBYEFPIPJCcn8mekXQzKGGZQyrlEyypxMB8GA1UdIwQYMBaAFPIPJCcn8mek
XQzKGGZQyrlEyypxMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB
ACLhdtiLhFxBRczbFW74fYpMf44wBCgBmqotTJ7hww4DRvhAiZqGQTrYlcwufdVj
j2HInGixHPj3otxk03fZ8AMuixcPQX+hJJSR1cPLcbvI5l0QByXR/3phXc4OyaTO
F5LtFbsLmpMLWT0lEIzE5aya+YrSH5K664LaUrz4tGEcjvLdYDF/ygio9z14ebln
6bOGqp3QdlN9OXIgWePoSNhev+5oRIAuaXFTshl05eD///u1F0q02JfZAoawibCI
JRvsH79Mc88j6AUUMhTCqvusNIfFpVgXQP74Ykx1ftNcHBJUGbT1T6LuTbm8Rjax
ThtF6M/HK0OR3kCGJ87B/6g=
-----END CERTIFICATE-----`
srvCert = `-----BEGIN CERTIFICATE-----
MIIDETCCAfkCFAECsFNXgt6VOgMMnSTpM7hLDw49MA0GCSqGSIb3DQEBCwUAMEUx
CzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRl
cm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMjIxMDIxMTAyMzMzWhcNMjMxMDIxMTAy
MzMzWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UE
CgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEAyPMnCCmzh+E9b6gW4Gr5cknrWXA0JZOpdT6j2ThMRDpMAUwC
J480Y/RZ9tOR/LHf54SI34ROKpyS1jk4PTzKZg2jwwQCgqMlyFMEXt8AeydbCF8E
pNttIK6T/fCGdHq3SfuOVfaJNNG+trBiZjJQzsRFotuHFXEXzQ6kZ6tAuEbGLf5Z
fwXS6r0vKrBNHQWsZVdhfGQh0qzbDJFUdFpMtNiIMQsxZ8EVETOqyvgGs4yLsbP3
0IRL8Te7dc+oJhasd1nZWoKqx5v7nUY6JiJIx8HnrpHE4BnLCrzLJXMJeTF6KsQj
VplKYrPwzJZb2VH0sCwakWM3/4xOWNcUczMU1QIDAQABMA0GCSqGSIb3DQEBCwUA
A4IBAQBL9kOzZSCMGJW49d8ixh50+FKurKmNmxYNpWAywpxqAIj+lYrJvTfIhCth
xBO3FRE0K2yD2nFZn4SMwMNwjkU73u+7rkroCzts2o+hw3PZzAmLIF+Jn4yP/bfR
7mn+C1gBktBqRyImwwsK7CE62ekK6t74ZmBo7xa+ieHRsYT2d5+ntWGuXdYjIGKv
+sr2rnoAqj87fapOmFoF0vzLvgKyxa/pJR1YQa64LsKoboIHJB/xHSa6hHrjOr0/
PefwirsdmZvFOh9blI6wItCshdkv52pLqKjqBzIkvckuagQAHNlEusFHq2CW5ew7
a0bpzEdBaA834btqaeAIsV0RtxZU
-----END CERTIFICATE-----`
srvKey = `-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDI8ycIKbOH4T1v
qBbgavlySetZcDQlk6l1PqPZOExEOkwBTAInjzRj9Fn205H8sd/nhIjfhE4qnJLW
OTg9PMpmDaPDBAKCoyXIUwRe3wB7J1sIXwSk220grpP98IZ0erdJ+45V9ok00b62
sGJmMlDOxEWi24cVcRfNDqRnq0C4RsYt/ll/BdLqvS8qsE0dBaxlV2F8ZCHSrNsM
kVR0Wky02IgxCzFnwRURM6rK+AazjIuxs/fQhEvxN7t1z6gmFqx3WdlagqrHm/ud
RjomIkjHweeukcTgGcsKvMslcwl5MXoqxCNWmUpis/DMllvZUfSwLBqRYzf/jE5Y
1xRzMxTVAgMBAAECggEAHFW05kDDEODgwdLIzwImhEgKCIV6xOWqWl7nyaRXlLNH
rlMiZqOZtpJo8RXqGuCV+tZEWogUYYvMZKqS1Iey3msD8WaqV/NbS4DxN9NoBPWK
r4Z+aCSMobQcKA13WAtJtwPikRp/RFRi+O2sIk7r+AvS6eDcjlhxC7gJ1JhgOtt3
8bscD4J7INkGn4NxDbVUwMgEItTvR85a3FA0h2fU5Xw4qcOBS3xrjg26dkBu3mPi
pchnB3COysx4wXcTN+osJlwIebZX0cikyoQsGarC1fXFfscxtgIznNTk3tf7LL3g
iFcPOR5D9h7ofgSZQB5h1TJA4N76G+dmnhObqgGhjQKBgQDn1+HoHT8mo5sV6ISj
r5IaXwzVNyr4Nyuy8Sjt/srtbrbKFbTUMboZw9LokYMZfADhAmTQQbDMoTI1OojB
46rGMnqdV4xoTgKJCa0Qja7Ih7PDKGT2aaC3gsfb8jEnUPt35JUnnuRmIzEUnfnW
MIcxkSoLabY1zsmiI5DHBEI/+wKBgQDd4zoQErm32TRz1MVlTXjSNV1G9m9fm2df
7+KZ1Kc3PCC9vz/I60shBSY8iDfd3+a5Z3J7B8J0Ko9wvG5pg8nyuHE7WpAMyKZe
Z5RvmsEcHOlXSa5br2d+4LrLeJnk6EWZDbWMCxsOgvh/BSpvbAXMPzlL0f7e0Uh2
QgL27cFVbwKBgQDCqcYZsazbkZVe8Mul8H3ZPKO2xsqCfTho2ApIwp26fDJoPY+G
d3ZNudl1wu/zzuWiB/OD1RRQzKwue0ZmnfU+0xWW1PKkhZOlYoV4l64A28g4/crA
B3KVgu6yo4lX/KwYP8po6QXXKIdGS1qB2F87ZCqMSKdgSI+OXxRptg62TwKBgQCX
UCGEXICx0zll1C9YyeAe2a1mex+wPzXbwqbw6Ievrx1UyFsjFPIC7pQIq4wNjma1
AMqdA8mjlnKDGrzgz7KkBwuQwk2BqkNqFZCwGwSdu0mU8PYqKA+YAoDfyLqJ06vC
mAq6Gci1uLLlTAyIN04s3uCfx/Da2jVkD9gdtD0nmQKBgQCH1udMp9ciPhruDe3r
ZY+usGKWKKzK540m7YfLoGgyhlmy9K6Ez5QsXlYYsFXlceP63arJ/7UmyLYUmxxx
NQ6jOLn6gYfWWll4m8/n0NI3ij7XrDCccV6US0zX6D/IZIwYQfmyvblLFpok6Rtx
iYROpm24XSpv5/4Nmtza+TbKgg==
-----END PRIVATE KEY-----`
clientCert = `-----BEGIN CERTIFICATE-----
MIIDETCCAfkCFF8MC134iR9ul6JL/pmcmo5TdH9CMA0GCSqGSIb3DQEBCwUAMEUx
CzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRl
cm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMjIxMDIxMTA1MTQ2WhcNMjIxMDIxMTA1
MTQ2WjBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UE
CgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEAz1UeOZBl69tMPbJokG/a9QBrVqExWBuiwunzajHq9i6aQ/I3
/Nyn/EmYr4BDJlITSVKsWLuAp/tDl+LFS8ws0ufy0hy0nAnWaVFg4b4DlsUO2CgW
SciWf6VZD3q8wGSkOADzOne/KROPUykOycYcWqcETti5TPqvTYm3yd2YxLeMqje1
TQ821QzC5W7iH5kvpCDAxM8BfushAuF4wYJYQWlsuWAY+uxVvjMWK6uJaOYKiQOf
oWElnwjJu/ll9wAdt/VCkh3iNguxKSvO/sWAS2tUlb4aOIh11iM9h0+tNQXPqr4x
3WxAphp3qrKS3xnnNVwS6kEGOjyQ7MeZj3Z1kwIDAQABMA0GCSqGSIb3DQEBCwUA
A4IBAQAfm9rVN/ISlDnrZstDBODMvgVZoz4bxriqL95uSKqrEAEtQdvjTdIiopC7
xfJ0wnWdENL+7TiVjM0i01HX73RNgpM7fR+XwT1Gk9yWnTzvyKgk/59WEDAihxIO
nokCmy+BvWQhl+E05ZVWq4u4GBOXrC+6vc+SgiTBbvGy6l7zCQntEimAI40M6x08
SGoiUDy3H3t6OlL4QloAzbwwdhxquj969S0x2BrApzfh9r9GrUwjYw898lh7g3ER
U1T0+AhuI9TUcx6WgrYQDbYS0nI4hqTpXS9MfVpnWJHUcOiuRRHdcT1f52Uue5O6
Dz1++jEtjLi/5EeOxzu7xb9EwHSd
-----END CERTIFICATE-----`
clientKey = `-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDPVR45kGXr20w9
smiQb9r1AGtWoTFYG6LC6fNqMer2LppD8jf83Kf8SZivgEMmUhNJUqxYu4Cn+0OX
4sVLzCzS5/LSHLScCdZpUWDhvgOWxQ7YKBZJyJZ/pVkPerzAZKQ4APM6d78pE49T
KQ7JxhxapwRO2LlM+q9NibfJ3ZjEt4yqN7VNDzbVDMLlbuIfmS+kIMDEzwF+6yEC
4XjBglhBaWy5YBj67FW+MxYrq4lo5gqJA5+hYSWfCMm7+WX3AB239UKSHeI2C7Ep
K87+xYBLa1SVvho4iHXWIz2HT601Bc+qvjHdbECmGneqspLfGec1XBLqQQY6PJDs
x5mPdnWTAgMBAAECggEAHm1tfCE29ABBFiTit5/S0HX5SsNpTHbx0g0njgQ5aVu5
hBM+KDvx41Kht8/pCuysq+wYIwWRghWb++Rp9A/I3ELyHefckbHX56jrwPVz7WKK
JSrs6nMnsx//DAiFPu8GMrng+EmuokaemCPEadRLQPqV5URlHWkE5So68MM2slfB
wIW+juddu73qmV3KWDM8bFEXv9MM6qBavoJtAkWC92rqcDPxEg1QhOlh1Bbm/TAK
PinPEohHAM3rpXtGleKwww1854dOZY0H9M7YZWunlMqTaqi02mvpvnxacqIP8Y0x
/MylDszUJ+wnV7yCOJupaTP1olCD9Xq+j2NvWQH5IQKBgQDR4EF8/VkaevvILAMR
xohpEeYm3KZCesG5Te+bOtlxSmueTg/yOCMHwwSAqWB7OrMlU8DDHRBIN6mF1JEV
hiDLKuhJ7Lpdl07WsLrGDnFXQs82g19sMOrBGLG7taV+99DqhSRpMMIS2WLSIXO/
zDi9M8UKNRzCvm+oP0XzVd8gWwKBgQD85cNaarPpRXlqG6BqkM/rr9byQAbDcXg1
HKpwU1Qsuq5VH5rbfSWLCLS2eX199+0ssfxmitPiieVm105w4egJGHZtkrK7RKDr
PkoJMqgHl1Mg93vPv/F9vTpVE5uGq5UnUPgeE2iR29PTo6c3cUQEqp+HcwWKZAog
W0LCzLGFKQKBgQDFuQ45YL0HM4HtLXmez3lH83LufcWsr9W+a+wmRCUClGga9dQU
EEsATvv48plQvxZzPhpGNyVVxArTaFVe/8P5Y+z/aCSTc670l/7+BDFHUkvBQbcu
SE+Bp3AaNaE6ouGRb+nDqAnOlDqDWLyhnxZ9OT6SxULZPWwYB7Qw8V+KLQKBgQCU
WYObCnS3JhXu9H3JhWEydFe2i3BsPaeyIDqq4XbDNk8FiCCjGGppgJXhZKsEtebf
DRluXYmlnhZ/mVVeSmZ+z2bJKADIcZ2j4Uo00w5WRaJx+Dscxw+2HsaVGYdmHEjG
Y2zo16HDzhwYTivNDhhEVIJ4RjS91alLCb3D36dS4QKBgHiQIt0dL07WfBNtwUvy
COKyV6t5Qi3AwHGAlzUHEL96Eflv/6qK7r+34ALezSCZkqgBJiC+VRG0e2w3HlxG
iqdOa6i0bfH7Vi6tuiu39zJKMrABdBSs9yu2iTUC+h65/6JehVMZ3gelRJp3vWMV
vghzfjn9k1NJpZWCusI17Sng
-----END PRIVATE KEY-----`
)
var (
serverLog = log.New(os.Stderr, "SERVER: ", log.LstdFlags|log.Lmsgprefix|log.Lmicroseconds)
clientLog = log.New(os.Stderr, "CLIENT: ", log.LstdFlags|log.Lmsgprefix|log.Lmicroseconds)
)
func main() {
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM([]byte(caCert))
serverCert, err := tls.X509KeyPair([]byte(srvCert), []byte(srvKey))
if err != nil {
log.Fatal(err)
}
clientCert, err := tls.X509KeyPair([]byte(clientCert), []byte(clientKey))
if err != nil {
log.Fatal(err)
}
tlsConfig := &tls.Config{
MinVersion: tls.VersionTLS12,
ClientCAs: caCertPool,
ClientAuth: tls.VerifyClientCertIfGiven,
Certificates: []tls.Certificate{serverCert},
}
listener, err := tls.Listen("tcp", listenAddr, tlsConfig)
if err != nil {
log.Fatalf("Could not listen on %s: %v\n", listenAddr, err)
}
wg := sync.WaitGroup{}
// run TLS server
go func() {
for {
c, err := listener.Accept()
if err != nil {
if errors.Is(err, net.ErrClosed) {
return
}
serverLog.Printf("cannot accept: %v", err)
continue
}
wg.Add(1)
go func(c net.Conn) {
defer wg.Done()
if tlsConn, ok := c.(*tls.Conn); ok {
err := tlsConn.Handshake()
if err != nil {
serverLog.Printf("tls handshake failed: %v", err)
c.Close()
return
}
b, err := io.ReadAll(tlsConn)
if err != nil {
serverLog.Fatalf("tls read failed: %v", err)
}
serverLog.Printf("server read: %s", b)
} else {
serverLog.Fatalf("non TLS conn")
}
c.Close()
}(c)
}
}()
tests := []uint16{
tls.VersionTLS12,
tls.VersionTLS13,
}
for i, version := range tests {
clientLog.Printf("calling: TLSv1.%d", i+2)
err = tlsTest(version, []tls.Certificate{clientCert})
wg.Wait()
if err == nil {
clientLog.Fatalf("ERROR: server must return a handshake error")
}
}
if err := listener.Close(); err != nil && !errors.Is(err, net.ErrClosed) {
clientLog.Fatalf("failed to close listener: %v", err)
}
}
func tlsTest(tlsVersion uint16, cert []tls.Certificate) error {
tlsConfig := &tls.Config{
MinVersion: tlsVersion,
MaxVersion: tlsVersion,
Certificates: cert,
InsecureSkipVerify: true,
}
conn, err := net.Dial("tcp", listenAddr)
if err != nil {
return err
}
defer conn.Close()
tlsConn := tls.Client(conn, tlsConfig)
err = tlsConn.Handshake()
if err != nil {
clientLog.Printf("TLS client Handshake failed: %v", err)
}
return err
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment