Exemple #1
0
        public static void AddContentsAfterSealing()
        {
            Pkcs12SafeContents contents = new Pkcs12SafeContents();

            contents.AddSecret(s_zeroOid, s_derNull);

            Pkcs12Builder builder = new Pkcs12Builder();

            builder.SealWithoutIntegrity();

            Assert.Throws <InvalidOperationException>(
                () => builder.AddSafeContentsUnencrypted(contents));

            Assert.Throws <InvalidOperationException>(
                () => builder.AddSafeContentsEncrypted(contents, Array.Empty <byte>(), s_pbkdf2Parameters));

            Assert.Throws <InvalidOperationException>(
                () => builder.AddSafeContentsEncrypted(contents, ReadOnlySpan <byte> .Empty, s_pbkdf2Parameters));

            Assert.Throws <InvalidOperationException>(
                () => builder.AddSafeContentsEncrypted(contents, string.Empty, s_pbkdf2Parameters));

            Assert.Throws <InvalidOperationException>(
                () => builder.AddSafeContentsEncrypted(contents, ReadOnlySpan <char> .Empty, s_pbkdf2Parameters));
        }
Exemple #2
0
        public static void BuildWithEmptySafeContents(bool encrypted)
        {
            string pw = nameof(BuildWithEmptySafeContents);

            Pkcs12Builder      builder = new Pkcs12Builder();
            Pkcs12SafeContents empty   = new Pkcs12SafeContents();

            if (encrypted)
            {
                builder.AddSafeContentsEncrypted(empty, pw, s_win7Pbe);
            }
            else
            {
                builder.AddSafeContentsUnencrypted(empty);
            }

            builder.SealWithMac(pw, HashAlgorithmName.SHA1, 1);
            byte[] pfxBytes = builder.Encode();

            X509Certificate2Collection coll = new X509Certificate2Collection();

            coll.Import(pfxBytes, pw, default);

            Assert.Equal(0, coll.Count);
        }
Exemple #3
0
        public static void WriteOneCertNoKeys_NoEncryption()
        {
            Pkcs12SafeContents contents = new Pkcs12SafeContents();

            byte[] rawData;

            using (X509Certificate2 cert = Certificates.RSAKeyTransferCapi1.GetCertificate())
            {
                contents.AddCertificate(cert);
                rawData = cert.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(1, coll.Collection.Count);
                Assert.Equal(rawData, coll.Collection[0].RawData);
                Assert.False(coll.Collection[0].HasPrivateKey, "coll.Collection[0].HasPrivateKey");
            }
        }
Exemple #4
0
        public static void CopyEncryptedSafeContents(bool withSpan)
        {
            Pkcs12Builder builder1 = new Pkcs12Builder();
            Pkcs12Builder builder2 = new Pkcs12Builder();

            Pkcs12SafeContents contents = new Pkcs12SafeContents();

            contents.AddSecret(s_zeroOid, s_derNull);

            if (withSpan)
            {
                builder1.AddSafeContentsEncrypted(contents, ReadOnlySpan <byte> .Empty, s_pbkdf2Parameters);
            }
            else
            {
                builder1.AddSafeContentsEncrypted(contents, (byte[])null, s_pbkdf2Parameters);
            }

            builder1.SealWithoutIntegrity();

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

            Assert.Equal(Pkcs12IntegrityMode.None, info.IntegrityMode);
            Assert.Equal(1, info.AuthenticatedSafe.Count);

            builder2.AddSafeContentsUnencrypted(info.AuthenticatedSafe[0]);
            builder2.SealWithoutIntegrity();

            byte[] encoded2 = builder2.Encode();
            Assert.Equal(encoded1.ByteArrayToHex(), encoded2.ByteArrayToHex());
        }
Exemple #5
0
        public static X509Certificate2 CreateCertificateWithPrivateKey(
            X509Certificate2 certificate,
            AsymmetricAlgorithm privateKey,
            string password = null)
        {
            var builder  = new Pkcs12Builder();
            var contents = new Pkcs12SafeContents();

            contents.AddCertificate(certificate);
            contents.AddKeyUnencrypted(privateKey);
            builder.AddSafeContentsUnencrypted(contents);

            // OpenSSL requires the file to have a mac, without mac this will run on Windows but not on Linux
            builder.SealWithMac(password, HashAlgorithmName.SHA256, 1);
            var pkcs12bytes = builder.Encode();

            if (string.IsNullOrEmpty(password))
            {
                var certificateOut = new X509Certificate2(pkcs12bytes);
                return(certificateOut);
            }
            else
            {
                var certificateOut = new X509Certificate2(pkcs12bytes, password);
                return(certificateOut);
            }
        }
