I'm trying to send a WSSE DSA public key encoded in base 64. I've been trying to use the Open SSL library to separate the public key from the cert file, but it seems that OpenSSL uses my entire cert file instead of extracting just the public key.
File.open("path/certificate.cer", 'rb') do |file|
cert_file = file.read()
cert = OpenSSL::X509::Certificate.new cert_file
end
cert_string = (cert.public_key.to_s+"").delete("\n") #it was formatting itself with newlines
cert_string = cert_string[26..-25] #the start/end messages aren't sent
puts cert_string
Here's the code I use to extract a public key from a certificate. I use it for public key pinning, so it uses a SSL*
from the connection.
Essentially, you call len1 = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), NULL)
one time to get a length, and then call len2 = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), buffer)
a second time to retrieve the certificate. You can use len1
and len2
as a basic sanity check to ensure you got back the expected number of bytes.
int pin_peer_pubkey(SSL* ssl)
{
if(NULL == ssl) return FALSE;
X509* cert = NULL;
/* Scratch */
int len1 = 0, len2 = 0;
unsigned char *buff1 = NULL;
/* Result is returned to caller */
int ret = 0, result = FALSE;
do
{
/* http://www.openssl.org/docs/ssl/SSL_get_peer_certificate.html */
cert = SSL_get_peer_certificate(ssl);
if(!(cert != NULL))
break; /* failed */
/* Begin Gyrations to get the subjectPublicKeyInfo */
/* Thanks to Viktor Dukhovni on the OpenSSL mailing list */
/* http://groups.google.com/group/mailing.openssl.users/browse_thread/thread/d61858dae102c6c7 */
len1 = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), NULL);
if(!(len1 > 0))
break; /* failed */
/* scratch */
unsigned char* temp = NULL;
/* http://www.openssl.org/docs/crypto/buffer.html */
buff1 = temp = OPENSSL_malloc(len1);
if(!(buff1 != NULL))
break; /* failed */
/* http://www.openssl.org/docs/crypto/d2i_X509.html */
len2 = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), &temp);
/* These checks are verifying we got back the same values as when we sized the buffer. */
/* Its pretty weak since they should always be the same. But it gives us something to test. */
if(!((len1 == len2) && (temp != NULL) && ((temp - buff1) == len1)))
break; /* failed */
/* End Gyrations */
/* Do something with the public key */
...
ret = TRUE;
} while(0);
/* http://www.openssl.org/docs/crypto/buffer.html */
if(NULL != buff1)
OPENSSL_free(buff1);
/* http://www.openssl.org/docs/crypto/X509_new.html */
if(NULL != cert)
X509_free(cert);
return result;
}
Sending a Public Key Encoded in Base 64 in Ruby using WSSE in SOAP...
Well, that's a protocol detail you can work out. You can send it as raw bytes, Base64 encode (RFC 4648, Section 4) it or Base64URL encode (RFC 4648, Section 5) it and send it. Its up to you.