pkcs12

package module
v0.0.0-...-1efe665 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 7, 2023 License: BSD-3-Clause Imports: 34 Imported by: 0

README

package pkcs12

Documentation

import "github.com/pschou/go-pkcs12" 

Package pkcs12 implements some of PKCS#12 (also known as P12 or PFX). It is intended for decoding DER-encoded P12/PFX files for use with the crypto/tls package, and for encoding P12/PFX files for use by legacy applications which do not support newer formats. Since PKCS#12 uses weak encryption primitives, it SHOULD NOT be used for new applications.

Note that only DER-encoded PKCS#12 files are supported, even though PKCS#12 allows BER encoding. This is because encoding/asn1 only supports DER.

This package is forked from golang.org/x/crypto/pkcs12, which is frozen and github.com/SSLMate/go-pkcs12. The implementation is distilled from https://tools.ietf.org/html/rfc7292 and referenced documents.

Documentation

Overview

Package pkcs12 implements some of PKCS#12 (also known as P12 or PFX). It is intended for decoding DER-encoded P12/PFX files for use with the crypto/tls package, and for encoding P12/PFX files for use by legacy applications which do not support newer formats. Since PKCS#12 uses weak encryption primitives, it SHOULD NOT be used for new applications.

Note that only DER-encoded PKCS#12 files are supported, even though PKCS#12 allows BER encoding. This is because encoding/asn1 only supports DER.

This package is forked from golang.org/x/crypto/pkcs12, which is frozen. The implementation is distilled from https://tools.ietf.org/html/rfc7292 and referenced documents.

By definition, the Fingerprint is a hash of the public key bytes, hence one can use the Fingerprint returned from reading a p12 file to match the key with the certificate, as they will have the same hash. This is important as when a p12 file is loaded, it may have multiple keys and certificates, which can be provided in any order.

Before loading the proper cert with key to make a tls.Certificate, it is a good idea to do something like the following:

ce := p12.CertEntries[0]  // After we have determined this is the needed cert
for _, k := range p12.KeyEntries {
  if bytes.Match(k.Fingerprint, ce.Fingerprint) {
    t := tls.Certificate{
      Certificate: [][]byte{ce.Cert.Raw},
      Leaf:        ce.Cert,
      PrivateKey:  k.Key,
    }
  }
}

Index

Constants

View Source
const DefaultPassword = "changeit"

DefaultPassword is the string "changeit", a commonly-used password for PKCS#12 files. Due to the weak encryption used by PKCS#12, it is RECOMMENDED that you use DefaultPassword when encoding PKCS#12 files, and protect the PKCS#12 files using other means.

Variables

View Source
var (
	// Password based encryption
	OidPBES2 = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 5, 13})

	// PBE algorithms
	OidPBEWithSHAAnd128BitRC4        = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 1, 1})
	OidPBEWithSHAAnd40BitRC4         = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 1, 2})
	OidPBEWithSHAAnd3KeyTripleDESCBC = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 1, 3})
	OidPBEWithSHAAnd2KeyTripleDESCBC = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 1, 4})
	OidPBEWithSHAAnd128BitRC2CBC     = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 1, 5})
	OidPBEWithSHAAnd40BitRC2CBC      = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 1, 6})

	// PBES2 HMAC algorithms
	OidHmacWithGOST3411_256 = asn1.ObjectIdentifier([]int{1, 2, 643, 7, 1, 1, 4, 1})
	OidHmacWithGOST3411_512 = asn1.ObjectIdentifier([]int{1, 2, 643, 7, 1, 1, 4, 2})
	OidHmacWithMD5          = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 2, 6})
	OidHmacWithSHA1         = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 2, 7})
	OidHmacWithSHA256_224   = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 2, 8})
	OidHmacWithSHA256       = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 2, 9})
	OidHmacWithSHA512_384   = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 2, 10})
	OidHmacWithSHA512       = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 2, 11})
	OidHmacWithSHA512_224   = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 2, 12})
	OidHmacWithSHA512_256   = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 2, 13})
	OidHmacWithSHA3_224     = asn1.ObjectIdentifier([]int{2, 16, 840, 1, 101, 3, 4, 2, 13})
	OidHmacWithSHA3_256     = asn1.ObjectIdentifier([]int{2, 16, 840, 1, 101, 3, 4, 2, 14})
	OidHmacWithSHA3_384     = asn1.ObjectIdentifier([]int{2, 16, 840, 1, 101, 3, 4, 2, 15})
	OidHmacWithSHA3_512     = asn1.ObjectIdentifier([]int{2, 16, 840, 1, 101, 3, 4, 2, 16})

	// PBES2 Stream ciphers
	OidEncryptionAlgorithmAES128CBC  = asn1.ObjectIdentifier([]int{2, 16, 840, 1, 101, 3, 4, 1, 2})
	OidEncryptionAlgorithmAES192CBC  = asn1.ObjectIdentifier([]int{2, 16, 840, 1, 101, 3, 4, 1, 22})
	OidEncryptionAlgorithmAES256CBC  = asn1.ObjectIdentifier([]int{2, 16, 840, 1, 101, 3, 4, 1, 42})
	OidEncryptionAlgorithmDESCBC     = asn1.ObjectIdentifier([]int{1, 3, 14, 3, 2, 7})
	OidEncryptionAlgorithmDESEDE3CBC = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 3, 7})

	OidAES128WrapPad = asn1.ObjectIdentifier([]int{2, 16, 840, 1, 101, 3, 4, 1, 8})
	OidAES192WrapPad = asn1.ObjectIdentifier([]int{2, 16, 840, 1, 101, 3, 4, 1, 28})
	OidAES256WrapPad = asn1.ObjectIdentifier([]int{2, 16, 840, 1, 101, 3, 4, 1, 48})
)
View Source
var (
	// ErrDecryption represents a failure to decrypt the input.
	ErrDecryption = errors.New("decryption error, incorrect padding")

	// ErrIncorrectPassword is returned when an incorrect password is detected.
	// Usually, P12/PFX data is signed to be able to verify the password.
	ErrIncorrectPassword = errors.New("decryption password incorrect")
)
View Source
var (
	OidGOST3411_256  = asn1.ObjectIdentifier([]int{1, 2, 643, 7, 1, 1, 2, 2})
	OidGOST3411_512  = asn1.ObjectIdentifier([]int{1, 2, 643, 7, 1, 1, 2, 3})
	OidMD2           = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 2, 2})
	OidMD4           = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 2, 4})
	OidMD5           = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 2, 5})
	OidSHA1          = asn1.ObjectIdentifier([]int{1, 3, 14, 3, 2, 26})
	OidSHA256        = asn1.ObjectIdentifier([]int{2, 16, 840, 1, 101, 3, 4, 2, 1})
	OidSHA384        = asn1.ObjectIdentifier([]int{2, 16, 840, 1, 101, 3, 4, 2, 2})
	OidSHA512        = asn1.ObjectIdentifier([]int{2, 16, 840, 1, 101, 3, 4, 2, 3})
	OidSHA256_224    = asn1.ObjectIdentifier([]int{2, 16, 840, 1, 101, 3, 4, 2, 4})
	OidSHA512_224    = asn1.ObjectIdentifier([]int{2, 16, 840, 1, 101, 3, 4, 2, 5})
	OidSHA512_256    = asn1.ObjectIdentifier([]int{2, 16, 840, 1, 101, 3, 4, 2, 6})
	OidSHA3_224      = asn1.ObjectIdentifier([]int{2, 16, 840, 1, 101, 3, 4, 2, 7})
	OidSHA3_256      = asn1.ObjectIdentifier([]int{2, 16, 840, 1, 101, 3, 4, 2, 8})
	OidSHA3_384      = asn1.ObjectIdentifier([]int{2, 16, 840, 1, 101, 3, 4, 2, 9})
	OidSHA3_512      = asn1.ObjectIdentifier([]int{2, 16, 840, 1, 101, 3, 4, 2, 10})
	OidSHA3_SHAKE128 = asn1.ObjectIdentifier([]int{2, 16, 840, 1, 101, 3, 4, 2, 11})
	OidSHA3_SHAKE256 = asn1.ObjectIdentifier([]int{2, 16, 840, 1, 101, 3, 4, 2, 12})
)
View Source
var (
	OidDataContentType = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 7, 1})
)
View Source
var PBES2_HMACs_Available = map[string]asn1.ObjectIdentifier{
	"GOST3411_256": OidHmacWithGOST3411_256,
	"GOST3411_512": OidHmacWithGOST3411_512,
	"MD5":          OidHmacWithMD5,
	"SHA1":         OidHmacWithSHA1,
	"SHA256_224":   OidHmacWithSHA256_224,
	"SHA256":       OidHmacWithSHA256,
	"SHA512_384":   OidHmacWithSHA512_384,
	"SHA512":       OidHmacWithSHA512,
	"SHA512_224":   OidHmacWithSHA512_224,
	"SHA512_256":   OidHmacWithSHA512_256,
	"SHA3_224":     OidHmacWithSHA3_224,
	"SHA3_256":     OidHmacWithSHA3_256,
	"SHA3_384":     OidHmacWithSHA3_384,
	"SHA3_512":     OidHmacWithSHA3_512,
}
View Source
var PBE_Algorithms_Available = map[string]asn1.ObjectIdentifier{
	"PBEWithSHAAnd128BitRC4":        OidPBEWithSHAAnd128BitRC4,
	"PBEWithSHAAnd40BitRC4":         OidPBEWithSHAAnd40BitRC4,
	"PBEWithSHAAnd3KeyTripleDESCBC": OidPBEWithSHAAnd3KeyTripleDESCBC,
	"PBEWithSHAAnd2KeyTripleDESCBC": OidPBEWithSHAAnd2KeyTripleDESCBC,
	"PBEWithSHAAnd128BitRC2CBC":     OidPBEWithSHAAnd128BitRC2CBC,
	"PBEWithSHAAnd40BitRC2CBC":      OidPBEWithSHAAnd40BitRC2CBC,
	"PBES2":                         OidPBES2,
	"None":                          OidDataContentType,
}
View Source
var PBE_MACs_Available = map[string]asn1.ObjectIdentifier{
	"GOST3411_256":  OidGOST3411_256,
	"GOST3411_512":  OidGOST3411_512,
	"MD2":           OidMD2,
	"MD4":           OidMD4,
	"MD5":           OidMD5,
	"SHA1":          OidSHA1,
	"SHA256":        OidSHA256,
	"SHA384":        OidSHA384,
	"SHA512":        OidSHA512,
	"SHA256_224":    OidSHA256_224,
	"SHA512_224":    OidSHA512_224,
	"SHA512_256":    OidSHA512_256,
	"SHA3_224":      OidSHA3_224,
	"SHA3_256":      OidSHA3_256,
	"SHA3_384":      OidSHA3_384,
	"SHA3_512":      OidSHA3_512,
	"SHA3_SHAKE128": OidSHA3_SHAKE128,
	"SHA3_SHAKE256": OidSHA3_SHAKE256,
}

