3

I'm trying to validate certificate to make sure it has the right keyUsage. But don't see how I can specify my X509KeyUsageFlags.KeyEncypherment usage flag into this application policy.

This is the code I have so far. Any one else got this to work?

X509Certificate2 tmpCert = new X509Certificate2(Cert);

X509Chain ch = new X509Chain();
ch.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
ch.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority;

var kUsage = new System.Security.Cryptography.Oid("2.5.29.15");                    
ch.ChainPolicy.ApplicationPolicy.Add(kUsage);

bool success = ch.Build(tmpCert);
savagepanda
  • 857
  • 12
  • 25
  • umm, looking at Mono source code, it looks like this oid would only check for Certificate signing usage. Didn't see any where that we could add in which specific keyusage flags. – savagepanda Sep 21 '15 at 21:00

2 Answers2

5

KeyUsage extension is not a part of the chain, as there are no constraints to this extension. As the result, you need two separate procedures

  1. validate certificate chain
  2. validate single certificate(s) in the chain for other requirements.

The code provided by @Yacoub lacks an important outcome: when Key Usage extension is not presented in the certificate. In this case, the key is assumed to be valid for all usages, except certKeySign and cRLSign usages for all type of V3 certificates. In the case of V1 or V2 certificate, the absence of KeyUsage extension literally means all usages.

I would propose the following code:

using System.Linq;
using System.Security.Cryptography.X509Certificates;
// there should go namespace and class definition
...
//
public bool KeyUsageHasUsage(X509Certificate2 cert, X509KeyUsageFlags flag) {
    if (cert.Version < 3) { return true; }
    List<X509KeyUsageExtension> extensions = cert.Extensions.OfType<X509KeyUsageExtension>().ToList();
    if (!extensions.Any()) {
        return flag != X509KeyUsageFlags.CrlSign && flag != X509KeyUsageFlags.KeyCertSign;
    }
    return (extensions[0].KeyUsages & flag) > 0;
}

it is implemented as an universal function to validate arbitrary key usage flag.

Crypt32
  • 12,850
  • 2
  • 41
  • 70
  • Based on the information you provided: You are always returning true if version is less than 3. Shouldn't you check first if there is a key usage extension even if version is less than 3 and use it if there is? – Yacoub Massad Sep 22 '15 at 10:31
  • Certificate extensions introduced only in X.509v3 certificates. Version 1 and Version 2 were extensionless certificates, therefore there is no need to check for any extension in non-v3 certificates. – Crypt32 Sep 22 '15 at 17:44
  • 1
    Hey @Crypt32, I am investigating an issue related to this. Do you have a reference regarding the case where the KeyUsage extension is not present (in V3 of course)? I have looked into rfc5280, and I cannot find a description on how to interpret the key usage if the extension if not present. – Yacoub Massad Mar 23 '18 at 15:58
1

You can verify the chain manually as you are doing without the Key Encipherment check. Then, you can manually check if the certificate has a Key Encipherment usage.

Use the following code to check the key usage:

static public bool UsageHasKeyEncipherment(X509Certificate2 tmpCert)
{

    foreach (X509KeyUsageExtension usage_extension in tmpCert.Extensions.OfType<X509KeyUsageExtension>())
    {
        if ((usage_extension.KeyUsages & X509KeyUsageFlags.KeyEncipherment) == X509KeyUsageFlags.KeyEncipherment)
        {
            return true;
        }
    }

    return false;
}
Yacoub Massad
  • 27,509
  • 2
  • 36
  • 62