// Copyright (c) Microsoft Open Technologies, Inc. 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 { /// /// Provides pinned certificate validation based on the subject key identifier of the certificate. /// public class CertificateSubjectKeyIdentifierValidator : ICertificateValidator { private readonly HashSet _validSubjectKeyIdentifiers; /// /// Initializes a new instance of the class. /// /// A set of subject key identifiers which are valid for an HTTPS request. public CertificateSubjectKeyIdentifierValidator([NotNull] IEnumerable validSubjectKeyIdentifiers) { _validSubjectKeyIdentifiers = new HashSet(validSubjectKeyIdentifiers, StringComparer.OrdinalIgnoreCase); if (_validSubjectKeyIdentifiers.Count == 0) { throw new ArgumentOutOfRangeException("validSubjectKeyIdentifiers"); } } /// /// Verifies the remote Secure Sockets Layer (SSL) certificate used for authentication. /// /// An object that contains state information for this validation. /// The certificate used to authenticate the remote party. /// The chain of certificate authorities associated with the remote certificate. /// One or more errors associated with the remote certificate. /// A Boolean value that determines whether the specified certificate is accepted for authentication. 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.IsNullOrWhiteSpace(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