Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I detect the type of a certificate (A1 or A3)?

I have 2 types of certificates on my machine, one A1 and the other is A3, when loading one of them into a X509Certificate2 object, how can I programmatically detect if it's a A1 or A3?

I understand that if the A3 certificate is not plugged in, the private key is not accessible. Take into account that both certificates are valid/installed and plugged in.

Edit

I just discovered that the types A1 and A3 are defined by a specific country legislation (Brazil), so let's me explain what's the difference:

ICP-Brasil allows 8 types of digital certificates, divided into 2 series (A and S).

The A series (A1, A2, A3 and 4) consists of digital signature certificates, used for Web identity verification, e-mail, virtual private networks (VPNs), and electronic documents with verification of the integrity of their Information.
The S series (S1, S2, S3 and S4) includes the certificates of confidentiality, which are used in the codification of documents, databases, messages and other confidential electronic information. The eight types are differentiated by use, security level and validity.
(Gisele Ribeiro, Source)

Types of certificate

So, to update my question, I wish to detect if the certificate comes from a smart card with key generation capability.

like image 788
Nicke Manarin Avatar asked Jan 05 '17 18:01

Nicke Manarin


1 Answers

Presumably your A1 and A3 nomenclature is about a Brazilian standard (e-CPF/e-CNPJ/something like that). As far as I can tell, those terms mean:

  • A1: Software private key
  • A3: Hardware private key

(I'm really curious as to what A2 was, but I digress).

Technically speaking, certificates don't know where their keys live. So a certificate doesn't know if its private key (wherever that may be) is hardware or software based. But, based on http://www.bcb.gov.br/sfn/ced/ManualdeSeguran%C7adaRSFN-v32.pdf and http://oid-info.com/get/2.16.76.1.2, it looks like you can do something along the lines of:

private static bool IsBrazilA1Certificate(X509Certificate2 cert)
{
    // End with the "." so it matches on children, but not that OID.
    return HasParentEku(cert, "2.16.76.1.2.1.");
}

private static bool IsBrazilA3Certificate(X509Certificate2 cert)
{
    // End with the "." so it matches on children, but not that OID.
    return HasParentEku(cert, "2.16.76.1.2.3.");
}

private static bool HasParentEku(X509Certificate2 cert, string oidFragment)
{
    var ekuExtension = (X509EnhancedKeyUsageExtension) cert.Extensions["2.5.29.37"];

    if (ekuExtension == null)
    {
        return false;
    }

    foreach (Oid eku in ekuExtension.EnhancedKeyUsages)
    {
        if (eku.Value.StartsWith(oidFragment))
        {
            return true;
        }
    }

    return false;
}

Since I don't have a Brazilian A1 or A3 certificate I can't really test this, but it's the best I can come up with from a description. Otherwise you're down to asking "does this have a private key?" (cert.HasPrivateKey) and "is the private key hardware-backed?" (a much harder question).

Edit: It's worth nothing that the above code doesn't follow the normal rules of EKU validation. Normally a certificate with no EKU extension at all is treated as if it has all EKUs. But since you're looking explicitly for something created under a Brazilian A1 or A3 policy, it matches what you were requesting. (Also, it's the only time I've ever seen anything have to be validated with a StartsWith based rule, usually a policy is a specific EKU OID)

like image 97
bartonjs Avatar answered Sep 20 '22 19:09

bartonjs