| File: System\Security\Cryptography\X509Certificates\FindPal.cs | Web Access |
| Project: src\runtime\src\libraries\System.Security.Cryptography\src\System.Security.Cryptography.csproj (System.Security.Cryptography) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; using System.Diagnostics; using System.Numerics; using Internal.Cryptography; namespace System.Security.Cryptography.X509Certificates { internal partial class FindPal { private const int NamedKeyUsageFlagsCount = 9; private static readonly Dictionary<string, X509KeyUsageFlags> s_keyUsages = new Dictionary<string, X509KeyUsageFlags>(NamedKeyUsageFlagsCount, StringComparer.OrdinalIgnoreCase) { { "DigitalSignature", X509KeyUsageFlags.DigitalSignature }, { "NonRepudiation", X509KeyUsageFlags.NonRepudiation }, { "KeyEncipherment", X509KeyUsageFlags.KeyEncipherment }, { "DataEncipherment", X509KeyUsageFlags.DataEncipherment }, { "KeyAgreement", X509KeyUsageFlags.KeyAgreement }, { "KeyCertSign", X509KeyUsageFlags.KeyCertSign }, { "CrlSign", X509KeyUsageFlags.CrlSign }, { "EncipherOnly", X509KeyUsageFlags.EncipherOnly }, { "DecipherOnly", X509KeyUsageFlags.DecipherOnly }, }; #if DEBUG static FindPal() { Debug.Assert(s_keyUsages.Count == NamedKeyUsageFlagsCount); } #endif private static partial IFindPal OpenPal( X509Certificate2Collection findFrom, X509Certificate2Collection copyTo, bool validOnly); public static X509Certificate2Collection FindFromCollection( X509Certificate2Collection coll, X509FindType findType, object findValue, bool validOnly) { X509Certificate2Collection results = new X509Certificate2Collection(); using (IFindPal findPal = OpenPal(coll, results, validOnly)) { switch (findType) { case X509FindType.FindByThumbprint: { byte[] thumbPrint = ConfirmedCast<string>(findValue).LaxDecodeHexString(); findPal.FindByThumbprint(thumbPrint); break; } case X509FindType.FindBySubjectName: { string subjectName = ConfirmedCast<string>(findValue); findPal.FindBySubjectName(subjectName); break; } case X509FindType.FindBySubjectDistinguishedName: { string subjectDistinguishedName = ConfirmedCast<string>(findValue); findPal.FindBySubjectDistinguishedName(subjectDistinguishedName); break; } case X509FindType.FindByIssuerName: { string issuerName = ConfirmedCast<string>(findValue); findPal.FindByIssuerName(issuerName); break; } case X509FindType.FindByIssuerDistinguishedName: { string issuerDistinguishedName = ConfirmedCast<string>(findValue); findPal.FindByIssuerDistinguishedName(issuerDistinguishedName); break; } case X509FindType.FindBySerialNumber: { string decimalOrHexString = ConfirmedCast<string>(findValue); // FindBySerialNumber allows the input format to be either in // hex or decimal. Since we can't know which one was intended, // it compares against both interpretations and treats a match // of either as a successful find. // string is big-endian byte[] hexBytes = decimalOrHexString.LaxDecodeHexString(); BigInteger hexValue = new BigInteger(hexBytes, isUnsigned: true, isBigEndian: true); BigInteger decimalValue = LaxParseDecimalBigInteger(decimalOrHexString); findPal.FindBySerialNumber(hexValue, decimalValue); break; } case X509FindType.FindByTimeValid: { DateTime dateTime = ConfirmedCast<DateTime>(findValue); findPal.FindByTimeValid(dateTime); break; } case X509FindType.FindByTimeNotYetValid: { DateTime dateTime = ConfirmedCast<DateTime>(findValue); findPal.FindByTimeNotYetValid(dateTime); break; } case X509FindType.FindByTimeExpired: { DateTime dateTime = ConfirmedCast<DateTime>(findValue); findPal.FindByTimeExpired(dateTime); break; } case X509FindType.FindByTemplateName: { string expected = ConfirmedCast<string>(findValue); findPal.FindByTemplateName(expected); break; } case X509FindType.FindByApplicationPolicy: { string oidValue = ConfirmedOidValue(findPal, findValue, OidGroup.Policy); findPal.FindByApplicationPolicy(oidValue); break; } case X509FindType.FindByCertificatePolicy: { string oidValue = ConfirmedOidValue(findPal, findValue, OidGroup.Policy); findPal.FindByCertificatePolicy(oidValue); break; } case X509FindType.FindByExtension: { string oidValue = ConfirmedOidValue(findPal, findValue, OidGroup.ExtensionOrAttribute); findPal.FindByExtension(oidValue); break; } case X509FindType.FindByKeyUsage: { X509KeyUsageFlags keyUsage = ConfirmedX509KeyUsage(findValue); findPal.FindByKeyUsage(keyUsage); break; } case X509FindType.FindBySubjectKeyIdentifier: { byte[] keyIdentifier = ConfirmedCast<string>(findValue).LaxDecodeHexString(); findPal.FindBySubjectKeyIdentifier(keyIdentifier); break; } default: throw new CryptographicException(SR.Cryptography_X509_InvalidFindType); } } return results; } private static T ConfirmedCast<T>(object findValue) { Debug.Assert(findValue != null); if (findValue.GetType() != typeof(T)) throw new CryptographicException(SR.Cryptography_X509_InvalidFindValue); return (T)findValue; } private static string ConfirmedOidValue(IFindPal findPal, object findValue, OidGroup oidGroup) { string maybeOid = ConfirmedCast<string>(findValue); if (maybeOid.Length == 0) { throw new ArgumentException(SR.Argument_InvalidOidValue); } return findPal.NormalizeOid(maybeOid, oidGroup); } private static X509KeyUsageFlags ConfirmedX509KeyUsage(object findValue) { if (findValue is X509KeyUsageFlags) return (X509KeyUsageFlags)findValue; if (findValue is int) return (X509KeyUsageFlags)(int)findValue; if (findValue is uint) return (X509KeyUsageFlags)(uint)findValue; if (findValue is string findValueString) { X509KeyUsageFlags usageFlags; if (s_keyUsages.TryGetValue(findValueString, out usageFlags)) { return usageFlags; } } throw new CryptographicException(SR.Cryptography_X509_InvalidFindValue); } // // verify the passed keyValue is valid as per X.208 // // The first number must be 0, 1 or 2. // Enforce all characters are digits and dots. // Enforce that no dot starts or ends the Oid, and disallow double dots. // Enforce there is at least one dot separator. // internal static void ValidateOidValue(string keyValue) { ArgumentNullException.ThrowIfNull(keyValue); int len = keyValue.Length; if (len < 2) throw new ArgumentException(SR.Argument_InvalidOidValue); // should not start with a dot. The first digit must be 0, 1 or 2. char c = keyValue[0]; if (c != '0' && c != '1' && c != '2') throw new ArgumentException(SR.Argument_InvalidOidValue); if (keyValue[1] != '.' || keyValue[len - 1] == '.') // should not end in a dot throw new ArgumentException(SR.Argument_InvalidOidValue); // While characters 0 and 1 were both validated, start at character 1 to validate // that there aren't two dots in a row. for (int i = 1; i < len; i++) { // ensure every character is either a digit or a dot if (char.IsDigit(keyValue[i])) continue; if (keyValue[i] != '.' || keyValue[i + 1] == '.') // disallow double dots throw new ArgumentException(SR.Argument_InvalidOidValue); } } private static BigInteger LaxParseDecimalBigInteger(string decimalString) { BigInteger ten = new BigInteger(10); BigInteger accum = BigInteger.Zero; foreach (char c in decimalString) { if (char.IsAsciiDigit(c)) { accum = BigInteger.Multiply(accum, ten); accum = BigInteger.Add(accum, c - '0'); } } return accum; } } }