go-pkcs12

repository·master·Indexed 41 days ago

https://github.com/sslmate/go-pkcs12

A Go implementation of PKCS#12 (P12/PFX) for decoding DER-encoded files for use with crypto/tls and encoding files for legacy application compatibility. It provides functionality to decode certificates and private keys via Decode and DecodeChain, handle Java TrustStores with DecodeTrustStore and EncodeTrustStore, and offer various encoding security levels including Modern, Modern2023, Modern2026, Legacy, and LegacyRC2.

Tokens
2.1K
Snippets
10
Records
11
Agent score
51%

What's inside go-pkcs12

  1. Overview of go-pkcs12 capabilities and limitations

    master

    The pkcs12 package provides functionality for handling PKCS#12 (P12/PFX) files.

    Primary Use Cases

    • Decoding: Extracting DER-encoded P12/PFX files for use with the standard crypto/tls package.
    • Encoding: Creating P12/PFX files for compatibility with legacy applications that do not support newer certificate formats.

    Important Constraints and Warnings

    • Encoding Support: This package supports only DER-encoded PKCS#12 files. It does not support BER encoding because the underlying encoding/asn1 package is limited to DER.
    • Security Warning: PKCS#12 uses weak encryption primitives. It SHOULD NOT be used for new applications where modern security standards can be applied.
    • Origin: This package is a fork of the frozen golang.org/x/crypto/pkcs12 and is based on the implementation details from RFC 7292.
  2. Install and import the go-pkcs12 package

    master

    To use this package in your Go project, use the following import path for both go get and your source code import statements. Note that while the repository is hosted on GitHub, the official import path is different.

    Import Path: software.sslmate.com/src/go-pkcs12

    import "software.sslmate.com/src/go-pkcs12"
  3. Encode PKCS#12 files with different security levels

    master

    The Encoder type provides several pre-defined configurations for encoding PKCS#12 files, allowing you to balance security and compatibility with legacy software.

    • Modern (or Modern2023): Uses modern, robust algorithms (PBES2 with PBKDF2-HMAC-SHA-256 and AES-256-CBC). Compatible with OpenSSL 1.1.1+, Java 12+, and Windows Server 2019+.
    • Modern2026: Uses even newer algorithms (PBMAC1 with PBKDF2-HMAC-SHA-256 and HMAC-SHA256). Requires OpenSSL 3.4.0+ and Java 26+.
    • Legacy (or LegacyDES): Uses 3DES for encryption. Provides high compatibility with older software but is considered weak.
    • LegacyRC2: Uses RC2 and 3DES. Primarily for very old OpenSSL or Java versions.
    • Passwordless: Encodes files without any encryption or MACs. Useful for creating Java trust stores.

    Customizing an Encoder

    You can create a custom encoder by starting with a base encoder and using the following methods:

    • WithIterations(iterations int): Sets the number of KDF iterations for both MAC and encryption keys. Panics if iterations < 1.
    • WithRand(rand io.Reader): Replaces the default crypto/rand.Reader with a custom reader.
    // Example: Using a modern encoder with custom iterations
    enc := pkcs12.Modern.WithIterations(10000)
    pfxData, err := enc.Encode(privateKey, certificate, caCerts, password)
  4. Decode Java TrustStores with DecodeTrustStore

    master

    Use DecodeTrustStore to extract certificates from a PKCS#12 file specifically formatted as a Java TrustStore. This function requires that the certificates are marked with the special Java trust anchor OID (2.16.840.1.113894.746875.1.1).

    If the password argument is empty, it will attempt to decode either password-less files or files with a literal empty password.

    certs, err := pkcs12.DecodeTrustStore(pfxData, password)
  5. Decode a single certificate and private key with Decode

    master

    Use Decode if you are certain the PKCS#12 file contains exactly one certificate and one private key. If the file contains more than two safe bags (e.g., a CA chain), this function will return an error.

    Note: This function is a wrapper around DecodeChain that enforces a strict limit on the number of items found.

    privateKey, certificate, err := pkcs12.Decode(pfxData, password)
  6. Deprecated: Convert PKCS#12 to PEM with ToPEM

    master

    The ToPEM function converts all "safe bags" in a PFX file to PEM blocks.

    Warning: This function is deprecated. It creates invalid PEM blocks because private keys are encoded as raw RSA or EC private keys rather than PKCS#8, despite being labeled "PRIVATE KEY".

    Recommended Alternative: Use DecodeChain to extract the keys/certificates, then use the standard encoding/pem package to encode them as desired.

    // Deprecated usage
    blocks, err := pkcs12.ToPEM(pfxData, password)
  7. Decode PKCS#12 files with DecodeChain

    master

    Use DecodeChain to extract a private key, a leaf certificate, and a CA certificate chain from a DER-encoded PKCS#12 file. This is the recommended method for most use cases as PKCS#12 files often contain multiple certificates.

    Note: The first certificate in the chain is assumed to be the leaf certificate, and subsequent certificates are treated as the CA chain.

    privateKey, certificate, caCerts, err := pkcs12.DecodeChain(pfxData, password)
  8. Create Java TrustStores with EncodeTrustStore

    master

    Use EncodeTrustStore to create a PKCS#12 file containing CA certificates marked for use as a Java TrustStore. The certificates' Subjects are used as their Friendly Names (Aliases).

    To specify custom Friendly Names for each certificate, use EncodeTrustStoreEntries with a slice of TrustStoreEntry objects.

    // Simple trust store
    pfxData, err := pkcs12.Modern.EncodeTrustStore(certs, password)
    
    // Custom trust store with specific aliases
    entries := []pkcs12.TrustStoreEntry{
        {Cert: cert1, FriendlyName: "alias1"},
        {Cert: cert2, FriendlyName: "alias2"},
    }
    pfxData, err := pkcs12.Modern.EncodeTrustStoreEntries(entries, password)
  9. Encode PKCS#12 files with Encode

    master

    Use Encoder.Encode to produce a DER-encoded PKCS#12 file containing one private key, one end-entity certificate, and any number of CA certificates.

    It emulates OpenSSL's PKCS12_create behavior: it creates two SafeContents—one encrypted (containing certificates) and one unencrypted (containing the shrouded private key). The LocalKeyId attribute is automatically set to the SHA-1 fingerprint of the end-entity certificate.

    // Using the Modern encoder
    enc := pkcs12.Modern
    pfxData, err := enc.Encode(privateKey, certificate, caCerts, password)
  10. Handle decryption and password errors in pkcs12

    master

    When performing PKCS#12 operations, you may encounter specific error variables to identify why an operation failed. Use errors.Is to check for these sentinel errors:

    • ErrDecryption: Indicates a failure to decrypt the input, often due to incorrect padding.
    • ErrIncorrectPassword: Indicates that the provided password was incorrect. This is typically detected when the P12/PFX data is signed and the signature verification fails.
    import (
    	"errors"
    	"fmt"
    	"sslmate/sslmate/go-pkcs12"
    )
    
    // Example error checking
    err := pkcs12.Decode("data", "wrong-password")
    if errors.Is(err, pkcs12.ErrIncorrectPassword) {
    	fmt.Println("Please check your password.")
    } else if errors.Is(err, pkcs12.ErrDecryption) {
    	fmt.Println("Decryption failed: incorrect padding.")
    }
  11. Handle unsupported input with NotImplementedError

    master

    The NotImplementedError type is used to indicate that a specific PKCS#12 feature or input format is not currently supported by the library. It is a string-based error type where the error message is prefixed with pkcs12: .

    // Example of how a NotImplementedError might be handled
    var err error = pkcs12.NotImplementedError("some unsupported feature")
    fmt.Println(err.Error()) // Output: pkcs12: some unsupported feature