Пример #1
0
 internal abstract void WriteString(AsnWriter writer, string s);
Пример #2
0
 internal override void WriteString(AsnWriter writer, Asn1Tag tag, string s) =>
 writer.WriteCharacterString(tag, UniversalTagNumber.BMPString, s);
Пример #3
0
        internal void Encode(AsnWriter writer, Asn1Tag tag)
        {
            writer.PushSequence(tag);


            // DEFAULT value handler for Version.
            {
                using (AsnWriter tmp = new AsnWriter(AsnEncodingRules.DER))
                {
                    tmp.WriteInteger(Version);
                    ReadOnlySpan <byte> encoded = tmp.EncodeAsSpan();

                    if (!encoded.SequenceEqual(DefaultVersion))
                    {
                        writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
                        writer.WriteEncodedValue(encoded);
                        writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
                    }
                }
            }

            writer.WriteInteger(SerialNumber.Span);
            SignatureAlgorithm.Encode(writer);
            // Validator for tag constraint for Issuer
            {
                if (!Asn1Tag.TryDecode(Issuer.Span, out Asn1Tag validateTag, out _) ||
                    !validateTag.HasSameClassAndValue(new Asn1Tag((UniversalTagNumber)16)))
                {
                    throw new CryptographicException();
                }
            }

            writer.WriteEncodedValue(Issuer.Span);
            Validity.Encode(writer);
            // Validator for tag constraint for Subject
            {
                if (!Asn1Tag.TryDecode(Subject.Span, out Asn1Tag validateTag, out _) ||
                    !validateTag.HasSameClassAndValue(new Asn1Tag((UniversalTagNumber)16)))
                {
                    throw new CryptographicException();
                }
            }

            writer.WriteEncodedValue(Subject.Span);
            SubjectPublicKeyInfo.Encode(writer);

            if (IssuerUniqueId.HasValue)
            {
                writer.WriteBitString(new Asn1Tag(TagClass.ContextSpecific, 1), IssuerUniqueId.Value.Span);
            }


            if (SubjectUniqueId.HasValue)
            {
                writer.WriteBitString(new Asn1Tag(TagClass.ContextSpecific, 2), SubjectUniqueId.Value.Span);
            }


            if (Extensions != null)
            {
                writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 3));

                writer.PushSequence();
                for (int i = 0; i < Extensions.Length; i++)
                {
                    Extensions[i].Encode(writer);
                }
                writer.PopSequence();

                writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 3));
            }

            writer.PopSequence(tag);
        }
Пример #4
0
        internal SignerInfoAsn Sign(
            ReadOnlyMemory <byte> data,
            string contentTypeOid,
            bool silent,
            out X509Certificate2Collection chainCerts)
        {
            HashAlgorithmName hashAlgorithmName = Helpers.GetDigestAlgorithm(DigestAlgorithm);
            IncrementalHash   hasher            = IncrementalHash.CreateHash(hashAlgorithmName);

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

            SignerInfoAsn newSignerInfo = new SignerInfoAsn();

            newSignerInfo.DigestAlgorithm.Algorithm = DigestAlgorithm;

            // 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.PushSetOf();
                    writer.WriteOctetString(dataHash);
                    writer.PopSetOf();

                    signedAttrs.Add(
                        new AttributeAsn
                    {
                        AttrType   = new Oid(Oids.MessageDigest, Oids.MessageDigest),
                        AttrValues = writer.Encode(),
                    });
                }

                if (contentTypeOid != null)
                {
                    using (var writer = new AsnWriter(AsnEncodingRules.DER))
                    {
                        writer.PushSetOf();
                        writer.WriteObjectIdentifier(contentTypeOid);
                        writer.PopSetOf();

                        signedAttrs.Add(
                            new AttributeAsn
                        {
                            AttrType   = new Oid(Oids.ContentType, Oids.ContentType),
                            AttrValues = writer.Encode(),
                        });
                    }
                }

                // Use the serializer/deserializer to DER-normalize the attribute order.
                SignedAttributesSet signedAttrsSet = new SignedAttributesSet();
                signedAttrsSet.SignedAttributes = Helpers.NormalizeSet(
                    signedAttrs.ToArray(),
                    normalized =>
                {
                    AsnReader reader = new AsnReader(normalized, AsnEncodingRules.DER);
                    hasher.AppendData(reader.PeekContentBytes().Span);
                });

                // 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 = AsnSerializer.Serialize(signedAttrsSet, AsnEncodingRules.BER))
                {
                    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 = Certificate.GetSubjectKeyIdentifier();
                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 = Helpers.NormalizeSet(attrs.ToArray());
            }

            bool signed = CmsSignature.Sign(
                dataHash,
                hashAlgorithmName,
                Certificate,
                PrivateKey,
                silent,
                out Oid signatureAlgorithm,
                out ReadOnlyMemory <byte> signatureValue);

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

            newSignerInfo.SignatureValue = signatureValue;
            newSignerInfo.SignatureAlgorithm.Algorithm = signatureAlgorithm;

            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(SR.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);
        }
Пример #5
0
 internal override void WriteString(AsnWriter writer, string s) =>
 writer.WriteCharacterString(UniversalTagNumber.UTF8String, s);
        internal void Encode(AsnWriter writer, Asn1Tag tag)
        {
            writer.PushSequence(tag);

            writer.WriteInteger(Version);
            try
            {
                writer.WriteObjectIdentifier(Policy);
            }
            catch (ArgumentException e)
            {
                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e);
            }
            MessageImprint.Encode(writer);
            writer.WriteInteger(SerialNumber.Span);
            writer.WriteGeneralizedTime(GenTime, false);

            if (Accuracy.HasValue)
            {
                Accuracy.Value.Encode(writer);
            }


            // DEFAULT value handler for Ordering.
            {
                AsnWriter tmp = new AsnWriter(AsnEncodingRules.DER);
                tmp.WriteBoolean(Ordering);

                if (!tmp.EncodedValueEquals(DefaultOrdering))
                {
                    tmp.CopyTo(writer);
                }
            }


            if (Nonce.HasValue)
            {
                writer.WriteInteger(Nonce.Value.Span);
            }


            if (Tsa.HasValue)
            {
                writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
                Tsa.Value.Encode(writer);
                writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
            }


            if (Extensions != null)
            {
                writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 1));
                for (int i = 0; i < Extensions.Length; i++)
                {
                    Extensions[i].Encode(writer);
                }
                writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 1));
            }

            writer.PopSequence(tag);
        }
Пример #7
0
        public virtual bool TryExportRSAPublicKey(Span <byte> destination, out int bytesWritten)
        {
            AsnWriter pkcs1PublicKey = WritePkcs1PublicKey();

            return(pkcs1PublicKey.TryEncode(destination, out bytesWritten));
        }
Пример #8
0
        private static ArraySegment <byte> EncodeAuthSafe(
            AsnWriter tmpWriter,
            ReadOnlyMemory <byte> encodedKeyContents,
            ReadOnlyMemory <byte> encodedCertContents,
            bool isPkcs12,
            string hmacOid,
            string encryptionAlgorithmOid,
            Span <byte> salt,
            Span <byte> certContentsIv)
        {
            Debug.Assert(tmpWriter.GetEncodedLength() == 0);

            tmpWriter.PushSequence();

            if (!encodedKeyContents.IsEmpty)
            {
                tmpWriter.PushSequence();
                tmpWriter.WriteObjectIdentifier(Oids.Pkcs7Data);
                tmpWriter.PushSequence(s_contextSpecific0);

                ReadOnlySpan <byte> keyContents = encodedKeyContents.Span;
                tmpWriter.WriteOctetString(keyContents);

                tmpWriter.PopSequence(s_contextSpecific0);
                tmpWriter.PopSequence();
            }

            if (!encodedCertContents.IsEmpty)
            {
                tmpWriter.PushSequence();

                {
                    tmpWriter.WriteObjectIdentifier(Oids.Pkcs7Encrypted);

                    tmpWriter.PushSequence(s_contextSpecific0);
                    tmpWriter.PushSequence();

                    {
                        // No unprotected attributes: version 0 data
                        tmpWriter.WriteInteger(0);

                        tmpWriter.PushSequence();

                        {
                            tmpWriter.WriteObjectIdentifier(Oids.Pkcs7Data);

                            PasswordBasedEncryption.WritePbeAlgorithmIdentifier(
                                tmpWriter,
                                isPkcs12,
                                encryptionAlgorithmOid,
                                salt,
                                s_windowsPbe.IterationCount,
                                hmacOid,
                                certContentsIv);

                            tmpWriter.WriteOctetString(encodedCertContents.Span, s_contextSpecific0);
                            tmpWriter.PopSequence();
                        }

                        tmpWriter.PopSequence();
                        tmpWriter.PopSequence(s_contextSpecific0);
                    }

                    tmpWriter.PopSequence();
                }
            }

            tmpWriter.PopSequence();

            int authSafeLength = tmpWriter.GetEncodedLength();

            byte[] authSafe = CryptoPool.Rent(authSafeLength);

            if (!tmpWriter.TryEncode(authSafe, out authSafeLength))
            {
                Debug.Fail("TryEncode failed with a pre-allocated buffer");
                throw new InvalidOperationException();
            }

            tmpWriter.Reset();

            return(new ArraySegment <byte>(authSafe, 0, authSafeLength));
        }
Пример #9
0
        private static unsafe byte[] MacAndEncode(
            AsnWriter tmpWriter,
            ReadOnlyMemory <byte> encodedAuthSafe,
            ReadOnlySpan <char> passwordSpan)
        {
            Span <byte> macKey  = stackalloc byte[HMACSHA1.HashSizeInBytes];
            Span <byte> macSalt = stackalloc byte[HMACSHA1.HashSizeInBytes];
            Span <byte> macSpan = stackalloc byte[HMACSHA1.HashSizeInBytes];

            RandomNumberGenerator.Fill(macSalt);

            Pkcs12Kdf.DeriveMacKey(
                passwordSpan,
                HashAlgorithmName.SHA1,
                s_windowsPbe.IterationCount,
                macSalt,
                macKey);

            int bytesWritten = HMACSHA1.HashData(macKey, encodedAuthSafe.Span, macSpan);

            if (bytesWritten != HMACSHA1.HashSizeInBytes)
            {
                Debug.Fail($"HMACSHA1.HashData wrote {bytesWritten} of {HMACSHA1.HashSizeInBytes} bytes");
                throw new CryptographicException();
            }

            CryptographicOperations.ZeroMemory(macKey);

            // https://tools.ietf.org/html/rfc7292#section-4
            //
            // PFX ::= SEQUENCE {
            //   version    INTEGER {v3(3)}(v3,...),
            //   authSafe   ContentInfo,
            //   macData    MacData OPTIONAL
            // }
            Debug.Assert(tmpWriter.GetEncodedLength() == 0);
            tmpWriter.PushSequence();

            tmpWriter.WriteInteger(3);

            tmpWriter.PushSequence();
            {
                tmpWriter.WriteObjectIdentifier(Oids.Pkcs7Data);

                tmpWriter.PushSequence(s_contextSpecific0);
                {
                    tmpWriter.WriteOctetString(encodedAuthSafe.Span);
                    tmpWriter.PopSequence(s_contextSpecific0);
                }

                tmpWriter.PopSequence();
            }

            // https://tools.ietf.org/html/rfc7292#section-4
            //
            // MacData ::= SEQUENCE {
            //   mac        DigestInfo,
            //   macSalt    OCTET STRING,
            //   iterations INTEGER DEFAULT 1
            //   -- Note: The default is for historical reasons and its use is
            //   -- deprecated.
            // }
            tmpWriter.PushSequence();
            {
                tmpWriter.PushSequence();
                {
                    tmpWriter.PushSequence();
                    {
                        tmpWriter.WriteObjectIdentifier(Oids.Sha1);
                        tmpWriter.PopSequence();
                    }

                    tmpWriter.WriteOctetString(macSpan);
                    tmpWriter.PopSequence();
                }

                tmpWriter.WriteOctetString(macSalt);
                tmpWriter.WriteInteger(s_windowsPbe.IterationCount);

                tmpWriter.PopSequence();
            }

            tmpWriter.PopSequence();
            return(tmpWriter.Encode());
        }