Exemple #6
0
        public static void ReadSerializedData(bool encryptSafe)
        {
            Pkcs12SafeContents container = new Pkcs12SafeContents();

            Pkcs12SafeContents builtContents = new Pkcs12SafeContents();

            builtContents.AddSecret(s_zeroOid, s_derNull);

            builtContents.AddSecret(s_zeroOid, new byte[] { 4, 1, 2 }).Attributes.Add(
                new Pkcs9LocalKeyId(s_derNull.Span));

            builtContents.AddSecret(s_zeroOid, new byte[] { 4, 1, 3 });
            container.AddNestedContents(builtContents);

            Pkcs12Builder builder = new Pkcs12Builder();

            if (encryptSafe)
            {
                builder.AddSafeContentsEncrypted(container, s_derNull.Span, s_pbkdf2Parameters);
            }
            else
            {
                builder.AddSafeContentsUnencrypted(container);
            }

            builder.SealWithoutIntegrity();
            byte[] encoded = builder.Encode();

            Pkcs12Info         info     = Pkcs12Info.Decode(encoded, out _, skipCopy: true);
            Pkcs12SafeContents onlySafe = info.AuthenticatedSafe.Single();

            if (encryptSafe)
            {
                onlySafe.Decrypt(s_derNull.Span);
            }

            Pkcs12SafeBag         onlyBag         = onlySafe.GetBags().Single();
            Pkcs12SafeContentsBag safeContentsBag = Assert.IsType <Pkcs12SafeContentsBag>(onlyBag);
            Pkcs12SafeContents    readContents    = safeContentsBag.SafeContents;

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

            Assert.True(readContents.IsReadOnly);

            List <Pkcs12SafeBag> bags1 = builtContents.GetBags().ToList();
            List <Pkcs12SafeBag> bags2 = readContents.GetBags().ToList();

            Assert.Equal(bags1.Count, bags2.Count);

            for (int i = 0; i < bags2.Count; i++)
            {
                byte[] encoded1 = bags1[i].Encode();
                byte[] encoded2 = bags1[i].Encode();

                Assert.True(encoded1.AsSpan().SequenceEqual(encoded2), $"Bag {i} encodes the same");
            }
        }
Exemple #7
0
        public static void WriteOneCertWithKey_LikeWindows()
        {
            Pkcs12SafeContents safe1 = new Pkcs12SafeContents();
            Pkcs12SafeContents safe2 = new Pkcs12SafeContents();

            byte[] rawData;

            Pkcs9LocalKeyId localKeyId = new Pkcs9LocalKeyId(new byte[] { 1 });
            const string    password   = nameof(WriteOneCertWithKey_LikeWindows);

            using (X509Certificate2 cert = Certificates.RSAKeyTransferCapi1.TryGetCertificateWithPrivateKey(true))
            {
                Pkcs12CertBag certBag = safe1.AddCertificate(cert);
                certBag.Attributes.Add(localKeyId);

                rawData = cert.RawData;

                Pkcs12ShroudedKeyBag keyBag;

                using (RSA rsa = cert.GetRSAPrivateKey())
                {
                    keyBag = safe2.AddShroudedKey(
                        rsa,
                        password,
                        s_win7Pbe);
                }

                keyBag.Attributes.Add(localKeyId);
            }

            Pkcs12Builder builder = new Pkcs12Builder();

            builder.AddSafeContentsEncrypted(
                safe1,
                password,
                s_win7Pbe);

            builder.AddSafeContentsUnencrypted(safe2);

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

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

            using (coll)
            {
                Assert.Equal(1, coll.Collection.Count);
                Assert.Equal(rawData, coll.Collection[0].RawData);
                Assert.True(coll.Collection[0].HasPrivateKey, "coll.Collection[0].HasPrivateKey");
            }
        }
Exemple #8
0
 private static void AddContents(
     Pkcs12SafeContents contents,
     Pkcs12Builder builder,
     string password,
     bool encrypt)
 {
     if (encrypt)
     {
         builder.AddSafeContentsEncrypted(contents, password, s_windowsPbe);
     }
     else
     {
         builder.AddSafeContentsUnencrypted(contents);
     }
 }
