pkcs12

package module
v0.0.0-...-3211765 Latest Latest
Warning

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

Go to latest
Published: Feb 13, 2024 License: BSD-3-Clause Imports: 23 Imported by: 0

README

package pkcs12

import "github.com/EverTrust/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. The implementation is distilled from https://tools.ietf.org/html/rfc7292 and referenced documents.

Import Path

Note that although the source code and issue tracker for this package are hosted on GitHub, the import path is:

github.com/EverTrust/go-pkcs12 

Please be sure to use this path when you go get and import this package.

Report Issues / Send Patches

Open an issue or PR at https://github.com/EverTrust/go-pkcs12

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.

Index

Constants

View Source
const DefaultPassword = "changeit"

DefaultPassword is the string "changeit", a commonly-used password for PKCS#12 files.

Variables

View Source
var (
	// ErrDecryption represents a failure to decrypt the input.
	ErrDecryption = errors.New("pkcs12: 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("pkcs12: decryption password incorrect")
)
View Source
var Legacy = LegacyDES

Legacy encodes PKCS#12 files using weak, legacy parameters that work in a wide variety of software.

Currently, this encoder is the same as LegacyDES, but this may change in the future if another encoder is found to provide better compatibility.

Due to the weak encryption, it is STRONGLY RECOMMENDED that you use DefaultPassword when encoding PKCS#12 files using this encoder, and protect the PKCS#12 files using other means.

View Source
var LegacyDES = &Encoder{
	macAlgorithm:         oidSHA1,
	certAlgorithm:        oidPBEWithSHAAnd3KeyTripleDESCBC,
	keyAlgorithm:         oidPBEWithSHAAnd3KeyTripleDESCBC,
	macIterations:        1,
	encryptionIterations: 2048,
	saltLen:              8,
	rand:                 rand.Reader,
}

LegacyDES encodes PKCS#12 files using weak algorithms that are supported by a wide variety of software. Certificates and keys are encrypted using PBE with 3DES using keys derived with 2048 iterations of HMAC-SHA-1. MACs use HMAC-SHA-1 with keys derived with 1 iteration of HMAC-SHA-1. These are the same parameters used by OpenSSL's -descert option. As of 2023, this encoder is likely to produce files that can be read by the most software.

Due to the weak encryption, it is STRONGLY RECOMMENDED that you use DefaultPassword when encoding PKCS#12 files using this encoder, and protect the PKCS#12 files using other means. To create more secure PKCS#12 files, use Modern2023.

View Source
var LegacyRC2 = &Encoder{
	macAlgorithm:         oidSHA1,
	certAlgorithm:        oidPBEWithSHAAnd40BitRC2CBC,
	keyAlgorithm:         oidPBEWithSHAAnd3KeyTripleDESCBC,
	macIterations:        1,
	encryptionIterations: 2048,
	saltLen:              8,
	rand:                 rand.Reader,
}

LegacyRC2 encodes PKCS#12 files using weak algorithms that were traditionally used in PKCS#12 files, including those produced by OpenSSL before 3.0.0, go-pkcs12 before 0.3.0, and Java when keystore.pkcs12.legacy is defined. Specifically, certificates are encrypted using PBE with RC2, and keys are encrypted using PBE with 3DES, using keys derived with 2048 iterations of HMAC-SHA-1. MACs use HMAC-SHA-1 with keys derived with 1 iteration of HMAC-SHA-1.

Due to the weak encryption, it is STRONGLY RECOMMENDED that you use DefaultPassword when encoding PKCS#12 files using this encoder, and protect the PKCS#12 files using other means.

By default, OpenSSL 3 can't decode PKCS#12 files created using this encoder. For better compatibility, use LegacyDES. For better security, use Modern2023.

View Source
var Modern = Modern2023

Modern encodes PKCS#12 files using modern, robust parameters.

Currently, this encoder is the same as Modern2023, but this may change in the future to keep up with modern practices.

View Source
var Modern2023 = &Encoder{
	macAlgorithm:         oidSHA256,
	certAlgorithm:        oidPBES2,
	keyAlgorithm:         oidPBES2,
	macIterations:        2048,
	encryptionIterations: 2048,
	saltLen:              16,
	rand:                 rand.Reader,
}

Modern2023 encodes PKCS#12 files using algorithms that are considered modern as of 2023. Private keys and certificates are encrypted using PBES2 with PBKDF2-HMAC-SHA-256 and AES-256-CBC. The MAC algorithm is HMAC-SHA-2. These are the same algorithms used by OpenSSL 3 (by default), Java 20 (by default), and Windows Server 2019 (when "stronger" is used).

Files produced with this encoder can be read by OpenSSL 1.1.1 and higher, Java 12 and higher, and Windows Server 2019 and higher.

For passwords, it is RECOMMENDED that you do one of the following: 1) Use DefaultPassword and protect the file using other means, or 2) Use a high-entropy password, such as one generated with `openssl rand -hex 16`.

