Пример #1
0
        public static void WriteTwoCertsNoKeys_NoEncryption()
        {
            Pkcs12SafeContents contents = new Pkcs12SafeContents();

            byte[] rawData1;
            byte[] rawData2;

            using (X509Certificate2 cert1 = Certificates.RSAKeyTransferCapi1.GetCertificate())
                using (X509Certificate2 cert2 = Certificates.RSAKeyTransfer2.GetCertificate())
                {
                    // Windows seems to treat these as a stack.  (LIFO)
                    contents.AddCertificate(cert2);
                    contents.AddCertificate(cert1);
                    rawData1 = cert1.RawData;
                    rawData2 = cert2.RawData;
                }

            Pkcs12Builder builder = new Pkcs12Builder();

            builder.AddSafeContentsUnencrypted(contents);

            const string password = nameof(WriteOneCertNoKeys_NoEncryption);

            builder.SealWithMac(password, HashAlgorithmName.SHA1, 1024);
            byte[] pfx = builder.Encode();

            ImportedCollection coll =
                ImportedCollection.Import(pfx, password, X509KeyStorageFlags.EphemeralKeySet);

            using (coll)
            {
                Assert.Equal(2, coll.Collection.Count);
                Assert.Equal(rawData1, coll.Collection[0].RawData);
                Assert.Equal(rawData2, coll.Collection[1].RawData);
                Assert.False(coll.Collection[0].HasPrivateKey, "coll.Collection[0].HasPrivateKey");
                Assert.False(coll.Collection[1].HasPrivateKey, "coll.Collection[1].HasPrivateKey");
            }
        }
Пример #2
0
        public static void AddNullContents()
        {
            Pkcs12Builder builder = new Pkcs12Builder();

            AssertExtensions.Throws <ArgumentNullException>(
                "safeContents",
                () => builder.AddSafeContentsUnencrypted(null));

            AssertExtensions.Throws <ArgumentNullException>(
                "safeContents",
                () => builder.AddSafeContentsEncrypted(null, Array.Empty <byte>(), s_pbkdf2Parameters));

            AssertExtensions.Throws <ArgumentNullException>(
                "safeContents",
                () => builder.AddSafeContentsEncrypted(null, ReadOnlySpan <byte> .Empty, s_pbkdf2Parameters));

            AssertExtensions.Throws <ArgumentNullException>(
                "safeContents",
                () => builder.AddSafeContentsEncrypted(null, string.Empty, s_pbkdf2Parameters));

            AssertExtensions.Throws <ArgumentNullException>(
                "safeContents",
                () => builder.AddSafeContentsEncrypted(null, ReadOnlySpan <char> .Empty, s_pbkdf2Parameters));
        }
