From a3c157cb6117507428f5e2fce48035348051026f Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Fri, 7 Jul 2017 09:16:51 -0700 Subject: [PATCH] Validate certificate EKU when it is provided --- KestrelHttpServer.sln | 17 ++++- .../HttpsConnectionAdapter.cs | 50 +++++++++++++- .../HttpsConnectionAdapterOptions.cs | 5 ++ .../HttpsStrings.resx | 3 + .../Properties/AssemblyInfo.cs | 6 ++ .../Properties/HttpsStrings.Designer.cs | 14 ++++ ...spNetCore.Server.Kestrel.Core.Tests.csproj | 2 +- .../HttpsConnectionAdapterTests.cs | 62 ++++++++++++++++++ ...Core.Server.Kestrel.FunctionalTests.csproj | 2 +- test/shared/TestCertificates/eku.client.ini | 12 ++++ test/shared/TestCertificates/eku.client.pfx | Bin 0 -> 2317 bytes .../TestCertificates/eku.code_signing.ini | 12 ++++ .../TestCertificates/eku.code_signing.pfx | Bin 0 -> 2317 bytes .../TestCertificates/eku.multiple_usages.ini | 12 ++++ .../TestCertificates/eku.multiple_usages.pfx | Bin 0 -> 2325 bytes test/shared/TestCertificates/eku.server.ini | 12 ++++ test/shared/TestCertificates/eku.server.pfx | Bin 0 -> 2317 bytes .../TestCertificates/make-test-certs.sh | 62 ++++++++++++++++++ .../shared/TestCertificates/no_extensions.ini | 13 ++++ .../shared/TestCertificates/no_extensions.pfx | Bin 0 -> 2293 bytes .../testCert.pfx | Bin test/shared/TestResources.cs | 5 +- 22 files changed, 281 insertions(+), 8 deletions(-) create mode 100644 src/Microsoft.AspNetCore.Server.Kestrel.Https/Properties/AssemblyInfo.cs create mode 100644 test/shared/TestCertificates/eku.client.ini create mode 100644 test/shared/TestCertificates/eku.client.pfx create mode 100644 test/shared/TestCertificates/eku.code_signing.ini create mode 100644 test/shared/TestCertificates/eku.code_signing.pfx create mode 100644 test/shared/TestCertificates/eku.multiple_usages.ini create mode 100644 test/shared/TestCertificates/eku.multiple_usages.pfx create mode 100644 test/shared/TestCertificates/eku.server.ini create mode 100644 test/shared/TestCertificates/eku.server.pfx create mode 100755 test/shared/TestCertificates/make-test-certs.sh create mode 100644 test/shared/TestCertificates/no_extensions.ini create mode 100644 test/shared/TestCertificates/no_extensions.pfx rename test/shared/{TestResources => TestCertificates}/testCert.pfx (100%) diff --git a/KestrelHttpServer.sln b/KestrelHttpServer.sln index 56420c09fa..a5e8db2e49 100644 --- a/KestrelHttpServer.sln +++ b/KestrelHttpServer.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26621.2 +VisualStudioVersion = 15.0.26706.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{7972A5D6-3385-4127-9277-428506DD44FF}" ProjectSection(SolutionItems) = preProject @@ -52,9 +52,20 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.Kestrel.Performance", "test\Microsoft.AspNetCore.Server.Kestrel.Performance\Microsoft.AspNetCore.Server.Kestrel.Performance.csproj", "{EBFE9719-A44B-4978-A71F-D5C254E7F35A}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TestResources", "TestResources", "{2822C132-BFFB-4D53-AC5B-E7E47DD81A6E}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TestCertificates", "TestCertificates", "{2822C132-BFFB-4D53-AC5B-E7E47DD81A6E}" ProjectSection(SolutionItems) = preProject - test\shared\TestResources\testCert.pfx = test\shared\TestResources\testCert.pfx + test\shared\TestCertificates\eku.client.ini = test\shared\TestCertificates\eku.client.ini + test\shared\TestCertificates\eku.client.pfx = test\shared\TestCertificates\eku.client.pfx + test\shared\TestCertificates\eku.code_signing.ini = test\shared\TestCertificates\eku.code_signing.ini + test\shared\TestCertificates\eku.code_signing.pfx = test\shared\TestCertificates\eku.code_signing.pfx + test\shared\TestCertificates\eku.multiple_usages.ini = test\shared\TestCertificates\eku.multiple_usages.ini + test\shared\TestCertificates\eku.multiple_usages.pfx = test\shared\TestCertificates\eku.multiple_usages.pfx + test\shared\TestCertificates\eku.server.ini = test\shared\TestCertificates\eku.server.ini + test\shared\TestCertificates\eku.server.pfx = test\shared\TestCertificates\eku.server.pfx + test\shared\TestCertificates\make-test-certs.sh = test\shared\TestCertificates\make-test-certs.sh + test\shared\TestCertificates\no_extensions.ini = test\shared\TestCertificates\no_extensions.ini + test\shared\TestCertificates\no_extensions.pfx = test\shared\TestCertificates\no_extensions.pfx + test\shared\TestCertificates\testCert.pfx = test\shared\TestCertificates\testCert.pfx EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv", "src\Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv\Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.csproj", "{A76B8C8C-0DC5-4DD3-9B1F-02E51A0915F4}" diff --git a/src/Microsoft.AspNetCore.Server.Kestrel.Https/HttpsConnectionAdapter.cs b/src/Microsoft.AspNetCore.Server.Kestrel.Https/HttpsConnectionAdapter.cs index 5f17cfaf63..4cf33b1832 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel.Https/HttpsConnectionAdapter.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel.Https/HttpsConnectionAdapter.cs @@ -3,6 +3,7 @@ using System; using System.IO; +using System.Linq; using System.Net.Security; using System.Security.Cryptography.X509Certificates; using System.Threading.Tasks; @@ -15,9 +16,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Https { public class HttpsConnectionAdapter : IConnectionAdapter { + // See http://oid-info.com/get/1.3.6.1.5.5.7.3.1 + // Indicates that a certificate can be used as a SSL server certificate + private const string ServerAuthenticationOid = "1.3.6.1.5.5.7.3.1"; + private static readonly ClosedAdaptedConnection _closedAdaptedConnection = new ClosedAdaptedConnection(); private readonly HttpsConnectionAdapterOptions _options; + private readonly X509Certificate2 _serverCertificate; private readonly ILogger _logger; public HttpsConnectionAdapter(HttpsConnectionAdapterOptions options) @@ -37,6 +43,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Https throw new ArgumentException(HttpsStrings.ServiceCertificateRequired, nameof(options)); } + // capture the certificate now so it can be switched after validation + _serverCertificate = options.ServerCertificate; + + EnsureCertificateIsAllowedForServerAuth(_serverCertificate); + _options = options; _logger = loggerFactory?.CreateLogger(nameof(HttpsConnectionAdapter)); } @@ -100,7 +111,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Https try { - await sslStream.AuthenticateAsServerAsync(_options.ServerCertificate, certificateRequired, + await sslStream.AuthenticateAsServerAsync(_serverCertificate, certificateRequired, _options.SslProtocols, _options.CheckCertificateRevocation); } catch (IOException ex) @@ -119,6 +130,43 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Https return new HttpsAdaptedConnection(sslStream); } + private static void EnsureCertificateIsAllowedForServerAuth(X509Certificate2 certificate) + { + /* If the Extended Key Usage extension is included, then we check that the serverAuth usage is included. (http://oid-info.com/get/1.3.6.1.5.5.7.3.1) + * If the Extended Key Usage extension is not included, then we assume the certificate is allowed for all usages. + * + * See also https://blogs.msdn.microsoft.com/kaushal/2012/02/17/client-certificates-vs-server-certificates/ + * + * From https://tools.ietf.org/html/rfc3280#section-4.2.1.13 "Certificate Extensions: Extended Key Usage" + * + * If the (Extended Key Usage) extension is present, then the certificate MUST only be used + * for one of the purposes indicated. If multiple purposes are + * indicated the application need not recognize all purposes indicated, + * as long as the intended purpose is present. Certificate using + * applications MAY require that a particular purpose be indicated in + * order for the certificate to be acceptable to that application. + */ + + var hasEkuExtension = false; + + foreach (var extension in certificate.Extensions.OfType()) + { + hasEkuExtension = true; + foreach (var oid in extension.EnhancedKeyUsages) + { + if (oid.Value.Equals(ServerAuthenticationOid, StringComparison.Ordinal)) + { + return; + } + } + } + + if (hasEkuExtension) + { + throw new InvalidOperationException(HttpsStrings.FormatInvalidServerCertificateEku(certificate.Thumbprint)); + } + } + private static X509Certificate2 ConvertToX509Certificate2(X509Certificate certificate) { if (certificate == null) diff --git a/src/Microsoft.AspNetCore.Server.Kestrel.Https/HttpsConnectionAdapterOptions.cs b/src/Microsoft.AspNetCore.Server.Kestrel.Https/HttpsConnectionAdapterOptions.cs index d10fdbf23b..f09ea10bc1 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel.Https/HttpsConnectionAdapterOptions.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel.Https/HttpsConnectionAdapterOptions.cs @@ -23,7 +23,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Https } /// + /// /// Specifies the server certificate used to authenticate HTTPS connections. + /// + /// + /// If the server certificate has an Extended Key Usage extension, the usages must include Server Authentication (OID 1.3.6.1.5.5.7.3.1). + /// /// public X509Certificate2 ServerCertificate { get; set; } diff --git a/src/Microsoft.AspNetCore.Server.Kestrel.Https/HttpsStrings.resx b/src/Microsoft.AspNetCore.Server.Kestrel.Https/HttpsStrings.resx index d0745abab8..b7ab3141db 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel.Https/HttpsStrings.resx +++ b/src/Microsoft.AspNetCore.Server.Kestrel.Https/HttpsStrings.resx @@ -120,6 +120,9 @@ Failed to authenticate HTTPS connection. + + Certificate {thumbprint} cannot be used as an SSL server certificate. It has an Extended Key Usage extension but the usages do not include Server Authentication (OID 1.3.6.1.5.5.7.3.1). + The server certificate parameter is required. diff --git a/src/Microsoft.AspNetCore.Server.Kestrel.Https/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.Server.Kestrel.Https/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..3bb5150c92 --- /dev/null +++ b/src/Microsoft.AspNetCore.Server.Kestrel.Https/Properties/AssemblyInfo.cs @@ -0,0 +1,6 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Server.Kestrel.FunctionalTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] diff --git a/src/Microsoft.AspNetCore.Server.Kestrel.Https/Properties/HttpsStrings.Designer.cs b/src/Microsoft.AspNetCore.Server.Kestrel.Https/Properties/HttpsStrings.Designer.cs index 1b86a18e5d..03676ba6a7 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel.Https/Properties/HttpsStrings.Designer.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel.Https/Properties/HttpsStrings.Designer.cs @@ -24,6 +24,20 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Https internal static string FormatAuthenticationFailed() => GetString("AuthenticationFailed"); + /// + /// Certificate {thumbprint} cannot be used as an SSL server certificate. It has an Extended Key Usage extension but the usages do not include Server Authentication (OID 1.3.6.1.5.5.7.3.1). + /// + internal static string InvalidServerCertificateEku + { + get => GetString("InvalidServerCertificateEku"); + } + + /// + /// Certificate {thumbprint} cannot be used as an SSL server certificate. It has an Extended Key Usage extension but the usages do not include Server Authentication (OID 1.3.6.1.5.5.7.3.1). + /// + internal static string FormatInvalidServerCertificateEku(object thumbprint) + => string.Format(CultureInfo.CurrentCulture, GetString("InvalidServerCertificateEku", "thumbprint"), thumbprint); + /// /// The server certificate parameter is required. /// diff --git a/test/Microsoft.AspNetCore.Server.Kestrel.Core.Tests/Microsoft.AspNetCore.Server.Kestrel.Core.Tests.csproj b/test/Microsoft.AspNetCore.Server.Kestrel.Core.Tests/Microsoft.AspNetCore.Server.Kestrel.Core.Tests.csproj index d4f68d8023..5289c063ab 100644 --- a/test/Microsoft.AspNetCore.Server.Kestrel.Core.Tests/Microsoft.AspNetCore.Server.Kestrel.Core.Tests.csproj +++ b/test/Microsoft.AspNetCore.Server.Kestrel.Core.Tests/Microsoft.AspNetCore.Server.Kestrel.Core.Tests.csproj @@ -17,7 +17,7 @@ - + diff --git a/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/HttpsConnectionAdapterTests.cs b/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/HttpsConnectionAdapterTests.cs index 0f6b48097e..d75728f8f0 100644 --- a/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/HttpsConnectionAdapterTests.cs +++ b/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/HttpsConnectionAdapterTests.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Net; using System.Net.Http; using System.Net.Security; @@ -18,12 +19,19 @@ using Microsoft.AspNetCore.Server.Kestrel.Core; using Microsoft.AspNetCore.Server.Kestrel.Https; using Microsoft.AspNetCore.Testing; using Xunit; +using Xunit.Abstractions; namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests { public class HttpsConnectionAdapterTests { private static X509Certificate2 _x509Certificate2 = new X509Certificate2(TestResources.TestCertificatePath, "testPassword"); + private readonly ITestOutputHelper _output; + + public HttpsConnectionAdapterTests(ITestOutputHelper output) + { + _output = output; + } // https://github.com/aspnet/KestrelHttpServer/issues/240 // This test currently fails on mono because of an issue with SslStream. @@ -367,6 +375,60 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests } } + [Theory] + [InlineData("no_extensions.pfx")] + public void AcceptsCertificateWithoutExtensions(string testCertName) + { + var certPath = TestResources.GetCertPath(testCertName); + _output.WriteLine("Loading " + certPath); + var cert = new X509Certificate2(certPath, "testPassword"); + Assert.Empty(cert.Extensions.OfType()); + + new HttpsConnectionAdapter(new HttpsConnectionAdapterOptions + { + ServerCertificate = cert, + }); + } + + [Theory] + [InlineData("eku.server.pfx")] + [InlineData("eku.multiple_usages.pfx")] + public void ValidatesEnhancedKeyUsageOnCertificate(string testCertName) + { + var certPath = TestResources.GetCertPath(testCertName); + _output.WriteLine("Loading " + certPath); + var cert = new X509Certificate2(certPath, "testPassword"); + Assert.NotEmpty(cert.Extensions); + var eku = Assert.Single(cert.Extensions.OfType()); + Assert.NotEmpty(eku.EnhancedKeyUsages); + + new HttpsConnectionAdapter(new HttpsConnectionAdapterOptions + { + ServerCertificate = cert, + }); + } + + [Theory] + [InlineData("eku.code_signing.pfx")] + [InlineData("eku.client.pfx")] + public void ThrowsForCertificatesMissingServerEku(string testCertName) + { + var certPath = TestResources.GetCertPath(testCertName); + _output.WriteLine("Loading " + certPath); + var cert = new X509Certificate2(certPath, "testPassword"); + Assert.NotEmpty(cert.Extensions); + var eku = Assert.Single(cert.Extensions.OfType()); + Assert.NotEmpty(eku.EnhancedKeyUsages); + + var ex = Assert.Throws(() => + new HttpsConnectionAdapter(new HttpsConnectionAdapterOptions + { + ServerCertificate = cert, + })); + + Assert.Equal(HttpsStrings.FormatInvalidServerCertificateEku(cert.Thumbprint), ex.Message); + } + private static async Task App(HttpContext httpContext) { var request = httpContext.Request; diff --git a/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests.csproj b/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests.csproj index e96a61c766..9265ff3a69 100644 --- a/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests.csproj +++ b/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests.csproj @@ -16,7 +16,7 @@ - + diff --git a/test/shared/TestCertificates/eku.client.ini b/test/shared/TestCertificates/eku.client.ini new file mode 100644 index 0000000000..e2f2d8ab74 --- /dev/null +++ b/test/shared/TestCertificates/eku.client.ini @@ -0,0 +1,12 @@ +# See https://www.openssl.org/docs/man1.0.2/apps/req.html for details on file format + +[ req ] +prompt = no +distinguished_name = testdn + +[ testdn ] +commonName = testcertonly + +# see https://www.openssl.org/docs/man1.0.2/apps/x509v3_config.html +[ req_extensions ] +extendedKeyUsage = clientAuth diff --git a/test/shared/TestCertificates/eku.client.pfx b/test/shared/TestCertificates/eku.client.pfx new file mode 100644 index 0000000000000000000000000000000000000000..32c76a1928a22fbfd6b901b0fd4e74c696252a7b GIT binary patch literal 2317 zcmV+o3G((Zf(Z!%0Ru3C2+sxyDuzgg_YDCD0ic2izyyK_yfA_YxG;hPZw3h}hDe6@ z4FLxRpn?NnFoFYI0s#Opf&*0s2`Yw2hW8Bt2LUh~1_~;MNQU6vv zQ93pPI%1syX_30Jg6-gACGu-Pkr7LszMdREjFiKDBa-i#2%Hqnx;CrJGqPUbpB(0M zreXhKI0HI{G5<$zo!&f0U$x52jBJoL?gE)5_ zksb>J)UbVGIBou!r0Q_74>_ODum&dQb2E%s6CoUq?-4LTCSc8z8}0DG=1q5E6&m2oel7oxSbXs zGm5Z&G9Fxp8xn;vbi+9eml1$#dCYW1%Sf`}fw)TC*NYJiZxpd$vL|A^m)OkOXqflQ zfV&0YAY2CUfd13-wf~fv3j@lV0bJWZVV*w*BdRDcOZCA0MLV8#fVndT3tSWcY58;d zMX>=wDey-c?lhH(F@Z>HQ69uwzGc3_WpDn*{z;B)Q^8caHF>D{*70sXsp2_xy*3$$ ze)}YaC~zP3;K5aSRYPn(p0vfVnEAu(I8X{(H;xDDbPFF~$s+&%a*n#;PxjXxtc|-A zKJ@_%fH3e9XA)ctu$v0uwt9WPzz{#KZ>O!Y8xGoH!JqaRcQlnmXfcsMSC9mAwct>9 z>HGVMlFm+#L##S%2qlcGz^_3uvvKNfwCPf@i~=`*=@9M+;lof#k0aHQh9QX>p7ue} zn1}hi14NXReuJB&ZFPcGi1rzhD}J@TM6P4MH3&;->>qsQTJ|8UKZp}BL*jxkVU*}bEp%59z`Eb zYv}b69@?urh_#>qgfB^&7nf32R|~6qcPX0<$(w&g}ZLMahmnA~Dro*Z2K)n0-Wa>y225n&NFoFd^1_>&LNQUI+LPUxZMOOcE5SHpo?# zs)qg!%;0bj^`P2qVgw`n&^e(UD@w}G=Cp>vsKgnLu*Ml|HdR0AX(tMwgR-I4-8IvaD8Z(EXS6D&6>xZ7 z9sO&(X^&a`c|M|GE9SdN%mffo%-h7UlJDm?VM|b;^4gfm-H)H8KnYnn_=;@C8A42< zH2(HlIPs!ctUA3mpK7jcNFz2at{Qj)+EisU|AW%!glm!#GxDC^;iM$mvQ06|`zp&4A-dtN$B|~zOt{NT}q}9E{6X59!Y`!6Ny}RaW zjenQYV;S{5rx46DkB}FJEWY8~Pr%`p!W8f6jX7 z8H{Q*jeqh_bP4f7oqtltFi|-JdBx|^dd0aq^OX?f`d2%2vWcI#T0=*&)yj$F!hf+YOP*Ekg-av7Axk6tXz!IsbcXaHi||iX)Z|e1_@w@7g?{FQ zT=_eAe4T437Zx;H>L+y=^1$QRLJW$E@`ty_m&cv^v{!IIqV^xHdDl)AKG}=inEUgQ-*5I90$~RpEaJE%vVvaD>>7Sm0Jw7TewaFVZGs~%#xWPoPOFgxM z1(DG@S@R=<;~N1&C$Na|YVbV+Z@pG~%A&q=^DzgqVycArqAp_&YxDqde1t+6y+Py6Na6WDYU^;!R4Qy+f}vg&Ow9T&(uYcf+sY{Z{~t@tf7)_>UL1&I(^PR z(p3f$)p)r*qC-2lm&9-}n)sjUm~c3BO`k)b6x8uOMl(VFJ9+5`@Dyeq3Uzg?`@i^l zt?pja9GAZ_ilqOidUzKr`Mi-U$%O4cO=bd7`g5=A8VnbdvE{uVVBMj3AgqV~5 z?JdGpz%oUWZ?{d*JL>beQ-~U%(t=E*9YP|SA~7SbU@g2aZ8{)vy$;#`ucdd!#Lq8& zAT*(V#v$>pxJ|Y>N1-psH-oC~GCt(QYWZy2?ku+;T*`H2VjW(8>_9zJkF}hjydCCFLv|>Buxn(#ww*liLHP z?i?>vuK4CmNBeu2 literal 0 HcmV?d00001 diff --git a/test/shared/TestCertificates/eku.code_signing.ini b/test/shared/TestCertificates/eku.code_signing.ini new file mode 100644 index 0000000000..d6a6c118f6 --- /dev/null +++ b/test/shared/TestCertificates/eku.code_signing.ini @@ -0,0 +1,12 @@ +# See https://www.openssl.org/docs/man1.0.2/apps/req.html for details on file format + +[ req ] +prompt = no +distinguished_name = testdn + +[ testdn ] +commonName = testcertonly + +# see https://www.openssl.org/docs/man1.0.2/apps/x509v3_config.html +[ req_extensions ] +extendedKeyUsage = codeSigning diff --git a/test/shared/TestCertificates/eku.code_signing.pfx b/test/shared/TestCertificates/eku.code_signing.pfx new file mode 100644 index 0000000000000000000000000000000000000000..050dfd05feccca028d7fd2027f7a6705b7cd9f13 GIT binary patch literal 2317 zcmY+Ec{J3G9>!-g#%?A?DN81MF|y5!niiC;?1U+@43RBcW-Q}pouUycls#{WvSgA% zqq6T=#=cd^7Q*lp427o1k*A-9I4zhh_d`OD2c<9Pm!+N||b$&TaA50teH zH$#;T=LR>aqs8FEZ%bUXF`|u)2GpL5SUHHVqhkD>Qgz{D_Cc3?T~$ zttM%CnuQLLac8+()kF}Z`D@E=^Ow^P>U)*2tu^9b%zpaW_f8e$%GGbU$H%llxw1XY za68(nldQ4Ec0X4bso%8V4u>#0`?%;h>V#oDiONZN2?v`L3%oN-d#Ml`VVqBQOO*H= zT-PTmGizP4HRO^?TV|lN-oFp~UZksMj$6%E%$QQR>Vm#1q_FR3$suJE*ysc|CCr~d zbb1;%Y0;irHnW6p`SD_qi=e|t>=I|IY7D0iX~+u z=j_;g3_T<|*W%SvmGS_sCxY=>t3WAZUX>9P&zE(|qANb;8d($ScJ8`+hGbN@wuCb5 zr79oxN1H`vXd!6n0kynWemN1TtM!J|?QOMi!DF(*UkWVV;xR{q*CXnd;4N{iJd-IM zca(?5CMOnj^P^s8hL$a(RS$b=&@Ddto~)cI;+IY+y5-nY&V$1aeu(@?i5Raq6h40@ z!TFPNwD}>8ts? zWiIfx3-MKt0cr443dMDaN-l4fAm0#-b59)xY&H%Y%~>m7wwjR5)6ZEcv~!-5PJ7w= zY(t4D$t~pLK9qg%>kWQkDQdg6rwA>ah9Hg&_l}93ztbab)zQ7zUE=oK>F`L)&o99^ zocfZ*4<4pT0&3HDOit6jlf(kaTu$H4Gg3zGJQ4)BN0d7J8^=VI6LLpw9yG0}&l|t- zalMqXeHK@Fe97;;9o%u_elhbd*u7rgT*T88g9W(G{Et|<0M~ICz@_pVEB!t>INyIX z;{`)<0oXDYfX)A(eb7Jl5u_t70C;@JiZ$l3N3dQQHNkEV3e^`lpG zK4cU3@2c-8Z2R&pj|!wLVlV0ugDdX2aL0|}s?U_)#rvpqpb=jn9qYY2Rb;Q3@EQ|~ zUnF4=0wm+lt2VT*Rl4#*P+S#x|Dz`Fc=qiZ4QH-h$nMOH=0P@^&Ao8*K1|Pov^Luaqp1enx@zmQauxMpf849FXPQKI zd93=y6kgM=owjwV(Mc_EbPQ1PAFDI9^}DehRzR=D=pk03eAOfguMkK-cQ zI3)XpS`zE4KiHmi`WG!3|HyLq=DI=I#~QKD@U^jBTx#D!4&jH=Z1oHxmCUSDi7sWn zJ#3hl^xBTHyEg5Z5Kra$4q`9Ro9S+!%=i1jmnC42GCRg-4I{b;(uCG!~8(ifXL#Y^^Xnn z4~OzPb;j`gt?NQY!D&@0R9yg?HucQ7e0==q(_NVtwf9Kb@n^xH``^lBka4)CZb=L(w;<6QRkD z5D&4au3M`qsRc*EBc@fbS?Tl$C4-NG@aa>5{P718oUfs$_pPiI*(|sc!guA{%yqPd z6g_csfojqRg0I!M4?ajRYkCLevvs3LwrYh)_TRMb3&K=h0G{MoMshM4UUf>{LHe6# z3`@W2?|{nfbb*_4D}(BDHO`MjydAA$FYn&DeupVJ^g(^9-}h4mD)dPG=1F$B(k(6c zIb;_qo~!&GgyKu8*Iqd4PesIZu(oWW8+``7u5RTX*uA%bzN4YlT;_I5L| zB{We@7K{1sI`W9BpMNg l2KltYxJhZuC+0oF&sXK7Wz`E{2r&oAzo!KXxBjf;zW{|OLJ$A| literal 0 HcmV?d00001 diff --git a/test/shared/TestCertificates/eku.multiple_usages.ini b/test/shared/TestCertificates/eku.multiple_usages.ini new file mode 100644 index 0000000000..128af9a6fb --- /dev/null +++ b/test/shared/TestCertificates/eku.multiple_usages.ini @@ -0,0 +1,12 @@ +# See https://www.openssl.org/docs/man1.0.2/apps/req.html for details on file format + +[ req ] +prompt = no +distinguished_name = req_distinguished_name + +[ req_distinguished_name ] +commonName = testcertonly + +# see https://www.openssl.org/docs/man1.0.2/apps/x509v3_config.html +[ req_extensions ] +extendedKeyUsage = serverAuth,clientAuth diff --git a/test/shared/TestCertificates/eku.multiple_usages.pfx b/test/shared/TestCertificates/eku.multiple_usages.pfx new file mode 100644 index 0000000000000000000000000000000000000000..3bbbd9c0d43b2c1b79bd0f31b27a333865ebf47f GIT binary patch literal 2325 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 literal 0 HcmV?d00001 diff --git a/test/shared/TestCertificates/make-test-certs.sh b/test/shared/TestCertificates/make-test-certs.sh new file mode 100755 index 0000000000..e489408b1c --- /dev/null +++ b/test/shared/TestCertificates/make-test-certs.sh @@ -0,0 +1,62 @@ +#!/usr/bin/env bash + +# +# Should be obvious, but don't use the certs created here for anything real. This is just meant for our testing. +# + +set -euo pipefail + +__machine_has() { + hash "$1" > /dev/null 2>&1 + return $? +} + +# +# Main +# + +if ! __machine_has openssl; then + echo 'OpenSSL is required to create the test certificates.' 1>&2 + exit 1 +fi + +# See https://www.openssl.org/docs/man1.0.2/apps/x509.html for more details on the openssl conf file + +if [[ $# == 0 ]]; then + echo "Usage: ${BASH_SOURCE[0]} ..." + echo "" + echo "Arguments:" + echo " Multiple allowed. Path to the *.ini file that configures a cert." +fi + +# loop over all arguments +while [[ $# > 0 ]]; do + # bashism for trimming the extension + config=$1 + shift + cert_name="${config%.*}" + key="$cert_name.pem" + cert="$cert_name.crt" + pfx="$cert_name.pfx" + + echo "Creating cert $cert_name" + + # see https://www.openssl.org/docs/man1.0.2/apps/req.html + openssl req -x509 \ + -days 1 \ + -config $config \ + -nodes \ + -newkey rsa:2048 \ + -keyout $key \ + -extensions req_extensions \ + -out $cert + + # See https://www.openssl.org/docs/man1.0.2/apps/pkcs12.html + openssl pkcs12 -export \ + -in $cert \ + -inkey $key \ + -out $pfx \ + -password pass:testPassword # so secure ;) + + rm $key $cert +done diff --git a/test/shared/TestCertificates/no_extensions.ini b/test/shared/TestCertificates/no_extensions.ini new file mode 100644 index 0000000000..df234f06a6 --- /dev/null +++ b/test/shared/TestCertificates/no_extensions.ini @@ -0,0 +1,13 @@ +# See https://www.openssl.org/docs/man1.0.2/apps/req.html for details on file format + +[ req ] +prompt = no +distinguished_name = testdn + +[ testdn ] +commonName = testcertonly + +# see https://www.openssl.org/docs/man1.0.2/apps/x509v3_config.html +[ req_extensions ] +# keyUsages = +# extendedKeyUsage = diff --git a/test/shared/TestCertificates/no_extensions.pfx b/test/shared/TestCertificates/no_extensions.pfx new file mode 100644 index 0000000000000000000000000000000000000000..b4be4b5edaabdecc5de68d713b1981b259357733 GIT binary patch literal 2293 zcmVf0Ru3C2)70aDuzgg_YDCD0ic2is04xtq%eXApfG|1R|W|xhDe6@ z4FLxRpn?NPFoFX_0s#Opf&)DU2`Yw2hW8Bt2LUh~1_~;MNQU;tm*1VQHz2#;sA1IY@c8XwD!^~f{3Y7D-#rH_pg+cdU$P{TDi zo}lV%rN_525IKF01QN)PK=M%6TQdT~atf8{r&r2ShhN$`hMm3a;d(6k^mD%(+M8D<0M9k z%YkYVJ4RL`cW}Rcyx1=71OWQ$kwSHCt2S;$~m*;k)g}(s7 z1xo#AEYgjg7+6(Xys9(HLGKxB@TkYep0-|Y19?N;!ud?4jXf}1JzjrGq4@xD!w-1* zT3*}dv?kluCp*kP)Jx<(Xll8Kg|^!~OTGSaq>%Pb3b_^7^zu91mbCj-QshJGWi4h@ zG%x5osyj%pcn%zTu4p!LQH2ACbw(nY!9O{s$1l*96Ky}oEifkw2BefR)2`BlvKz5+ z!yA-1VFD0v8@AGeEn{E`PUvKux2^-1)aQ@;&LNQUJ802Lczvvq0Zz$v&DBg7~)V54)?&);BiYcMQu-=`DUHGAEj#|1%6-@#`Xse0)zr z1iTqfD<4$5_StZRb(U}bF$l)f#ZBBzJ9sw9z#iope~3oZ5Um=#U^~1PVKorO1E|M_aJ~k0VPC|+HRZ8V!&m% zRGTVVD0@5_=2BGb03tGy@+9!a*W>1gB(+30Ziw(F@UrJ*Qe8nj!)5W1~Q6MN2nwi{x?<(@5kJmcXi%8UGU z>vayIGnDoO@oN=R{WgJHyEo>wOOI=`eLhoX5iaoNvNDMg#do^JSRrV zsYsyv$U;8UgKWZu{Yss>2wGDy%NBOqn3aEP0McQZQ_O;plVO!`_tEj?55Ka z9O+g5VZgchIZU1KhXkiY`&RAeTRp+)y3Z>-;YxV!3Pk#jjD04-yCgS^qo+n&wlDes z?m&3x?F$+UrwFZ3NiW?LMF1&mBi78;ohlEdNb|P(7v~~sEz$D4~gK7R2dw#`N5z7SvwQt0h9hZbyf2tGGEOzd_r^jQUSp1qH5 z-~P2B^?pX>Sj+Fyg?bqDZgj;VNgY>{d%z)Q5P8?zF@GvGZ%LLhn2Y^oxM=OwN$gPv zii@C8g!V9qGvk-PI%bdZuGyfkQ-(G=Uz``yt^V&qSN@Qs$vF`%7T&y1{b^cDsLn@zz;PvEI%xLF2NRXFRs+1+>!F=tLl^&(;C9&x%Kh1Rk zkgRcBz)e3nu*@tJwL>KKI&zwRn6Et=uL`*urdR`q$`31u3h#HwHE*moH|k z_P<5OeJliQ^NcvS2-!B|Nrx`5ufa0{%o}$ zry8!4F&3VK4_)UNmP}o$W;5u~z=;x9?NmRqCv=RZglUNZI@?W~v(?1caUKLU(mbZ; zW?q8mOf(LWUJGWg;QsAH-+@f _testCertificatePath; + public static string TestCertificatePath { get; } = Path.Combine(_baseDir, "testCert.pfx"); + public static string GetCertPath(string name) => Path.Combine(_baseDir, name); } }