You SHOULD NOT use a lower-entropy password with this encoder because the number of KDF iterations is only 2048 and doesn't provide meaningful protection against brute-forcing. You can increase the number of iterations using Encoder.WithIterations, but as https://neilmadden.blog/2023/01/09/on-pbkdf2-iterations/ explains, this doesn't help as much as you think.

View Source
var Passwordless = &Encoder{
	macAlgorithm:  nil,
	certAlgorithm: nil,
	keyAlgorithm:  nil,
	rand:          rand.Reader,
}

Passwordless encodes PKCS#12 files without any encryption or MACs. A lot of software has trouble reading such files, so it's probably only useful for creating Java trust stores using Encoder.EncodeTrustStore or Encoder.EncodeTrustStoreEntries.

When using this encoder, you MUST specify an empty password.

Functions

func Decode

func Decode(pfxData []byte, password string) (privateKey interface{}, certificate *x509.Certificate, err error)

Decode extracts a certificate and private key from pfxData, which must be a DER-encoded PKCS#12 file. This function assumes that there is only one certificate and only one private key in the pfxData. Since PKCS#12 files often contain more than one certificate, you probably want to use DecodeChain instead.

func DecodeChain

func DecodeChain(pfxData []byte, password string) (privateKey interface{}, certificate *x509.Certificate, caCerts []*x509.Certificate, err error)

DecodeChain 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.

func DecodeTrustStore

func DecodeTrustStore(pfxData []byte, password string) (certs []*x509.Certificate, err error)

DecodeTrustStore extracts the certificates 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.

If the password argument is empty, DecodeTrustStore will decode either password-less PKCS#12 files (i.e. those without encryption) or files with a literal empty password.

func Encode deprecated

func Encode(rand io.Reader, privateKey interface{}, certificate *x509.Certificate, caCerts []*x509.Certificate, password string) (pfxData []byte, err error)

Encode is equivalent to LegacyRC2.WithRand(rand).Encode. See Encoder.Encode and LegacyRC2 for details.

Deprecated: for the same behavior, use LegacyRC2.Encode; for better compatibility, use Legacy.Encode; for better security, use Modern.Encode.

func EncodeTrustStore deprecated

func EncodeTrustStore(rand io.Reader, certs []*x509.Certificate, password string) (pfxData []byte, err error)

EncodeTrustStore is equivalent to LegacyRC2.WithRand(rand).EncodeTrustStore. See Encoder.EncodeTrustStore and LegacyRC2 for details.

Deprecated: for the same behavior, use LegacyRC2.EncodeTrustStore; to generate passwordless trust stores, use Passwordless.EncodeTrustStore.

func EncodeTrustStoreEntries deprecated

func EncodeTrustStoreEntries(rand io.Reader, entries []TrustStoreEntry, password string) (pfxData []byte, err error)

EncodeTrustStoreEntries is equivalent to LegacyRC2.WithRand(rand).EncodeTrustStoreEntries. See Encoder.EncodeTrustStoreEntries and LegacyRC2 for details.

Deprecated: for the same behavior, use LegacyRC2.EncodeTrustStoreEntries; to generate passwordless trust stores, use Passwordless.EncodeTrustStoreEntries.

func ToPEM deprecated

func ToPEM(pfxData []byte, password string) ([]*pem.Block, error)

ToPEM converts all "safe bags" contained in pfxData to PEM blocks.

