SignerInformation
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.Cms;
using Org.BouncyCastle.Asn1.Pkcs;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.IO;
using Org.BouncyCastle.Crypto.Signers;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;
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;
public string DigestAlgOid => digestAlgorithm.Algorithm.Id;
public Asn1Object DigestAlgParams => digestAlgorithm.Parameters?.ToAsn1Object();
public AlgorithmIdentifier EncryptionAlgorithmID => encryptionAlgorithm;
public string EncryptionAlgOid => encryptionAlgorithm.Algorithm.Id;
public Asn1Object EncryptionAlgParams => encryptionAlgorithm.Parameters?.ToAsn1Object();
public Org.BouncyCastle.Asn1.Cms.AttributeTable SignedAttributes {
get {
if (signedAttributeSet != null && signedAttributeTable == null)
signedAttributeTable = new Org.BouncyCastle.Asn1.Cms.AttributeTable(signedAttributeSet);
return signedAttributeTable;
}
}
public Org.BouncyCastle.Asn1.Cms.AttributeTable UnsignedAttributes {
get {
if (unsignedAttributeSet != null && unsignedAttributeTable == null)
unsignedAttributeTable = new Org.BouncyCastle.Asn1.Cms.AttributeTable(unsignedAttributeSet);
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 instance = Asn1OctetString.GetInstance(signerID.ID);
sid.SubjectKeyIdentifier = instance.GetEncoded("DER");
} else {
Org.BouncyCastle.Asn1.Cms.IssuerAndSerialNumber instance2 = Org.BouncyCastle.Asn1.Cms.IssuerAndSerialNumber.GetInstance(signerID.ID);
sid.Issuer = instance2.Name;
sid.SerialNumber = instance2.SerialNumber.Value;
}
} catch (IOException) {
throw new ArgumentException("invalid sid in SignerInfo");
}
digestAlgorithm = info.DigestAlgorithm;
signedAttributeSet = info.AuthenticatedAttributes;
unsignedAttributeSet = info.UnauthenticatedAttributes;
encryptionAlgorithm = info.DigestEncryptionAlgorithm;
signature = (byte[])info.EncryptedDigest.GetOctets().Clone();
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.AuthenticatedAttributes;
unsignedAttributeSet = info.UnauthenticatedAttributes;
encryptionAlgorithm = info.DigestEncryptionAlgorithm;
signature = (byte[])info.EncryptedDigest.GetOctets().Clone();
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();
}
public byte[] GetSignature()
{
return (byte[])signature.Clone();
}
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 (Asn1Encodable item2 in attrValues) {
Org.BouncyCastle.Asn1.Cms.SignerInfo instance = Org.BouncyCastle.Asn1.Cms.SignerInfo.GetInstance(item2.ToAsn1Object());
byte[] array = DigestUtilities.DoFinal(CmsSignedHelper.GetDigestInstance(CmsSignedHelper.GetDigestAlgName(instance.DigestAlgorithm.Algorithm)), GetSignature());
list.Add(new SignerInformation(instance, null, null, array));
}
}
return new SignerInformationStore(list);
}
public virtual byte[] GetEncodedSignedAttributes()
{
return signedAttributeSet?.GetEncoded("DER");
}
private bool DoVerify(AsymmetricKeyParameter publicKey)
{
DerObjectIdentifier algorithm = encryptionAlgorithm.Algorithm;
Asn1Encodable parameters = encryptionAlgorithm.Parameters;
string digestAlgName = CmsSignedHelper.GetDigestAlgName(algorithm);
if (digestAlgName.Equals(algorithm.Id))
digestAlgName = CmsSignedHelper.GetDigestAlgName(digestAlgorithm.Algorithm);
IDigest digestInstance = CmsSignedHelper.GetDigestInstance(digestAlgName);
ISigner signer;
if (PkcsObjectIdentifiers.IdRsassaPss.Equals(algorithm)) {
if (parameters == null)
throw new CmsException("RSASSA-PSS signature must specify algorithm parameters");
try {
RsassaPssParameters instance = RsassaPssParameters.GetInstance(parameters.ToAsn1Object());
if (!instance.HashAlgorithm.Algorithm.Equals(digestAlgorithm.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(instance.HashAlgorithm.Algorithm);
int intValueExact = instance.SaltLength.IntValueExact;
if (!RsassaPssParameters.DefaultTrailerField.Equals(instance.TrailerField))
throw new CmsException("RSASSA-PSS signature parameters must have trailerField of 1");
IAsymmetricBlockCipher cipher = new RsaBlindedEngine();
signer = ((signedAttributeSet != null || calculatedDigest == null) ? new PssSigner(cipher, digest, intValueExact) : PssSigner.CreateRawSigner(cipher, digest, digest, intValueExact, 188));
} catch (Exception innerException) {
throw new CmsException("failed to set RSASSA-PSS signature parameters", innerException);
}
} else
signer = CmsSignedHelper.GetSignatureInstance(digestAlgName + "with" + CmsSignedHelper.GetEncryptionAlgName(algorithm));
try {
if (calculatedDigest != null)
resultDigest = calculatedDigest;
else {
if (content != null)
content.Write(new DigestSink(digestInstance));
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 {
signer.Init(false, publicKey);
if (signedAttributeSet == null) {
if (calculatedDigest != null) {
if (!(signer is PssSigner))
return VerifyDigest(resultDigest, publicKey, GetSignature());
signer.BlockUpdate(resultDigest, 0, resultDigest.Length);
} else if (content != null) {
try {
content.Write(new SignerSink(signer));
} catch (SignatureException ex) {
throw new CmsStreamException("signature problem: " + ex?.ToString());
}
}
} else {
byte[] encodedSignedAttributes = GetEncodedSignedAttributes();
signer.BlockUpdate(encodedSignedAttributes, 0, encodedSignedAttributes.Length);
}
return signer.VerifySignature(GetSignature());
} 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 ex2) {
throw new CmsException("invalid signature format in message: " + ex2.Message, ex2);
}
}
throw new CmsException("A countersignature attribute MUST NOT be a signed attribute");
}
private bool IsNull(Asn1Encodable o)
{
if (!(o is Asn1Null))
return o == null;
return true;
}
private DigestInfo DerDecode(byte[] encoding)
{
if (encoding[0] != 48)
throw new IOException("not a digest info object");
DigestInfo instance = DigestInfo.GetInstance(Asn1Object.FromByteArray(encoding));
if (instance.GetEncoded().Length != encoding.Length)
throw new CmsException("malformed RSA signature");
return instance;
}
private bool VerifyDigest(byte[] digest, AsymmetricKeyParameter publicKey, byte[] signature)
{
string encryptionAlgName = CmsSignedHelper.GetEncryptionAlgName(encryptionAlgorithm.Algorithm);
try {
if (!encryptionAlgName.Equals("RSA")) {
if (!encryptionAlgName.Equals("DSA"))
throw new CmsException("algorithm: " + encryptionAlgName + " not supported in base signatures.");
ISigner signatureInstance = CmsSignedHelper.GetSignatureInstance("NONEwithDSA");
signatureInstance.Init(false, publicKey);
signatureInstance.BlockUpdate(digest, 0, digest.Length);
return signatureInstance.VerifySignature(signature);
}
IBufferedCipher cipher = CipherUtilities.GetCipher(PkcsObjectIdentifiers.RsaEncryption);
cipher.Init(false, publicKey);
byte[] encoding = cipher.DoFinal(signature);
DigestInfo digestInfo = DerDecode(encoding);
if (digestInfo.AlgorithmID.Algorithm.Equals(digestAlgorithm.Algorithm)) {
if (IsNull(digestInfo.AlgorithmID.Parameters)) {
byte[] digest2 = digestInfo.GetDigest();
return Arrays.FixedTimeEquals(digest, digest2);
}
return false;
}
return false;
} catch (SecurityUtilityException) {
throw;
} catch (GeneralSecurityException ex2) {
throw new CmsException("Exception processing signature: " + ex2?.ToString(), ex2);
} catch (IOException ex3) {
throw new CmsException("Exception decoding signature: " + ex3?.ToString(), ex3);
}
}
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());
}
public Org.BouncyCastle.Asn1.Cms.SignerInfo ToSignerInfo()
{
return info;
}
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)
{
Org.BouncyCastle.Asn1.Cms.SignerInfo signerInfo = signerInformation.info;
Asn1Set unauthenticatedAttributes = null;
if (unsignedAttributes != null)
unauthenticatedAttributes = DerSet.FromVector(unsignedAttributes.ToAsn1EncodableVector());
return new SignerInformation(new Org.BouncyCastle.Asn1.Cms.SignerInfo(signerInfo.SignerID, signerInfo.DigestAlgorithm, signerInfo.AuthenticatedAttributes, signerInfo.DigestEncryptionAlgorithm, signerInfo.EncryptedDigest, unauthenticatedAttributes), signerInformation.contentType, signerInformation.content, null);
}
public static SignerInformation AddCounterSigners(SignerInformation signerInformation, SignerInformationStore counterSigners)
{
Org.BouncyCastle.Asn1.Cms.SignerInfo signerInfo = signerInformation.info;
Org.BouncyCastle.Asn1.Cms.AttributeTable unsignedAttributes = signerInformation.UnsignedAttributes;
Asn1EncodableVector asn1EncodableVector = (unsignedAttributes == null) ? new Asn1EncodableVector(1) : unsignedAttributes.ToAsn1EncodableVector();
IList<SignerInformation> signers = counterSigners.GetSigners();
Asn1EncodableVector asn1EncodableVector2 = new Asn1EncodableVector(signers.Count);
foreach (SignerInformation item in signers) {
asn1EncodableVector2.Add(item.ToSignerInfo());
}
asn1EncodableVector.Add(new Org.BouncyCastle.Asn1.Cms.Attribute(CmsAttributes.CounterSignature, DerSet.FromVector(asn1EncodableVector2)));
return new SignerInformation(new Org.BouncyCastle.Asn1.Cms.SignerInfo(signerInfo.SignerID, signerInfo.DigestAlgorithm, signerInfo.AuthenticatedAttributes, signerInfo.DigestEncryptionAlgorithm, signerInfo.EncryptedDigest, DerSet.FromVector(asn1EncodableVector)), signerInformation.contentType, signerInformation.content, null);
}
}
}