pkcs7

package module
v0.0.0-...-8095bc9 Latest Latest
Warning

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

Go to latest
Published: Apr 8, 2026 License: MIT Imports: 19 Imported by: 0

README

pkcs7

GoDoc

Package pkcs7 implements parsing and creating PKCS#7 / CMS structures as defined in RFC 5652.

Install

go get github.com/gurre/pkcs7

RFC 5652 feature matrix

RFC section Feature Status
3 ContentInfo
3 Parse ContentInfo wrapper Supported
3 BER-to-DER conversion (indefinite length) Supported
5 SignedData
5.1 Parse SignedData Supported
5.1 Create SignedData Supported
5.1 Degenerate certificates-only SignedData Supported
5.1 Version assignment (v1 for issuerAndSerialNumber) Supported
5.1 Version assignment (v3 for subjectKeyIdentifier) Not supported
5.2.1 Primitive OCTET STRING eContent Supported
5.2.1 Constructed OCTET STRING eContent Supported
5.2.1 Detached signatures (omitted eContent) Supported
5.3 SignerInfo with issuerAndSerialNumber Supported
5.3 SignerInfo with subjectKeyIdentifier Not supported
5.3 Required attributes: content-type, message-digest Supported
5.3 Optional attribute: signing-time Supported
5.3 Custom signed/unsigned attributes Supported
5.4 Message digest: SHA-1, SHA-256, SHA-384, SHA-512 Supported
5.4 DER-encoded signedAttrs for signature input Supported
5.6 Independent digest computation on verify Supported
5.6 Content-type attribute match validation Supported
5.6 Certificate chain verification Supported
5.6 Time-based chain verification Supported
6 EnvelopedData
6.1 Parse EnvelopedData Supported
6.1 Create EnvelopedData Supported
6.2.1 KeyTransRecipientInfo (RSA PKCS#1 v1.5) Supported
6.2.2 KeyAgreeRecipientInfo (ECDH) Not supported
6.2.3 KEKRecipientInfo Not supported
6.2.4 PasswordRecipientInfo Not supported
6.3 PKCS#7 padding Supported
8 EncryptedData
8 Parse EncryptedData Supported
8 Create EncryptedData (pre-shared key) Supported
11 Useful attributes
11.1 Content-type attribute Supported
11.2 Message-digest attribute Supported
11.3 Signing-time attribute Supported
11.4 Countersignature attribute Not supported

Signature algorithms

Algorithm Sign Verify
RSA with SHA-1 Yes Yes
RSA with SHA-256 Yes Yes
RSA with SHA-384 Yes Yes
RSA with SHA-512 Yes Yes
RSA-PSS (SHA-256/384/512) No Yes
ECDSA with SHA-1 Yes Yes
ECDSA with SHA-256 Yes Yes
ECDSA with SHA-384 Yes Yes
ECDSA with SHA-512 Yes Yes
Ed25519 No Yes
DSA with SHA-1/SHA-256 No Yes

Content encryption algorithms

Algorithm Encrypt Decrypt
DES-CBC Yes Yes
3DES-CBC (DES-EDE3) No Yes
AES-128-CBC Yes Yes
AES-256-CBC Yes Yes
AES-128-GCM Yes Yes
AES-256-GCM Yes Yes

Credits

Fork of fullsailor/pkcs7.

Documentation

Overview

Package pkcs7 implements parsing and generation of PKCS#7 / CMS structures as defined in RFC 5652 (Cryptographic Message Syntax).

Supported content types:

  • SignedData (OID 1.2.840.113549.1.7.2) — RFC 5652 §5
  • EnvelopedData (OID 1.2.840.113549.1.7.3) — RFC 5652 §6
  • EncryptedData (OID 1.2.840.113549.1.7.6) — RFC 5652 §8

Not yet implemented:

  • DigestedData (OID 1.2.840.113549.1.7.5) — RFC 5652 §7
  • AuthenticatedData (OID 1.2.840.113549.1.9.16.1.2) — RFC 5652 §9
  • SubjectKeyIdentifier as SignerIdentifier — RFC 5652 §5.3
  • KeyAgreeRecipientInfo (ECDH key agreement) — RFC 5652 §6.2.2
  • KEKRecipientInfo (pre-distributed symmetric keys) — RFC 5652 §6.2.3
  • PasswordRecipientInfo — RFC 5652 §6.2.4
  • RSA-OAEP key transport — RFC 3560

Index

Examples

Constants

View Source
const (
	// EncryptionAlgorithmDESCBC is the DES CBC encryption algorithm
	EncryptionAlgorithmDESCBC = iota

	// EncryptionAlgorithmAES128CBC is the AES 128 bits with CBC encryption algorithm
	// Avoid this algorithm unless required for interoperability; use AES GCM instead.
	EncryptionAlgorithmAES128CBC

	// EncryptionAlgorithmAES256CBC is the AES 256 bits with CBC encryption algorithm
	// Avoid this algorithm unless required for interoperability; use AES GCM instead.
	EncryptionAlgorithmAES256CBC

	// EncryptionAlgorithmAES128GCM is the AES 128 bits with GCM encryption algorithm
	EncryptionAlgorithmAES128GCM

	// EncryptionAlgorithmAES256GCM is the AES 256 bits with GCM encryption algorithm
	EncryptionAlgorithmAES256GCM
)

Variables

View Source
var (
	// Content type OIDs (RFC 5652 §4–§9)
	OIDData              = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 1}
	OIDSignedData        = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 2}
	OIDEnvelopedData     = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 3}
	OIDDigestedData      = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 5}
	OIDEncryptedData     = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 6}
	OIDAuthenticatedData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 16, 1, 2}

	// Attribute OIDs (RFC 5652 §11)
	OIDAttributeContentType   = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 3}
	OIDAttributeMessageDigest = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 4}
	OIDAttributeSigningTime   = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 5}

	// Digest Algorithms
	OIDDigestAlgorithmSHA1   = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 26}
	OIDDigestAlgorithmSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 1}
	OIDDigestAlgorithmSHA384 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 2}
	OIDDigestAlgorithmSHA512 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 3}

	OIDDigestAlgorithmDSA     = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 1}
	OIDDigestAlgorithmDSASHA1 = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 3}

	OIDDigestAlgorithmECDSASHA1   = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 1}
	OIDDigestAlgorithmECDSASHA256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 2}
	OIDDigestAlgorithmECDSASHA384 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 3}
	OIDDigestAlgorithmECDSASHA512 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 4}

	// Signature Algorithms
	OIDEncryptionAlgorithmRSA       = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}
	OIDEncryptionAlgorithmRSASHA1   = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5}
	OIDEncryptionAlgorithmRSAPSS    = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 10}
	OIDEncryptionAlgorithmRSASHA256 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11}
	OIDEncryptionAlgorithmRSASHA384 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 12}
	OIDEncryptionAlgorithmRSASHA512 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 13}

	OIDEncryptionAlgorithmECDSAP256   = asn1.ObjectIdentifier{1, 2, 840, 10045, 3, 1, 7} // 256 bit elliptic curve
	OIDEncryptionAlgorithmECDSAP384   = asn1.ObjectIdentifier{1, 3, 132, 0, 34}          // 384-bit elliptic curve
	OIDEncryptionAlgorithmECDSAP521   = asn1.ObjectIdentifier{1, 3, 132, 0, 35}          // 512-bit elliptic curve!
	OIDEncryptionAlgorithmECPUBLICKEY = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1}    // ecPublicKey

	OIDEncryptionAlgorithmDESCBC     = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 7}
	OIDEncryptionAlgorithmDESEDE3CBC = asn1.ObjectIdentifier{1, 2, 840, 113549, 3, 7}

	OIDEncryptionAlgorithmAES256CBC = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 42}
	OIDEncryptionAlgorithmAES128GCM = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 6}
	OIDEncryptionAlgorithmAES128CBC = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 2}
	OIDEncryptionAlgorithmAES256GCM = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 46}

	OIDEncryptionAlgorithmECDSAWithSHA256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 2}
	OIDEncryptionAlgorithmECDSAWithSHA384 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 3}
	OIDEncryptionAlgorithmECDSAWithSHA512 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 4}

	OIDEncryptionAlgorithmEd25519 = asn1.ObjectIdentifier{1, 3, 101, 112}

	// Elliptic curve names
	OIDCurveP256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 3, 1, 7}
	OIDCurveP384 = asn1.ObjectIdentifier{1, 3, 132, 0, 34}
	OIDCurveP521 = asn1.ObjectIdentifier{1, 3, 132, 0, 35}
)
View Source
var ContentEncryptionAlgorithm = EncryptionAlgorithmDESCBC

