Generate OpenSSL subject_name hash in ruby - ruby

I've investigated 30261296 however I'm still at a loss to find a way to generate the same results in Ruby with the openssl and/or digest gems. The OpenSSL output I'm trying to replicate in ruby is as follows:
$ openssl x509 -noout -subject_hash -in DigiCertSHA2SecureServerCA.pem
85cf5865
In reading many things, I believe this hash is generated from the Subject: portion of the certificate, which is like the distinguished name. In this certificates case something to the effect of:
$ openssl x509 -noout -subject -in DigiCertSHA2SecureServerCA.crt
subject=C = US, O = DigiCert Inc, CN = DigiCert SHA2 Secure Server CA
Attempting to SHA-1 encode that on the command line or in Ruby (which represents this as /C=US,/O=DigiCert Inc/CN=DigiCert SHA2 Secure Server CA when using the openssl gem) has not yeilded the same has results displayed by OpenSSL.
I'm trying to do this more natively in Ruby to avoid shelling out to openssl if possible since openssl and digest come along with the ruby env. In the end I need this to generate the hash directory tree ... i.e. 85cf5865.0 (hash + '.0').
The CA I'm hasing is DigiCertSHA2SecureServerCA.crt - DER encoded. I converted DER to PEM because openssl command line uses that without the additional -inform der switch. It doesn't appear to matter to Ruby's openssl gem.

This turns out to be pretty straightforward, since Ruby’s OpenSSL bindings includes the OpenSSL::X509::Name#hash method, which is exactly what we want.
require 'openssl'
# Read the certificate.
cert = OpenSSL::X509::Certificate.new(File.binread("DigiCertSHA2SecureServerCA.crt"))
# Get the subject, which is an OpenSSL::X509::Name object.
name = cert.subject
# hash returns an integer, we want the hex string so call to_s(16).
puts name.hash.to_s(16) #=> 85cf5865
The integer will be positive since OpenSSL returns an unsigned int, so we can just use to_s(16) and don’t need to worry about converting negative values.

Related

Encrypt private key with passphrase using openssl ruby

In order to encrypt my private key and provide the passphrase. Currently, I am using bash cmd to get my encrypted key user_enc.pem
( openssl rsa -in user.pem -pubout && openssl rsa -in user.pem -aes256 ) > user_enc.pem
It would be helpful if someone can have a look and help me out to achieve this by using ruby probably with openssl.
OpenSSL::Cipher, which belong to Ruby standard library, provides symmetric algorithms for encryption and decryption. To use it just require OpenSSL in Ruby:
require 'openssl'
You can create a cipher instance specifying the Cipher algorithm. For example:
cipher = OpenSSL::Cipher::AES256.new(:CBC)
cipher.encrypt
key = cipher.random_key
iv = cipher.random_iv
data = "Confidential data"
encrypted = cipher.update(data) + cipher.final
For more details, check Ruby documentation: https://ruby-doc.org/stdlib-2.5.0/libdoc/openssl/rdoc/OpenSSL/Cipher.html

Convert openssl command in ruby language using OpenSSL-Gem

i'm going crazy
I need to convert this openssl command
openssl smime -verify -in mysignedfile.xml.p7m -inform der -noverify -out simplefile.xml
into Ruby / RoR language. It's working as expected in console but I can't find the way to use it in ruby.
looking at the OpenSSL document, I can not succeed
this is an example of code
myfile = File.read "mysignedfile.xml.p7m"
OpenSSL::PKCS7::read_smime(myfile)
Response:
OpenSSL::PKCS7::PKCS7Error: no content type
The file was successfully opened (i can read it), but i think read_smime expect for some value as content_type

ruby openssl smime encryption

I am looking for ruby code to mimic below openssl smime encryption. I looked up other related topics but mostly were around signing. In snippet below cert.pem is a PEM-encoded X.509 certificate containing the PEM public key. token.txt file is the file to be encrypted.
openssl smime -encrypt -out encrypted.p7m -in token.txt cert.pem
Figured it.
token_plain_text = File.read("/path/to/token.txt")
cert = X509::Certificate.new("/path/to/cert.pem")
encrypted_object = OpenSSL::PKCS7.encrypt([cert], token_plain_text)
Got the encrypted string by outputting above object to string.
encrypted_str = encrypted_object.to_str

Ruby OpenSSL, print issuer and subject of pem file

How do I print (or save to variable) the Issuer and Subject from a .pem certificate using the OpenSSL module ?
(This is after trying to understand the ruby-docs)
I used this System-depended and ugly code, but I'm sure there is a much nicer thing to do
pfxsubject = %x(openssl x509 -in '/root/cert.pem' -noout -subject | cut -c 10-).to_s.chomp

Ruby code for openssl to generate fingerprint

I need the ruby equivalent of the following:
openssl x509 -sha1 -fingerprint -noout -in cert.pem
The code that I wrote is:
data = File.read("cert.pem")
data["-----BEGIN CERTIFICATE-----\n"]=""
data["-----END CERTIFICATE-----\n"]=""
OpenSSL::Digest::SHA1.new(Base64.encode64(data))
This code does not generate the same fingerprint as the openssl cli command does.
Any idea what I may be doing wrong?
As gtrig mentions, the OpenSSL command line builds the fingerprint by hashing the DER encoding of the certificate, not the Base64 PEM representation. You can parse this using pure OpenSSL:
file_data = File.read("cert.pem")
cert = OpenSSL::X509::Certificate.new(file_data)
puts OpenSSL::Digest::SHA1.new(cert.to_der).to_s
Shameless plug: r509 can also do this like so:
cert = R509::Cert.load_from_file("cert.pem")
puts cert.fingerprint('sha1')
If you need it to be in colon separated form you can just take the hash and do something like "fingerprint".scan(/../).map{ |s| s.upcase }.join(":")
Try Base64.decode64.
OpenSSL::Digest::SHA1.new(Base64.decode64(data))
Certificates in PEM format are Base 64 encoded versions of a binary DER format, so they need to be DEcoded before the SHA1 hash is taken.
Alternatively, you could convert the PEM file to DER format with OpenSSL like this:
openssl x509 -in cert.pem -out cert.der -outform der
Then your Ruby code would look like this:
data2 = File.read("cert.der")
print OpenSSL::Digest::SHA1.new(data2)
Either way works.

Resources