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: 05f6847ff80ca34c92a01a688c7b81e874af3009 GitHub-Pull-Request: golang/crypto#38 Reviewed-on: https://go-review.googlesource.com/c/105876 Reviewed-by: Adam Shannon <adamkshannon@gmail.com> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
committed by
Brad Fitzpatrick
parent
c7b33c32a3
commit
bf88e3f4ba
@@ -267,6 +267,45 @@ func Decode(pfxData []byte, password string) (privateKey interface{}, certificat
|
||||
return
|
||||
}
|
||||
|
||||
// DecodeAll extracts all certificate and private keys from pfxData.
|
||||
func DecodeAll(pfxData []byte, password string) (privateKeys []interface{}, certificates []*x509.Certificate, err error) {
|
||||
encodedPassword, err := bmpString(password)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
bags, encodedPassword, err := getSafeContents(pfxData, encodedPassword)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
for _, bag := range bags {
|
||||
switch {
|
||||
case bag.Id.Equal(oidCertBag):
|
||||
certsData, err := decodeCertBag(bag.Value.Bytes)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
certs, err := x509.ParseCertificates(certsData)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
certificates = append(certificates, certs...)
|
||||
|
||||
case bag.Id.Equal(oidPKCS8ShroundedKeyBag):
|
||||
privateKey, err := decodePkcs8ShroudedKeyBag(bag.Value.Bytes, encodedPassword)
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
privateKeys = append(privateKeys, privateKey)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func getSafeContents(p12Data, password []byte) (bags []safeBag, updatedPassword []byte, err error) {
|
||||
pfx := new(pfxPdu)
|
||||
if err := unmarshal(p12Data, pfx); err != nil {
|
||||
|
||||
@@ -31,6 +31,34 @@ func TestPfx(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestPfxDecodeAll(t *testing.T) {
|
||||
for commonName, base64P12 := range testdata {
|
||||
p12, _ := base64.StdEncoding.DecodeString(base64P12)
|
||||
|
||||
privs, certs, err := DecodeAll(p12, "")
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(privs) != 1 {
|
||||
t.Errorf("expected 1 private key, but got %d", len(privs))
|
||||
}
|
||||
|
||||
if len(certs) != 1 {
|
||||
t.Errorf("expected 1 certificate, but got %d", len(certs))
|
||||
}
|
||||
|
||||
if err := privs[0].(*rsa.PrivateKey).Validate(); err != nil {
|
||||
t.Errorf("error while validating private key: %v", err)
|
||||
}
|
||||
|
||||
if certs[0].Subject.CommonName != commonName {
|
||||
t.Errorf("expected common name to be %q, but found %q", commonName, certs[0].Subject.CommonName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPEM(t *testing.T) {
|
||||
for commonName, base64P12 := range testdata {
|
||||
p12, _ := base64.StdEncoding.DecodeString(base64P12)
|
||||
|
||||
Reference in New Issue
Block a user