Пример #3
0
        public void CertAndKeyTwice_KeysUntagged()
        {
            string pw = nameof(CertAndKeyTwice);

            using (var cert = new X509Certificate2(TestData.PfxData, TestData.PfxDataPassword, s_exportableImportFlags))
                using (RSA key = cert.GetRSAPrivateKey())
                {
                    Pkcs12Builder      builder      = new Pkcs12Builder();
                    Pkcs12SafeContents keyContents  = new Pkcs12SafeContents();
                    Pkcs12SafeContents certContents = new Pkcs12SafeContents();

                    Pkcs12SafeBag key1  = keyContents.AddShroudedKey(key, pw, s_windowsPbe);
                    Pkcs12SafeBag key2  = keyContents.AddShroudedKey(key, pw, s_windowsPbe);
                    Pkcs12SafeBag cert1 = certContents.AddCertificate(cert);
                    Pkcs12SafeBag cert2 = certContents.AddCertificate(cert);

                    Pkcs9LocalKeyId id2 = new Pkcs9LocalKeyId(cert.GetCertHash());
                    Pkcs9LocalKeyId id3 = new Pkcs9LocalKeyId(BitConverter.GetBytes(3));
                    Pkcs9LocalKeyId id4 = new Pkcs9LocalKeyId(BitConverter.GetBytes(4));
                    cert1.Attributes.Add(s_keyIdOne);
                    cert2.Attributes.Add(id2);
                    key1.Attributes.Add(id3);
                    key2.Attributes.Add(id4);

                    AddContents(keyContents, builder, pw, encrypt: false);
                    AddContents(certContents, builder, pw, encrypt: true);
                    builder.SealWithMac(pw, s_digestAlgorithm, MacCount);
                    byte[] pfxBytes = builder.Encode();

                    ReadUnreadablePfx(
                        pfxBytes,
                        pw,
                        // NTE_BAD_DATA
                        -2146893819);
                }
        }
        public void OneCertWithOneKey(SingleCertOptions options)
        {
            bool   sameContainer           = (options & SingleCertOptions.KeyAndCertInSameContents) != 0;
            bool   dontShroudKey           = (options & SingleCertOptions.UnshroudedKey) != 0;
            bool   keyContainerLast        = (options & SingleCertOptions.KeyContentsLast) != 0;
            bool   encryptCertSafeContents = (options & SingleCertOptions.PlaintextCertContents) == 0;
            bool   encryptKeySafeContents  = (options & SingleCertOptions.EncryptKeyContents) != 0;
            bool   skipMac  = (options & SingleCertOptions.SkipMac) != 0;
            string password = options.ToString();

            using (var cert = new X509Certificate2(TestData.PfxData, TestData.PfxDataPassword, s_exportableImportFlags))
                using (RSA key = cert.GetRSAPrivateKey())
                {
                    if (dontShroudKey && OperatingSystem.IsWindows())
                    {
                        // CNG keys are only encrypted-exportable, so we need to export them encrypted.
                        // Then we can import it into a new, fully-exportable key. (Sigh.)
                        byte[] tmpPkcs8 = key.ExportEncryptedPkcs8PrivateKey(password, s_windowsPbe);
                        key.ImportEncryptedPkcs8PrivateKey(password, tmpPkcs8, out _);
                    }

                    Pkcs12Builder builder = new Pkcs12Builder();

                    Pkcs12SafeContents certContents         = new Pkcs12SafeContents();
                    Pkcs12SafeContents keyContents          = sameContainer ? null : new Pkcs12SafeContents();
                    Pkcs12SafeContents keyEffectiveContents = keyContents ?? certContents;

                    Pkcs12SafeBag certBag = certContents.AddCertificate(cert);
                    Pkcs12SafeBag keyBag;

                    if (dontShroudKey)
                    {
                        keyBag = keyEffectiveContents.AddKeyUnencrypted(key);
                    }
                    else
                    {
                        keyBag = keyEffectiveContents.AddShroudedKey(key, password, s_windowsPbe);
                    }

                    certBag.Attributes.Add(s_keyIdOne);
                    keyBag.Attributes.Add(s_keyIdOne);

                    if (sameContainer)
                    {
                        AddContents(certContents, builder, password, encryptCertSafeContents);
                    }
                    else if (keyContainerLast)
                    {
                        AddContents(certContents, builder, password, encryptCertSafeContents);
                        AddContents(keyContents, builder, password, encryptKeySafeContents);
                    }
                    else
                    {
                        AddContents(keyContents, builder, password, encryptKeySafeContents);
                        AddContents(certContents, builder, password, encryptCertSafeContents);
                    }

                    if (skipMac)
                    {
                        builder.SealWithoutIntegrity();
                    }
                    else
                    {
                        builder.SealWithMac(password, s_digestAlgorithm, MacCount);
                    }

                    ReadPfx(builder.Encode(), password, cert);
                }
        }
Пример #5
0
        public static void EncryptDecryptMixBytesAndChars(bool encryptBytes, bool withSpan)
        {
            Pkcs12SafeContents contents = new Pkcs12SafeContents();

            contents.AddSecret(s_zeroOid, s_derNull);

            string      password          = nameof(EncryptDecryptMixBytesAndChars);
            Span <byte> passwordUtf8Bytes = stackalloc byte[password.Length];

            Encoding.UTF8.GetBytes(password, passwordUtf8Bytes);

            Pkcs12Builder builder = new Pkcs12Builder();

            if (encryptBytes)
            {
                builder.AddSafeContentsEncrypted(contents, passwordUtf8Bytes, s_pbkdf2Parameters);
            }
            else
            {
                builder.AddSafeContentsEncrypted(contents, password, s_pbkdf2Parameters);
            }

            builder.SealWithMac(password, HashAlgorithmName.SHA1, 2048);

            byte[]     encoded = builder.Encode();
            Pkcs12Info info    = Pkcs12Info.Decode(encoded, out _, skipCopy: true);

            Assert.True(info.VerifyMac(password));
            ReadOnlyCollection <Pkcs12SafeContents> authSafe = info.AuthenticatedSafe;

            Assert.Equal(1, authSafe.Count);

            Pkcs12SafeContents readContents = authSafe[0];

            Assert.Equal(
                Pkcs12ConfidentialityMode.Password,
                readContents.ConfidentialityMode);

            if (encryptBytes)
            {
                if (withSpan)
                {
                    readContents.Decrypt(password.AsSpan());
                }
                else
                {
                    readContents.Decrypt(password);
                }
            }
            else
            {
                if (withSpan)
                {
                    readContents.Decrypt(passwordUtf8Bytes);
                }
                else
                {
                    readContents.Decrypt(passwordUtf8Bytes.ToArray());
                }
            }

            Assert.Equal(
                Pkcs12ConfidentialityMode.None,
                readContents.ConfidentialityMode);

            List <Pkcs12SafeBag> bags = readContents.GetBags().ToList();

            Assert.Equal(1, bags.Count);
            Pkcs12SecretBag secretBag = Assert.IsType <Pkcs12SecretBag>(bags[0]);

            Assert.Equal(s_zeroOid.Value, secretBag.GetSecretType().Value);
            Assert.Equal(s_derNull.ByteArrayToHex(), secretBag.SecretValue.ByteArrayToHex());
        }
Пример #6
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());
            }
        }
Пример #7
0
        public void TwoCerts_TwoKeys_ManySafeContentsValues(bool invertCertOrder, bool invertKeyOrder)
        {
            string pw = nameof(TwoCerts_TwoKeys_ManySafeContentsValues);

            using (ImportedCollection ic = Cert.Import(TestData.MultiPrivateKeyPfx, null, s_exportableImportFlags))
            {
                X509Certificate2Collection certs  = ic.Collection;
                X509Certificate2           first  = certs[0];
                X509Certificate2           second = certs[1];

                if (invertCertOrder)
                {
                    X509Certificate2 tmp = first;
                    first  = second;
                    second = tmp;
                }

                using (AsymmetricAlgorithm firstKey = first.GetRSAPrivateKey())
                    using (AsymmetricAlgorithm secondKey = second.GetRSAPrivateKey())
                    {
                        AsymmetricAlgorithm firstAdd  = firstKey;
                        AsymmetricAlgorithm secondAdd = secondKey;

                        if (invertKeyOrder != invertCertOrder)
                        {
                            AsymmetricAlgorithm tmp = firstKey;
                            firstAdd  = secondAdd;
                            secondAdd = tmp;
                        }

                        Pkcs12Builder      builder            = new Pkcs12Builder();
                        Pkcs12SafeContents firstKeyContents   = new Pkcs12SafeContents();
                        Pkcs12SafeContents secondKeyContents  = new Pkcs12SafeContents();
                        Pkcs12SafeContents firstCertContents  = new Pkcs12SafeContents();
                        Pkcs12SafeContents secondCertContents = new Pkcs12SafeContents();

                        Pkcs12SafeContents irrelevant = new Pkcs12SafeContents();
                        irrelevant.AddSecret(new Oid("0.0"), new byte[] { 0x05, 0x00 });

                        Pkcs12SafeBag firstAddedKeyBag  = firstKeyContents.AddShroudedKey(firstAdd, pw, s_windowsPbe);
                        Pkcs12SafeBag secondAddedKeyBag = secondKeyContents.AddShroudedKey(secondAdd, pw, s_windowsPbe);
                        Pkcs12SafeBag firstCertBag      = firstCertContents.AddCertificate(first);
                        Pkcs12SafeBag secondCertBag     = secondCertContents.AddCertificate(second);
                        Pkcs12SafeBag firstKeyBag       = firstAddedKeyBag;
                        Pkcs12SafeBag secondKeyBag      = secondAddedKeyBag;

                        if (invertKeyOrder != invertCertOrder)
                        {
                            Pkcs12SafeBag tmp = firstKeyBag;
                            firstKeyBag  = secondKeyBag;
                            secondKeyBag = tmp;
                        }

                        firstCertBag.Attributes.Add(s_keyIdOne);
                        firstKeyBag.Attributes.Add(s_keyIdOne);

                        Pkcs9LocalKeyId secondKeyId = new Pkcs9LocalKeyId(second.GetCertHash());
                        secondCertBag.Attributes.Add(secondKeyId);
                        secondKeyBag.Attributes.Add(secondKeyId);

                        // 2C, 1K, 1C, 2K
                        // With some non-participating contents values sprinkled in for good measure.
                        AddContents(irrelevant, builder, pw, encrypt: true);
                        AddContents(secondCertContents, builder, pw, encrypt: true);
                        AddContents(irrelevant, builder, pw, encrypt: false);
                        AddContents(firstKeyContents, builder, pw, encrypt: false);
                        AddContents(firstCertContents, builder, pw, encrypt: true);
                        AddContents(irrelevant, builder, pw, encrypt: false);
                        AddContents(secondKeyContents, builder, pw, encrypt: true);
                        AddContents(irrelevant, builder, pw, encrypt: true);

                        builder.SealWithMac(pw, s_digestAlgorithm, MacCount);
                        byte[] pfxBytes = builder.Encode();

                        X509Certificate2[] expectedOrder = { first, second };

                        Action <X509Certificate2> followup = CheckKeyConsistency;

                        // For unknown reasons, CheckKeyConsistency on this test fails
                        // on Windows 7 with an Access Denied in all variations for
                        // Collections, and in invertCertOrder: true for Single.
                        //
                        // Obviously this hit some sort of weird corner case in the Win7
                        // loader, but it's not important to the test.

                        if (OperatingSystem.IsWindows() &&
                            !PlatformDetection.IsWindows8xOrLater)
                        {
                            followup = null;
                        }

                        ReadMultiPfx(
                            pfxBytes,
                            pw,
                            first,
                            expectedOrder,
                            followup);
                    }
            }
        }