ContentEncryptionAlgorithm determines the algorithm used to encrypt the plaintext message. Change the value of this variable to change which algorithm is used in the Encrypt() function.

View Source
var ErrNotEncryptedContent = errors.New("pkcs7: content is not an encrypted data type")

ErrNotEncryptedContent is returned when attempting to Decrypt data that is not encrypted data.

View Source
var ErrPSKNotProvided = errors.New("pkcs7: cannot encrypt content: PSK not provided")

ErrPSKNotProvided is returned when attempting to encrypt using a PSK without actually providing the PSK.

View Source
var ErrUnsupportedAlgorithm = errors.New("pkcs7: cannot decrypt data: only RSA, DES, DES-EDE3, AES-256-CBC and AES-128-GCM supported")

ErrUnsupportedAlgorithm tells you when our quick dev assumptions have failed

View Source
var ErrUnsupportedContentType = errors.New("pkcs7: cannot parse data: unimplemented content type")

ErrUnsupportedContentType is returned when a PKCS7 content is not supported. Currently only Data (1.2.840.113549.1.7.1), Signed Data (1.2.840.113549.1.7.2), and Enveloped Data are supported (1.2.840.113549.1.7.3)

View Source
var ErrUnsupportedEncryptionAlgorithm = errors.New("pkcs7: cannot encrypt content: only DES-CBC, AES-CBC, and AES-GCM supported")

