net.go 3.98 KB
Newer Older
1
// Copyright (C) 2017. See AUTHORS.
JT Olds's avatar
JT Olds committed
2 3 4 5 6 7 8 9 10 11 12 13
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
JT Olds's avatar
JT Olds committed
14 15 16 17

package openssl

import (
18 19
	"errors"
	"net"
JT Olds's avatar
JT Olds committed
20 21 22
)

type listener struct {
23 24
	net.Listener
	ctx *Ctx
JT Olds's avatar
JT Olds committed
25 26 27
}

func (l *listener) Accept() (c net.Conn, err error) {
28 29 30 31
	c, err = l.Listener.Accept()
	if err != nil {
		return nil, err
	}
JT Olds's avatar
JT Olds committed
32 33 34 35 36 37
	ssl_c, err := Server(c, l.ctx)
	if err != nil {
		c.Close()
		return nil, err
	}
	return ssl_c, nil
JT Olds's avatar
JT Olds committed
38 39
}

JT Olds's avatar
JT Olds committed
40 41 42
// NewListener wraps an existing net.Listener such that all accepted
// connections are wrapped as OpenSSL server connections using the provided
// context ctx.
JT Olds's avatar
JT Olds committed
43
func NewListener(inner net.Listener, ctx *Ctx) net.Listener {
44 45 46
	return &listener{
		Listener: inner,
		ctx:      ctx}
JT Olds's avatar
JT Olds committed
47 48
}

JT Olds's avatar
JT Olds committed
49 50
// Listen is a wrapper around net.Listen that wraps incoming connections with
// an OpenSSL server connection using the provided context ctx.
JT Olds's avatar
JT Olds committed
51
func Listen(network, laddr string, ctx *Ctx) (net.Listener, error) {
52 53 54 55 56 57 58 59
	if ctx == nil {
		return nil, errors.New("no ssl context provided")
	}
	l, err := net.Listen(network, laddr)
	if err != nil {
		return nil, err
	}
	return NewListener(l, ctx), nil
JT Olds's avatar
JT Olds committed
60 61 62 63 64
}

type DialFlags int

const (
JT Olds's avatar
JT Olds committed
65 66
	InsecureSkipHostVerification DialFlags = 1 << iota
	DisableSNI
JT Olds's avatar
JT Olds committed
67 68
)

JT Olds's avatar
JT Olds committed
69 70 71 72 73 74 75 76 77 78
// Dial will connect to network/address and then wrap the corresponding
// underlying connection with an OpenSSL client connection using context ctx.
// If flags includes InsecureSkipHostVerification, the server certificate's
// hostname will not be checked to match the hostname in addr. Otherwise, flags
// should be 0.
//
// Dial probably won't work for you unless you set a verify location or add
// some certs to the certificate store of the client context you're using.
// This library is not nice enough to use the system certificate store by
// default for you yet.
JT Olds's avatar
JT Olds committed
79
func Dial(network, addr string, ctx *Ctx, flags DialFlags) (*Conn, error) {
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
	return DialSession(network, addr, ctx, flags, nil)
}

// DialSession will connect to network/address and then wrap the corresponding
// underlying connection with an OpenSSL client connection using context ctx.
// If flags includes InsecureSkipHostVerification, the server certificate's
// hostname will not be checked to match the hostname in addr. Otherwise, flags
// should be 0.
//
// Dial probably won't work for you unless you set a verify location or add
// some certs to the certificate store of the client context you're using.
// This library is not nice enough to use the system certificate store by
// default for you yet.
//
// If session is not nil it will be used to resume the tls state. The session
// can be retrieved from the GetSession method on the Conn.
func DialSession(network, addr string, ctx *Ctx, flags DialFlags,
	session []byte) (*Conn, error) {

JT Olds's avatar
JT Olds committed
99 100 101 102
	host, _, err := net.SplitHostPort(addr)
	if err != nil {
		return nil, err
	}
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
	if ctx == nil {
		var err error
		ctx, err = NewCtx()
		if err != nil {
			return nil, err
		}
		// TODO: use operating system default certificate chain?
	}
	c, err := net.Dial(network, addr)
	if err != nil {
		return nil, err
	}
	conn, err := Client(c, ctx)
	if err != nil {
		c.Close()
		return nil, err
	}
120 121 122 123 124 125 126
	if session != nil {
		err := conn.setSession(session)
		if err != nil {
			c.Close()
			return nil, err
		}
	}
JT Olds's avatar
JT Olds committed
127 128 129 130 131 132 133
	if flags&DisableSNI == 0 {
		err = conn.SetTlsExtHostName(host)
		if err != nil {
			conn.Close()
			return nil, err
		}
	}
134 135
	err = conn.Handshake()
	if err != nil {
136
		conn.Close()
137 138 139 140 141 142 143 144 145 146
		return nil, err
	}
	if flags&InsecureSkipHostVerification == 0 {
		err = conn.VerifyHostname(host)
		if err != nil {
			conn.Close()
			return nil, err
		}
	}
	return conn, nil
JT Olds's avatar
JT Olds committed
147
}