Пример #10
0
        private static unsafe ArraySegment <byte> EncodeAuthSafe(
            AsnWriter tmpWriter,
            SafeBagAsn[] keyBags,
            int keyCount,
            CertBagAsn[] certBags,
            AttributeAsn[] certAttrs,
            int certIdx,
            ReadOnlySpan <char> passwordSpan)
        {
            string?encryptionAlgorithmOid  = null;
            bool   certsIsPkcs12Encryption = false;
            string?certsHmacOid            = null;

            ArraySegment <byte> encodedKeyContents  = default;
            ArraySegment <byte> encodedCertContents = default;

            try
            {
                if (keyCount > 0)
                {
                    encodedKeyContents = EncodeKeys(tmpWriter, keyBags, keyCount);
                }

                Span <byte> salt = stackalloc byte[16];
                RandomNumberGenerator.Fill(salt);
                Span <byte> certContentsIv = stackalloc byte[8];

                if (certIdx > 0)
                {
                    encodedCertContents = EncodeCerts(
                        tmpWriter,
                        certBags,
                        certAttrs,
                        certIdx,
                        salt,
                        passwordSpan,
                        certContentsIv,
                        out certsHmacOid,
                        out encryptionAlgorithmOid,
                        out certsIsPkcs12Encryption);
                }

                return(EncodeAuthSafe(
                           tmpWriter,
                           encodedKeyContents,
                           encodedCertContents,
                           certsIsPkcs12Encryption,
                           certsHmacOid !,
                           encryptionAlgorithmOid !,
                           salt,
                           certContentsIv));
            }
            finally
            {
                if (encodedCertContents.Array != null)
                {
                    CryptoPool.Return(encodedCertContents);
                }

                if (encodedKeyContents.Array != null)
                {
                    CryptoPool.Return(encodedKeyContents);
                }
            }
        }
Пример #11
0
        private static ArraySegment <byte> EncodeCerts(
            AsnWriter tmpWriter,
            CertBagAsn[] certBags,
            AttributeAsn[] certAttrs,
            int certCount,
            Span <byte> salt,
            ReadOnlySpan <char> passwordSpan,
            Span <byte> certContentsIv,
            out string hmacOid,
            out string encryptionAlgorithmOid,
            out bool isPkcs12)
        {
            Debug.Assert(tmpWriter.GetEncodedLength() == 0);
            tmpWriter.PushSequence();

            PasswordBasedEncryption.InitiateEncryption(
                s_windowsPbe,
                out SymmetricAlgorithm cipher,
                out hmacOid,
                out encryptionAlgorithmOid,
                out isPkcs12);

            using (cipher)
            {
                Debug.Assert(certContentsIv.Length * 8 == cipher.BlockSize);

                for (int i = certCount - 1; i >= 0; --i)
                {
                    // Manually write the SafeBagAsn
                    // https://tools.ietf.org/html/rfc7292#section-4.2
                    //
                    // SafeBag ::= SEQUENCE {
                    //   bagId          BAG-TYPE.&id ({PKCS12BagSet})
                    //   bagValue       [0] EXPLICIT BAG-TYPE.&Type({PKCS12BagSet}{@bagId}),
                    //   bagAttributes  SET OF PKCS12Attribute OPTIONAL
                    // }
                    tmpWriter.PushSequence();

                    tmpWriter.WriteObjectIdentifierForCrypto(Oids.Pkcs12CertBag);

                    tmpWriter.PushSequence(s_contextSpecific0);
                    certBags[i].Encode(tmpWriter);
                    tmpWriter.PopSequence(s_contextSpecific0);

                    if (certAttrs[i].AttrType != null)
                    {
                        tmpWriter.PushSetOf();
                        certAttrs[i].Encode(tmpWriter);
                        tmpWriter.PopSetOf();
                    }

                    tmpWriter.PopSequence();
                }

                tmpWriter.PopSequence();

                // The padding applied will add at most a block to the output,
                // so ask for contentsSpan.Length + the number of bytes in a cipher block.
                int    cipherBlockBytes = cipher.BlockSize >> 3;
                int    requestedSize    = checked (tmpWriter.GetEncodedLength() + cipherBlockBytes);
                byte[] certContents     = CryptoPool.Rent(requestedSize);

                int encryptedLength = PasswordBasedEncryption.Encrypt(
                    passwordSpan,
                    ReadOnlySpan <byte> .Empty,
                    cipher,
                    isPkcs12,
                    tmpWriter,
                    s_windowsPbe,
                    salt,
                    certContents,
                    certContentsIv);

                Debug.Assert(encryptedLength <= requestedSize);
                tmpWriter.Reset();

                return(new ArraySegment <byte>(certContents, 0, encryptedLength));
            }
        }
Пример #12
0
        protected void VerifyWrite_Span_NonEncodable(string input)
        {
            AsnWriter writer = new AsnWriter(AsnEncodingRules.BER);

            Assert.Throws <EncoderFallbackException>(() => WriteSpan(writer, input.AsReadOnlySpan()));
        }
Пример #13
0
 internal abstract void WriteSpan(AsnWriter writer, Asn1Tag tag, ReadOnlySpan <char> s);
Пример #14
0
 internal abstract void WriteString(AsnWriter writer, Asn1Tag tag, string s);
Пример #15
0
 internal void Encode(AsnWriter writer)
 {
     EncodeApplication(writer, ApplicationTag);
 }