Deprecated: ToPEM creates invalid PEM blocks (private keys are encoded as raw RSA or EC private keys rather than PKCS#8 despite being labeled "PRIVATE KEY"). To decode a PKCS#12 file, use DecodeChain instead, and use the encoding/pem package to convert to PEM if necessary.

Types

type Encoder

type Encoder struct {
	// contains filtered or unexported fields
}

An Encoder contains methods for encoding PKCS#12 files. This package defines several different Encoders with different parameters.

func (*Encoder) Encode

func (enc *Encoder) Encode(privateKey interface{}, certificate *x509.Certificate, caCerts []*x509.Certificate, password string) (pfxData []byte, err error)

Encode produces pfxData containing one private key (privateKey), an end-entity certificate (certificate), and any number of CA certificates (caCerts).

The pfxData is encrypted and authenticated with keys derived from the provided password.

Encode emulates the behavior of OpenSSL's PKCS12_create: it creates two SafeContents: one that's encrypted with the certificate encryption algorithm and contains the certificates, and another that is unencrypted and contains the private key shrouded with the key encryption algorithm. The private key bag and the end-entity certificate bag have the LocalKeyId attribute set to the SHA-1 fingerprint of the end-entity certificate.

func (*Encoder) EncodeTrustStore

func (enc *Encoder) EncodeTrustStore(certs []*x509.Certificate, password string) (pfxData []byte, err error)

EncodeTrustStore produces pfxData containing any number of CA certificates (certs) 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.

EncodeTrustStore creates a single SafeContents that's optionally encrypted and contains the certificates.

The Subject of the certificates are used as the Friendly Names (Aliases) within the resulting pfxData. If certificates share a Subject, then the resulting Friendly Names (Aliases) will be identical, which Java may treat as the same entry when used as a Java TrustStore, e.g. with `keytool`. To customize the Friendly Names, use EncodeTrustStoreEntries.

func (*Encoder) EncodeTrustStoreEntries

func (enc *Encoder) EncodeTrustStoreEntries(entries []TrustStoreEntry, password string) (pfxData []byte, err error)

EncodeTrustStoreEntries 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 Encoder.EncodeTrustStore, but also allows for setting specific Friendly Names (Aliases) to be used per certificate, by specifying a slice of TrustStoreEntry.

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`.

EncodeTrustStoreEntries creates a single SafeContents that's optionally encrypted and contains the certificates.

func (*Encoder) EncodeWithAttributes

func (enc *Encoder) EncodeWithAttributes(privateKey interface{}, certificate *x509.Certificate, caCerts []*x509.Certificate, password, friendlyName, cspName string) (pfxData []byte, err error)

EncodeWithAttributes produces pfxData containing one private key (privateKey), an end-entity certificate (certificate), any number of CA certificates (caCerts), as well as supplementary attributes (friendlyName and cspName).

The pfxData is encrypted and authenticated with keys derived from the provided password.

EncodeWithAttributes emulates the behavior of OpenSSL's PKCS12_create: it creates two SafeContents: one that's encrypted with the certificate encryption algorithm and contains the certificates, and another that is unencrypted and contains the private key shrouded with the key encryption algorithm. The private key bag and the end-entity certificate bag have the LocalKeyId attribute set to the SHA-1 fingerprint of the end-entity certificate.

func (*Encoder) WithIterations

func (enc *Encoder) WithIterations(iterations int) *Encoder

WithIterations creates a new Encoder identical to enc except that it will use the given number of KDF iterations for deriving the MAC and encryption keys.

Note that even with a large number of iterations, a weak password can still be brute-forced in much less time than it would take to brute-force a high-entropy encrytion key. For the best security, don't worry about the number of iterations and just use a high-entropy password (e.g. one generated with `openssl rand -hex 16`). See https://neilmadden.blog/2023/01/09/on-pbkdf2-iterations/ for more detail.

Panics if iterations is less than 1.

func (*Encoder) WithRand

func (enc *Encoder) WithRand(rand io.Reader) *Encoder

WithRand creates a new Encoder identical to enc except that it will use the given io.Reader for its random number generator instead of crypto/rand.Reader.

type NotImplementedError

type NotImplementedError string

NotImplementedError indicates that the input is not currently supported.

func (NotImplementedError) Error

func (e NotImplementedError) Error() string

type TrustStoreEntry

type TrustStoreEntry struct {
	Cert         *x509.Certificate
	FriendlyName string
}

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