Class CmsSignatureBuilder
- Namespace
- SimpleSign.Core.Crypto
- Assembly
- SimpleSign.Core.dll
Builds a CMS/PKCS#7 SignedData compatible with PAdES (adbe.pkcs7.detached). Uses exclusively System.Security.Cryptography from .NET — zero external dependencies.
public sealed class CmsSignatureBuilder
- Inheritance
-
CmsSignatureBuilder
- Inherited Members
Methods
AddUnsignedAttributes(byte[], IReadOnlyList<CmsAttribute>)
Adds unsigned attributes to an existing CMS/PKCS#7 SignedData structure. Parses the original CMS, injects the attributes into SignerInfo unsignedAttrs [1], and returns the rewritten DER. Follows the same pattern used for timestamp embedding.
public static byte[] AddUnsignedAttributes(byte[] cmsBytes, IReadOnlyList<CmsAttribute> unsignedAttributes)
Parameters
cmsBytesbyte[]DER-encoded CMS/PKCS#7 SignedData.
unsignedAttributesIReadOnlyList<CmsAttribute>Unsigned attributes to inject (e.g., CertValues, RevocationValues, ArchiveTimeStamp).
Returns
- byte[]
Rewritten CMS bytes with unsigned attributes appended.
Build(ReadOnlySpan<byte>, X509Certificate2, HashAlgorithmName, DateTimeOffset?, IReadOnlyList<X509Certificate2>?, IReadOnlyList<CmsAttribute>?, bool, string?, ILogger?)
Signs the provided bytes and returns a DER-encoded CMS/SignedData. The certificate must contain a private key (A1/PFX or Windows Store with minidriver).
public static byte[] Build(ReadOnlySpan<byte> dataToSign, X509Certificate2 certificate, HashAlgorithmName hashAlgorithm, DateTimeOffset? signingTime = null, IReadOnlyList<X509Certificate2>? extraCertificates = null, IReadOnlyList<CmsAttribute>? extraAttributes = null, bool padesAttributes = true, string? signatureAlgorithmOid = null, ILogger? logger = null)
Parameters
dataToSignReadOnlySpan<byte>The document bytes to be signed (ByteRange 1 + ByteRange 2).
certificateX509Certificate2Certificate with private key.
hashAlgorithmHashAlgorithmNameHash algorithm (SHA256 or SHA512).
signingTimeDateTimeOffset?Signing date/time (UTC).
extraCertificatesIReadOnlyList<X509Certificate2>Intermediate certificates to compose the chain.
extraAttributesIReadOnlyList<CmsAttribute>Optional CAdES signed attributes (e.g., commitment-type, signature-policy).
padesAttributesboolWhen true (default), adds the
id-aa-signingCertificateV2(ESS CertV2) attribute required by PAdES B-B.signatureAlgorithmOidstringOptional override for the signature algorithm OID. When not null, this OID is used instead of the one auto-detected from the certificate. Must be compatible with the certificate's public key type (validated at call time). Primary use case: forcing RSASSA-PSS on an
rsaEncryptioncertificate.loggerILoggerOptional logger for debug diagnostics.
Returns
- byte[]
BuildAsync(ReadOnlyMemory<byte>, X509Certificate2, Func<byte[], Task<byte[]>>, string, HashAlgorithmName, DateTimeOffset?, IReadOnlyList<X509Certificate2>?, IReadOnlyList<CmsAttribute>?, bool, ILogger?)
Signs the provided bytes using an external signing delegate and returns a DER-encoded CMS/SignedData. Use this overload for A3 tokens, HSMs, cloud KMS, or any scenario where the private key is not directly accessible via X509Certificate2.
public static Task<byte[]> BuildAsync(ReadOnlyMemory<byte> dataToSign, X509Certificate2 certificate, Func<byte[], Task<byte[]>> externalSigner, string signatureAlgorithmOid, HashAlgorithmName hashAlgorithm, DateTimeOffset? signingTime = null, IReadOnlyList<X509Certificate2>? extraCertificates = null, IReadOnlyList<CmsAttribute>? extraAttributes = null, bool padesAttributes = true, ILogger? logger = null)
Parameters
dataToSignReadOnlyMemory<byte>The document bytes to be signed (ByteRange 1 + ByteRange 2).
certificateX509Certificate2The signer's public certificate (private key NOT required).
externalSignerFunc<byte[], Task<byte[]>>A delegate that receives the DER-encoded signed attributes and returns the raw signature bytes. For RSA: PKCS#1 v1.5 signature. For ECDSA: DER SEQUENCE { r, s } (RFC 3279). For EdDSA: raw signature bytes.
signatureAlgorithmOidstringThe OID of the signature algorithm (e.g., "1.2.840.113549.1.1.11" for RSA-SHA256). Must match the algorithm used by the external signer.
hashAlgorithmHashAlgorithmNameHash algorithm (SHA256 or SHA512).
signingTimeDateTimeOffset?Signing date/time (UTC).
extraCertificatesIReadOnlyList<X509Certificate2>Intermediate certificates to compose the chain.
extraAttributesIReadOnlyList<CmsAttribute>Optional CAdES signed attributes (e.g., commitment-type, signature-policy).
padesAttributesboolWhen true (default), adds the
id-aa-signingCertificateV2(ESS CertV2) attribute required by PAdES B-B. Set to false to produce a plain PKCS#7/CMS signature without PAdES-specific attributes.loggerILoggerOptional logger for debug diagnostics.
Returns
BuildSignedAttributes(byte[], string, DateTimeOffset, X509Certificate2, IReadOnlyList<CmsAttribute>?, bool)
Builds the DER-encoded signed attributes SET for a CMS signature.
public static byte[] BuildSignedAttributes(byte[] contentHash, string digestOid, DateTimeOffset time, X509Certificate2 signerCertificate, IReadOnlyList<CmsAttribute>? extraAttributes = null, bool padesAttributes = true)
Parameters
contentHashbyte[]The hash of the content being signed.
digestOidstringThe digest algorithm OID.
timeDateTimeOffsetSigning timestamp.
signerCertificateX509Certificate2The signer's certificate (for signingCertificateV2).
extraAttributesIReadOnlyList<CmsAttribute>Optional extra CAdES signed attributes.
padesAttributesboolWhen true, includes PAdES-specific attributes (signingCertificateV2).
Returns
- byte[]
BuildSignedData(string, string, HashAlgorithmName, byte[], byte[], X509Certificate2, List<X509Certificate2>, int, ILogger?)
Assembles a complete CMS/PKCS#7 SignedData DER structure from pre-built components. Used by the deferred signing pipeline and the CAdES external signer flow.
public static byte[] BuildSignedData(string digestOid, string signatureOid, HashAlgorithmName hashAlgorithm, byte[] signedAttrs, byte[] signature, X509Certificate2 signerCert, List<X509Certificate2> allCerts, int extraAttributeCount = 0, ILogger? logger = null)
Parameters
digestOidstringThe digest algorithm OID used for the content hash.
signatureOidstringThe signature algorithm OID.
hashAlgorithmHashAlgorithmNameThe hash algorithm (used for RSASSA-PSS-params).
signedAttrsbyte[]Pre-built DER-encoded signed attributes SET.
signaturebyte[]The raw signature bytes over the signed attributes.
signerCertX509Certificate2The signer's certificate.
allCertsList<X509Certificate2>All certificates to embed (signer + intermediates).
extraAttributeCountintCount of extra signed attributes (for logging).
loggerILoggerOptional logger.
Returns
- byte[]
ComputeHash(ReadOnlySpan<byte>, HashAlgorithmName)
Computes a cryptographic hash of the provided data using the specified algorithm.
public static byte[] ComputeHash(ReadOnlySpan<byte> data, HashAlgorithmName algorithm)
Parameters
dataReadOnlySpan<byte>algorithmHashAlgorithmName
Returns
- byte[]
DetectRsaPadding(X509Certificate2)
Detects the RSA padding mode from the certificate's signature algorithm. Returns PSS if the cert was issued with RSA-PSS, PKCS1 otherwise.
public static RSASignaturePadding DetectRsaPadding(X509Certificate2 cert)
Parameters
certX509Certificate2
Returns
GetDigestOid(HashAlgorithmName)
Maps a HashAlgorithmName to its corresponding OID string.
public static string GetDigestOid(HashAlgorithmName alg)
Parameters
Returns
SignatureAlgorithmUsesNullParameter(string)
Returns true when the signature algorithm OID expects an explicit NULL parameter in the AlgorithmIdentifier.
public static bool SignatureAlgorithmUsesNullParameter(string signatureOid)
Parameters
signatureOidstring
Returns
ValidateSignatureAlgorithmCompatibility(X509Certificate2, string)
Validates that the requested signature algorithm OID is compatible with the certificate's public key type. Throws ArgumentException if not.
public static void ValidateSignatureAlgorithmCompatibility(X509Certificate2 cert, string signatureAlgorithmOid)
Parameters
certX509Certificate2The signer's certificate.
signatureAlgorithmOidstringOID of the signature algorithm to validate.
Exceptions
- ArgumentException
The OID is incompatible with the certificate's key type.