in net/JetBrains.SignatureVerifier/src/Crypt/BC/SignerInformation.cs [330:552]
private bool DoVerify(
AsymmetricKeyParameter key)
{
string digestName = Helper.GetDigestAlgName(this.DigestAlgOid);
IDigest digest = Helper.GetDigestInstance(digestName);
DerObjectIdentifier sigAlgOid = this.encryptionAlgorithm.Algorithm;
Asn1Encodable sigParams = this.encryptionAlgorithm.Parameters;
ISigner sig;
if (sigAlgOid.Equals(PkcsObjectIdentifiers.IdRsassaPss))
{
// RFC 4056 2.2
// When the id-RSASSA-PSS algorithm identifier is used for a signature,
// the AlgorithmIdentifier parameters field MUST contain RSASSA-PSS-params.
if (sigParams == null)
throw new CmsException("RSASSA-PSS signature must specify algorithm parameters");
try
{
// TODO Provide abstract configuration mechanism
// (via alternate SignerUtilities.GetSigner method taking ASN.1 params)
RsassaPssParameters pss = RsassaPssParameters.GetInstance(
sigParams.ToAsn1Object());
if (!pss.HashAlgorithm.Algorithm.Equals(this.digestAlgorithm.Algorithm))
throw new CmsException("RSASSA-PSS signature parameters specified incorrect hash algorithm");
if (!pss.MaskGenAlgorithm.Algorithm.Equals(PkcsObjectIdentifiers.IdMgf1))
throw new CmsException("RSASSA-PSS signature parameters specified unknown MGF");
IDigest pssDigest = DigestUtilities.GetDigest(pss.HashAlgorithm.Algorithm);
int saltLength = pss.SaltLength.IntValueExact;
// RFC 4055 3.1
// The value MUST be 1, which represents the trailer field with hexadecimal value 0xBC
if (!RsassaPssParameters.DefaultTrailerField.Equals(pss.TrailerField))
throw new CmsException("RSASSA-PSS signature parameters must have trailerField of 1");
IAsymmetricBlockCipher rsa = new RsaBlindedEngine();
if (signedAttributeSet == null && digestCalculator != null)
{
sig = PssSigner.CreateRawSigner(rsa, pssDigest, pssDigest, saltLength, PssSigner.TrailerImplicit);
}
else
{
sig = new PssSigner(rsa, pssDigest, saltLength);
}
}
catch (Exception e)
{
throw new CmsException("failed to set RSASSA-PSS signature parameters", e);
}
}
else
{
// TODO Probably too strong a check at the moment
// if (sigParams != null)
// throw new CmsException("unrecognised signature parameters provided");
string signatureName = digestName + "with" + Helper.GetEncryptionAlgName(this.EncryptionAlgOid);
sig = Helper.GetSignatureInstance(signatureName);
//sig = Helper.GetSignatureInstance(this.EncryptionAlgOid);
//sig = SignerUtilities.GetSigner(sigAlgOid);
}
try
{
if (digestCalculator != null)
{
resultDigest = digestCalculator.GetDigest();
}
else
{
if (content != null)
{
content.Write(new DigestSink(digest));
}
else if (signedAttributeSet == null)
{
// TODO Get rid of this exception and just treat content==null as empty not missing?
throw new CmsException("data not encapsulated in signature - use detached constructor.");
}
resultDigest = DigestUtilities.DoFinal(digest);
}
}
catch (IOException e)
{
throw new CmsException("can't process mime object to create signature.", e);
}
// RFC 3852 11.1 Check the content-type attribute is correct
{
Asn1Object validContentType = GetSingleValuedSignedAttribute(
CmsAttributes.ContentType, "content-type");
if (validContentType == 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
{
/*
* We do not care !
* https://github.com/bcgit/bc-csharp/issues/312
*/
// if (isCounterSignature)
// throw new CmsException("[For counter signatures,] the signedAttributes field MUST NOT contain a content-type attribute");
//
// if (!(validContentType is DerObjectIdentifier))
// throw new CmsException("content-type attribute value not of ASN.1 type 'OBJECT IDENTIFIER'");
//
// DerObjectIdentifier signedContentType = (DerObjectIdentifier)validContentType;
//
// if (!signedContentType.Equals(contentType))
// throw new CmsException("content-type attribute value does not match eContentType");
}
}
// RFC 3852 11.2 Check the message-digest attribute is correct
{
Asn1Object validMessageDigest = GetSingleValuedSignedAttribute(
CmsAttributes.MessageDigest, "message-digest");
if (validMessageDigest == null)
{
if (signedAttributeSet != null)
throw new CmsException(
"the message-digest signed attribute type MUST be present when there are any signed attributes present");
}
else
{
if (!(validMessageDigest is Asn1OctetString))
{
throw new CmsException("message-digest attribute value not of ASN.1 type 'OCTET STRING'");
}
Asn1OctetString signedMessageDigest = (Asn1OctetString)validMessageDigest;
if (!Arrays.AreEqual(resultDigest, signedMessageDigest.GetOctets()))
throw new CmsException("message-digest attribute value does not match calculated value");
}
}
// RFC 3852 11.4 Validate countersignature attribute(s)
{
AttributeTable signedAttrTable = this.SignedAttributes;
if (signedAttrTable != null
&& signedAttrTable.GetAll(CmsAttributes.CounterSignature).Count > 0)
{
throw new CmsException("A countersignature attribute MUST NOT be a signed attribute");
}
AttributeTable unsignedAttrTable = this.UnsignedAttributes;
if (unsignedAttrTable != null)
{
foreach (Attribute csAttr in unsignedAttrTable.GetAll(CmsAttributes.CounterSignature))
{
if (csAttr.AttrValues.Count < 1)
throw new CmsException("A countersignature attribute MUST contain at least one AttributeValue");
// Note: We don't recursively validate the countersignature value
}
}
}
try
{
sig.Init(false, key);
if (signedAttributeSet == null)
{
if (digestCalculator != null)
{
if (sig is PssSigner)
{
sig.BlockUpdate(resultDigest, 0, resultDigest.Length);
}
else
{
// need to decrypt signature and check message bytes
return VerifyDigest(resultDigest, key, this.GetSignature());
}
}
else if (content != null)
{
try
{
// TODO Use raw signature of the hash value instead
content.Write(new SignerSink(sig));
}
catch (SignatureException e)
{
throw new CmsStreamException("signature problem: " + e);
}
}
}
else
{
byte[] tmp = this.GetEncodedSignedAttributes();
sig.BlockUpdate(tmp, 0, tmp.Length);
}
return sig.VerifySignature(this.GetSignature());
}
catch (InvalidKeyException e)
{
throw new CmsException("key not appropriate to signature in message.", e);
}
catch (IOException e)
{
throw new CmsException("can't process mime object to create signature.", e);
}
catch (SignatureException e)
{
throw new CmsException("invalid signature format in message: " + e.Message, e);
}
}