ErrUnsupportedEncryptionAlgorithm is returned when attempting to encrypt content with an unsupported algorithm.

Functions

func CheckSignature

func CheckSignature(cert *x509.Certificate, signer SignerInfo, content []byte) error

CheckSignature verifies the cryptographic signature in signer using the public key from cert (RFC 5652 §5.6). If content is empty, the signature is verified over the DER-encoded authenticated attributes instead.

err := pkcs7.CheckSignature(signerCert, p7.Signers[0], nil)

func DegenerateCertificate

func DegenerateCertificate(cert []byte) ([]byte, error)

DegenerateCertificate creates a SignedData structure containing only certificates and no signers (RFC 5652 §5.1). This is commonly used for certificate distribution.

der, err := pkcs7.DegenerateCertificate(cert.Raw)

func DigestOIDForSignatureAlgorithm

func DigestOIDForSignatureAlgorithm(digestAlg x509.SignatureAlgorithm) (asn1.ObjectIdentifier, error)

DigestOIDForSignatureAlgorithm returns the digest algorithm OID for the given x509.SignatureAlgorithm. This is used to populate the digestAlgorithm field in SignerInfo (RFC 5652 §5.3).

oid, err := pkcs7.DigestOIDForSignatureAlgorithm(cert.SignatureAlgorithm)

func Encrypt

func Encrypt(content []byte, recipients []*x509.Certificate) ([]byte, error)

Encrypt creates a CMS EnvelopedData structure (RFC 5652 §6) with the content encrypted under a random symmetric key, and that key encrypted for each recipient using RSA PKCS#1 v1.5 (KeyTransRecipientInfo, RFC 5652 §6.2.1).

Set ContentEncryptionAlgorithm before calling to control the cipher:

pkcs7.ContentEncryptionAlgorithm = pkcs7.EncryptionAlgorithmAES128GCM
encrypted, err := pkcs7.Encrypt(plaintext, []*x509.Certificate{recipientCert})

