Skip to content

Commit

Permalink
Allow PKCS#8 private keys in .pem files (sideshow#101)
Browse files Browse the repository at this point in the history
* Allow PKCS#8 private keys in .pem files

* Fix tests and test new behavior
  • Loading branch information
jameshfisher authored and sideshow committed Dec 18, 2017
1 parent cf826c6 commit df275e5
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 9 deletions.
60 changes: 60 additions & 0 deletions certificate/_fixtures/certificate-valid-pkcs8.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
Bag Attributes
localKeyID: 8C 1A 9F 00 66 BD 24 42 B9 5D 1E EB FE 5E 8B CA 04 3D 73 83
friendlyName: APNS/2 Private Key
subject=/C=NZ/ST=Wellington/L=Wellington/O=Internet Widgits Pty Ltd/OU=9ZEH62KRVV/CN=APNS/2 Development IOS Push Services: com.sideshow.Apns2
issuer=/C=NZ/ST=Wellington/L=Wellington/O=APNS/2 Inc./OU=APNS/2 Worldwide Developer Relations/CN=APNS/2 Worldwide Developer Relations Certification Authority
-----BEGIN CERTIFICATE-----
MIID6zCCAtMCAQIwDQYJKoZIhvcNAQELBQAwgcMxCzAJBgNVBAYTAk5aMRMwEQYD
VQQIEwpXZWxsaW5ndG9uMRMwEQYDVQQHEwpXZWxsaW5ndG9uMRQwEgYDVQQKEwtB
UE5TLzIgSW5jLjEtMCsGA1UECxMkQVBOUy8yIFdvcmxkd2lkZSBEZXZlbG9wZXIg
UmVsYXRpb25zMUUwQwYDVQQDEzxBUE5TLzIgV29ybGR3aWRlIERldmVsb3BlciBS
ZWxhdGlvbnMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTYwMTA4MDgzNDMw
WhcNMjYwMTA1MDgzNDMwWjCBsjELMAkGA1UEBhMCTloxEzARBgNVBAgTCldlbGxp
bmd0b24xEzARBgNVBAcTCldlbGxpbmd0b24xITAfBgNVBAoTGEludGVybmV0IFdp
ZGdpdHMgUHR5IEx0ZDETMBEGA1UECxMKOVpFSDYyS1JWVjFBMD8GA1UEAxM4QVBO
Uy8yIERldmVsb3BtZW50IElPUyBQdXNoIFNlcnZpY2VzOiBjb20uc2lkZXNob3cu
QXBuczIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDY0c1TKB5oZPwQ
7t1CwMIrvqB6GIU3tPy6RhckZXTkOB8YeBWJ7UKfCz8HGHFVomBP0T5OUbeqQzqW
YJbQzZ8a6ZMszbL0lO4X9++3Oi5/TtAwOUOK8rOFN25m2KfsayHQZ/4vWStK2Fwm
5aJbGLlpH/b/7z1D4vhmMgoBuT1IuyhGiyFxlZ9EtTloFvsqM1E5fYZOSZACyXTa
K4vdgbQMgUVsI714FAgLTlK0UeiRkmKm3pdbtfVbrthzI+IHXKItUIy+Fn20PRMh
dSnaztSz7tgBWCIx22qvcYogHWiOgUYIM772zE2y8UVOr8DsiRlsOHSA7EI4MJcQ
G2FUq2Z/AgMBAAEwDQYJKoZIhvcNAQELBQADggEBAGyfyO2HMgcdeBcz3bt5BILX
f7RA2/UmVIwcKR1qotTsF+PnBmcILeyOQgDe9tGU5cRc79kDt3JRmMYROFIMgFRf
Wf22uOKtho7GQQaKvG+bkgMVdYFRlBHnF+KeqKH81qb9p+CT4Iw0GehIL1DijFLR
VIAIBYpz4oBPCIE1ISVT+Fgaf3JAh59kbPbNw9AIDxaBtP8EuzSTNwfbxoGbCobS
Wi1U8IsCwQFt8tM1m4ZXD1CcZIrGdryeAhVkvKIJRiU5QYWI2nqZN+JqQucm9ad0
mYO5mJkIobUa4+ZJhCPKEdmgpFbRGk0wVuaDM9Cv6P2srsYAjaO4y3VP0GvNKRI=
-----END CERTIFICATE-----
Bag Attributes
localKeyID: 8C 1A 9F 00 66 BD 24 42 B9 5D 1E EB FE 5E 8B CA 04 3D 73 83
friendlyName: APNS/2 Private Key
Key Attributes: <No Attributes>
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDY0c1TKB5oZPwQ
7t1CwMIrvqB6GIU3tPy6RhckZXTkOB8YeBWJ7UKfCz8HGHFVomBP0T5OUbeqQzqW
YJbQzZ8a6ZMszbL0lO4X9++3Oi5/TtAwOUOK8rOFN25m2KfsayHQZ/4vWStK2Fwm
5aJbGLlpH/b/7z1D4vhmMgoBuT1IuyhGiyFxlZ9EtTloFvsqM1E5fYZOSZACyXTa
K4vdgbQMgUVsI714FAgLTlK0UeiRkmKm3pdbtfVbrthzI+IHXKItUIy+Fn20PRMh
dSnaztSz7tgBWCIx22qvcYogHWiOgUYIM772zE2y8UVOr8DsiRlsOHSA7EI4MJcQ
G2FUq2Z/AgMBAAECggEBAJbxkIj44Bp7W0SKln0XZtY/csctdOjwVhV0ID5VZ4hO
Tc+iIhSQmZXRpYJSEOy2C2jl2gN6PmwJO6te+P/Kdp6sx6okVhaR7CPBlyAvIBm/
C47W/t+n0TTH/1MYN+eOOc815q6d3FbRw23M5jeXQdUezL0ml7dANwAmi/LhO/n6
EVjiQPFQEazKO+FJxWAqDm0uQlyWbew678sbIuqnA0jc4kB0wi5UPg3YFnVo4Rqn
qanbLwh7T9HhhZxpnkDg/DvFQ+XpJdz265r/vxBMRG08Lp6PIIGITTlrybdDeK53
de2eXLCzYrCGAEB8TozjNH9/c5AHtkhcyHJmmZlnDnECgYEA9ifzgiuUhB61ZB+8
90zsrOCHpQMcK6CeUIOCHBilEkaLyEx+5lXE0itgAnMtgNDTWUUlEmBZdNxurP00
HPWeGD5w07PX8pj7fx65157oM1ibO0/uMM/aOdpL522MLyEBc5ucWob42KUwMsu7
ppGasloiZuNKt/IuITqa8nu7zWcCgYEA4X2D3fBnSYvWuTazlbAcZM1T8do62ZZL
jPuQDt/hBpG5v4zCmlmaYNk8emJlfsE9xnOI49CH7GfsipEahBYEvKQFW3zNkWgt
kmgJHefreV7HkDin/Q+nWAVmtH7Ffw9hWizfJ56JbI8qxdc1zSzlDAdlxfpZvwQd
OFNcYIF61ykCgYAx5AkL0g9o89xp7bDcIsA5jcyQWmAES6qqwOzHCwux95BvSWnS
/4FD47yy4mtPl4OurUAFSHf5IpBgCXXdhL7FRSqTDflv1yfqLO0X0cJYXdYgoGOz
iv09Coyl3GM0TilAKEL5ai/XoStysC5ZZVuIWJJubhT/0VseKwWqrf9zcwKBgH6/
NK4+AXDfv7SgQNW1BmDK4ZKink3MI299v/38bdppc0Vuc7ya/SHPOiV4xaA4Mucn
7hxQDPcfe2BwK71vOv5mG/TO9CX1rxgKjoVW5Y91bStuDU87y064yoBOeejv1kL/
0ffNL2XsG5jVXZKU17KpPdXI4UVzpJESmmxMm6XxAoGADGdAHwwDvM9Qu7VyXJok
t20R1E+QpY3uUpim1zR79Ud9KwrGx5aR+qLOBdnnWRBOtPplvodhF/ALWYxcdZEp
HJiMCcLFWKbphB34pVPj2JEMMCIgWgwYDiK+9wiWd6o5lk8MigonrQiM78NkdaTD
mYuNoitP6pDdcAZ0kDXeFyY=
-----END PRIVATE KEY-----
21 changes: 13 additions & 8 deletions certificate/certificate.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ import (

// Possible errors when parsing a certificate.
var (
ErrFailedToDecryptKey = errors.New("failed to decrypt private key")
ErrFailedToParsePKCS1PrivateKey = errors.New("failed to parse PKCS1 private key")
ErrFailedToParseCertificate = errors.New("failed to parse certificate PEM data")
ErrNoPrivateKey = errors.New("no private key")
ErrNoCertificate = errors.New("no certificate")
ErrFailedToDecryptKey = errors.New("failed to decrypt private key")
ErrFailedToParsePrivateKey = errors.New("failed to parse private key")
ErrFailedToParseCertificate = errors.New("failed to parse certificate PEM data")
ErrNoPrivateKey = errors.New("no private key")
ErrNoCertificate = errors.New("no certificate")
)

// FromP12File loads a PKCS#12 certificate from a local file and returns a
Expand Down Expand Up @@ -120,9 +120,14 @@ func unencryptPrivateKey(block *pem.Block, password string) (crypto.PrivateKey,
}

func parsePrivateKey(bytes []byte) (crypto.PrivateKey, error) {
var key crypto.PrivateKey
key, err := x509.ParsePKCS1PrivateKey(bytes)
if err != nil {
return nil, ErrFailedToParsePKCS1PrivateKey
if err == nil {
return key, nil
}
key, err = x509.ParsePKCS8PrivateKey(bytes)
if err == nil {
return key, nil
}
return key, nil
return nil, ErrFailedToParsePrivateKey
}
15 changes: 14 additions & 1 deletion certificate/certificate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,19 @@ func TestValidCertificateFromPemBytes(t *testing.T) {
assert.Nil(t, verifyHostname(cer))
}

func TestValidCertificateFromPemFileWithPKCS8PrivateKey(t *testing.T) {
cer, err := certificate.FromPemFile("_fixtures/certificate-valid-pkcs8.pem", "")
assert.NoError(t, err)
assert.Nil(t, verifyHostname(cer))
}

func TestValidCertificateFromPemBytesWithPKCS8PrivateKey(t *testing.T) {
bytes, _ := ioutil.ReadFile("_fixtures/certificate-valid-pkcs8.pem")
cer, err := certificate.FromPemBytes(bytes, "")
assert.NoError(t, err)
assert.Nil(t, verifyHostname(cer))
}

func TestEncryptedValidCertificateFromPemFile(t *testing.T) {
cer, err := certificate.FromPemFile("_fixtures/certificate-valid-encrypted.pem", "password")
assert.NoError(t, err)
Expand All @@ -79,7 +92,7 @@ func TestBadPasswordPemFile(t *testing.T) {
func TestBadKeyPemFile(t *testing.T) {
cer, err := certificate.FromPemFile("_fixtures/certificate-bad-key.pem", "")
assert.Equal(t, tls.Certificate{}, cer)
assert.Equal(t, certificate.ErrFailedToParsePKCS1PrivateKey, err)
assert.Equal(t, certificate.ErrFailedToParsePrivateKey, err)
}

func TestNoKeyPemFile(t *testing.T) {
Expand Down

0 comments on commit df275e5

Please sign in to comment.