| File: System\Security\Cryptography\X509Certificates\ECDsaCertificateExtensions.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 Internal.Cryptography; namespace System.Security.Cryptography.X509Certificates { /// <summary> /// Provides extension methods for retrieving <see cref="ECDsa" /> implementations for the /// public and private keys of a <see cref="X509Certificate2" />. /// </summary> public static class ECDsaCertificateExtensions { /// <summary> /// Gets the <see cref="ECDsa" /> public key from the certificate or null if the certificate does not have an ECDsa public key. /// </summary> public static ECDsa? GetECDsaPublicKey(this X509Certificate2 certificate) { return certificate.GetPublicKey<ECDsa>(HasECDsaKeyUsage); } /// <summary> /// Gets the <see cref="ECDsa" /> private key from the certificate or null if the certificate does not have an ECDsa private key. /// </summary> public static ECDsa? GetECDsaPrivateKey(this X509Certificate2 certificate) { return certificate.GetPrivateKey<ECDsa>(HasECDsaKeyUsage); } public static X509Certificate2 CopyWithPrivateKey(this X509Certificate2 certificate, ECDsa privateKey) { ArgumentNullException.ThrowIfNull(certificate); ArgumentNullException.ThrowIfNull(privateKey); if (certificate.HasPrivateKey) throw new InvalidOperationException(SR.Cryptography_Cert_AlreadyHasPrivateKey); using (ECDsa? publicKey = GetECDsaPublicKey(certificate)) { if (publicKey == null) throw new ArgumentException(SR.Cryptography_PrivateKey_WrongAlgorithm); if (!Helpers.AreSamePublicECParameters(publicKey.ExportParameters(false), privateKey.ExportParameters(false))) { throw new ArgumentException(SR.Cryptography_PrivateKey_DoesNotMatch, nameof(privateKey)); } } ICertificatePal pal = certificate.Pal.CopyWithPrivateKey(privateKey); return new X509Certificate2(pal); } private static bool HasECDsaKeyUsage(X509Certificate2 certificate) { foreach (X509Extension extension in certificate.Extensions) { if (extension.Oid!.Value == Oids.KeyUsage) { X509KeyUsageExtension ext = (X509KeyUsageExtension)extension; if ((ext.KeyUsages & X509KeyUsageFlags.KeyAgreement) == 0) { // If this does not have KeyAgreement flag present, it cannot be ECDH // or ECMQV key as KeyAgreement is mandatory flag for ECDH or ECMQV (RFC 5480 Section 3). // // In that case, at this point, it is safe to assume it is ECDSA return true; } // Even if KeyAgreement was specified, if any of the signature uses was // specified then ECDSA is a valid usage. const X509KeyUsageFlags ecdsaFlags = X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.NonRepudiation | X509KeyUsageFlags.KeyCertSign | X509KeyUsageFlags.CrlSign; return ((ext.KeyUsages & ecdsaFlags) != 0); } } // If the key usage extension is not present in the certificate it is // considered valid for all usages, so we can use it for ECDSA. return true; } } }