Skip to content

Commit

Permalink
GODRIVER-364 Support PKCS8 encrypted client private keys (mongodb#565)
Browse files Browse the repository at this point in the history
  • Loading branch information
benjirewis authored Feb 1, 2021
1 parent 1cc9b89 commit 15a1051
Show file tree
Hide file tree
Showing 16 changed files with 609 additions and 72 deletions.
52 changes: 52 additions & 0 deletions data/certificates/client-pkcs8-encrypted.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIsqMuOBMVHM4CAggA
MBQGCCqGSIb3DQMHBAjGoriU4YaS6wSCBMhu0dQ8OjzcAJzyhe3osPWFQObhlpsi
sD6Hzx2mcJcZMAv1AG7/MPpPQixiZipQLIiQPOozgjHDqmBp1lGz4FW7sXT01SJT
xlALdUGVrHp5BZRVZGhfZ/SeRknqxoQKqIEZQZeTBJDVZ/dWrLOUfycp0rLWxctq
FVUcb0jq2YL7u9IBIAmFgFyj2ZVWu68HiiwuhKJ0botuFSHe76DP0lthwlHMOR+L
brK7IrMuGhp4xAI16pDoQbwj4AFz2JWhb5WeYhE2CMFhzoZZLgfafBeO/GG04QTt
VB2/Tj5M6jbeCO8H3rYo9yDuWijeOxNDEwRHpLrRcK0T9TouETYzcSFpZIJXhHS3
0ZV44JMGmPP5fkt34mbkBs68nNqcaWuInBx4k7FZZqkd7LyjGRP3mWeqfMhqDaw+
KhAADLRCY7P7ooa3WGGP8+/hdI+I1SR+TCwmiHzY6FRgBlnmlqNH1WS3je4/Dx3w
H8YzPurMpyLlETN1u1DIIZEQteZHVNcZBkTdW1eWOgoOt30wNzrJQPEgPEZgAzvR
4vgKVF68892g755hyOgXl5Hoqf1w2q85l+3qp1zb2UDUvcIkbU7HXnmgZWRJ9T94
kgDlJ82Y+BECQFPVTrEhoVGO0q0eF6On8r7slCoY5edqGdXcyLCuYolEgFHqUFQg
Hjj6x17HQBRa3nnkF3j8tho5kxa6pdvmJcXghJ4Y6Tfs2x9qyjHVYqJH2emuuP9f
Gk5oyicOBTjDnGHG0Hvdd3OSpzQP9P6xMhVByomnz+iGO2CYiJdplKHCeS62Lh7D
px0p7CNxIZtWCBWeQXKqofrJm7PQP+izAqurzGLhMTggCfH8QRZPhiykRnRaIwdV
Ml1veBN6JA91OBkwuioiTH+/zEL8KmpFW5f5okpicUSw6NTx5N2OGqYzqIdo1D0B
0MThRHQszOF4v89O3OPy2PXrYZdxM521CckBsEEVvyKWWd/xlXzheqZvpao2me05
Dmrjb6VTuE5kev/3I6mC6aJMi7CF6fqXaUGm+StlPEAbUudjBnwav8PWTv2hF1VS
Ogj9K6nNG1EyTik4uEltZL6h1EWeZqYap/VJXfwNQn+BAv5xX2mLieIVHpltLQY7
ushULJhMTkMJVQbtHulMyUibE/JBT70ra5GgpjRdpib+3M/7OZOZAm0tWZMovZZS
+UfoC7JApa1FXcsQ03WhGHu3q6kL7TB6VW+QrBnxi8MQBeEydu2cAwrdGKJWtIjL
gBWuAJCEwH/wenim+7YzFYg72aCsaVQxcjYvHAiqEFPDziqk+CLebfZkgF4IEfdF
XbCnAYb8GQmlaJsbEVPtLvVVCYN0/RAEn6ec3ivHkCt4tM67F9pOEaIyk7PWOfpm
ViyUn62O30fQNfWKfjfhD5ttSY/8X0Fa7B9+V4s+2Exb2r0P/wd9k2sjK2IyDNMu
rim0ILriuQ3geBXdJi+uauPA3VnS0uoJoUPs4+nrWHITPOH8ZS7KeZYb9bdEtt61
I47cMXZl9LZASzRnhzgMYN0QBcnnwOXDHKQhwC0FSpB8NZ/gFjgy141/NM1VIIw0
fC9OjnidYxYTv58uFXCPKqCk+iEDQLj68M+VUJgwMSov7M5BA/ymwIPy/548vTZ4
rgE=
-----END ENCRYPTED PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIDdjCCAl6gAwIBAgIDBpgxMA0GCSqGSIb3DQEBBQUAMG4xEzARBgNVBAMTCkNE
cml2ZXIgQ0ExEDAOBgNVBAsTB0RyaXZlcnMxEDAOBgNVBAoTB01vbmdvREIxEjAQ
BgNVBAcTCVJleWtqYXZpazESMBAGA1UECBMJUmV5a2phdmlrMQswCQYDVQQGEwJJ
UzAeFw0xODAyMjgyMDQ0NDhaFw0zODAyMjgyMDQ0NDhaMG0xETAPBgNVBAMTCGV4
dGVybmFsMQ4wDAYDVQQLEwVvdGhlcjEQMA4GA1UEChMHTW9uZ29EQjEWMBQGA1UE
BxMNTmV3IFlvcmsgQ2l0eTERMA8GA1UECBMITmV3IFlvcmsxCzAJBgNVBAYTAlVT
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmaii9Oq1jnOjD/NvCOE5
XJAU0xSdWLi28q/HhsrIUwT2aRRObkVPx57Cl90/QKfwYmY4Z1E6oEXQX0F7tcV0
/e9easzBFB69ZS/ztF91xuofeK6tOmAPzRJx4pEAgoY5tlG+Ifs4BS23qe278w51
u1JWo1v50v5qr2MzDt/zZHz1EFz0Q5SBhVe9x5/jyVgd7f6gts2aXFrwE53OavlD
QS3d1aC3xlCGo8tH7UmI0rtJNiwmcPrvbkgSkxmsUDZW4kuvrrY3oDxeLEgaUrZq
rHkVY4WXbbe2359izlpZql5JsaW9FCcqmRP0xmjMZfTcMCLVKCK9JObGj/jlkOzg
QQIDAQABox4wHDAaBgNVHREEEzARgglsb2NhbGhvc3SHBH8AAAEwDQYJKoZIhvcN
AQEFBQADggEBAJ2pQoO8zf2BW5jZ8U5WVQlRm/s9LflH7jCkqqIIxRwFENtHEeK0
tOxfW1/JYw6GAuGsLrCXwVI1OeV0KPquoh26sFtrxHeeIxJjAOZ5ov/tLDBciBBD
QCnqPOCehvv/OH9BLFoFdW/3hLqHuKTiiDL9537CiZuDqiKyjucwSlqLk3fBcrna
Se8n2w+g3btD8dEYe0+G+dh2k0EJZ+78LW8Gr642knebxMjrsqD+wooryBBn8jls
9hJjG0D5TbX1koIHDYJE727FC/kWmNhK1Rvt1AKnsMFlrrQBbNK9YvEP6y3KQrb0
R1YgAaV74AIDaGGT1Id+mSteN7KOK34Ruso=
-----END CERTIFICATE-----

50 changes: 50 additions & 0 deletions data/certificates/client-pkcs8-unencrypted.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCZqKL06rWOc6MP
828I4TlckBTTFJ1YuLbyr8eGyshTBPZpFE5uRU/HnsKX3T9Ap/BiZjhnUTqgRdBf
QXu1xXT9715qzMEUHr1lL/O0X3XG6h94rq06YA/NEnHikQCChjm2Ub4h+zgFLbep
7bvzDnW7UlajW/nS/mqvYzMO3/NkfPUQXPRDlIGFV73Hn+PJWB3t/qC2zZpcWvAT
nc5q+UNBLd3VoLfGUIajy0ftSYjSu0k2LCZw+u9uSBKTGaxQNlbiS6+utjegPF4s
SBpStmqseRVjhZdtt7bfn2LOWlmqXkmxpb0UJyqZE/TGaMxl9NwwItUoIr0k5saP
+OWQ7OBBAgMBAAECggEAUm1YHTHa+vOlQWVA5u6KqtDPmvuv/Gv6F+2bhv84vvAm
ju/JsvWTem37zSNuTuzH0sEq+KFmZZuNz8t85WFrBN1nNLtpx7VFvAYhIV0j/PSS
tVZerrXhRAzk8rj+IQaH5vmqmOf+gSipIYraC+Rx226r8y3fsgOwjy0TsqMIGZrp
puczHAaMFvSXzTn2rD7d0AYnTgdIPJNDSwnTvTbnwMNDA4F7E/pJjjkm2kABdXSJ
wTuPnPSeUz0mTYpu4cOc+q+4jhpZr5GaF1declyIl8uU9gyK+gZRdrMHLVsFzdIM
Z+6beF+aCta5wXACou7kRvXQhatiQfTmOe4cpTElwQKBgQDMnkZVhDE7BryVnRE2
N/OJD64g/ygvJOL7rT+dqrNGhJCDHw30Vast2fxmibMk6iI3PkCj3XuTnXEtEOLr
td2bDpWCreMmj0hlFnFAh/p7J6olgbsnJO1Vhn7PcKevUfQVlpcDcu+GcvBHly2r
exAwKNxj6ZxqXf+KtI8w8Ca+PQKBgQDAPnfy7mMg/ytJtSlQz3srWSUERkOI1xcF
GimnVdofKu1PeqAsHOyNTRgoLDmI1NXG+1jva9ML8yBJQAf/+4a8IXKEwCQDVVHs
9iNa7gs6ULo41YRouL8cmat4XLh/OxWwYKZdxQWGTgnHKjVNdf6Df7OOm7uZBbU4
i4sYii/uVQKBgQCCJ39HsDF8gVl9tY4YNdjkayPw+zy9WDJFsrsPeGBWz8X4kc1X
iRK8tLcXJincpk2jZCbL1PthNzmhV+dv1ZwjoFA78o3VnjiHjJH3YUdUBTP2baH1
UUjiKQ4Kt3cCTxf6j3J5kCeKFxx9/UzgkgQHDka6CwQiqK3+tcGLeIa8ZQKBgQCM
wfBvde4s7chTKor6uT/UyGubCptOKTaYrMRM2kZfxb2GESIPyonFF+qVF3R05Gk2
TTib7NXVDQnZuEFjQ1Yuj0rbOhfkPOdEWiAe5uZfp1YCYQuW5ZZAqZ9r/G+18Jv7
zXhideyKnr74DcaDVd6ph6n/w7UC4LQEl9+bcyqPFQKBgATRW/owDjadRVuDB9C4
qzdyXuibMqRRUtvm6k4hs+HyirkrTnWb2YVbRMvrdT783s2wIeKB1oR5aG12A8ln
Hn7CeoLtRU12q65yOkX7vzER6oRmcyBVLhC+izRdoaBmKRuFdmQpXOALZRb/iNzQ
2nUsi2lvjvL42tYvIa8rtm4o
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIDdjCCAl6gAwIBAgIDBpgxMA0GCSqGSIb3DQEBBQUAMG4xEzARBgNVBAMTCkNE
cml2ZXIgQ0ExEDAOBgNVBAsTB0RyaXZlcnMxEDAOBgNVBAoTB01vbmdvREIxEjAQ
BgNVBAcTCVJleWtqYXZpazESMBAGA1UECBMJUmV5a2phdmlrMQswCQYDVQQGEwJJ
UzAeFw0xODAyMjgyMDQ0NDhaFw0zODAyMjgyMDQ0NDhaMG0xETAPBgNVBAMTCGV4
dGVybmFsMQ4wDAYDVQQLEwVvdGhlcjEQMA4GA1UEChMHTW9uZ29EQjEWMBQGA1UE
BxMNTmV3IFlvcmsgQ2l0eTERMA8GA1UECBMITmV3IFlvcmsxCzAJBgNVBAYTAlVT
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmaii9Oq1jnOjD/NvCOE5
XJAU0xSdWLi28q/HhsrIUwT2aRRObkVPx57Cl90/QKfwYmY4Z1E6oEXQX0F7tcV0
/e9easzBFB69ZS/ztF91xuofeK6tOmAPzRJx4pEAgoY5tlG+Ifs4BS23qe278w51
u1JWo1v50v5qr2MzDt/zZHz1EFz0Q5SBhVe9x5/jyVgd7f6gts2aXFrwE53OavlD
QS3d1aC3xlCGo8tH7UmI0rtJNiwmcPrvbkgSkxmsUDZW4kuvrrY3oDxeLEgaUrZq
rHkVY4WXbbe2359izlpZql5JsaW9FCcqmRP0xmjMZfTcMCLVKCK9JObGj/jlkOzg
QQIDAQABox4wHDAaBgNVHREEEzARgglsb2NhbGhvc3SHBH8AAAEwDQYJKoZIhvcN
AQEFBQADggEBAJ2pQoO8zf2BW5jZ8U5WVQlRm/s9LflH7jCkqqIIxRwFENtHEeK0
tOxfW1/JYw6GAuGsLrCXwVI1OeV0KPquoh26sFtrxHeeIxJjAOZ5ov/tLDBciBBD
QCnqPOCehvv/OH9BLFoFdW/3hLqHuKTiiDL9537CiZuDqiKyjucwSlqLk3fBcrna
Se8n2w+g3btD8dEYe0+G+dh2k0EJZ+78LW8Gr642knebxMjrsqD+wooryBBn8jls
9hJjG0D5TbX1koIHDYJE727FC/kWmNhK1Rvt1AKnsMFlrrQBbNK9YvEP6y3KQrb0
R1YgAaV74AIDaGGT1Id+mSteN7KOK34Ruso=
-----END CERTIFICATE-----

3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ require (
github.com/tidwall/pretty v1.0.0
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c
github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc
golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e
golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2 // indirect
golang.org/x/text v0.3.3 // indirect
Expand Down
6 changes: 6 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,17 @@ github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c h1:u40Z8hqBAAQyv+vATcGgV
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=
github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc h1:n+nNi93yXLkJvKwXNP9d55HC7lGK4H/SRcwB5IaUZLo=
github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a h1:fZHgsYlfvtyqToslyjUt3VOPF4J7aK/3MPcK7xp3PDk=
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a/go.mod h1:ul22v+Nro/R083muKhosV54bj5niojjWZvU8xrevuH4=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5 h1:8dUaAV7K4uHsF56JQWkprecIQKdPHtR9jCHF5nB8uzc=
golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 h1:xMPOj6Pz6UipU1wXLkrtqpHbR0AVFnyPEQq/wRWz9lM=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI=
Expand Down
138 changes: 80 additions & 58 deletions mongo/integration/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,67 +82,89 @@ func TestClient(t *testing.T) {
assert.Nil(mt, found, "SSLServerHasCertificateAuthority not found in result")
})
mt.RunOpts("x509", mtest.NewOptions().Auth(true).SSL(true), func(mt *mtest.T) {
const user = "C=US,ST=New York,L=New York City,O=MongoDB,OU=other,CN=external"
db := mt.Client.Database("$external")

// We don't care if the user doesn't already exist.
_ = db.RunCommand(
mtest.Background,
bson.D{{"dropUser", user}},
)
err := db.RunCommand(
mtest.Background,
bson.D{
{"createUser", user},
{"roles", bson.A{
bson.D{{"role", "readWrite"}, {"db", "test"}},
}},
testCases := []struct {
certificate string
password string
}{
{
"client.pem",
"",
},
).Err()
assert.Nil(mt, err, "createUser error: %v", err)

baseConnString := mtest.ClusterURI()
// remove username/password from base conn string
revisedConnString := "mongodb://"
split := strings.Split(baseConnString, "@")
assert.Equal(t, 2, len(split), "expected 2 parts after split, got %v (connstring %v)", split, baseConnString)
revisedConnString += split[1]

cs := fmt.Sprintf(
"%s&sslClientCertificateKeyFile=%s&authMechanism=MONGODB-X509&authSource=$external",
revisedConnString,
path.Join(certificatesDir, "client.pem"),
)
authClientOpts := options.Client().ApplyURI(cs)
testutil.AddTestServerAPIVersion(authClientOpts)
authClient, err := mongo.Connect(mtest.Background, authClientOpts)
assert.Nil(mt, err, "authClient Connect error: %v", err)
defer func() { _ = authClient.Disconnect(mtest.Background) }()

rdr, err := authClient.Database("test").RunCommand(mtest.Background, bson.D{
{"connectionStatus", 1},
}).DecodeBytes()
assert.Nil(mt, err, "connectionStatus error: %v", err)
users, err := rdr.LookupErr("authInfo", "authenticatedUsers")
assert.Nil(mt, err, "authenticatedUsers not found in response")
elems, err := users.Array().Elements()
assert.Nil(mt, err, "error getting users elements: %v", err)

for _, userElem := range elems {
rdr := userElem.Value().Document()
var u struct {
User string
DB string
}
{
"client-pkcs8-encrypted.pem",
"&sslClientCertificateKeyPassword=password",
},
{
"client-pkcs8-unencrypted.pem",
"",
},
}
for _, tc := range testCases {
mt.Run(tc.certificate, func(mt *mtest.T) {
const user = "C=US,ST=New York,L=New York City,O=MongoDB,OU=other,CN=external"
db := mt.Client.Database("$external")

// We don't care if the user doesn't already exist.
_ = db.RunCommand(
mtest.Background,
bson.D{{"dropUser", user}},
)
err := db.RunCommand(
mtest.Background,
bson.D{
{"createUser", user},
{"roles", bson.A{
bson.D{{"role", "readWrite"}, {"db", "test"}},
}},
},
).Err()
assert.Nil(mt, err, "createUser error: %v", err)

baseConnString := mtest.ClusterURI()
// remove username/password from base conn string
revisedConnString := "mongodb://"
split := strings.Split(baseConnString, "@")
assert.Equal(t, 2, len(split), "expected 2 parts after split, got %v (connstring %v)", split, baseConnString)
revisedConnString += split[1]

cs := fmt.Sprintf(
"%s&sslClientCertificateKeyFile=%s&authMechanism=MONGODB-X509&authSource=$external%s",
revisedConnString,
path.Join(certificatesDir, tc.certificate),
tc.password,
)
authClientOpts := options.Client().ApplyURI(cs)
testutil.AddTestServerAPIVersion(authClientOpts)
authClient, err := mongo.Connect(mtest.Background, authClientOpts)
assert.Nil(mt, err, "authClient Connect error: %v", err)
defer func() { _ = authClient.Disconnect(mtest.Background) }()

rdr, err := authClient.Database("test").RunCommand(mtest.Background, bson.D{
{"connectionStatus", 1},
}).DecodeBytes()
assert.Nil(mt, err, "connectionStatus error: %v", err)
users, err := rdr.LookupErr("authInfo", "authenticatedUsers")
assert.Nil(mt, err, "authenticatedUsers not found in response")
elems, err := users.Array().Elements()
assert.Nil(mt, err, "error getting users elements: %v", err)

for _, userElem := range elems {
rdr := userElem.Value().Document()
var u struct {
User string
DB string
}

if err := bson.Unmarshal(rdr, &u); err != nil {
continue
}
if u.User == user && u.DB == "$external" {
return
}
if err := bson.Unmarshal(rdr, &u); err != nil {
continue
}
if u.User == user && u.DB == "$external" {
return
}
}
mt.Fatal("unable to find authenticated user")
})
}
mt.Fatal("unable to find authenticated user")
})
mt.RunOpts("list databases", noClientOpts, func(mt *mtest.T) {
mt.RunOpts("filter", noClientOpts, func(mt *mtest.T) {
Expand Down
33 changes: 27 additions & 6 deletions mongo/options/clientoptions.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"strings"
"time"

"github.com/youmark/pkcs8"
"go.mongodb.org/mongo-driver/bson/bsoncodec"
"go.mongodb.org/mongo-driver/event"
"go.mongodb.org/mongo-driver/mongo/readconcern"
Expand Down Expand Up @@ -902,14 +903,34 @@ func addClientCertFromBytes(cfg *tls.Config, data []byte, keyPasswd string) (str
certDecodedBlock = currentBlock.Bytes
start += len(certBlock)
} else if strings.HasSuffix(currentBlock.Type, "PRIVATE KEY") {
if keyPasswd != "" && x509.IsEncryptedPEMBlock(currentBlock) {
var encoded bytes.Buffer
buf, err := x509.DecryptPEMBlock(currentBlock, []byte(keyPasswd))
if err != nil {
return "", err
isEncrypted := x509.IsEncryptedPEMBlock(currentBlock) || strings.Contains(currentBlock.Type, "ENCRYPTED PRIVATE KEY")
if isEncrypted {
if keyPasswd == "" {
return "", fmt.Errorf("no password provided to decrypt private key")
}

pem.Encode(&encoded, &pem.Block{Type: currentBlock.Type, Bytes: buf})
var keyBytes []byte
var err error
// Process the X.509-encrypted or PKCS-encrypted PEM block.
if x509.IsEncryptedPEMBlock(currentBlock) {
// Only covers encrypted PEM data with a DEK-Info header.
keyBytes, err = x509.DecryptPEMBlock(currentBlock, []byte(keyPasswd))
if err != nil {
return "", err
}
} else if strings.Contains(currentBlock.Type, "ENCRYPTED") {
// The pkcs8 package only handles the PKCS #5 v2.0 scheme.
decrypted, err := pkcs8.ParsePKCS8PrivateKey(currentBlock.Bytes, []byte(keyPasswd))
if err != nil {
return "", err
}
keyBytes, err = x509MarshalPKCS8PrivateKey(decrypted)
if err != nil {
return "", err
}
}
var encoded bytes.Buffer
pem.Encode(&encoded, &pem.Block{Type: currentBlock.Type, Bytes: keyBytes})
keyBlock = encoded.Bytes()
start = len(data) - len(remaining)
} else {
Expand Down
4 changes: 4 additions & 0 deletions mongo/options/clientoptions_1_10.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,7 @@ import "crypto/x509"
func x509CertSubject(cert *x509.Certificate) string {
return cert.Subject.String()
}

func x509MarshalPKCS8PrivateKey(pkcs8 interface{}) ([]byte, error) {
return x509.MarshalPKCS8PrivateKey(pkcs8)
}
11 changes: 9 additions & 2 deletions mongo/options/clientoptions_1_9.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,17 @@ package options

import (
"crypto/x509"
"fmt"
)

// We don't support version less then 1.10, but Evergreen needs to be able to compile the driver
// using version 1.8.
// We don't support Go versions less than 1.10, but Evergreen needs to be able to compile the driver
// using version 1.9 and cert.Subject
func x509CertSubject(cert *x509.Certificate) string {
return ""
}

// We don't support Go versions less than 1.10, but Evergreen needs to be able to compile the driver
// using version 1.9 and x509.MarshalPKCS8PrivateKey()
func x509MarshalPKCS8PrivateKey(pkcs8 interface{}) ([]byte, error) {
return nil, fmt.Errorf("PKCS8-encrypted client private keys are only supported with go1.10+")
}
23 changes: 23 additions & 0 deletions vendor/github.com/youmark/pkcs8/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions vendor/github.com/youmark/pkcs8/.travis.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 15a1051

Please sign in to comment.