TODO: Support ECDH key agreement (KeyAgreeRecipientInfo, RFC 5652 §6.2.2). TODO: ContentEncryptionAlgorithm is a global variable and not safe for concurrent use. Consider passing it as a parameter.

func EncryptUsingPSK

func EncryptUsingPSK(content []byte, key []byte) ([]byte, error)

EncryptUsingPSK creates a CMS EncryptedData structure (RFC 5652 §8) using a pre-shared symmetric key. The key must match the expected size for the selected ContentEncryptionAlgorithm.

pkcs7.ContentEncryptionAlgorithm = pkcs7.EncryptionAlgorithmAES128GCM
encrypted, err := pkcs7.EncryptUsingPSK(plaintext, aes128Key)

func GetCertFromCertsByIssuerAndSerial

func GetCertFromCertsByIssuerAndSerial(certs []*x509.Certificate, ias issuerAndSerial) *x509.Certificate

GetCertFromCertsByIssuerAndSerial finds a certificate matching the given IssuerAndSerialNumber (RFC 5652 §5.3 SignerIdentifier). Returns nil if no match is found.

func HashForOID

func HashForOID(oid asn1.ObjectIdentifier) (crypto.Hash, error)

HashForOID returns the crypto.Hash corresponding to the given digest algorithm OID. Supported OIDs include SHA-1, SHA-256, SHA-384, and SHA-512 (and their ECDSA/DSA combined variants).

hash, err := pkcs7.HashForOID(pkcs7.OIDDigestAlgorithmSHA256)
h := hash.New()
h.Write(data)
digest := h.Sum(nil)

func OIDForEncryptionAlgorithm

func OIDForEncryptionAlgorithm(pkey crypto.PrivateKey, OIDDigestAlg asn1.ObjectIdentifier) (asn1.ObjectIdentifier, error)

OIDForEncryptionAlgorithm returns the signature algorithm OID for the given private key type and digest algorithm OID. This maps to the signatureAlgorithm field in SignerInfo (RFC 5652 §5.3).

Supported key types: *rsa.PrivateKey, *ecdsa.PrivateKey.

func VerifyCertChain

func VerifyCertChain(ee *x509.Certificate, certs []*x509.Certificate, truststore *x509.CertPool, currentTime time.Time) (chains [][]*x509.Certificate, err error)

VerifyCertChain builds and verifies certificate chains from the end-entity certificate to a trusted root via the provided intermediates. The currentTime parameter controls the time used for validity checks; use time.Time{} for now.

chains, err := pkcs7.VerifyCertChain(eeCert, intermediates, roots, time.Now())

func VerifyMessageDigestDetached

func VerifyMessageDigestDetached(signer SignerInfo, signedData []byte) error

VerifyMessageDigestDetached verifies that the message-digest authenticated attribute in signer matches the hash of signedData (RFC 5652 §5.4). Use this for detached signatures where the content is supplied separately.

err := pkcs7.VerifyMessageDigestDetached(p7.Signers[0], originalContent)

func VerifyMessageDigestEmbedded

func VerifyMessageDigestEmbedded(oidDigestAlg asn1.ObjectIdentifier, digest, signedData []byte) error

VerifyMessageDigestEmbedded verifies a message digest for embedded signatures without authenticated attributes (RFC 5652 §5.4). The oidDigestAlg parameter specifies which hash algorithm to use, matching the signer's digestAlgorithm.

err := pkcs7.VerifyMessageDigestEmbedded(
    signer.DigestAlgorithm.Algorithm, expectedDigest, content)

func VerifyMessageDigestTSToken

func VerifyMessageDigestTSToken(oidHashAlg asn1.ObjectIdentifier, digest, signedData []byte) error

VerifyMessageDigestTSToken verifies a message digest for timestamp token responses (RFC 3161). Delegates to VerifyMessageDigestEmbedded.

Types

type Attribute

type Attribute struct {
	Type  asn1.ObjectIdentifier
	Value interface{}
}

Attribute represents a CMS attribute (RFC 5652 §11). Value must be marshalable by encoding/asn1.

type ESSCertID

