The Go Programming Language

Source file src/pkg/crypto/tls/tls.go

     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	
     5	// Package tls partially implements the TLS 1.1 protocol, as specified in RFC
     6	// 4346.
     7	package tls
     8	
     9	import (
    10		"crypto/rsa"
    11		"crypto/x509"
    12		"encoding/pem"
    13		"io/ioutil"
    14		"net"
    15		"os"
    16		"strings"
    17	)
    18	
    19	// Server returns a new TLS server side connection
    20	// using conn as the underlying transport.
    21	// The configuration config must be non-nil and must have
    22	// at least one certificate.
    23	func Server(conn net.Conn, config *Config) *Conn {
    24		return &Conn{conn: conn, config: config}
    25	}
    26	
    27	// Client returns a new TLS client side connection
    28	// using conn as the underlying transport.
    29	// Client interprets a nil configuration as equivalent to
    30	// the zero configuration; see the documentation of Config
    31	// for the defaults.
    32	func Client(conn net.Conn, config *Config) *Conn {
    33		return &Conn{conn: conn, config: config, isClient: true}
    34	}
    35	
    36	// A Listener implements a network listener (net.Listener) for TLS connections.
    37	type Listener struct {
    38		listener net.Listener
    39		config   *Config
    40	}
    41	
    42	// Accept waits for and returns the next incoming TLS connection.
    43	// The returned connection c is a *tls.Conn.
    44	func (l *Listener) Accept() (c net.Conn, err os.Error) {
    45		c, err = l.listener.Accept()
    46		if err != nil {
    47			return
    48		}
    49		c = Server(c, l.config)
    50		return
    51	}
    52	
    53	// Close closes the listener.
    54	func (l *Listener) Close() os.Error { return l.listener.Close() }
    55	
    56	// Addr returns the listener's network address.
    57	func (l *Listener) Addr() net.Addr { return l.listener.Addr() }
    58	
    59	// NewListener creates a Listener which accepts connections from an inner
    60	// Listener and wraps each connection with Server.
    61	// The configuration config must be non-nil and must have
    62	// at least one certificate.
    63	func NewListener(listener net.Listener, config *Config) (l *Listener) {
    64		l = new(Listener)
    65		l.listener = listener
    66		l.config = config
    67		return
    68	}
    69	
    70	// Listen creates a TLS listener accepting connections on the
    71	// given network address using net.Listen.
    72	// The configuration config must be non-nil and must have
    73	// at least one certificate.
    74	func Listen(network, laddr string, config *Config) (*Listener, os.Error) {
    75		if config == nil || len(config.Certificates) == 0 {
    76			return nil, os.NewError("tls.Listen: no certificates in configuration")
    77		}
    78		l, err := net.Listen(network, laddr)
    79		if err != nil {
    80			return nil, err
    81		}
    82		return NewListener(l, config), nil
    83	}
    84	
    85	// Dial connects to the given network address using net.Dial
    86	// and then initiates a TLS handshake, returning the resulting
    87	// TLS connection.
    88	// Dial interprets a nil configuration as equivalent to
    89	// the zero configuration; see the documentation of Config
    90	// for the defaults.
    91	func Dial(network, addr string, config *Config) (*Conn, os.Error) {
    92		raddr := addr
    93		c, err := net.Dial(network, raddr)
    94		if err != nil {
    95			return nil, err
    96		}
    97	
    98		colonPos := strings.LastIndex(raddr, ":")
    99		if colonPos == -1 {
   100			colonPos = len(raddr)
   101		}
   102		hostname := raddr[:colonPos]
   103	
   104		if config == nil {
   105			config = defaultConfig()
   106		}
   107		if config.ServerName != "" {
   108			// Make a copy to avoid polluting argument or default.
   109			c := *config
   110			c.ServerName = hostname
   111			config = &c
   112		}
   113		conn := Client(c, config)
   114		if err = conn.Handshake(); err != nil {
   115			c.Close()
   116			return nil, err
   117		}
   118		return conn, nil
   119	}
   120	
   121	// LoadX509KeyPair reads and parses a public/private key pair from a pair of
   122	// files. The files must contain PEM encoded data.
   123	func LoadX509KeyPair(certFile string, keyFile string) (cert Certificate, err os.Error) {
   124		certPEMBlock, err := ioutil.ReadFile(certFile)
   125		if err != nil {
   126			return
   127		}
   128		keyPEMBlock, err := ioutil.ReadFile(keyFile)
   129		if err != nil {
   130			return
   131		}
   132		return X509KeyPair(certPEMBlock, keyPEMBlock)
   133	}
   134	
   135	// X509KeyPair parses a public/private key pair from a pair of
   136	// PEM encoded data.
   137	func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (cert Certificate, err os.Error) {
   138		var certDERBlock *pem.Block
   139		for {
   140			certDERBlock, certPEMBlock = pem.Decode(certPEMBlock)
   141			if certDERBlock == nil {
   142				break
   143			}
   144			if certDERBlock.Type == "CERTIFICATE" {
   145				cert.Certificate = append(cert.Certificate, certDERBlock.Bytes)
   146			}
   147		}
   148	
   149		if len(cert.Certificate) == 0 {
   150			err = os.NewError("crypto/tls: failed to parse certificate PEM data")
   151			return
   152		}
   153	
   154		keyDERBlock, _ := pem.Decode(keyPEMBlock)
   155		if keyDERBlock == nil {
   156			err = os.NewError("crypto/tls: failed to parse key PEM data")
   157			return
   158		}
   159	
   160		key, err := x509.ParsePKCS1PrivateKey(keyDERBlock.Bytes)
   161		if err != nil {
   162			err = os.NewError("crypto/tls: failed to parse key: " + err.String())
   163			return
   164		}
   165	
   166		cert.PrivateKey = key
   167	
   168		// We don't need to parse the public key for TLS, but we so do anyway
   169		// to check that it looks sane and matches the private key.
   170		x509Cert, err := x509.ParseCertificate(cert.Certificate[0])
   171		if err != nil {
   172			return
   173		}
   174	
   175		if x509Cert.PublicKeyAlgorithm != x509.RSA || x509Cert.PublicKey.(*rsa.PublicKey).N.Cmp(key.PublicKey.N) != 0 {
   176			err = os.NewError("crypto/tls: private key does not match public key")
   177			return
   178		}
   179	
   180		return
   181	}

release.r60.3. Except as noted, this content is licensed under a Creative Commons Attribution 3.0 License.