如何在 TLS 侦听器中验证对等证书

How to verify peer certificates in TLS listener

我正在编写 TLS 侦听器并接受新连接。在继续之前,必须根据 SHA1 列表验证新连接。问题是 tls.Listen() returns 接口的侦听器 net.Listener。这意味着 Accept() 将产生 plain-jane net.Conn 而不是提供 ConnectionState().PeerCertificates.

tls.Conn

接受的 net.Conn 太基础了,但是当我转换为更具体的 *tls.Conn 类型时,我收到运行时异常。

package main

import (
    "crypto/tls"
    "fmt"
    "net"
)

type Service struct {
    listener net.Listener
}

func (serv *Service)Listen(port int64) (err error) {
    cert, err := tls.LoadX509KeyPair( "/etc/SCAMP/services/helloworld.crt","/etc/SCAMP/services/helloworld.key" )
    if err != nil {
        return
    }

    config := &tls.Config{
        Certificates: []tls.Certificate{ cert },
    }

    serv.listener,err = tls.Listen("tcp", "127.0.0.1:30101", config)
    if err != nil {
        return err
    }

    return
}

func (serv *Service)AcceptRequests() {
    for {
        netConn,_ := serv.listener.Accept()
        var tlsConn (*tls.Conn) = netConn.(*tls.Conn)

        certs := tlsConn.ConnectionState().PeerCertificates

        fmt.Printf("got certs: `%s`\n", certs)
    }
}

func main() {
    serv := new(Service)
    serv.Listen(30100)

    tlsConn, _ := tls.Dial("tcp","127.0.0.1:30101", &tls.Config{
        InsecureSkipVerify: true,
    })
    tlsConn.Write([]byte("hey"))
}

这样的错误:

panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xb code=0xffffffff addr=0x0 pc=0x78a77]

goroutine 1 [running]:
crypto/tls.(*Conn).Handshake(0x0, 0x1050a008, 0x0, 0x0)
    /usr/src/go/src/crypto/tls/conn.go:967 +0x317
crypto/tls.(*Conn).Write(0x0, 0x10538120, 0x3, 0x8, 0x0, 0x0, 0x0, 0xfefd2220)
    /usr/src/go/src/crypto/tls/conn.go:845 +0x80
main.main()
    /tmp/sandbox290881341/main.go:49 +0x1c0

goroutine 2 [runnable]:
runtime.forcegchelper()
    /usr/src/go/src/runtime/proc.go:90
runtime.goexit()
    /usr/src/go/src/runtime/asm_amd64p32.s:1086 +0x1

goroutine 3 [runnable]:
runtime.bgsweep()
    /usr/src/go/src/runtime/mgc0.go:82
runtime.goexit()
    /usr/src/go/src/runtime/asm_amd64p32.s:1086 +0x1

goroutine 4 [runnable]:
runtime.runfinq()
    /usr/src/go/src/runtime/malloc.go:712
runtime.goexit()
    /usr/src/go/src/runtime/asm_amd64p32.s:1086 +0x1

http://play.golang.org/p/gv7dy8XQ81

问题在于加载证书。这是一个工作示例,以防其他人偶然发现此示例。您确实可以从 Accept() 中检查证书(但据我所知,这在 TLS 中并不常见,您通常会从客户端检查证书,因为各个客户端不需要证书)。

package main

import (
    "crypto/tls"
    "fmt"
    "net"
    "time"
)

type Service struct {
    listener net.Listener
}

