openssl icon indicating copy to clipboard operation
openssl copied to clipboard

access to raw public key, or keyid

Open mcr opened this issue 8 years ago • 2 comments

RFC5280, section 4.2.1.2 defines keyid as the SHA1 of the subjectPublicKey encoding.

OpenSSL::PKey::EC's to_text 

reveals the public key info via an OpenSSL method that produces text. This is the input that we need for the SHA1, and I guess I could decode the text back to binary if I had to, but this seems really wrong....
While there is some code in openssl/crypto/x509v3/v3_skey.c that calculates what I want, it's buried inside an extension definition, and can't (AFAIK) be used directly.

I can get what I want via: a1 = OpenSSL::ASN1.decode(pubkey.to_der) a1.value[1].value

but that just seems wrong. Is there another way to pull the encoded public key out? Should getting this keyid be ruby or C code?

mcr avatar Oct 24 '17 18:10 mcr

RFC5280 has an example, which is available at: https://csrc.nist.gov/projects/pki-testing/sample-certificates-and-crls

you want example C.2. Download it as rfc5280_cert2.cer.

Start an irb:

> cert = OpenSSL::X509::Certificate.new(IO::read("rfc5280_cert2.cer"))                            
                                                                                              
2.4.1 :005 > cert.extensions[1].to_s                                                              
 => "subjectKeyIdentifier =                                                                  
17:7B:92:30:FF:44:D6:66:E1:90:10:22:6C:16:4F:C0:8E:41:DD:6D"                                      

(matches line 7930 of rfc5280, so this is the right object)

2.4.1 :013 > der = cert.public_key.to_der                                                         
2.4.1 :014 > asn1 = OpenSSL::ASN1.decode(der)                                                     
2.4.1 :015 > rawpubkey = nil                                                                      
 => nil                                                                                           
 2.4.1 :016 > asn1.value.each {|v|                                                                
 2.4.1 :017 >           if v.tag == 3                                                             
 2.4.1 :018?>             rawpubkey = v.value                                                     
 2.4.1 :019?>           end                                                                       
 2.4.1 :020?>       }                                                                             
                                                                                                  
2.4.1 :039 > Digest::SHA1.digest(rawpubkey).unpack("H*")                                          
 => ["177b9230ff44d666e19010226c164fc08e41dd6d"]                                                  

YEAH. So getting it out of openssl/ruby-openssl is a bit daft, but it works and gives the right answer. Should this be added as ruby code until we find a better way to get it out of the OpenSSL API?

mcr avatar Oct 24 '17 19:10 mcr

With the current Ruby/OpenSSL, it has to be extracted from the output of a_public_pkey.to_der. If what you need is to (re)calculate just the SHA-1 for a subject key identifier, you might be able to use OpenSSL::X509::ExtensionFactory.

cert = OpenSSL::X509::Certificate.new
cert.public_key = ...
ef = OpenSSL::X509::ExtensionFactory.new(nil, cert)
p ext = ef.create_extension("subjectKeyIdentifier", "hash")

Actually, OpenSSL provides X509_get0_pubkey_bitstr() function that does the job. It's possible to add a binding to that, but I wonder what use case this would benefit.

rhenium avatar Oct 28 '17 06:10 rhenium