Friday, May 2, 2014

quick and dirty SSL client using Ruby and Savon

I needed to test my Apache CXF web service using a particular SOAP request stored in a plain xml file. Since I am familiar with Ruby (and I'm always looking for excuses to use it), I used Savon as a tool to start from. I added the ability to provide a file whose contents is the desired SOAP request. I also needed to send my request via HTTPS and Savon was already able to accommodate (thanks to it's own use of HTTPI).

To use my forked version of savon:


gem 'savon', :git => 'https://github.com/dcvezzani/savon.git'

Once a Savon client has been created and initialized with the necessary WSDL and SSL configuration, the call is simple:


call_options = {body_content: body_content}
response = client.call(:soap_operation, call_options)

See the sample client for details.

Need to extract private and public keys out of a Java Keystore (JKS)? See my other post.

extracting private, public and trusted keys from a Java Keystore (JKS)

Provide your own particular values.

  • STORE_PASS: the keystore password
  • STORE_LOCATION: the absolute path for your keystore location
  • TARGET_ALIAS: the alias name for the targeted key in the keystore
  • WSDL_URI: the uri (or url) for the WSDL associated with the service that will be called
  • TRUSTED_ALIASES: list of alias values to be extracted out of JKS file and put into PEM formatted truststore file

  export STORE_PASS=
  export STORE_LOCATION=/Users/joe/...
  export TARGET_ALIAS=
  export WSDL_URI=https://...
  export TRUSTED_ALIASES=1("one" "two" "three")

Verify your environment variables


keytool -list -v -storepass ${STORE_PASS} -keystore ${STORE_LOCATION} | less

filename=$(basename "$STORE_LOCATION")
suffix="${filename##*.}"
prefix="${filename%.*}"
alias=${TARGET_ALIAS}

Export the public key


keytool -export -rfc -keystore ${STORE_LOCATION} -storepass ${STORE_PASS} -alias ${alias} -file ${prefix}.pub

Export the private key. This is necessary because some tools don't know how to use a Java keystore.


keytool -importkeystore -srckeystore ${STORE_LOCATION} -destkeystore ${prefix}.p12 -srcstoretype JKS -deststoretype PKCS12 -srcstorepass ${STORE_PASS} -deststorepass ${STORE_PASS} -srcalias ${alias} -destalias ${alias} -srckeypass ${STORE_PASS} -destkeypass ${STORE_PASS} -noprompt

openssl pkcs12 -in ${prefix}.p12 -out ${prefix}.key -passin pass:${STORE_PASS} -passout pass:${STORE_PASS}

openssl x509 -in ${prefix}.pub -text -noout
openssl rsa -in ${prefix}.key -check

Verify that private/public key pair were extracted correctly


export WGET_CONFIG="--secure-protocol TLSv1 --no-check-certificate --certificate ${prefix}.pub --certificate-type PEM --private-key ${prefix}.key --private-key-type PEM"

wget ${WGET_CONFIG} ${WSDL_URI}

Remove password on the private key (dangerous!). Make sure the file permissions, at least, are locked down.


openssl pkcs12 -in ${prefix}.p12 -out ${prefix}.pem

openssl rsa -in ${prefix}.key -out ${prefix}-no-password.key
chmod 400 ${prefix}-no-password.key

Create a truststore file in pem format.


echo "" > ${prefix}-truststore.pem
for trusted_alias in "${TRUSTED_ALIASES[@]}"
do
keytool -export -alias ${trusted_alias} -file trust-${trusted_alias}.crt -keystore ${STORE_LOCATION} -storepass ${STORE_PASS}
openssl x509 -inform der -in trust-${trusted_alias}.crt -out trust-${trusted_alias}.pem
cat trust-${trusted_alias}.pem >> ${prefix}-truststore.pem
done