Question How to calculate a X509 certificate's issuer name hash

Cecil

19+ years progress programming and still learning.
I had a situation where the DLC cert folder needed to be updated with a missing CA root certificate.
OpenEdge raised an error about certificate 6079867.0 was missing.
I managed to get the certificate root file and import it successfully, but I'm unsure how the hash is calculated.

From what I have found on the internet, the hash is calculated by SHA1 on the "subject issuer" and then taking the first 4 bytes and hex-encoding the result.
However, no matter what I try, I'm just unable to calculate the same hash that OpenSSL generates.

$ openssl x509 -in "DigiCert Global Root G2.crt" -hash -noout
607986c7

Objective:
I want to test to see if a certificate exists in the %DLC%/cert folder and to do that I need to make sure I can calculate the hash.
I can't assume that OpenSSL utility is installed on a desktop PC, so using OpenSSL is not an option to calculate the hash for me.

Question:
In the ABL how do I calculate the hash of a certificate?
 
Last edited:

Cecil

19+ years progress programming and still learning.
Additional information on what the OpenEdge command line tool produces.

1701318307361.png
 

Cecil

19+ years progress programming and still learning.
i have always been I
under the impression that the sslc command was a customised version of openSSl with very limited functionality.

is sslc just a rebadged version of openSSL???.
 

peterjudge

Member
i have always been I under the impression that the sslc command was a customised version of openSSl with very limited functionality.

is sslc just a rebadged version of openSSL???.

It may be (I don't know 100% for sure that it is; I have a suspicion that it's just a custom executable that links openssh) but this command proenv> sslc x509 -in "DigiCert Global Root G2.crt" -hash -noout produces the hash value you are after.
 

Cecil

19+ years progress programming and still learning.
this is great, that i can use the sslc command. but is such a shame that i was has unable to generate the hash programatically. i felt like i was getting so close to figuring it out.
 

peterjudge

Member
It appears to be a tad involved.

Take a look at the answer to What does `openssl x509 -hash` calculate the hash of? . So far, so easy. Now you need the ASN.1 encoding ... you can see what that looks like using ASN.1 JavaScript decoder (upload a .0 file from $dlc/certs).

The progresstalk.com certificate looks something like the below. Your mission, should you accept it, is to find a spec/doc for the various bytes you need to write to create the ASN.1 encoded subject. And then write it in ABL. This looks useful String Types - Win32 apps but I'm sure there are many others.

Good luck / enjoy. I'm sure if you wanted to put it on a Github or something you'd find company in writing such ABL.

1701373152995.png

Hm, doesn't look awful-awful: "indentifier" "size-in-bytes-in-hex" "data". That Microsoft site has a decent description of the things you'll need.
 
Last edited:

Cecil

19+ years progress programming and still learning.
Thanks, Peter.

I'm using the .NET X509Certificate2:IssuerName:RawData. to return the ASN.1 Certificate's Issuer.

Which looks like this (hex encoded):

Code:
3061310B300906035504061302555331
153013060355040A130C446967694365
727420496E6331193017060355040B13
107777772E64696769636572742E636F
6D3120301E0603550403131744696769
4365727420476C6F62616C20526F6F74
204732

Which matches up perfectly with ASN.i tool .

1701376234417.png

I'm wondering if I need to trim some bytes???
 

peterjudge

Member
Thanks, Peter.

I'm using the .NET X509Certificate2:IssuerName:RawData. to return the ASN.1 Certificate's Issuer.

Which looks like this (hex encoded):

Code:
3061310B300906035504061302555331
153013060355040A130C446967694365
727420496E6331193017060355040B13
107777772E64696769636572742E636F
6D3120301E0603550403131744696769
4365727420476C6F62616C20526F6F74
204732

Which matches up perfectly with ASN.i tool .

View attachment 2983

I'm wondering if I need to trim some bytes???

Possibly. You need the Subject, not the issuer, though.

So, get ASN.1-encoded subject.
SHA-1 hash it (into a big-endian-byte-order memptr).
Hex-encode the first 4 bytes .
Profit.

(edit: had to /.-ify this post)
 

peterjudge

Member
Thanks, Peter.

I'm using the .NET X509Certificate2:IssuerName:RawData. to return the ASN.1 Certificate's Issuer.

Which looks like this (hex encoded):

Code:
3061310B300906035504061302555331
153013060355040A130C446967694365
727420496E6331193017060355040B13
107777772E64696769636572742E636F
6D3120301E0603550403131744696769
4365727420476C6F62616C20526F6F74
204732

Which matches up perfectly with ASN.i tool .

View attachment 2983

I'm wondering if I need to trim some bytes???

@Cecil , does the Thumbprint property not give you what you need?

Per that page

The thumbprint is dynamically generated using the SHA1 algorithm and does not physically exist in the certificate. Since the thumbprint is a unique value for the certificate, it is commonly used to find a particular certificate in a certificate store.

Doesn't look like it.
 
Last edited:

Cecil

19+ years progress programming and still learning.
I've got a bit of a breakthrough...Sort of.

Before you hash the 'subject' their need to be some manipulation of the raw data.
Some notes: The "hash" is essentially a dump of the certificate's DER encoded subject name SEQUENCE with the following modifications:
  1. the leading SEQUENCE header is stripped that's the first \x30\xXX((\xXX>7e?\xYY{\xXX}:"") i.e. between 2 and 258 bytes.
  2. Strings encoded as PRINTABLESTRING, IA5STRING, T61String (...) become UTF8 strings.
  3. the Strings also become lowercase, have leading and trailing spaces removed and duplicate spaces collapsed

From what I can determine, the raw data needs to be 'unpacked', re-encode with byte prefix string values to be trimmed, converted to lower case and double spaces to be replace with a single space.

More information found here: OpenSSL: how to get x509 -subject_hash "manually"?
 
Last edited:

Cecil

19+ years progress programming and still learning.
I'm working backwards in my problem solving.

I now have a working HEX encoded value of the 'Subject' so I know what the correct result I'm expecting.
Code:
function HashTruncate character (input hexEncodedANS1Subject as character):

    define variable rawHashSubject  as raw   no-undo.
    define variable rawHashTruncate as raw   no-undo.
   
    // Decode the hex encoded value and then SHA1 hash it.  
    rawHashSubject = sha1-digest(hex-decode(hexEncodedANS1Subject)).

    //Swappie doodle, revese the order.
    put-byte(rawHashTruncate,1) = get-byte(rawHashSubject,4).
    put-byte(rawHashTruncate,2) = get-byte(rawHashSubject,3).
    put-byte(rawHashTruncate,3) = get-byte(rawHashSubject,2).
    put-byte(rawHashTruncate,4) = get-byte(rawHashSubject,1).
   
    return string(hex-encode(rawHashTruncate)) + '.0'.

end function.

message "Subject Hash: " HashTruncate(input "310b300906035504060c02757331153013060355040a0c0c646967696365727420696E6331193017060355040b0c107777772E64696769636572742E636F6D3120301e06035504030c17646967696365727420676C6F62616C20726F6F74206732")
    view-as alert-box info title "sha1-based subject".

Correct response:
1701428572788.png

Objective:

Convert/re-encode this:

3061310B300906035504061302555331153013060355040A130C446967694365727420496E6331193017060355040B13107777772E64696769636572742E636F6D3120301E060355040313446967694365727420476C6F62616C20526F6F74204732

into this:

310b300906035504060c02757331153013060355040a0c0c646967696365727420696E6331193017060355040b0c107777772E64696769636572742E636F6D3120301e06035504030c17646967696365727420676C6F62616C20726F6F74206732
 
Top