2007-04-11

ssl mutual authentication in perl

Here is a perl script to invoke web service using SSL mutual authentication.

use LWP::UserAgent;
use HTTP::Request::Common;

my $request = << REQ;
# message here
REQ

# client certificate support
$ENV{HTTPS_CERT_FILE} = 'test.crt';
$ENV{HTTPS_KEY_FILE} = 'test.key';

# CA cert peer verification
$ENV{HTTPS_CA_FILE} = 'ca.crt';

my $ua = new LWP::UserAgent;
my $res = $ua->request(POST 'https://test.com',
SOAPAction => 'http://test.com/operationA',
Content_Type => 'application/xml',
Content => $request);

print $res->code."\n";
print $res->content."\n";

print "Work is done. \n\n";

2007-04-10

Python utility for generating certificate

Here is a Python script that generates a certificate with various formats, including JKS and PFX. It also requires JDK and OpenSSL being installed.

-----------------------------
#!/usr/local/bin python

"""
Create a certificate with Python.
"""

import urllib, sys, getopt, os, shutil
from M2Crypto import SSL, httpslib
from M2Crypto import RSA, X509, EVP, m2, Rand, Err

keystorepass = 'secret'

def passphrase_callback(v):
return keystorepass

def generateRSAKey():
return RSA.gen_key(1024, m2.RSA_F4)

def makePKey(key):
pkey = EVP.PKey()
pkey.assign_rsa(key)
return pkey

def makeRequest(pkey, server_dns):
req = X509.Request()
# Seems to default to 0, but we can now set it as well, so just API test
req.set_version(req.get_version())
req.set_pubkey(pkey)
name = X509.X509_Name()
name.CN = server_dns
name.OU = 'My Unit'
name.O = 'My Company'
name.L = 'My City'
name.ST = 'My State'
name.C = 'US'
req.set_subject_name(name)
ext1 = X509.new_extension('Comment', 'Auto Generated')
extstack = X509.X509_Extension_Stack()
extstack.push(ext1)
req.add_extensions(extstack)
req.sign(pkey, 'md5')
return req

def sendRequest(crtreq):
# send to a web service to sign the certificate
return crtresp

def extractCert(crtresp):

crt = ''
# extract crt from the response
return crt

def createJKS(fqdn):

java_home = os.environ['JAVA_HOME']
if java_home is None:
raise 'JAVA_HOME needs to be set.'

# an empty Java keystore
jks_template = 'template.jks'
jksfile = ''.join([fqdn, '.jks'])
certfile = ''.join([fqdn, '.crt'])
keyfile = ''.join([fqdn, '.der'])
shutil.copyfile(jks_template, jksfile)

os.spawnl(os.P_WAIT, ''.join([java_home, '/bin/java.exe']), 'java', '-cp', '.', 'KeyStoreImport', jksfile, keystorepass, fqdn, certfile, keyfile, keystorepass)

def createPFX(fqdn):

openssl_home = "c:/tools/openssl"
if openssl_home is None:
raise 'openssl needs to be installed.'

certfile = ''.join([fqdn, '.crt'])
keyfile = ''.join([fqdn, '.key'])
pfxfile = ''.join([fqdn, '.pfx'])
inpass = ":".join(['pass', keystorepass])
outpass = ":".join(['pass', keystorepass])

os.spawnl(os.P_WAIT, ''.join([openssl_home, '/bin/openssl.exe']), 'openssl', 'pkcs12', '-export', '-inkey', keyfile, \
'-in', certfile, '-out', pfxfile, '-passin', inpass, '-passout', outpass)

def moveFiles(fqdn):

if os.path.isdir(fqdn):
os.rmdir(fqdn)
os.mkdir(fqdn)
shutil.move(''.join([fqdn, '.key']), fqdn)
shutil.move(''.join([fqdn, '.der']), fqdn)
shutil.move(''.join([fqdn, '.crt']), fqdn)
shutil.move(''.join([fqdn, '.jks']), fqdn)
shutil.move(''.join([fqdn, '.pfx']), fqdn)

def makeCert(fqdn):

print '####### Generate RSA Key #######'
rsa = generateRSAKey()
rsa.save_key(''.join([fqdn, '.key']), cipher='aes_256_cbc', callback=passphrase_callback)
rsa.save_key_der(''.join([fqdn, '.der']))

print '####### Generate Pub/Pri Keys #######'
pkey = makePKey(rsa)

print '####### Generate Certificate Request #######'
req = makeRequest(pkey, fqdn)

print '####### Generate Certificate Request PEM #######'
crtreq = req.as_pem()
print '####### Certificate Request #######'
print crtreq
print '####### Certificate Request #######', '\n'

crtresp = sendRequest(crtreq, fqdn)
# print '####### Certificate Response #######'
# print crtresp
# print '####### Certificate Response #######', '\n'
crtfile = open(''.join([fqdn, '.crt']), 'w')
crtfile.write(crtresp)
crtfile.close()

crtfile = open(''.join([fqdn, '.crt']), 'r')
crt = extractCert(crtfile)
print '####### Certificate #######'
print crt
print '####### Certificate #######', '\n'
crtfile.close()

crtfile = open(''.join([fqdn, '.crt']), 'w')
crtfile.write(crt)
crtfile.close()

print '####### Generate JKS #######'
createJKS(fqdn)

print '####### Generate PFX #######'
createPFX(fqdn)

print '####### Move Files #######'
moveFiles(fqdn)

print "Certificate generated"

def usage():

print "Usage:"
print "python gencrt.py -n <fqdn>"

if __name__ == '__main__':

try:
opts, args = getopt.getopt(sys.argv[1:], "hn:", ["help", "fqdn="])
except getopt.GetoptError:
usage()
sys.exit(2)

fqdn = None
for opt, arg in opts:
if opt in ("-h", "--help"):
usage()
sys.exit()
elif opt in ("-n", "--fqdn"):
fqdn = arg

if fqdn == None:
usage()
sys.exit(2)

makeCert(fqdn)</fqdn>

Cross Domain Ajax in IE

I have recently had the opportunity to implement an AJAX solution for my project. The goal is to allow AJAX calls to our web service. The challenge is the call is cross-domain. After spending some hours in investigation, I realized that it is real hard if not possible to accomplish this in Firefox. Tricks, such as iframe and JSOD, won't work well because the web service interface (SOAP) is already defined and I cannot make changes to it. Fortunately, the standard browser we need to support is IE, and this is an intranet application. These two conditions made things much, much easier.

To enable cross-domain AJAX, we need to make a few configuration changes to IE
1) add the site which hosts the AJAX code to the "Trust Zone"
2) enable the configuration "Access data sources cross domain"

That's the most of it. In addition, you also need to pay attention to issues such as cross-transport and cross-port. You need to load specific version of MSXML in order to work-around the restrictions. Here is a summary of it (http://msdn.microsoft.com/workshop/author/dhtml/overview/aboutxmlhttp.asp):

Option Cross Port Cross Protocol
--------------------------------------------------
Native XMLHttpRequest Disallow Disallow
MSXML 6.0 Allow Disallow
MSXML 5.0 Allow Disallow
MSXML 4.0 Allow Disallow
MSXML 3.0 Allow Allow HTTP to HTTPS
Microsoft XML Allow Allow HTTP to HTTPS