type ESSCertID struct {
	CertHash              []byte
	IssuerAndSerialNumber issuerAndSerial `asn1:"optional"`
}

ESSCertID identifies a certificate by hash for the id-smime-aa-signingCertificate attribute (RFC 2634 §5.4).

type ESSCertIDv2

type ESSCertIDv2 struct {
	HashAlgorithm         pkix.AlgorithmIdentifier `asn1:"optional"` // DEFAULT sha256
	CertHash              []byte
	IssuerAndSerialNumber issuerAndSerial `asn1:"optional"`
}

ESSCertIDv2 identifies a certificate by hash for the id-smime-aa-signingCertificateV2 attribute (RFC 5035 §3). HashAlgorithm defaults to SHA-256 when absent.

type MessageDigestMismatchError

type MessageDigestMismatchError struct {
	ExpectedDigest []byte
	ActualDigest   []byte
}

MessageDigestMismatchError indicates that the message-digest attribute in the SignerInfo does not match the independently computed digest of the content (RFC 5652 §5.4). This typically means the content was modified after signing.

func (*MessageDigestMismatchError) Error

func (err *MessageDigestMismatchError) Error() string

type PKCS7

type PKCS7 struct {
	Content      []byte
	ContentType  asn1.ObjectIdentifier
	Certificates []*x509.Certificate
	CRLs         []*x509.RevocationList
	Signers      []SignerInfo
	// contains filtered or unexported fields
}

PKCS7 represents a parsed PKCS#7 / CMS message (RFC 5652 §3 ContentInfo). After calling Parse, the Content, Certificates, and Signers fields are populated from the inner structure. For EnvelopedData and EncryptedData, call PKCS7.Decrypt or PKCS7.DecryptUsingPSK to recover plaintext.

func Parse

func Parse(data []byte) (p7 *PKCS7, err error)

Parse decodes a DER or BER encoded PKCS#7 / CMS ContentInfo structure (RFC 5652 §3). BER input is automatically converted to DER before parsing.

The returned PKCS7 contains the parsed content, certificates, and signer information. For SignedData, call PKCS7.Verify to verify signatures. For EnvelopedData, call PKCS7.Decrypt to recover plaintext.

p7, err := pkcs7.Parse(derBytes)
if err != nil {
    log.Fatal(err)
}
if err := p7.Verify(); err != nil {
    log.Fatal(err)
}
fmt.Println(string(p7.Content))

func (*PKCS7) Decrypt

func (p7 *PKCS7) Decrypt(cert *x509.Certificate, pkey crypto.PrivateKey) ([]byte, error)

Decrypt decrypts a CMS EnvelopedData structure (RFC 5652 §6). The recipient's certificate is used to find the matching RecipientInfo, and the private key decrypts the content-encryption key via RSA PKCS#1 v1.5.

p7, _ := pkcs7.Parse(envelopedDER)
plaintext, err := p7.Decrypt(recipientCert, recipientKey)

TODO: Only RSA key transport is supported. ECDH key agreement (RFC 5652 §6.2.2) is not implemented.

func (*PKCS7) DecryptUsingPSK

func (p7 *PKCS7) DecryptUsingPSK(key []byte) ([]byte, error)

DecryptUsingPSK decrypts a CMS EncryptedData structure (RFC 5652 §8) using a pre-shared symmetric key.

p7, _ := pkcs7.Parse(encryptedDER)
plaintext, err := p7.DecryptUsingPSK(symmetricKey)

func (*PKCS7) GetOnlySigner

func (p7 *PKCS7) GetOnlySigner() *x509.Certificate

GetOnlySigner returns the certificate for the single signer of a SignedData. Returns nil if there are zero or more than one signers.

cert := p7.GetOnlySigner()
if cert == nil {
    log.Fatal("expected exactly one signer")
}

func (*PKCS7) UnmarshalSignedAttribute

func (p7 *PKCS7) UnmarshalSignedAttribute(attributeType asn1.ObjectIdentifier, out interface{}) error

UnmarshalSignedAttribute decodes a signed attribute from the first signer's authenticated attributes (RFC 5652 §11). The out parameter must be a pointer to a type compatible with encoding/asn1 unmarshaling.

