diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a05c0c..6df6cbf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog for OpenAuthenticode +## v0.6.1 - 2025-02-12 + +* Fix up certificate selection logic for `Get-OpenAuthenticodeAzTrustedSigner` to retrieve the correct leaf certificate on Windows. + ## v0.6.0 - 2025-02-12 * Added the `-TokenSource` parameter for `Get-OpenAuthenticodeAzKey` to specify the authentication method used. diff --git a/module/OpenAuthenticode.psd1 b/module/OpenAuthenticode.psd1 index db6b618..f51568b 100644 --- a/module/OpenAuthenticode.psd1 +++ b/module/OpenAuthenticode.psd1 @@ -14,7 +14,7 @@ RootModule = 'OpenAuthenticode.psm1' # Version number of this module. - ModuleVersion = '0.6.0' + ModuleVersion = '0.6.1' # Supported PSEditions # CompatiblePSEditions = @() diff --git a/src/OpenAuthenticode.Module/OpenAuthenticodeAzTrustedSigner.cs b/src/OpenAuthenticode.Module/OpenAuthenticodeAzTrustedSigner.cs index 5650555..ccb82db 100644 --- a/src/OpenAuthenticode.Module/OpenAuthenticodeAzTrustedSigner.cs +++ b/src/OpenAuthenticode.Module/OpenAuthenticodeAzTrustedSigner.cs @@ -79,7 +79,8 @@ await chainResponse.Value.CopyToAsync( WriteVerbose("Importing certificate chain"); X509Certificate2Collection chain = []; chain.Import(rawChain); - X509Certificate2 cert = chain[0]; + + X509Certificate2 cert = CertificateHelper.GetAzureTrustedSigningCertificate(chain, cmdlet: this); WriteVerbose($"Creating AzureTrustedSigner object with cert '{cert.SubjectName.Name}' - {cert.Thumbprint}"); try diff --git a/src/OpenAuthenticode/CertificateHelper.cs b/src/OpenAuthenticode/CertificateHelper.cs new file mode 100644 index 0000000..5a946f6 --- /dev/null +++ b/src/OpenAuthenticode/CertificateHelper.cs @@ -0,0 +1,48 @@ +using System.Management.Automation; +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; + +namespace OpenAuthenticode; + +internal static class CertificateHelper +{ + + /// + /// The order of cert in the collection is platform specific. We manually + /// find the Azure Trusted Signing cert by the one with an EKU that is the + /// Azure Trusted Signing OID prefix '1.3.6.1.4.1.311.97.'. + /// + /// The collection to search. + /// The cmdlet to write verbose messages to. + /// The leaf certificate to use for signing. + /// Leaf certificate was not found. + public static X509Certificate2 GetAzureTrustedSigningCertificate( + X509Certificate2Collection collection, + AsyncPSCmdlet? cmdlet = null) + { + foreach (X509Certificate2 cert in collection) + { + cmdlet?.WriteVerbose( + $"Processing Azure Trusted Signing certificate: Subject '{cert.Subject}' - Issuer '{cert.Issuer}'"); + + foreach (X509Extension ext in cert.Extensions) + { + if (ext is not X509EnhancedKeyUsageExtension eku) + { + continue; + } + + foreach (Oid oid in eku.EnhancedKeyUsages) + { + if (oid?.Value?.StartsWith("1.3.6.1.4.1.311.97.") == true) + { + return cert; + } + } + } + } + + // This should not happen but just in case. + throw new ItemNotFoundException("Failed to find leaf certificate in Azure Trusted Signing collection."); + } +} diff --git a/src/OpenAuthenticode/ECDsaPrivateKey.cs b/src/OpenAuthenticode/ECDsaPrivateKey.cs index 22bc11d..a416fb6 100644 --- a/src/OpenAuthenticode/ECDsaPrivateKey.cs +++ b/src/OpenAuthenticode/ECDsaPrivateKey.cs @@ -5,6 +5,11 @@ namespace OpenAuthenticode; internal abstract class ECDsaPrivateKey : ECDsa { + public ECDsaPrivateKey(int keySize) + { + KeySizeValue = keySize; + } + public abstract byte[] SignHashCore(byte[] hash); public override byte[] SignHash(byte[] hash) => SignHashCore(hash); diff --git a/src/OpenAuthenticode/KeyProvider.cs b/src/OpenAuthenticode/KeyProvider.cs index 2584a03..50755b8 100644 --- a/src/OpenAuthenticode/KeyProvider.cs +++ b/src/OpenAuthenticode/KeyProvider.cs @@ -46,8 +46,8 @@ internal KeyProvider( DefaultHashAlgorithm = defaultHashAlgorithm; Key = keyType switch { - KeyType.RSA => new CachedRSAPrivateKey(this), - KeyType.ECDsa => new CachedECDsaPrivateKey(this), + KeyType.RSA => new CachedRSAPrivateKey(this, certificate.GetRSAPublicKey()!.KeySize), + KeyType.ECDsa => new CachedECDsaPrivateKey(this, certificate.GetECDsaPublicKey()!.KeySize), _ => throw new NotImplementedException(), }; } @@ -265,7 +265,7 @@ private sealed class CachedRSAPrivateKey : RSAPrivateKey { private readonly KeyProvider _provider; - public CachedRSAPrivateKey(KeyProvider provider) + public CachedRSAPrivateKey(KeyProvider provider, int keySize) : base(keySize) { _provider = provider; } @@ -278,7 +278,7 @@ private sealed class CachedECDsaPrivateKey : ECDsaPrivateKey { private readonly KeyProvider _provider; - public CachedECDsaPrivateKey(KeyProvider provider) + public CachedECDsaPrivateKey(KeyProvider provider, int keySize) : base(keySize) { _provider = provider; } diff --git a/src/OpenAuthenticode/LoadContext.cs b/src/OpenAuthenticode/LoadContext.cs index 9c0bb83..532e58e 100644 --- a/src/OpenAuthenticode/LoadContext.cs +++ b/src/OpenAuthenticode/LoadContext.cs @@ -1,10 +1,7 @@ using System.IO; using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.Loader; -[assembly: InternalsVisibleTo("OpenAuthenticode.Module")] - namespace OpenAuthenticode; public class LoadContext : AssemblyLoadContext diff --git a/src/OpenAuthenticode/OpenAuthenticode.csproj b/src/OpenAuthenticode/OpenAuthenticode.csproj index 8323da5..f8bc0a4 100644 --- a/src/OpenAuthenticode/OpenAuthenticode.csproj +++ b/src/OpenAuthenticode/OpenAuthenticode.csproj @@ -28,4 +28,9 @@ + + + + + diff --git a/src/OpenAuthenticode/RSAPrivateKey.cs b/src/OpenAuthenticode/RSAPrivateKey.cs index 2024140..e1bdb20 100644 --- a/src/OpenAuthenticode/RSAPrivateKey.cs +++ b/src/OpenAuthenticode/RSAPrivateKey.cs @@ -5,6 +5,11 @@ namespace OpenAuthenticode; internal abstract class RSAPrivateKey : RSA { + public RSAPrivateKey(int keySize) + { + KeySizeValue = keySize; + } + public abstract byte[] SignHashCore(byte[] hash, HashAlgorithmName hashAlgorithm); public override byte[] SignHash( diff --git a/tests/units/OpenAuthenticodeTests.csproj b/tests/units/OpenAuthenticodeTests.csproj new file mode 100644 index 0000000..808f8b5 --- /dev/null +++ b/tests/units/OpenAuthenticodeTests.csproj @@ -0,0 +1,37 @@ + + + + net8.0 + enable + + false + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + + + + + + + diff --git a/tests/units/SignatureHelperTests.cs b/tests/units/SignatureHelperTests.cs new file mode 100644 index 0000000..cd83032 --- /dev/null +++ b/tests/units/SignatureHelperTests.cs @@ -0,0 +1,27 @@ +using OpenAuthenticode; +using System; +using System.Management.Automation; +using System.Security.Cryptography.X509Certificates; +using Xunit; + +namespace OpenAuthenticodeTests; + +public static class SignatureHelperTests +{ + [Fact] + public static void TestFindCertificateWithEkuOid() + { + const string certChain = "30821E8A06092A864886F70D010702A0821E7B30821E770201013100300B06092A864886F70D010701A0821E5F308206B73082049FA0030201020213330000A76A3482697F7106D3BA00000000A76A300D06092A864886F70D01010C05003069310B3009060355040613025553311E301C060355040A13154D6963726F736F667420436F72706F726174696F6E313A3038060355040313314D6963726F736F667420456E746572707269736520494420566572696669636174696F6E20435320414F43204341203033301E170D3235303231323032333732395A170D3235303231353032333732395A306E31163014060355040B130D4A6F7264616E20426F7265616E31293027060355040A13206A626F7265616E3933686F746D61696C2E6F6E6D6963726F736F66742E636F6D31293027060355040313206A626F7265616E3933686F746D61696C2E6F6E6D6963726F736F66742E636F6D308201A2300D06092A864886F70D01010105000382018F003082018A02820181008FB8F0D9CEC0D96A2B29AF12787703D38FF65D8C799C2E7CF5F186D30E28652CB6607697B4397A424843CCFDAB5328FA309427E88571863F5BA2ADD1368A0D16EBB2A4CF8EDB4D1CC4016B701A3A6E563423B1C89BF9A8F24D0EA0C154EE38DBC3D5A65F142DC69A842059689FD7B79AC4F360540487C06E4EFABC52D5EA46C2A3B1F4F12ED981B6D0562C5AA272E33C172A03C39B37AD3D11E287A35D4893287D0007EE9A67D72CCEB8E7B61C1D6CD3CDBD64F2B7384C037F1652586F9675E9D55FFA29DF3DDB30E6C0C4CAB3CA38FE69C8AC676E155C161ADE7F51E225A6B3EBD6743F75E613A5B93E920EA8EF7AF203A0862D2FE11828AF79A728BC3920540BDC160426ED347CF576B18DB281C22E600083F2E5EDB5E464852E761CC9BBBD8A585EEF83A79DE5409C6B8DD6664A4712728BBADC0C1B63C37B2BBD3683D20FAA4DA0D7186C5F7011E60DCBF652CDB3967C0064F85C492A6C127E56DACEB809D75D8DB5C1571A12AA2EC9332FB1482AA1689C862842EDA05DDC5EAEC8167FAD0203010001A38201D1308201CD300C0603551D130101FF04023000300E0603551D0F0101FF040403020780303A0603551D250101FF0430302E06082B0601050507030306222B06010401823761010301C72F83FD2483BB5681902882FF5983842781B92182FD59301D0603551D0E0416041426D356DCA8C1C8B79159CE5DD2B936132FD72D9E301F0603551D23041830168014403A4AE5EF35B7CD34B0E8471BADBA9A90A3A58430780603551D1F0471306F306DA06BA0698667687474703A2F2F7777772E6D6963726F736F66742E636F6D2F706B696F70732F63726C2F4D6963726F736F6674253230456E74657270726973652532304944253230566572696669636174696F6E2532304353253230414F43253230434125323030332E63726C3081B606082B060105050701010481A93081A6307506082B060105050730028669687474703A2F2F7777772E6D6963726F736F66742E636F6D2F706B696F70732F63657274732F4D6963726F736F6674253230456E74657270726973652532304944253230566572696669636174696F6E2532304353253230414F43253230434125323030332E637274302D06082B060105050730018621687474703A2F2F6F6E656F6373702E6D6963726F736F66742E636F6D2F6F637370300D06092A864886F70D01010C050003820201009DE46FF262ABD303873B717204A279480209ED12714DF604A475A62C931D6B4E0A4CE036DD2A5DA24C67E1A543C13C559CBFD04FBC312B42EBC76F66C9AE531D3D8A275ECCF169005BAA236A7F4825C76E4C79B4E3D8BBF79FA1E3ABA196874071AD88E066854EBD65B850DE9BD2542D0DB0699E28A9D53F1C2ABBFC7E46F68485EE4E78A5CCBB3DAF746A242F97AEFFC9760DD65DB3E750D4E5A8D6D9DB9B8651480F799040EA1B0F724E03AA6A90AD9230C9768E51322749D5BE4C97A3F622C7D7D2C30CD7F3D9CEB00BA97993FF7A1E54D21AAC02EA4A1BA79E0DCB4C89C2E2320A1B6A575DA49D7852879F0175570DAC8DF9316D25CF6A8D8FCC6BC02AFF6C68BE14E7E29164EB467CA68F407E31F03F49CC856D8C869EFDFF74B39CB60A725BD0C0D31724F992E2A9A1A8DCD1A3E195AAA6A5749F8D1995EB1DBC3EA2203457EAB193C8E3E1DF7C8DAFCC3BC174A580DBDCC07A14DB2DBF53099255ABDC2057B86030DF4035E57412D28C3B046D17B3193351A70EA4A3A66071CA8AFDF651CDA136FFA9A0F8B8BEB3C5345D42FC8F3D0B7BCC2E3A234A3BADFA54EFF49F3D15D31FE29CBFAC8550000E24740B5D30A0AE87D33DC3325231D0D036DB960B106662E487D95861EFE762CCF5270DE88B3D17C2439D49BB01B1303387E06C461D01D7D91F3D4456476FBB3718723146CB3E25EF724137DA4B1BC95283394E2E308208B63082069EA0030201020213330000000C36A2493F62DEC1D200000000000C300D06092A864886F70D01010C05003078310B3009060355040613025553311E301C060355040A13154D6963726F736F667420436F72706F726174696F6E31493047060355040313404D6963726F736F667420456E7465727072697365204964656E7469747920566572696669636174696F6E20436F6465205369676E696E67205043412032303230301E170D3230303631383139313135335A170D3235303631383139313135335A3069310B3009060355040613025553311E301C060355040A13154D6963726F736F667420436F72706F726174696F6E313A3038060355040313314D6963726F736F667420456E746572707269736520494420566572696669636174696F6E20435320414F4320434120303330820222300D06092A864886F70D01010105000382020F003082020A0282020100A17131BB09FE507BEAC8BDAB62B228BD499C395269DA03AAEF387F95F4AB1FDC1B988115439B141080C11ECF0DB6443430E0E00BEFD27F2CAA8D1471DB17DE9477AE7CD288E2FE87489BDC0575122C7AF02DBD323DBB8F9D45C3706BF9B34D07AAFA7A445DC7DDD73D373BA6C5972610264CFEE42244A1D1FDF887742780080E8CBFB501520BC3164AD87541698E6D3E0ACADDA89E24B60E6B7FFEE2BF0E1F776DD3D576EC8C3456A94E8985DA10A75A8FA606550ADB4AE7199621F7C81A29471D2EDE51989F8AFC04932D40706372AB387A4691A9A85A989C19F52929683791F1C21E39F1D1C3272E42385C59795C48DD34947FF25B444B8FCBF70BD4E274520AFBBB9AC3A6DDBFF03B47FC55140B1AB521842F5B86BFF540832242B0694690442DAEEB468C17DF98A3495D84CFC04FFFF2291772B936C44DFDD82DE3A3F05C45DD7F99C7F07A050E4B281179D714B43772093C8D151F20072279E3DB0FE1EDA562A389BD08E921F4805E8218758DB410895EFBD207B721B23B79E6C1D3140F1A08FAB5CAF57CCB5D297941BAC6898F9F19F3AEDC7D9B8531713D2531E02C7A724D436238270768DDD2DA4C5C913AEC42107B588B8BB952FD8DFE1AE7EB01D8A10DBCC9D7DAAB46996781674417E5A5DD840952498A0038CE697485BB081E90B0BBD5817DFBD2CCBD48ADB0041D2B15DC830991DBD6545905F0E54E658BB6430203010001A382034630820342300E0603551D0F0101FF040403020186301006092B06010401823715010403020100301D0603551D0E04160414403A4AE5EF35B7CD34B0E8471BADBA9A90A3A58430540603551D20044D304B30490604551D20003041303F06082B060105050702011633687474703A2F2F7777772E6D6963726F736F66742E636F6D2F706B696F70732F446F63732F5265706F7369746F72792E68746D301906092B0601040182371402040C1E0A0053007500620043004130120603551D130101FF040830060101FF020100301F0603551D230418301680146E77068FB1A795281C314F5F1556DED7BF4BBCB5308201040603551D1F0481FC3081F93081F6A081F3A081F08676687474703A2F2F7777772E6D6963726F736F66742E636F6D2F706B696F70732F63726C2F4D6963726F736F6674253230456E74657270726973652532304964656E74697479253230566572696669636174696F6E253230436F64652532305369676E696E67253230504341253230323032302E63726C8676687474703A2F2F63726C2E6D6963726F736F66742E636F6D2F706B696F70732F63726C2F4D6963726F736F6674253230456E74657270726973652532304964656E74697479253230566572696669636174696F6E253230436F64652532305369676E696E67253230504341253230323032302E63726C3082014F06082B06010505070101048201413082013D30818406082B060105050730028678687474703A2F2F7777772E6D6963726F736F66742E636F6D2F706B696F70732F63657274732F4D6963726F736F6674253230456E74657270726973652532304964656E74697479253230566572696669636174696F6E253230436F64652532305369676E696E67253230504341253230323032302E63727430818406082B060105050730028678687474703A2F2F63726C2E6D6963726F736F66742E636F6D2F706B696F70732F63657274732F4D6963726F736F6674253230456E74657270726973652532304964656E74697479253230566572696669636174696F6E253230436F64652532305369676E696E67253230504341253230323032302E637274302D06082B060105050730018621687474703A2F2F6F6E656F6373702E6D6963726F736F66742E636F6D2F6F637370300D06092A864886F70D01010C0500038202010080C6754338B9D6FF0D19C086772A4F127004F1012DC3EC4545004FB305C1E641AFAB1611FB52C4DAB13F846F10B28443CE6C5B544B6E76D8DAE49B8808A772441BBA3DE55307B681A395258033738F9EE0EBFAEE20FE8EAB9A178F630B485FC280717D38C067F87624AA3F2FD50DF683E5C322069D8BCA25E69455C7F7429B13280326A0D7A911F0091EF4CC1EC3A9ECF3AA2EB53A35C72E74A39A5ECAE0162E85952DFE6745A681356A3A6F1C66745E5751B967AB48CEA8D23D2238425DF600CB16C52B96966C3E3E002C660F4661D382E40D3D2A4F3757129A9F81065487FB700460903E2E4D906BC1E7D80D9A95309A0F76790ABEC0C8674F68CFAED5FD4F5F61C0126835E9ABE9D9038C1B9A1451961737B50DAD1DE8FEF26B29E3452F14E41CA87B8C384F2925EC6ACCD0ED1F6E3B602789BDBC85D65E9184CEEC545C9AD7D6D30960D7AA37A31747E1C0310FA0ECF3F49949718FFC102995FE460C1EA8CE1ED85FEAB2828ABC220766EFA744AE9CFA0415CCA268C7CFE7E9ACC277B60F2AF72838653102BEFABD5F6619C6F036733ED0766C2C3F2B56F6D3ACBDAAC718D9727D01A4D70A33AC563A8D7AAE0D952CB298B3166226C9C766A0A20DB9D556BE2D788B3BEBE60C53D44545E6C72B828B45B6B949D3F3D0F84EC3F7186372A839075106E9B2EFCD2222AF76AFE2CE30D166D2F3F25AA2AE1C3EC2BB5659E156308208FE308206E6A003020102021333000000020E127499BA83CEE1000000000002300D06092A864886F70D01010C0500308182310B3009060355040613025553311E301C060355040A13154D6963726F736F667420436F72706F726174696F6E315330510603550403134A4D6963726F736F667420456E7465727072697365204964656E7469747920566572696669636174696F6E20526F6F7420436572746966696361746520417574686F726974792032303230301E170D3230303530373139323135335A170D3335303530373139333135335A3078310B3009060355040613025553311E301C060355040A13154D6963726F736F667420436F72706F726174696F6E31493047060355040313404D6963726F736F667420456E7465727072697365204964656E7469747920566572696669636174696F6E20436F6465205369676E696E6720504341203230323030820222300D06092A864886F70D01010105000382020F003082020A0282020100B70898F6C56D65E7A5F63F7B61D48B9D3035365D84B18D9A45ABCAF76AD2BAA43447E246D02896F61904C987B84526EEE46B49C839E840D6CAF9EC3010E8406BB381FBEFC3F6C9670D6A1E657B9D847E15740B89B60CD6EB9D522EBBD336635A51AFF5A9516C5096638315BBEA1FBB5B4B63FAE0E3FBC1311C9D230B902BA8281A62A97F5A2131A478D9B5479A88242A3DCD70406E4C46D7FED2BA7623EB5269016F4C595A67E91745C70128DB0917D238A410E4FA649E693AD962FDE24CD4F249F95A0B627A2321860906DE8AB4998AAD56682C992E2EF52553FFF6727C2CCD425D526573913A704EFCC5647AB1AAE34EE103D010266C26B73C344B2520174D3339600F39A79B324ACD16FFF9444D5029D77D8D1398ECA06D956E2ED3DF913951EC8F5BA8B0F34C6072E1EE14DBB49B6ABAC6E0BBDAFFB94DB8ACBB4CDE8DD657B79C784D1B52A1B1BCB3B44A1DC613398A9E9970DFBE73351CFEBB5B6972ADEAA39FCCAC131802FD77E9F46AD210FD8CA110C8E47A2C0016DBC4F3FFC17C5E65602DE127FB824763457D314262CFD5606AD66A84F319811241FC4CCBB308E967521E3DA75AB4113813ED06DE6C0A168606C24333F3550A8F2C163B21EEC7553009CC5756A4DD7BA2B78593885A6650B1AEA236684645FC135CC6F8A953FEF37F1867842E4EAC4AA15947C1E9EDE48A7BB149CB9400E7FB6C4651877C1D88E50203010001A382037430820370300E0603551D0F0101FF040403020186301006092B06010401823715010403020100301D0603551D0E041604146E77068FB1A795281C314F5F1556DED7BF4BBCB530540603551D20044D304B30490604551D20003041303F06082B060105050702011633687474703A2F2F7777772E6D6963726F736F66742E636F6D2F706B696F70732F446F63732F5265706F7369746F72792E68746D301906092B0601040182371402040C1E0A00530075006200430041300F0603551D130101FF040530030101FF301F0603551D230418301680147F047D80310C0249EC46B4DDA26737EA59B0CE063082011F0603551D1F04820116308201123082010EA082010AA0820106868180687474703A2F2F7777772E6D6963726F736F66742E636F6D2F706B696F70732F63726C2F4D6963726F736F6674253230456E74657270726973652532304964656E74697479253230566572696669636174696F6E253230526F6F742532304365727469666963617465253230417574686F72697479253230323032302E63726C868180687474703A2F2F63726C2E6D6963726F736F66742E636F6D2F706B696F70732F63726C2F4D6963726F736F6674253230456E74657270726973652532304964656E74697479253230566572696669636174696F6E253230526F6F742532304365727469666963617465253230417574686F72697479253230323032302E63726C3082016506082B06010505070101048201573082015330818F06082B06010505073002868182687474703A2F2F7777772E6D6963726F736F66742E636F6D2F706B696F70732F63657274732F4D6963726F736F6674253230456E74657270726973652532304964656E74697479253230566572696669636174696F6E253230526F6F742532304365727469666963617465253230417574686F72697479253230323032302E637274302D06082B060105050730018621687474703A2F2F6F6E656F6373702E6D6963726F736F66742E636F6D2F6F63737030818F06082B06010505073002868182687474703A2F2F63726C2E6D6963726F736F66742E636F6D2F706B696F70732F63657274732F4D6963726F736F6674253230456E74657270726973652532304964656E74697479253230566572696669636174696F6E253230526F6F742532304365727469666963617465253230417574686F72697479253230323032302E637274300D06092A864886F70D01010C05000382020100438F4D26C4F194BEDBBB62881F5AF646F954A520E9E49483E390A281E261AF3A5696E00977D322F8CEF41E68A540674C506D1F3873C87DEEA8AAE4E2E9BA08554DAA6037865F914FE13125950479ACFFDE0E5B7827E4DCBC647C0D4359FCC1BA54065729B246CFFFEABFD9A959EF424EBD801701FC62D0C88C6F13DCDE49710DFCBEF3ECBB73CA8A84B8D6857C8BF7E162F579DF7EFAE059FB1779C1420A87ECF7F3E39AA9D8CD5C7C44FA0ABD750B030FE7A97B28646E54DE6CBEE43F1C04CFA2125447F80839CBBB081A02BDCD786AA9D8E284DBB6DA3A054D5454B21E170F4E1622E61BCAD15731EF49A5F63F3204BD194395DDD514B390F08B6CABC24EFA89BA31891E811C1414C54A879A69F35F877C2A94395EB29F2CAA0BC6C5EE8F3C73FB733ADFF04933D60D1D283D1337738ED6EF921D872B18F5D1469C78B40F44405C2A61CE1F3573194FB00BD6512C3FD833AB3A683ED07612E58147199E01CE98E61898207E2D518B96259F2838E2C90B9FFC3671AE574686540A90B1016890C2DE2505F62D5048D3A3D047615C5D690655BAAED27D2B538B88416FDC30BA8EF857802F6083C28FF4861DE750CABA421FBDCBFF21A988ED548D42E69B7AAA48C50B255C9930A0B7CC66A66E882C6C49D77C647544A3E8825D61FD5270D30E19C254CE2C99BCA5AC73D8AEECDDC6E54A5F12623DA5B022416801DCF876B0FEE2308205E4308203CCA0030201020210222AE57290958B904294F5CA2B064BA5300D06092A864886F70D01010C0500308182310B3009060355040613025553311E301C060355040A13154D6963726F736F667420436F72706F726174696F6E315330510603550403134A4D6963726F736F667420456E7465727072697365204964656E7469747920566572696669636174696F6E20526F6F7420436572746966696361746520417574686F726974792032303230301E170D3230303431363139303330395A170D3435303431363139313134345A308182310B3009060355040613025553311E301C060355040A13154D6963726F736F667420436F72706F726174696F6E315330510603550403134A4D6963726F736F667420456E7465727072697365204964656E7469747920566572696669636174696F6E20526F6F7420436572746966696361746520417574686F72697479203230323030820222300D06092A864886F70D01010105000382020F003082020A0282020100A22008048FDFDBCE1BF4D2144AF6B83870B929226FE1197205A97D05D1019A8A08EC83A7F6E9440C3420E086F46A70BD43843A96D9443C7DB7C8C0C9B5D441DE59F7C63A832316A84516922C289B3F36D2074E363999433E60555AE29581E8179A575952C71193E2D1688E6E45D11D619C785F0372A6E1F3B28D592BACEC4208C37478789F37993847B08EA8E3CB8BCF125B36DAC89F9887A6026D8575BA826F22DEFAF9A9BC7E1092C4B313E97D65D888E5C543AB84278D8D281B2A18644F541D7B3573FB3922A0F6F032E149FB8208F0A7079A1C4244A1365615A864FD1A6D52433577DD1C136D47AA45D1351FCA5713B2D071E66E8BAB29F176AA267B8F680429921FD7A9C90C8E724E592F511BE2C6EC15EA30117D92497E7B471F1BEA4969352306A152BCBE7B7B0EBCE823058CC3F025198B2A8218E209EBC0F4B9CA4C8605260242BD3A672AD2250AA6606F955267F00923E357C6AB61E294BF9819524C5BA8FCEE636E558A03B8C96B9DD8F2A98C94279642CE6D82678FBBC19CD61DC0E6F515B84FF2800D1384852CEA99279E5E3CFECD13AF0EA47DEA474815D817385BE02B05F3E6AA4D3F90C997DE8B96EE0DBE3F41FC3C9E16D50B817BEDFF95EA08F7162DA91D5E63C9D76C35CF53C4E0B62B249A81822BE62AC3D5B836568482CB8D67692000A214333FBE6048FDB8CB4E08DFA68415DD1E036A8A75A44DD90203010001A3543052300E0603551D0F0101FF040403020186300F0603551D130101FF040530030101FF301D0603551D0E041604147F047D80310C0249EC46B4DDA26737EA59B0CE06301006092B06010401823715010403020100300D06092A864886F70D01010C050003820201004261CC37CD17A41F591820A3BAFB68219CB206DFABEE1DD46D495130C8F22E4538E4D16D2EC55039989BC9B1C8DEF95346972949030676B5ABB6146AF264F5B15D17045319DE0142AE6510CAEA3BD480487208A68FEA119AE0CDF7432AF603D718FEA5103F25C85559BA54D63E6AD8B13544772AC030B9CE4216869352B8DF27535C38FBDD1C77110C26D870548E24E37ECB02D4A83D9AED87ED5FC71C08C4C23FA38CB438504542E92C7B87764561F16B5A93711826F593013345C51D022EFEF0F6D5272FCFFDD9F3AFE8CBCC8954064C8AE1D65B1E158C7399AF6DB605F9BCDFB4DDD40500E65FE95021003131157C584A7CB7B901502E291AEB6F2BEF9A45A5A655F0C8FBE316E8EFDCDF6EC072C61CB2CA8EB4F8867D00C62274A2D31EC3EB15F3C745A266D9C08C22C2B5A3662C88C63B2C99D67F8E130DBAB9490B86A36C41C96624869E52A92636EE2710AE8DB7DFAE3FB5B62299C4964F945502AEDA31376D68835C9801F9B4D618BEB99DD00A1C5A501361713560731AB16854C23249D3BD10026EB5D6F151A5F35567F06F5C09B7BE2D86A299656234A0B1D24DB00640A2051C0C2C687BB429EF72A6AAD6669BC9326DEC9E06B226E45D91C2DBA21FCB1F9735A80EA10688858E24FDCA3F97EE451491A964E71F70C9EA9C93800430973D895EAC167A15E0C3ACA67CA4AE537655F1ED14517D2F77B3E512F62BAD3100"; + X509Certificate2Collection collection = []; + collection.Import(Convert.FromHexString(certChain)); + + X509Certificate2 actual = CertificateHelper.GetAzureTrustedSigningCertificate(collection); + Assert.Equal("CN=jborean93hotmail.onmicrosoft.com, O=jborean93hotmail.onmicrosoft.com, OU=Jordan Borean", actual.Subject); + } + + [Fact] + public static void TestFailToFindCertificate() + { + Assert.Throws(() => CertificateHelper.GetAzureTrustedSigningCertificate([])); + } +}