summaryrefslogtreecommitdiff
path: root/src/mongo/gotools/common/db/tlsgo
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/gotools/common/db/tlsgo')
-rw-r--r--src/mongo/gotools/common/db/tlsgo/config.go246
-rw-r--r--src/mongo/gotools/common/db/tlsgo/config_test.go41
-rw-r--r--src/mongo/gotools/common/db/tlsgo/rootcerts.go22
-rw-r--r--src/mongo/gotools/common/db/tlsgo/rootcerts_darwin.go58
-rw-r--r--src/mongo/gotools/common/db/tlsgo/testdata/pkcs1-encrypted-rev.pem51
-rw-r--r--src/mongo/gotools/common/db/tlsgo/testdata/pkcs1-encrypted.pem51
-rw-r--r--src/mongo/gotools/common/db/tlsgo/testdata/pkcs1-rev.pem48
-rw-r--r--src/mongo/gotools/common/db/tlsgo/testdata/pkcs1.pem48
-rw-r--r--src/mongo/gotools/common/db/tlsgo/testdata/pkcs8-encrypted-rev.pem51
-rw-r--r--src/mongo/gotools/common/db/tlsgo/testdata/pkcs8-encrypted.pem51
-rw-r--r--src/mongo/gotools/common/db/tlsgo/testdata/pkcs8-rev.pem50
-rw-r--r--src/mongo/gotools/common/db/tlsgo/testdata/pkcs8.pem50
-rw-r--r--src/mongo/gotools/common/db/tlsgo/tlsgo.go135
13 files changed, 902 insertions, 0 deletions
diff --git a/src/mongo/gotools/common/db/tlsgo/config.go b/src/mongo/gotools/common/db/tlsgo/config.go
new file mode 100644
index 00000000000..8d3971b537b
--- /dev/null
+++ b/src/mongo/gotools/common/db/tlsgo/config.go
@@ -0,0 +1,246 @@
+// Copyright (C) MongoDB, Inc. 2018-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
+
+// This file contains code adapted from the MongoDB Go Driver.
+
+// Package tlsgo provides a mgo connection using Go's native TLS library.
+package tlsgo
+
+import (
+ "crypto/tls"
+ "crypto/x509"
+ "encoding/asn1"
+ "encoding/hex"
+ "encoding/pem"
+ "fmt"
+ "io/ioutil"
+ "strings"
+)
+
+// TLSConfig contains options for configuring an SSL connection to the server.
+type TLSConfig struct {
+ caCert *x509.Certificate
+ clientCert *tls.Certificate
+ insecure bool
+}
+
+// NewTLSConfig creates a new TLSConfig.
+func NewTLSConfig() *TLSConfig {
+ cfg := &TLSConfig{}
+
+ return cfg
+}
+
+// SetInsecure sets whether the client should verify the server's certificate chain and hostnames.
+func (c *TLSConfig) SetInsecure(allow bool) {
+ c.insecure = allow
+}
+
+// AddClientCertFromFile adds a client certificate to the configuration given a path to the
+// containing file and returns the certificate's subject name.
+func (c *TLSConfig) AddClientCertFromFile(clientFile, password string) (string, error) {
+ data, err := ioutil.ReadFile(clientFile)
+ if err != nil {
+ return "", err
+ }
+
+ certPEM, err := loadPEMBlock(data, "CERTIFICATE")
+ if err != nil {
+ return "", err
+ }
+
+ keyPEM, err := loadPEMBlock(data, "PRIVATE KEY")
+ if err != nil {
+ return "", err
+ }
+ // This check only covers encrypted PEM data with a DEK-Info header. It
+ // does not detect unencrypted PEM containing PKCS#8 format data with an
+ // encrypted private key.
+ if x509.IsEncryptedPEMBlock(keyPEM) {
+ if password == "" {
+ return "", fmt.Errorf("No password provided to decrypt private key")
+ }
+ decrypted, err := x509.DecryptPEMBlock(keyPEM, []byte(password))
+ if err != nil {
+ return "", err
+ }
+ keyPEM = &pem.Block{Bytes: decrypted, Type: keyPEM.Type}
+ }
+
+ if strings.Contains(keyPEM.Type, "ENCRYPTED") {
+ return "", fmt.Errorf("PKCS#8 encrypted private keys are not supported")
+ }
+
+ cert, err := tls.X509KeyPair(pem.EncodeToMemory(certPEM), pem.EncodeToMemory(keyPEM))
+ if err != nil {
+ return "", err
+ }
+
+ c.clientCert = &cert
+
+ // The documentation for the tls.X509KeyPair indicates that the Leaf
+ // certificate is not retained. Because there isn't any way of creating a
+ // tls.Certificate from an x509.Certificate short of calling X509KeyPair
+ // on the raw bytes, we're forced to parse the certificate over again to
+ // get the subject name.
+ crt, err := x509.ParseCertificate(certPEM.Bytes)
+ if err != nil {
+ return "", err
+ }
+
+ return x509CertSubject(crt), nil
+}
+
+// AddCaCertFromFile adds a root CA certificate to the configuration given a path to the containing file.
+func (c *TLSConfig) AddCaCertFromFile(caFile string) error {
+ data, err := ioutil.ReadFile(caFile)
+ if err != nil {
+ return err
+ }
+
+ certBytes, err := loadCertBytes(data)
+ if err != nil {
+ return err
+ }
+
+ cert, err := x509.ParseCertificate(certBytes)
+ if err != nil {
+ return err
+ }
+
+ c.caCert = cert
+
+ return nil
+}
+
+// MakeConfig constructs a new tls.Config from the configuration specified.
+func (c *TLSConfig) MakeConfig() (*tls.Config, error) {
+ cfg := &tls.Config{}
+
+ if c.clientCert != nil {
+ cfg.Certificates = []tls.Certificate{*c.clientCert}
+ }
+
+ if c.caCert == nil {
+ roots, err := loadSystemCAs()
+ if err != nil {
+ return nil, err
+ }
+ cfg.RootCAs = roots
+ } else {
+ cfg.RootCAs = x509.NewCertPool()
+ cfg.RootCAs.AddCert(c.caCert)
+ }
+
+ cfg.InsecureSkipVerify = c.insecure
+
+ return cfg, nil
+}
+
+func loadCertBytes(data []byte) ([]byte, error) {
+ b, err := loadPEMBlock(data, "CERTIFICATE")
+ if err != nil {
+ return nil, err
+ }
+ return b.Bytes, nil
+}
+
+func loadPEMBlock(data []byte, blocktype string) (*pem.Block, error) {
+ var b *pem.Block
+
+ for b == nil {
+ if data == nil || len(data) == 0 {
+ return nil, fmt.Errorf("no block of type %s found in .pem file", blocktype)
+ }
+
+ block, rest := pem.Decode(data)
+ if block == nil {
+ return nil, fmt.Errorf("invalid .pem file")
+ }
+
+ if strings.Contains(block.Type, blocktype) {
+ if b != nil {
+ return nil, fmt.Errorf("multiple %s sections in .pem file", blocktype)
+ }
+ b = block
+ }
+
+ data = rest
+ }
+
+ return b, nil
+}
+
+// Because the functionality to convert a pkix.Name to a string wasn't added until Go 1.10, we
+// need to copy the implementation (along with the attributeTypeNames map below).
+func x509CertSubject(cert *x509.Certificate) string {
+ r := cert.Subject.ToRDNSequence()
+
+ s := ""
+ for i := 0; i < len(r); i++ {
+ rdn := r[len(r)-1-i]
+ if i > 0 {
+ s += ","
+ }
+ for j, tv := range rdn {
+ if j > 0 {
+ s += "+"
+ }
+
+ oidString := tv.Type.String()
+ typeName, ok := attributeTypeNames[oidString]
+ if !ok {
+ derBytes, err := asn1.Marshal(tv.Value)
+ if err == nil {
+ s += oidString + "=#" + hex.EncodeToString(derBytes)
+ continue // No value escaping necessary.
+ }
+
+ typeName = oidString
+ }
+
+ valueString := fmt.Sprint(tv.Value)
+ escaped := make([]rune, 0, len(valueString))
+
+ for k, c := range valueString {
+ escape := false
+
+ switch c {
+ case ',', '+', '"', '\\', '<', '>', ';':
+ escape = true
+
+ case ' ':
+ escape = k == 0 || k == len(valueString)-1
+
+ case '#':
+ escape = k == 0
+ }
+
+ if escape {
+ escaped = append(escaped, '\\', c)
+ } else {
+ escaped = append(escaped, c)
+ }
+ }
+
+ s += typeName + "=" + string(escaped)
+ }
+ }
+
+ return s
+}
+
+var attributeTypeNames = map[string]string{
+ "2.5.4.6": "C",
+ "2.5.4.10": "O",
+ "2.5.4.11": "OU",
+ "2.5.4.3": "CN",
+ "2.5.4.5": "SERIALNUMBER",
+ "2.5.4.7": "L",
+ "2.5.4.8": "ST",
+ "2.5.4.9": "STREET",
+ "2.5.4.17": "POSTALCODE",
+}
diff --git a/src/mongo/gotools/common/db/tlsgo/config_test.go b/src/mongo/gotools/common/db/tlsgo/config_test.go
new file mode 100644
index 00000000000..7eb09b8643c
--- /dev/null
+++ b/src/mongo/gotools/common/db/tlsgo/config_test.go
@@ -0,0 +1,41 @@
+package tlsgo
+
+import (
+ "strings"
+ "testing"
+)
+
+func TestAddClientCert(t *testing.T) {
+ cases := []struct {
+ Path string
+ Pass string
+ Valid bool
+ }{
+ {Path: "testdata/pkcs1.pem", Valid: true},
+ {Path: "testdata/pkcs1-rev.pem", Valid: true},
+ {Path: "testdata/pkcs1-encrypted.pem", Pass: "qwerty", Valid: true},
+ {Path: "testdata/pkcs1-encrypted-rev.pem", Pass: "qwerty", Valid: true},
+
+ {Path: "testdata/pkcs8.pem", Valid: true},
+ {Path: "testdata/pkcs8-rev.pem", Valid: true},
+ {Path: "testdata/pkcs8-encrypted.pem", Valid: false},
+ {Path: "testdata/pkcs8-encrypted-rev.pem", Valid: false},
+ }
+
+ for _, v := range cases {
+ tlsc := NewTLSConfig()
+ _, err := tlsc.AddClientCertFromFile(v.Path, v.Pass)
+ switch v.Valid {
+ case true:
+ if err != nil {
+ t.Errorf("Error parsing %s: %s", v.Path, err.Error())
+ }
+ case false:
+ if err == nil {
+ t.Errorf("Expected error parsing %s but parsed OK", v.Path)
+ } else if !strings.Contains(err.Error(), "encrypted private keys are not supported") {
+ t.Errorf("Incorrect error for %s: %s", v.Path, err.Error())
+ }
+ }
+ }
+}
diff --git a/src/mongo/gotools/common/db/tlsgo/rootcerts.go b/src/mongo/gotools/common/db/tlsgo/rootcerts.go
new file mode 100644
index 00000000000..ee3ec3769f1
--- /dev/null
+++ b/src/mongo/gotools/common/db/tlsgo/rootcerts.go
@@ -0,0 +1,22 @@
+// Copyright (C) MongoDB, Inc. 2018-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
+//
+// Based on https://github.com/hashicorp/go-rootcerts by HashiCorp
+// See THIRD-PARTY-NOTICES for original license terms.
+
+// +build !darwin
+
+package tlsgo
+
+import (
+ "crypto/x509"
+)
+
+// Stubbed for non-darwin systems. By returning nil, the Go library
+// will use its own code for finding system certs.
+func loadSystemCAs() (*x509.CertPool, error) {
+ return nil, nil
+}
diff --git a/src/mongo/gotools/common/db/tlsgo/rootcerts_darwin.go b/src/mongo/gotools/common/db/tlsgo/rootcerts_darwin.go
new file mode 100644
index 00000000000..72c7a9116ad
--- /dev/null
+++ b/src/mongo/gotools/common/db/tlsgo/rootcerts_darwin.go
@@ -0,0 +1,58 @@
+// Copyright (C) MongoDB, Inc. 2018-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
+//
+// Based on https://github.com/hashicorp/go-rootcerts by HashiCorp
+// See THIRD-PARTY-NOTICES for original license terms.
+
+package tlsgo
+
+import (
+ "crypto/x509"
+ "os/exec"
+ "os/user"
+ "path"
+)
+
+// loadSystemCAs has special behavior on Darwin systems to work around
+// bugs loading certs from keychains. See this GitHub issues query:
+// https://github.com/golang/go/issues?utf8=%E2%9C%93&q=is%3Aissue+darwin+keychain
+func loadSystemCAs() (*x509.CertPool, error) {
+ pool := x509.NewCertPool()
+
+ for _, keychain := range certKeychains() {
+ err := addCertsFromKeychain(pool, keychain)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ return pool, nil
+}
+
+func addCertsFromKeychain(pool *x509.CertPool, keychain string) error {
+ cmd := exec.Command("/usr/bin/security", "find-certificate", "-a", "-p", keychain)
+ data, err := cmd.Output()
+ if err != nil {
+ return err
+ }
+
+ pool.AppendCertsFromPEM(data)
+
+ return nil
+}
+
+func certKeychains() []string {
+ keychains := []string{
+ "/System/Library/Keychains/SystemRootCertificates.keychain",
+ "/Library/Keychains/System.keychain",
+ }
+ user, err := user.Current()
+ if err == nil {
+ loginKeychain := path.Join(user.HomeDir, "Library", "Keychains", "login.keychain")
+ keychains = append(keychains, loginKeychain)
+ }
+ return keychains
+}
diff --git a/src/mongo/gotools/common/db/tlsgo/testdata/pkcs1-encrypted-rev.pem b/src/mongo/gotools/common/db/tlsgo/testdata/pkcs1-encrypted-rev.pem
new file mode 100644
index 00000000000..308e2263d4a
--- /dev/null
+++ b/src/mongo/gotools/common/db/tlsgo/testdata/pkcs1-encrypted-rev.pem
@@ -0,0 +1,51 @@
+-----BEGIN CERTIFICATE-----
+MIIDfjCCAmagAwIBAgIDBUEVMA0GCSqGSIb3DQEBBQUAMHQxFzAVBgNVBAMTDktl
+cm5lbCBUZXN0IENBMQ8wDQYDVQQLEwZLZXJuZWwxEDAOBgNVBAoTB01vbmdvREIx
+FjAUBgNVBAcTDU5ldyBZb3JrIENpdHkxETAPBgNVBAgTCE5ldyBZb3JrMQswCQYD
+VQQGEwJVUzAeFw0xNjA5MjIxODE1MTJaFw0zNjA5MjIxODE1MTJaMG8xEjAQBgNV
+BAMTCWxvY2FsaG9zdDEPMA0GA1UECxMGS2VybmVsMRAwDgYDVQQKEwdNb25nb0RC
+MRYwFAYDVQQHEw1OZXcgWW9yayBDaXR5MREwDwYDVQQIEwhOZXcgWW9yazELMAkG
+A1UEBhMCVVMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCTHMXV0LEZ
+OCuDZ292e26NbbrMaib6IL3obp/5tOvNVCNnvfgYyJwCCTIZq/mwCjAV5N8Y7tJM
+v0JrrGIWgJ3qtPMQ/1VxfzLLW598nnBuqZG2HiR3CTfhd0JBmnjKDMscz90+xB2x
+DUDVe6PkbZWnN2otsBzVbW+AAJRVTgUb3cjSbGcC0eTMg3SGaWiB+DtiJIAe3bl8
+6TTmrUKVvbzbJrdrFWpz+NVxf5ejZje+Wlz6OXgkWki5U41PtA7aDFIX3mo1J3c0
+jW957fC/q76jrBoTCbufYPaLQIb5QSex+aJZ40rHpSSV75tsXNUkn22u83Bes+Ih
+X0As7g5kW2TDAgMBAAGjHjAcMBoGA1UdEQQTMBGCCWxvY2FsaG9zdIcEfwAAATAN
+BgkqhkiG9w0BAQUFAAOCAQEAEDzWG64/IlXSEFQZom1z0uBLSLVaxrNg4se6geLH
+Bt63EW78H+JMf97AA32DsDiT3ih5uo8yUcOVoEUwontUOSjekHrYfagF/KxMvyMy
+sWX+8m5SLrU6s4FysUCtlXa92g1Nh/rET074U2sNShhALgNB2XSw9P5n9GnKt5VT
+Rkh0AeBJd09WcOGnSHs30+kKGNV8A5a2GTJbDma0dLa7zlhV6VU91Z9LA0aamyrX
+eWwnymJvRcIYvxGqgNDxN/8MsaU1EcW0MNEDkc+kDE1LbOwlAQbCeLQDq/w6AlmC
+smoCi0pp6Bf8tZM2RhcUN/xXxgEKcZzhlDOI4v8RNHOyMg==
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-CBC,B57A03692CDD397E50317A829B4A4698
+
+V/V8LyrTJtyxBZYcodeO7xyS/+pmjmbEEYWC6ugP+MgeStTINrjfiYbc3QPkfUEg
+SpWFgeq6rFbnszeWrcuk9U0NCv+vg3SjMuprrisCJerpv9bCldF9lbbqElL6o3ov
+Q3EIS5JJWxXOJN/FAvTF4nNhh+0aasMmnZyHZMsT2aqBrswDQ7h51wCV4IRHk5Xr
+StqjV314kQHMRQfybYkPKZkABtpghSLGGLguwch1cbKPCKHTinFuIuZGHJlQmnOz
+tfXtnjlrAG7LtyfddrTlWkm/fGF6lhewC15HLLgpNVkLmFtHCyOtDVTkInT6CM+x
+DaDnXebj4gghvJ0kmm7uX3rLX/pvnne+iNpNLaZcjVx20+iGhYaJdy4yUq+nH/UU
++dHlyublzcsDHmZG8CX297DT5kRgkH6Nh3VQdhygQNRNCEHQbR8Gsff/3bJ+KDO8
+6vw/xtcjnbIsOVM8Wxp+lkvKmwk+tTVEhL4bG/+6sq1Cd9jDnf0fzWx7t+IA4t/Y
+OJ2K65T6I7QVgu0y3jSyLN1MH3oLPF3VGlF6NZlRZUObDL/HzWCFWCpBMtdAxfjI
+Wxh5QyQix5lo9IuvYMYmCGk6d+N/fhpLmp3mcURkZrSZCIvfLFF7jrlO4z68j0Os
+XODkuYgBXhHKf+tYc0Scokd5cbHlLZ986ngPsSClTtdovouHMxRfWoLQBdlXvxi0
+CjC7SRPuvLSSRLXzF72Htgb7U/W+JflSwvpZrO8VJ7ngR4sU2s1fO1K7x+fLIHEx
+M1V6OTQfmJoumg6DIYqAqO8QD6JVIn+JfZ8Ympt7zFaPCJtpxxmKjmpQ1BWatDP6
+dLrdxW9uV6VKYBQuVv+k+jFcjNMrRfJHfeUxrOjCIo3dUDfju+DOdJUAMxWPzdZZ
+OmcTG/4AIzw0BJirIAuAsz1RE3V8UXjefnO3YOBZMJPx22iBOacRtcYZXX5Vi/hs
+UMmBWrjrsgmtb8KxIvDED3fnfWI6JdK92x+yIJAOB920z//XP1XmiLV6QjwXgXIw
+g85ZceCh7Z6E62GYRQ3xboelbKlOzeRXqwM9Tz75677pqnloeEZfN/0GCABX4SAi
+jDmb1dt9DiwHsVnt2zvY85V14qNq5QkCTkD+34l+ASLrwgYj8iJ8f3NQMXvBatY0
+eKUonwjSD0odxgvgdwvGlsx1++ec6TWB7jUD/dLxPqPy+m+SpsrxmJG9/WxFXIA/
+UHcW8n5xy1D1mKgeGxTPgWLwYlbcLD3HBaIFj6s9vDfP7+ztcg6Xdsslf8irHByp
+JZgnG3ptQFAVEftM7oWvM2eXdBp1mgxuSGgZohURNOAdW0m5VEsmMp95k/iN4vXI
++aTYuVmeWJhQY9pvRW38RDhwxBXIiN2dCkijUPHCi7fc1k9ox06rGsX3doW6UBu+
+H45w0BTVpJR8kv7y+Ep5yd0VTKnGy16PVL/K9GqNahzwb72JxLP+hI4Amlp7rSAG
+Mfq0O3SvSrDks5PsPgBHEKnBfMMgKgTQOWICLtFG7Xoh1aJA9ykge2TniaUZeRuN
+Wm4FEDBqhCEZpOOFdtq/P9v8KV/IDuyMhFEMb6tSn9P6EDTIS7feJnhXn7JFMdJT
+-----END RSA PRIVATE KEY-----
diff --git a/src/mongo/gotools/common/db/tlsgo/testdata/pkcs1-encrypted.pem b/src/mongo/gotools/common/db/tlsgo/testdata/pkcs1-encrypted.pem
new file mode 100644
index 00000000000..fa92cebe1d7
--- /dev/null
+++ b/src/mongo/gotools/common/db/tlsgo/testdata/pkcs1-encrypted.pem
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-CBC,B57A03692CDD397E50317A829B4A4698
+
+V/V8LyrTJtyxBZYcodeO7xyS/+pmjmbEEYWC6ugP+MgeStTINrjfiYbc3QPkfUEg
+SpWFgeq6rFbnszeWrcuk9U0NCv+vg3SjMuprrisCJerpv9bCldF9lbbqElL6o3ov
+Q3EIS5JJWxXOJN/FAvTF4nNhh+0aasMmnZyHZMsT2aqBrswDQ7h51wCV4IRHk5Xr
+StqjV314kQHMRQfybYkPKZkABtpghSLGGLguwch1cbKPCKHTinFuIuZGHJlQmnOz
+tfXtnjlrAG7LtyfddrTlWkm/fGF6lhewC15HLLgpNVkLmFtHCyOtDVTkInT6CM+x
+DaDnXebj4gghvJ0kmm7uX3rLX/pvnne+iNpNLaZcjVx20+iGhYaJdy4yUq+nH/UU
++dHlyublzcsDHmZG8CX297DT5kRgkH6Nh3VQdhygQNRNCEHQbR8Gsff/3bJ+KDO8
+6vw/xtcjnbIsOVM8Wxp+lkvKmwk+tTVEhL4bG/+6sq1Cd9jDnf0fzWx7t+IA4t/Y
+OJ2K65T6I7QVgu0y3jSyLN1MH3oLPF3VGlF6NZlRZUObDL/HzWCFWCpBMtdAxfjI
+Wxh5QyQix5lo9IuvYMYmCGk6d+N/fhpLmp3mcURkZrSZCIvfLFF7jrlO4z68j0Os
+XODkuYgBXhHKf+tYc0Scokd5cbHlLZ986ngPsSClTtdovouHMxRfWoLQBdlXvxi0
+CjC7SRPuvLSSRLXzF72Htgb7U/W+JflSwvpZrO8VJ7ngR4sU2s1fO1K7x+fLIHEx
+M1V6OTQfmJoumg6DIYqAqO8QD6JVIn+JfZ8Ympt7zFaPCJtpxxmKjmpQ1BWatDP6
+dLrdxW9uV6VKYBQuVv+k+jFcjNMrRfJHfeUxrOjCIo3dUDfju+DOdJUAMxWPzdZZ
+OmcTG/4AIzw0BJirIAuAsz1RE3V8UXjefnO3YOBZMJPx22iBOacRtcYZXX5Vi/hs
+UMmBWrjrsgmtb8KxIvDED3fnfWI6JdK92x+yIJAOB920z//XP1XmiLV6QjwXgXIw
+g85ZceCh7Z6E62GYRQ3xboelbKlOzeRXqwM9Tz75677pqnloeEZfN/0GCABX4SAi
+jDmb1dt9DiwHsVnt2zvY85V14qNq5QkCTkD+34l+ASLrwgYj8iJ8f3NQMXvBatY0
+eKUonwjSD0odxgvgdwvGlsx1++ec6TWB7jUD/dLxPqPy+m+SpsrxmJG9/WxFXIA/
+UHcW8n5xy1D1mKgeGxTPgWLwYlbcLD3HBaIFj6s9vDfP7+ztcg6Xdsslf8irHByp
+JZgnG3ptQFAVEftM7oWvM2eXdBp1mgxuSGgZohURNOAdW0m5VEsmMp95k/iN4vXI
++aTYuVmeWJhQY9pvRW38RDhwxBXIiN2dCkijUPHCi7fc1k9ox06rGsX3doW6UBu+
+H45w0BTVpJR8kv7y+Ep5yd0VTKnGy16PVL/K9GqNahzwb72JxLP+hI4Amlp7rSAG
+Mfq0O3SvSrDks5PsPgBHEKnBfMMgKgTQOWICLtFG7Xoh1aJA9ykge2TniaUZeRuN
+Wm4FEDBqhCEZpOOFdtq/P9v8KV/IDuyMhFEMb6tSn9P6EDTIS7feJnhXn7JFMdJT
+-----END RSA PRIVATE KEY-----
+-----BEGIN CERTIFICATE-----
+MIIDfjCCAmagAwIBAgIDBUEVMA0GCSqGSIb3DQEBBQUAMHQxFzAVBgNVBAMTDktl
+cm5lbCBUZXN0IENBMQ8wDQYDVQQLEwZLZXJuZWwxEDAOBgNVBAoTB01vbmdvREIx
+FjAUBgNVBAcTDU5ldyBZb3JrIENpdHkxETAPBgNVBAgTCE5ldyBZb3JrMQswCQYD
+VQQGEwJVUzAeFw0xNjA5MjIxODE1MTJaFw0zNjA5MjIxODE1MTJaMG8xEjAQBgNV
+BAMTCWxvY2FsaG9zdDEPMA0GA1UECxMGS2VybmVsMRAwDgYDVQQKEwdNb25nb0RC
+MRYwFAYDVQQHEw1OZXcgWW9yayBDaXR5MREwDwYDVQQIEwhOZXcgWW9yazELMAkG
+A1UEBhMCVVMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCTHMXV0LEZ
+OCuDZ292e26NbbrMaib6IL3obp/5tOvNVCNnvfgYyJwCCTIZq/mwCjAV5N8Y7tJM
+v0JrrGIWgJ3qtPMQ/1VxfzLLW598nnBuqZG2HiR3CTfhd0JBmnjKDMscz90+xB2x
+DUDVe6PkbZWnN2otsBzVbW+AAJRVTgUb3cjSbGcC0eTMg3SGaWiB+DtiJIAe3bl8
+6TTmrUKVvbzbJrdrFWpz+NVxf5ejZje+Wlz6OXgkWki5U41PtA7aDFIX3mo1J3c0
+jW957fC/q76jrBoTCbufYPaLQIb5QSex+aJZ40rHpSSV75tsXNUkn22u83Bes+Ih
+X0As7g5kW2TDAgMBAAGjHjAcMBoGA1UdEQQTMBGCCWxvY2FsaG9zdIcEfwAAATAN
+BgkqhkiG9w0BAQUFAAOCAQEAEDzWG64/IlXSEFQZom1z0uBLSLVaxrNg4se6geLH
+Bt63EW78H+JMf97AA32DsDiT3ih5uo8yUcOVoEUwontUOSjekHrYfagF/KxMvyMy
+sWX+8m5SLrU6s4FysUCtlXa92g1Nh/rET074U2sNShhALgNB2XSw9P5n9GnKt5VT
+Rkh0AeBJd09WcOGnSHs30+kKGNV8A5a2GTJbDma0dLa7zlhV6VU91Z9LA0aamyrX
+eWwnymJvRcIYvxGqgNDxN/8MsaU1EcW0MNEDkc+kDE1LbOwlAQbCeLQDq/w6AlmC
+smoCi0pp6Bf8tZM2RhcUN/xXxgEKcZzhlDOI4v8RNHOyMg==
+-----END CERTIFICATE-----
diff --git a/src/mongo/gotools/common/db/tlsgo/testdata/pkcs1-rev.pem b/src/mongo/gotools/common/db/tlsgo/testdata/pkcs1-rev.pem
new file mode 100644
index 00000000000..0bb7b967c9d
--- /dev/null
+++ b/src/mongo/gotools/common/db/tlsgo/testdata/pkcs1-rev.pem
@@ -0,0 +1,48 @@
+-----BEGIN CERTIFICATE-----
+MIIDfjCCAmagAwIBAgIDBUEVMA0GCSqGSIb3DQEBBQUAMHQxFzAVBgNVBAMTDktl
+cm5lbCBUZXN0IENBMQ8wDQYDVQQLEwZLZXJuZWwxEDAOBgNVBAoTB01vbmdvREIx
+FjAUBgNVBAcTDU5ldyBZb3JrIENpdHkxETAPBgNVBAgTCE5ldyBZb3JrMQswCQYD
+VQQGEwJVUzAeFw0xNjA5MjIxODE1MTJaFw0zNjA5MjIxODE1MTJaMG8xEjAQBgNV
+BAMTCWxvY2FsaG9zdDEPMA0GA1UECxMGS2VybmVsMRAwDgYDVQQKEwdNb25nb0RC
+MRYwFAYDVQQHEw1OZXcgWW9yayBDaXR5MREwDwYDVQQIEwhOZXcgWW9yazELMAkG
+A1UEBhMCVVMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCTHMXV0LEZ
+OCuDZ292e26NbbrMaib6IL3obp/5tOvNVCNnvfgYyJwCCTIZq/mwCjAV5N8Y7tJM
+v0JrrGIWgJ3qtPMQ/1VxfzLLW598nnBuqZG2HiR3CTfhd0JBmnjKDMscz90+xB2x
+DUDVe6PkbZWnN2otsBzVbW+AAJRVTgUb3cjSbGcC0eTMg3SGaWiB+DtiJIAe3bl8
+6TTmrUKVvbzbJrdrFWpz+NVxf5ejZje+Wlz6OXgkWki5U41PtA7aDFIX3mo1J3c0
+jW957fC/q76jrBoTCbufYPaLQIb5QSex+aJZ40rHpSSV75tsXNUkn22u83Bes+Ih
+X0As7g5kW2TDAgMBAAGjHjAcMBoGA1UdEQQTMBGCCWxvY2FsaG9zdIcEfwAAATAN
+BgkqhkiG9w0BAQUFAAOCAQEAEDzWG64/IlXSEFQZom1z0uBLSLVaxrNg4se6geLH
+Bt63EW78H+JMf97AA32DsDiT3ih5uo8yUcOVoEUwontUOSjekHrYfagF/KxMvyMy
+sWX+8m5SLrU6s4FysUCtlXa92g1Nh/rET074U2sNShhALgNB2XSw9P5n9GnKt5VT
+Rkh0AeBJd09WcOGnSHs30+kKGNV8A5a2GTJbDma0dLa7zlhV6VU91Z9LA0aamyrX
+eWwnymJvRcIYvxGqgNDxN/8MsaU1EcW0MNEDkc+kDE1LbOwlAQbCeLQDq/w6AlmC
+smoCi0pp6Bf8tZM2RhcUN/xXxgEKcZzhlDOI4v8RNHOyMg==
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAkxzF1dCxGTgrg2dvdntujW26zGom+iC96G6f+bTrzVQjZ734
+GMicAgkyGav5sAowFeTfGO7STL9Ca6xiFoCd6rTzEP9VcX8yy1uffJ5wbqmRth4k
+dwk34XdCQZp4ygzLHM/dPsQdsQ1A1Xuj5G2VpzdqLbAc1W1vgACUVU4FG93I0mxn
+AtHkzIN0hmlogfg7YiSAHt25fOk05q1Clb282ya3axVqc/jVcX+Xo2Y3vlpc+jl4
+JFpIuVONT7QO2gxSF95qNSd3NI1vee3wv6u+o6waEwm7n2D2i0CG+UEnsfmiWeNK
+x6Ukle+bbFzVJJ9trvNwXrPiIV9ALO4OZFtkwwIDAQABAoIBAAuueTclPyrVfv8M
+M5mg64JneDHLLBUojGvsfN+DMkY3rCgMuaqeI2U1/bh0I3uLE45pgh2kuSZG+as7
+IP7Qb7m3bKWo4MwGYa4sNFnc6uiepmdjtVmObdWFdslmzrick3RSPStCv2jTuJY7
+HySAXyXMDK5cEa4Q5o2vfhfX/ifcMZrS2Pz1o4k2Wh8EtzmRxJR+QR8d+XLtVsKf
+WIvtlhwGqWkmocFOsWW/6Mtf7IPWC3QAPjVYNcxe/8LSE/FhnRr7L6Uv1K7vGImE
+/+QVScl5sP2bpvo+9LxzOMANMdTWWX5ZZJhIdvwpsyctcZovuJq/Lrh9A0j40nRJ
+LuR6wUECgYEA2AgCKimqgpf7WCZMv72Kbur2banm1nwRsnPENGK4e6ZuYwHXu5n6
+HLgk/zp2lJdE4yGr8EBE5hvoFCosxEuvF2ldlqnKDqRUC9IKNtXJEisadWCEPmOp
+v04zPaV5hWOXaK3ZoCQ7D8xvzThcZderMMdGoeacv050nJnSkPEhissCgYEArlSG
+x2KRa1AvAYwMnEIeABrzjSzLLPHyYmCByouo3ljjWiBu7gSsJCO+O8QBjIklpW24
+g+Cek8d9X3oMw2aKKukgecxTR/XE7StB6RXngEIWvIqLj3CNWn1l+K/F95rrQrBr
+6Fea6qWnMYeZrnuGGvBX7PwjJncE1nvn+ey/9ukCgYB/1N1TDayz8jLsil1H6GSO
+FcMUSUErEed27UHgrbn0kRsowuJhRE/Xxq89x957NrewnzAaziz27PR7Wil7Tj2h
+YNvcV0QVPe/tvrAEmqSMd60EX8RhFqBPb3qqs8wgvjnN23G3bTj1tEdD7GHgcan/
+BywoiUmfelFOiUcsNUNf2QKBgBUuig3R6S9r17pNZP7bfb+vhqZBqhI096mCZmLQ
+41zY2g8KX9Al2zCs8yFZ6IJF68AU+9VyRnJYS+B8+O4JGIKsPtjtvbTBpQLYPbLv
+iWhpH1AbWWe9Wj+Dew9jdB9owGsi+omJk3YtWIpJGqA7vAir6VMPM8oprfnNplsU
+rCJ5AoGBANRKxMsriiA/sDLPxDCQOZg4JGRy1ycRVu75wETwoWnDMUP6J6BxE/pK
+keA1nmrVXLheVs3kB7Bg7Jm+53E6RPATRGbvJ+5nqtDDxjL3HL8Jg6uKFjPmnpJ4
+crTsbc7nrAxo0cRmUlgbzQqhgAfnb8B7Fai2T1qoFixPtIFicehx
+-----END RSA PRIVATE KEY-----
diff --git a/src/mongo/gotools/common/db/tlsgo/testdata/pkcs1.pem b/src/mongo/gotools/common/db/tlsgo/testdata/pkcs1.pem
new file mode 100644
index 00000000000..9f6124b5fa2
--- /dev/null
+++ b/src/mongo/gotools/common/db/tlsgo/testdata/pkcs1.pem
@@ -0,0 +1,48 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAkxzF1dCxGTgrg2dvdntujW26zGom+iC96G6f+bTrzVQjZ734
+GMicAgkyGav5sAowFeTfGO7STL9Ca6xiFoCd6rTzEP9VcX8yy1uffJ5wbqmRth4k
+dwk34XdCQZp4ygzLHM/dPsQdsQ1A1Xuj5G2VpzdqLbAc1W1vgACUVU4FG93I0mxn
+AtHkzIN0hmlogfg7YiSAHt25fOk05q1Clb282ya3axVqc/jVcX+Xo2Y3vlpc+jl4
+JFpIuVONT7QO2gxSF95qNSd3NI1vee3wv6u+o6waEwm7n2D2i0CG+UEnsfmiWeNK
+x6Ukle+bbFzVJJ9trvNwXrPiIV9ALO4OZFtkwwIDAQABAoIBAAuueTclPyrVfv8M
+M5mg64JneDHLLBUojGvsfN+DMkY3rCgMuaqeI2U1/bh0I3uLE45pgh2kuSZG+as7
+IP7Qb7m3bKWo4MwGYa4sNFnc6uiepmdjtVmObdWFdslmzrick3RSPStCv2jTuJY7
+HySAXyXMDK5cEa4Q5o2vfhfX/ifcMZrS2Pz1o4k2Wh8EtzmRxJR+QR8d+XLtVsKf
+WIvtlhwGqWkmocFOsWW/6Mtf7IPWC3QAPjVYNcxe/8LSE/FhnRr7L6Uv1K7vGImE
+/+QVScl5sP2bpvo+9LxzOMANMdTWWX5ZZJhIdvwpsyctcZovuJq/Lrh9A0j40nRJ
+LuR6wUECgYEA2AgCKimqgpf7WCZMv72Kbur2banm1nwRsnPENGK4e6ZuYwHXu5n6
+HLgk/zp2lJdE4yGr8EBE5hvoFCosxEuvF2ldlqnKDqRUC9IKNtXJEisadWCEPmOp
+v04zPaV5hWOXaK3ZoCQ7D8xvzThcZderMMdGoeacv050nJnSkPEhissCgYEArlSG
+x2KRa1AvAYwMnEIeABrzjSzLLPHyYmCByouo3ljjWiBu7gSsJCO+O8QBjIklpW24
+g+Cek8d9X3oMw2aKKukgecxTR/XE7StB6RXngEIWvIqLj3CNWn1l+K/F95rrQrBr
+6Fea6qWnMYeZrnuGGvBX7PwjJncE1nvn+ey/9ukCgYB/1N1TDayz8jLsil1H6GSO
+FcMUSUErEed27UHgrbn0kRsowuJhRE/Xxq89x957NrewnzAaziz27PR7Wil7Tj2h
+YNvcV0QVPe/tvrAEmqSMd60EX8RhFqBPb3qqs8wgvjnN23G3bTj1tEdD7GHgcan/
+BywoiUmfelFOiUcsNUNf2QKBgBUuig3R6S9r17pNZP7bfb+vhqZBqhI096mCZmLQ
+41zY2g8KX9Al2zCs8yFZ6IJF68AU+9VyRnJYS+B8+O4JGIKsPtjtvbTBpQLYPbLv
+iWhpH1AbWWe9Wj+Dew9jdB9owGsi+omJk3YtWIpJGqA7vAir6VMPM8oprfnNplsU
+rCJ5AoGBANRKxMsriiA/sDLPxDCQOZg4JGRy1ycRVu75wETwoWnDMUP6J6BxE/pK
+keA1nmrVXLheVs3kB7Bg7Jm+53E6RPATRGbvJ+5nqtDDxjL3HL8Jg6uKFjPmnpJ4
+crTsbc7nrAxo0cRmUlgbzQqhgAfnb8B7Fai2T1qoFixPtIFicehx
+-----END RSA PRIVATE KEY-----
+-----BEGIN CERTIFICATE-----
+MIIDfjCCAmagAwIBAgIDBUEVMA0GCSqGSIb3DQEBBQUAMHQxFzAVBgNVBAMTDktl
+cm5lbCBUZXN0IENBMQ8wDQYDVQQLEwZLZXJuZWwxEDAOBgNVBAoTB01vbmdvREIx
+FjAUBgNVBAcTDU5ldyBZb3JrIENpdHkxETAPBgNVBAgTCE5ldyBZb3JrMQswCQYD
+VQQGEwJVUzAeFw0xNjA5MjIxODE1MTJaFw0zNjA5MjIxODE1MTJaMG8xEjAQBgNV
+BAMTCWxvY2FsaG9zdDEPMA0GA1UECxMGS2VybmVsMRAwDgYDVQQKEwdNb25nb0RC
+MRYwFAYDVQQHEw1OZXcgWW9yayBDaXR5MREwDwYDVQQIEwhOZXcgWW9yazELMAkG
+A1UEBhMCVVMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCTHMXV0LEZ
+OCuDZ292e26NbbrMaib6IL3obp/5tOvNVCNnvfgYyJwCCTIZq/mwCjAV5N8Y7tJM
+v0JrrGIWgJ3qtPMQ/1VxfzLLW598nnBuqZG2HiR3CTfhd0JBmnjKDMscz90+xB2x
+DUDVe6PkbZWnN2otsBzVbW+AAJRVTgUb3cjSbGcC0eTMg3SGaWiB+DtiJIAe3bl8
+6TTmrUKVvbzbJrdrFWpz+NVxf5ejZje+Wlz6OXgkWki5U41PtA7aDFIX3mo1J3c0
+jW957fC/q76jrBoTCbufYPaLQIb5QSex+aJZ40rHpSSV75tsXNUkn22u83Bes+Ih
+X0As7g5kW2TDAgMBAAGjHjAcMBoGA1UdEQQTMBGCCWxvY2FsaG9zdIcEfwAAATAN
+BgkqhkiG9w0BAQUFAAOCAQEAEDzWG64/IlXSEFQZom1z0uBLSLVaxrNg4se6geLH
+Bt63EW78H+JMf97AA32DsDiT3ih5uo8yUcOVoEUwontUOSjekHrYfagF/KxMvyMy
+sWX+8m5SLrU6s4FysUCtlXa92g1Nh/rET074U2sNShhALgNB2XSw9P5n9GnKt5VT
+Rkh0AeBJd09WcOGnSHs30+kKGNV8A5a2GTJbDma0dLa7zlhV6VU91Z9LA0aamyrX
+eWwnymJvRcIYvxGqgNDxN/8MsaU1EcW0MNEDkc+kDE1LbOwlAQbCeLQDq/w6AlmC
+smoCi0pp6Bf8tZM2RhcUN/xXxgEKcZzhlDOI4v8RNHOyMg==
+-----END CERTIFICATE-----
diff --git a/src/mongo/gotools/common/db/tlsgo/testdata/pkcs8-encrypted-rev.pem b/src/mongo/gotools/common/db/tlsgo/testdata/pkcs8-encrypted-rev.pem
new file mode 100644
index 00000000000..2a9b8ea4aa4
--- /dev/null
+++ b/src/mongo/gotools/common/db/tlsgo/testdata/pkcs8-encrypted-rev.pem
@@ -0,0 +1,51 @@
+-----BEGIN CERTIFICATE-----
+MIIDfjCCAmagAwIBAgIDBUEVMA0GCSqGSIb3DQEBBQUAMHQxFzAVBgNVBAMTDktl
+cm5lbCBUZXN0IENBMQ8wDQYDVQQLEwZLZXJuZWwxEDAOBgNVBAoTB01vbmdvREIx
+FjAUBgNVBAcTDU5ldyBZb3JrIENpdHkxETAPBgNVBAgTCE5ldyBZb3JrMQswCQYD
+VQQGEwJVUzAeFw0xNjA5MjIxODE1MTJaFw0zNjA5MjIxODE1MTJaMG8xEjAQBgNV
+BAMTCWxvY2FsaG9zdDEPMA0GA1UECxMGS2VybmVsMRAwDgYDVQQKEwdNb25nb0RC
+MRYwFAYDVQQHEw1OZXcgWW9yayBDaXR5MREwDwYDVQQIEwhOZXcgWW9yazELMAkG
+A1UEBhMCVVMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCTHMXV0LEZ
+OCuDZ292e26NbbrMaib6IL3obp/5tOvNVCNnvfgYyJwCCTIZq/mwCjAV5N8Y7tJM
+v0JrrGIWgJ3qtPMQ/1VxfzLLW598nnBuqZG2HiR3CTfhd0JBmnjKDMscz90+xB2x
+DUDVe6PkbZWnN2otsBzVbW+AAJRVTgUb3cjSbGcC0eTMg3SGaWiB+DtiJIAe3bl8
+6TTmrUKVvbzbJrdrFWpz+NVxf5ejZje+Wlz6OXgkWki5U41PtA7aDFIX3mo1J3c0
+jW957fC/q76jrBoTCbufYPaLQIb5QSex+aJZ40rHpSSV75tsXNUkn22u83Bes+Ih
+X0As7g5kW2TDAgMBAAGjHjAcMBoGA1UdEQQTMBGCCWxvY2FsaG9zdIcEfwAAATAN
+BgkqhkiG9w0BAQUFAAOCAQEAEDzWG64/IlXSEFQZom1z0uBLSLVaxrNg4se6geLH
+Bt63EW78H+JMf97AA32DsDiT3ih5uo8yUcOVoEUwontUOSjekHrYfagF/KxMvyMy
+sWX+8m5SLrU6s4FysUCtlXa92g1Nh/rET074U2sNShhALgNB2XSw9P5n9GnKt5VT
+Rkh0AeBJd09WcOGnSHs30+kKGNV8A5a2GTJbDma0dLa7zlhV6VU91Z9LA0aamyrX
+eWwnymJvRcIYvxGqgNDxN/8MsaU1EcW0MNEDkc+kDE1LbOwlAQbCeLQDq/w6AlmC
+smoCi0pp6Bf8tZM2RhcUN/xXxgEKcZzhlDOI4v8RNHOyMg==
+-----END CERTIFICATE-----
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFHzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQIP80PLbXYYHUCAggA
+MB0GCWCGSAFlAwQBAgQQu1qZnln9ymhZVDJmGJpIJQSCBNDufC1nGCgwBWtkzqP+
+MN3/UJD4cX6TQDjGotN484gLvCm138yB8EPSuFz2RUcOFQImKm3fuqBKgx08jen6
+DQRNekzW1ngIV3BZwn5kMwr0lJK4ibpfEmdTYu/2INq55ljsFx7pq+69PLOqskPa
+l+1CzPub0xPC8spG6H0xxOV3HYZlzNX6SKgpK/GPCyGzspgijdacn+x+KFpvMRG3
+fDvdGTP5F/lk6++EHFM/LBfitNV0qkd9GoOIbcDkinu6EytSfJY/mY337AhitWQZ
+zdhgC3nA+QYy9s/hs2hXBepkIsFzLMRF162Cqc7KPNObpVGBPxFS+an3c7FyYXVw
+ekTf1XrUpdsqNIgvSQkUhzkPc01jHWd4paHgSCLayLx6c9jPXiCxgASZ7BcjAZOC
+VLqoi9RHYrEdpoZBwMnSheHa6OVdqPbitlx4vA41s1ERuRktz9hXuhl/Rje+IF5i
+2N2l4q3ix4K2yvtZ4wmoc92/WPy2XVudeBinupIxLbrq82HIs1KvLZZ78s+s2Gfh
+PDH/1gMiraOWyBY1/4DtAnptl2qKW3YsTwMGCfrX8euRC7WCk/QBw6SBy1XlV2pc
+uc1ZOAgWQHwDSRK6XJHgElrQkgVRlszg5vofJ1RdRxJo6XossIc3vx/IUqv2+7xx
+mGBE+71FYDg4vmN5nAgN2MjEGdyMEGL4WiKT6Y/WSOTrtRVKRFTilzxuOmx6Hq37
+rldBokhttrx0JikU0fqDWSaDbERSslmv5TinygKyq/PnGOHtcBzHC0c+AIlp2Rj8
+Z5TbgMVcxjV0GZ0SojjO6DO9weJ5c5iBom+VJrniYNDc4jqn0OqIQEembgGuTdHk
+37Dqp7oxonLZS1Qi+YNljxQvGUeaoy0hSJS/9C2ANWoo+POB/BkhdS3NT2CQAxNZ
+ca4ThdtyLvhSjLIEEMJH7J+LFVuE32hbivWtjKcha8vJ/sYz5gZE193Jfz5H92Zq
+3Ee7ipvaKQrxATCp7xJdX5ftHp2+dMsiRKxff8TOO9TVwoJkWOw9zSOMidI+znuL
+IF2kTMMPu/o1EbOzEvgck/dcvPlTzWQEGy6eCSixndB4c9yjcVnZpzYnWJEhV7to
+W9OfcBkQ/3V5jn96yQPCXm1br2j9FS5QDmWP+GOlLUEPwb27jUajTs3emeqvC0qJ
+OALtJsKkwT9L7Cq/cZNByBrbmimEI1NkaVRPjauHhQSzPYIJWBkaJPoZIkbCJ5eO
+vRi/2Bd74fda8pVFxm9kUNP8wwpz9JSXmzVRzGXOJ3lS1TKAXl++gb5HX+bieSNy
+QHcjw6rBwOkdac40vs5mxGb0XHtP8Qqvn0+fzmKan4MBGKGrB2nlfBrhI2Uopni5
+WRSWbZjDe3ofsjlaj39rxQksvSnZEN/us4JHl2QWfYhpg9tYiCmO0zPREqdWKoi2
+IgydR30JXmNx+W2UBoh1iIPgxeqkDXsxWusGbAgyZs4s7/dcrlcVQz5vzHm0zXsK
+hix58eAuxTJORkGKaxva5fmdwvHJJPt5/nPPsGdm81WVqm79yKRRE4mjl+PTBryE
+4IuFZjGksVDHpi1LMpW4FMmaYjf/oNm9/ZAqOtxJYC8CFIyyVbqSMOwrqSDxmE8O
+gHyWskGclbX/lOH8H83lXnh2xw==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/src/mongo/gotools/common/db/tlsgo/testdata/pkcs8-encrypted.pem b/src/mongo/gotools/common/db/tlsgo/testdata/pkcs8-encrypted.pem
new file mode 100644
index 00000000000..88773490b0f
--- /dev/null
+++ b/src/mongo/gotools/common/db/tlsgo/testdata/pkcs8-encrypted.pem
@@ -0,0 +1,51 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFHzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQIP80PLbXYYHUCAggA
+MB0GCWCGSAFlAwQBAgQQu1qZnln9ymhZVDJmGJpIJQSCBNDufC1nGCgwBWtkzqP+
+MN3/UJD4cX6TQDjGotN484gLvCm138yB8EPSuFz2RUcOFQImKm3fuqBKgx08jen6
+DQRNekzW1ngIV3BZwn5kMwr0lJK4ibpfEmdTYu/2INq55ljsFx7pq+69PLOqskPa
+l+1CzPub0xPC8spG6H0xxOV3HYZlzNX6SKgpK/GPCyGzspgijdacn+x+KFpvMRG3
+fDvdGTP5F/lk6++EHFM/LBfitNV0qkd9GoOIbcDkinu6EytSfJY/mY337AhitWQZ
+zdhgC3nA+QYy9s/hs2hXBepkIsFzLMRF162Cqc7KPNObpVGBPxFS+an3c7FyYXVw
+ekTf1XrUpdsqNIgvSQkUhzkPc01jHWd4paHgSCLayLx6c9jPXiCxgASZ7BcjAZOC
+VLqoi9RHYrEdpoZBwMnSheHa6OVdqPbitlx4vA41s1ERuRktz9hXuhl/Rje+IF5i
+2N2l4q3ix4K2yvtZ4wmoc92/WPy2XVudeBinupIxLbrq82HIs1KvLZZ78s+s2Gfh
+PDH/1gMiraOWyBY1/4DtAnptl2qKW3YsTwMGCfrX8euRC7WCk/QBw6SBy1XlV2pc
+uc1ZOAgWQHwDSRK6XJHgElrQkgVRlszg5vofJ1RdRxJo6XossIc3vx/IUqv2+7xx
+mGBE+71FYDg4vmN5nAgN2MjEGdyMEGL4WiKT6Y/WSOTrtRVKRFTilzxuOmx6Hq37
+rldBokhttrx0JikU0fqDWSaDbERSslmv5TinygKyq/PnGOHtcBzHC0c+AIlp2Rj8
+Z5TbgMVcxjV0GZ0SojjO6DO9weJ5c5iBom+VJrniYNDc4jqn0OqIQEembgGuTdHk
+37Dqp7oxonLZS1Qi+YNljxQvGUeaoy0hSJS/9C2ANWoo+POB/BkhdS3NT2CQAxNZ
+ca4ThdtyLvhSjLIEEMJH7J+LFVuE32hbivWtjKcha8vJ/sYz5gZE193Jfz5H92Zq
+3Ee7ipvaKQrxATCp7xJdX5ftHp2+dMsiRKxff8TOO9TVwoJkWOw9zSOMidI+znuL
+IF2kTMMPu/o1EbOzEvgck/dcvPlTzWQEGy6eCSixndB4c9yjcVnZpzYnWJEhV7to
+W9OfcBkQ/3V5jn96yQPCXm1br2j9FS5QDmWP+GOlLUEPwb27jUajTs3emeqvC0qJ
+OALtJsKkwT9L7Cq/cZNByBrbmimEI1NkaVRPjauHhQSzPYIJWBkaJPoZIkbCJ5eO
+vRi/2Bd74fda8pVFxm9kUNP8wwpz9JSXmzVRzGXOJ3lS1TKAXl++gb5HX+bieSNy
+QHcjw6rBwOkdac40vs5mxGb0XHtP8Qqvn0+fzmKan4MBGKGrB2nlfBrhI2Uopni5
+WRSWbZjDe3ofsjlaj39rxQksvSnZEN/us4JHl2QWfYhpg9tYiCmO0zPREqdWKoi2
+IgydR30JXmNx+W2UBoh1iIPgxeqkDXsxWusGbAgyZs4s7/dcrlcVQz5vzHm0zXsK
+hix58eAuxTJORkGKaxva5fmdwvHJJPt5/nPPsGdm81WVqm79yKRRE4mjl+PTBryE
+4IuFZjGksVDHpi1LMpW4FMmaYjf/oNm9/ZAqOtxJYC8CFIyyVbqSMOwrqSDxmE8O
+gHyWskGclbX/lOH8H83lXnh2xw==
+-----END ENCRYPTED PRIVATE KEY-----
+-----BEGIN CERTIFICATE-----
+MIIDfjCCAmagAwIBAgIDBUEVMA0GCSqGSIb3DQEBBQUAMHQxFzAVBgNVBAMTDktl
+cm5lbCBUZXN0IENBMQ8wDQYDVQQLEwZLZXJuZWwxEDAOBgNVBAoTB01vbmdvREIx
+FjAUBgNVBAcTDU5ldyBZb3JrIENpdHkxETAPBgNVBAgTCE5ldyBZb3JrMQswCQYD
+VQQGEwJVUzAeFw0xNjA5MjIxODE1MTJaFw0zNjA5MjIxODE1MTJaMG8xEjAQBgNV
+BAMTCWxvY2FsaG9zdDEPMA0GA1UECxMGS2VybmVsMRAwDgYDVQQKEwdNb25nb0RC
+MRYwFAYDVQQHEw1OZXcgWW9yayBDaXR5MREwDwYDVQQIEwhOZXcgWW9yazELMAkG
+A1UEBhMCVVMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCTHMXV0LEZ
+OCuDZ292e26NbbrMaib6IL3obp/5tOvNVCNnvfgYyJwCCTIZq/mwCjAV5N8Y7tJM
+v0JrrGIWgJ3qtPMQ/1VxfzLLW598nnBuqZG2HiR3CTfhd0JBmnjKDMscz90+xB2x
+DUDVe6PkbZWnN2otsBzVbW+AAJRVTgUb3cjSbGcC0eTMg3SGaWiB+DtiJIAe3bl8
+6TTmrUKVvbzbJrdrFWpz+NVxf5ejZje+Wlz6OXgkWki5U41PtA7aDFIX3mo1J3c0
+jW957fC/q76jrBoTCbufYPaLQIb5QSex+aJZ40rHpSSV75tsXNUkn22u83Bes+Ih
+X0As7g5kW2TDAgMBAAGjHjAcMBoGA1UdEQQTMBGCCWxvY2FsaG9zdIcEfwAAATAN
+BgkqhkiG9w0BAQUFAAOCAQEAEDzWG64/IlXSEFQZom1z0uBLSLVaxrNg4se6geLH
+Bt63EW78H+JMf97AA32DsDiT3ih5uo8yUcOVoEUwontUOSjekHrYfagF/KxMvyMy
+sWX+8m5SLrU6s4FysUCtlXa92g1Nh/rET074U2sNShhALgNB2XSw9P5n9GnKt5VT
+Rkh0AeBJd09WcOGnSHs30+kKGNV8A5a2GTJbDma0dLa7zlhV6VU91Z9LA0aamyrX
+eWwnymJvRcIYvxGqgNDxN/8MsaU1EcW0MNEDkc+kDE1LbOwlAQbCeLQDq/w6AlmC
+smoCi0pp6Bf8tZM2RhcUN/xXxgEKcZzhlDOI4v8RNHOyMg==
+-----END CERTIFICATE-----
diff --git a/src/mongo/gotools/common/db/tlsgo/testdata/pkcs8-rev.pem b/src/mongo/gotools/common/db/tlsgo/testdata/pkcs8-rev.pem
new file mode 100644
index 00000000000..7d902b28e11
--- /dev/null
+++ b/src/mongo/gotools/common/db/tlsgo/testdata/pkcs8-rev.pem
@@ -0,0 +1,50 @@
+-----BEGIN CERTIFICATE-----
+MIIDuDCCAqCgAwIBAgIJAIJdodI/q6hqMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNV
+BAYTAlVTMREwDwYDVQQIDAhOZXcgWW9yazEQMA4GA1UECgwHTW9uZ29EQjERMA8G
+A1UECwwIU2VjdXJpdHkxCzAJBgNVBAMMAmNhMB4XDTE3MDMxNzEwMTQ0MVoXDTI3
+MDMxNTEwMTQ0MVowaDELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE5ldyBZb3JrMREw
+DwYDVQQHDAhOZXcgWW9yazEQMA4GA1UECgwHTW9uZ29EQjEQMA4GA1UECwwHRHJp
+dmVyczEPMA0GA1UEAwwGY2xpZW50MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEA0nYSydRYw7eM1KtyM6s49A7SIPGUua+wStu9KkTzFcaJ8y/hcrek5J/4
+PcpY5gf8tkf3GrXxumtPnWCJJP+wbNh4U9HJgtFrzkIHnYmOxjLERGgu/w+4W3J+
+/RUSOOHK2DeOzIYZd79d48716kNWYFV80nhQRJexJSD1fGgQLll947HBh50f4Jne
+JMtq3Bw/YoJfKDa8AcsWj80U5yGF6BUhVddteIwXlHbTUJxFu5cZ3iVOEr7sTd8O
+gpJ1XZgUGOW9fVBxwRRiLe1MXHrljvaNOT532W+kQDw9U94teD6pDTIRPrOxJ8l4
+GWiP3hyKVqcbx2fPumj5zqRz8nlZSQIDAQABo3sweTAJBgNVHRMEAjAAMCwGCWCG
+SAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4E
+FgQUd7IrLVymryD9EI7JqSDy61B0hiYwHwYDVR0jBBgwFoAU6V78cAw4dTLrQwZE
+x8Vf5k+rHDkwDQYJKoZIhvcNAQELBQADggEBAGxTZl9WrjlXd9UFIFKiTx3io/YR
+NuAfStSuLwoNAi3P+XYLwvfUScyHOambqBmBFsMSNiQe6h4tepcVIFLeGcsTsoyf
+JkTMwiJH1iIdAchNJmsdkWrPlzUc8s7modmzBx6TBokiGL79vVuh20SW8IyWJZaf
+79A1vFR7PRRPsJWfbXkEOP+CoyQfJtPLz+fFcX2CFkvtn5T8IM97OBBckyE3pjRQ
+nZ7bDc+mM/2T23KMnSWNvqP68Yt+7YMyQ+uj1+HJOHfHQSD0nU/Mn0+EqLhZbzvL
+EKJ5z1meByoriHlMGvZjGMIIcH1Gt/QAi8sVzZBJr+Cq0c9P7F+uNFcODaM=
+-----END CERTIFICATE-----
+-----BEGIN PRIVATE KEY-----
+MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQDSdhLJ1FjDt4zU
+q3Izqzj0DtIg8ZS5r7BK270qRPMVxonzL+Fyt6Tkn/g9yljmB/y2R/catfG6a0+d
+YIkk/7Bs2HhT0cmC0WvOQgediY7GMsREaC7/D7hbcn79FRI44crYN47Mhhl3v13j
+zvXqQ1ZgVXzSeFBEl7ElIPV8aBAuWX3jscGHnR/gmd4ky2rcHD9igl8oNrwByxaP
+zRTnIYXoFSFV1214jBeUdtNQnEW7lxneJU4SvuxN3w6CknVdmBQY5b19UHHBFGIt
+7UxceuWO9o05PnfZb6RAPD1T3i14PqkNMhE+s7EnyXgZaI/eHIpWpxvHZ8+6aPnO
+pHPyeVlJAgMBAAECggEBALR2AAhF51Ly2XQmCkeZor1K1AzhePh7WDvoDVzoQFPE
+qNb4kGTwaRiMvqwlDHM6GAwoyw6BQmPpzhuRAifSgvHh79NXiGV+suTqI2OG5wC1
+2Ssa9mlIjnkDRTY3UieqHGenw+9FcSMH2TcUaDLWSINT6jMCbTlTpNbEWxqwlGdY
+URP4I0lN/NiKyfGemctXTuKj3YOB+6feQZaL1RWYJ9pneSad6rbsLYLOc0JAK8zG
+wu3mPhPTrMqaj7DXAbhz4NWmIjosIp4/5bnV2HSvpd4UiB7/yK/gknZ4XesHOz4z
+aIKbYxbaUkrKIGO/mwuZOjCDSw/rSDmuxuDWFRU3NE0CgYEA6LW2dFPfxIxEmeXl
+EzFxJhsCeCOcPo4ueWxbMboILl2KjMhTUGxKZEjJtWpK+FwVqashU2CrDfW/zfzp
+ekb1EVAeq+bDsHKRXMJfHQ3qky733nqsKbpQonJwyQ64AVhQVLgr8Xi+gNiYaOWo
+g5ZftrlNlJu59GJv+St2eipAlwsCgYEA54ZTpYAodRkMcZOGqiG8mHwNwxPSRIRO
+7iRRT+8NFLVfC3Y1oPD7o2tmwFDpSzybgIOpdKuqHOG6/ed82AyqnODhmdNPcCpv
+FgyWZaurgJepe8Y61vjoaV6y7geLJAOL/WAbqzRRq6tDI708t21lsFCTvtoyW/0I
+0kggr/+ytXsCgYEAkaW5jlE4ilGoVhI3L64QPWNGRl8zWUuv9rtE0Hi4yhwtrTNs
+QbelT+LmrC7cwVkRDeJXt1GXfeNDqu8SSj/C/pUAvWJvNC5goIfe89ZT7M7GwG5S
+9sLv2Nx7jrsxm1Xk4UFr73Q893OY4H5s2/7v5PNRhSN6XWSG5JK5UnjDeEUCgYEA
+iMQnAWsVeybS3Pzi3fmT6RfPIV/CJEtsPO0jQ27ZcVQ60xB/WZVBcSXuysiBJ7qj
+uWUNYyhNE0adKYPnkdDZsFZ/rljPYlkOyh2hcmnYo9vzeHR/KaJb2HLijA3Uue+G
+cKSnc5kybZB71s7g4RI0sdTHkkRe30w4O8/zz0PjE6UCgYEAzARJZItdMu9wGu3U
+X7tSSXJL2avVKv/lBDUfZAChBhpXOQf7MvgmKUCiZC/BMZ/plw/AxBL8swrfKgsw
+TdrZwrhK3wOgqYWIHCAfzR+Qa0rRTqVmRQERFylqXzNmUWMG5iq7D9rp3Ht9/Ozn
+6NGsAa53FvCDeBkFzi/dsbhxvjk=
+-----END PRIVATE KEY-----
diff --git a/src/mongo/gotools/common/db/tlsgo/testdata/pkcs8.pem b/src/mongo/gotools/common/db/tlsgo/testdata/pkcs8.pem
new file mode 100644
index 00000000000..305c67658c9
--- /dev/null
+++ b/src/mongo/gotools/common/db/tlsgo/testdata/pkcs8.pem
@@ -0,0 +1,50 @@
+-----BEGIN PRIVATE KEY-----
+MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQDSdhLJ1FjDt4zU
+q3Izqzj0DtIg8ZS5r7BK270qRPMVxonzL+Fyt6Tkn/g9yljmB/y2R/catfG6a0+d
+YIkk/7Bs2HhT0cmC0WvOQgediY7GMsREaC7/D7hbcn79FRI44crYN47Mhhl3v13j
+zvXqQ1ZgVXzSeFBEl7ElIPV8aBAuWX3jscGHnR/gmd4ky2rcHD9igl8oNrwByxaP
+zRTnIYXoFSFV1214jBeUdtNQnEW7lxneJU4SvuxN3w6CknVdmBQY5b19UHHBFGIt
+7UxceuWO9o05PnfZb6RAPD1T3i14PqkNMhE+s7EnyXgZaI/eHIpWpxvHZ8+6aPnO
+pHPyeVlJAgMBAAECggEBALR2AAhF51Ly2XQmCkeZor1K1AzhePh7WDvoDVzoQFPE
+qNb4kGTwaRiMvqwlDHM6GAwoyw6BQmPpzhuRAifSgvHh79NXiGV+suTqI2OG5wC1
+2Ssa9mlIjnkDRTY3UieqHGenw+9FcSMH2TcUaDLWSINT6jMCbTlTpNbEWxqwlGdY
+URP4I0lN/NiKyfGemctXTuKj3YOB+6feQZaL1RWYJ9pneSad6rbsLYLOc0JAK8zG
+wu3mPhPTrMqaj7DXAbhz4NWmIjosIp4/5bnV2HSvpd4UiB7/yK/gknZ4XesHOz4z
+aIKbYxbaUkrKIGO/mwuZOjCDSw/rSDmuxuDWFRU3NE0CgYEA6LW2dFPfxIxEmeXl
+EzFxJhsCeCOcPo4ueWxbMboILl2KjMhTUGxKZEjJtWpK+FwVqashU2CrDfW/zfzp
+ekb1EVAeq+bDsHKRXMJfHQ3qky733nqsKbpQonJwyQ64AVhQVLgr8Xi+gNiYaOWo
+g5ZftrlNlJu59GJv+St2eipAlwsCgYEA54ZTpYAodRkMcZOGqiG8mHwNwxPSRIRO
+7iRRT+8NFLVfC3Y1oPD7o2tmwFDpSzybgIOpdKuqHOG6/ed82AyqnODhmdNPcCpv
+FgyWZaurgJepe8Y61vjoaV6y7geLJAOL/WAbqzRRq6tDI708t21lsFCTvtoyW/0I
+0kggr/+ytXsCgYEAkaW5jlE4ilGoVhI3L64QPWNGRl8zWUuv9rtE0Hi4yhwtrTNs
+QbelT+LmrC7cwVkRDeJXt1GXfeNDqu8SSj/C/pUAvWJvNC5goIfe89ZT7M7GwG5S
+9sLv2Nx7jrsxm1Xk4UFr73Q893OY4H5s2/7v5PNRhSN6XWSG5JK5UnjDeEUCgYEA
+iMQnAWsVeybS3Pzi3fmT6RfPIV/CJEtsPO0jQ27ZcVQ60xB/WZVBcSXuysiBJ7qj
+uWUNYyhNE0adKYPnkdDZsFZ/rljPYlkOyh2hcmnYo9vzeHR/KaJb2HLijA3Uue+G
+cKSnc5kybZB71s7g4RI0sdTHkkRe30w4O8/zz0PjE6UCgYEAzARJZItdMu9wGu3U
+X7tSSXJL2avVKv/lBDUfZAChBhpXOQf7MvgmKUCiZC/BMZ/plw/AxBL8swrfKgsw
+TdrZwrhK3wOgqYWIHCAfzR+Qa0rRTqVmRQERFylqXzNmUWMG5iq7D9rp3Ht9/Ozn
+6NGsAa53FvCDeBkFzi/dsbhxvjk=
+-----END PRIVATE KEY-----
+-----BEGIN CERTIFICATE-----
+MIIDuDCCAqCgAwIBAgIJAIJdodI/q6hqMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNV
+BAYTAlVTMREwDwYDVQQIDAhOZXcgWW9yazEQMA4GA1UECgwHTW9uZ29EQjERMA8G
+A1UECwwIU2VjdXJpdHkxCzAJBgNVBAMMAmNhMB4XDTE3MDMxNzEwMTQ0MVoXDTI3
+MDMxNTEwMTQ0MVowaDELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE5ldyBZb3JrMREw
+DwYDVQQHDAhOZXcgWW9yazEQMA4GA1UECgwHTW9uZ29EQjEQMA4GA1UECwwHRHJp
+dmVyczEPMA0GA1UEAwwGY2xpZW50MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEA0nYSydRYw7eM1KtyM6s49A7SIPGUua+wStu9KkTzFcaJ8y/hcrek5J/4
+PcpY5gf8tkf3GrXxumtPnWCJJP+wbNh4U9HJgtFrzkIHnYmOxjLERGgu/w+4W3J+
+/RUSOOHK2DeOzIYZd79d48716kNWYFV80nhQRJexJSD1fGgQLll947HBh50f4Jne
+JMtq3Bw/YoJfKDa8AcsWj80U5yGF6BUhVddteIwXlHbTUJxFu5cZ3iVOEr7sTd8O
+gpJ1XZgUGOW9fVBxwRRiLe1MXHrljvaNOT532W+kQDw9U94teD6pDTIRPrOxJ8l4
+GWiP3hyKVqcbx2fPumj5zqRz8nlZSQIDAQABo3sweTAJBgNVHRMEAjAAMCwGCWCG
+SAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4E
+FgQUd7IrLVymryD9EI7JqSDy61B0hiYwHwYDVR0jBBgwFoAU6V78cAw4dTLrQwZE
+x8Vf5k+rHDkwDQYJKoZIhvcNAQELBQADggEBAGxTZl9WrjlXd9UFIFKiTx3io/YR
+NuAfStSuLwoNAi3P+XYLwvfUScyHOambqBmBFsMSNiQe6h4tepcVIFLeGcsTsoyf
+JkTMwiJH1iIdAchNJmsdkWrPlzUc8s7modmzBx6TBokiGL79vVuh20SW8IyWJZaf
+79A1vFR7PRRPsJWfbXkEOP+CoyQfJtPLz+fFcX2CFkvtn5T8IM97OBBckyE3pjRQ
+nZ7bDc+mM/2T23KMnSWNvqP68Yt+7YMyQ+uj1+HJOHfHQSD0nU/Mn0+EqLhZbzvL
+EKJ5z1meByoriHlMGvZjGMIIcH1Gt/QAi8sVzZBJr+Cq0c9P7F+uNFcODaM=
+-----END CERTIFICATE-----
diff --git a/src/mongo/gotools/common/db/tlsgo/tlsgo.go b/src/mongo/gotools/common/db/tlsgo/tlsgo.go
new file mode 100644
index 00000000000..c26b7e2dc4f
--- /dev/null
+++ b/src/mongo/gotools/common/db/tlsgo/tlsgo.go
@@ -0,0 +1,135 @@
+// Copyright (C) MongoDB, Inc. 2014-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 tlsgo implements connection to MongoDB with Go native TLS.
+package tlsgo
+
+import (
+ "crypto/tls"
+ "fmt"
+ "net"
+ "strings"
+ "time"
+
+ "github.com/mongodb/mongo-tools/common/db/kerberos"
+ "github.com/mongodb/mongo-tools/common/log"
+ "github.com/mongodb/mongo-tools/common/options"
+ "github.com/mongodb/mongo-tools/common/util"
+ "gopkg.in/mgo.v2"
+)
+
+// TLSDBConnector makes a connection to the database with Go native TLS.
+type TLSDBConnector struct {
+ dialInfo *mgo.DialInfo
+ config *TLSConfig
+}
+
+// Configure the connector to connect to the server over ssl. Sets up the
+// correct function to dial the server based on the ssl options passed in.
+func (c *TLSDBConnector) Configure(opts options.ToolOptions) error {
+ if opts.SSLFipsMode {
+ return fmt.Errorf("FIPS mode not supported")
+ }
+
+ if opts.SSLCRLFile != "" {
+ return fmt.Errorf("CRL files are not supported on this platform")
+ }
+
+ c.config = NewTLSConfig()
+
+ if opts.SSLAllowInvalidCert || opts.SSLAllowInvalidHost {
+ c.config.SetInsecure(true)
+ }
+
+ if opts.SSLPEMKeyFile != "" {
+ subject, err := c.config.AddClientCertFromFile(opts.SSLPEMKeyFile, opts.SSLPEMKeyPassword)
+ if err != nil {
+ return err
+ }
+ if opts.Auth.Mechanism == "MONGODB-X509" && opts.Auth.Username == "" {
+ opts.Auth.Username = subject
+ }
+ }
+
+ if opts.SSLCAFile != "" {
+ c.config.AddCaCertFromFile(opts.SSLCAFile)
+ }
+
+ // set up the dial info
+ c.dialInfo = &mgo.DialInfo{
+ Timeout: time.Duration(opts.Timeout) * time.Second,
+ Direct: opts.Direct,
+ ReplicaSetName: opts.ReplicaSetName,
+ DialServer: c.makeDialer(opts),
+ Username: opts.Auth.Username,
+ Password: opts.Auth.Password,
+ Source: opts.GetAuthenticationDatabase(),
+ Mechanism: opts.Auth.Mechanism,
+ }
+
+ // create or fetch the addresses to be used to connect
+ if opts.URI != nil && opts.URI.ConnectionString != "" {
+ c.dialInfo.Addrs = opts.URI.GetConnectionAddrs()
+ } else {
+ c.dialInfo.Addrs = util.CreateConnectionAddrs(opts.Host, opts.Port)
+ }
+ kerberos.AddKerberosOpts(opts, c.dialInfo)
+ return nil
+}
+
+// GetNewSession dials the server.
+func (c *TLSDBConnector) GetNewSession() (*mgo.Session, error) {
+ return mgo.DialWithInfo(c.dialInfo)
+}
+
+// To be handed to mgo.DialInfo for connecting to the server.
+type dialerFunc func(addr *mgo.ServerAddr) (net.Conn, error)
+
+func (c *TLSDBConnector) makeDialer(opts options.ToolOptions) dialerFunc {
+ return func(addr *mgo.ServerAddr) (net.Conn, error) {
+ address := addr.String()
+ conn, err := net.Dial("tcp", address)
+ if err != nil {
+ // mgo discards dialer errors so log it now
+ log.Logvf(log.Always, "error dialing %v: %v", address, err)
+ return nil, err
+ }
+ // enable TCP keepalive
+ err = util.EnableTCPKeepAlive(conn, time.Duration(opts.TCPKeepAliveSeconds)*time.Second)
+ if err != nil {
+ // mgo discards dialer errors so log it now
+ log.Logvf(log.Always, "error enabling TCP keepalive on connection to %v: %v", address, err)
+ conn.Close()
+ return nil, err
+ }
+
+ tlsConfig, err := c.config.MakeConfig()
+ if err != nil {
+ return nil, err
+ }
+
+ if !tlsConfig.InsecureSkipVerify {
+ colonPos := strings.LastIndex(address, ":")
+ if colonPos == -1 {
+ colonPos = len(address)
+ }
+
+ hostname := address[:colonPos]
+ tlsConfig.ServerName = hostname
+ }
+
+ client := tls.Client(conn, tlsConfig)
+ err = client.Handshake()
+ if err != nil {
+ // mgo discards dialer errors so log it now
+ log.Logvf(log.Always, "error doing TLS handshake with %v: %v", address, err)
+ client.Close()
+ return nil, err
+ }
+
+ return client, nil
+ }
+}