diff --git a/src/Security/Authentication/Certificate/ref/Microsoft.AspNetCore.Authentication.Certificate.netcoreapp.cs b/src/Security/Authentication/Certificate/ref/Microsoft.AspNetCore.Authentication.Certificate.netcoreapp.cs index ecd78d5680..b158cdec1b 100644 --- a/src/Security/Authentication/Certificate/ref/Microsoft.AspNetCore.Authentication.Certificate.netcoreapp.cs +++ b/src/Security/Authentication/Certificate/ref/Microsoft.AspNetCore.Authentication.Certificate.netcoreapp.cs @@ -24,6 +24,8 @@ namespace Microsoft.AspNetCore.Authentication.Certificate { public CertificateAuthenticationOptions() { } public Microsoft.AspNetCore.Authentication.Certificate.CertificateTypes AllowedCertificateTypes { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } + public System.Security.Cryptography.X509Certificates.X509ChainTrustMode ChainTrustValidationMode { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } + public System.Security.Cryptography.X509Certificates.X509Certificate2Collection CustomTrustStore { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } public new Microsoft.AspNetCore.Authentication.Certificate.CertificateAuthenticationEvents Events { get { throw null; } set { } } public System.Security.Cryptography.X509Certificates.X509RevocationFlag RevocationFlag { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } public System.Security.Cryptography.X509Certificates.X509RevocationMode RevocationMode { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } diff --git a/src/Security/Authentication/Certificate/src/CertificateAuthenticationHandler.cs b/src/Security/Authentication/Certificate/src/CertificateAuthenticationHandler.cs index 68a7abdde0..a33b05ceb8 100644 --- a/src/Security/Authentication/Certificate/src/CertificateAuthenticationHandler.cs +++ b/src/Security/Authentication/Certificate/src/CertificateAuthenticationHandler.cs @@ -167,6 +167,15 @@ namespace Microsoft.AspNetCore.Authentication.Certificate chainPolicy.VerificationFlags |= X509VerificationFlags.IgnoreEndRevocationUnknown; chainPolicy.ExtraStore.Add(certificate); } + else + { + if (Options.CustomTrustStore != null) + { + chainPolicy.CustomTrustStore.AddRange(Options.CustomTrustStore); + } + + chainPolicy.TrustMode = Options.ChainTrustValidationMode; + } if (!Options.ValidateValidityPeriod) { diff --git a/src/Security/Authentication/Certificate/src/CertificateAuthenticationOptions.cs b/src/Security/Authentication/Certificate/src/CertificateAuthenticationOptions.cs index 1b8eebfa6f..70789514ac 100644 --- a/src/Security/Authentication/Certificate/src/CertificateAuthenticationOptions.cs +++ b/src/Security/Authentication/Certificate/src/CertificateAuthenticationOptions.cs @@ -15,10 +15,21 @@ namespace Microsoft.AspNetCore.Authentication.Certificate /// public CertificateTypes AllowedCertificateTypes { get; set; } = CertificateTypes.Chained; + /// + /// Collection of X509 certificates which are trusted components of the certificate chain. + /// + public X509Certificate2Collection CustomTrustStore { get; set; } = new X509Certificate2Collection(); + + /// + /// Method used to validate certificate chains against . + /// + /// This property must be set to to enable to be used in certificate chain validation. + public X509ChainTrustMode ChainTrustValidationMode { get; set; } = X509ChainTrustMode.System; + /// /// Flag indicating whether the client certificate must be suitable for client /// authentication, either via the Client Authentication EKU, or having no EKUs - /// at all. If the certificate chains to a root CA all certificates in the chain must be validate + /// at all. If the certificate chains to a root CA all certificates in the chain must be validated /// for the client authentication EKU. /// public bool ValidateCertificateUse { get; set; } = true; diff --git a/src/Security/Authentication/test/CertificateTests.cs b/src/Security/Authentication/test/CertificateTests.cs index 1ff4ffa58a..bd395c33ff 100644 --- a/src/Security/Authentication/test/CertificateTests.cs +++ b/src/Security/Authentication/test/CertificateTests.cs @@ -255,6 +255,51 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode); } + [Fact] + public async Task VerifyUntrustedClientCertEndsUpInForbidden() + { + var server = CreateServer( + new CertificateAuthenticationOptions + { + Events = successfulValidationEvents + }, Certificates.SignedClient); + + var response = await server.CreateClient().GetAsync("https://example.com/"); + Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode); + } + + [Fact] + public async Task VerifyClientCertWithUntrustedRootAndTrustedChainEndsUpInForbidden() + { + var server = CreateServer( + new CertificateAuthenticationOptions + { + Events = successfulValidationEvents, + CustomTrustStore = new X509Certificate2Collection() { Certificates.SignedSecondaryRoot }, + ChainTrustValidationMode = X509ChainTrustMode.CustomRootTrust, + RevocationMode = X509RevocationMode.NoCheck + }, Certificates.SignedClient); + + var response = await server.CreateClient().GetAsync("https://example.com/"); + Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode); + } + + [Fact] + public async Task VerifyValidClientCertWithTrustedChainAuthenticates() + { + var server = CreateServer( + new CertificateAuthenticationOptions + { + Events = successfulValidationEvents, + CustomTrustStore = new X509Certificate2Collection() { Certificates.SelfSignedPrimaryRoot, Certificates.SignedSecondaryRoot }, + ChainTrustValidationMode = X509ChainTrustMode.CustomRootTrust, + RevocationMode = X509RevocationMode.NoCheck + }, Certificates.SignedClient); + + var response = await server.CreateClient().GetAsync("https://example.com/"); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + } + [Fact] public async Task VerifyHeaderIsUsedIfCertIsNotPresent() { @@ -534,11 +579,13 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test { services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme).AddCertificate(options => { + options.CustomTrustStore = configureOptions.CustomTrustStore; + options.ChainTrustValidationMode = configureOptions.ChainTrustValidationMode; options.AllowedCertificateTypes = configureOptions.AllowedCertificateTypes; options.Events = configureOptions.Events; options.ValidateCertificateUse = configureOptions.ValidateCertificateUse; - options.RevocationFlag = options.RevocationFlag; - options.RevocationMode = options.RevocationMode; + options.RevocationFlag = configureOptions.RevocationFlag; + options.RevocationMode = configureOptions.RevocationMode; options.ValidateValidityPeriod = configureOptions.ValidateValidityPeriod; }); } @@ -599,6 +646,15 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test private static class Certificates { + public static X509Certificate2 SelfSignedPrimaryRoot { get; private set; } = + new X509Certificate2(GetFullyQualifiedFilePath("validSelfSignedPrimaryRootCertificate.cer")); + + public static X509Certificate2 SignedSecondaryRoot { get; private set; } = + new X509Certificate2(GetFullyQualifiedFilePath("validSignedSecondaryRootCertificate.cer")); + + public static X509Certificate2 SignedClient { get; private set; } = + new X509Certificate2(GetFullyQualifiedFilePath("validSignedClientCertificate.cer")); + public static X509Certificate2 SelfSignedValidWithClientEku { get; private set; } = new X509Certificate2(GetFullyQualifiedFilePath("validSelfSignedClientEkuCertificate.cer")); @@ -626,3 +682,4 @@ namespace Microsoft.AspNetCore.Authentication.Certificate.Test } } } + diff --git a/src/Security/Authentication/test/TestCertificates/validSelfSignedPrimaryRootCertificate.cer b/src/Security/Authentication/test/TestCertificates/validSelfSignedPrimaryRootCertificate.cer new file mode 100644 index 0000000000..a7420c8493 --- /dev/null +++ b/src/Security/Authentication/test/TestCertificates/validSelfSignedPrimaryRootCertificate.cer @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDPTCCAiWgAwIBAgIQTmWeCzG8SbRJ0y+osLWwDjANBgkqhkiG9w0BAQsFADAp +MScwJQYDVQQDDB5WYWxpZCBTZWxmIFNpZ25lZCBQcmltYXJ5IFJvb3QwHhcNMjAw +MTIxMDAwMDAwWhcNNDUwMTIxMDAwMDAwWjApMScwJQYDVQQDDB5WYWxpZCBTZWxm +IFNpZ25lZCBQcmltYXJ5IFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQDMK6v6HsJ19iRlXIRQVBJiy9xnJWBddLjm+2RRkyiiffEitBExiXVyrQ8L +DlegQQH3oJR0xgXwisJctjpHHz54dfbw5LwC9j9EVtu/UgDgK4lo6X3WLNYMJ1pX +xxjGfXcyzGGhcI0KATlyWhWgOrZNFzE+v0KY/LtZvcZ290Y4X7MQLge+V/09Lohx +pj6vsHkpoK8tD8ksJp+O8jk45TXTxs4yo8BRXbIv0oMmuZ9+gVkiaGurCCe/o+nw +vjEQre9oKNFI9KOgen6l1152BVQaXMDd22vemGIz738Scl9kcBQhy1D0dPuL6QV3 +rR8HoNG3i0cuYxB4xgFF5GY2fhQBAgMBAAGjYTBfMA4GA1UdDwEB/wQEAwIBhjAd +BgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAd +BgNVHQ4EFgQU/cAC4CkVEtEj2UCYMVS/mlFCdBAwDQYJKoZIhvcNAQELBQADggEB +AInTuEG8Kv2aWy7MJg/N/AvEmC7USMgTceFY+bKhVogYCE9m2VAa4Tz5DEEJwYQV +IBnEamQN1eWP/R7dxcg+gIck8TevZC6r7wKMUATCcn9Ti0I0Hxdplts9+YIksJJ7 +GbgyPS3UWnXl2D0374KrqTKSRjEXPOzaNyJ0HB4Pr9bibuSZ6Qc0gSltz7xOPFYS +7cedTqpABJXF6hZM7tDsxPfXmBHDy2sU84yXTQQghmU5S7fLWgy3so4g/DUqxffS +hmYPagc9DsmRGc2CCZz8IHlVc7byZ/NF4FgqB3IATbqYBAw4S/RyKHfWpURie2hC +OtYLcOTzVJG4uD3FGxyXP1k= +-----END CERTIFICATE----- diff --git a/src/Security/Authentication/test/TestCertificates/validSignedClientCertificate.cer b/src/Security/Authentication/test/TestCertificates/validSignedClientCertificate.cer new file mode 100644 index 0000000000..a8034b05a8 --- /dev/null +++ b/src/Security/Authentication/test/TestCertificates/validSignedClientCertificate.cer @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDTTCCAjWgAwIBAgIQaaZ/qIdm4K5JhFdDzzj53DANBgkqhkiG9w0BAQsFADAm +MSQwIgYDVQQDDBtWYWxpZCBTaWduZWQgU2Vjb25kYXJ5IFJvb3QwHhcNMjAwMTIx +MDAwMDAwWhcNMjIwMTIxMDAwMDAwWjAeMRwwGgYDVQQDDBNWYWxpZCBTaWduZWQg +Q2xpZW50MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu3dVA8q1GewW +i1K0Pw0gKqgv92RrX3JI6tTiLbU6FBpFdV63b1M3jgFhUSXJi7L8A/dxh2HwvKBJ +p+4KW7V+aXQXOY8iShQwrIud5IExFdtEjyGVtfFSvfYmDgbfjFKIGswxsLenlfEt +7mp303GH99JVFql1n7S+bib79vKkrjFBqixhnXisXjNlBlfH6kRBYiwQ1Gc5oyib +fZQkfakXo896UwIvQjc0W27c0tiGY6xyGLSesLih2yECADiGa+cc5rnRc7R9/IMB +N7o5gLpbe71WBopI1uq1VSuXwH9xy0bq307dZEMaX0b4SqhkuQHsBVtOV1mYAskE +K3W8VUZy7QIDAQABo38wfTAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYB +BQUHAwEGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUx9BZtKX7 +/z2mmoO2Ec127GkibsAwHQYDVR0OBBYEFDmtlIR/fVwtDseOG/NNQ/QEv3/PMA0G +CSqGSIb3DQEBCwUAA4IBAQBQMhsmlwF5JKEkfay7uLCH9IrJZGk1ZDxK/qcVaOk5 +mQ4IcCBq+Wp7Hg/D92b5diwlkXJDrYZZ7OHSEcD/PrxUKyZkoBQIvlNKDgmjp0wV +lXYUISZHaXbWZ0XNFAS0KyqoLZ8c2xmhuI21L3hyOoRcoqKleO1kzYfb2seBaRHk +Iu4la0opKGFoI/o7gC9uLrcizpj3SoPF9+vJz/FJmeBbKzKe1zA479a74tjfOODy +LZVbsGDhKRQ02GftFqXRl257hVX+6etQiOePj7S++R1B/QXRjvKrOTMs/NpMLAeK +8uWXSx+boL/8j/3u+65Udh614C5dXSrgDjMGJ7/OchC1 +-----END CERTIFICATE----- diff --git a/src/Security/Authentication/test/TestCertificates/validSignedSecondaryRootCertificate.cer b/src/Security/Authentication/test/TestCertificates/validSignedSecondaryRootCertificate.cer new file mode 100644 index 0000000000..ef31f31a98 --- /dev/null +++ b/src/Security/Authentication/test/TestCertificates/validSignedSecondaryRootCertificate.cer @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDXTCCAkWgAwIBAgIQE2HFYAdh7b5NSBsomRG9cjANBgkqhkiG9w0BAQsFADAp +MScwJQYDVQQDDB5WYWxpZCBTZWxmIFNpZ25lZCBQcmltYXJ5IFJvb3QwHhcNMjAw +MTIxMDAwMDAwWhcNMzUwMTIxMDAwMDAwWjAmMSQwIgYDVQQDDBtWYWxpZCBTaWdu +ZWQgU2Vjb25kYXJ5IFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQCw1Wvr8SeMdXM0ZMN3/NyZhGzXC/IcqJyI1tM1IQNpO9OxJWDkfxGh14ORRZ3f +4pTdXOXRCcPYxHk8d3kuH9EEo78WRrLV4XHw31vGrQkHAPn3ZMl/Qre1mYvzkKbn +DIpScfPYMuqydOvx1YSsTP2G37pNszOAXTkHPPH9smTo/W7Dv/1mnroAru/FU+Hv +zOMqNirIz1EpCEopLeBS41lcohyuCMzHPKJJZOnNbV3wV3AnpEriRLQVNO9WiaGs +Nwj8ffai9M4vncRQ9wLK866lx6iA7istjod9hourKQWC1284pv+RLtIeJaGrpXkV +mSbk9ebabz1fPC2/WgPtd1JVAgMBAAGjgYMwgYAwDgYDVR0PAQH/BAQDAgGGMB0G +A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAPBgNVHRMBAf8EBTADAQH/MB8G +A1UdIwQYMBaAFP3AAuApFRLRI9lAmDFUv5pRQnQQMB0GA1UdDgQWBBTH0Fm0pfv/ +Paaag7YRzXbsaSJuwDANBgkqhkiG9w0BAQsFAAOCAQEAT5fEUkVP3Allay2ODcjQ +GzM135mV718DS84B4bVDBWr+CW9i89bzYgRZgClTABqddotHEqmLEan/bV4suBSt +QuACy7m39Q8kj/S/ydBhvHx9fxqWnAsacQ+fuAPviBQ11UZB19zWj1zikw1/Xfow +V9OIf4gYtY2aBPyygWN3HwpszhJWQIuFGl4rwqAxli7Wp2eUBXxDtYBHAscsclG4 +1rduhiV5eUZXZ11mbA7KBH9XwWKoFpRza049I0WC+V0PWqlK4H4P0QzCWUlXmTC8 +kN04cnPtyciOlP9J3Uro5xTXaDC0Cge82JmRxnCovGKGBEdjIxMC4nbPB4emmcth +BA== +-----END CERTIFICATE----- diff --git a/src/Shared/test/Certificates/validSelfSignedPrimaryRootCertificate.cer b/src/Shared/test/Certificates/validSelfSignedPrimaryRootCertificate.cer new file mode 100644 index 0000000000..a7420c8493 --- /dev/null +++ b/src/Shared/test/Certificates/validSelfSignedPrimaryRootCertificate.cer @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDPTCCAiWgAwIBAgIQTmWeCzG8SbRJ0y+osLWwDjANBgkqhkiG9w0BAQsFADAp +MScwJQYDVQQDDB5WYWxpZCBTZWxmIFNpZ25lZCBQcmltYXJ5IFJvb3QwHhcNMjAw +MTIxMDAwMDAwWhcNNDUwMTIxMDAwMDAwWjApMScwJQYDVQQDDB5WYWxpZCBTZWxm +IFNpZ25lZCBQcmltYXJ5IFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQDMK6v6HsJ19iRlXIRQVBJiy9xnJWBddLjm+2RRkyiiffEitBExiXVyrQ8L +DlegQQH3oJR0xgXwisJctjpHHz54dfbw5LwC9j9EVtu/UgDgK4lo6X3WLNYMJ1pX +xxjGfXcyzGGhcI0KATlyWhWgOrZNFzE+v0KY/LtZvcZ290Y4X7MQLge+V/09Lohx +pj6vsHkpoK8tD8ksJp+O8jk45TXTxs4yo8BRXbIv0oMmuZ9+gVkiaGurCCe/o+nw +vjEQre9oKNFI9KOgen6l1152BVQaXMDd22vemGIz738Scl9kcBQhy1D0dPuL6QV3 +rR8HoNG3i0cuYxB4xgFF5GY2fhQBAgMBAAGjYTBfMA4GA1UdDwEB/wQEAwIBhjAd +BgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAd +BgNVHQ4EFgQU/cAC4CkVEtEj2UCYMVS/mlFCdBAwDQYJKoZIhvcNAQELBQADggEB +AInTuEG8Kv2aWy7MJg/N/AvEmC7USMgTceFY+bKhVogYCE9m2VAa4Tz5DEEJwYQV +IBnEamQN1eWP/R7dxcg+gIck8TevZC6r7wKMUATCcn9Ti0I0Hxdplts9+YIksJJ7 +GbgyPS3UWnXl2D0374KrqTKSRjEXPOzaNyJ0HB4Pr9bibuSZ6Qc0gSltz7xOPFYS +7cedTqpABJXF6hZM7tDsxPfXmBHDy2sU84yXTQQghmU5S7fLWgy3so4g/DUqxffS +hmYPagc9DsmRGc2CCZz8IHlVc7byZ/NF4FgqB3IATbqYBAw4S/RyKHfWpURie2hC +OtYLcOTzVJG4uD3FGxyXP1k= +-----END CERTIFICATE----- diff --git a/src/Shared/test/Certificates/validSignedClientCertificate.cer b/src/Shared/test/Certificates/validSignedClientCertificate.cer new file mode 100644 index 0000000000..a8034b05a8 --- /dev/null +++ b/src/Shared/test/Certificates/validSignedClientCertificate.cer @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDTTCCAjWgAwIBAgIQaaZ/qIdm4K5JhFdDzzj53DANBgkqhkiG9w0BAQsFADAm +MSQwIgYDVQQDDBtWYWxpZCBTaWduZWQgU2Vjb25kYXJ5IFJvb3QwHhcNMjAwMTIx +MDAwMDAwWhcNMjIwMTIxMDAwMDAwWjAeMRwwGgYDVQQDDBNWYWxpZCBTaWduZWQg +Q2xpZW50MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu3dVA8q1GewW +i1K0Pw0gKqgv92RrX3JI6tTiLbU6FBpFdV63b1M3jgFhUSXJi7L8A/dxh2HwvKBJ +p+4KW7V+aXQXOY8iShQwrIud5IExFdtEjyGVtfFSvfYmDgbfjFKIGswxsLenlfEt +7mp303GH99JVFql1n7S+bib79vKkrjFBqixhnXisXjNlBlfH6kRBYiwQ1Gc5oyib +fZQkfakXo896UwIvQjc0W27c0tiGY6xyGLSesLih2yECADiGa+cc5rnRc7R9/IMB +N7o5gLpbe71WBopI1uq1VSuXwH9xy0bq307dZEMaX0b4SqhkuQHsBVtOV1mYAskE +K3W8VUZy7QIDAQABo38wfTAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYB +BQUHAwEGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUx9BZtKX7 +/z2mmoO2Ec127GkibsAwHQYDVR0OBBYEFDmtlIR/fVwtDseOG/NNQ/QEv3/PMA0G +CSqGSIb3DQEBCwUAA4IBAQBQMhsmlwF5JKEkfay7uLCH9IrJZGk1ZDxK/qcVaOk5 +mQ4IcCBq+Wp7Hg/D92b5diwlkXJDrYZZ7OHSEcD/PrxUKyZkoBQIvlNKDgmjp0wV +lXYUISZHaXbWZ0XNFAS0KyqoLZ8c2xmhuI21L3hyOoRcoqKleO1kzYfb2seBaRHk +Iu4la0opKGFoI/o7gC9uLrcizpj3SoPF9+vJz/FJmeBbKzKe1zA479a74tjfOODy +LZVbsGDhKRQ02GftFqXRl257hVX+6etQiOePj7S++R1B/QXRjvKrOTMs/NpMLAeK +8uWXSx+boL/8j/3u+65Udh614C5dXSrgDjMGJ7/OchC1 +-----END CERTIFICATE----- diff --git a/src/Shared/test/Certificates/validSignedSecondaryRootCertificate.cer b/src/Shared/test/Certificates/validSignedSecondaryRootCertificate.cer new file mode 100644 index 0000000000..ef31f31a98 --- /dev/null +++ b/src/Shared/test/Certificates/validSignedSecondaryRootCertificate.cer @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDXTCCAkWgAwIBAgIQE2HFYAdh7b5NSBsomRG9cjANBgkqhkiG9w0BAQsFADAp +MScwJQYDVQQDDB5WYWxpZCBTZWxmIFNpZ25lZCBQcmltYXJ5IFJvb3QwHhcNMjAw +MTIxMDAwMDAwWhcNMzUwMTIxMDAwMDAwWjAmMSQwIgYDVQQDDBtWYWxpZCBTaWdu +ZWQgU2Vjb25kYXJ5IFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQCw1Wvr8SeMdXM0ZMN3/NyZhGzXC/IcqJyI1tM1IQNpO9OxJWDkfxGh14ORRZ3f +4pTdXOXRCcPYxHk8d3kuH9EEo78WRrLV4XHw31vGrQkHAPn3ZMl/Qre1mYvzkKbn +DIpScfPYMuqydOvx1YSsTP2G37pNszOAXTkHPPH9smTo/W7Dv/1mnroAru/FU+Hv +zOMqNirIz1EpCEopLeBS41lcohyuCMzHPKJJZOnNbV3wV3AnpEriRLQVNO9WiaGs +Nwj8ffai9M4vncRQ9wLK866lx6iA7istjod9hourKQWC1284pv+RLtIeJaGrpXkV +mSbk9ebabz1fPC2/WgPtd1JVAgMBAAGjgYMwgYAwDgYDVR0PAQH/BAQDAgGGMB0G +A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAPBgNVHRMBAf8EBTADAQH/MB8G +A1UdIwQYMBaAFP3AAuApFRLRI9lAmDFUv5pRQnQQMB0GA1UdDgQWBBTH0Fm0pfv/ +Paaag7YRzXbsaSJuwDANBgkqhkiG9w0BAQsFAAOCAQEAT5fEUkVP3Allay2ODcjQ +GzM135mV718DS84B4bVDBWr+CW9i89bzYgRZgClTABqddotHEqmLEan/bV4suBSt +QuACy7m39Q8kj/S/ydBhvHx9fxqWnAsacQ+fuAPviBQ11UZB19zWj1zikw1/Xfow +V9OIf4gYtY2aBPyygWN3HwpszhJWQIuFGl4rwqAxli7Wp2eUBXxDtYBHAscsclG4 +1rduhiV5eUZXZ11mbA7KBH9XwWKoFpRza049I0WC+V0PWqlK4H4P0QzCWUlXmTC8 +kN04cnPtyciOlP9J3Uro5xTXaDC0Cge82JmRxnCovGKGBEdjIxMC4nbPB4emmcth +BA== +-----END CERTIFICATE-----