Functions

func BagDecrypt

func BagDecrypt(info Decryptable, password []rune) (decrypted []byte, salt []byte, HMACAlgorithm, EncryptionAlgorithm asn1.ObjectIdentifier, err error)

func BagEncrypt

func BagEncrypt(info Encryptable, decrypted []byte, password []rune) (err error)

func DecodeAttribute

func DecodeAttribute(attribute *pkcs12Attribute) (key, value string, err error)

func DecodePkcs8ShroudedKeyBagWithPassword

func DecodePkcs8ShroudedKeyBagWithPassword(asn1Data []byte, password []rune) (privateKey interface{}, algorithm, PBES2HMACAlgorithm, PBES2EncryptionAlgorithm asn1.ObjectIdentifier, salt []byte, err error)

Function which decodes a keybag, for use in a Custom Key Decoder with a string input (password)

func EncodePkcs8ShroudedKeyBagWithPassword

func EncodePkcs8ShroudedKeyBagWithPassword(rand io.Reader, privateKey interface{}, password []rune,
	algorithm, pbes2Hash, pbes2Enc asn1.ObjectIdentifier, iterations uint, salt []byte) (asn1Data []byte, err error)

func MakePBEParameters

func MakePBEParameters(salt []byte, iterations int) ([]byte, error)

func MakePBES2Parameters

func MakePBES2Parameters(rand io.Reader, hmacAlgorithm, encryptionAlgorithm asn1.ObjectIdentifier, salt []byte, iterations int) ([]byte, error)

func Marshal

func Marshal(p12 *P12) (pfxData []byte, err error)

Marshal produces pfxData containing private keys (PrivateKeys), an entity certificates (CertEntries), and any number of CA certificates included as CertEntries.

The private key is encrypted with the provided password, but due to the weak encryption primitives used by PKCS#12, it is RECOMMENDED that you specify a hard-coded password (such as DefaultPassword) and protect the resulting pfxData using other means.

The p12.Rand argument is used to provide entropy for the encryption, and can be set to crypto/rand.Reader.

Encode uses the P12 structure with all the Algorithm specifications for for securing the PFX.

Example usage:

p := pkcs12.NewWithPassword("mypass")
p.KeyEntries = append(p.KeyEntries, pkcs12.KeyEntry{Key: myKey})
p.CertEntries = append(p.CertEntries, pkcs12.CertEntry{Certificate: myCert})
derBytes, err := pkcs12.Marshal(p12)

Example definition of a P12 with custom algorithms:

p := &pkcs12.P12{
  Password:         "myPassword",
  KeyBagAlgorithm:  pkcs12.OidPBEWithSHAAnd3KeyTripleDESCBC,
  CertBagAlgorithm: pkcs12.OidPBEWithSHAAnd40BitRC2CBC,
  MACAlgorithm:     pkcs12.OidSHA256,
})

func MarshalTrustStore

func MarshalTrustStore(ts *TrustStore) (pfxData []byte, err error)

MarshalTrustStore produces pfxData containing any number of CA certificates (entries) to be trusted. The certificates will be marked with a special OID that allow it to be used as a Java TrustStore in Java 1.8 and newer.

This is identical to [EncodeTrustStore], but also allows for setting specific Friendly Names (Aliases) to be used per certificate, by specifying a slice of TrustStoreEntry and Algorithm for key/cert storage.

If the same Friendly Name is used for more than one certificate, then the resulting Friendly Names (Aliases) in the pfxData will be identical, which Java may treat as the same entry when used as a Java TrustStore, e.g. with `keytool`.

Due to the weak encryption primitives used by PKCS#12, it is RECOMMENDED that you specify a hard-coded password (such as DefaultPassword) and protect the resulting pfxData using other means.

The rand argument is used to provide entropy for the encryption, and can be set to crypto/rand.Reader.

Example definition of a TrustStore:

ts := &pkcs12.TrustStore{
  Password:         []byte("myPassword"),
  CertBagAlgorithm: pkcs12.OidPBEWithSHAAnd40BitRC2CBC,
  MACAlgorithm:     pkcs12.OidSHA1,
})

MarshalTrustStore takes a TrustStore structure with Algorithm specifications to use for for securing the PFX.

func Unmarshal

func Unmarshal(pfxData []byte, p12 *P12) (err error)

Unmarshal extracts a certificate, a CA certificate chain, and private key from pfxData, which must be a DER-encoded PKCS#12 file. This function assumes that there is at least one certificate and only one private key in the pfxData. The first certificate is assumed to be the leaf certificate, and subsequent certificates, if any, are assumed to comprise the CA certificate chain.

Note:

  • Password []byte is updated to show the password used in the file (if different than given)

  • The P12 output will be filled with the actual settings of the encryption methods used in the PKCS#12

func UnmarshalTrustStore

func UnmarshalTrustStore(pfxData []byte, ts *TrustStore) (err error)

UnmarshalTrustStore extracts the TrustStoreEntries from pfxData, which must be a DER-encoded PKCS#12 file containing exclusively certificates with attribute 2.16.840.1.113894.746875.1.1, which is used by Java to designate a trust anchor.

Types

type CertEntry