Пример #16
0
        private byte[] ExportPfx(SafePasswordHandle password)
        {
            int certCount = 1;

            if (_singleCertPal == null)
            {
                Debug.Assert(_certs != null);
                certCount = _certs.Count;
            }

            CertBagAsn[] certBags = ArrayPool <CertBagAsn> .Shared.Rent(certCount);

            SafeBagAsn[] keyBags = ArrayPool <SafeBagAsn> .Shared.Rent(certCount);

            AttributeAsn[] certAttrs = ArrayPool <AttributeAsn> .Shared.Rent(certCount);

            certAttrs.AsSpan(0, certCount).Clear();

            AsnWriter           tmpWriter       = new AsnWriter(AsnEncodingRules.DER);
            ArraySegment <byte> encodedAuthSafe = default;

            bool gotRef = false;

            password.DangerousAddRef(ref gotRef);

            try
            {
                ReadOnlySpan <char> passwordSpan = password.DangerousGetSpan();

                int keyIdx  = 0;
                int certIdx = 0;

                if (_singleCertPal != null)
                {
                    BuildBags(
                        _singleCertPal,
                        passwordSpan,
                        tmpWriter,
                        certBags,
                        certAttrs,
                        keyBags,
                        ref certIdx,
                        ref keyIdx);
                }
                else
                {
                    foreach (X509Certificate2 cert in _certs !)
                    {
                        BuildBags(
                            cert.Pal,
                            passwordSpan,
                            tmpWriter,
                            certBags,
                            certAttrs,
                            keyBags,
                            ref certIdx,
                            ref keyIdx);
                    }
                }

                encodedAuthSafe = EncodeAuthSafe(
                    tmpWriter,
                    keyBags,
                    keyIdx,
                    certBags,
                    certAttrs,
                    certIdx,
                    passwordSpan);

                return(MacAndEncode(tmpWriter, encodedAuthSafe, passwordSpan));
            }
            finally
            {
                password.DangerousRelease();
                certAttrs.AsSpan(0, certCount).Clear();
                certBags.AsSpan(0, certCount).Clear();
                keyBags.AsSpan(0, certCount).Clear();
                ArrayPool <AttributeAsn> .Shared.Return(certAttrs);

                ArrayPool <CertBagAsn> .Shared.Return(certBags);

                ArrayPool <SafeBagAsn> .Shared.Return(keyBags);

                if (encodedAuthSafe.Array != null)
                {
                    CryptoPool.Return(encodedAuthSafe);
                }
            }
        }
Пример #17
0
        public override byte[] GetSignatureAlgorithmIdentifier(HashAlgorithmName hashAlgorithm)
        {
            // If we ever support options in PSS (like MGF-2, if such an MGF is ever invented)
            // Or, more reasonably, supporting a custom value for the salt size.
            if (_padding != RSASignaturePadding.Pss)
            {
                throw new CryptographicException(SR.Cryptography_InvalidPaddingMode);
            }

            int    cbSalt;
            string digestOid;

            if (hashAlgorithm == HashAlgorithmName.SHA256)
            {
                cbSalt    = 256 / 8;
                digestOid = Oids.Sha256;
            }
            else if (hashAlgorithm == HashAlgorithmName.SHA384)
            {
                cbSalt    = 384 / 8;
                digestOid = Oids.Sha384;
            }
            else if (hashAlgorithm == HashAlgorithmName.SHA512)
            {
                cbSalt    = 512 / 8;
                digestOid = Oids.Sha512;
            }
            else
            {
                throw new ArgumentOutOfRangeException(
                          nameof(hashAlgorithm),
                          hashAlgorithm,
                          SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithm.Name));
            }

            // RFC 5754 says that the NULL for SHA2 (256/384/512) MUST be omitted
            // (https://tools.ietf.org/html/rfc5754#section-2) (and that you MUST
            // be able to read it even if someone wrote it down)
            //
            // Since we
            //  * don't support SHA-1 in this class
            //  * only support MGF-1
            //  * don't support the MGF PRF being different than hashAlgorithm
            //  * use saltLength==hashLength
            //  * don't allow custom trailer
            // we don't have to worry about any of the DEFAULTs. (specify, specify, specify, omit).

            PssParamsAsn parameters = new PssParamsAsn
            {
                HashAlgorithm = new AlgorithmIdentifierAsn {
                    Algorithm = new Oid(digestOid)
                },
                MaskGenAlgorithm = new AlgorithmIdentifierAsn {
                    Algorithm = new Oid(Oids.Mgf1)
                },
                SaltLength   = cbSalt,
                TrailerField = 1,
            };

            using (AsnWriter mgfParamWriter = new AsnWriter(AsnEncodingRules.DER))
            {
                mgfParamWriter.PushSequence();
                mgfParamWriter.WriteObjectIdentifier(digestOid);
                mgfParamWriter.PopSequence();
                parameters.MaskGenAlgorithm.Parameters = mgfParamWriter.Encode();
            }

            using (AsnWriter parametersWriter = new AsnWriter(AsnEncodingRules.DER))
                using (AsnWriter identifierWriter = new AsnWriter(AsnEncodingRules.DER))
                {
                    parameters.Encode(parametersWriter);

                    AlgorithmIdentifierAsn identifier = new AlgorithmIdentifierAsn
                    {
                        Algorithm  = new Oid(Oids.RsaPss),
                        Parameters = parametersWriter.Encode(),
                    };

                    identifier.Encode(identifierWriter);
                    return(identifierWriter.Encode());
                }
        }
