<PackageReference Include="BouncyCastle.Cryptography" Version="2.6.2" />

SignerInformation

public class SignerInformation
using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Asn1.Cms; using Org.BouncyCastle.Asn1.EdEC; using Org.BouncyCastle.Asn1.Nist; using Org.BouncyCastle.Asn1.Pkcs; using Org.BouncyCastle.Asn1.X509; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Digests; using Org.BouncyCastle.Crypto.Engines; using Org.BouncyCastle.Crypto.IO; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Crypto.Signers; using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities; using Org.BouncyCastle.Utilities.Collections; using Org.BouncyCastle.X509; using System; using System.Collections.Generic; using System.IO; namespace Org.BouncyCastle.Cms { public class SignerInformation { private SignerID sid; private CmsProcessable content; private byte[] signature; private DerObjectIdentifier contentType; private byte[] calculatedDigest; private byte[] resultDigest; private Org.BouncyCastle.Asn1.Cms.AttributeTable signedAttributeTable; private Org.BouncyCastle.Asn1.Cms.AttributeTable unsignedAttributeTable; private readonly bool isCounterSignature; protected Org.BouncyCastle.Asn1.Cms.SignerInfo info; protected AlgorithmIdentifier digestAlgorithm; protected AlgorithmIdentifier encryptionAlgorithm; protected readonly Asn1Set signedAttributeSet; protected readonly Asn1Set unsignedAttributeSet; public bool IsCounterSignature => isCounterSignature; public DerObjectIdentifier ContentType => contentType; public SignerID SignerID => sid; public int Version => info.Version.IntValueExact; public AlgorithmIdentifier DigestAlgorithmID => digestAlgorithm; [Obsolete("Use 'DigestAlgorithmID' instead")] public string DigestAlgOid { get { return digestAlgorithm.Algorithm.GetID(); } } [Obsolete("Use 'DigestAlgorithmID' instead")] public Asn1Object DigestAlgParams { get { return digestAlgorithm.Parameters?.ToAsn1Object(); } } [Obsolete("Use 'SignatureAlgorithm' property instead")] public AlgorithmIdentifier EncryptionAlgorithmID { get { return encryptionAlgorithm; } } [Obsolete("Use 'SignatureAlgorithm' property instead")] public string EncryptionAlgOid { get { return encryptionAlgorithm.Algorithm.Id; } } [Obsolete("Use 'SignatureAlgorithm' property instead")] public Asn1Object EncryptionAlgParams { get { return encryptionAlgorithm.Parameters?.ToAsn1Object(); } } public AlgorithmIdentifier SignatureAlgorithm => encryptionAlgorithm; public Org.BouncyCastle.Asn1.Cms.AttributeTable SignedAttributes { get { if (signedAttributeTable == null) { Asn1Set asn1Set = signedAttributeSet; signedAttributeTable = ((asn1Set != null) ? asn1Set.ToAttributeTable() : null); } return signedAttributeTable; } } public Org.BouncyCastle.Asn1.Cms.SignerInfo SignerInfo => info; public Org.BouncyCastle.Asn1.Cms.AttributeTable UnsignedAttributes { get { if (unsignedAttributeTable == null) { Asn1Set asn1Set = unsignedAttributeSet; unsignedAttributeTable = ((asn1Set != null) ? asn1Set.ToAttributeTable() : null); } return unsignedAttributeTable; } } internal SignerInformation(Org.BouncyCastle.Asn1.Cms.SignerInfo info, DerObjectIdentifier contentType, CmsProcessable content, byte[] calculatedDigest) { this.info = info; sid = new SignerID(); this.contentType = contentType; isCounterSignature = (contentType == null); try { SignerIdentifier signerID = info.SignerID; if (signerID.IsTagged) { Asn1OctetString asn1OctetString = (Asn1OctetString)signerID.ID; sid.SubjectKeyIdentifier = asn1OctetString.GetEncoded("DER"); } else { Org.BouncyCastle.Asn1.Cms.IssuerAndSerialNumber instance = Org.BouncyCastle.Asn1.Cms.IssuerAndSerialNumber.GetInstance(signerID.ID); sid.Issuer = instance.Issuer; sid.SerialNumber = instance.SerialNumber.Value; } } catch (IOException) { throw new ArgumentException("invalid sid in SignerInfo"); } digestAlgorithm = info.DigestAlgorithm; signedAttributeSet = info.SignedAttrs; unsignedAttributeSet = info.UnsignedAttrs; encryptionAlgorithm = info.SignatureAlgorithm; signature = Arrays.Clone(info.Signature.GetOctets()); this.content = content; this.calculatedDigest = calculatedDigest; } protected SignerInformation(SignerInformation baseInfo) { info = baseInfo.info; content = baseInfo.content; contentType = baseInfo.contentType; isCounterSignature = baseInfo.IsCounterSignature; sid = baseInfo.sid; digestAlgorithm = info.DigestAlgorithm; signedAttributeSet = info.SignedAttrs; unsignedAttributeSet = info.UnsignedAttrs; encryptionAlgorithm = info.SignatureAlgorithm; signature = Arrays.Clone(info.Signature.GetOctets()); calculatedDigest = baseInfo.calculatedDigest; signedAttributeTable = baseInfo.signedAttributeTable; unsignedAttributeTable = baseInfo.unsignedAttributeTable; } public byte[] GetContentDigest() { if (resultDigest == null) throw new InvalidOperationException("method can only be called after verify."); return (byte[])resultDigest.Clone(); } [Obsolete("Use 'SignerInfo' property instead")] public Org.BouncyCastle.Asn1.Cms.SignerInfo ToSignerInfo() { return info; } public byte[] GetSignature() { return Arrays.Clone(signature); } public SignerInformationStore GetCounterSignatures() { Org.BouncyCastle.Asn1.Cms.AttributeTable unsignedAttributes = UnsignedAttributes; if (unsignedAttributes == null) return new SignerInformationStore(new List<SignerInformation>(0)); List<SignerInformation> list = new List<SignerInformation>(); foreach (Org.BouncyCastle.Asn1.Cms.Attribute item in unsignedAttributes.GetAll(CmsAttributes.CounterSignature)) { Asn1Set attrValues = item.AttrValues; int count = attrValues.Count; foreach (Org.BouncyCastle.Asn1.Cms.SignerInfo item2 in CollectionUtilities.Select(attrValues, Org.BouncyCastle.Asn1.Cms.SignerInfo.GetInstance)) { byte[] array = DigestUtilities.CalculateDigest(item2.DigestAlgorithm.Algorithm, signature); list.Add(new SignerInformation(item2, null, null, array)); } } return new SignerInformationStore(list); } public virtual byte[] GetEncodedSignedAttributes() { return signedAttributeSet?.GetEncoded("DER"); } private bool DoVerify(AsymmetricKeyParameter publicKey) { AlgorithmIdentifier digestAlgorithmID = DigestAlgorithmID; DerObjectIdentifier algorithm = digestAlgorithmID.Algorithm; Asn1Encodable parameters = digestAlgorithmID.Parameters; AlgorithmIdentifier signatureAlgorithm = SignatureAlgorithm; DerObjectIdentifier algorithm2 = signatureAlgorithm.Algorithm; Asn1Encodable parameters2 = signatureAlgorithm.Parameters; string text; ISigner signer; MLDsaParameters value; SlhDsaParameters value2; if (EdECObjectIdentifiers.id_Ed25519.Equals(algorithm2)) { if (parameters2 != null) throw new CmsException("Ed25519 signature cannot specify algorithm parameters"); if (signedAttributeSet == null) text = null; else { if (!NistObjectIdentifiers.IdSha512.Equals(algorithm) || parameters != null) throw new CmsException("Ed25519 signature used with unsupported digest algorithm"); text = CmsSignedHelper.GetDigestAlgName(algorithm); } signer = SignerUtilities.GetSigner(algorithm2); } else if (MLDsaParameters.ByOid.TryGetValue(algorithm2, out value)) { if (value.IsPreHash) throw new CmsException($"{value}"""); if (parameters2 != null) throw new CmsException($"{value}"""); if (signedAttributeSet == null) text = null; else { if (!NistObjectIdentifiers.IdSha512.Equals(algorithm) && !NistObjectIdentifiers.IdShake256.Equals(algorithm)) throw new CmsException($"{value}"""); if (parameters != null) throw new CmsException($"{value}"""); text = CmsSignedHelper.GetDigestAlgName(algorithm); } signer = SignerUtilities.GetSigner(algorithm2); } else if (SlhDsaParameters.ByOid.TryGetValue(algorithm2, out value2)) { if (value2.IsPreHash) throw new CmsException($"{value2}"""); if (parameters2 != null) throw new CmsException($"{value2}"""); if (signedAttributeSet == null) text = null; else { if (!CmsSignedHelper.GetSlhDsaDigestOid(algorithm2).Equals(algorithm) || parameters != null) throw new CmsException($"{value2}"""); text = CmsSignedHelper.GetDigestAlgName(algorithm); } signer = SignerUtilities.GetSigner(algorithm2); } else if (PkcsObjectIdentifiers.IdRsassaPss.Equals(algorithm2)) { if (parameters2 == null) throw new CmsException("RSASSA-PSS signature must specify algorithm parameters"); try { RsassaPssParameters instance = RsassaPssParameters.GetInstance(parameters2); if (!instance.HashAlgorithm.Algorithm.Equals(algorithm)) throw new CmsException("RSASSA-PSS signature parameters specified incorrect hash algorithm"); if (!instance.MaskGenAlgorithm.Algorithm.Equals(PkcsObjectIdentifiers.IdMgf1)) throw new CmsException("RSASSA-PSS signature parameters specified unknown MGF"); IDigest digest = DigestUtilities.GetDigest(algorithm); int intValueExact = instance.SaltLength.IntValueExact; if (!RsassaPssParameters.DefaultTrailerField.Equals(instance.TrailerField)) throw new CmsException("RSASSA-PSS signature parameters must have trailerField of 1"); text = CmsSignedHelper.GetDigestAlgName(algorithm); IAsymmetricBlockCipher cipher = new RsaBlindedEngine(); signer = ((signedAttributeSet != null) ? new PssSigner(cipher, digest, intValueExact) : PssSigner.CreateRawSigner(cipher, digest, intValueExact)); } catch (Exception innerException) { throw new CmsException("failed to set RSASSA-PSS signature parameters", innerException); } } else { if (!X509Utilities.IsAbsentParameters(parameters2)) throw new CmsException("unrecognised signature parameters provided"); text = CmsSignedHelper.GetDigestAlgName(algorithm2); if (text.Equals(algorithm2.GetID())) text = CmsSignedHelper.GetDigestAlgName(algorithm); signer = CmsSignedHelper.GetSignatureInstance(text + "with" + CmsSignedHelper.GetEncryptionAlgName(algorithm2)); } try { if (signedAttributeSet == null && text == null) { if (content == null) throw new CmsException("data not encapsulated in signature - use detached constructor."); resultDigest = null; } else if (calculatedDigest != null) { resultDigest = calculatedDigest; } else { IDigest digestInstance = CmsSignedHelper.GetDigestInstance(text); if (content != null) { using (DigestSink outStream = new DigestSink(digestInstance)) content.Write(outStream); } else if (signedAttributeSet == null) { throw new CmsException("data not encapsulated in signature - use detached constructor."); } resultDigest = DigestUtilities.DoFinal(digestInstance); } } catch (IOException innerException2) { throw new CmsException("can't process mime object to create signature.", innerException2); } Asn1Object singleValuedSignedAttribute = GetSingleValuedSignedAttribute(CmsAttributes.ContentType, "content-type"); if (singleValuedSignedAttribute == null) { if (!isCounterSignature && signedAttributeSet != null) throw new CmsException("The content-type attribute type MUST be present whenever signed attributes are present in signed-data"); } else { if (isCounterSignature) throw new CmsException("[For counter signatures,] the signedAttributes field MUST NOT contain a content-type attribute"); DerObjectIdentifier obj = singleValuedSignedAttribute as DerObjectIdentifier; if (obj == null) throw new CmsException("content-type attribute value not of ASN.1 type 'OBJECT IDENTIFIER'"); if (!obj.Equals(contentType)) throw new CmsException("content-type attribute value does not match eContentType"); } Asn1Object singleValuedSignedAttribute2 = GetSingleValuedSignedAttribute(CmsAttributes.MessageDigest, "message-digest"); if (singleValuedSignedAttribute2 == null) { if (signedAttributeSet != null) throw new CmsException("the message-digest signed attribute type MUST be present when there are any signed attributes present"); } else { Asn1OctetString asn1OctetString = singleValuedSignedAttribute2 as Asn1OctetString; if (asn1OctetString == null) throw new CmsException("message-digest attribute value not of ASN.1 type 'OCTET STRING'"); if (!Arrays.AreEqual(resultDigest, asn1OctetString.GetOctets())) throw new CmsException("message-digest attribute value does not match calculated value"); } Org.BouncyCastle.Asn1.Cms.AttributeTable signedAttributes = SignedAttributes; if (signedAttributes == null || signedAttributes.GetAll(CmsAttributes.CounterSignature).Count <= 0) { Org.BouncyCastle.Asn1.Cms.AttributeTable unsignedAttributes = UnsignedAttributes; if (unsignedAttributes != null) { foreach (Org.BouncyCastle.Asn1.Cms.Attribute item in unsignedAttributes.GetAll(CmsAttributes.CounterSignature)) { if (item.AttrValues.Count < 1) throw new CmsException("A countersignature attribute MUST contain at least one AttributeValue"); } } try { if (signedAttributeSet == null) { if (!(signer is PssSigner)) { if (resultDigest != null && TryGetRawVerifier(out ISigner rawVerifier)) return VerifySignature(rawVerifier, publicKey, resultDigest, signature); signer.Init(false, publicKey); if (content != null) { using (SignerSink outStream2 = new SignerSink(signer)) content.Write(outStream2); } return signer.VerifySignature(signature); } return VerifySignature(signer, publicKey, resultDigest, signature); } return VerifySignature(signer, publicKey, GetEncodedSignedAttributes(), signature); } catch (InvalidKeyException innerException3) { throw new CmsException("key not appropriate to signature in message.", innerException3); } catch (IOException innerException4) { throw new CmsException("can't process mime object to create signature.", innerException4); } catch (SignatureException ex) { throw new CmsException("invalid signature format in message: " + ex.Message, ex); } } throw new CmsException("A countersignature attribute MUST NOT be a signed attribute"); } private bool TryGetRawVerifier(out ISigner rawVerifier) { string encryptionAlgName = CmsSignedHelper.GetEncryptionAlgName(SignatureAlgorithm.Algorithm); if ("RSA".Equals(encryptionAlgName)) rawVerifier = new RsaDigestSigner(new NullDigest(), digestAlgorithm); else if ("ECDSA".Equals(encryptionAlgName)) { rawVerifier = CmsSignedHelper.GetSignatureInstance("NONEwithECDSA"); } else if ("PLAIN-ECDSA".Equals(encryptionAlgName)) { rawVerifier = CmsSignedHelper.GetSignatureInstance("NONEwithPLAIN-ECDSA"); } else { if (!"DSA".Equals(encryptionAlgName)) { rawVerifier = null; return false; } rawVerifier = CmsSignedHelper.GetSignatureInstance("NONEwithDSA"); } return true; } public bool Verify(AsymmetricKeyParameter pubKey) { if (pubKey.IsPrivate) throw new ArgumentException("Expected public key", "pubKey"); GetSigningTime(); return DoVerify(pubKey); } public bool Verify(X509Certificate cert) { Org.BouncyCastle.Asn1.Cms.Time signingTime = GetSigningTime(); if (signingTime != null) cert.CheckValidity(signingTime.ToDateTime()); return DoVerify(cert.GetPublicKey()); } private Asn1Object GetSingleValuedSignedAttribute(DerObjectIdentifier attrOid, string printableName) { Org.BouncyCastle.Asn1.Cms.AttributeTable unsignedAttributes = UnsignedAttributes; if (unsignedAttributes != null && unsignedAttributes.GetAll(attrOid).Count > 0) throw new CmsException("The " + printableName + " attribute MUST NOT be an unsigned attribute"); Org.BouncyCastle.Asn1.Cms.AttributeTable signedAttributes = SignedAttributes; if (signedAttributes != null) { Asn1EncodableVector all = signedAttributes.GetAll(attrOid); switch (all.Count) { case 0: return null; case 1: { Asn1Set attrValues = ((Org.BouncyCastle.Asn1.Cms.Attribute)all[0]).AttrValues; if (attrValues.Count != 1) throw new CmsException("A " + printableName + " attribute MUST have a single attribute value"); return attrValues[0].ToAsn1Object(); } default: throw new CmsException("The SignedAttributes in a signerInfo MUST NOT include multiple instances of the " + printableName + " attribute"); } } return null; } private Org.BouncyCastle.Asn1.Cms.Time GetSigningTime() { Asn1Object singleValuedSignedAttribute = GetSingleValuedSignedAttribute(CmsAttributes.SigningTime, "signing-time"); if (singleValuedSignedAttribute != null) try { return Org.BouncyCastle.Asn1.Cms.Time.GetInstance(singleValuedSignedAttribute); } catch (ArgumentException) { throw new CmsException("signing-time attribute value not a valid 'Time' structure"); } return null; } public static SignerInformation ReplaceUnsignedAttributes(SignerInformation signerInformation, Org.BouncyCastle.Asn1.Cms.AttributeTable unsignedAttributes) { Asn1Set unauthenticatedAttributes = unsignedAttributes?.ToDerSet(); Org.BouncyCastle.Asn1.Cms.SignerInfo signerInfo = signerInformation.SignerInfo; return new SignerInformation(new Org.BouncyCastle.Asn1.Cms.SignerInfo(signerInfo.SignerID, signerInfo.DigestAlgorithm, signerInfo.SignedAttrs, signerInfo.SignatureAlgorithm, signerInfo.Signature, unauthenticatedAttributes), signerInformation.contentType, signerInformation.content, null); } public static SignerInformation AddCounterSigners(SignerInformation signerInformation, SignerInformationStore counterSigners) { DerSet attrValues = DerSet.Map(counterSigners.SignersInternal, (SignerInformation sigInf) => sigInf.SignerInfo); Asn1Set unauthenticatedAttributes = (signerInformation.UnsignedAttributes ?? DerSet.Empty.ToAttributeTable()).Add(new Org.BouncyCastle.Asn1.Cms.Attribute(CmsAttributes.CounterSignature, attrValues)).ToDerSet(); Org.BouncyCastle.Asn1.Cms.SignerInfo signerInfo = signerInformation.SignerInfo; return new SignerInformation(new Org.BouncyCastle.Asn1.Cms.SignerInfo(signerInfo.SignerID, signerInfo.DigestAlgorithm, signerInfo.SignedAttrs, signerInfo.SignatureAlgorithm, signerInfo.Signature, unauthenticatedAttributes), signerInformation.contentType, signerInformation.content, null); } private static bool VerifySignature(ISigner verifier, ICipherParameters parameters, byte[] message, byte[] signature) { verifier.Init(false, parameters); verifier.BlockUpdate(message, 0, message.Length); return verifier.VerifySignature(signature); } } }