type CertEntry struct {
	Cert         *x509.Certificate
	KeyID        []byte
	FriendlyName string
	Attributes   []pkcs12Attribute
}

func (CertEntry) Clone

func (d CertEntry) Clone() CertEntry

type Decryptable

type Decryptable interface {
	Algorithm() pkix.AlgorithmIdentifier
	Data() []byte
}

decryptable abstracts an object that contains ciphertext.

type Encryptable

type Encryptable interface {
	Algorithm() pkix.AlgorithmIdentifier
	SetData([]byte)
}

encryptable abstracts a object that contains ciphertext.

type KeyEntry

type KeyEntry struct {
	Key          interface{}
	KeyID        []byte
	FriendlyName string
	Attributes   []pkcs12Attribute
	// contains filtered or unexported fields
}

func (KeyEntry) Clone

func (d KeyEntry) Clone() KeyEntry

type NotImplementedError

type NotImplementedError string

NotImplementedError indicates that the input is not currently supported.

func (NotImplementedError) Error

func (e NotImplementedError) Error() string

type P12

type P12 struct {
	SkipDecodeErrors bool
	CertEntries      []CertEntry
	KeyEntries       []KeyEntry

	// Password based encryption settings
	Password []rune

	// These are defined when a password is provided, if left undefined defaults will be set
	MACAlgorithm                        asn1.ObjectIdentifier
	MACIterations, EncryptionIterations uint
	KeyBagAlgorithm, CertBagAlgorithm   asn1.ObjectIdentifier

	// When PBES2 is used
	PBES2_HMACAlgorithm, PBES2_EncryptionAlgorithm asn1.ObjectIdentifier

	// If unique passwords or algorithms must be assigned to each key, a custom callback may be defined
	CustomKeyEncrypt func(ke *KeyEntry) (encrypted []byte, isEncrypted bool, err error)
	CustomKeyDecrypt func(ke *KeyEntry, payload []byte) error
	CustomBagDecrypt func(info Decryptable, password []byte) (decrypted []byte, err error)
	CustomBagEncrypt func(info Encryptable, data []byte) error
	// contains filtered or unexported fields
}

When doing key level custom encryption, one can provide a call back function to handle individual keys. If no function is provided the settings Password, NoPassword, and KeyBagAlgorithm will be used for all the key bags.

func New

func New() *P12

Create a new P12 with defaults

func NewWithPassword

func NewWithPassword(password []rune) P12

Create a new P12 with defaults and set the password

func (*P12) GenerateSalts

func (p *P12) GenerateSalts(sl int) (err error)

Generate salts

func (*P12) WithRand

func (p *P12) WithRand(r io.Reader)

Set the random entropy source

type TrustStore

type TrustStore struct {
	Entries []TrustStoreEntry

	Password                                       []rune
	MACAlgorithm                                   asn1.ObjectIdentifier
	MACIterations, EncryptionIterations            uint
	CertBagAlgorithm                               asn1.ObjectIdentifier
	PBES2_HMACAlgorithm, PBES2_EncryptionAlgorithm asn1.ObjectIdentifier

	// If unique passwords or algorithms must be assigned to each key, a custom callback may be defined
	CustomBagDecrypt func(info Decryptable, password []byte) (decrypted []byte, err error)
	CustomBagEncrypt func(info Encryptable, data []byte) error
	// contains filtered or unexported fields
}

TrustStore represents a Java TrustStore in P12 format.

func NewTrustStoreWithPassword

func NewTrustStoreWithPassword(password []rune) *TrustStore

func (*TrustStore) GenerateSalts

func (ts *TrustStore) GenerateSalts(sl int) (err error)

Generate salts

func (*TrustStore) WithRand

func (t *TrustStore) WithRand(r io.Reader)

Set the random entropy source

type TrustStoreEntry

type TrustStoreEntry struct {
	Cert         *x509.Certificate
	FriendlyName string
	Fingerprint  []byte
	KeyID        []byte
	Attributes   []pkcs12Attribute
}

TrustStoreEntry represents an entry in a Java TrustStore.

Directories

Path Synopsis
internal
rc2
Package rc2 implements the RC2 cipher
Package rc2 implements the RC2 cipher

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL