diff options
| author | cvs2svn <admin@example.com> | 2019-11-19 19:57:05 +0000 |
|---|---|---|
| committer | cvs2svn <admin@example.com> | 2019-11-19 19:57:05 +0000 |
| commit | e9f9eb6198f1757b7c0dfef043fadf1fa8243022 (patch) | |
| tree | b5a648f6ccaf6c1cd9915ddb45503d1fccfeba0e /src/regress/lib/libtls/gotls | |
| parent | ab72e3a6f7e8d5c71bbba034410468781d5923b6 (diff) | |
| download | openbsd-bluhm_20191119.tar.gz openbsd-bluhm_20191119.tar.bz2 openbsd-bluhm_20191119.zip | |
This commit was manufactured by cvs2git to create tag 'bluhm_20191119'.bluhm_20191119
Diffstat (limited to 'src/regress/lib/libtls/gotls')
| -rw-r--r-- | src/regress/lib/libtls/gotls/Makefile | 18 | ||||
| -rw-r--r-- | src/regress/lib/libtls/gotls/tls.go | 351 | ||||
| -rw-r--r-- | src/regress/lib/libtls/gotls/tls_test.go | 429 |
3 files changed, 0 insertions, 798 deletions
diff --git a/src/regress/lib/libtls/gotls/Makefile b/src/regress/lib/libtls/gotls/Makefile deleted file mode 100644 index ceb9e5ab0a..0000000000 --- a/src/regress/lib/libtls/gotls/Makefile +++ /dev/null | |||
| @@ -1,18 +0,0 @@ | |||
| 1 | # $OpenBSD: Makefile,v 1.3 2019/04/24 22:45:54 bluhm Exp $ | ||
| 2 | |||
| 3 | .if ! (make(clean) || make(cleandir) || make(obj)) | ||
| 4 | GO_VERSION != sh -c "(go version) 2>/dev/null || true" | ||
| 5 | .endif | ||
| 6 | |||
| 7 | .if empty(GO_VERSION) | ||
| 8 | regress: | ||
| 9 | @echo package go is required for this regress | ||
| 10 | @echo SKIPPED | ||
| 11 | .endif | ||
| 12 | |||
| 13 | REGRESS_TARGETS=regress-gotls | ||
| 14 | |||
| 15 | regress-gotls: | ||
| 16 | cd ${.CURDIR} && go test -test.v . | ||
| 17 | |||
| 18 | .include <bsd.regress.mk> | ||
diff --git a/src/regress/lib/libtls/gotls/tls.go b/src/regress/lib/libtls/gotls/tls.go deleted file mode 100644 index dbd3b717b0..0000000000 --- a/src/regress/lib/libtls/gotls/tls.go +++ /dev/null | |||
| @@ -1,351 +0,0 @@ | |||
| 1 | // Package tls provides a Go interface to the libtls library. | ||
| 2 | package tls | ||
| 3 | |||
| 4 | /* | ||
| 5 | #cgo LDFLAGS: -ltls -lssl -lcrypto | ||
| 6 | |||
| 7 | #include <stdlib.h> | ||
| 8 | |||
| 9 | #include <tls.h> | ||
| 10 | |||
| 11 | typedef void *tls; | ||
| 12 | */ | ||
| 13 | import "C" | ||
| 14 | |||
| 15 | import ( | ||
| 16 | "errors" | ||
| 17 | "fmt" | ||
| 18 | "time" | ||
| 19 | "unsafe" | ||
| 20 | ) | ||
| 21 | |||
| 22 | var ( | ||
| 23 | errWantPollIn = errors.New("want poll in") | ||
| 24 | errWantPollOut = errors.New("want poll out") | ||
| 25 | ) | ||
| 26 | |||
| 27 | // ProtocolVersion represents a TLS protocol version. | ||
| 28 | type ProtocolVersion uint32 | ||
| 29 | |||
| 30 | // String returns the string representation of a protocol version. | ||
| 31 | func (pv ProtocolVersion) String() string { | ||
| 32 | name, ok := protocolNames[pv] | ||
| 33 | if !ok { | ||
| 34 | return fmt.Sprintf("unknown protocol version %x", uint32(pv)) | ||
| 35 | } | ||
| 36 | return name | ||
| 37 | } | ||
| 38 | |||
| 39 | const ( | ||
| 40 | ProtocolTLSv10 ProtocolVersion = C.TLS_PROTOCOL_TLSv1_0 | ||
| 41 | ProtocolTLSv11 ProtocolVersion = C.TLS_PROTOCOL_TLSv1_1 | ||
| 42 | ProtocolTLSv12 ProtocolVersion = C.TLS_PROTOCOL_TLSv1_2 | ||
| 43 | ProtocolsAll ProtocolVersion = C.TLS_PROTOCOLS_ALL | ||
| 44 | ) | ||
| 45 | |||
| 46 | var protocolNames = map[ProtocolVersion]string{ | ||
| 47 | ProtocolTLSv10: "TLSv1", | ||
| 48 | ProtocolTLSv11: "TLSv1.1", | ||
| 49 | ProtocolTLSv12: "TLSv1.2", | ||
| 50 | ProtocolsAll: "all", | ||
| 51 | } | ||
| 52 | |||
| 53 | // ProtocolVersionFromString returns the protocol version with the given name. | ||
| 54 | func ProtocolVersionFromString(version string) (ProtocolVersion, error) { | ||
| 55 | for proto, name := range protocolNames { | ||
| 56 | if version == name { | ||
| 57 | return proto, nil | ||
| 58 | } | ||
| 59 | } | ||
| 60 | return 0, fmt.Errorf("unknown protocol version %q", version) | ||
| 61 | } | ||
| 62 | |||
| 63 | // TLSConfig provides configuration options for a TLS context. | ||
| 64 | type TLSConfig struct { | ||
| 65 | tlsCfg *C.struct_tls_config | ||
| 66 | } | ||
| 67 | |||
| 68 | // TLS encapsulates the TLS context. | ||
| 69 | type TLS struct { | ||
| 70 | cfg *TLSConfig | ||
| 71 | ctx *C.struct_tls | ||
| 72 | } | ||
| 73 | |||
| 74 | // Init initialises the TLS library. | ||
| 75 | func Init() error { | ||
| 76 | if C.tls_init() != 0 { | ||
| 77 | return errors.New("initialisation failed") | ||
| 78 | } | ||
| 79 | return nil | ||
| 80 | } | ||
| 81 | |||
| 82 | // NewConfig returns a new TLS configuration. | ||
| 83 | func NewConfig() (*TLSConfig, error) { | ||
| 84 | cfg := C.tls_config_new() | ||
| 85 | if cfg == nil { | ||
| 86 | return nil, errors.New("failed to allocate config") | ||
| 87 | } | ||
| 88 | return &TLSConfig{ | ||
| 89 | tlsCfg: cfg, | ||
| 90 | }, nil | ||
| 91 | } | ||
| 92 | |||
| 93 | // Error returns the error message from the TLS configuration. | ||
| 94 | func (c *TLSConfig) Error() error { | ||
| 95 | if msg := C.tls_config_error(c.tlsCfg); msg != nil { | ||
| 96 | return errors.New(C.GoString(msg)) | ||
| 97 | } | ||
| 98 | return errors.New("unknown error") | ||
| 99 | } | ||
| 100 | |||
| 101 | // SetCAFile sets the CA file to be used for connections. | ||
| 102 | func (c *TLSConfig) SetCAFile(filename string) error { | ||
| 103 | caFile := C.CString(filename) | ||
| 104 | defer C.free(unsafe.Pointer(caFile)) | ||
| 105 | if C.tls_config_set_ca_file(c.tlsCfg, caFile) != 0 { | ||
| 106 | return c.Error() | ||
| 107 | } | ||
| 108 | return nil | ||
| 109 | } | ||
| 110 | |||
| 111 | // SetCiphers sets the cipher suites enabled for the connection. | ||
| 112 | func (c *TLSConfig) SetCiphers(ciphers string) error { | ||
| 113 | cipherStr := C.CString(ciphers) | ||
| 114 | defer C.free(unsafe.Pointer(cipherStr)) | ||
| 115 | if C.tls_config_set_ciphers(c.tlsCfg, cipherStr) != 0 { | ||
| 116 | return c.Error() | ||
| 117 | } | ||
| 118 | return nil | ||
| 119 | } | ||
| 120 | |||
| 121 | // SetProtocols sets the protocol versions enabled for the connection. | ||
| 122 | func (c *TLSConfig) SetProtocols(proto ProtocolVersion) error { | ||
| 123 | if C.tls_config_set_protocols(c.tlsCfg, C.uint32_t(proto)) != 0 { | ||
| 124 | return c.Error() | ||
| 125 | } | ||
| 126 | return nil | ||
| 127 | } | ||
| 128 | |||
| 129 | // InsecureNoVerifyCert disables certificate verification for the connection. | ||
| 130 | func (c *TLSConfig) InsecureNoVerifyCert() { | ||
| 131 | C.tls_config_insecure_noverifycert(c.tlsCfg) | ||
| 132 | } | ||
| 133 | |||
| 134 | // InsecureNoVerifyName disables server name verification for the connection. | ||
| 135 | func (c *TLSConfig) InsecureNoVerifyName() { | ||
| 136 | C.tls_config_insecure_noverifyname(c.tlsCfg) | ||
| 137 | } | ||
| 138 | |||
| 139 | // SetSecure enables verification for the connection. | ||
| 140 | func (c *TLSConfig) SetVerify() { | ||
| 141 | C.tls_config_verify(c.tlsCfg) | ||
| 142 | } | ||
| 143 | |||
| 144 | // Free frees resources associated with the TLS configuration. | ||
| 145 | func (c *TLSConfig) Free() { | ||
| 146 | if c.tlsCfg == nil { | ||
| 147 | return | ||
| 148 | } | ||
| 149 | C.tls_config_free(c.tlsCfg) | ||
| 150 | c.tlsCfg = nil | ||
| 151 | } | ||
| 152 | |||
| 153 | // NewClient returns a new TLS client context, using the optional configuration. | ||
| 154 | // If no configuration is specified the default configuration will be used. | ||
| 155 | func NewClient(config *TLSConfig) (*TLS, error) { | ||
| 156 | var sslCfg *C.struct_tls_config | ||
| 157 | if config != nil { | ||
| 158 | sslCfg = config.tlsCfg | ||
| 159 | } | ||
| 160 | ctx := C.tls_client() | ||
| 161 | if ctx == nil { | ||
| 162 | return nil, errors.New("tls client failed") | ||
| 163 | } | ||
| 164 | if C.tls_configure(ctx, sslCfg) != 0 { | ||
| 165 | return nil, errors.New("tls configure failed") | ||
| 166 | } | ||
| 167 | return &TLS{ | ||
| 168 | cfg: config, | ||
| 169 | ctx: ctx, | ||
| 170 | }, nil | ||
| 171 | } | ||
| 172 | |||
| 173 | // Error returns the error message from the TLS context. | ||
| 174 | func (t *TLS) Error() error { | ||
| 175 | if msg := C.tls_error(t.ctx); msg != nil { | ||
| 176 | return errors.New(C.GoString(msg)) | ||
| 177 | } | ||
| 178 | return errors.New("unknown error") | ||
| 179 | } | ||
| 180 | |||
| 181 | // PeerCertProvided returns whether the peer provided a certificate. | ||
| 182 | func (t *TLS) PeerCertProvided() bool { | ||
| 183 | return C.tls_peer_cert_provided(t.ctx) == 1 | ||
| 184 | } | ||
| 185 | |||
| 186 | // PeerCertContainsName checks whether the peer certificate contains | ||
| 187 | // the specified name. | ||
| 188 | func (t *TLS) PeerCertContainsName(name string) bool { | ||
| 189 | n := C.CString(name) | ||
| 190 | defer C.free(unsafe.Pointer(n)) | ||
| 191 | return C.tls_peer_cert_contains_name(t.ctx, n) == 1 | ||
| 192 | } | ||
| 193 | |||
| 194 | // PeerCertIssuer returns the issuer of the peer certificate. | ||
| 195 | func (t *TLS) PeerCertIssuer() (string, error) { | ||
| 196 | issuer := C.tls_peer_cert_issuer(t.ctx) | ||
| 197 | if issuer == nil { | ||
| 198 | return "", errors.New("no issuer returned") | ||
| 199 | } | ||
| 200 | return C.GoString(issuer), nil | ||
| 201 | } | ||
| 202 | |||
| 203 | // PeerCertSubject returns the subject of the peer certificate. | ||
| 204 | func (t *TLS) PeerCertSubject() (string, error) { | ||
| 205 | subject := C.tls_peer_cert_subject(t.ctx) | ||
| 206 | if subject == nil { | ||
| 207 | return "", errors.New("no subject returned") | ||
| 208 | } | ||
| 209 | return C.GoString(subject), nil | ||
| 210 | } | ||
| 211 | |||
| 212 | // PeerCertHash returns a hash of the peer certificate. | ||
| 213 | func (t *TLS) PeerCertHash() (string, error) { | ||
| 214 | hash := C.tls_peer_cert_hash(t.ctx) | ||
| 215 | if hash == nil { | ||
| 216 | return "", errors.New("no hash returned") | ||
| 217 | } | ||
| 218 | return C.GoString(hash), nil | ||
| 219 | } | ||
| 220 | |||
| 221 | // PeerCertNotBefore returns the notBefore time from the peer | ||
| 222 | // certificate. | ||
| 223 | func (t *TLS) PeerCertNotBefore() (time.Time, error) { | ||
| 224 | notBefore := C.tls_peer_cert_notbefore(t.ctx) | ||
| 225 | if notBefore == -1 { | ||
| 226 | return time.Time{}, errors.New("no notBefore time returned") | ||
| 227 | } | ||
| 228 | return time.Unix(int64(notBefore), 0), nil | ||
| 229 | } | ||
| 230 | |||
| 231 | // PeerCertNotAfter returns the notAfter time from the peer | ||
| 232 | // certificate. | ||
| 233 | func (t *TLS) PeerCertNotAfter() (time.Time, error) { | ||
| 234 | notAfter := C.tls_peer_cert_notafter(t.ctx) | ||
| 235 | if notAfter == -1 { | ||
| 236 | return time.Time{}, errors.New("no notAfter time") | ||
| 237 | } | ||
| 238 | return time.Unix(int64(notAfter), 0), nil | ||
| 239 | } | ||
| 240 | |||
| 241 | // ConnVersion returns the protocol version of the connection. | ||
| 242 | func (t *TLS) ConnVersion() (ProtocolVersion, error) { | ||
| 243 | ver := C.tls_conn_version(t.ctx) | ||
| 244 | if ver == nil { | ||
| 245 | return 0, errors.New("no connection version") | ||
| 246 | } | ||
| 247 | return ProtocolVersionFromString(C.GoString(ver)) | ||
| 248 | } | ||
| 249 | |||
| 250 | // ConnCipher returns the cipher suite used for the connection. | ||
| 251 | func (t *TLS) ConnCipher() (string, error) { | ||
| 252 | cipher := C.tls_conn_cipher(t.ctx) | ||
| 253 | if cipher == nil { | ||
| 254 | return "", errors.New("no connection cipher") | ||
| 255 | } | ||
| 256 | return C.GoString(cipher), nil | ||
| 257 | } | ||
| 258 | |||
| 259 | // ConnCipherStrength returns the strength in bits for the symmetric | ||
| 260 | // cipher that is used for the connection. | ||
| 261 | func (t *TLS) ConnCipherStrength() (int, error) { | ||
| 262 | strength := C.tls_conn_cipher_strength(t.ctx) | ||
| 263 | if strength == 0 { | ||
| 264 | return 0, errors.New("no connection cipher strength") | ||
| 265 | } | ||
| 266 | return int(strength), nil | ||
| 267 | } | ||
| 268 | |||
| 269 | // Connect attempts to establish an TLS connection to the specified host on | ||
| 270 | // the given port. The host may optionally contain a colon separated port | ||
| 271 | // value if the port string is specified as an empty string. | ||
| 272 | func (t *TLS) Connect(host, port string) error { | ||
| 273 | h := C.CString(host) | ||
| 274 | var p *C.char | ||
| 275 | if port != "" { | ||
| 276 | p = C.CString(port) | ||
| 277 | } | ||
| 278 | defer C.free(unsafe.Pointer(h)) | ||
| 279 | defer C.free(unsafe.Pointer(p)) | ||
| 280 | if C.tls_connect(t.ctx, h, p) != 0 { | ||
| 281 | return t.Error() | ||
| 282 | } | ||
| 283 | return nil | ||
| 284 | } | ||
| 285 | |||
| 286 | // Handshake attempts to complete the TLS handshake. | ||
| 287 | func (t *TLS) Handshake() error { | ||
| 288 | ret := C.tls_handshake(t.ctx) | ||
| 289 | switch { | ||
| 290 | case ret == C.TLS_WANT_POLLIN: | ||
| 291 | return errWantPollIn | ||
| 292 | case ret == C.TLS_WANT_POLLOUT: | ||
| 293 | return errWantPollOut | ||
| 294 | case ret != 0: | ||
| 295 | return t.Error() | ||
| 296 | } | ||
| 297 | return nil | ||
| 298 | } | ||
| 299 | |||
| 300 | // Read reads data the TLS connection into the given buffer. | ||
| 301 | func (t *TLS) Read(buf []byte) (int, error) { | ||
| 302 | ret := C.tls_read(t.ctx, unsafe.Pointer(&buf[0]), C.size_t(len(buf))) | ||
| 303 | switch { | ||
| 304 | case ret == C.TLS_WANT_POLLIN: | ||
| 305 | return -1, errWantPollIn | ||
| 306 | case ret == C.TLS_WANT_POLLOUT: | ||
| 307 | return -1, errWantPollOut | ||
| 308 | case ret < 0: | ||
| 309 | return -1, t.Error() | ||
| 310 | } | ||
| 311 | return int(ret), nil | ||
| 312 | } | ||
| 313 | |||
| 314 | // Write writes the given data to the TLS connection. | ||
| 315 | func (t *TLS) Write(buf []byte) (int, error) { | ||
| 316 | p := C.CString(string(buf)) | ||
| 317 | defer C.free(unsafe.Pointer(p)) | ||
| 318 | ret := C.tls_write(t.ctx, unsafe.Pointer(p), C.size_t(len(buf))) | ||
| 319 | switch { | ||
| 320 | case ret == C.TLS_WANT_POLLIN: | ||
| 321 | return -1, errWantPollIn | ||
| 322 | case ret == C.TLS_WANT_POLLOUT: | ||
| 323 | return -1, errWantPollOut | ||
| 324 | case ret < 0: | ||
| 325 | return -1, t.Error() | ||
| 326 | } | ||
| 327 | return int(ret), nil | ||
| 328 | } | ||
| 329 | |||
| 330 | // Close closes the TLS connection. | ||
| 331 | func (t *TLS) Close() error { | ||
| 332 | ret := C.tls_close(t.ctx) | ||
| 333 | switch { | ||
| 334 | case ret == C.TLS_WANT_POLLIN: | ||
| 335 | return errWantPollIn | ||
| 336 | case ret == C.TLS_WANT_POLLOUT: | ||
| 337 | return errWantPollOut | ||
| 338 | case ret != 0: | ||
| 339 | return t.Error() | ||
| 340 | } | ||
| 341 | return nil | ||
| 342 | } | ||
| 343 | |||
| 344 | // Free frees resources associated with the TLS context. | ||
| 345 | func (t *TLS) Free() { | ||
| 346 | if t.ctx == nil { | ||
| 347 | return | ||
| 348 | } | ||
| 349 | C.tls_free(t.ctx) | ||
| 350 | t.ctx = nil | ||
| 351 | } | ||
diff --git a/src/regress/lib/libtls/gotls/tls_test.go b/src/regress/lib/libtls/gotls/tls_test.go deleted file mode 100644 index 1a9f62eff8..0000000000 --- a/src/regress/lib/libtls/gotls/tls_test.go +++ /dev/null | |||
| @@ -1,429 +0,0 @@ | |||
| 1 | package tls | ||
| 2 | |||
| 3 | import ( | ||
| 4 | "crypto/tls" | ||
| 5 | "encoding/pem" | ||
| 6 | "fmt" | ||
| 7 | "io/ioutil" | ||
| 8 | "net/http" | ||
| 9 | "net/http/httptest" | ||
| 10 | "net/url" | ||
| 11 | "os" | ||
| 12 | "strings" | ||
| 13 | "testing" | ||
| 14 | "time" | ||
| 15 | ) | ||
| 16 | |||
| 17 | const ( | ||
| 18 | httpContent = "Hello, TLS!" | ||
| 19 | |||
| 20 | certHash = "SHA256:448f628a8a65aa18560e53a80c53acb38c51b427df0334082349141147dc9bf6" | ||
| 21 | ) | ||
| 22 | |||
| 23 | var ( | ||
| 24 | certNotBefore = time.Unix(0, 0) | ||
| 25 | certNotAfter = certNotBefore.Add(1000000 * time.Hour) | ||
| 26 | ) | ||
| 27 | |||
| 28 | type handshakeError string | ||
| 29 | |||
| 30 | func (he handshakeError) Error() string { | ||
| 31 | return string(he) | ||
| 32 | } | ||
| 33 | |||
| 34 | // createCAFile writes a PEM encoded version of the certificate out to a | ||
| 35 | // temporary file, for use by libtls. | ||
| 36 | func createCAFile(cert []byte) (string, error) { | ||
| 37 | f, err := ioutil.TempFile("", "tls") | ||
| 38 | if err != nil { | ||
| 39 | return "", fmt.Errorf("failed to create file: %v", err) | ||
| 40 | } | ||
| 41 | defer f.Close() | ||
| 42 | block := &pem.Block{ | ||
| 43 | Type: "CERTIFICATE", | ||
| 44 | Bytes: cert, | ||
| 45 | } | ||
| 46 | if err := pem.Encode(f, block); err != nil { | ||
| 47 | return "", fmt.Errorf("failed to encode certificate: %v", err) | ||
| 48 | } | ||
| 49 | return f.Name(), nil | ||
| 50 | } | ||
| 51 | |||
| 52 | func newTestServer(tlsCfg *tls.Config) (*httptest.Server, *url.URL, string, error) { | ||
| 53 | ts := httptest.NewUnstartedServer( | ||
| 54 | http.HandlerFunc( | ||
| 55 | func(w http.ResponseWriter, r *http.Request) { | ||
| 56 | fmt.Fprintln(w, httpContent) | ||
| 57 | }, | ||
| 58 | ), | ||
| 59 | ) | ||
| 60 | ts.TLS = tlsCfg | ||
| 61 | ts.StartTLS() | ||
| 62 | |||
| 63 | u, err := url.Parse(ts.URL) | ||
| 64 | if err != nil { | ||
| 65 | return nil, nil, "", fmt.Errorf("failed to parse URL %q: %v", ts.URL, err) | ||
| 66 | } | ||
| 67 | |||
| 68 | caFile, err := createCAFile(ts.TLS.Certificates[0].Certificate[0]) | ||
| 69 | if err != nil { | ||
| 70 | return nil, nil, "", fmt.Errorf("failed to create CA file: %v", err) | ||
| 71 | } | ||
| 72 | |||
| 73 | return ts, u, caFile, nil | ||
| 74 | } | ||
| 75 | |||
| 76 | func handshakeVersionTest(tlsCfg *tls.Config) (ProtocolVersion, error) { | ||
| 77 | ts, u, caFile, err := newTestServer(tlsCfg) | ||
| 78 | if err != nil { | ||
| 79 | return 0, fmt.Errorf("failed to start test server: %v", err) | ||
| 80 | } | ||
| 81 | defer os.Remove(caFile) | ||
| 82 | defer ts.Close() | ||
| 83 | |||
| 84 | if err := Init(); err != nil { | ||
| 85 | return 0, err | ||
| 86 | } | ||
| 87 | |||
| 88 | cfg, err := NewConfig() | ||
| 89 | if err != nil { | ||
| 90 | return 0, err | ||
| 91 | } | ||
| 92 | defer cfg.Free() | ||
| 93 | if err := cfg.SetCAFile(caFile); err != nil { | ||
| 94 | return 0, err | ||
| 95 | } | ||
| 96 | if err := cfg.SetCiphers("compat"); err != nil { | ||
| 97 | return 0, err | ||
| 98 | } | ||
| 99 | if err := cfg.SetProtocols(ProtocolsAll); err != nil { | ||
| 100 | return 0, err | ||
| 101 | } | ||
| 102 | |||
| 103 | tls, err := NewClient(cfg) | ||
| 104 | if err != nil { | ||
| 105 | return 0, err | ||
| 106 | } | ||
| 107 | defer tls.Free() | ||
| 108 | |||
| 109 | if err := tls.Connect(u.Host, ""); err != nil { | ||
| 110 | return 0, err | ||
| 111 | } | ||
| 112 | if err := tls.Handshake(); err != nil { | ||
| 113 | return 0, handshakeError(err.Error()) | ||
| 114 | } | ||
| 115 | version, err := tls.ConnVersion() | ||
| 116 | if err != nil { | ||
| 117 | return 0, err | ||
| 118 | } | ||
| 119 | if err := tls.Close(); err != nil { | ||
| 120 | return 0, err | ||
| 121 | } | ||
| 122 | return version, nil | ||
| 123 | } | ||
| 124 | |||
| 125 | func TestTLSBasic(t *testing.T) { | ||
| 126 | ts, u, caFile, err := newTestServer(nil) | ||
| 127 | if err != nil { | ||
| 128 | t.Fatalf("Failed to start test server: %v", err) | ||
| 129 | } | ||
| 130 | defer os.Remove(caFile) | ||
| 131 | defer ts.Close() | ||
| 132 | |||
| 133 | if err := Init(); err != nil { | ||
| 134 | t.Fatal(err) | ||
| 135 | } | ||
| 136 | |||
| 137 | cfg, err := NewConfig() | ||
| 138 | if err != nil { | ||
| 139 | t.Fatal(err) | ||
| 140 | } | ||
| 141 | defer cfg.Free() | ||
| 142 | if err := cfg.SetCAFile(caFile); err != nil { | ||
| 143 | t.Fatal(err) | ||
| 144 | } | ||
| 145 | |||
| 146 | tls, err := NewClient(cfg) | ||
| 147 | if err != nil { | ||
| 148 | t.Fatal(err) | ||
| 149 | } | ||
| 150 | defer tls.Free() | ||
| 151 | |||
| 152 | t.Logf("Connecting to %s", u.Host) | ||
| 153 | |||
| 154 | if err := tls.Connect(u.Host, ""); err != nil { | ||
| 155 | t.Fatal(err) | ||
| 156 | } | ||
| 157 | defer func() { | ||
| 158 | if err := tls.Close(); err != nil { | ||
| 159 | t.Fatalf("Close failed: %v", err) | ||
| 160 | } | ||
| 161 | }() | ||
| 162 | |||
| 163 | n, err := tls.Write([]byte("GET / HTTP/1.0\n\n")) | ||
| 164 | if err != nil { | ||
| 165 | t.Fatal(err) | ||
| 166 | } | ||
| 167 | t.Logf("Wrote %d bytes...", n) | ||
| 168 | |||
| 169 | buf := make([]byte, 1024) | ||
| 170 | n, err = tls.Read(buf) | ||
| 171 | if err != nil { | ||
| 172 | t.Fatal(err) | ||
| 173 | } | ||
| 174 | t.Logf("Read %d bytes...", n) | ||
| 175 | |||
| 176 | if !strings.Contains(string(buf), httpContent) { | ||
| 177 | t.Errorf("Response does not contain %q", httpContent) | ||
| 178 | } | ||
| 179 | } | ||
| 180 | |||
| 181 | func TestTLSVersions(t *testing.T) { | ||
| 182 | tests := []struct { | ||
| 183 | minVersion uint16 | ||
| 184 | maxVersion uint16 | ||
| 185 | wantVersion ProtocolVersion | ||
| 186 | wantHandshakeErr bool | ||
| 187 | }{ | ||
| 188 | {tls.VersionSSL30, tls.VersionTLS12, ProtocolTLSv12, false}, | ||
| 189 | {tls.VersionTLS10, tls.VersionTLS12, ProtocolTLSv12, false}, | ||
| 190 | {tls.VersionTLS11, tls.VersionTLS12, ProtocolTLSv12, false}, | ||
| 191 | {tls.VersionSSL30, tls.VersionTLS11, ProtocolTLSv11, false}, | ||
| 192 | {tls.VersionSSL30, tls.VersionTLS10, ProtocolTLSv10, false}, | ||
| 193 | {tls.VersionSSL30, tls.VersionSSL30, 0, true}, | ||
| 194 | {tls.VersionTLS10, tls.VersionTLS10, ProtocolTLSv10, false}, | ||
| 195 | {tls.VersionTLS11, tls.VersionTLS11, ProtocolTLSv11, false}, | ||
| 196 | {tls.VersionTLS12, tls.VersionTLS12, ProtocolTLSv12, false}, | ||
| 197 | } | ||
| 198 | for i, test := range tests { | ||
| 199 | t.Logf("Testing handshake with protocols %x:%x", test.minVersion, test.maxVersion) | ||
| 200 | tlsCfg := &tls.Config{ | ||
| 201 | MinVersion: test.minVersion, | ||
| 202 | MaxVersion: test.maxVersion, | ||
| 203 | } | ||
| 204 | version, err := handshakeVersionTest(tlsCfg) | ||
| 205 | switch { | ||
| 206 | case test.wantHandshakeErr && err == nil: | ||
| 207 | t.Errorf("Test %d - handshake %x:%x succeeded, want handshake error", | ||
| 208 | i, test.minVersion, test.maxVersion) | ||
| 209 | case test.wantHandshakeErr && err != nil: | ||
| 210 | if _, ok := err.(handshakeError); !ok { | ||
| 211 | t.Errorf("Test %d - handshake %x:%x; got unknown error, want handshake error: %v", | ||
| 212 | i, test.minVersion, test.maxVersion, err) | ||
| 213 | } | ||
| 214 | case !test.wantHandshakeErr && err != nil: | ||
| 215 | t.Errorf("Test %d - handshake %x:%x failed: %v", i, test.minVersion, test.maxVersion, err) | ||
| 216 | case !test.wantHandshakeErr && err == nil: | ||
| 217 | if got, want := version, test.wantVersion; got != want { | ||
| 218 | t.Errorf("Test %d - handshake %x:%x; got protocol version %v, want %v", | ||
| 219 | i, test.minVersion, test.maxVersion, got, want) | ||
| 220 | } | ||
| 221 | } | ||
| 222 | } | ||
| 223 | } | ||
| 224 | |||
| 225 | func TestTLSSingleByteReadWrite(t *testing.T) { | ||
| 226 | ts, u, caFile, err := newTestServer(nil) | ||
| 227 | if err != nil { | ||
| 228 | t.Fatalf("Failed to start test server: %v", err) | ||
| 229 | } | ||
| 230 | defer os.Remove(caFile) | ||
| 231 | defer ts.Close() | ||
| 232 | |||
| 233 | if err := Init(); err != nil { | ||
| 234 | t.Fatal(err) | ||
| 235 | } | ||
| 236 | |||
| 237 | cfg, err := NewConfig() | ||
| 238 | if err != nil { | ||
| 239 | t.Fatal(err) | ||
| 240 | } | ||
| 241 | defer cfg.Free() | ||
| 242 | if err := cfg.SetCAFile(caFile); err != nil { | ||
| 243 | t.Fatal(err) | ||
| 244 | } | ||
| 245 | |||
| 246 | tls, err := NewClient(cfg) | ||
| 247 | if err != nil { | ||
| 248 | t.Fatal(err) | ||
| 249 | } | ||
| 250 | defer tls.Free() | ||
| 251 | |||
| 252 | t.Logf("Connecting to %s", u.Host) | ||
| 253 | |||
| 254 | if err := tls.Connect(u.Host, ""); err != nil { | ||
| 255 | t.Fatal(err) | ||
| 256 | } | ||
| 257 | defer func() { | ||
| 258 | if err := tls.Close(); err != nil { | ||
| 259 | t.Fatalf("Close failed: %v", err) | ||
| 260 | } | ||
| 261 | }() | ||
| 262 | |||
| 263 | for _, b := range []byte("GET / HTTP/1.0\n\n") { | ||
| 264 | n, err := tls.Write([]byte{b}) | ||
| 265 | if err != nil { | ||
| 266 | t.Fatal(err) | ||
| 267 | } | ||
| 268 | if n != 1 { | ||
| 269 | t.Fatalf("Wrote byte %v, got length %d, want 1", b, n) | ||
| 270 | } | ||
| 271 | } | ||
| 272 | |||
| 273 | var body []byte | ||
| 274 | for { | ||
| 275 | buf := make([]byte, 1) | ||
| 276 | n, err := tls.Read(buf) | ||
| 277 | if err != nil { | ||
| 278 | t.Fatal(err) | ||
| 279 | } | ||
| 280 | if n == 0 { | ||
| 281 | break | ||
| 282 | } | ||
| 283 | if n != 1 { | ||
| 284 | t.Fatalf("Read single byte, got length %d, want 1", n) | ||
| 285 | } | ||
| 286 | body = append(body, buf...) | ||
| 287 | } | ||
| 288 | |||
| 289 | if !strings.Contains(string(body), httpContent) { | ||
| 290 | t.Errorf("Response does not contain %q", httpContent) | ||
| 291 | } | ||
| 292 | } | ||
| 293 | |||
| 294 | func TestTLSInfo(t *testing.T) { | ||
| 295 | ts, u, caFile, err := newTestServer(nil) | ||
| 296 | if err != nil { | ||
| 297 | t.Fatalf("Failed to start test server: %v", err) | ||
| 298 | } | ||
| 299 | defer os.Remove(caFile) | ||
| 300 | defer ts.Close() | ||
| 301 | |||
| 302 | if err := Init(); err != nil { | ||
| 303 | t.Fatal(err) | ||
| 304 | } | ||
| 305 | |||
| 306 | cfg, err := NewConfig() | ||
| 307 | if err != nil { | ||
| 308 | t.Fatal(err) | ||
| 309 | } | ||
| 310 | defer cfg.Free() | ||
| 311 | if err := cfg.SetCAFile(caFile); err != nil { | ||
| 312 | t.Fatal(err) | ||
| 313 | } | ||
| 314 | |||
| 315 | tls, err := NewClient(cfg) | ||
| 316 | if err != nil { | ||
| 317 | t.Fatal(err) | ||
| 318 | } | ||
| 319 | defer tls.Free() | ||
| 320 | |||
| 321 | t.Logf("Connecting to %s", u.Host) | ||
| 322 | |||
| 323 | if err := tls.Connect(u.Host, ""); err != nil { | ||
| 324 | t.Fatal(err) | ||
| 325 | } | ||
| 326 | defer func() { | ||
| 327 | if err := tls.Close(); err != nil { | ||
| 328 | t.Fatalf("Close failed: %v", err) | ||
| 329 | } | ||
| 330 | }() | ||
| 331 | |||
| 332 | // All of these should fail since the handshake has not completed. | ||
| 333 | if _, err := tls.ConnVersion(); err == nil { | ||
| 334 | t.Error("ConnVersion() return nil error, want error") | ||
| 335 | } | ||
| 336 | if _, err := tls.ConnCipher(); err == nil { | ||
| 337 | t.Error("ConnCipher() return nil error, want error") | ||
| 338 | } | ||
| 339 | if _, err := tls.ConnCipherStrength(); err == nil { | ||
| 340 | t.Error("ConnCipherStrength() return nil error, want error") | ||
| 341 | } | ||
| 342 | |||
| 343 | if got, want := tls.PeerCertProvided(), false; got != want { | ||
| 344 | t.Errorf("PeerCertProvided() = %v, want %v", got, want) | ||
| 345 | } | ||
| 346 | for _, name := range []string{"127.0.0.1", "::1", "example.com"} { | ||
| 347 | if got, want := tls.PeerCertContainsName(name), false; got != want { | ||
| 348 | t.Errorf("PeerCertContainsName(%q) = %v, want %v", name, got, want) | ||
| 349 | } | ||
| 350 | } | ||
| 351 | |||
| 352 | if _, err := tls.PeerCertIssuer(); err == nil { | ||
| 353 | t.Error("PeerCertIssuer() returned nil error, want error") | ||
| 354 | } | ||
| 355 | if _, err := tls.PeerCertSubject(); err == nil { | ||
| 356 | t.Error("PeerCertSubject() returned nil error, want error") | ||
| 357 | } | ||
| 358 | if _, err := tls.PeerCertHash(); err == nil { | ||
| 359 | t.Error("PeerCertHash() returned nil error, want error") | ||
| 360 | } | ||
| 361 | if _, err := tls.PeerCertNotBefore(); err == nil { | ||
| 362 | t.Error("PeerCertNotBefore() returned nil error, want error") | ||
| 363 | } | ||
| 364 | if _, err := tls.PeerCertNotAfter(); err == nil { | ||
| 365 | t.Error("PeerCertNotAfter() returned nil error, want error") | ||
| 366 | } | ||
| 367 | |||
| 368 | // Complete the handshake... | ||
| 369 | if err := tls.Handshake(); err != nil { | ||
| 370 | t.Fatalf("Handshake failed: %v", err) | ||
| 371 | } | ||
| 372 | |||
| 373 | if version, err := tls.ConnVersion(); err != nil { | ||
| 374 | t.Errorf("ConnVersion() returned error: %v", err) | ||
| 375 | } else { | ||
| 376 | t.Logf("Protocol version: %v", version) | ||
| 377 | } | ||
| 378 | if cipher, err := tls.ConnCipher(); err != nil { | ||
| 379 | t.Errorf("ConnCipher() returned error: %v", err) | ||
| 380 | } else { | ||
| 381 | t.Logf("Cipher: %v", cipher) | ||
| 382 | } | ||
| 383 | if strength, err := tls.ConnCipherStrength(); err != nil { | ||
| 384 | t.Errorf("ConnCipherStrength() return ederror: %v", err) | ||
| 385 | } else { | ||
| 386 | t.Logf("Cipher Strength: %v bits", strength) | ||
| 387 | } | ||
| 388 | |||
| 389 | if got, want := tls.PeerCertProvided(), true; got != want { | ||
| 390 | t.Errorf("PeerCertProvided() = %v, want %v", got, want) | ||
| 391 | } | ||
| 392 | for _, name := range []string{"127.0.0.1", "::1", "example.com"} { | ||
| 393 | if got, want := tls.PeerCertContainsName(name), true; got != want { | ||
| 394 | t.Errorf("PeerCertContainsName(%q) = %v, want %v", name, got, want) | ||
| 395 | } | ||
| 396 | } | ||
| 397 | |||
| 398 | if issuer, err := tls.PeerCertIssuer(); err != nil { | ||
| 399 | t.Errorf("PeerCertIssuer() returned error: %v", err) | ||
| 400 | } else { | ||
| 401 | t.Logf("Issuer: %v", issuer) | ||
| 402 | } | ||
| 403 | if subject, err := tls.PeerCertSubject(); err != nil { | ||
| 404 | t.Errorf("PeerCertSubject() returned error: %v", err) | ||
| 405 | } else { | ||
| 406 | t.Logf("Subject: %v", subject) | ||
| 407 | } | ||
| 408 | if hash, err := tls.PeerCertHash(); err != nil { | ||
| 409 | t.Errorf("PeerCertHash() returned error: %v", err) | ||
| 410 | } else if hash != certHash { | ||
| 411 | t.Errorf("Got cert hash %q, want %q", hash, certHash) | ||
| 412 | } else { | ||
| 413 | t.Logf("Hash: %v", hash) | ||
| 414 | } | ||
| 415 | if notBefore, err := tls.PeerCertNotBefore(); err != nil { | ||
| 416 | t.Errorf("PeerCertNotBefore() returned error: %v", err) | ||
| 417 | } else if !certNotBefore.Equal(notBefore) { | ||
| 418 | t.Errorf("Got cert notBefore %v, want %v", notBefore.UTC(), certNotBefore.UTC()) | ||
| 419 | } else { | ||
| 420 | t.Logf("NotBefore: %v", notBefore.UTC()) | ||
| 421 | } | ||
| 422 | if notAfter, err := tls.PeerCertNotAfter(); err != nil { | ||
| 423 | t.Errorf("PeerCertNotAfter() returned error: %v", err) | ||
| 424 | } else if !certNotAfter.Equal(notAfter) { | ||
| 425 | t.Errorf("Got cert notAfter %v, want %v", notAfter.UTC(), certNotAfter.UTC()) | ||
| 426 | } else { | ||
| 427 | t.Logf("NotAfter: %v", notAfter.UTC()) | ||
| 428 | } | ||
| 429 | } | ||