Пример #18
0
        public static void WriteAfterDispose(bool empty)
        {
            using (AsnWriter writer = new AsnWriter(AsnEncodingRules.DER))
            {
                if (!empty)
                {
                    writer.WriteNull();
                }

                writer.Dispose();

                // Type not enum
                Assert.Throws <ArgumentException>(
                    "enumType",
                    () => writer.WriteNamedBitList(false));

                // Type not enum
                Assert.Throws <ArgumentException>(
                    "enumType",
                    () => writer.WriteNamedBitList((object)"hi"));

                Assert.Throws <ArgumentNullException>(
                    "enumValue",
                    () => writer.WriteNamedBitList((object)null));

                // valid input
                Assert.Throws <ObjectDisposedException>(
                    () => writer.WriteNamedBitList(ReadNamedBitList.LongFlags.Mid));

                // Type is not [Flags]
                Assert.Throws <ArgumentException>(
                    "tEnum",
                    () => writer.WriteNamedBitList(ReadEnumerated.UIntBacked.Fluff));

                // valid input
                Assert.Throws <ObjectDisposedException>(
                    () => writer.WriteNamedBitList((object)ReadNamedBitList.ULongFlags.Mid));

                // Unboxed type is [Flags]
                Assert.Throws <ArgumentException>(
                    "tEnum",
                    () => writer.WriteNamedBitList((object)ReadEnumerated.SByteBacked.Fluff));

                Assert.Throws <ArgumentException>(
                    "tag",
                    () => writer.WriteNamedBitList(Asn1Tag.Integer, false));

                Assert.Throws <ArgumentException>(
                    "tag",
                    () => writer.WriteNamedBitList(Asn1Tag.Integer, (object)"hi"));

                Assert.Throws <ArgumentNullException>(
                    "enumValue",
                    () => writer.WriteNamedBitList(Asn1Tag.Integer, (object)null));

                Assert.Throws <ArgumentException>(
                    "tag",
                    () => writer.WriteNamedBitList(Asn1Tag.Integer, ReadNamedBitList.LongFlags.Mid));

                Assert.Throws <ArgumentException>(
                    "tag",
                    () => writer.WriteNamedBitList(Asn1Tag.Integer, ReadEnumerated.UIntBacked.Fluff));

                Assert.Throws <ArgumentException>(
                    "tag",
                    () => writer.WriteNamedBitList(Asn1Tag.Integer, (object)ReadNamedBitList.ULongFlags.Mid));

                Assert.Throws <ArgumentException>(
                    "tag",
                    () => writer.WriteNamedBitList(Asn1Tag.Integer, (object)ReadEnumerated.SByteBacked.Fluff));

                Asn1Tag tag = new Asn1Tag(TagClass.Private, 6);

                // Type not enum
                Assert.Throws <ArgumentException>(
                    "enumType",
                    () => writer.WriteNamedBitList(tag, false));

                // Type not enum
                Assert.Throws <ArgumentException>(
                    "enumType",
                    () => writer.WriteNamedBitList(tag, (object)"hi"));

                Assert.Throws <ArgumentNullException>(
                    "enumValue",
                    () => writer.WriteNamedBitList(tag, (object)null));

                // valid input
                Assert.Throws <ObjectDisposedException>(
                    () => writer.WriteNamedBitList(tag, ReadNamedBitList.LongFlags.Mid));

                // Type is [Flags]
                Assert.Throws <ArgumentException>(
                    "tEnum",
                    () => writer.WriteNamedBitList(tag, ReadEnumerated.UIntBacked.Fluff));

                // valid input
                Assert.Throws <ObjectDisposedException>(
                    () => writer.WriteNamedBitList(tag, (object)ReadNamedBitList.ULongFlags.Mid));

                // Unboxed type is not [Flags]
                Assert.Throws <ArgumentException>(
                    "tEnum",
                    () => writer.WriteNamedBitList(tag, (object)ReadEnumerated.SByteBacked.Fluff));
            }
        }
Пример #19
0
        public virtual byte[] ExportRSAPublicKey()
        {
            AsnWriter pkcs1PublicKey = WritePkcs1PublicKey();

            return(pkcs1PublicKey.Encode());
        }
Пример #20
0
        /// <summary>
        /// To DER algorithm identifier
        /// </summary>
        /// <param name="signature"></param>
        /// <returns></returns>
        public static byte[] ToAlgorithmIdentifier(this SignatureType signature)
        {
            var    hashAlgorithm = signature.ToHashAlgorithmName();
            string oid;

            if (signature.IsRSA())
            {
                var padding = signature.ToRSASignaturePadding();
                if (padding == RSASignaturePadding.Pkcs1)
                {
                    if (hashAlgorithm == HashAlgorithmName.SHA256)
                    {
                        oid = Oids.RsaPkcs1Sha256;
                    }
                    else if (hashAlgorithm == HashAlgorithmName.SHA384)
                    {
                        oid = Oids.RsaPkcs1Sha384;
                    }
                    else if (hashAlgorithm == HashAlgorithmName.SHA512)
                    {
                        oid = Oids.RsaPkcs1Sha512;
                    }
                    else
                    {
                        throw new ArgumentOutOfRangeException(nameof(hashAlgorithm),
                                                              $"The hash algorithm {hashAlgorithm.Name} is not supported.");
                    }
                    using (var writer = new AsnWriter(AsnEncodingRules.DER)) {
                        writer.PushSequence();
                        writer.WriteObjectIdentifier(oid);
                        writer.WriteNull();
                        writer.PopSequence();
                        return(writer.Encode());
                    }
                }
                if (padding == RSASignaturePadding.Pss)
                {
                    int saltLen;

                    if (hashAlgorithm == HashAlgorithmName.SHA256)
                    {
                        saltLen = 256 / 8;
                        oid     = Oids.Sha256;
                    }
                    else if (hashAlgorithm == HashAlgorithmName.SHA384)
                    {
                        saltLen = 384 / 8;
                        oid     = Oids.Sha384;
                    }
                    else if (hashAlgorithm == HashAlgorithmName.SHA512)
                    {
                        saltLen = 512 / 8;
                        oid     = Oids.Sha512;
                    }
                    else
                    {
                        throw new ArgumentOutOfRangeException(nameof(hashAlgorithm),
                                                              $"The hash algorithm {hashAlgorithm.Name} is not supported.");
                    }
                    using (var writer = new AsnWriter(AsnEncodingRules.DER)) {
                        writer.WritePssSignatureAlgorithmIdentifier(saltLen, oid);
                        return(writer.Encode());
                    }
                }
                throw new ArgumentOutOfRangeException(nameof(signature),
                                                      "Specified Padding is not supported.");
            }

            if (hashAlgorithm == HashAlgorithmName.SHA256)
            {
                oid = Oids.ECDsaWithSha256;
            }
            else if (hashAlgorithm == HashAlgorithmName.SHA384)
            {
                oid = Oids.ECDsaWithSha384;
            }
            else if (hashAlgorithm == HashAlgorithmName.SHA512)
            {
                oid = Oids.ECDsaWithSha512;
            }
            else
            {
                throw new ArgumentOutOfRangeException(nameof(hashAlgorithm),
                                                      $"The hash algorithm {hashAlgorithm.Name} is not supported.");
            }
            using (var writer = new AsnWriter(AsnEncodingRules.DER)) {
                writer.PushSequence();
                writer.WriteObjectIdentifier(oid);
                writer.PopSequence();
                return(writer.Encode());
            }
        }
Пример #21
0
        public override bool TryExportPkcs8PrivateKey(Span <byte> destination, out int bytesWritten)
        {
            AsnWriter writer = WritePkcs8PrivateKey();

            return(writer.TryEncode(destination, out bytesWritten));
        }
