Generating Custom SSL Certificates for WebScarab

From OWASP
Revision as of 16:59, 8 January 2009 by Mtesauro (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

When using WebScarab to proxy SSL conversations, you may want to avoid the somewhat annoying warnings for an unrecognized certificate. Generating a custom SSL certificate is how you can remove these warning messages and its rather straight forward. Read on to see how.

Background

Below is an illustration of what happens when WebScarab is used as a intercepting proxy for SSL connections.

 --------           -----------           ---------
| server |<--[1]-->| WebScarab |<--[2]-->| browser |
 --------           -----------           ---------

For [1], you are using the "real" SSL certificate from the website you are browsing to. That SSL certificate is signed by a recognized certificate authority (CA). The thing that makes those CA's special is that browsers know about them and trust them. For example in Firefox:

  1. Open Edit -> Preferences -> Advanced -> Encryption
  2. View Certificates button
  3. Authorities tab

to see a list of built-in trusted CA's. The only thing that needs to trust this certificate is WebScarab which Rogan (WebScarab project lead) has said it will by default.

For [2], you are using the the server.p12 certificate which comes with WebScarab. The difference between [1] and [2] is that the CA which signed that certs is NOT built into browsers so they do not trust them by default. Additionally, the domain name of this certificate will not match the domain your browser is accessing. The default is the webscarab CA and a host name of webscarab.

Generating a Certificate

Since you're browser doesn't trust the CA which signed server.p12 in [2] above, you've got two choices:

  1. Instruct the browser to trust the certificate. This will work for the CA part but not for the host name. You will still be prompted by the browser so this doesn't really help much. I know that you can have Firefox trust the CA used in [2] permanently - though its a bunch of clicks in Firefox 3 - about 6 or 7 clicks and you still have the host name mis-match issue.
  1. Use a .p12 file & CA certificate. You'll have to have WebScarab use the new .p12 file and install the CA certificate into your browser.

Rogan has graciously put a script to do this in the WebScarab Git repository. You can get it here or copy and paste it from the listing at the bottom of this page.

The script that Rogan provides will create a CA certificate and a new .p12 certificate for WebScarab to use. The name of the .p12 certificate is based on the first argument to that script. If you called that script like:

$ ./cert.sh www.example.com

It will generate a bunch of output and create a www.example.com.p12 file for WebScarab and a ca_cert.pem file (this is the CA used to sign www.example.com.p12). The script will run fine on Linux (I just tried it) and possibly OS X but won't work on Windows (maybe with Cygwin - any volunteers?).

Take the www.example.com.p12 (assuming you ran the script like above) and let WebScarab know about it. To do this you will need to place it in ${WEBSCARAB_HOME}/certs/. WebScarab checks in that directory at start up for any SSL certificates and remembers what it finds.

Take the ca_cert.pem file and configure your browser to trust that CA. For Firefox:

  1. Open Edit -> Preferences -> Advanced -> Encryption
  2. View Certificates button
  3. Authorities
  4. Click the Import button and navigate to the ca_cert.pem file

Make sure you at least check the box "Trust this CA to identify web sites." option when you are importing - it will bring up a window with that information.

For IE, I don't know off the top of my head. Try this link except for instead of downloading it you can right-click on the ca_cert.pem file and select "Install Certificate"

FYI: Firefox and IE will both need to be configured if both are used as they keep their lists of trusted CAs in different places.

Added Bonus If you keep the working directory for cert.sh, you can create new custom SSL certificates and the CA will stay the same. No need to continually add CAs to the browser(s) of your choice. If you know all the domains you'll be testing, you can run cert.sh multiple time and just restart WebScarab once to get them all recognized.

For the curious, this is the directory structure the cert.sh script Rogan linked creates:

./
|-- cert.sh
|-- sslcerts
|   |-- ca_cert.pem
|   |-- certindex.txt
|   |-- certindex.txt.attr
|   |-- certindex.txt.old
|   |-- certs
|   |   `-- 100001.pem
|   |-- openssl.cnf
|   |-- private
|   |   |-- ca_key.pem
|   |   `-- www.example.com-key.pem
|   |-- serial
|   |-- serial.old
|   |-- www.example.com-cert.pem
|   `-- www.example.com-req.pem
`-- www.example.com.p12

3 directories, 14 files 

Notes

  1. I was not precise in terms and used SSL and HTTPS loosely in the above. This process would also applies to TLS - I just didn't want to type SSL/TLS over and over.
  2. Matt Tesauro was the author of this document. If you have corrections, feel free to make them yourself (its a Wiki after all) or contact Matt at mtesauro (at) gmail.com
  3. The certificate script can be copy and pasted from here:
#!/bin/sh

if [ ! -d sslcerts ] ; then
  mkdir sslcerts || die "Couldn't create sslcerts directory"
fi
if [ ! -d sslcerts/certs ] ; then
  mkdir sslcerts/certs || die "Couldn't create certs directory"
fi
if [ ! -d sslcerts/private ] ; then
  mkdir sslcerts/private || die "Couldn't create private directory"
fi
if [ ! -f sslcerts/serial ] ; then
  echo '100001' > sslcerts/serial
fi
touch sslcerts/certindex.txt
if [ ! -f sslcerts/openssl.cnf ] ; then
  cat <<-EOF > sslcerts/openssl.cnf
	#
	# OpenSSL configuration file.
	#

	# Establish working directory.
 
	dir			= .

	[ ca ]
	default_ca		= CA_default

	[ CA_default ]
	serial			= ./serial
	database		= ./certindex.txt
	new_certs_dir		= ./certs
	certificate		= ./ca_cert.pem
	private_key		= ./private/ca_key.pem
	default_days		= 365
	default_md		= md5
	preserve		= no
	email_in_dn		= no
	nameopt			= default_ca
	certopt			= default_ca
	policy			= policy_anything

	[ policy_match ]
	countryName		= match
	stateOrProvinceName	= match
	organizationName	= match
	organizationalUnitName	= match
	commonName		= supplied
	emailAddress		= optional

	[ policy_anything ]
	countryName		= optional
	stateOrProvinceName	= optional
	localityName		= optional
	organizationName	= optional
	organizationalUnitName	= optional
	commonName		= supplied
	emailAddress		= optional

 
	[ req ]
	default_bits		= 1024			# Size of keys
	default_keyfile		= key.pem		# name of generated keys
	default_md		= md5			# message digest algorithm
	string_mask		= nombstr		# permitted characters
	distinguished_name	= req_distinguished_name
	req_extensions		= v3_req
 
	[ req_distinguished_name ]
	# Variable name				Prompt string
	#-------------------------	  ----------------------------------
	0.organizationName	= Organization Name (company)
	organizationalUnitName	= Organizational Unit Name (department, division)
	emailAddress		= Email Address
	emailAddress_max	= 40
	localityName		= Locality Name (city, district)
	stateOrProvinceName	= State or Province Name (full name)
	countryName		= Country Name (2 letter code)
	countryName_min		= 2
	countryName_max		= 2
	commonName		= Common Name (hostname, IP, or your name)
	commonName_max		= 64

	# Default values for the above, for consistency and less typing.
	# Variable name			Value
	#------------------------  ------------------------------
	0.organizationName_default	= WebScarab
	localityName_default		= WebScarab
	stateOrProvinceName_default	= WebScarab
	countryName_default		= ZA
 
	[ v3_ca ]
	basicConstraints		= CA:TRUE
	subjectKeyIdentifier		= hash
	authorityKeyIdentifier		= keyid:always,issuer:always

	[ v3_req ]
	basicConstraints		= CA:FALSE
	subjectKeyIdentifier		= hash
	EOF
fi

if [ ! -f sslcerts/private/ca_key.pem -a ! -f sslcerts/ca_cert.p12 ] ; then
  printf "\n\n\n\n\n\n\n" | \
  openssl req -new -x509 -extensions v3_ca -keyout sslcerts/private/ca_key.pem \
    -out sslcerts/ca_cert.pem -days 3650 -config ./sslcerts/openssl.cnf \
    -passin pass:password -passout pass:password
fi

cd sslcerts

# Create the cert for the specified site
if [ ! -f $1-req.pem ] ; then
  printf "\n\n\n\n\n\n$1\n" | \
  openssl req -new -nodes \
    -out $1-req.pem -keyout ./private/$1-key.pem \
    -days 3650 -config ./openssl.cnf
fi

if [ ! -f $1-cert.pem ] ; then
  printf "y\ny\n" | \
  openssl ca -out $1-cert.pem -days 3650 \
    -key password -config ./openssl.cnf -infiles $1-req.pem
fi

if [ ! -f ../$1.p12 ] ; then
  openssl pkcs12 -export -in $1-cert.pem -inkey ./private/$1-key.pem \
    -certfile ca_cert.pem -out ../$1.p12 -password pass:password
fi