Esempio n. 1
0
        public static Pkcs12Info Decode(
            ReadOnlyMemory <byte> encodedBytes,
            out int bytesConsumed,
            bool skipCopy = false)
        {
            AsnReader reader = new AsnReader(encodedBytes, AsnEncodingRules.BER);

            // Trim it to the first value
            encodedBytes = reader.PeekEncodedValue();

            ReadOnlyMemory <byte> maybeCopy = skipCopy ? encodedBytes : encodedBytes.ToArray();
            PfxAsn pfx = PfxAsn.Decode(maybeCopy, AsnEncodingRules.BER);

            // https://tools.ietf.org/html/rfc7292#section-4 only defines version 3.
            if (pfx.Version != 3)
            {
                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
            }

            ReadOnlyMemory <byte> authSafeBytes = ReadOnlyMemory <byte> .Empty;
            Pkcs12IntegrityMode   mode          = Pkcs12IntegrityMode.Unknown;

            if (pfx.AuthSafe.ContentType == Oids.Pkcs7Data)
            {
                authSafeBytes = PkcsHelpers.DecodeOctetStringAsMemory(pfx.AuthSafe.Content);

                if (pfx.MacData.HasValue)
                {
                    mode = Pkcs12IntegrityMode.Password;
                }
                else
                {
                    mode = Pkcs12IntegrityMode.None;
                }
            }
            else if (pfx.AuthSafe.ContentType == Oids.Pkcs7Signed)
            {
                SignedDataAsn signedData = SignedDataAsn.Decode(pfx.AuthSafe.Content, AsnEncodingRules.BER);

                mode = Pkcs12IntegrityMode.PublicKey;

                if (signedData.EncapContentInfo.ContentType == Oids.Pkcs7Data)
                {
                    authSafeBytes = signedData.EncapContentInfo.Content.GetValueOrDefault();
                }

                if (pfx.MacData.HasValue)
                {
                    throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
                }
            }

            if (mode == Pkcs12IntegrityMode.Unknown)
            {
                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
            }

            List <ContentInfoAsn> authSafeData   = new List <ContentInfoAsn>();
            AsnReader             authSafeReader = new AsnReader(authSafeBytes, AsnEncodingRules.BER);
            AsnReader             sequenceReader = authSafeReader.ReadSequence();

            authSafeReader.ThrowIfNotEmpty();
            while (sequenceReader.HasData)
            {
                ContentInfoAsn.Decode(sequenceReader, out ContentInfoAsn contentInfo);
                authSafeData.Add(contentInfo);
            }

            ReadOnlyCollection <Pkcs12SafeContents> authSafe;

            if (authSafeData.Count == 0)
            {
                authSafe = new ReadOnlyCollection <Pkcs12SafeContents>(Array.Empty <Pkcs12SafeContents>());
            }
            else
            {
                Pkcs12SafeContents[] contentsArray = new Pkcs12SafeContents[authSafeData.Count];

                for (int i = 0; i < contentsArray.Length; i++)
                {
                    contentsArray[i] = new Pkcs12SafeContents(authSafeData[i]);
                }

                authSafe = new ReadOnlyCollection <Pkcs12SafeContents>(contentsArray);
            }

            bytesConsumed = encodedBytes.Length;

            return(new Pkcs12Info
            {
                AuthenticatedSafe = authSafe,
                IntegrityMode = mode,
                _decoded = pfx,
                _authSafeContents = authSafeBytes,
            });
        }
Esempio n. 2
0
        public static void EncodeAndTryEncode(Pkcs12IntegrityMode mode)
        {
            Pkcs12Builder builder1 = new Pkcs12Builder();
            Pkcs12Builder builder2 = new Pkcs12Builder();

            Pkcs12SafeContents contents = new Pkcs12SafeContents();

            contents.AddSecret(s_zeroOid, s_derNull);

            builder1.AddSafeContentsUnencrypted(contents);
            builder2.AddSafeContentsUnencrypted(contents);

            int macTrailerLength = 0;

            if (mode == Pkcs12IntegrityMode.Password)
            {
                builder1.SealWithMac(ReadOnlySpan <char> .Empty, HashAlgorithmName.SHA1, 2);
                builder2.SealWithMac(ReadOnlySpan <char> .Empty, HashAlgorithmName.SHA1, 2);

                // Two OCTET STRINGs of 20 bytes, and the INTEGER 2
                macTrailerLength = 2 + 20 + 2 + 20 + 2 + 3;
            }
            else if (mode == Pkcs12IntegrityMode.None)
            {
                builder1.SealWithoutIntegrity();
                builder2.SealWithoutIntegrity();
            }

            Assert.True(builder1.IsSealed, "builder1.IsSealed");
            Assert.True(builder2.IsSealed, "builder2.IsSealed");

            byte[]      encoded = builder1.Encode();
            byte[]      buf     = new byte[encoded.Length + 40];
            Span <byte> bufSpan = buf;

            // Span too small
            Assert.False(builder2.TryEncode(buf.AsSpan(0, encoded.Length - 1), out int bytesWritten));
            Assert.Equal(0, bytesWritten);

            // Span exactly right
            bufSpan.Fill(0xCA);
            Assert.True(builder2.TryEncode(buf.AsSpan(1, encoded.Length), out bytesWritten));
            Assert.Equal(encoded.Length, bytesWritten);
            Assert.Equal(0xCA, buf[0]);
            Assert.Equal(0xCA, buf[bytesWritten + 1]);

            if (mode == Pkcs12IntegrityMode.Password)
            {
                Assert.Equal(0x02, buf[bytesWritten]);
            }

            // The same contents except the MAC (different random salt)
            Assert.Equal(
                encoded.AsSpan(0, bytesWritten - macTrailerLength).ByteArrayToHex(),
                buf.AsSpan(1, bytesWritten - macTrailerLength).ByteArrayToHex());

            if (macTrailerLength > 0)
            {
                Assert.NotEqual(
                    encoded.AsSpan(bytesWritten - macTrailerLength).ByteArrayToHex(),
                    buf.AsSpan(1 + bytesWritten - macTrailerLength, macTrailerLength).ByteArrayToHex());
            }

            // Span larger than needed
            bufSpan.Fill(0xCA);
            Assert.True(builder2.TryEncode(buf.AsSpan(2), out bytesWritten));
            Assert.Equal(encoded.Length, bytesWritten);
            Assert.Equal(0xCA, buf[0]);
            Assert.Equal(0xCA, buf[1]);
            Assert.Equal(0xCA, buf[bytesWritten + 2]);

            if (mode == Pkcs12IntegrityMode.Password)
            {
                Assert.Equal(0x02, buf[bytesWritten + 1]);
            }

            // The same contents except the MAC (different random salt)
            Assert.Equal(
                encoded.AsSpan(0, bytesWritten - macTrailerLength).ByteArrayToHex(),
                buf.AsSpan(2, bytesWritten - macTrailerLength).ByteArrayToHex());

            if (macTrailerLength > 0)
            {
                Assert.NotEqual(
                    encoded.AsSpan(bytesWritten - macTrailerLength).ByteArrayToHex(),
                    buf.AsSpan(2 + bytesWritten - macTrailerLength, macTrailerLength).ByteArrayToHex());
            }
        }