Fixes #1009. R=adg, rsc CC=golang-dev https://golang.org/cl/5262041tls13
@@ -17,4 +17,22 @@ GOFILES=\ | |||
prf.go\ | |||
tls.go\ | |||
ifeq ($(CGO_ENABLED),1) | |||
CGOFILES_darwin=\ | |||
root_darwin.go | |||
else | |||
GOFILES_darwin+=root_stub.go | |||
endif | |||
GOFILES_freebsd+=root_unix.go | |||
GOFILES_linux+=root_unix.go | |||
GOFILES_openbsd+=root_unix.go | |||
GOFILES_plan9+=root_stub.go | |||
GOFILES_windows+=root_stub.go | |||
GOFILES+=$(GOFILES_$(GOOS)) | |||
ifneq ($(CGOFILES_$(GOOS)),) | |||
CGOFILES+=$(CGOFILES_$(GOOS)) | |||
endif | |||
include ../../../Make.pkg |
@@ -9,7 +9,6 @@ import ( | |||
"crypto/rsa" | |||
"crypto/x509" | |||
"io" | |||
"io/ioutil" | |||
"strings" | |||
"sync" | |||
"time" | |||
@@ -155,6 +154,14 @@ type Config struct { | |||
// anything more than self-signed. | |||
AuthenticateClient bool | |||
// InsecureSkipVerify controls whether a client verifies the | |||
// server's certificate chain and host name. | |||
// If InsecureSkipVerify is true, TLS accepts any certificate | |||
// presented by the server and any host name in that certificate. | |||
// In this mode, TLS is susceptible to man-in-the-middle attacks. | |||
// This should be used only for testing. | |||
InsecureSkipVerify bool | |||
// CipherSuites is a list of supported cipher suites. If CipherSuites | |||
// is nil, TLS uses a list of suites supported by the implementation. | |||
CipherSuites []uint16 | |||
@@ -284,15 +291,6 @@ func defaultConfig() *Config { | |||
return &emptyConfig | |||
} | |||
// Possible certificate files; stop after finding one. | |||
// On OS X we should really be using the Directory Services keychain | |||
// but that requires a lot of Mach goo to get at. Instead we use | |||
// the same root set that curl uses. | |||
var certFiles = []string{ | |||
"/etc/ssl/certs/ca-certificates.crt", // Linux etc | |||
"/usr/share/curl/curl-ca-bundle.crt", // OS X | |||
} | |||
var once sync.Once | |||
func defaultRoots() *x509.CertPool { | |||
@@ -310,21 +308,10 @@ func initDefaults() { | |||
initDefaultCipherSuites() | |||
} | |||
var varDefaultRoots *x509.CertPool | |||
func initDefaultRoots() { | |||
roots := x509.NewCertPool() | |||
for _, file := range certFiles { | |||
data, err := ioutil.ReadFile(file) | |||
if err == nil { | |||
roots.AppendCertsFromPEM(data) | |||
break | |||
} | |||
} | |||
varDefaultRoots = roots | |||
} | |||
var varDefaultCipherSuites []uint16 | |||
var ( | |||
varDefaultRoots *x509.CertPool | |||
varDefaultCipherSuites []uint16 | |||
) | |||
func initDefaultCipherSuites() { | |||
varDefaultCipherSuites = make([]uint16, len(cipherSuites)) | |||
@@ -97,11 +97,9 @@ func (c *Conn) clientHandshake() os.Error { | |||
certs[i] = cert | |||
} | |||
// If we don't have a root CA set configured then anything is accepted. | |||
// TODO(rsc): Find certificates for OS X 10.6. | |||
if c.config.RootCAs != nil { | |||
if !c.config.InsecureSkipVerify { | |||
opts := x509.VerifyOptions{ | |||
Roots: c.config.RootCAs, | |||
Roots: c.config.rootCAs(), | |||
CurrentTime: c.config.time(), | |||
DNSName: c.config.ServerName, | |||
Intermediates: x509.NewCertPool(), | |||
@@ -38,6 +38,7 @@ func init() { | |||
testConfig.Certificates[0].Certificate = [][]byte{testCertificate} | |||
testConfig.Certificates[0].PrivateKey = testPrivateKey | |||
testConfig.CipherSuites = []uint16{TLS_RSA_WITH_RC4_128_SHA} | |||
testConfig.InsecureSkipVerify = true | |||
} | |||
func testClientHelloFailure(t *testing.T, m handshakeMessage, expected os.Error) { | |||
@@ -0,0 +1,95 @@ | |||
// Copyright 2011 The Go Authors. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
package tls | |||
/* | |||
// Note: We disable -Werror here because the code in this file uses a deprecated API to stay | |||
// compatible with both Mac OS X 10.6 and 10.7. Using a deprecated function on Darwin generates | |||
// a warning. | |||
#cgo CFLAGS: -Wno-error | |||
#cgo LDFLAGS: -framework CoreFoundation -framework Security | |||
#include <CoreFoundation/CoreFoundation.h> | |||
#include <Security/Security.h> | |||
// FetchPEMRoots fetches the system's list of trusted X.509 root certificates. | |||
// | |||
// On success it returns 0 and fills pemRoots with a CFDataRef that contains the extracted root | |||
// certificates of the system. On failure, the function returns -1. | |||
// | |||
// Note: The CFDataRef returned in pemRoots must be released (using CFRelease) after | |||
// we've consumed its content. | |||
int FetchPEMRoots(CFDataRef *pemRoots) { | |||
if (pemRoots == NULL) { | |||
return -1; | |||
} | |||
CFArrayRef certs = NULL; | |||
OSStatus err = SecTrustCopyAnchorCertificates(&certs); | |||
if (err != noErr) { | |||
return -1; | |||
} | |||
CFMutableDataRef combinedData = CFDataCreateMutable(kCFAllocatorDefault, 0); | |||
int i, ncerts = CFArrayGetCount(certs); | |||
for (i = 0; i < ncerts; i++) { | |||
CFDataRef data = NULL; | |||
SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(certs, i); | |||
if (cert == NULL) { | |||
continue; | |||
} | |||
// SecKeychainImportExport is deprecated in >= OS X 10.7, and has been replaced by | |||
// SecItemExport. If we're built on a host with a Lion SDK, this code gets conditionally | |||
// included in the output, also for binaries meant for 10.6. | |||
// | |||
// To make sure that we run on both Mac OS X 10.6 and 10.7 we use weak linking | |||
// and check whether SecItemExport is available before we attempt to call it. On | |||
// 10.6, this won't be the case, and we'll fall back to calling SecKeychainItemExport. | |||
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 | |||
if (SecItemExport) { | |||
err = SecItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data); | |||
if (err != noErr) { | |||
continue; | |||
} | |||
} else | |||
#endif | |||
if (data == NULL) { | |||
err = SecKeychainItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data); | |||
if (err != noErr) { | |||
continue; | |||
} | |||
} | |||
if (data != NULL) { | |||
CFDataAppendBytes(combinedData, CFDataGetBytePtr(data), CFDataGetLength(data)); | |||
CFRelease(data); | |||
} | |||
} | |||
CFRelease(certs); | |||
*pemRoots = combinedData; | |||
return 0; | |||
} | |||
*/ | |||
import "C" | |||
import ( | |||
"crypto/x509" | |||
"unsafe" | |||
) | |||
func initDefaultRoots() { | |||
roots := x509.NewCertPool() | |||
var data C.CFDataRef = nil | |||
err := C.FetchPEMRoots(&data) | |||
if err != -1 { | |||
defer C.CFRelease(C.CFTypeRef(data)) | |||
buf := C.GoBytes(unsafe.Pointer(C.CFDataGetBytePtr(data)), C.int(C.CFDataGetLength(data))) | |||
roots.AppendCertsFromPEM(buf) | |||
} | |||
varDefaultRoots = roots | |||
} |
@@ -0,0 +1,8 @@ | |||
// Copyright 2011 The Go Authors. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
package tls | |||
func initDefaultRoots() { | |||
} |
@@ -0,0 +1,36 @@ | |||
// Copyright 2011 The Go Authors. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
package tls | |||
import ( | |||
"testing" | |||
) | |||
var tlsServers = []string{ | |||
"google.com:443", | |||
"github.com:443", | |||
"twitter.com:443", | |||
} | |||
func TestOSCertBundles(t *testing.T) { | |||
defaultRoots() | |||
if testing.Short() { | |||
t.Logf("skipping certificate tests in short mode") | |||
return | |||
} | |||
for _, addr := range tlsServers { | |||
conn, err := Dial("tcp", addr, nil) | |||
if err != nil { | |||
t.Errorf("unable to verify %v: %v", addr, err) | |||
continue | |||
} | |||
err = conn.Close() | |||
if err != nil { | |||
t.Error(err) | |||
} | |||
} | |||
} |
@@ -0,0 +1,27 @@ | |||
// Copyright 2011 The Go Authors. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
package tls | |||
import ( | |||
"crypto/x509" | |||
"io/ioutil" | |||
) | |||
// Possible certificate files; stop after finding one. | |||
var certFiles = []string{ | |||
"/etc/ssl/certs/ca-certificates.crt", // Linux etc | |||
} | |||
func initDefaultRoots() { | |||
roots := x509.NewCertPool() | |||
for _, file := range certFiles { | |||
data, err := ioutil.ReadFile(file) | |||
if err == nil { | |||
roots.AppendCertsFromPEM(data) | |||
break | |||
} | |||
} | |||
varDefaultRoots = roots | |||
} |