Пример #8
0
        public void OneCert_TwoKeys_FirstWins(bool correctKeyFirst)
        {
            string pw = nameof(OneCert_TwoKeys_FirstWins);

            // Build the PFX in the normal Windows style, except the private key doesn't match.
            using (var cert = new X509Certificate2(TestData.PfxData, TestData.PfxDataPassword, s_exportableImportFlags))
                using (RSA key = cert.GetRSAPrivateKey())
                    using (RSA unrelated = RSA.Create(key.KeySize))
                    {
                        Pkcs12Builder      builder      = new Pkcs12Builder();
                        Pkcs12SafeContents keyContents  = new Pkcs12SafeContents();
                        Pkcs12SafeContents certContents = new Pkcs12SafeContents();
                        Pkcs12SafeBag      keyBag;
                        Pkcs12SafeBag      keyBag2;
                        Pkcs12SafeBag      certBag = certContents.AddCertificate(cert);

                        if (correctKeyFirst)
                        {
                            keyBag  = keyContents.AddShroudedKey(key, pw, s_windowsPbe);
                            keyBag2 = keyContents.AddShroudedKey(unrelated, pw, s_windowsPbe);
                        }
                        else
                        {
                            keyBag  = keyContents.AddShroudedKey(unrelated, pw, s_windowsPbe);
                            keyBag2 = keyContents.AddShroudedKey(key, pw, s_windowsPbe);
                        }

                        keyBag.Attributes.Add(s_keyIdOne);
                        keyBag2.Attributes.Add(s_keyIdOne);
                        certBag.Attributes.Add(s_keyIdOne);

                        builder.AddSafeContentsUnencrypted(keyContents);
                        builder.AddSafeContentsEncrypted(certContents, pw, s_windowsPbe);
                        builder.SealWithoutIntegrity();
                        byte[] pfxBytes = builder.Encode();

                        // On macOS the cert will come back with HasPrivateKey being false when the
                        // incorrect key comes first
                        if (!correctKeyFirst && OperatingSystem.IsMacOS())
                        {
                            using (var publicCert = new X509Certificate2(cert.RawData))
                            {
                                ReadPfx(
                                    pfxBytes,
                                    pw,
                                    publicCert);
                            }

                            return;
                        }

                        // The RSA "self-test" should pass when the correct key is first,
                        // and fail when the unrelated key is first.
                        Action <X509Certificate2> followup = CheckKeyConsistency;

                        if (!correctKeyFirst)
                        {
                            followup = CheckKeyConsistencyFails;
                        }

                        ReadPfx(
                            pfxBytes,
                            pw,
                            cert,
                            followup);
                    }
        }