diff options
Diffstat (limited to 'crypto/src/asn1/cms/SignedData.cs')
-rw-r--r-- | crypto/src/asn1/cms/SignedData.cs | 354 |
1 files changed, 148 insertions, 206 deletions
diff --git a/crypto/src/asn1/cms/SignedData.cs b/crypto/src/asn1/cms/SignedData.cs index 380305c32..4ceb0155b 100644 --- a/crypto/src/asn1/cms/SignedData.cs +++ b/crypto/src/asn1/cms/SignedData.cs @@ -22,213 +22,56 @@ namespace Org.BouncyCastle.Asn1.Cms return new SignedData(Asn1Sequence.GetInstance(taggedObject, declaredExplicit)); } - private static readonly DerInteger Version1 = DerInteger.One; - private static readonly DerInteger Version3 = DerInteger.Three; - private static readonly DerInteger Version4 = DerInteger.Four; - private static readonly DerInteger Version5 = DerInteger.Five; - - private readonly DerInteger version; - private readonly Asn1Set digestAlgorithms; - private readonly ContentInfo contentInfo; - private readonly Asn1Set certificates; - private readonly Asn1Set crls; - private readonly Asn1Set signerInfos; - private readonly bool certsBer; - private readonly bool crlsBer; - - public SignedData( - Asn1Set digestAlgorithms, - ContentInfo contentInfo, - Asn1Set certificates, - Asn1Set crls, - Asn1Set signerInfos) + private readonly DerInteger m_version; + private readonly Asn1Set m_digestAlgorithms; + private readonly ContentInfo m_contentInfo; + private readonly Asn1Set m_certificates; + private readonly Asn1Set m_crls; + private readonly Asn1Set m_signerInfos; + private readonly bool m_certsBer; + private readonly bool m_crlsBer; + + public SignedData(Asn1Set digestAlgorithms, ContentInfo contentInfo, Asn1Set certificates, Asn1Set crls, + Asn1Set signerInfos) { - this.version = CalculateVersion(contentInfo.ContentType, certificates, crls, signerInfos); - this.digestAlgorithms = digestAlgorithms; - this.contentInfo = contentInfo; - this.certificates = certificates; - this.crls = crls; - this.signerInfos = signerInfos; - this.crlsBer = crls is BerSet; - this.certsBer = certificates is BerSet; - } - - // RFC3852, section 5.1: - // IF ((certificates is present) AND - // (any certificates with a type of other are present)) OR - // ((crls is present) AND - // (any crls with a type of other are present)) - // THEN version MUST be 5 - // ELSE - // IF (certificates is present) AND - // (any version 2 attribute certificates are present) - // THEN version MUST be 4 - // ELSE - // IF ((certificates is present) AND - // (any version 1 attribute certificates are present)) OR - // (any SignerInfo structures are version 3) OR - // (encapContentInfo eContentType is other than id-data) - // THEN version MUST be 3 - // ELSE version MUST be 1 - // - private DerInteger CalculateVersion( - DerObjectIdentifier contentOid, - Asn1Set certs, - Asn1Set crls, - Asn1Set signerInfs) - { - bool otherCert = false; - bool otherCrl = false; - bool attrCertV1Found = false; - bool attrCertV2Found = false; - - if (certs != null) - { - foreach (object obj in certs) - { - if (obj is Asn1TaggedObject tagged) - { - if (tagged.TagNo == 1) - { - attrCertV1Found = true; - } - else if (tagged.TagNo == 2) - { - attrCertV2Found = true; - } - else if (tagged.TagNo == 3) - { - otherCert = true; - break; - } - } - } - } - - if (otherCert) - { - return Version5; - } - - if (crls != null) - { - foreach (object obj in crls) - { - if (obj is Asn1TaggedObject) - { - otherCrl = true; - break; - } - } - } - - if (otherCrl) - { - return Version5; - } - - if (attrCertV2Found) - { - return Version4; - } - - if (attrCertV1Found || !CmsObjectIdentifiers.Data.Equals(contentOid) || CheckForVersion3(signerInfs)) - { - return Version3; - } - - return Version1; - } - - private bool CheckForVersion3(Asn1Set signerInfs) - { - foreach (object obj in signerInfs) - { - SignerInfo s = SignerInfo.GetInstance(obj); - - if (s.Version.HasValue(3)) - { - return true; - } - } - - return false; + m_digestAlgorithms = digestAlgorithms ?? throw new ArgumentNullException(nameof(digestAlgorithms)); + m_contentInfo = contentInfo ?? throw new ArgumentNullException(nameof(contentInfo)); + m_certificates = certificates; + m_crls = crls; + m_signerInfos = signerInfos ?? throw new ArgumentNullException(nameof(signerInfos)); + m_crlsBer = crls is BerSet; + m_certsBer = certificates is BerSet; + m_version = CalculateVersionField(contentInfo.ContentType, certificates, crls, signerInfos); } private SignedData(Asn1Sequence seq) { - var e = seq.GetEnumerator(); - - e.MoveNext(); - version = (DerInteger)e.Current; - - e.MoveNext(); - digestAlgorithms = (Asn1Set)e.Current.ToAsn1Object(); - - e.MoveNext(); - contentInfo = ContentInfo.GetInstance(e.Current.ToAsn1Object()); - - while (e.MoveNext()) - { - Asn1Object o = e.Current.ToAsn1Object(); - - // - // an interesting feature of SignedData is that there appear - // to be varying implementations... - // for the moment we ignore anything which doesn't fit. - // - if (o is Asn1TaggedObject tagged) - { - switch (tagged.TagNo) - { - case 0: - certsBer = tagged is BerTaggedObject; - certificates = Asn1Set.GetInstance(tagged, false); - break; - case 1: - crlsBer = tagged is BerTaggedObject; - crls = Asn1Set.GetInstance(tagged, false); - break; - default: - throw new ArgumentException("unknown tag value " + tagged.TagNo); - } - } - else - { - signerInfos = (Asn1Set) o; - } - } + int count = seq.Count, pos = 0; + if (count < 4 || count > 6) + throw new ArgumentException("Bad sequence size: " + count, nameof(seq)); + + m_version = DerInteger.GetInstance(seq[pos++]); + m_digestAlgorithms = Asn1Set.GetInstance(seq[pos++]); + m_contentInfo = ContentInfo.GetInstance(seq[pos++]); + m_certificates = ReadOptionalTaggedSet(seq, ref pos, 0, out m_certsBer); + m_crls = ReadOptionalTaggedSet(seq, ref pos, 1, out m_crlsBer); + m_signerInfos = Asn1Set.GetInstance(seq[pos++]); + + if (pos != count) + throw new ArgumentException("Unexpected elements in sequence", nameof(seq)); } - public DerInteger Version - { - get { return version; } - } + public DerInteger Version => m_version; - public Asn1Set DigestAlgorithms - { - get { return digestAlgorithms; } - } + public Asn1Set DigestAlgorithms => m_digestAlgorithms; - public ContentInfo EncapContentInfo - { - get { return contentInfo; } - } + public ContentInfo EncapContentInfo => m_contentInfo; - public Asn1Set Certificates - { - get { return certificates; } - } + public Asn1Set Certificates => m_certificates; - public Asn1Set CRLs - { - get { return crls; } - } + public Asn1Set CRLs => m_crls; - public Asn1Set SignerInfos - { - get { return signerInfos; } - } + public Asn1Set SignerInfos => m_signerInfos; /** * Produce an object suitable for an Asn1OutputStream. @@ -245,36 +88,135 @@ namespace Org.BouncyCastle.Asn1.Cms */ public override Asn1Object ToAsn1Object() { - Asn1EncodableVector v = new Asn1EncodableVector( - version, digestAlgorithms, contentInfo); + Asn1EncodableVector v = new Asn1EncodableVector(6); + v.Add(m_version, m_digestAlgorithms, m_contentInfo); - if (certificates != null) + if (m_certificates != null) { - if (certsBer) + if (m_certsBer) { - v.Add(new BerTaggedObject(false, 0, certificates)); + v.Add(new BerTaggedObject(false, 0, m_certificates)); } else { - v.Add(new DerTaggedObject(false, 0, certificates)); + v.Add(new DerTaggedObject(false, 0, m_certificates)); } } - if (crls != null) + if (m_crls != null) { - if (crlsBer) + if (m_crlsBer) { - v.Add(new BerTaggedObject(false, 1, crls)); + v.Add(new BerTaggedObject(false, 1, m_crls)); } else { - v.Add(new DerTaggedObject(false, 1, crls)); + v.Add(new DerTaggedObject(false, 1, m_crls)); } } - v.Add(signerInfos); + v.Add(m_signerInfos); return new BerSequence(v); } + + private static DerInteger CalculateVersionField(DerObjectIdentifier contentOid, Asn1Set certs, Asn1Set crls, + Asn1Set signerInfs) + { + /* + * RFC3852, section 5.1: + * IF((certificates is present) AND + * (any certificates with a type of other are present)) OR + * ((crls is present) AND + * (any crls with a type of other are present)) + * THEN version MUST be 5 + * ELSE + * IF(certificates is present) AND + * (any version 2 attribute certificates are present) + * THEN version MUST be 4 + * ELSE + * IF((certificates is present) AND + * (any version 1 attribute certificates are present)) OR + * (any SignerInfo structures are version 3) OR + * (encapContentInfo eContentType is other than id - data) + * THEN version MUST be 3 + * ELSE version MUST be 1 + */ + + if (crls != null) + { + foreach (var element in crls) + { + var tagged = Asn1TaggedObject.GetOptional(element); + if (tagged != null) + { + // RevocationInfoChoice.other + if (tagged.HasContextTag(1)) + return DerInteger.Five; + } + } + } + + bool anyV1AttrCerts = false; + + if (certs != null) + { + bool anyV2AttrCerts = false; + + foreach (var element in certs) + { + var tagged = Asn1TaggedObject.GetOptional(element); + if (tagged != null) + { + // CertificateChoices.other + if (tagged.HasContextTag(3)) + return DerInteger.Five; + + // CertificateChoices.v2AttrCert + anyV2AttrCerts = anyV2AttrCerts || tagged.HasContextTag(2); + + // CertificateChoices.v1AttrCert + anyV1AttrCerts = anyV1AttrCerts || tagged.HasContextTag(1); + } + } + + if (anyV2AttrCerts) + return DerInteger.Four; + } + + if (anyV1AttrCerts || !CmsObjectIdentifiers.Data.Equals(contentOid) || HasV3SignerInfos(signerInfs)) + return DerInteger.Three; + + return DerInteger.One; + } + + // (any SignerInfo structures are version 3) + private static bool HasV3SignerInfos(Asn1Set signerInfs) + { + foreach (object obj in signerInfs) + { + var signerInfo = SignerInfo.GetInstance(obj); + if (signerInfo.Version.HasValue(3)) + return true; + } + return false; + } + + private static Asn1Set ReadOptionalTaggedSet(Asn1Sequence sequence, ref int sequencePosition, int tagNo, + out bool isBer) + { + if (sequencePosition < sequence.Count && + sequence[sequencePosition] is Asn1TaggedObject taggedObject && + taggedObject.HasContextTag(tagNo)) + { + var result = Asn1Set.GetInstance(taggedObject, false); + sequencePosition++; + isBer = taggedObject is BerTaggedObject; + return result; + } + + isBer = default; + return null; + } } } |