Adam Langley | 950f263 | 2009-11-05 16:43:29 -0800 | [diff] [blame] | 1 | // Copyright 2009 The Go Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style |
| 3 | // license that can be found in the LICENSE file. |
| 4 | |
Frithjof Schulze | 4d7c635 | 2013-10-02 12:09:13 -0400 | [diff] [blame] | 5 | // Package tls partially implements TLS 1.2, as specified in RFC 5246. |
Adam Langley | 950f263 | 2009-11-05 16:43:29 -0800 | [diff] [blame] | 6 | package tls |
| 7 | |
| 8 | import ( |
Joel Sing | aaf3b71 | 2012-11-16 19:33:59 +1100 | [diff] [blame] | 9 | "crypto" |
| 10 | "crypto/ecdsa" |
Adam Langley | 836529a | 2010-11-05 09:54:56 -0400 | [diff] [blame] | 11 | "crypto/rsa" |
| 12 | "crypto/x509" |
| 13 | "encoding/pem" |
Russ Cox | c2049d2 | 2011-11-01 22:04:37 -0400 | [diff] [blame] | 14 | "errors" |
Adam Langley | fc23def | 2010-07-02 13:00:18 -0400 | [diff] [blame] | 15 | "io/ioutil" |
Robert Griesemer | 5a1d332 | 2009-12-15 15:33:31 -0800 | [diff] [blame] | 16 | "net" |
Adam Langley | 836529a | 2010-11-05 09:54:56 -0400 | [diff] [blame] | 17 | "strings" |
Adam Langley | 950f263 | 2009-11-05 16:43:29 -0800 | [diff] [blame] | 18 | ) |
| 19 | |
Russ Cox | b15c424 | 2010-12-07 16:15:15 -0500 | [diff] [blame] | 20 | // Server returns a new TLS server side connection |
| 21 | // using conn as the underlying transport. |
| 22 | // The configuration config must be non-nil and must have |
| 23 | // at least one certificate. |
Adam Langley | 6e0842d | 2009-11-21 15:53:03 -0800 | [diff] [blame] | 24 | func Server(conn net.Conn, config *Config) *Conn { |
Russ Cox | 72d9322 | 2010-04-26 22:19:04 -0700 | [diff] [blame] | 25 | return &Conn{conn: conn, config: config} |
Adam Langley | 6e0842d | 2009-11-21 15:53:03 -0800 | [diff] [blame] | 26 | } |
| 27 | |
Russ Cox | b15c424 | 2010-12-07 16:15:15 -0500 | [diff] [blame] | 28 | // Client returns a new TLS client side connection |
| 29 | // using conn as the underlying transport. |
Adam Langley | 80692a3 | 2014-02-19 11:17:09 -0500 | [diff] [blame^] | 30 | // The config cannot be nil: users must set either ServerHostname or |
| 31 | // InsecureSkipVerify in the config. |
Adam Langley | 6e0842d | 2009-11-21 15:53:03 -0800 | [diff] [blame] | 32 | func Client(conn net.Conn, config *Config) *Conn { |
Russ Cox | 72d9322 | 2010-04-26 22:19:04 -0700 | [diff] [blame] | 33 | return &Conn{conn: conn, config: config, isClient: true} |
Adam Langley | 6e0842d | 2009-11-21 15:53:03 -0800 | [diff] [blame] | 34 | } |
| 35 | |
Adam Langley | 005686f | 2012-02-03 15:08:53 -0500 | [diff] [blame] | 36 | // A listener implements a network listener (net.Listener) for TLS connections. |
| 37 | type listener struct { |
| 38 | net.Listener |
| 39 | config *Config |
Adam Langley | 950f263 | 2009-11-05 16:43:29 -0800 | [diff] [blame] | 40 | } |
| 41 | |
Russ Cox | b15c424 | 2010-12-07 16:15:15 -0500 | [diff] [blame] | 42 | // Accept waits for and returns the next incoming TLS connection. |
| 43 | // The returned connection c is a *tls.Conn. |
Adam Langley | 005686f | 2012-02-03 15:08:53 -0500 | [diff] [blame] | 44 | func (l *listener) Accept() (c net.Conn, err error) { |
| 45 | c, err = l.Listener.Accept() |
Adam Langley | 950f263 | 2009-11-05 16:43:29 -0800 | [diff] [blame] | 46 | if err != nil { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 47 | return |
Adam Langley | 950f263 | 2009-11-05 16:43:29 -0800 | [diff] [blame] | 48 | } |
Robert Griesemer | 5a1d332 | 2009-12-15 15:33:31 -0800 | [diff] [blame] | 49 | c = Server(c, l.config) |
| 50 | return |
Adam Langley | 950f263 | 2009-11-05 16:43:29 -0800 | [diff] [blame] | 51 | } |
| 52 | |
Adam Langley | 950f263 | 2009-11-05 16:43:29 -0800 | [diff] [blame] | 53 | // NewListener creates a Listener which accepts connections from an inner |
| 54 | // Listener and wraps each connection with Server. |
Russ Cox | 72d9322 | 2010-04-26 22:19:04 -0700 | [diff] [blame] | 55 | // The configuration config must be non-nil and must have |
| 56 | // at least one certificate. |
Adam Langley | 005686f | 2012-02-03 15:08:53 -0500 | [diff] [blame] | 57 | func NewListener(inner net.Listener, config *Config) net.Listener { |
| 58 | l := new(listener) |
| 59 | l.Listener = inner |
Robert Griesemer | 5a1d332 | 2009-12-15 15:33:31 -0800 | [diff] [blame] | 60 | l.config = config |
Adam Langley | 005686f | 2012-02-03 15:08:53 -0500 | [diff] [blame] | 61 | return l |
Adam Langley | 950f263 | 2009-11-05 16:43:29 -0800 | [diff] [blame] | 62 | } |
Russ Cox | 99d258a | 2010-04-05 14:38:02 -0700 | [diff] [blame] | 63 | |
Russ Cox | b15c424 | 2010-12-07 16:15:15 -0500 | [diff] [blame] | 64 | // Listen creates a TLS listener accepting connections on the |
| 65 | // given network address using net.Listen. |
| 66 | // The configuration config must be non-nil and must have |
| 67 | // at least one certificate. |
Adam Langley | 005686f | 2012-02-03 15:08:53 -0500 | [diff] [blame] | 68 | func Listen(network, laddr string, config *Config) (net.Listener, error) { |
Russ Cox | 72d9322 | 2010-04-26 22:19:04 -0700 | [diff] [blame] | 69 | if config == nil || len(config.Certificates) == 0 { |
Russ Cox | c2049d2 | 2011-11-01 22:04:37 -0400 | [diff] [blame] | 70 | return nil, errors.New("tls.Listen: no certificates in configuration") |
Russ Cox | 72d9322 | 2010-04-26 22:19:04 -0700 | [diff] [blame] | 71 | } |
Russ Cox | 99d258a | 2010-04-05 14:38:02 -0700 | [diff] [blame] | 72 | l, err := net.Listen(network, laddr) |
| 73 | if err != nil { |
| 74 | return nil, err |
| 75 | } |
Russ Cox | 72d9322 | 2010-04-26 22:19:04 -0700 | [diff] [blame] | 76 | return NewListener(l, config), nil |
Russ Cox | 99d258a | 2010-04-05 14:38:02 -0700 | [diff] [blame] | 77 | } |
| 78 | |
Russ Cox | b15c424 | 2010-12-07 16:15:15 -0500 | [diff] [blame] | 79 | // Dial connects to the given network address using net.Dial |
| 80 | // and then initiates a TLS handshake, returning the resulting |
| 81 | // TLS connection. |
| 82 | // Dial interprets a nil configuration as equivalent to |
| 83 | // the zero configuration; see the documentation of Config |
| 84 | // for the defaults. |
Russ Cox | c2049d2 | 2011-11-01 22:04:37 -0400 | [diff] [blame] | 85 | func Dial(network, addr string, config *Config) (*Conn, error) { |
Russ Cox | 41f93a4 | 2011-03-28 23:28:42 -0400 | [diff] [blame] | 86 | raddr := addr |
| 87 | c, err := net.Dial(network, raddr) |
Russ Cox | 99d258a | 2010-04-05 14:38:02 -0700 | [diff] [blame] | 88 | if err != nil { |
| 89 | return nil, err |
| 90 | } |
Adam Langley | 836529a | 2010-11-05 09:54:56 -0400 | [diff] [blame] | 91 | |
| 92 | colonPos := strings.LastIndex(raddr, ":") |
| 93 | if colonPos == -1 { |
| 94 | colonPos = len(raddr) |
| 95 | } |
| 96 | hostname := raddr[:colonPos] |
| 97 | |
Russ Cox | b15c424 | 2010-12-07 16:15:15 -0500 | [diff] [blame] | 98 | if config == nil { |
| 99 | config = defaultConfig() |
Adam Langley | 6989f6e | 2010-09-20 10:32:08 -0400 | [diff] [blame] | 100 | } |
Mikkel Krautz | a324a5a | 2012-03-07 13:12:35 -0500 | [diff] [blame] | 101 | // If no ServerName is set, infer the ServerName |
| 102 | // from the hostname we're connecting to. |
| 103 | if config.ServerName == "" { |
Russ Cox | b15c424 | 2010-12-07 16:15:15 -0500 | [diff] [blame] | 104 | // Make a copy to avoid polluting argument or default. |
| 105 | c := *config |
| 106 | c.ServerName = hostname |
| 107 | config = &c |
| 108 | } |
| 109 | conn := Client(c, config) |
| 110 | if err = conn.Handshake(); err != nil { |
| 111 | c.Close() |
| 112 | return nil, err |
| 113 | } |
| 114 | return conn, nil |
Russ Cox | 99d258a | 2010-04-05 14:38:02 -0700 | [diff] [blame] | 115 | } |
Adam Langley | fc23def | 2010-07-02 13:00:18 -0400 | [diff] [blame] | 116 | |
Adam Langley | f6e2eab | 2010-10-11 10:39:56 -0400 | [diff] [blame] | 117 | // LoadX509KeyPair reads and parses a public/private key pair from a pair of |
| 118 | // files. The files must contain PEM encoded data. |
Jeff R. Allen | c581ec4 | 2012-01-05 12:05:38 -0500 | [diff] [blame] | 119 | func LoadX509KeyPair(certFile, keyFile string) (cert Certificate, err error) { |
Adam Langley | fc23def | 2010-07-02 13:00:18 -0400 | [diff] [blame] | 120 | certPEMBlock, err := ioutil.ReadFile(certFile) |
| 121 | if err != nil { |
| 122 | return |
| 123 | } |
Brad Fitzpatrick | cc40870 | 2011-04-04 08:32:59 -0700 | [diff] [blame] | 124 | keyPEMBlock, err := ioutil.ReadFile(keyFile) |
| 125 | if err != nil { |
| 126 | return |
| 127 | } |
| 128 | return X509KeyPair(certPEMBlock, keyPEMBlock) |
| 129 | } |
Adam Langley | fc23def | 2010-07-02 13:00:18 -0400 | [diff] [blame] | 130 | |
Brad Fitzpatrick | cc40870 | 2011-04-04 08:32:59 -0700 | [diff] [blame] | 131 | // X509KeyPair parses a public/private key pair from a pair of |
| 132 | // PEM encoded data. |
Russ Cox | c2049d2 | 2011-11-01 22:04:37 -0400 | [diff] [blame] | 133 | func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (cert Certificate, err error) { |
Adam Langley | 5626bd9 | 2011-02-05 13:54:25 -0500 | [diff] [blame] | 134 | var certDERBlock *pem.Block |
| 135 | for { |
| 136 | certDERBlock, certPEMBlock = pem.Decode(certPEMBlock) |
| 137 | if certDERBlock == nil { |
| 138 | break |
| 139 | } |
| 140 | if certDERBlock.Type == "CERTIFICATE" { |
| 141 | cert.Certificate = append(cert.Certificate, certDERBlock.Bytes) |
| 142 | } |
| 143 | } |
| 144 | |
| 145 | if len(cert.Certificate) == 0 { |
Russ Cox | c2049d2 | 2011-11-01 22:04:37 -0400 | [diff] [blame] | 146 | err = errors.New("crypto/tls: failed to parse certificate PEM data") |
Adam Langley | fc23def | 2010-07-02 13:00:18 -0400 | [diff] [blame] | 147 | return |
| 148 | } |
| 149 | |
Adam Langley | ecc04b8 | 2012-09-13 11:00:16 -0400 | [diff] [blame] | 150 | var keyDERBlock *pem.Block |
| 151 | for { |
| 152 | keyDERBlock, keyPEMBlock = pem.Decode(keyPEMBlock) |
| 153 | if keyDERBlock == nil { |
| 154 | err = errors.New("crypto/tls: failed to parse key PEM data") |
| 155 | return |
| 156 | } |
Brad Fitzpatrick | 444b7b5 | 2012-12-01 11:02:08 -0800 | [diff] [blame] | 157 | if keyDERBlock.Type == "PRIVATE KEY" || strings.HasSuffix(keyDERBlock.Type, " PRIVATE KEY") { |
Adam Langley | ecc04b8 | 2012-09-13 11:00:16 -0400 | [diff] [blame] | 158 | break |
| 159 | } |
Adam Langley | fc23def | 2010-07-02 13:00:18 -0400 | [diff] [blame] | 160 | } |
| 161 | |
Joel Sing | aaf3b71 | 2012-11-16 19:33:59 +1100 | [diff] [blame] | 162 | cert.PrivateKey, err = parsePrivateKey(keyDERBlock.Bytes) |
| 163 | if err != nil { |
| 164 | return |
Adam Langley | fc23def | 2010-07-02 13:00:18 -0400 | [diff] [blame] | 165 | } |
| 166 | |
Adam Langley | fc23def | 2010-07-02 13:00:18 -0400 | [diff] [blame] | 167 | // We don't need to parse the public key for TLS, but we so do anyway |
| 168 | // to check that it looks sane and matches the private key. |
Adam Langley | 5626bd9 | 2011-02-05 13:54:25 -0500 | [diff] [blame] | 169 | x509Cert, err := x509.ParseCertificate(cert.Certificate[0]) |
Adam Langley | fc23def | 2010-07-02 13:00:18 -0400 | [diff] [blame] | 170 | if err != nil { |
| 171 | return |
| 172 | } |
| 173 | |
Joel Sing | aaf3b71 | 2012-11-16 19:33:59 +1100 | [diff] [blame] | 174 | switch pub := x509Cert.PublicKey.(type) { |
| 175 | case *rsa.PublicKey: |
| 176 | priv, ok := cert.PrivateKey.(*rsa.PrivateKey) |
| 177 | if !ok { |
| 178 | err = errors.New("crypto/tls: private key type does not match public key type") |
| 179 | return |
| 180 | } |
| 181 | if pub.N.Cmp(priv.N) != 0 { |
| 182 | err = errors.New("crypto/tls: private key does not match public key") |
| 183 | return |
| 184 | } |
| 185 | case *ecdsa.PublicKey: |
| 186 | priv, ok := cert.PrivateKey.(*ecdsa.PrivateKey) |
| 187 | if !ok { |
| 188 | err = errors.New("crypto/tls: private key type does not match public key type") |
| 189 | return |
| 190 | |
| 191 | } |
| 192 | if pub.X.Cmp(priv.X) != 0 || pub.Y.Cmp(priv.Y) != 0 { |
| 193 | err = errors.New("crypto/tls: private key does not match public key") |
| 194 | return |
| 195 | } |
| 196 | default: |
| 197 | err = errors.New("crypto/tls: unknown public key algorithm") |
Adam Langley | fc23def | 2010-07-02 13:00:18 -0400 | [diff] [blame] | 198 | return |
| 199 | } |
| 200 | |
| 201 | return |
| 202 | } |
Joel Sing | aaf3b71 | 2012-11-16 19:33:59 +1100 | [diff] [blame] | 203 | |
| 204 | // Attempt to parse the given private key DER block. OpenSSL 0.9.8 generates |
| 205 | // PKCS#1 private keys by default, while OpenSSL 1.0.0 generates PKCS#8 keys. |
| 206 | // OpenSSL ecparam generates SEC1 EC private keys for ECDSA. We try all three. |
| 207 | func parsePrivateKey(der []byte) (crypto.PrivateKey, error) { |
| 208 | if key, err := x509.ParsePKCS1PrivateKey(der); err == nil { |
| 209 | return key, nil |
| 210 | } |
| 211 | if key, err := x509.ParsePKCS8PrivateKey(der); err == nil { |
| 212 | switch key := key.(type) { |
| 213 | case *rsa.PrivateKey, *ecdsa.PrivateKey: |
| 214 | return key, nil |
| 215 | default: |
| 216 | return nil, errors.New("crypto/tls: found unknown private key type in PKCS#8 wrapping") |
| 217 | } |
| 218 | } |
| 219 | if key, err := x509.ParseECPrivateKey(der); err == nil { |
| 220 | return key, nil |
| 221 | } |
| 222 | |
| 223 | return nil, errors.New("crypto/tls: failed to parse private key") |
| 224 | } |