github.com/ruphin/docker@v1.10.1/pkg/tlsconfig/config.go (about) 1 // Package tlsconfig provides primitives to retrieve secure-enough TLS configurations for both clients and servers. 2 // 3 // As a reminder from https://golang.org/pkg/crypto/tls/#Config: 4 // A Config structure is used to configure a TLS client or server. After one has been passed to a TLS function it must not be modified. 5 // A Config may be reused; the tls package will also not modify it. 6 package tlsconfig 7 8 import ( 9 "crypto/tls" 10 "crypto/x509" 11 "fmt" 12 "io/ioutil" 13 "os" 14 15 "github.com/Sirupsen/logrus" 16 ) 17 18 // Options represents the information needed to create client and server TLS configurations. 19 type Options struct { 20 CAFile string 21 22 // If either CertFile or KeyFile is empty, Client() will not load them 23 // preventing the client from authenticating to the server. 24 // However, Server() requires them and will error out if they are empty. 25 CertFile string 26 KeyFile string 27 28 // client-only option 29 InsecureSkipVerify bool 30 // server-only option 31 ClientAuth tls.ClientAuthType 32 } 33 34 // Extra (server-side) accepted CBC cipher suites - will phase out in the future 35 var acceptedCBCCiphers = []uint16{ 36 tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, 37 tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, 38 tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, 39 tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, 40 tls.TLS_RSA_WITH_AES_256_CBC_SHA, 41 tls.TLS_RSA_WITH_AES_128_CBC_SHA, 42 } 43 44 // Client TLS cipher suites (dropping CBC ciphers for client preferred suite set) 45 var clientCipherSuites = []uint16{ 46 tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 47 tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 48 } 49 50 // DefaultServerAcceptedCiphers should be uses by code which already has a crypto/tls 51 // options struct but wants to use a commonly accepted set of TLS cipher suites, with 52 // known weak algorithms removed. 53 var DefaultServerAcceptedCiphers = append(clientCipherSuites, acceptedCBCCiphers...) 54 55 // ServerDefault is a secure-enough TLS configuration for the server TLS configuration. 56 var ServerDefault = tls.Config{ 57 // Avoid fallback to SSL protocols < TLS1.0 58 MinVersion: tls.VersionTLS10, 59 PreferServerCipherSuites: true, 60 CipherSuites: DefaultServerAcceptedCiphers, 61 } 62 63 // ClientDefault is a secure-enough TLS configuration for the client TLS configuration. 64 var ClientDefault = tls.Config{ 65 // Prefer TLS1.2 as the client minimum 66 MinVersion: tls.VersionTLS12, 67 CipherSuites: clientCipherSuites, 68 } 69 70 // certPool returns an X.509 certificate pool from `caFile`, the certificate file. 71 func certPool(caFile string) (*x509.CertPool, error) { 72 // If we should verify the server, we need to load a trusted ca 73 certPool := x509.NewCertPool() 74 pem, err := ioutil.ReadFile(caFile) 75 if err != nil { 76 return nil, fmt.Errorf("Could not read CA certificate %q: %v", caFile, err) 77 } 78 if !certPool.AppendCertsFromPEM(pem) { 79 return nil, fmt.Errorf("failed to append certificates from PEM file: %q", caFile) 80 } 81 s := certPool.Subjects() 82 subjects := make([]string, len(s)) 83 for i, subject := range s { 84 subjects[i] = string(subject) 85 } 86 logrus.Debugf("Trusting certs with subjects: %v", subjects) 87 return certPool, nil 88 } 89 90 // Client returns a TLS configuration meant to be used by a client. 91 func Client(options Options) (*tls.Config, error) { 92 tlsConfig := ClientDefault 93 tlsConfig.InsecureSkipVerify = options.InsecureSkipVerify 94 if !options.InsecureSkipVerify { 95 CAs, err := certPool(options.CAFile) 96 if err != nil { 97 return nil, err 98 } 99 tlsConfig.RootCAs = CAs 100 } 101 102 if options.CertFile != "" && options.KeyFile != "" { 103 tlsCert, err := tls.LoadX509KeyPair(options.CertFile, options.KeyFile) 104 if err != nil { 105 return nil, fmt.Errorf("Could not load X509 key pair: %v. Make sure the key is not encrypted", err) 106 } 107 tlsConfig.Certificates = []tls.Certificate{tlsCert} 108 } 109 110 return &tlsConfig, nil 111 } 112 113 // Server returns a TLS configuration meant to be used by a server. 114 func Server(options Options) (*tls.Config, error) { 115 tlsConfig := ServerDefault 116 tlsConfig.ClientAuth = options.ClientAuth 117 tlsCert, err := tls.LoadX509KeyPair(options.CertFile, options.KeyFile) 118 if err != nil { 119 if os.IsNotExist(err) { 120 return nil, fmt.Errorf("Could not load X509 key pair (cert: %q, key: %q): %v", options.CertFile, options.KeyFile, err) 121 } 122 return nil, fmt.Errorf("Error reading X509 key pair (cert: %q, key: %q): %v. Make sure the key is not encrypted.", options.CertFile, options.KeyFile, err) 123 } 124 tlsConfig.Certificates = []tls.Certificate{tlsCert} 125 if options.ClientAuth >= tls.VerifyClientCertIfGiven { 126 CAs, err := certPool(options.CAFile) 127 if err != nil { 128 return nil, err 129 } 130 tlsConfig.ClientCAs = CAs 131 } 132 return &tlsConfig, nil 133 }