package main import ( "crypto" "crypto/x509" "fmt" "software.sslmate.com/src/go-pkcs12") // createBundle writes key, certificate and chain with modern protection:// AES-256-CBC with PBKDF2 for the contents, HMAC-SHA-256 for integrity.func createBundle(key crypto.PrivateKey, leaf *x509.Certificate, chain []*x509.Certificate, password string) ([]byte, error) { return pkcs12.Modern.Encode(key, leaf, chain, password)} // readBundle decodes the file again: the key, the leaf certificate and the rest of the chain.func readBundle(data []byte, password string) error { key, leaf, chain, err := pkcs12.DecodeChain(data, password) if err != nil { return err } fmt.Println("certificate:", leaf.Subject) for _, c := range chain { fmt.Println("chain:", c.Subject) } public := key.(crypto.Signer).Public().(interface{ Equal(crypto.PublicKey) bool }) fmt.Println("key matches certificate:", public.Equal(leaf.PublicKey)) return nil} How it works
pkcs12.Modern.Encode(key, leaf, chain, password)produces the file: PBES2 with PBKDF2 and AES-256-CBC for key and certificates, an HMAC-SHA-256 MAC over the whole.pkcs12.DecodeChain(data, password)returns the key, the leaf certificate and the rest of the chain.- The key comes back as
crypto.PrivateKey;Public().Equal(leaf.PublicKey)confirms it belongs to the certificate. golang.org/x/crypto/pkcs12is frozen and can only decode; go-pkcs12 is the maintained fork that also encodes.
Gotchas
pkcs12.Decode(singular) expects exactly one key and one certificate; on a bundle with a chain it fails withpkcs12: expected exactly two safe bags in the PFX PDU. UseDecodeChain.- go-pkcs12 writes no friendly name: OpenSSL shows an empty
friendlyNamefor the key. Tools that select the key by alias need it set by other means. pkcs12.Legacy(today the same asLegacyDES) writes 3DES —pbeWithSHA1And3-KeyTripleDES-CBCin the run — for software that cannot read AES; useModernunless such a reader forces you.- A wrong password returns
pkcs12: decryption password incorrect; the same error comes back for a damaged file.
Related recipes
- How to create a PKCS#12 (.p12/.pfx) file from a key and certificate chain with OpenSSL
- How to create a PKCS#12 (.p12/.pfx) file from a key and certificate chain in Python
- How to create a PKCS#12 (.p12/.pfx) file from a key and certificate chain in Rust
- How to convert a certificate and a private key between PEM and DER in Go
- How to verify a certificate chain against your own trust store in Go