Beispiel #1
0
        internal SignerInfo(ref SignerInfoAsn parsedData, SignedCms ownerDocument)
        {
            Version                       = parsedData.Version;
            SignerIdentifier              = new SubjectIdentifier(parsedData.Sid);
            _digestAlgorithm              = parsedData.DigestAlgorithm.Algorithm;
            _signedAttributesMemory       = parsedData.SignedAttributes;
            _signatureAlgorithm           = parsedData.SignatureAlgorithm.Algorithm;
            _signatureAlgorithmParameters = parsedData.SignatureAlgorithm.Parameters;
            _signature                    = parsedData.SignatureValue;
            _unsignedAttributes           = parsedData.UnsignedAttributes;

            if (_signedAttributesMemory.HasValue)
            {
                SignedAttributesSet signedSet = SignedAttributesSet.Decode(
                    _signedAttributesMemory.Value,
                    AsnEncodingRules.BER);

                _signedAttributes = signedSet.SignedAttributes;
                Debug.Assert(_signedAttributes != null);
            }

            _document = ownerDocument;
        }
        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory <byte> rebind, out SignedAttributesSet decoded)
        {
            decoded = default;
            Asn1Tag        tag = reader.PeekTag();
            AsnValueReader collectionReader;

            if (tag.HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 0)))
            {
                // Decode SEQUENCE OF for SignedAttributes
                {
                    collectionReader = reader.ReadSetOf(new Asn1Tag(TagClass.ContextSpecific, 0));
                    var          tmpList = new List <AttributeAsn>();
                    AttributeAsn tmpItem;

                    while (collectionReader.HasData)
                    {
                        AttributeAsn.Decode(ref collectionReader, rebind, out tmpItem);
                        tmpList.Add(tmpItem);
                    }

                    decoded.SignedAttributes = tmpList.ToArray();
                }
            }
            else
            {
                throw new CryptographicException();
            }
        }
Beispiel #3
0
        internal SignerInfoAsn Sign(
            ReadOnlyMemory <byte> data,
            string?contentTypeOid,
            bool silent,
            out X509Certificate2Collection chainCerts)
        {
            HashAlgorithmName hashAlgorithmName = PkcsHelpers.GetDigestAlgorithm(SigningPolicy.DigestAlgorithmOID);
            IncrementalHash   hasher            = IncrementalHash.CreateHash(hashAlgorithmName);

            hasher.AppendData(data.Span);
            byte[] dataHash = hasher.GetHashAndReset();

            SignerInfoAsn newSignerInfo = default;

            newSignerInfo.DigestAlgorithm.Algorithm  = new Oid(SigningPolicy.DigestAlgorithmOID);
            newSignerInfo.DigestAlgorithm.Parameters = SigningPolicy.DigestAlgorithmParameters;

            // If the user specified attributes (not null, count > 0) we need attributes.
            // If the content type is null we're counter-signing, and need the message digest attr.
            // If the content type is otherwise not-data we need to record it as the content-type attr.
            if (SignedAttributes?.Count > 0 || contentTypeOid != Oids.Pkcs7Data)
            {
                List <AttributeAsn> signedAttrs = BuildAttributes(SignedAttributes);
                using (var writer = new AsnWriter(AsnEncodingRules.DER))
                {
                    writer.WriteOctetString(dataHash);
                    signedAttrs.Add(
                        new AttributeAsn
                    {
                        AttrType   = new Oid(Oids.MessageDigest, Oids.MessageDigest),
                        AttrValues = new[] { new ReadOnlyMemory <byte>(writer.Encode()) },
                    });
                }

                if (contentTypeOid != null)
                {
                    using (var writer = new AsnWriter(AsnEncodingRules.DER))
                    {
                        writer.WriteObjectIdentifier(contentTypeOid);
                        signedAttrs.Add(
                            new AttributeAsn
                        {
                            AttrType   = new Oid(Oids.ContentType, Oids.ContentType),
                            AttrValues = new[] { new ReadOnlyMemory <byte>(writer.Encode()) },
                        });
                    }
                }

                // Use the serializer/deserializer to DER-normalize the attribute order.
                SignedAttributesSet signedAttrsSet = default;
                signedAttrsSet.SignedAttributes = PkcsHelpers.NormalizeAttributeSet(
                    signedAttrs.ToArray(),
                    normalized => hasher.AppendData(normalized));

                // Since this contains user data in a context where BER is permitted, use BER.
                // There shouldn't be any observable difference here between BER and DER, though,
                // since the top level fields were written by NormalizeSet.
                using (AsnWriter attrsWriter = new AsnWriter(AsnEncodingRules.BER))
                {
                    signedAttrsSet.Encode(attrsWriter);
                    newSignerInfo.SignedAttributes = attrsWriter.Encode();
                }

                dataHash = hasher.GetHashAndReset();
            }

            switch (SignerIdentifierType)
            {
            case SubjectIdentifierType.IssuerAndSerialNumber:
                byte[] serial = Certificate !.GetSerialNumber();
                Array.Reverse(serial);

                newSignerInfo.Sid.IssuerAndSerialNumber = new IssuerAndSerialNumberAsn
                {
                    Issuer       = Certificate.IssuerName.RawData,
                    SerialNumber = serial,
                };

                newSignerInfo.Version = 1;
                break;

            case SubjectIdentifierType.SubjectKeyIdentifier:
                // newSignerInfo.Sid.SubjectKeyIdentifier = PkcsPal.Instance.GetSubjectKeyIdentifier(Certificate!);
                newSignerInfo.Version = 3;
                break;

            case SubjectIdentifierType.NoSignature:
                newSignerInfo.Sid.IssuerAndSerialNumber = new IssuerAndSerialNumberAsn
                {
                    Issuer       = SubjectIdentifier.DummySignerEncodedValue,
                    SerialNumber = new byte[1],
                };
                newSignerInfo.Version = 1;
                break;

            default:
                Debug.Fail($"Unresolved SignerIdentifierType value: {SignerIdentifierType}");
                throw new CryptographicException();
            }

            if (UnsignedAttributes != null && UnsignedAttributes.Count > 0)
            {
                List <AttributeAsn> attrs = BuildAttributes(UnsignedAttributes);
                newSignerInfo.UnsignedAttributes = PkcsHelpers.NormalizeAttributeSet(attrs.ToArray());
            }

            bool signed;
            Oid? signatureAlgorithm;
            ReadOnlyMemory <byte> signatureValue;

            if (SignerIdentifierType == SubjectIdentifierType.NoSignature)
            {
                signatureAlgorithm = new Oid(Oids.NoSignature, null);
                signatureValue     = dataHash;
                signed             = true;
            }
            else
            {
                signed = _signer.Sign(dataHash, hashAlgorithmName, Certificate !, PrivateKey, silent, out signatureAlgorithm, out signatureValue);
            }

            if (!signed)
            {
                throw new CryptographicException(Strings.Cryptography_Cms_CannotDetermineSignatureAlgorithm);
            }

            newSignerInfo.SignatureValue = signatureValue;
            newSignerInfo.SignatureAlgorithm.Algorithm  = new Oid(SigningPolicy.EncryptionAlgorithmOID, SigningPolicy.SignatureAlgorithmName);
            newSignerInfo.SignatureAlgorithm.Parameters = SigningPolicy.SigningParameters;
            X509Certificate2Collection certs = new X509Certificate2Collection();

            certs.AddRange(Certificates);

            if (SignerIdentifierType != SubjectIdentifierType.NoSignature)
            {
                if (IncludeOption == X509IncludeOption.EndCertOnly)
                {
                    certs.Add(Certificate !);
                }
                else if (IncludeOption != X509IncludeOption.None)
                {
                    X509Chain chain = new X509Chain();
                    chain.ChainPolicy.RevocationMode    = X509RevocationMode.NoCheck;
                    chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllFlags;

                    if (!chain.Build(Certificate !))
                    {
                        foreach (X509ChainStatus status in chain.ChainStatus)
                        {
                            if (status.Status == X509ChainStatusFlags.PartialChain)
                            {
                                throw new CryptographicException(Strings.Cryptography_Cms_IncompleteCertChain);
                            }
                        }
                    }

                    X509ChainElementCollection elements = chain.ChainElements;
                    int count = elements.Count;
                    int last  = count - 1;

                    if (last == 0)
                    {
                        // If there's always one cert treat it as EE, not root.
                        last = -1;
                    }

                    for (int i = 0; i < count; i++)
                    {
                        X509Certificate2 cert = elements[i].Certificate;

                        if (i == last &&
                            IncludeOption == X509IncludeOption.ExcludeRoot &&
                            cert.SubjectName.RawData.AsSpan().SequenceEqual(cert.IssuerName.RawData))
                        {
                            break;
                        }

                        certs.Add(cert);
                    }
                }
            }

            chainCerts = certs;
            return(newSignerInfo);
        }