I am not able to find a reliable definition for the different algorithm properties in a certificate. In windows UI, I have this CA certificate and a CRL it generated (with certutil/ADCS):
My interpretation of this is that:
'Signature algorithm' -> only relates to how the signature of the CA certificate was computed by the parent CA (so it relates to the parent of the certificate of the example) 'Signature hash algorithm' -> I think it's the same? But I am not sure since SHA384 seems to be used also for the 'child' CRL generated with the certificate in the example 'Public key parameters' -> It seems to be the algorithm that is actually used for the 'children' of the CA certificate of the example, because it is the 'Signature algorithm' property of the CRL file on the right
Now, I figured, maybe this is just Windows UI being confusing, so I took a look at openssl:
openssl x509 -in 'somecert.crt' -noout -text
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
17:00:00:00:0d:2a:7f:28:7b:10:75:11:5d:00:00:00:00:00:0d
Signature Algorithm: sha384WithRSAEncryption
Issuer: -----
Validity
Not Before: Mar 14 21:07:30 2019 GMT
Not After : Mar 14 21:17:30 2024 GMT
Subject: -----
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (384 bit)
pub:
04:cc:db:61:51:3a:bc:7b:35:e8:c6:28:2a:82:1b:
6c:fd:f2:db:2f:ec:27:7a:2f:e9:60:85:ad:9f:e6:
bb:25:cf:a7:a0:97:ab:c6:fe:82:30:6d:ce:f0:ff:
23:9a:8a:c3:a9:68:4f:17:39:82:0c:22:f9:10:93:
4f:54:6b:ff:2f:8a:99:4a:31:e0:a6:c2:d6:4e:26:
23:78:55:a0:e1:55:4f:c1:8f:28:c9:82:38:0e:cf:
12:e6:c2:ce:b9:92:ff
ASN1 OID: secp384r1
NIST CURVE: P-384
X509v3 extensions:
[irrelevant parts]
Signature Algorithm: sha384WithRSAEncryption
Signature Value:
5d:4f:db:84:9b:34:e3:9e:0b:e7:e2:35:0c:69:5a:58:2f:70:
b9:97:47:f0:9a:5a:19:fd:3f:5c:7a:a6:87:a9:d9:8a:1c:20:
7a:a4:9c:b3:a4:60:f5:18:5b:29:17:42:11:69:77:71:e9:c6:
77:ea:f2:f1:d0:96:d1:70:2f:70:58:42:b3:08:55:42:ed:24:
3e:ff:4b:98:2c:af:0a:f6:d7:53:30:9d:43:1d:83:39:b9:75:
77:90:c6:31:35:b0:e5:b6:4f:cc:9d:fc:7f:06:97:d4:72:79:
8a:71:5a:cf:ec:3a:a3:2d:f8:65:eb:3f:01:91:2f:e7:0b:51:
ff:75:a9:65:59:6b:2f:a4:0a:2d:1a:a0:73:5a:c4:99:9f:37:
7b:ea:f4:ff:b9:47:f7:d8:bc:61:d9:c2:ab:ef:dc:2b:7a:3e:
41:5d:79:5e:21:27:e8:66:37:0f:b7:03:7e:0d:79:40:13:a0:
4f:2a:89:48:00:b7:86:81:ed:e2:bc:c0:70:3b:91:1c:47:f1:
ad:72:19:d5:63:46:78:d6:67:5d:c0:58:96:11:67:73:36:6c:
fb:7e:b2:e7:8b:2f:a7:e0:37:41:37:bd:3d:c9:92:10:c4:95:
b6:e3:4b:09:57:d7:d6:6e:e2:64:a2:b2:d1:3d:c8:e7:26:ba:
b5:ba:46:8c:5c:1d:d4:d1:a8:53:47:88:26:8d:65:2e:85:ac:
cb:69:25:47:ea:d5:44:cb:99:12:07:1d:bb:01:77:87:47:5e:
8d:92:7f:1d:23:27:ae:3f:9e:e1:c8:51:c7:df:6d:ad:b6:02:
72:1f:28:f7:1c:3a:7e:70:f2:46:4b:b7:4b:90:de:c3:69:8c:
75:bd:d5:4b:04:98:7d:6e:00:92:92:f5:f5:57:29:a7:66:0f:
35:09:f5:58:be:23:a1:95:b1:10:2c:11:ea:9a:fe:65:82:94:
48:ff:45:f2:37:58:96:55:d3:ca:97:f7:c3:a7:30:a2:07:6a:
92:9d:a3:fc:4e:1f:bc:f4:5f:5f:c6:14:59:18:ff:df:66:65:
21:ad:4a:bc:5e:a2:b6:a2:11:d7:40:13:30:ec:fb:df:c4:ef:
36:3a:33:dd:c1:64:0b:7f:de:41:0b:72:0d:c6:66:03:55:be:
38:ae:89:d2:37:41:c7:88:2b:ac:2c:25:96:ac:2b:82:f1:15:
57:8b:47:1f:5f:2d:33:ce:ba:e9:78:30:55:ec:43:aa:f7:49:
6e:34:3c:60:51:86:9a:39:ea:e3:fd:ba:80:87:a4:ae:bc:7d:
83:75:7e:94:85:62:e1:89:47:3a:8d:44:13:bd:30:62:81:a0:
d6:73:23:d0:8a:ed:08:76
So openssl also has that weird redundancy of specifying a 'Signature algorithm' property twice, along with the 'Public Key Algorithm'.
In a nutshell, I am trying to know how to determine what is the hashing & signing algorithms used by a CA to sign its children, and what are the algorithms used by its parents (I actually don't understand why those are worth mentioning in a certificate: wouldn't someone verifying the cert look for those properties in the parent?)
BONUS QUESTION: how to get those properties from the X509Certificate2 object of the certificate in C#?
I looked for various documentation and asked chatgpt, but no reliable answer came out so I am basically trying to reverse engineer this from examples I have
The OpenSSL output shows it twice because that data is in the certificate redundantly, as part of a signature protection strategy that (IIRC) the industry has later decided wasn't important.
https://datatracker.ietf.org/doc/html/rfc5280#section-4.1:
Certificate ::= SEQUENCE {
tbsCertificate TBSCertificate,
signatureAlgorithm AlgorithmIdentifier,
signatureValue BIT STRING }
TBSCertificate ::= SEQUENCE {
version [0] EXPLICIT Version DEFAULT v1,
serialNumber CertificateSerialNumber,
signature AlgorithmIdentifier,
issuer Name,
validity Validity,
subject Name,
subjectPublicKeyInfo SubjectPublicKeyInfo,
issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
-- If present, version MUST be v2 or v3
subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
-- If present, version MUST be v2 or v3
extensions [3] EXPLICIT Extensions OPTIONAL
-- If present, version MUST be v3
}
And from 4.1.1.2. signatureAlgorithm:
The signatureAlgorithm field contains the identifier for the cryptographic algorithm used by the CA to sign this certificate. ... This field MUST contain the same algorithm identifier as the signature field in the sequence tbsCertificate (Section 4.1.2.3).
The SignatureAlgorithm value from the Windows CertUI is available in .NET as X509Certificate2.SignatureAlgorithm.
The "Signature Hash Algorithm" property is made up by Windows CertUI, it's not really in the certificate, they just have mapped all the signature algorithms they know into what the underlying hash algorithm is. .NET doesn't have a way for getting this data without building the mapping table yourself based on SignatureAlgorithm. While your example uses SHA-2-384 for both creating the intermediate CA cert and signing the CRLs from that intermediate CA, there's no requirement that they match. SHA-2-384 is generally the recommended hash algorithm to use with secp384r1 aka NIST P-384, aka "ECDSA_P384".
The public key algorithm (Windows CertUI says "ECC" here, and OpenSSL says "id-ecPublicKey") is cert.PublicKey.Oid
. For RSA that OID is all that you need. For DSA and ECC (ECDSA/ECDH) you also need to interpret the public key parameters, which .NET only exposes as the raw bytes. For DSA you shouldn't care, it's a dead algorithm. For ECC, your best bet if you want it is to do something like
using (ECDsa key = cert.GetECDsaPublicKey())
{
if (key != null)
{
Oid curveId = key.ExportParameters(false).Curve.Oid;
...
}
}
Basically, you just want to poke around at the methods and properties on X509Certificate2 (and the X509Certificate base class).