func (serv *Service)Listen(port int64) (err error) {
    rsaCertPEM := `-----BEGIN CERTIFICATE-----
MIIGKjCCBBKgAwIBAgIJAOaBs5/Gdk7RMA0GCSqGSIb3DQEBBQUAMGsxHzAdBgNV
BAMTFlhhdmllcnMtTUJQIGhlbGxvd29ybGQxEjAQBgNVBAoTCVNDQU1QIEluYzEL
MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVNhbiBE
aWVnbzAeFw0xNTA3MjcxNzMyNDNaFw0yNTA3MjQxNzMyNDNaMGsxHzAdBgNVBAMT
FlhhdmllcnMtTUJQIGhlbGxvd29ybGQxEjAQBgNVBAoTCVNDQU1QIEluYzELMAkG
A1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVNhbiBEaWVn
bzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAOMiK19vGbRH7Y40jC3E
B+r2NNeEO9BIB8umzAs0uh1hRxEWYgdYwOvmEeuUQgimHbJ7Neh8IKjUiD529Ir0
rxNwhmu3AxFJf5hBC9Ix5nO2oVjIPdCVX+1CL9BJvmYyRlV5cq5WukTeYuSLG/tB
h9fARwIhcR9HrjYYb6LtMUX0oIlHQytDRn9pM27TfoR6ad3dwZdRpf9kQH4x467d
rBiRvRnBx5JBCE/cpFg7fQtrsrurn6tmMR/WMpv8GU0dLGEMCs/Te1bwH3XHDwNZ
mLVukfIhyWU/hXNzbggar0wk3ZqJrEeDm8zQJ73ywhs4D8AY+UX3V+1SBah45U+f
S9fZi7yi8XoCuEHTZoYU3hVcSP3Yqx1aZS5D7rx2X+T5XrJxy8FHiRX1LEPWKzz+
3x3+s9UcCIFz9xlAm0tM6ZjzeOcXhadSd+zTNngfQcwOPbPbyTM4Z9RD2VDPtfvV
eqJ82ZOGVWWkBFElZV6I5idRDph4/eEvO1Ij02C6oJJbyfbXzuMAgGVch8oMd65S
mVLppAT2uiNYebWp2Q2TleShNiv7AhvnV0saEfuCtX6fsryzogOMsEXiK+EqAZ3c
QUT+9hdIrwGWEOcx4Dpm2Tzh2QDIzmPVKIJ/PHPZgVq/zkc03ThuSRGYiNgz0YY4
AWsPtAVVZafh3ZcnPjP8OocxAgMBAAGjgdAwgc0wHQYDVR0OBBYEFOePjJeN13Rm
AzPVb/Tcp8x1gGh6MIGdBgNVHSMEgZUwgZKAFOePjJeN13RmAzPVb/Tcp8x1gGh6
oW+kbTBrMR8wHQYDVQQDExZYYXZpZXJzLU1CUCBoZWxsb3dvcmxkMRIwEAYDVQQK
EwlTQ0FNUCBJbmMxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRIw
EAYDVQQHEwlTYW4gRGllZ2+CCQDmgbOfxnZO0TAMBgNVHRMEBTADAQH/MA0GCSqG
SIb3DQEBBQUAA4ICAQDTlOdkKl1VT+VleeORUU3vVfeNGmiWrd88v6JlUxdYBU2o
YfQgVzPijxy9EGdgdaw/BPI0ypMn/DQ5hOcAHtHWCn7hHnRGTM4GMqZ6TOwexUyh
W02QFdwnB5jKQ3HNokp43NnoxAxEFnd6m27O39unwbq49Tt16HfEeUXMbXQabV6I
fZy7YsulamH0M5eZ2qtX25BkuYV1d4PpnahKWGRRvdg9jEszMfksI/tmv8CDmCi4
3cOS2c6i86XF3Cx+SlNPhJ7YpQK8IVxE3xzRMCf2kiA2vdb7DhVz4N5ZBzZYX5qD
HkYdjTdj4I6jtdeeNKqrEMV2Q3/X2Mdp0jp8dcK8WO7jXSIBvo4GO5797ok5mbQT
om0xvBljFkkyTuWJLUJslg9N7IyXCYZXLXpUvm40J+fXMNnd6lGbygNSrKFyjdDX
x5r9XCAKmtRteZSVpknN1eE5Gl5naY6iZrxXeeNlCG8x6a2XaQM6/0/XhSEZnGog
XiiirE3s5xZnWVRqOwx7iihs9I4mdHNj9kFdsB3vPjlMfbiQl+GbLIaF16H+LFP2
ArBiqwKM5kOcA3kT0XMm1rvxHZrpEACGf2zRhuBlZRyP96KPp49A4FpVHjsYweI8
DkIeTJpAsCXxgqDCw0P8xfhM5gP/ILmWgOIGj0+E/8OTgL3J85Jg8rmIo86mSg==
-----END CERTIFICATE-----`

 var rsaKeyPEM = `-----BEGIN RSA PRIVATE KEY-----
MIIJKQIBAAKCAgEA4yIrX28ZtEftjjSMLcQH6vY014Q70EgHy6bMCzS6HWFHERZi
B1jA6+YR65RCCKYdsns16HwgqNSIPnb0ivSvE3CGa7cDEUl/mEEL0jHmc7ahWMg9
0JVf7UIv0Em+ZjJGVXlyrla6RN5i5Isb+0GH18BHAiFxH0euNhhvou0xRfSgiUdD
K0NGf2kzbtN+hHpp3d3Bl1Gl/2RAfjHjrt2sGJG9GcHHkkEIT9ykWDt9C2uyu6uf
q2YxH9Yym/wZTR0sYQwKz9N7VvAfdccPA1mYtW6R8iHJZT+Fc3NuCBqvTCTdmoms
R4ObzNAnvfLCGzgPwBj5RfdX7VIFqHjlT59L19mLvKLxegK4QdNmhhTeFVxI/dir
HVplLkPuvHZf5PlesnHLwUeJFfUsQ9YrPP7fHf6z1RwIgXP3GUCbS0zpmPN45xeF
p1J37NM2eB9BzA49s9vJMzhn1EPZUM+1+9V6onzZk4ZVZaQEUSVlXojmJ1EOmHj9
4S87UiPTYLqgklvJ9tfO4wCAZVyHygx3rlKZUumkBPa6I1h5tanZDZOV5KE2K/sC
G+dXSxoR+4K1fp+yvLOiA4ywReIr4SoBndxBRP72F0ivAZYQ5zHgOmbZPOHZAMjO
Y9Uogn88c9mBWr/ORzTdOG5JEZiI2DPRhjgBaw+0BVVlp+Hdlyc+M/w6hzECAwEA
AQKCAgEAvOnVo1m3yl+s8QM5uHL8luvSxZJBYZoXicYgng1r4zXesxKn1C54v3wr
WYKFbcYkmyepjcV4MJQdAb9U5CJhX8zOsNaWIZG9I3iuiVRhtcqn5j0eVNd44tCT
Di3XxA56u2r4/JI7+T3yiN4/FrrJbqSJKvd/rCGlf27Ro3Se7+1ofOWds2UQRLbO
RZZ4+10JorRn6SDK7WGH1q5ODkpnckP9QWgQQs/+RtZghtZrycz46ujzM88aer1g
eKa0sJPcLpeignsGcifkMsSu8v1Za0Yc84QwixrLN1xBn1H6jV14R6nMdeq78h0L
gQxhb9wwFXlwE0aHhmcbN6XeLFx06fCSskpu8AoBRC1acOEY1uiF3NVAdw3bILX+
jxUh0Qhsb3JoAAIPwqV3SDnqiQi40k8hv6MfCw3Xn6UhyYNHGQBn7cX7llSvo0wF
DvQd0dJHmfBXXldVnhruH2275aqu1qVbPlNmoA6+2gChfOPgSUO9xNQXYc0dvgbl
7UBX/MR8SJlawptb3pwfTv+fBioSodWwfhkbZ0TMVGwSFUHXDN/+VeHoZsafZIog
knyKeE587y4aDcaYsHYYgz/WLjGMfROeUoplZQoBLfis+nTVBA6gCUGOFKynB5/b
ZpoqXxfkroYClVpiDrbJlCzwjnb1CBC49m+fTC4meX4EhqL7ZLECggEBAPvFxenW
GRC6fe05fWJwNi47Qf49Ll2BXipeq9NZlL3Z1j4V/DTcB9xw9HvuilsY4Hy+jQZM
mNOw8xPcPQLZxuG5HKAkuy/YOzWfgQCthAM+9ewQfcg8yEGv4qUx+iMxbR67SW0n
oOK5xGEOyIhnyywhcuicJecoK/8m4mZXryJTZced9oAiGXziEVcPVYqe+JLAea8G
3fqvHQj5EF5IC7q9sohSqSvnILukFmhgdG5xDvNGcVwczw8EO/hzDGT7ZAT1EheA
r29bnn6rxDYWsatOUeXx7qLjPJcH1ZEoQF8YdWvUu4v0wHwIZRB+Ul0soMS1KvP8
RlT5VuspRkby8a0CggEBAObyfKlBWiZWMu4iLxySHoAvxuAVI/7UJI5SCwMLZOtZ
FvNumPfVAS9YdJNnV44en368b8Lk+oBahlrgssTTIHN6eFlS/b7okHlkb6O2ED0v
LingYZ8iELAxeBEhM0sLthjXV2GzshqGTLDSc/SbInKtIZKY9mwAEQn75WH1sGbX
GPixZpS64f3fzV5lXZSb39gx/YAKn6LlrM6pxrOKA947ZIYpCCx+2vVeYS2tWl23
iJaKCdy5GMKb/BOhBA08zWMYVmejB+hRtaFz1wcloDQJvyu3SL2mMV/mU3ERDG2R
+o6K9EEmMnB8xci40EOCMETDXxmeMGnsXQf5bEVeBBUCggEAHtw6CxR8FAnX35j5
XnSEn5wR1bjoEvwFb8oU454KVk76LLgDJvOFXybVQM+XU90zvvaYUJpY7TG2Scvo
Co5pC0fmU1bNPusRLtxzMoMSOFeiSyImWMHihfKqJDeBAolPZ8HrGR8PYFsG0CLA
v7+BLtKWxB5HoxLQecDpZUQAKoPwaMxa54/GcgE/wN0XTht4OnyvLZ343X5TX8Mv
l27bSTNxS7ZeGAyHfZh6Sqbv/o2LGJSc1n6Nfri1JRns/f+2XckwQ4M5fbvMLJif
P0X+1xGNhlLmPj7+MUD7k4RMh5t24RW9O0VvxoQ85w2kyNjsh8/xCOD2OfoqBj8T
5yRmLQKCAQBZA6Wg5xuEIz1GI87cyEURS1jwDbXuBn6AjIbKCZ5AR/pcoYg8HdFz
Gjj0h6RrlsoK4z6AdBlJV5rpdCnzSxz65X11kFNVPfZRk7Cj/QyNSJ4WbfGykEK2
ZprMn2tRxZXORVHcypIfPxxYGwWuhgzk/m4uPt7cCbqHipuDAluXh9iMInRTZySr
4ZMaix9ipCHHBp2auH2HH9dXYIDBurR695FrVG1eGRbz9AiovmRSMudmfpYGiSFO
ASlLt4gEQic3xq2nDGOD29qR/EAo9Qumgws4IlDbKC9nszL+JYAQy28zecNjSQGv
8aeaEgHTw14vYs5I5Xvrl7rT1AMzSWVxAoIBAQCaDhdF/OyysP5WuQYd3v0J1yBM
bYc3y+RxdzCHtdxor5fQvTAN0gtp1KhrCmfoYdW4yUnOQZ6YoRzllERcQyoD2tGm
nEWm5YXQU8WZBGvCNfcL2qAVKZ3g498NJ3NqFMW9u2O1OlCSTRzLYp5Hdsx/7kl/
rzuo3vqtgYQqUkWDps6gjGkr55ztZHMoV6wGH9nf8tD0kqk+U6zIzaxiDj0U8+nr
xtEY4RYeEg1LV1I+kKvhEXx2mlyw7EbHTBXsfr7NdW3i7jFGN+mYywEhAqTlxJds
/IIDg+agTUeg+vYYbPA9nAwlTU1nzkhE3x3Aix/YRrtM70xFEF1v/sg4Oot/
-----END RSA PRIVATE KEY-----`

    cert, err := tls.X509KeyPair([]byte(rsaCertPEM), []byte(rsaKeyPEM))

    config := &tls.Config{
        Certificates: []tls.Certificate{ cert },
    }

    serv.listener,err = tls.Listen("tcp", "127.0.0.1:30101", config)
    if err != nil {
        return err
    }

    return
}

func (serv *Service)AcceptRequests() {
    for {
        netConn,_ := serv.listener.Accept()
        var tlsConn (*tls.Conn) = netConn.(*tls.Conn)

        certs := tlsConn.ConnectionState().PeerCertificates

        fmt.Printf("got certs: `%s`\n", certs)
    }
}

func main() {
    serv := new(Service)
    err := serv.Listen(30100)
    if err != nil {
        fmt.Printf("go err: `%s`", err)
        return
    }
    go serv.AcceptRequests()

    time.Sleep(1)

    tlsConn, _ := tls.Dial("tcp","127.0.0.1:30101", &tls.Config{
        InsecureSkipVerify: true,
    })
    tlsConn.Write([]byte("hey"))
}