Пример #22
0
        public void ComputeSignature(CmsSigner signer, bool silent)
        {
            if (signer == null)
            {
                throw new ArgumentNullException(nameof(signer));
            }

            // While it shouldn't be possible to change the length of ContentInfo.Content
            // after it's built, use the property at this stage, then use the saved value
            // (if applicable) after this point.
            if (ContentInfo.Content.Length == 0)
            {
                throw new CryptographicException(SR.Cryptography_Cms_Sign_Empty_Content);
            }

            if (_hasData && signer.SignerIdentifierType == SubjectIdentifierType.NoSignature)
            {
                // Even if all signers have been removed, throw if doing a NoSignature signature
                // on a loaded (from file, or from first signature) document.
                //
                // This matches the NetFX behavior.
                throw new CryptographicException(SR.Cryptography_Cms_Sign_No_Signature_First_Signer);
            }

            if (signer.Certificate == null && signer.SignerIdentifierType != SubjectIdentifierType.NoSignature)
            {
                if (silent)
                {
                    // NetFX compatibility, silent disallows prompting, so throws InvalidOperationException
                    // in this state.
                    //
                    // The message is different than on NetFX, because the resource string was for
                    // enveloped CMS recipients (and the other site which would use that resource
                    // is unreachable code due to CmsRecipient's ctor guarding against null certificates)
                    throw new InvalidOperationException(SR.Cryptography_Cms_NoSignerCertSilent);
                }

                // Otherwise, PNSE. .NET Core doesn't support launching the cert picker UI.
                throw new PlatformNotSupportedException(SR.Cryptography_Cms_NoSignerCert);
            }

            // If we had content already, use that now.
            // (The second signer doesn't inherit edits to signedCms.ContentInfo.Content)
            ReadOnlyMemory <byte> content = _heldContent ?? ContentInfo.Content;
            string contentType            = _contentType ?? ContentInfo.ContentType.Value ?? Oids.Pkcs7Data;

            X509Certificate2Collection chainCerts;
            SignerInfoAsn newSigner   = signer.Sign(content, contentType, silent, out chainCerts);
            bool          firstSigner = false;

            if (!_hasData)
            {
                firstSigner = true;

                _signedData = new SignedDataAsn
                {
                    DigestAlgorithms = Array.Empty <AlgorithmIdentifierAsn>(),
                    SignerInfos      = Array.Empty <SignerInfoAsn>(),
                    EncapContentInfo = new EncapsulatedContentInfoAsn {
                        ContentType = contentType
                    },
                };

                // Since we're going to call Decode before this method exits we don't need to save
                // the copy of _heldContent or _contentType here if we're attached.
                if (!Detached)
                {
                    using (AsnWriter writer = new AsnWriter(AsnEncodingRules.DER))
                    {
                        writer.WriteOctetString(content.Span);

                        _signedData.EncapContentInfo.Content = writer.Encode();
                    }
                }

                _hasData = true;
            }

            int newIdx = _signedData.SignerInfos.Length;

            Array.Resize(ref _signedData.SignerInfos, newIdx + 1);
            _signedData.SignerInfos[newIdx] = newSigner;
            UpdateCertificatesFromAddition(chainCerts);
            ConsiderDigestAddition(newSigner.DigestAlgorithm);
            UpdateMetadata();

            if (firstSigner)
            {
                Reencode();

                Debug.Assert(_heldContent != null);
                Debug.Assert(_contentType == contentType);
            }
        }
 internal override void WriteString(AsnWriter writer, Asn1Tag tag, string s) =>
 writer.WriteCharacterString(UniversalTagNumber.IA5String, s, tag);
Пример #24
0
        public static void SerializeAllTheSimpleThings_CER()
        {
            const string ExpectedHex =
                "3080" +
                "0101FF" +
                "0201FE" +
                "020101" +
                "0202FEFF" +
                "02020101" +
                "0204FEFFFFFF" +
                "020401000001" +
                "0208FEFFFFFFFFFFFFFF" +
                "02080100000000000001" +
                "0209010000000000000001" +
                "0303000102" +
                "0404FF0055AA" +
                "0500" +
                "06082A8648CE3D030107" +
                "06072A8648CE3D0201" +
                "06092A864886F70D010101" +
                "0A011E" +
                "0C2544722E2026204D72732E20536D697468E280904A6F6E657320EFB9A0206368696C6472656E" +
                "162144722E2026204D72732E20536D6974682D4A6F6E65732026206368696C6472656E" +
                "1E42" +
                "00440072002E002000260020004D00720073002E00200053006D006900740068" +
                "2010004A006F006E006500730020FE600020006300680069006C006400720065" +
                "006E" +
                "3080" +
                "010100" +
                "010100" +
                "0101FF" +
                "0101FF" +
                "010100" +
                "0000" +
                "3180" +
                "020100" +
                "020101" +
                "0201FE" +
                "0201FF" +
                "02020100" +
                "0000" +
                "3080" +
                "020100" +
                "020101" +
                "020200FE" +
                "02017F" +
                "020200FF" +
                "0000" +
                "170D3530303130323132333435365A" +
                "170D3530303130323132333435365A" +
                // This is different than what we read in deserialize,
                // because we don't write back the .0004 second.
                "181332303136313130363031323334352E3736355A" +
                "180F32303136313130363031323334355A" +
                "020F0102030405060708090A0B0C0D0E0F" +
                "0000";

            const string UnicodeVerifier = "Dr. & Mrs. Smith\u2010Jones \uFE60 children";
            const string AsciiVerifier   = "Dr. & Mrs. Smith-Jones & children";

            var allTheThings = new AllTheSimpleThings
            {
                NotBool          = false,
                SByte            = -2,
                Byte             = 1,
                Short            = unchecked ((short)0xFEFF),
                UShort           = 0x0101,
                Int              = unchecked ((int)0xFEFFFFFF),
                UInt             = 0x01000001U,
                Long             = unchecked ((long)0xFEFFFFFFFFFFFFFF),
                ULong            = 0x0100000000000001UL,
                BigIntBytes      = "010000000000000001".HexToByteArray(),
                BitStringBytes   = new byte[] { 1, 2 },
                OctetStringBytes = new byte[] { 0xFF, 0, 0x55, 0xAA },
                Null             = new byte[] { 5, 0 },
                UnattrOid        = new Oid("1.2.840.10045.3.1.7", "1.2.840.10045.3.1.7"),
                WithName         = new Oid("1.2.840.10045.2.1", "ECC"),
                OidString        = "1.2.840.113549.1.1.1",
                LinearEnum       = UniversalTagNumber.BMPString,
                Utf8Encoded      = UnicodeVerifier,
                Ia5Encoded       = AsciiVerifier,
                BmpEncoded       = UnicodeVerifier,
                Bools            = new[] { false, false, true, true, false },
                Ints             = new [] { 0, 1, -2, -1, 256 },
                LittleUInts      = new byte[] { 0, 1, 254, 127, 255 },
                UtcTime2049      = new DateTimeOffset(1950, 1, 2, 12, 34, 56, TimeSpan.Zero),
                // 1950 is out of range for the reader, but the writer just does mod 100.
                UtcTime2099 = new DateTimeOffset(1950, 1, 2, 12, 34, 56, TimeSpan.Zero),
                GeneralizedTimeWithFractions = new DateTimeOffset(2016, 11, 6, 1, 23, 45, 765, TimeSpan.Zero),
                // The fractions will be dropped off by the serializer/writer, to simplify
                // the cases where the time was computed and isn't an integer number of seconds.
                GeneralizedTimeNoFractions = new DateTimeOffset(2016, 11, 6, 1, 23, 45, 765, TimeSpan.Zero),
                BigInteger = BigInteger.Parse("0102030405060708090A0B0C0D0E0F", NumberStyles.HexNumber),
            };

            using (AsnWriter writer = AsnSerializer.Serialize(allTheThings, AsnEncodingRules.CER))
            {
                Assert.Equal(ExpectedHex, writer.Encode().ByteArrayToHex());
            }
        }