var signingTime time.Time
err := p7.UnmarshalSignedAttribute(pkcs7.OIDAttributeSigningTime, &signingTime)

func (*PKCS7) Verify

func (p7 *PKCS7) Verify() (err error)

Verify checks the signatures of a PKCS#7 SignedData structure (RFC 5652 §5.6) without certificate chain verification.

For each signer, it independently computes the message digest, validates the content-type attribute, and verifies the signature.

p7, _ := pkcs7.Parse(data)
if err := p7.Verify(); err != nil {
    log.Fatal("signature verification failed:", err)
}

func (*PKCS7) VerifyWithChain

func (p7 *PKCS7) VerifyWithChain(truststore *x509.CertPool) (err error)

VerifyWithChain checks the signatures and certificate chains of a PKCS#7 SignedData (RFC 5652 §5.6). If truststore is non-nil, each signer's certificate chain is verified to a root in the trust store. Chain validation time uses the signing-time attribute if present, otherwise the current time.

roots := x509.NewCertPool()
roots.AppendCertsFromPEM(rootPEM)
if err := p7.VerifyWithChain(roots); err != nil {
    log.Fatal(err)
}

func (*PKCS7) VerifyWithChainAtTime

func (p7 *PKCS7) VerifyWithChainAtTime(truststore *x509.CertPool, currentTime time.Time) (err error)

VerifyWithChainAtTime checks signatures and certificate chains at a specific time, ignoring the signing-time attribute. Use this when you need to verify a signature as it was valid at a particular point in time.

validAt := time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC)
if err := p7.VerifyWithChainAtTime(roots, validAt); err != nil {
    log.Fatal(err)
}

type SignedData

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

SignedData is a builder for creating CMS SignedData structures (RFC 5652 §5). Create one with NewSignedData, add signers with SignedData.AddSigner or SignedData.AddSignerChain, then call SignedData.Finish to produce the DER-encoded output.

Example
// generate a signing cert or load a key pair
cert, err := createTestCertificate(x509.SHA256WithRSA)
if err != nil {
	fmt.Printf("Cannot create test certificates: %s", err)
}

// Initialize a SignedData struct with content to be signed
signedData, err := NewSignedData()
//signedData, err := NewSignedData([]byte("Example data to be signed"))
if err != nil {
	fmt.Printf("Cannot initialize signed data: %s", err)
}

// Add the signing cert and private key
if err := signedData.AddSigner(cert.Certificate, cert.PrivateKey, nil, nil, SignerInfoConfig{}); err != nil {
	fmt.Printf("Cannot add signer: %s", err)
}

// Call Detach() is you want to remove content from the signature
// and generate an S/MIME detached signature
//signedData.Detach()

// Finish() to obtain the signature bytes
detachedSignature, err := signedData.Finish()
if err != nil {
	fmt.Printf("Cannot finish signing data: %s", err)
}
_ = pem.Encode(os.Stdout, &pem.Block{Type: "PKCS7", Bytes: detachedSignature})

func NewSignedData

func NewSignedData() (*SignedData, error)

NewSignedData initializes a CMS SignedData builder (RFC 5652 §5.1). The returned SignedData is ready for adding signers via SignedData.AddSigner.

sd, err := pkcs7.NewSignedData()
if err != nil {
    log.Fatal(err)
}
sd.SetContent([]byte("data to sign"))
err = sd.AddSigner(cert, key, nil, nil, pkcs7.SignerInfoConfig{})
der, err := sd.Finish()

func (*SignedData) AddCertificate

func (sd *SignedData) AddCertificate(cert *x509.Certificate)

AddCertificate adds a certificate to the SignedData certificates field (RFC 5652 §5.1). Use this to include intermediate CA certificates.

func (*SignedData) AddSigner

func (sd *SignedData) AddSigner(cert *x509.Certificate, pkey crypto.PrivateKey, messageDigest []byte, digestOid asn1.ObjectIdentifier, config SignerInfoConfig) error

AddSigner adds a signer to the SignedData without intermediate certificates. It is a convenience wrapper around SignedData.AddSignerChain.

If messageDigest is nil, it is computed over the encapsulated content. If digestOid is nil, it is inferred from the certificate's signature algorithm.

func (*SignedData) AddSignerChain

func (sd *SignedData) AddSignerChain(cert *x509.Certificate, pkey crypto.PrivateKey, messageDigest []byte, digestOid asn1.ObjectIdentifier, parents []*x509.Certificate, config SignerInfoConfig) error

AddSignerChain creates a SignerInfo (RFC 5652 §5.3) and adds it to the SignedData along with the signer certificate and any intermediate certificates.

If digestOid is nil, the digest algorithm is inferred from the signer certificate's signature algorithm. If messageDigest is nil, it is computed over the encapsulated content (which may be empty for detached signatures).

The authenticated attributes always include content-type and message-digest as required by RFC 5652 §5.3. Additional attributes can be provided via config.

The signature is computed over the DER-encoded authenticated attributes (RFC 5652 §5.4).

func (*SignedData) Detach

func (sd *SignedData) Detach()

Detach removes the encapsulated content from the SignedData, producing a detached signature (RFC 5652 §5.2). The recipient must supply the content separately for verification. Call this after adding signers but before SignedData.Finish.

Note: the message digest is computed over the content at AddSigner time, so the digest is already embedded in the signed attributes.

func (*SignedData) Finish

func (sd *SignedData) Finish() ([]byte, error)

Finish marshals the SignedData into a DER-encoded CMS ContentInfo (RFC 5652 §3). The output can be parsed back with Parse.

signedDER, err := sd.Finish()

func (*SignedData) GetSignedData

func (sd *SignedData) GetSignedData() *signedData

GetSignedData returns the internal signedData structure for advanced manipulation before calling SignedData.Finish.

func (*SignedData) SetContent

func (sd *SignedData) SetContent(data []byte)

SetContent sets the encapsulated content (eContent) that will be signed (RFC 5652 §5.2). Call this before SignedData.AddSigner to include content in the SignedData structure. If not called, the content is empty (suitable for detached signatures after calling SignedData.Detach).

sd, _ := pkcs7.NewSignedData()
sd.SetContent([]byte("data to sign"))
sd.AddSigner(cert, key, nil, nil, pkcs7.SignerInfoConfig{})

type SignerInfo

type SignerInfo struct {
	Version                   int `asn1:"default:1"`
	IssuerAndSerialNumber     issuerAndSerial
	DigestAlgorithm           pkix.AlgorithmIdentifier
	AuthenticatedAttributes   []attribute `asn1:"optional,omitempty,tag:0"` // RFC5652: signedAttrs [0] IMPLICIT SignedAttributes OPTIONAL
	DigestEncryptionAlgorithm pkix.AlgorithmIdentifier
	EncryptedDigest           []byte      `asn1:"octet"`
	UnauthenticatedAttributes []attribute `asn1:"optional,omitempty,tag:1"` // RFC5652: unsignedAttrs [1] IMPLICIT UnsignedAttributes OPTIONAL
}

SignerInfo contains per-signer information (RFC 5652 §5.3).

type SignerInfoConfig

type SignerInfoConfig struct {
	ExtraSignedAttributes   []Attribute
	ExtraUnsignedAttributes []Attribute
}

SignerInfoConfig holds optional attributes to include when adding a signer. Extra attributes are added to the SignerInfo authenticated or unauthenticated attribute sets (RFC 5652 §5.3).

type SigningCertificate

type SigningCertificate struct {
	Certs []ESSCertID `asn1:"sequence"`
}

SigningCertificate is the value of the id-smime-aa-signingCertificate attribute (RFC 2634 §5.4). It binds a signer to a specific certificate.

type SigningCertificateV2

type SigningCertificateV2 struct {
	Certs []ESSCertIDv2
}

SigningCertificateV2 is the value of the id-smime-aa-signingCertificateV2 attribute (RFC 5035 §3).

Jump to

Keyboard shortcuts

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