Skip to content

Commit bf88e3f

Browse files
ereOnbradfitz
authored andcommitted
pkcs12: add a DecodeAll method
Addition of a DecodeAll function as it was mentioned in #14015. This solves a need many people seem to have, where there is no effective way loading PKCS12 files that contain more than one certificate and one private key. The utility functions used by Decode are all internal, which makes implementing this on the user-side tedious, hence the suggestion of providing a more liberal version of the function: DecodeAll. Fixes golang/go#14015 Change-Id: I03c541553b6cb488c2c59d39575342a43136e592 GitHub-Last-Rev: 05f6847 GitHub-Pull-Request: #38 Reviewed-on: https://go-review.googlesource.com/c/105876 Reviewed-by: Adam Shannon <[email protected]> Reviewed-by: Brad Fitzpatrick <[email protected]> Run-TryBot: Brad Fitzpatrick <[email protected]>
1 parent c7b33c3 commit bf88e3f

File tree

2 files changed

+67
-0
lines changed

2 files changed

+67
-0
lines changed

pkcs12/pkcs12.go

+39
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,45 @@ func Decode(pfxData []byte, password string) (privateKey interface{}, certificat
267267
return
268268
}
269269

270+
// DecodeAll extracts all certificate and private keys from pfxData.
271+
func DecodeAll(pfxData []byte, password string) (privateKeys []interface{}, certificates []*x509.Certificate, err error) {
272+
encodedPassword, err := bmpString(password)
273+
if err != nil {
274+
return nil, nil, err
275+
}
276+
277+
bags, encodedPassword, err := getSafeContents(pfxData, encodedPassword)
278+
if err != nil {
279+
return nil, nil, err
280+
}
281+
282+
for _, bag := range bags {
283+
switch {
284+
case bag.Id.Equal(oidCertBag):
285+
certsData, err := decodeCertBag(bag.Value.Bytes)
286+
if err != nil {
287+
return nil, nil, err
288+
}
289+
certs, err := x509.ParseCertificates(certsData)
290+
if err != nil {
291+
return nil, nil, err
292+
}
293+
certificates = append(certificates, certs...)
294+
295+
case bag.Id.Equal(oidPKCS8ShroundedKeyBag):
296+
privateKey, err := decodePkcs8ShroudedKeyBag(bag.Value.Bytes, encodedPassword)
297+
298+
if err != nil {
299+
return nil, nil, err
300+
}
301+
302+
privateKeys = append(privateKeys, privateKey)
303+
}
304+
}
305+
306+
return
307+
}
308+
270309
func getSafeContents(p12Data, password []byte) (bags []safeBag, updatedPassword []byte, err error) {
271310
pfx := new(pfxPdu)
272311
if err := unmarshal(p12Data, pfx); err != nil {

pkcs12/pkcs12_test.go

+28
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,34 @@ func TestPfx(t *testing.T) {
3131
}
3232
}
3333

34+
func TestPfxDecodeAll(t *testing.T) {
35+
for commonName, base64P12 := range testdata {
36+
p12, _ := base64.StdEncoding.DecodeString(base64P12)
37+
38+
privs, certs, err := DecodeAll(p12, "")
39+
40+
if err != nil {
41+
t.Fatal(err)
42+
}
43+
44+
if len(privs) != 1 {
45+
t.Errorf("expected 1 private key, but got %d", len(privs))
46+
}
47+
48+
if len(certs) != 1 {
49+
t.Errorf("expected 1 certificate, but got %d", len(certs))
50+
}
51+
52+
if err := privs[0].(*rsa.PrivateKey).Validate(); err != nil {
53+
t.Errorf("error while validating private key: %v", err)
54+
}
55+
56+
if certs[0].Subject.CommonName != commonName {
57+
t.Errorf("expected common name to be %q, but found %q", commonName, certs[0].Subject.CommonName)
58+
}
59+
}
60+
}
61+
3462
func TestPEM(t *testing.T) {
3563
for commonName, base64P12 := range testdata {
3664
p12, _ := base64.StdEncoding.DecodeString(base64P12)

0 commit comments

Comments
 (0)