Documentation
¶
Overview ¶
Package cms provides CMS/PKCS#7 signature generation and verification with Ed25519 support.
Package cms implements CMS/PKCS#7 signature generation with Ed25519 support.
This package fills a gap in the Go ecosystem as existing CMS libraries (mozilla/pkcs7, cloudflare/cfssl) do not support Ed25519 signatures.
Security Considerations ¶
Time Security: The signing time attribute is included in the CMS signature and is cryptographically protected. However, the accuracy depends on the security of the time source. For production use, provide a TimeSource synchronized with a trusted NTP server or use a hardware-based secure time source via SignDataWithOptions.
Private Key Memory: Go's garbage collector does not guarantee that memory containing sensitive data will be zeroed before being reused or released. Private keys passed to SignData will remain in memory until garbage collected, and there is no way to force immediate clearing of this memory. For high-security environments requiring guaranteed key material erasure from memory, consider:
- Using hardware security modules (HSMs) that keep keys in secure hardware
- Using platform-specific memory protection mechanisms
- Minimizing the time private keys are held in memory
- Using short-lived signing keys
Package cms implements CMS/PKCS#7 signature verification with Ed25519 support.
This package provides RFC 5652 compliant verification of CMS/PKCS#7 signatures using Ed25519 keys, which is unique among Go CMS implementations.
Security Considerations ¶
Memory Security: For memory security considerations when handling private keys in verification contexts (e.g., when using HSMs or secure enclaves for signing), see the signer package documentation.
Example usage:
// Read CMS signature and data
cmsData, _ := os.ReadFile("signature.p7s")
originalData, _ := os.ReadFile("document.txt")
// Setup verification options
opts := cms.VerifyOptions{
Roots: systemRootPool, // Optional: uses system roots if nil
}
// Verify the signature
chain, err := cms.Verify(cmsData, originalData, opts)
if err != nil {
log.Fatal("Verification failed:", err)
}
// The first certificate is the signer
signerCert := chain[0]
fmt.Printf("Signed by: %s\n", signerCert.Subject)
Index ¶
- func SignData(data []byte, cert *x509.Certificate, privateKey ed25519.PrivateKey) ([]byte, error)
- func SignDataWithOptions(data []byte, cert *x509.Certificate, privateKey ed25519.PrivateKey, ...) ([]byte, error)
- func SignDataWithSigner(data []byte, cert *x509.Certificate, signer crypto.Signer) ([]byte, error)
- func SignDataWithoutAttributes(data []byte, cert *x509.Certificate, privateKey ed25519.PrivateKey) ([]byte, error)
- func Verify(cmsSignature, detachedData []byte, opts VerifyOptions) ([]*x509.Certificate, error)
- type KeyError
- type RevocationChecker
- type SignOptions
- type SignatureError
- type TimeSource
- type ValidationError
- type VerifyOptions
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func SignData ¶
func SignData(data []byte, cert *x509.Certificate, privateKey ed25519.PrivateKey) ([]byte, error)
SignData creates a detached CMS/PKCS#7 signature using Ed25519.
This function implements RFC 5652 (CMS) with RFC 8410 (Ed25519 in CMS). The signature is detached (does not include the original data).
This creates a Case 1 signature (WITH signed attributes), which includes: - Content-type attribute - Message-digest attribute - Signing-time attribute
For Case 2 signatures (WITHOUT signed attributes), use SignDataWithoutAttributes. For more control over signature generation (e.g., custom time sources), use SignDataWithOptions.
Parameters:
- data: The data to be signed
- cert: The X.509 certificate containing the public key
- privateKey: The Ed25519 private key for signing
Returns:
- DER-encoded CMS/PKCS#7 signature
func SignDataWithOptions ¶
func SignDataWithOptions(data []byte, cert *x509.Certificate, privateKey ed25519.PrivateKey, opts SignOptions) ([]byte, error)
SignDataWithOptions creates a detached CMS/PKCS#7 signature using Ed25519 with custom options.
This function implements RFC 5652 (CMS) with RFC 8410 (Ed25519 in CMS). The signature is detached (does not include the original data).
Parameters:
- data: The data to be signed
- cert: The X.509 certificate containing the public key
- privateKey: The Ed25519 private key for signing
- opts: Optional parameters for signature generation
Returns:
- DER-encoded CMS/PKCS#7 signature
func SignDataWithSigner ¶ added in v0.0.2
SignDataWithSigner creates a detached CMS/PKCS#7 signature using a crypto.Signer.
This function enables hardware-backed signing (e.g., PKCS#11, HSMs) by accepting the standard crypto.Signer interface instead of requiring direct access to the private key material.
Parameters:
- data: The data to be signed
- cert: The X.509 certificate containing the public key
- signer: A crypto.Signer implementation (e.g., ed25519.PrivateKey)
Returns:
- DER-encoded CMS/PKCS#7 signature
func SignDataWithoutAttributes ¶ added in v0.0.3
func SignDataWithoutAttributes(data []byte, cert *x509.Certificate, privateKey ed25519.PrivateKey) ([]byte, error)
SignDataWithoutAttributes creates a Case 2 CMS/PKCS#7 signature (without signed attributes).
This function implements RFC 5652 (CMS) with RFC 8419 (Ed25519 in CMS) for Case 2: - No signed attributes are included - For Ed25519 (PureEdDSA), the signature is directly over the raw data - The signature is detached (does not include the original data)
Case 2 signatures are simpler but provide less metadata: - No signing time - No content-type protection - Message digest is implicit (not included as an attribute)
Use this when: - You need minimal signature size - Compatibility with systems that don't support signed attributes - The signing time is not important
Parameters:
- data: The data to be signed
- cert: The X.509 certificate containing the public key
- privateKey: The Ed25519 private key for signing
Returns:
- DER-encoded CMS/PKCS#7 signature without signed attributes
func Verify ¶
func Verify(cmsSignature, detachedData []byte, opts VerifyOptions) ([]*x509.Certificate, error)
Verify parses and validates a detached CMS/PKCS#7 signature
This function implements RFC 5652 (CMS) verification for Ed25519 signatures. It validates the signature structure, certificate chain, message digest, and cryptographic signature.
Parameters:
- cmsSignature: DER-encoded CMS/PKCS#7 signature
- detachedData: The original data that was signed
- opts: Verification options including trusted roots
Returns:
- The validated certificate chain (signer cert first, then intermediates)
- An error if verification fails at any step
Types ¶
type KeyError ¶
type KeyError struct {
Operation string // Operation that failed (generate, load, verify, etc.)
KeyType string // Type of key (master, ephemeral, etc.)
Wrapped error // Underlying error
}
KeyError provides detailed information about key operation failures
func NewKeyError ¶
NewKeyError creates a new KeyError
type RevocationChecker ¶
type RevocationChecker interface {
// CheckRevocation checks if a certificate has been revoked.
// Returns an error if the certificate is revoked or if the check fails.
// Returns nil if the certificate is valid and not revoked.
CheckRevocation(cert *x509.Certificate) error
}
RevocationChecker provides an interface for checking certificate revocation status. Implementations can use CRL, OCSP, or other revocation mechanisms.
Example implementation:
type MyRevocationChecker struct{}
func (c *MyRevocationChecker) CheckRevocation(cert *x509.Certificate) error {
// Check CRL or OCSP
if isRevoked(cert) {
return fmt.Errorf("certificate %s is revoked", cert.SerialNumber)
}
return nil
}
type SignOptions ¶
type SignOptions struct {
// TimeSource provides the time to use for the signing time attribute.
// If nil, time.Now() is used. For production use, consider using a
// secure time source synchronized with a trusted time server.
TimeSource TimeSource
// DigestAlgorithm specifies the hash algorithm to use for message digest.
//
// IMPORTANT: For Ed25519 signatures, this field is IGNORED.
// RFC 8419 Section 3 mandates that Ed25519 with signed attributes MUST use SHA-512.
// This requirement is enforced regardless of the value specified here.
//
// For future support of other signature algorithms (RSA, ECDSA), this field
// would allow selection of the digest algorithm.
DigestAlgorithm crypto.Hash
// IntermediateCerts are additional certificates to include in the CMS structure.
// These should be intermediate CA certificates in the chain from the signer
// certificate to the root CA. The signer certificate (passed to SignData) is
// always included; these are additional certificates to help verifiers build
// the certificate chain.
IntermediateCerts []*x509.Certificate
}
SignOptions provides optional parameters for signature generation.
type SignatureError ¶
type SignatureError struct {
Type string // Type of signature (binding, request, CMS, etc.)
Reason string // Human-readable reason for failure
Wrapped error // Underlying error
}
SignatureError provides detailed information about signature verification failures
func NewSignatureError ¶
func NewSignatureError(sigType, reason string, wrapped error) *SignatureError
NewSignatureError creates a new SignatureError
func (*SignatureError) Error ¶
func (e *SignatureError) Error() string
func (*SignatureError) Unwrap ¶
func (e *SignatureError) Unwrap() error
type TimeSource ¶
type TimeSource interface {
// Now returns the current time to be used for signature generation.
Now() time.Time
}
TimeSource provides the current time for signature generation. Implementations can provide secure time sources (NTP, trusted time servers) or fixed times for testing.
Security Note: The signing time is included in the signed attributes and is cryptographically protected by the signature. However, the accuracy of this time depends on the security of the time source. For high-security applications, use a trusted time source synchronized with a reliable NTP server or a hardware-based secure time source.
Example implementation:
type SecureTimeSource struct{}
func (s *SecureTimeSource) Now() time.Time {
// Query trusted NTP server or hardware time source
return getSecureTime()
}
type ValidationError ¶
type ValidationError struct {
Field string // Field that failed validation
Value string // Value that was invalid (if safe to include)
Reason string // Why it's invalid
Wrapped error // Underlying error
}
ValidationError represents validation failures
func NewValidationError ¶
func NewValidationError(field, value, reason string, wrapped error) *ValidationError
NewValidationError creates a new ValidationError
func (*ValidationError) Error ¶
func (e *ValidationError) Error() string
func (*ValidationError) Unwrap ¶
func (e *ValidationError) Unwrap() error
type VerifyOptions ¶
type VerifyOptions struct {
Roots *x509.CertPool // Trusted root certificates
Intermediates *x509.CertPool // Intermediate certificates
CurrentTime time.Time // Time for validation (default: time.Now())
TimeFunc func() time.Time // Optional time source for testing (overrides CurrentTime)
SkipTimeValidation bool // Skip certificate expiry validation (useful for ephemeral certificate scenarios, e.g., short-lived certs in automation or Git commits)
KeyUsages []x509.ExtKeyUsage // Required key usages
RevocationChecker RevocationChecker // Optional revocation checker (CRL/OCSP)
MaxSignatureSize int64 // Maximum signature size in bytes (default: 1MB, prevents DoS)
}
VerifyOptions allows specifying verification parameters