1package tlsutil 2 3import ( 4 "crypto/tls" 5 "crypto/x509" 6 "errors" 7 "fmt" 8 9 "github.com/hashicorp/vault/sdk/helper/strutil" 10) 11 12var ErrInvalidCertParams = errors.New("invalid certificate parameters") 13 14// TLSLookup maps the tls_min_version configuration to the internal value 15var TLSLookup = map[string]uint16{ 16 "tls10": tls.VersionTLS10, 17 "tls11": tls.VersionTLS11, 18 "tls12": tls.VersionTLS12, 19} 20 21// cipherMap maps the cipher suite names to the internal cipher suite code. 22var cipherMap = map[string]uint16{ 23 "TLS_RSA_WITH_RC4_128_SHA": tls.TLS_RSA_WITH_RC4_128_SHA, 24 "TLS_RSA_WITH_3DES_EDE_CBC_SHA": tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA, 25 "TLS_RSA_WITH_AES_128_CBC_SHA": tls.TLS_RSA_WITH_AES_128_CBC_SHA, 26 "TLS_RSA_WITH_AES_256_CBC_SHA": tls.TLS_RSA_WITH_AES_256_CBC_SHA, 27 "TLS_RSA_WITH_AES_128_CBC_SHA256": tls.TLS_RSA_WITH_AES_128_CBC_SHA256, 28 "TLS_RSA_WITH_AES_128_GCM_SHA256": tls.TLS_RSA_WITH_AES_128_GCM_SHA256, 29 "TLS_RSA_WITH_AES_256_GCM_SHA384": tls.TLS_RSA_WITH_AES_256_GCM_SHA384, 30 "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA": tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, 31 "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, 32 "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA": tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, 33 "TLS_ECDHE_RSA_WITH_RC4_128_SHA": tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA, 34 "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, 35 "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, 36 "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, 37 "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, 38 "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256": tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, 39 "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256": tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 40 "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 41 "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384": tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 42 "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384": tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, 43 "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305": tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, 44 "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305": tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, 45} 46 47// ParseCiphers parse ciphersuites from the comma-separated string into recognized slice 48func ParseCiphers(cipherStr string) ([]uint16, error) { 49 suites := []uint16{} 50 ciphers := strutil.ParseStringSlice(cipherStr, ",") 51 for _, cipher := range ciphers { 52 if v, ok := cipherMap[cipher]; ok { 53 suites = append(suites, v) 54 } else { 55 return suites, fmt.Errorf("unsupported cipher %q", cipher) 56 } 57 } 58 59 return suites, nil 60} 61 62// GetCipherName returns the name of a given cipher suite code or an error if the 63// given cipher is unsupported. 64func GetCipherName(cipher uint16) (string, error) { 65 for cipherStr, cipherCode := range cipherMap { 66 if cipherCode == cipher { 67 return cipherStr, nil 68 } 69 } 70 return "", fmt.Errorf("unsupported cipher %d", cipher) 71} 72 73func ClientTLSConfig(caCert []byte, clientCert []byte, clientKey []byte) (*tls.Config, error) { 74 var tlsConfig *tls.Config 75 var pool *x509.CertPool 76 77 switch { 78 case len(caCert) != 0: 79 // Valid 80 case len(clientCert) != 0 && len(clientKey) != 0: 81 // Valid 82 default: 83 return nil, ErrInvalidCertParams 84 } 85 86 if len(caCert) != 0 { 87 pool = x509.NewCertPool() 88 pool.AppendCertsFromPEM(caCert) 89 } 90 91 tlsConfig = &tls.Config{ 92 RootCAs: pool, 93 ClientAuth: tls.RequireAndVerifyClientCert, 94 MinVersion: tls.VersionTLS12, 95 } 96 97 var cert tls.Certificate 98 var err error 99 if len(clientCert) != 0 && len(clientKey) != 0 { 100 cert, err = tls.X509KeyPair(clientCert, clientKey) 101 if err != nil { 102 return nil, err 103 } 104 tlsConfig.Certificates = []tls.Certificate{cert} 105 } 106 tlsConfig.BuildNameToCertificate() 107 108 return tlsConfig, nil 109} 110