2020-05-14 19:09:55 +02:00
// Copyright (C) MongoDB, Inc. 2017-present.
//
// 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
package options
2022-01-18 15:28:46 +01:00
import (
"crypto/tls"
"fmt"
)
2020-05-14 19:09:55 +02:00
// ClientEncryptionOptions represents all possible options used to configure a ClientEncryption instance.
type ClientEncryptionOptions struct {
KeyVaultNamespace string
KmsProviders map [ string ] map [ string ] interface { }
2022-01-18 15:28:46 +01:00
TLSConfig map [ string ] * tls . Config
2020-05-14 19:09:55 +02:00
}
// ClientEncryption creates a new ClientEncryptionOptions instance.
func ClientEncryption ( ) * ClientEncryptionOptions {
return & ClientEncryptionOptions { }
}
// SetKeyVaultNamespace specifies the namespace of the key vault collection. This is required.
func ( c * ClientEncryptionOptions ) SetKeyVaultNamespace ( ns string ) * ClientEncryptionOptions {
c . KeyVaultNamespace = ns
return c
}
// SetKmsProviders specifies options for KMS providers. This is required.
func ( c * ClientEncryptionOptions ) SetKmsProviders ( providers map [ string ] map [ string ] interface { } ) * ClientEncryptionOptions {
c . KmsProviders = providers
return c
}
2022-01-18 15:28:46 +01:00
// SetTLSConfig specifies tls.Config instances for each KMS provider to use to configure TLS on all connections created
// to the KMS provider.
//
// This should only be used to set custom TLS configurations. By default, the connection will use an empty tls.Config{} with MinVersion set to tls.VersionTLS12.
func ( c * ClientEncryptionOptions ) SetTLSConfig ( tlsOpts map [ string ] * tls . Config ) * ClientEncryptionOptions {
tlsConfigs := make ( map [ string ] * tls . Config )
for provider , config := range tlsOpts {
// use TLS min version 1.2 to enforce more secure hash algorithms and advanced cipher suites
if config . MinVersion == 0 {
config . MinVersion = tls . VersionTLS12
}
tlsConfigs [ provider ] = config
}
c . TLSConfig = tlsConfigs
return c
}
// BuildTLSConfig specifies tls.Config options for each KMS provider to use to configure TLS on all connections created
// to the KMS provider. The input map should contain a mapping from each KMS provider to a document containing the necessary
// options, as follows:
//
// {
// "kmip": {
// "tlsCertificateKeyFile": "foo.pem",
// "tlsCAFile": "fooCA.pem"
// }
// }
//
// Currently, the following TLS options are supported:
//
// 1. "tlsCertificateKeyFile" (or "sslClientCertificateKeyFile"): The "tlsCertificateKeyFile" option specifies a path to
// the client certificate and private key, which must be concatenated into one file.
//
// 2. "tlsCertificateKeyFilePassword" (or "sslClientCertificateKeyPassword"): Specify the password to decrypt the client
// private key file (e.g. "tlsCertificateKeyFilePassword=password").
//
// 3. "tlsCaFile" (or "sslCertificateAuthorityFile"): Specify the path to a single or bundle of certificate authorities
// to be considered trusted when making a TLS connection (e.g. "tlsCaFile=/path/to/caFile").
//
// This should only be used to set custom TLS options. By default, the connection will use an empty tls.Config{} with MinVersion set to tls.VersionTLS12.
func BuildTLSConfig ( tlsOpts map [ string ] interface { } ) ( * tls . Config , error ) {
// use TLS min version 1.2 to enforce more secure hash algorithms and advanced cipher suites
cfg := & tls . Config { MinVersion : tls . VersionTLS12 }
for name := range tlsOpts {
var err error
switch name {
case "tlsCertificateKeyFile" , "sslClientCertificateKeyFile" :
clientCertPath , ok := tlsOpts [ name ] . ( string )
if ! ok {
return nil , fmt . Errorf ( "expected %q value to be of type string, got %T" , name , tlsOpts [ name ] )
}
// apply custom key file password if found, otherwise use empty string
if keyPwd , found := tlsOpts [ "tlsCertificateKeyFilePassword" ] . ( string ) ; found {
_ , err = addClientCertFromConcatenatedFile ( cfg , clientCertPath , keyPwd )
} else if keyPwd , found := tlsOpts [ "sslClientCertificateKeyPassword" ] . ( string ) ; found {
_ , err = addClientCertFromConcatenatedFile ( cfg , clientCertPath , keyPwd )
} else {
_ , err = addClientCertFromConcatenatedFile ( cfg , clientCertPath , "" )
}
case "tlsCertificateKeyFilePassword" , "sslClientCertificateKeyPassword" :
continue
case "tlsCAFile" , "sslCertificateAuthorityFile" :
caPath , ok := tlsOpts [ name ] . ( string )
if ! ok {
return nil , fmt . Errorf ( "expected %q value to be of type string, got %T" , name , tlsOpts [ name ] )
}
err = addCACertFromFile ( cfg , caPath )
default :
return nil , fmt . Errorf ( "unrecognized TLS option %v" , name )
}
if err != nil {
return nil , err
}
}
return cfg , nil
}
2020-05-14 19:09:55 +02:00
// MergeClientEncryptionOptions combines the argued ClientEncryptionOptions in a last-one wins fashion.
func MergeClientEncryptionOptions ( opts ... * ClientEncryptionOptions ) * ClientEncryptionOptions {
ceo := ClientEncryption ( )
for _ , opt := range opts {
if opt == nil {
continue
}
if opt . KeyVaultNamespace != "" {
ceo . KeyVaultNamespace = opt . KeyVaultNamespace
}
if opt . KmsProviders != nil {
ceo . KmsProviders = opt . KmsProviders
}
2022-01-18 15:28:46 +01:00
if opt . TLSConfig != nil {
ceo . TLSConfig = opt . TLSConfig
}
2020-05-14 19:09:55 +02:00
}
return ceo
}