#443 Remove custom certificate validators.
This commit is contained in:
parent
ebcad24307
commit
2982d743d8
|
|
@ -2,7 +2,6 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Net.Http;
|
||||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
|
@ -63,7 +62,7 @@ namespace Microsoft.AspNet.Authentication.JwtBearer
|
|||
Options.MetadataAddress += ".well-known/openid-configuration";
|
||||
}
|
||||
|
||||
var httpClient = new HttpClient(ResolveHttpMessageHandler(Options));
|
||||
var httpClient = new HttpClient(Options.BackchannelHttpHandler ?? new HttpClientHandler());
|
||||
httpClient.Timeout = Options.BackchannelTimeout;
|
||||
httpClient.MaxResponseContentBufferSize = 1024 * 1024 * 10; // 10 MB
|
||||
|
||||
|
|
@ -80,28 +79,5 @@ namespace Microsoft.AspNet.Authentication.JwtBearer
|
|||
{
|
||||
return new JwtBearerAuthenticationHandler();
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Managed by caller")]
|
||||
private static HttpMessageHandler ResolveHttpMessageHandler(JwtBearerAuthenticationOptions options)
|
||||
{
|
||||
HttpMessageHandler handler = options.BackchannelHttpHandler ??
|
||||
#if DNX451
|
||||
new WebRequestHandler();
|
||||
// If they provided a validator, apply it or fail.
|
||||
if (options.BackchannelCertificateValidator != null)
|
||||
{
|
||||
// Set the cert validate callback
|
||||
var webRequestHandler = handler as WebRequestHandler;
|
||||
if (webRequestHandler == null)
|
||||
{
|
||||
throw new InvalidOperationException(Resources.Exception_ValidatorHandlerMismatch);
|
||||
}
|
||||
webRequestHandler.ServerCertificateValidationCallback = options.BackchannelCertificateValidator.Validate;
|
||||
}
|
||||
#else
|
||||
new HttpClientHandler();
|
||||
#endif
|
||||
return handler;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,18 +66,6 @@ namespace Microsoft.AspNet.Authentication.JwtBearer
|
|||
/// </summary>
|
||||
public TimeSpan BackchannelTimeout { get; set; } = TimeSpan.FromMinutes(1);
|
||||
|
||||
#if DNX451
|
||||
/// <summary>
|
||||
/// Gets or sets the a pinned certificate validator to use to validate the endpoints used
|
||||
/// when retrieving metadata.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The pinned certificate validator.
|
||||
/// </value>
|
||||
/// <remarks>If this property is null then the default certificate checks are performed,
|
||||
/// validating the subject name and if the signing chain is a trusted party.</remarks>
|
||||
public ICertificateValidator BackchannelCertificateValidator { get; set; }
|
||||
#endif
|
||||
/// <summary>
|
||||
/// Configuration provided directly by the developer. If provided, then MetadataAddress and the Backchannel properties
|
||||
/// will not be used. This information should not be updated during request processing.
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@
|
|||
"frameworks": {
|
||||
"dnx451": {
|
||||
"frameworkAssemblies": {
|
||||
"System.Net.Http.WebRequest": "",
|
||||
"System.Net.Http": ""
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ namespace Microsoft.AspNet.Authentication.OAuth
|
|||
Options.StateDataFormat = new PropertiesDataFormat(dataProtector);
|
||||
}
|
||||
|
||||
Backchannel = new HttpClient(ResolveHttpMessageHandler(Options));
|
||||
Backchannel = new HttpClient(Options.BackchannelHttpHandler ?? new HttpClientHandler());
|
||||
Backchannel.DefaultRequestHeaders.UserAgent.ParseAdd("Microsoft ASP.NET OAuth middleware");
|
||||
Backchannel.Timeout = Options.BackchannelTimeout;
|
||||
Backchannel.MaxResponseContentBufferSize = 1024 * 1024 * 10; // 10 MB
|
||||
|
|
@ -96,28 +96,5 @@ namespace Microsoft.AspNet.Authentication.OAuth
|
|||
{
|
||||
return new OAuthAuthenticationHandler<TOptions>(Backchannel);
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Managed by caller")]
|
||||
private static HttpMessageHandler ResolveHttpMessageHandler(OAuthAuthenticationOptions options)
|
||||
{
|
||||
HttpMessageHandler handler = options.BackchannelHttpHandler ??
|
||||
#if DNX451
|
||||
new WebRequestHandler();
|
||||
// If they provided a validator, apply it or fail.
|
||||
if (options.BackchannelCertificateValidator != null)
|
||||
{
|
||||
// Set the cert validate callback
|
||||
var webRequestHandler = handler as WebRequestHandler;
|
||||
if (webRequestHandler == null)
|
||||
{
|
||||
throw new InvalidOperationException(Resources.Exception_ValidatorHandlerMismatch);
|
||||
}
|
||||
webRequestHandler.ServerCertificateValidationCallback = options.BackchannelCertificateValidator.Validate;
|
||||
}
|
||||
#else
|
||||
new HttpClientHandler();
|
||||
#endif
|
||||
return handler;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,19 +42,6 @@ namespace Microsoft.AspNet.Authentication.OAuth
|
|||
/// </summary>
|
||||
public string UserInformationEndpoint { get; set; }
|
||||
|
||||
#if DNX451
|
||||
/// <summary>
|
||||
/// Gets or sets the a pinned certificate validator to use to validate the endpoints used
|
||||
/// in back channel communications belong to the auth provider.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The pinned certificate validator.
|
||||
/// </value>
|
||||
/// <remarks>If this property is null then the default certificate checks are performed,
|
||||
/// validating the subject name and if the signing chain is a trusted party.</remarks>
|
||||
public ICertificateValidator BackchannelCertificateValidator { get; set; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Get or sets the text that the user can display on a sign in user interface.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@
|
|||
"frameworks": {
|
||||
"dnx451": {
|
||||
"frameworkAssemblies": {
|
||||
"System.Net.Http.WebRequest": "",
|
||||
"System.Net.Http": ""
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ namespace Microsoft.AspNet.Authentication.OpenIdConnect
|
|||
Options.TokenValidationParameters.ValidAudience = Options.ClientId;
|
||||
}
|
||||
|
||||
Backchannel = new HttpClient(ResolveHttpMessageHandler(Options));
|
||||
Backchannel = new HttpClient(Options.BackchannelHttpHandler ?? new HttpClientHandler());
|
||||
Backchannel.DefaultRequestHeaders.UserAgent.ParseAdd("Microsoft ASP.NET OpenIdConnect middleware");
|
||||
Backchannel.Timeout = Options.BackchannelTimeout;
|
||||
Backchannel.MaxResponseContentBufferSize = 1024 * 1024 * 10; // 10 MB
|
||||
|
|
@ -149,29 +149,6 @@ namespace Microsoft.AspNet.Authentication.OpenIdConnect
|
|||
return new OpenIdConnectAuthenticationHandler(Backchannel);
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Managed by caller")]
|
||||
private static HttpMessageHandler ResolveHttpMessageHandler(OpenIdConnectAuthenticationOptions options)
|
||||
{
|
||||
var handler = options.BackchannelHttpHandler ??
|
||||
#if DNX451
|
||||
new WebRequestHandler();
|
||||
// If they provided a validator, apply it or fail.
|
||||
if (options.BackchannelCertificateValidator != null)
|
||||
{
|
||||
// Set the cert validate callback
|
||||
var webRequestHandler = handler as WebRequestHandler;
|
||||
if (webRequestHandler == null)
|
||||
{
|
||||
throw new InvalidOperationException(Resources.OIDCH_0102_Exception_ValidatorHandlerMismatch);
|
||||
}
|
||||
webRequestHandler.ServerCertificateValidationCallback = options.BackchannelCertificateValidator.Validate;
|
||||
}
|
||||
#else
|
||||
new HttpClientHandler();
|
||||
#endif
|
||||
return handler;
|
||||
}
|
||||
|
||||
private class StringSerializer : IDataSerializer<string>
|
||||
{
|
||||
public string Deserialize(byte[] data)
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ using System.Diagnostics.CodeAnalysis;
|
|||
using System.IdentityModel.Tokens;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Net.Http;
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.Http.Authentication;
|
||||
using Microsoft.Framework.Caching.Distributed;
|
||||
|
|
@ -66,18 +65,6 @@ namespace Microsoft.AspNet.Authentication.OpenIdConnect
|
|||
/// </summary>
|
||||
public string Authority { get; set; }
|
||||
|
||||
#if DNX451
|
||||
/// <summary>
|
||||
/// Gets or sets the a pinned certificate validator to use to validate the endpoints used
|
||||
/// when retrieving metadata.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The pinned certificate validator.
|
||||
/// </value>
|
||||
/// <remarks>If this property is null then the default certificate checks are performed,
|
||||
/// validating the subject name and if the signing chain is a trusted party.</remarks>
|
||||
public ICertificateValidator BackchannelCertificateValidator { get; set; }
|
||||
#endif
|
||||
/// <summary>
|
||||
/// The HttpMessageHandler used to retrieve metadata.
|
||||
/// This cannot be set at the same time as BackchannelCertificateValidator unless the value
|
||||
|
|
|
|||
|
|
@ -14,8 +14,7 @@
|
|||
"frameworks": {
|
||||
"dnx451": {
|
||||
"frameworkAssemblies": {
|
||||
"System.Net.Http": "",
|
||||
"System.Net.Http.WebRequest": ""
|
||||
"System.Net.Http": ""
|
||||
}
|
||||
},
|
||||
"dnxcore50": {
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ namespace Microsoft.AspNet.Authentication.Twitter
|
|||
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, "SignInScheme"));
|
||||
}
|
||||
|
||||
_httpClient = new HttpClient(ResolveHttpMessageHandler(Options));
|
||||
_httpClient = new HttpClient(Options.BackchannelHttpHandler ?? new HttpClientHandler());
|
||||
_httpClient.Timeout = Options.BackchannelTimeout;
|
||||
_httpClient.MaxResponseContentBufferSize = 1024 * 1024 * 10; // 10 MB
|
||||
_httpClient.DefaultRequestHeaders.Accept.ParseAdd("*/*");
|
||||
|
|
@ -90,28 +90,5 @@ namespace Microsoft.AspNet.Authentication.Twitter
|
|||
{
|
||||
return new TwitterAuthenticationHandler(_httpClient);
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Managed by caller")]
|
||||
private static HttpMessageHandler ResolveHttpMessageHandler(TwitterAuthenticationOptions options)
|
||||
{
|
||||
var handler = options.BackchannelHttpHandler ??
|
||||
#if DNX451
|
||||
new WebRequestHandler();
|
||||
// If they provided a validator, apply it or fail.
|
||||
if (options.BackchannelCertificateValidator != null)
|
||||
{
|
||||
// Set the cert validate callback
|
||||
var webRequestHandler = handler as WebRequestHandler;
|
||||
if (webRequestHandler == null)
|
||||
{
|
||||
throw new InvalidOperationException(Resources.Exception_ValidatorHandlerMismatch);
|
||||
}
|
||||
webRequestHandler.ServerCertificateValidationCallback = options.BackchannelCertificateValidator.Validate;
|
||||
}
|
||||
#else
|
||||
new HttpClientHandler();
|
||||
#endif
|
||||
return handler;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNet.Http;
|
||||
|
||||
namespace Microsoft.AspNet.Authentication.Twitter
|
||||
|
|
@ -22,16 +21,6 @@ namespace Microsoft.AspNet.Authentication.Twitter
|
|||
Caption = AuthenticationScheme;
|
||||
CallbackPath = new PathString("/signin-twitter");
|
||||
BackchannelTimeout = TimeSpan.FromSeconds(60);
|
||||
#if DNX451
|
||||
// Twitter lists its valid Subject Key Identifiers at https://dev.twitter.com/docs/security/using-ssl
|
||||
BackchannelCertificateValidator = new CertificateSubjectKeyIdentifierValidator(
|
||||
new[]
|
||||
{
|
||||
"A5EF0B11CEC04103A34A659048B21CE0572D7D47", // VeriSign Class 3 Secure Server CA - G2
|
||||
"0D445C165344C1827E1D20AB25F40163D8BE79A5", // VeriSign Class 3 Secure Server CA - G3
|
||||
"5F60CF619055DF8443148A602AB2F57AF44318EF", // Symantec Class 3 Secure Server CA - G4
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -53,18 +42,7 @@ namespace Microsoft.AspNet.Authentication.Twitter
|
|||
/// The back channel timeout.
|
||||
/// </value>
|
||||
public TimeSpan BackchannelTimeout { get; set; }
|
||||
#if DNX451
|
||||
/// <summary>
|
||||
/// Gets or sets the a pinned certificate validator to use to validate the endpoints used
|
||||
/// in back channel communications belong to Twitter.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The pinned certificate validator.
|
||||
/// </value>
|
||||
/// <remarks>If this property is null then the default certificate checks are performed,
|
||||
/// validating the subject name and if the signing chain is a trusted party.</remarks>
|
||||
public ICertificateValidator BackchannelCertificateValidator { get; set; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// The HttpMessageHandler used to communicate with Twitter.
|
||||
/// This cannot be set at the same time as BackchannelCertificateValidator unless the value
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@
|
|||
"frameworks": {
|
||||
"dnx451": {
|
||||
"frameworkAssemblies": {
|
||||
"System.Net.Http.WebRequest": "",
|
||||
"System.Net.Http": ""
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,81 +0,0 @@
|
|||
// 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.
|
||||
|
||||
#if DNX451
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Security;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
||||
namespace Microsoft.AspNet.Authentication
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides pinned certificate validation based on the subject key identifier of the certificate.
|
||||
/// </summary>
|
||||
public class CertificateSubjectKeyIdentifierValidator : ICertificateValidator
|
||||
{
|
||||
private readonly HashSet<string> _validSubjectKeyIdentifiers;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CertificateSubjectKeyIdentifierValidator"/> class.
|
||||
/// </summary>
|
||||
/// <param name="validSubjectKeyIdentifiers">A set of subject key identifiers which are valid for an HTTPS request.</param>
|
||||
public CertificateSubjectKeyIdentifierValidator([NotNull] IEnumerable<string> validSubjectKeyIdentifiers)
|
||||
{
|
||||
_validSubjectKeyIdentifiers = new HashSet<string>(validSubjectKeyIdentifiers, StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
if (_validSubjectKeyIdentifiers.Count == 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(validSubjectKeyIdentifiers));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies the remote Secure Sockets Layer (SSL) certificate used for authentication.
|
||||
/// </summary>
|
||||
/// <param name="sender">An object that contains state information for this validation.</param>
|
||||
/// <param name="certificate">The certificate used to authenticate the remote party.</param>
|
||||
/// <param name="chain">The chain of certificate authorities associated with the remote certificate.</param>
|
||||
/// <param name="sslPolicyErrors">One or more errors associated with the remote certificate.</param>
|
||||
/// <returns>A Boolean value that determines whether the specified certificate is accepted for authentication.</returns>
|
||||
public bool Validate(object sender, X509Certificate certificate, [NotNull] X509Chain chain, SslPolicyErrors sslPolicyErrors)
|
||||
{
|
||||
if (sslPolicyErrors != SslPolicyErrors.None)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (chain.ChainElements.Count < 2)
|
||||
{
|
||||
// Self signed.
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (var chainElement in chain.ChainElements)
|
||||
{
|
||||
string subjectKeyIdentifier = GetSubjectKeyIdentifier(chainElement.Certificate);
|
||||
if (string.IsNullOrEmpty(subjectKeyIdentifier))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_validSubjectKeyIdentifiers.Contains(subjectKeyIdentifier))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static string GetSubjectKeyIdentifier(X509Certificate2 certificate)
|
||||
{
|
||||
const string SubjectKeyIdentifierOid = "2.5.29.14";
|
||||
var extension = certificate.Extensions[SubjectKeyIdentifierOid] as X509SubjectKeyIdentifierExtension;
|
||||
|
||||
return extension == null ? null : extension.SubjectKeyIdentifier;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1,128 +0,0 @@
|
|||
// 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.
|
||||
|
||||
#if DNX451
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Net.Security;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Cryptography;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using Microsoft.Framework.Internal;
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace Microsoft.AspNet.Authentication
|
||||
{
|
||||
/// <summary>
|
||||
/// Implements a cert pinning validator passed on
|
||||
/// http://datatracker.ietf.org/doc/draft-ietf-websec-key-pinning/?include_text=1
|
||||
/// </summary>
|
||||
public class CertificateSubjectPublicKeyInfoValidator : ICertificateValidator
|
||||
{
|
||||
private readonly HashSet<string> _validBase64EncodedSubjectPublicKeyInfoHashes;
|
||||
|
||||
private readonly SubjectPublicKeyInfoAlgorithm _algorithm;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CertificateSubjectPublicKeyInfoValidator"/> class.
|
||||
/// </summary>
|
||||
/// <param name="validBase64EncodedSubjectPublicKeyInfoHashes">A collection of valid base64 encoded hashes of the certificate public key information blob.</param>
|
||||
/// <param name="algorithm">The algorithm used to generate the hashes.</param>
|
||||
public CertificateSubjectPublicKeyInfoValidator([NotNull] IEnumerable<string> validBase64EncodedSubjectPublicKeyInfoHashes, SubjectPublicKeyInfoAlgorithm algorithm)
|
||||
{
|
||||
_validBase64EncodedSubjectPublicKeyInfoHashes = new HashSet<string>(validBase64EncodedSubjectPublicKeyInfoHashes);
|
||||
|
||||
if (_validBase64EncodedSubjectPublicKeyInfoHashes.Count == 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(validBase64EncodedSubjectPublicKeyInfoHashes));
|
||||
}
|
||||
|
||||
if (_algorithm != SubjectPublicKeyInfoAlgorithm.Sha1 && _algorithm != SubjectPublicKeyInfoAlgorithm.Sha256)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(algorithm));
|
||||
}
|
||||
|
||||
_algorithm = algorithm;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates at least one SPKI hash is known.
|
||||
/// </summary>
|
||||
/// <param name="sender">An object that contains state information for this validation.</param>
|
||||
/// <param name="certificate">The certificate used to authenticate the remote party.</param>
|
||||
/// <param name="chain">The chain of certificate authorities associated with the remote certificate.</param>
|
||||
/// <param name="sslPolicyErrors">One or more errors associated with the remote certificate.</param>
|
||||
/// <returns>A Boolean value that determines whether the specified certificate is accepted for authentication.</returns>
|
||||
public bool Validate(object sender, X509Certificate certificate, [NotNull] X509Chain chain, SslPolicyErrors sslPolicyErrors)
|
||||
{
|
||||
if (sslPolicyErrors != SslPolicyErrors.None)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (chain.ChainElements.Count < 2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
using (HashAlgorithm algorithm = CreateHashAlgorithm())
|
||||
{
|
||||
foreach (var chainElement in chain.ChainElements)
|
||||
{
|
||||
X509Certificate2 chainedCertificate = chainElement.Certificate;
|
||||
string base64Spki = Convert.ToBase64String(algorithm.ComputeHash(ExtractSpkiBlob(chainedCertificate)));
|
||||
if (_validBase64EncodedSubjectPublicKeyInfoHashes.Contains(base64Spki))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static byte[] ExtractSpkiBlob(X509Certificate2 certificate)
|
||||
{
|
||||
// Get a native cert_context from the managed X590Certificate2 instance.
|
||||
var certContext = (NativeMethods.CERT_CONTEXT)Marshal.PtrToStructure(certificate.Handle, typeof(NativeMethods.CERT_CONTEXT));
|
||||
|
||||
// Pull the CERT_INFO structure from the context.
|
||||
var certInfo = (NativeMethods.CERT_INFO)Marshal.PtrToStructure(certContext.pCertInfo, typeof(NativeMethods.CERT_INFO));
|
||||
|
||||
// And finally grab the key information, public key, algorithm and parameters from it.
|
||||
NativeMethods.CERT_PUBLIC_KEY_INFO publicKeyInfo = certInfo.SubjectPublicKeyInfo;
|
||||
|
||||
// Now start encoding to ASN1.
|
||||
// First see how large the ASN1 representation is going to be.
|
||||
UInt32 blobSize = 0;
|
||||
var structType = new IntPtr(NativeMethods.X509_PUBLIC_KEY_INFO);
|
||||
if (!NativeMethods.CryptEncodeObject(NativeMethods.X509_ASN_ENCODING, structType, ref publicKeyInfo, null, ref blobSize))
|
||||
{
|
||||
int error = Marshal.GetLastWin32Error();
|
||||
throw new Win32Exception(error);
|
||||
}
|
||||
|
||||
// Allocate enough space.
|
||||
var blob = new byte[blobSize];
|
||||
|
||||
// Finally get the ASN1 representation.
|
||||
if (!NativeMethods.CryptEncodeObject(NativeMethods.X509_ASN_ENCODING, structType, ref publicKeyInfo, blob, ref blobSize))
|
||||
{
|
||||
int error = Marshal.GetLastWin32Error();
|
||||
throw new Win32Exception(error);
|
||||
}
|
||||
|
||||
return blob;
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Security.Cryptography", "CA5354:SHA1CannotBeUsed", Justification = "Only used to verify cert hashes.")]
|
||||
[SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Caller is responsible for disposal.")]
|
||||
private HashAlgorithm CreateHashAlgorithm()
|
||||
{
|
||||
return _algorithm == SubjectPublicKeyInfoAlgorithm.Sha1 ? (HashAlgorithm)new SHA1CryptoServiceProvider() : new SHA256CryptoServiceProvider();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
// 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.
|
||||
|
||||
#if DNX451
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Security;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
||||
namespace Microsoft.AspNet.Authentication
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides pinned certificate validation based on the certificate thumbprint.
|
||||
/// </summary>
|
||||
public class CertificateThumbprintValidator : ICertificateValidator
|
||||
{
|
||||
private readonly HashSet<string> _validCertificateThumbprints;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CertificateThumbprintValidator"/> class.
|
||||
/// </summary>
|
||||
/// <param name="validThumbprints">A set of thumbprints which are valid for an HTTPS request.</param>
|
||||
public CertificateThumbprintValidator([NotNull] IEnumerable<string> validThumbprints)
|
||||
{
|
||||
_validCertificateThumbprints = new HashSet<string>(validThumbprints, StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
if (_validCertificateThumbprints.Count == 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(validThumbprints));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates that the certificate thumbprints in the signing chain match at least one whitelisted thumbprint.
|
||||
/// </summary>
|
||||
/// <param name="sender">An object that contains state information for this validation.</param>
|
||||
/// <param name="certificate">The certificate used to authenticate the remote party.</param>
|
||||
/// <param name="chain">The chain of certificate authorities associated with the remote certificate.</param>
|
||||
/// <param name="sslPolicyErrors">One or more errors associated with the remote certificate.</param>
|
||||
/// <returns>A Boolean value that determines whether the specified certificate is accepted for authentication.</returns>
|
||||
public bool Validate(object sender, X509Certificate certificate, [NotNull] X509Chain chain, SslPolicyErrors sslPolicyErrors)
|
||||
{
|
||||
if (sslPolicyErrors != SslPolicyErrors.None)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (chain.ChainElements.Count < 2)
|
||||
{
|
||||
// Self signed.
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (var chainElement in chain.ChainElements)
|
||||
{
|
||||
string thumbprintToCheck = chainElement.Certificate.Thumbprint;
|
||||
|
||||
if (thumbprintToCheck == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_validCertificateThumbprints.Contains(thumbprintToCheck))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
// 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.
|
||||
|
||||
#if DNX451
|
||||
using System;
|
||||
using System.Net.Security;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
|
||||
namespace Microsoft.AspNet.Authentication
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface for providing pinned certificate validation, which checks HTTPS
|
||||
/// communication against a known good list of certificates to protect against
|
||||
/// compromised or rogue CAs issuing certificates for hosts without the
|
||||
/// knowledge of the host owner.
|
||||
/// </summary>
|
||||
public interface ICertificateValidator
|
||||
{
|
||||
/// <summary>
|
||||
/// Verifies the remote Secure Sockets Layer (SSL) certificate used for authentication.
|
||||
/// </summary>
|
||||
/// <param name="sender">An object that contains state information for this validation.</param>
|
||||
/// <param name="certificate">The certificate used to authenticate the remote party.</param>
|
||||
/// <param name="chain">The chain of certificate authorities associated with the remote certificate.</param>
|
||||
/// <param name="sslPolicyErrors">One or more errors associated with the remote certificate.</param>
|
||||
/// <returns>A Boolean value that determines whether the specified certificate is accepted for authentication.</returns>
|
||||
bool Validate(Object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1,123 +0,0 @@
|
|||
// 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;
|
||||
using System.Net.Security;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Authentication
|
||||
{
|
||||
public class CertificateSubjectKeyIdentifierValidatorTests
|
||||
{
|
||||
private static readonly X509Certificate2 SelfSigned = new X509Certificate2("selfSigned.cer");
|
||||
private static readonly X509Certificate2 Chained = new X509Certificate2("katanatest.redmond.corp.microsoft.com.cer");
|
||||
|
||||
// The Katana test cert has a valid full chain
|
||||
// katanatest.redmond.corp.microsoft.com -> MSIT Machine Auth CA2 -> Microsoft Internet Authority -> Baltimore CyberTrustRoot
|
||||
|
||||
private const string KatanaTestKeyIdentifier = "d964b2941aaf3e62761041b1f3db098edfa3270a";
|
||||
private const string MicrosoftInternetAuthorityKeyIdentifier = "2a4d97955d347e9db6e633be9c27c1707e67dbc1";
|
||||
|
||||
[Fact]
|
||||
public void ConstructorShouldNotThrowWithValidValues()
|
||||
{
|
||||
var instance = new CertificateSubjectKeyIdentifierValidator(new[] { string.Empty });
|
||||
|
||||
instance.ShouldNotBe(null);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ConstructorShouldThrownWhenTheValidHashEnumerableIsNull()
|
||||
{
|
||||
Should.Throw<ArgumentNullException>(() =>
|
||||
new CertificateSubjectKeyIdentifierValidator(null));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ValidatorShouldReturnFalseWhenSslPolicyErrorsIsRemoteCertificateChainErrors()
|
||||
{
|
||||
var instance = new CertificateSubjectKeyIdentifierValidator(new[] { string.Empty });
|
||||
bool result = instance.Validate(null, null, null, SslPolicyErrors.RemoteCertificateChainErrors);
|
||||
result.ShouldBe(false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ValidatorShouldReturnFalseWhenSslPolicyErrorsIsRemoteCertificateNameMismatch()
|
||||
{
|
||||
var instance = new CertificateSubjectKeyIdentifierValidator(new[] { string.Empty });
|
||||
bool result = instance.Validate(null, null, null, SslPolicyErrors.RemoteCertificateNameMismatch);
|
||||
result.ShouldBe(false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ValidatorShouldReturnFalseWhenSslPolicyErrorsIsRemoteCertificateNotAvailable()
|
||||
{
|
||||
var instance = new CertificateSubjectKeyIdentifierValidator(new[] { string.Empty });
|
||||
bool result = instance.Validate(null, null, null, SslPolicyErrors.RemoteCertificateNotAvailable);
|
||||
result.ShouldBe(false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ValidatorShouldReturnFalseWhenPassedASelfSignedCertificate()
|
||||
{
|
||||
var instance = new CertificateSubjectKeyIdentifierValidator(new[] { string.Empty });
|
||||
var certificateChain = new X509Chain();
|
||||
certificateChain.Build(SelfSigned);
|
||||
certificateChain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
|
||||
|
||||
bool result = instance.Validate(null, SelfSigned, certificateChain, SslPolicyErrors.None);
|
||||
|
||||
result.ShouldBe(false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ValidatorShouldReturnFalseWhenPassedATrustedCertificateWhichDoesNotHaveAWhitelistedSubjectKeyIdentifier()
|
||||
{
|
||||
var instance = new CertificateSubjectKeyIdentifierValidator(new[] { string.Empty });
|
||||
var certificateChain = new X509Chain();
|
||||
certificateChain.Build(Chained);
|
||||
certificateChain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
|
||||
|
||||
bool result = instance.Validate(null, Chained, certificateChain, SslPolicyErrors.None);
|
||||
|
||||
result.ShouldBe(false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ValidatorShouldReturnTrueWhenPassedATrustedCertificateWhichHasItsSubjectKeyIdentifierWhiteListed()
|
||||
{
|
||||
var instance = new CertificateSubjectKeyIdentifierValidator(
|
||||
new[]
|
||||
{
|
||||
KatanaTestKeyIdentifier
|
||||
});
|
||||
|
||||
var certificateChain = new X509Chain();
|
||||
certificateChain.Build(Chained);
|
||||
certificateChain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
|
||||
|
||||
bool result = instance.Validate(null, Chained, certificateChain, SslPolicyErrors.None);
|
||||
|
||||
result.ShouldBe(true);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ValidatorShouldReturnTrueWhenPassedATrustedCertificateWhichHasAChainElementSubjectKeyIdentifierWhiteListed()
|
||||
{
|
||||
var instance = new CertificateSubjectKeyIdentifierValidator(
|
||||
new[]
|
||||
{
|
||||
MicrosoftInternetAuthorityKeyIdentifier
|
||||
});
|
||||
var certificateChain = new X509Chain();
|
||||
certificateChain.Build(Chained);
|
||||
certificateChain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
|
||||
|
||||
bool result = instance.Validate(null, Chained, certificateChain, SslPolicyErrors.None);
|
||||
|
||||
result.ShouldBe(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,173 +0,0 @@
|
|||
// 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;
|
||||
using System.Net.Security;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Authentication
|
||||
{
|
||||
public class CertificateSubjectPublicKeyInfoValidatorTests
|
||||
{
|
||||
private static readonly X509Certificate2 SelfSigned = new X509Certificate2("selfSigned.cer");
|
||||
private static readonly X509Certificate2 Chained = new X509Certificate2("katanatest.redmond.corp.microsoft.com.cer");
|
||||
|
||||
// The Katana test cert has a valid full chain
|
||||
// katanatest.redmond.corp.microsoft.com -> MSIT Machine Auth CA2 -> Microsoft Internet Authority -> Baltimore CyberTrustRoot
|
||||
|
||||
// The following fingerprints were generated using the go program in appendix A of the Public Key Pinning Extension for HTTP
|
||||
// draft-ietf-websec-key-pinning-05
|
||||
|
||||
private const string KatanaTestSha1Hash = "xvNsCWwxvL3qsCYChZLiwNm1D6o=";
|
||||
private const string KatanaTestSha256Hash = "AhR1Y/xhxK2uD7YJ0xKUPq8tYrWm4+F7DgO2wUOqB+4=";
|
||||
|
||||
private const string MicrosoftInternetAuthoritySha1Hash = "Z3HnseSVDEPu5hZoj05/bBSnT/s=";
|
||||
private const string MicrosoftInternetAuthoritySha256Hash = "UQTPeq/Tlg/vLt2ijtl7qlMFBFkbGG9aAWJbQMOMWFg=";
|
||||
|
||||
[Fact]
|
||||
public void ConstructorShouldNotThrowWithValidValues()
|
||||
{
|
||||
var instance = new CertificateSubjectPublicKeyInfoValidator(new string[1], SubjectPublicKeyInfoAlgorithm.Sha1);
|
||||
|
||||
instance.ShouldNotBe(null);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ConstructorShouldThrownWhenTheValidHashEnumerableIsNull()
|
||||
{
|
||||
Should.Throw<ArgumentNullException>(() =>
|
||||
new CertificateSubjectPublicKeyInfoValidator(null, SubjectPublicKeyInfoAlgorithm.Sha1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ConstructorShouldThrowWhenTheHashEnumerableContainsNoHashes()
|
||||
{
|
||||
Should.Throw<ArgumentOutOfRangeException>(() =>
|
||||
new CertificateSubjectPublicKeyInfoValidator(new string[0], SubjectPublicKeyInfoAlgorithm.Sha1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ConstructorShouldThrowIfAnInvalidAlgorithmIsPassed()
|
||||
{
|
||||
Should.Throw<ArgumentOutOfRangeException>(() =>
|
||||
new CertificateSubjectPublicKeyInfoValidator(new string[0], (SubjectPublicKeyInfoAlgorithm)2));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ValidatorShouldReturnFalseWhenSslPolicyErrorsIsRemoteCertificateChainErrors()
|
||||
{
|
||||
var instance = new CertificateSubjectPublicKeyInfoValidator(new string[1], SubjectPublicKeyInfoAlgorithm.Sha1);
|
||||
bool result = instance.Validate(null, null, null, SslPolicyErrors.RemoteCertificateChainErrors);
|
||||
result.ShouldBe(false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ValidatorShouldReturnFalseWhenSslPolicyErrorsIsRemoteCertificateNameMismatch()
|
||||
{
|
||||
var instance = new CertificateSubjectPublicKeyInfoValidator(new string[1], SubjectPublicKeyInfoAlgorithm.Sha1);
|
||||
bool result = instance.Validate(null, null, null, SslPolicyErrors.RemoteCertificateNameMismatch);
|
||||
result.ShouldBe(false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ValidatorShouldReturnFalseWhenSslPolicyErrorsIsRemoteCertificateNotAvailable()
|
||||
{
|
||||
var instance = new CertificateSubjectPublicKeyInfoValidator(new string[1], SubjectPublicKeyInfoAlgorithm.Sha1);
|
||||
bool result = instance.Validate(null, null, null, SslPolicyErrors.RemoteCertificateNotAvailable);
|
||||
result.ShouldBe(false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ValidatorShouldReturnFalseWhenPassedASelfSignedCertificate()
|
||||
{
|
||||
var instance = new CertificateSubjectPublicKeyInfoValidator(new string[1], SubjectPublicKeyInfoAlgorithm.Sha1);
|
||||
var certificateChain = new X509Chain();
|
||||
certificateChain.Build(SelfSigned);
|
||||
certificateChain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
|
||||
|
||||
bool result = instance.Validate(null, SelfSigned, certificateChain, SslPolicyErrors.None);
|
||||
|
||||
result.ShouldBe(false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ValidatorShouldReturnFalseWhenPassedATrustedCertificateWhichDoesNotHaveAWhitelistedSha1Spki()
|
||||
{
|
||||
var instance = new CertificateSubjectPublicKeyInfoValidator(new string[1], SubjectPublicKeyInfoAlgorithm.Sha1);
|
||||
var certificateChain = new X509Chain();
|
||||
certificateChain.Build(Chained);
|
||||
certificateChain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
|
||||
|
||||
bool result = instance.Validate(null, Chained, certificateChain, SslPolicyErrors.None);
|
||||
|
||||
result.ShouldBe(false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ValidatorShouldReturnTrueWhenPassedATrustedCertificateWhichHasItsSha1SpkiWhiteListed()
|
||||
{
|
||||
var instance = new CertificateSubjectPublicKeyInfoValidator(new[] { KatanaTestSha1Hash }, SubjectPublicKeyInfoAlgorithm.Sha1);
|
||||
var certificateChain = new X509Chain();
|
||||
certificateChain.Build(Chained);
|
||||
certificateChain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
|
||||
|
||||
bool result = instance.Validate(null, Chained, certificateChain, SslPolicyErrors.None);
|
||||
|
||||
result.ShouldBe(true);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ValidatorShouldReturnTrueWhenPassedATrustedCertificateWhichHasAChainElementSha1SpkiWhiteListed()
|
||||
{
|
||||
var instance = new CertificateSubjectPublicKeyInfoValidator(new[] { MicrosoftInternetAuthoritySha1Hash }, SubjectPublicKeyInfoAlgorithm.Sha1);
|
||||
var certificateChain = new X509Chain();
|
||||
certificateChain.Build(Chained);
|
||||
certificateChain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
|
||||
|
||||
bool result = instance.Validate(null, Chained, certificateChain, SslPolicyErrors.None);
|
||||
|
||||
result.ShouldBe(true);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ValidatorShouldReturnFalseWhenPassedATrustedCertificateWhichDoesNotHaveAWhitelistedSha256Spki()
|
||||
{
|
||||
var instance = new CertificateSubjectPublicKeyInfoValidator(new string[1], SubjectPublicKeyInfoAlgorithm.Sha256);
|
||||
var certificateChain = new X509Chain();
|
||||
certificateChain.Build(Chained);
|
||||
certificateChain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
|
||||
|
||||
bool result = instance.Validate(null, Chained, certificateChain, SslPolicyErrors.None);
|
||||
|
||||
result.ShouldBe(false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ValidatorShouldReturnTrueWhenPassedATrustedCertificateWhichHasItsSha256SpkiWhiteListed()
|
||||
{
|
||||
var instance = new CertificateSubjectPublicKeyInfoValidator(new[] { KatanaTestSha256Hash }, SubjectPublicKeyInfoAlgorithm.Sha256);
|
||||
var certificateChain = new X509Chain();
|
||||
certificateChain.Build(Chained);
|
||||
certificateChain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
|
||||
|
||||
bool result = instance.Validate(null, Chained, certificateChain, SslPolicyErrors.None);
|
||||
|
||||
result.ShouldBe(true);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ValidatorShouldReturnTrueWhenPassedATrustedCertificateWhichHasAChainElementSha256SpkiWhiteListed()
|
||||
{
|
||||
var instance = new CertificateSubjectPublicKeyInfoValidator(new[] { MicrosoftInternetAuthoritySha256Hash }, SubjectPublicKeyInfoAlgorithm.Sha256);
|
||||
var certificateChain = new X509Chain();
|
||||
certificateChain.Build(Chained);
|
||||
certificateChain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
|
||||
|
||||
bool result = instance.Validate(null, Chained, certificateChain, SslPolicyErrors.None);
|
||||
|
||||
result.ShouldBe(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,121 +0,0 @@
|
|||
// 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;
|
||||
using System.Net.Security;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Authentication
|
||||
{
|
||||
public class CertificateThumbprintValidatorTests
|
||||
{
|
||||
private static readonly X509Certificate2 SelfSigned = new X509Certificate2("selfSigned.cer");
|
||||
private static readonly X509Certificate2 Chained = new X509Certificate2("katanatest.redmond.corp.microsoft.com.cer");
|
||||
|
||||
// The Katana test cert has a valid full chain
|
||||
// katanatest.redmond.corp.microsoft.com -> MSIT Machine Auth CA2 -> Microsoft Internet Authority -> Baltimore CyberTrustRoot
|
||||
|
||||
private const string KatanaTestThumbprint = "a9894c464b260cac3f5b91cece33b3c55e82e61c";
|
||||
private const string MicrosoftInternetAuthorityThumbprint = "992ad44d7dce298de17e6f2f56a7b9caa41db93f";
|
||||
|
||||
[Fact]
|
||||
public void ConstructorShouldNotThrowWithValidValues()
|
||||
{
|
||||
var instance = new CertificateThumbprintValidator(new string[1]);
|
||||
|
||||
instance.ShouldNotBe(null);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ConstructorShouldThrownWhenTheValidHashEnumerableIsNull()
|
||||
{
|
||||
Should.Throw<ArgumentNullException>(() =>
|
||||
new CertificateThumbprintValidator(null));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ConstructorShouldThrowWhenTheHashEnumerableContainsNoHashes()
|
||||
{
|
||||
Should.Throw<ArgumentOutOfRangeException>(() =>
|
||||
new CertificateThumbprintValidator(new string[0]));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ValidatorShouldReturnFalseWhenSslPolicyErrorsIsRemoteCertificateChainErrors()
|
||||
{
|
||||
var instance = new CertificateThumbprintValidator(new string[1]);
|
||||
bool result = instance.Validate(null, null, null, SslPolicyErrors.RemoteCertificateChainErrors);
|
||||
result.ShouldBe(false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ValidatorShouldReturnFalseWhenSslPolicyErrorsIsRemoteCertificateNameMismatch()
|
||||
{
|
||||
var instance = new CertificateThumbprintValidator(new string[1]);
|
||||
bool result = instance.Validate(null, null, null, SslPolicyErrors.RemoteCertificateNameMismatch);
|
||||
result.ShouldBe(false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ValidatorShouldReturnFalseWhenSslPolicyErrorsIsRemoteCertificateNotAvailable()
|
||||
{
|
||||
var instance = new CertificateThumbprintValidator(new string[1]);
|
||||
bool result = instance.Validate(null, null, null, SslPolicyErrors.RemoteCertificateNotAvailable);
|
||||
result.ShouldBe(false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ValidatorShouldReturnFalseWhenPassedASelfSignedCertificate()
|
||||
{
|
||||
var instance = new CertificateThumbprintValidator(new string[1]);
|
||||
var certificateChain = new X509Chain();
|
||||
certificateChain.Build(SelfSigned);
|
||||
certificateChain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
|
||||
|
||||
bool result = instance.Validate(null, SelfSigned, certificateChain, SslPolicyErrors.None);
|
||||
|
||||
result.ShouldBe(false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ValidatorShouldReturnFalseWhenPassedATrustedCertificateWhichDoesNotHaveAWhitelistedThumbprint()
|
||||
{
|
||||
var instance = new CertificateThumbprintValidator(new string[1]);
|
||||
var certificateChain = new X509Chain();
|
||||
certificateChain.Build(Chained);
|
||||
certificateChain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
|
||||
|
||||
bool result = instance.Validate(null, Chained, certificateChain, SslPolicyErrors.None);
|
||||
|
||||
result.ShouldBe(false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ValidatorShouldReturnTrueWhenPassedATrustedCertificateWhichHasItsThumbprintWhiteListed()
|
||||
{
|
||||
var instance = new CertificateThumbprintValidator(new[] { KatanaTestThumbprint });
|
||||
var certificateChain = new X509Chain();
|
||||
certificateChain.Build(Chained);
|
||||
certificateChain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
|
||||
|
||||
bool result = instance.Validate(null, Chained, certificateChain, SslPolicyErrors.None);
|
||||
|
||||
result.ShouldBe(true);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ValidatorShouldReturnTrueWhenPassedATrustedCertificateWhichHasAChainElementThumbprintWhiteListed()
|
||||
{
|
||||
var instance = new CertificateThumbprintValidator(new[] { MicrosoftInternetAuthorityThumbprint });
|
||||
var certificateChain = new X509Chain();
|
||||
certificateChain.Build(Chained);
|
||||
certificateChain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
|
||||
|
||||
bool result = instance.Validate(null, Chained, certificateChain, SslPolicyErrors.None);
|
||||
|
||||
result.ShouldBe(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -48,7 +48,6 @@ namespace Microsoft.AspNet.Authentication.Twitter
|
|||
return null;
|
||||
}
|
||||
};
|
||||
options.BackchannelCertificateValidator = null;
|
||||
},
|
||||
context =>
|
||||
{
|
||||
|
|
@ -123,7 +122,6 @@ namespace Microsoft.AspNet.Authentication.Twitter
|
|||
return null;
|
||||
}
|
||||
};
|
||||
options.BackchannelCertificateValidator = null;
|
||||
},
|
||||
context =>
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue