diff --git a/src/dev/impl/DevToys/Helpers/CertificateHelper.cs b/src/dev/impl/DevToys/Helpers/CertificateHelper.cs index 87ac057663..b2cdba8909 100644 --- a/src/dev/impl/DevToys/Helpers/CertificateHelper.cs +++ b/src/dev/impl/DevToys/Helpers/CertificateHelper.cs @@ -5,6 +5,7 @@ using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Text; +using DevToys.Core; namespace DevToys.Helpers { @@ -47,9 +48,10 @@ internal static bool TryDecodeCertificate(string input, string? password, out st } } + X509Certificate2 certificate; try { - var certificate = new X509Certificate2(Convert.FromBase64String(publicCert), password); + certificate = new X509Certificate2(Convert.FromBase64String(publicCert), password); decoded = certificate.ToString(); } catch (CryptographicException wce) @@ -68,9 +70,44 @@ internal static bool TryDecodeCertificate(string input, string? password, out st return false; } + if (!string.IsNullOrEmpty(decoded) && certificate.Extensions.OfType().Any()) + { + decoded = string.Join(Environment.NewLine, decoded, DecodeExtensions(certificate)); + } + return true; } + private static string DecodeExtensions(X509Certificate2 certificate) + { + // Try to decode the X.509 extensions. + try + { + StringBuilder extensionData = new(); + foreach (X509Extension x509Extension in certificate.Extensions) + { + AsnEncodedData asnEncodedData = new(x509Extension.Oid, x509Extension.RawData); + + // Add the name in brackets to match the previous output from X509Certificate.ToString() + extensionData.AppendLine($"[{x509Extension.Oid.FriendlyName}]"); + + // Add each line of the data, indented by two spaces to match the output from X509Certificate.ToString() + foreach (string dataLine in asnEncodedData.Format(multiLine: true).Split(Environment.NewLine)) + { + extensionData.AppendLine($" {dataLine}"); + } + } + + return extensionData.ToString().Trim(); + } + catch (Exception ex) + { + Logger.LogFault("Failed to parse X.509 extensions from certificate.", ex); + } + + return string.Empty; + } + /// /// Get the string data from a certificate file. /// If the string is pem format with plain text values, it will return as is. diff --git a/src/tests/DevToys.Tests/Helpers/CertificateHelperTests.cs b/src/tests/DevToys.Tests/Helpers/CertificateHelperTests.cs index c0729759b8..450db489ac 100644 --- a/src/tests/DevToys.Tests/Helpers/CertificateHelperTests.cs +++ b/src/tests/DevToys.Tests/Helpers/CertificateHelperTests.cs @@ -1,4 +1,5 @@ using System; +using System.Text; using DevToys.Helpers; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -12,6 +13,9 @@ public class CertificateHelperTests [DataRow(PemCertWithPrivateKey, null, true, CertDecoded)] [DataRow(PfxNoPassword, null, true, CertDecoded)] [DataRow(PfxWithPassword, "test1234", true, CertDecoded)] + [DataRow(PemCertPublicWithExtensions, null, true, CertWithExtensionsDecoded)] + [DataRow(PemCertWithPrivateKeyWithExtensions, null, true, CertWithExtensionsDecoded)] + [DataRow(PfxWithExtensionsNoPassword, null, true, CertWithExtensionsDecoded)] public void DecodeCertificateSuccess(string input, string password, bool successfullyDecoded, string expectedResult) => DecodeCertificate(input, password, successfullyDecoded, expectedResult); @@ -25,20 +29,34 @@ public void DecodeCertificateErrors() private void DecodeCertificate(string input, string password, bool successfullyDecoded, string expectedResult) { - // Convert date output to UTC so that tests pass on any machine with any timezone - var notBefore = DateTime.Parse("4/17/2023 10:40:48 AM"); - var notAfter = DateTime.Parse("4/16/2024 10:40:48 AM"); - var easternZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time"); - DateTime notBeforeUtc = TimeZoneInfo.ConvertTimeToUtc(notBefore, easternZone); - DateTime notAfterUtc = TimeZoneInfo.ConvertTimeToUtc(notAfter, easternZone); - bool result = CertificateHelper.TryDecodeCertificate(input, password, out string decoded); - decoded = decoded.Replace(notBefore.ToString(), notBeforeUtc.ToString()); - decoded = decoded.Replace(notAfter.ToString(), notAfterUtc.ToString()); + decoded = CleanDateTimes(decoded); + expectedResult = CleanDateTimes(expectedResult); Assert.AreEqual(result, successfullyDecoded); Assert.AreEqual(expectedResult, decoded); } + /// + /// Strips times from decoded certificates to avoid issues with testing in different timezones + /// + private string CleanDateTimes(string decoded) + { + var decodedCleaned = new StringBuilder(); + foreach (string line in decoded.Split(Environment.NewLine)) + { + if (DateTime.TryParse(line, out DateTime dateTime)) + { + decodedCleaned.AppendLine($" {dateTime.Date}"); + } + else + { + decodedCleaned.AppendLine(line); + } + } + + return decodedCleaned.ToString(); + } + /// /// These certificates can be created via /// PEM: @@ -210,5 +228,157 @@ [Not After] [Thumbprint] 9E5B55F43B571EFE82D386C856506FC96018217C "; + + /// + /// PEM: openssl req -x509 -newkey rsa:4096 -keyout test-devtoys.key -out test-devtoys.pem -sha256 -days 3650 -nodes + /// PFX: openssl pkcs12 -inkey test-devtoys.key -in test-devtoys.pem -export -out test-devtoys.pfx | base64 -w 0 + /// + private const string PemCertPublicWithExtensions = @"-----BEGIN CERTIFICATE----- +MIIFSzCCAzOgAwIBAgIUCi1nl4PF23ETmg7rNHnU99XHbnkwDQYJKoZIhvcNAQEL +BQAwNTELMAkGA1UEBhMCRFQxEzARBgNVBAgMClNvbWUtU3RhdGUxETAPBgNVBAoM +CERldi1Ub3lzMB4XDTIzMDYwMjEzMTIwM1oXDTMzMDUzMDEzMTIwM1owNTELMAkG +A1UEBhMCRFQxEzARBgNVBAgMClNvbWUtU3RhdGUxETAPBgNVBAoMCERldi1Ub3lz +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAuxTovybg74QlGSo7lGlX +Kxz7nq0Mfvulj+t2NVfGXEu6VUTaDZNDYwynRR397N82RKsYt17dSkjUYWZI5nsu +QfH9LJIlstokqu+6/CXA5T79TGNYVz9iFbMQXNy+M2zLaO42LCOHUs8oYFB5FXL7 +x6nXmtsJUB0eITPc2wrKCN7SY3QuMZ/A6Bn2dVJ+7+2SwCRLv7SDDGX/jxiLCxXn +tdmgv/PKQnxq0JXIi3n1BOrdz6e9DYDMjPR5FkZWh0TEjFMpCSxqq/IfQc/DNYii +ragXuvoVpLHswRu4C8ytksZYEg+RjozqjTpVI4c++xXQpNK4zIs0bI6bkczj4T97 +WEzE3xE90RD7gG09tEL7/dKeok5o0zC6N+1rNTPMKTwDPEUig8uNcplN7W5vWehi +ixJGceIFb91zMr+W1ImY39cFllQZnQrBvfsoq0IxHaadYjdvA/C2H1FsFPT4SgSH +D/9HgWyu1wAt7e/xcHa9OM71ac1SpXN2br0Up0P4STXPeolf5I0BsAffNdRrKRM0 +cSZpftnM/gFjoJVcd2unVA4suFoXArHGSRKdqPb3XjnqcFU7MjHDycRXzhfUj90a +Th9pg6lovY1gq9TS8vfNC6zd/W2GcxDD2+ONjsGBnfmF4BLo9eVeMu3kvtMG9l09 +JZZKqQc0x9IxwTZx1JP2CVUCAwEAAaNTMFEwHQYDVR0OBBYEFCad/q2ghyzGQ1B5 +LCVY32+ghsQbMB8GA1UdIwQYMBaAFCad/q2ghyzGQ1B5LCVY32+ghsQbMA8GA1Ud +EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIBAG+/mgWf0zhVXcbZKgrvBqsM +a5qiJPUp4JSjUtUs5TGQRM5HICS+flgzhUa55xDjy9q5Lv3FI04KwT6K8XaSGBGr +zkp2Vyxn5DDboYK2FiJEHJojGzqElOELdOSbMYLO8bLY7SK3eH8pMuy6jPOqABOp +hpVAWhrhvDoBsREwXZDD1CrlorfBCM5ue2Xa1elH3qswG3HkKWq+Ieis8AlFvx7i +JPzw5KTGBdAZzsakF1KN9qC9Xjzoc526yo0RvlsOjK0i9XKpWkjE2pAE/jpqcapZ +Y+mgKJe9wl+ZfZ1Z2AEk9U/T4aZMmxsqo5z3ztjuB290oxR8dnfJlZobAOyFnA3G +5y1/s1Sw0hmKpY7563/c+vvWBwq48R1hYOLB5UsNBSijD+KyAii+ATd0yp/ItPb0 +Ng5ek4rln1BaCumKTJ4WAMBDtqBFCVd0xNidRoI1Ljug8+MPafVzw8KIYP1FrnOy +Vx0sorzO7j2T2rLtTO/RrCbVErBHHyHvLLjxeKnVdc1khtBG/MQv6zkb2w8oxl/9 +6BmGhbw4S5Ti33qO4r1bs8if1zzZJgckcf7f7DPzNvBslUlARy6Kz3CRc2sK9lwm +JIff9Js+BoWwO3KGDnk8paJf/YNBc1qaiFQTHOBCOefqOaTiHG5TGSklO7Ij+xNx +ulEjWxGlNtL7tLMeToVU +-----END CERTIFICATE-----"; + + private const string PemCertWithPrivateKeyWithExtensions = @"-----BEGIN PRIVATE KEY----- +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 +6WNJmQTHY+2bURcR9d1vIO3eGkCrGvs= +-----END PRIVATE KEY----- + +-----BEGIN CERTIFICATE----- +MIIFSzCCAzOgAwIBAgIUCi1nl4PF23ETmg7rNHnU99XHbnkwDQYJKoZIhvcNAQEL +BQAwNTELMAkGA1UEBhMCRFQxEzARBgNVBAgMClNvbWUtU3RhdGUxETAPBgNVBAoM +CERldi1Ub3lzMB4XDTIzMDYwMjEzMTIwM1oXDTMzMDUzMDEzMTIwM1owNTELMAkG +A1UEBhMCRFQxEzARBgNVBAgMClNvbWUtU3RhdGUxETAPBgNVBAoMCERldi1Ub3lz +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAuxTovybg74QlGSo7lGlX +Kxz7nq0Mfvulj+t2NVfGXEu6VUTaDZNDYwynRR397N82RKsYt17dSkjUYWZI5nsu +QfH9LJIlstokqu+6/CXA5T79TGNYVz9iFbMQXNy+M2zLaO42LCOHUs8oYFB5FXL7 +x6nXmtsJUB0eITPc2wrKCN7SY3QuMZ/A6Bn2dVJ+7+2SwCRLv7SDDGX/jxiLCxXn +tdmgv/PKQnxq0JXIi3n1BOrdz6e9DYDMjPR5FkZWh0TEjFMpCSxqq/IfQc/DNYii +ragXuvoVpLHswRu4C8ytksZYEg+RjozqjTpVI4c++xXQpNK4zIs0bI6bkczj4T97 +WEzE3xE90RD7gG09tEL7/dKeok5o0zC6N+1rNTPMKTwDPEUig8uNcplN7W5vWehi +ixJGceIFb91zMr+W1ImY39cFllQZnQrBvfsoq0IxHaadYjdvA/C2H1FsFPT4SgSH +D/9HgWyu1wAt7e/xcHa9OM71ac1SpXN2br0Up0P4STXPeolf5I0BsAffNdRrKRM0 +cSZpftnM/gFjoJVcd2unVA4suFoXArHGSRKdqPb3XjnqcFU7MjHDycRXzhfUj90a +Th9pg6lovY1gq9TS8vfNC6zd/W2GcxDD2+ONjsGBnfmF4BLo9eVeMu3kvtMG9l09 +JZZKqQc0x9IxwTZx1JP2CVUCAwEAAaNTMFEwHQYDVR0OBBYEFCad/q2ghyzGQ1B5 +LCVY32+ghsQbMB8GA1UdIwQYMBaAFCad/q2ghyzGQ1B5LCVY32+ghsQbMA8GA1Ud +EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIBAG+/mgWf0zhVXcbZKgrvBqsM +a5qiJPUp4JSjUtUs5TGQRM5HICS+flgzhUa55xDjy9q5Lv3FI04KwT6K8XaSGBGr +zkp2Vyxn5DDboYK2FiJEHJojGzqElOELdOSbMYLO8bLY7SK3eH8pMuy6jPOqABOp +hpVAWhrhvDoBsREwXZDD1CrlorfBCM5ue2Xa1elH3qswG3HkKWq+Ieis8AlFvx7i +JPzw5KTGBdAZzsakF1KN9qC9Xjzoc526yo0RvlsOjK0i9XKpWkjE2pAE/jpqcapZ +Y+mgKJe9wl+ZfZ1Z2AEk9U/T4aZMmxsqo5z3ztjuB290oxR8dnfJlZobAOyFnA3G +5y1/s1Sw0hmKpY7563/c+vvWBwq48R1hYOLB5UsNBSijD+KyAii+ATd0yp/ItPb0 +Ng5ek4rln1BaCumKTJ4WAMBDtqBFCVd0xNidRoI1Ljug8+MPafVzw8KIYP1FrnOy +Vx0sorzO7j2T2rLtTO/RrCbVErBHHyHvLLjxeKnVdc1khtBG/MQv6zkb2w8oxl/9 +6BmGhbw4S5Ti33qO4r1bs8if1zzZJgckcf7f7DPzNvBslUlARy6Kz3CRc2sK9lwm +JIff9Js+BoWwO3KGDnk8paJf/YNBc1qaiFQTHOBCOefqOaTiHG5TGSklO7Ij+xNx +ulEjWxGlNtL7tLMeToVU +-----END CERTIFICATE----- +"; + + private const string PfxWithExtensionsNoPassword = "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"; + + private const string CertWithExtensionsDecoded = @"[Subject] + O=Dev-Toys, S=Some-State, C=DT + +[Issuer] + O=Dev-Toys, S=Some-State, C=DT + +[Serial Number] + 0A2D679783C5DB71139A0EEB3479D4F7D5C76E79 + +[Not Before] + 6/2/2023 9:12:03 AM + +[Not After] + 5/30/2033 9:12:03 AM + +[Thumbprint] + 41D8D90FE633CFF63CED9E4A53889C0133AEF106 + +[Subject Key Identifier] + 269dfeada0872cc64350792c2558df6fa086c41b + +[Authority Key Identifier] + KeyID=269dfeada0872cc64350792c2558df6fa086c41b + +[Basic Constraints] + Subject Type=CA + Path Length Constraint=None"; } }