Exemple #9
0
        private static X509Certificate2 CreateCertificateWithPrivateKey(X509Certificate2 certificate, AsymmetricAlgorithm privateKey)
        {
            var builder  = new Pkcs12Builder();
            var contents = new Pkcs12SafeContents();

            contents.AddCertificate(certificate);
            contents.AddKeyUnencrypted(privateKey);
            builder.AddSafeContentsUnencrypted(contents);

            // OpenSSL requires the file to have a mac, without mac this will run on Windows but not on Linux
            builder.SealWithMac("temp", HashAlgorithmName.SHA256, 1);
            var pkcs12bytes = builder.Encode();

            var certificateWithKey = new X509Certificate2(pkcs12bytes, "temp");

            return(certificateWithKey);
        }
Exemple #10
0
        public void OneCert_MismatchedKey()
        {
            string pw = nameof(OneCert_MismatchedKey);

            // 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 realKey = cert.GetRSAPrivateKey())
                    using (RSA key = RSA.Create(realKey.KeySize))
                    {
                        Pkcs12Builder      builder      = new Pkcs12Builder();
                        Pkcs12SafeContents keyContents  = new Pkcs12SafeContents();
                        Pkcs12SafeBag      keyBag       = keyContents.AddShroudedKey(key, pw, s_windowsPbe);
                        Pkcs12SafeContents certContents = new Pkcs12SafeContents();
                        Pkcs12SafeBag      certBag      = certContents.AddCertificate(cert);

                        keyBag.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.
                        if (OperatingSystem.IsMacOS())
                        {
                            using (var publicCert = new X509Certificate2(cert.RawData))
                            {
                                ReadPfx(
                                    pfxBytes,
                                    pw,
                                    publicCert);
                            }

                            return;
                        }

                        ReadPfx(
                            pfxBytes,
                            pw,
                            cert,
                            CheckKeyConsistencyFails);
                    }
        }
        public static void BuildEmptyContents(bool withMac)
        {
            string             password;
            Pkcs12Builder      builder  = new Pkcs12Builder();
            Pkcs12SafeContents contents = new Pkcs12SafeContents();

            builder.AddSafeContentsUnencrypted(contents);

            if (withMac)
            {
                password = "******";
                builder.SealWithMac(password, HashAlgorithmName.SHA1, 2);
            }
            else
            {
                password = null;
                builder.SealWithoutIntegrity();
            }

            byte[] encoded = builder.Encode();

            const string EmptyHex =
                "3029020103302406092A864886F70D010701A01704153013301106092A864886" +
                "F70D010701A00404023000";

            if (withMac)
            {
                Assert.Equal(60 + EmptyHex.Length / 2, encoded.Length);
            }
            else
            {
                Assert.Equal(EmptyHex, encoded.ByteArrayToHex());
            }

            // [ActiveIssue(11046, TestPlatforms.AnyUnix)]
            if (withMac || RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                X509Certificate2Collection collection = new X509Certificate2Collection();
                collection.Import(encoded, password, X509KeyStorageFlags.DefaultKeySet);
                Assert.Equal(0, collection.Count);
            }
        }
        public static void WriteCustomType()
        {
            Pkcs12SafeContents contents = new Pkcs12SafeContents();

            contents.AddSafeBag(new CustomBagType(2));

            Pkcs12Builder builder = new Pkcs12Builder();

            builder.AddSafeContentsUnencrypted(contents);
            builder.SealWithoutIntegrity();

            byte[] encoded = builder.Encode();

            const string expectedHex =
                "3033020103302E06092A864886F70D010701A021041F301D301B06092A864886" +
                "F70D010701A00E040C300A3008060100A003040102";

            Assert.Equal(
                expectedHex,
                encoded.ByteArrayToHex());
        }
        public static void CopyCustomType()
        {
            const string startHex =
                "3033020103302E06092A864886F70D010701A021041F301D301B06092A864886" +
                "F70D010701A00E040C300A3008060100A003040102";

            Pkcs12Info info = Pkcs12Info.Decode(startHex.HexToByteArray(), out _, skipCopy: true);
            // This next line implicitly asserts no encryption, and a couple of Single
            Pkcs12SafeBag bag = info.AuthenticatedSafe.Single().GetBags().Single();

            Pkcs12SafeContents contents = new Pkcs12SafeContents();

            contents.AddSafeBag(bag);

            Pkcs12Builder builder = new Pkcs12Builder();

            builder.AddSafeContentsUnencrypted(contents);
            builder.SealWithoutIntegrity();
            byte[] encoded = builder.Encode();

            Assert.Equal(startHex, encoded.ByteArrayToHex());
        }
Exemple #14
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");
            }
        }
Exemple #15
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));
        }
Exemple #16
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());
            }
        }
Exemple #17
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);
                    }
        }