Пример #25
0
 internal override void WriteSpan(AsnWriter writer, ReadOnlySpan <char> s) =>
 writer.WriteCharacterString(UniversalTagNumber.UTF8String, s);
Пример #26
0
        public void SealWithMac(
            ReadOnlySpan <char> password,
            HashAlgorithmName hashAlgorithm,
            int iterationCount)
        {
            if (iterationCount < 1)
            {
                throw new ArgumentOutOfRangeException(nameof(iterationCount));
            }
            if (IsSealed)
            {
                throw new InvalidOperationException(SR.Cryptography_Pkcs12_PfxIsSealed);
            }

            byte[]? rentedAuthSafe = null;
            Span <byte> authSafeSpan = default;

            byte[]? rentedMac = null;
            Span <byte> macSpan = default;
            Span <byte> salt    = stackalloc byte[0];

            try
            {
                AsnWriter contentsWriter = new AsnWriter(AsnEncodingRules.BER);

                using (IncrementalHash hasher = IncrementalHash.CreateHash(hashAlgorithm))
                {
                    contentsWriter.PushSequence();
                    if (_contents != null)
                    {
                        foreach (ContentInfoAsn contentInfo in _contents)
                        {
                            contentInfo.Encode(contentsWriter);
                        }
                    }
                    contentsWriter.PopSequence();

                    rentedAuthSafe = CryptoPool.Rent(contentsWriter.GetEncodedLength());

                    if (!contentsWriter.TryEncode(rentedAuthSafe, out int written))
                    {
                        Debug.Fail("TryEncode failed with a pre-allocated buffer");
                        throw new InvalidOperationException();
                    }

                    authSafeSpan = rentedAuthSafe.AsSpan(0, written);

                    // Get an array of the proper size for the hash.
                    byte[] macKey = hasher.GetHashAndReset();
                    rentedMac = CryptoPool.Rent(macKey.Length);
                    macSpan   = rentedMac.AsSpan(0, macKey.Length);

                    // Since the biggest supported hash is SHA-2-512 (64 bytes), the
                    // 128-byte cap here shouldn't ever come into play.
                    Debug.Assert(macKey.Length <= 128);
                    salt = stackalloc byte[Math.Min(macKey.Length, 128)];
                    RandomNumberGenerator.Fill(salt);

                    Pkcs12Kdf.DeriveMacKey(
                        password,
                        hashAlgorithm,
                        iterationCount,
                        salt,
                        macKey);

                    using (IncrementalHash mac = IncrementalHash.CreateHMAC(hashAlgorithm, macKey))
                    {
                        mac.AppendData(authSafeSpan);

                        if (!mac.TryGetHashAndReset(macSpan, out int bytesWritten) || bytesWritten != macSpan.Length)
                        {
                            Debug.Fail($"TryGetHashAndReset wrote {bytesWritten} of {macSpan.Length} bytes");
                            throw new CryptographicException();
                        }
                    }
                }

                // https://tools.ietf.org/html/rfc7292#section-4
                //
                // PFX ::= SEQUENCE {
                //   version    INTEGER {v3(3)}(v3,...),
                //   authSafe   ContentInfo,
                //   macData    MacData OPTIONAL
                // }
                AsnWriter writer = new AsnWriter(AsnEncodingRules.BER);
                {
                    writer.PushSequence();

                    writer.WriteInteger(3);

                    writer.PushSequence();
                    {
                        writer.WriteObjectIdentifierForCrypto(Oids.Pkcs7Data);

                        Asn1Tag contextSpecific0 = new Asn1Tag(TagClass.ContextSpecific, 0);

                        writer.PushSequence(contextSpecific0);
                        {
                            writer.WriteOctetString(authSafeSpan);
                            writer.PopSequence(contextSpecific0);
                        }

                        writer.PopSequence();
                    }

                    // https://tools.ietf.org/html/rfc7292#section-4
                    //
                    // MacData ::= SEQUENCE {
                    //   mac        DigestInfo,
                    //   macSalt    OCTET STRING,
                    //   iterations INTEGER DEFAULT 1
                    //   -- Note: The default is for historical reasons and its use is
                    //   -- deprecated.
                    // }
                    writer.PushSequence();
                    {
                        writer.PushSequence();
                        {
                            writer.PushSequence();
                            {
                                writer.WriteObjectIdentifierForCrypto(PkcsHelpers.GetOidFromHashAlgorithm(hashAlgorithm));
                                writer.PopSequence();
                            }

                            writer.WriteOctetString(macSpan);
                            writer.PopSequence();
                        }

                        writer.WriteOctetString(salt);

                        if (iterationCount > 1)
                        {
                            writer.WriteInteger(iterationCount);
                        }

                        writer.PopSequence();
                    }

                    writer.PopSequence();
                    _sealedData = writer.Encode();
                }
            }
            finally
            {
                CryptographicOperations.ZeroMemory(macSpan);
                CryptographicOperations.ZeroMemory(authSafeSpan);

                if (rentedMac != null)
                {
                    // Already cleared
                    CryptoPool.Return(rentedMac, clearSize: 0);
                }

                if (rentedAuthSafe != null)
                {
                    // Already cleared
                    CryptoPool.Return(rentedAuthSafe, clearSize: 0);
                }
            }
        }
