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"); } }
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)); }
public static void EncryptEncryptedSafeContents() { Pkcs12Builder builder1 = new Pkcs12Builder(); Pkcs12Builder builder2 = new Pkcs12Builder(); Pkcs12SafeContents contents = new Pkcs12SafeContents(); contents.AddSecret(s_zeroOid, s_derNull); builder1.AddSafeContentsEncrypted(contents, ReadOnlySpan <byte> .Empty, s_pbkdf2Parameters); builder1.SealWithoutIntegrity(); byte[] encoded = builder1.Encode(); Pkcs12Info info = Pkcs12Info.Decode(encoded, out _, skipCopy: true); Assert.Equal(Pkcs12IntegrityMode.None, info.IntegrityMode); Assert.Equal(1, info.AuthenticatedSafe.Count); AssertExtensions.Throws <ArgumentException>( "safeContents", () => builder2.AddSafeContentsEncrypted( info.AuthenticatedSafe[0], "nope", s_pbkdf2Parameters)); AssertExtensions.Throws <ArgumentException>( "safeContents", () => builder2.AddSafeContentsEncrypted( info.AuthenticatedSafe[0], s_derNull.Span, s_pbkdf2Parameters)); }
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()); }
public static void OidRequired() { Pkcs12SafeContents contents = new Pkcs12SafeContents(); AssertExtensions.Throws <ArgumentNullException>( "secretType", () => contents.AddSecret(null, ReadOnlyMemory <byte> .Empty)); }
public static void BadOidFails() { string payloadHex = "0403090807"; Pkcs12SafeContents contents = new Pkcs12SafeContents(); Assert.ThrowsAny <CryptographicException>( () => contents.AddSecret(new Oid("Hi", "There"), payloadHex.HexToByteArray())); }
public static void EncryptPkcs12KdfWithBytes() { Pkcs12SafeContents contents = new Pkcs12SafeContents(); contents.AddSecret(s_zeroOid, s_derNull); Pkcs12Builder builder = new Pkcs12Builder(); Assert.ThrowsAny <CryptographicException>( () => builder.AddSafeContentsEncrypted(contents, s_derNull.Span, s_win7Pbe)); }
public static void CreatingBagSerializesInput() { 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 }); Pkcs12SafeContentsBag safeContentsBag = container.AddNestedContents(builtContents); builtContents.AddSecret(s_zeroOid, new byte[] { 4, 1, 4 }); Pkcs12SafeContents readContents = safeContentsBag.SafeContents; Assert.NotSame(readContents, builtContents); Assert.Equal( Pkcs12ConfidentialityMode.None, readContents.ConfidentialityMode); Assert.True(readContents.IsReadOnly); List <Pkcs12SafeBag> bags1 = builtContents.GetBags().ToList(); List <Pkcs12SafeBag> bags2 = readContents.GetBags().ToList(); Assert.Equal(4, bags1.Count); Assert.Equal(3, 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"); } }
public static void LegalBerPayloadRequired(string inputHex, bool expectSuccess) { Pkcs12SafeContents contents = new Pkcs12SafeContents(); Action addAction = () => contents.AddSecret(new Oid("0.0", "0.0"), inputHex.HexToByteArray()); if (expectSuccess) { addAction(); } else { Assert.ThrowsAny <CryptographicException>(addAction); } }
public static void HasExpectedEncode(bool withAttribute) { string expectedHexWithAttribute = "303F060B2A864886F70D010C0A0105A01C301A060100A0150C1353776F726466" + "6973682E20436C6561726C792E3112301006092A864886F70D01091531030401" + "01"; string expectedHexNoAttribute = "302B060B2A864886F70D010C0A0105A01C301A060100A0150C1353776F726466" + "6973682E20436C6561726C792E"; string expectedHex = withAttribute ? expectedHexWithAttribute : expectedHexNoAttribute; // UTF8String ("Swordfish. Clearly.") string payloadHex = "0C1353776F7264666973682E20436C6561726C792E"; Pkcs12SafeContents contents = new Pkcs12SafeContents(); Pkcs12SecretBag bag = contents.AddSecret(new Oid("0.0", "0.0"), payloadHex.HexToByteArray()); if (withAttribute) { bag.Attributes.Add(new Pkcs9LocalKeyId(new byte[] { 0x01 })); } byte[] encoded = bag.Encode(); Assert.Equal(expectedHex, encoded.ByteArrayToHex()); Span <byte> tooBig = new byte[encoded.Length + 10]; tooBig.Fill(0xCA); Assert.False(bag.TryEncode(tooBig.Slice(0, encoded.Length - 1), out int bytesWritten)); Assert.Equal(0, bytesWritten); Assert.Equal(0xCA, tooBig[0]); Assert.True(bag.TryEncode(tooBig.Slice(3), out bytesWritten)); Assert.Equal(encoded.Length, bytesWritten); Assert.Equal(expectedHex, tooBig.Slice(3, bytesWritten).ByteArrayToHex()); tooBig.Fill(0xCA); bytesWritten = 0; Assert.True(bag.TryEncode(tooBig.Slice(3, encoded.Length), out bytesWritten)); Assert.Equal(encoded.Length, bytesWritten); Assert.Equal(expectedHex, tooBig.Slice(3, bytesWritten).ByteArrayToHex()); }
public static void AddEncryptedNestedContents() { Pkcs12Builder builder = new Pkcs12Builder(); Pkcs12SafeContents contents = new Pkcs12SafeContents(); contents.AddSecret(s_zeroOid, s_derNull); builder.AddSafeContentsEncrypted(contents, "hi", s_pbeParameters); builder.SealWithoutIntegrity(); byte[] encoded = builder.Encode(); Pkcs12Info info = Pkcs12Info.Decode(encoded, out _, skipCopy: true); Assert.Equal(Pkcs12IntegrityMode.None, info.IntegrityMode); Assert.Equal(1, info.AuthenticatedSafe.Count); Pkcs12SafeContents newContents = new Pkcs12SafeContents(); AssertExtensions.Throws <ArgumentException>( "safeContents", () => newContents.AddNestedContents(info.AuthenticatedSafe[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()); }
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()); } }
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); } } }