Пример #27
0
 internal override void WriteSpan(AsnWriter writer, Asn1Tag tag, ReadOnlySpan <char> s) =>
 writer.WriteCharacterString(tag, UniversalTagNumber.BMPString, s);
Пример #28
0
        public void ComputeSignature(CmsSigner signer, bool silent)
        {
            if (signer == null)
            {
                throw new ArgumentNullException(nameof(signer));
            }

            // While it shouldn't be possible to change the length of ContentInfo.Content
            // after it's built, use the property at this stage, then use the saved value
            // (if applicable) after this point.
            if (ContentInfo.Content.Length == 0)
            {
                throw new CryptographicException(SR.Cryptography_Cms_Sign_Empty_Content);
            }

            // If we had content already, use that now.
            // (The second signer doesn't inherit edits to signedCms.ContentInfo.Content)
            ReadOnlyMemory <byte> content = _heldContent ?? ContentInfo.Content;
            string contentType            = _contentType ?? ContentInfo.ContentType.Value ?? Oids.Pkcs7Data;

            X509Certificate2Collection chainCerts;
            SignerInfoAsn newSigner   = signer.Sign(content, contentType, silent, out chainCerts);
            bool          firstSigner = false;

            if (!_hasData)
            {
                firstSigner = true;

                _signedData = new SignedDataAsn
                {
                    DigestAlgorithms = Array.Empty <AlgorithmIdentifierAsn>(),
                    SignerInfos      = Array.Empty <SignerInfoAsn>(),
                    EncapContentInfo = new EncapsulatedContentInfoAsn {
                        ContentType = contentType
                    },
                };

                // Since we're going to call Decode before this method exits we don't need to save
                // the copy of _heldContent or _contentType here if we're attached.
                if (!Detached)
                {
                    using (AsnWriter writer = new AsnWriter(AsnEncodingRules.DER))
                    {
                        writer.WriteOctetString(content.Span);

                        _signedData.EncapContentInfo.Content = writer.Encode();
                    }
                }

                _hasData = true;
            }

            int newIdx = _signedData.SignerInfos.Length;

            Array.Resize(ref _signedData.SignerInfos, newIdx + 1);
            _signedData.SignerInfos[newIdx] = newSigner;
            UpdateCertificatesFromAddition(chainCerts);
            ConsiderDigestAddition(newSigner.DigestAlgorithm);
            UpdateMetadata();

            if (firstSigner)
            {
                Reencode();

                Debug.Assert(_heldContent != null);
                Debug.Assert(_contentType == contentType);
            }
        }
Пример #29
0
 internal void Encode(AsnWriter writer)
 {
     Encode(writer, Asn1Tag.Sequence);
 }
Пример #30
0
        private static unsafe byte[] MacAndEncode(
            AsnWriter tmpWriter,
            ReadOnlyMemory <byte> encodedAuthSafe,
            ReadOnlySpan <char> passwordSpan)
        {
            // Windows/macOS compatibility: Use HMAC-SHA-1,
            // other algorithms may not be understood
            byte[]            macKey        = new byte[20];
            Span <byte>       macSalt       = stackalloc byte[20];
            Span <byte>       macSpan       = stackalloc byte[20];
            HashAlgorithmName hashAlgorithm = HashAlgorithmName.SHA1;

            RandomNumberGenerator.Fill(macSalt);

            fixed(byte *macKeyPtr = macKey)
            {
                Span <byte> macKeySpan = macKey;

                Pkcs12Kdf.DeriveMacKey(
                    passwordSpan,
                    hashAlgorithm,
                    s_windowsPbe.IterationCount,
                    macSalt,
                    macKeySpan);

                using (IncrementalHash mac = IncrementalHash.CreateHMAC(hashAlgorithm, macKey))
                {
                    mac.AppendData(encodedAuthSafe.Span);

                    if (!mac.TryGetHashAndReset(macSpan, out int bytesWritten) || bytesWritten != macSpan.Length)
                    {
                        Debug.Fail($"TryGetHashAndReset wrote {bytesWritten} of {macSpan.Length} bytes");
                        throw new CryptographicException();
                    }
                }

                CryptographicOperations.ZeroMemory(macKeySpan);
            }

            // https://tools.ietf.org/html/rfc7292#section-4
            //
            // PFX ::= SEQUENCE {
            //   version    INTEGER {v3(3)}(v3,...),
            //   authSafe   ContentInfo,
            //   macData    MacData OPTIONAL
            // }
            Debug.Assert(tmpWriter.GetEncodedLength() == 0);
            tmpWriter.PushSequence();

            tmpWriter.WriteInteger(3);

            tmpWriter.PushSequence();
            {
                tmpWriter.WriteObjectIdentifier(Oids.Pkcs7Data);

                tmpWriter.PushSequence(s_contextSpecific0);
                {
                    tmpWriter.WriteOctetString(encodedAuthSafe.Span);
                    tmpWriter.PopSequence(s_contextSpecific0);
                }

                tmpWriter.PopSequence();
            }

            // https://tools.ietf.org/html/rfc7292#section-4
            //
            // MacData ::= SEQUENCE {
            //   mac        DigestInfo,
            //   macSalt    OCTET STRING,
            //   iterations INTEGER DEFAULT 1
            //   -- Note: The default is for historical reasons and its use is
            //   -- deprecated.
            // }
            tmpWriter.PushSequence();
            {
                tmpWriter.PushSequence();
                {
                    tmpWriter.PushSequence();
                    {
                        tmpWriter.WriteObjectIdentifier(Oids.Sha1);
                        tmpWriter.PopSequence();
                    }

                    tmpWriter.WriteOctetString(macSpan);
                    tmpWriter.PopSequence();
                }

                tmpWriter.WriteOctetString(macSalt);
                tmpWriter.WriteInteger(s_windowsPbe.IterationCount);

                tmpWriter.PopSequence();
            }

            tmpWriter.PopSequence();
            return(tmpWriter.Encode());
        }