There have been a few times where I've needed to create a remote service that would run from cron but I couldn't use Kerberos and didn't want to have an exposed password. Certificated based authentication is a handy thing to have in your toolbox when the need arises.
The examples below are just slight modifications to the example client and server that come with the excellent IO::Socket::SSL module.
Hopefully the example and comments make the code speak for themselves.
create_certs.sh
1 #!/bin/bash
2 # ----------------------------------------------------------------------------
3 # create_certs.sh - Create a self signed certificate and create a client
4 # cert that is signed by that cert.
5 #
6 # See Also: http://www.madboa.com/geek/openssl/#cert-self
7
8 # ----------------------------------------------------------------------------
9 # GLOBALS
10
11 CERTDIR=certs # Directory to store our certs
12 C='US' # Country
13 S='New Jersey' # State
14 L='lost' # Location (here I'm using my domain)
15 O='rdennis.net' # Organization
16 U='Testing' # Organizational Unit (e.g. Engineering)
17 M='rdennis_at_rdennis.net' # Email Address of Administrator
18
19 if [ ! -d ${CERTDIR} ] ; then
20 mkdir ${CERTDIR}
21 test -d ${CERTDIR} || (echo >&2 "Error creating dir."; exit 1)
22 fi
23
24 # ----------------------------------------------------------------------------
25 # Create the server (root) key and cert:
26
27 # Generate key
28 openssl req -nodes -newkey rsa:1024 -sha1 \
29 -keyout ${CERTDIR}/rootkey.pem -out ${CERTDIR}/rootreq.pem \
30 -subj "/C=${C}/ST=${S}/L=${L}/O=${O}/OU=${U}/CN=server/emailAddress=${M}"
31
32 # Self sign our cert
33 openssl x509 -req -in ${CERTDIR}/rootreq.pem -sha1 -extensions v3_ca \
34 -signkey ${CERTDIR}/rootkey.pem -out ${CERTDIR}/rootcert.pem
35
36 # Consolidate Cert and Key
37 cat ${CERTDIR}/rootcert.pem ${CERTDIR}/rootkey.pem > ${CERTDIR}/root.pem
38
39 # ----------------------------------------------------------------------------
40 # Create Client key signed w/ the root cert:
41
42 # Generate key
43 openssl req -nodes -newkey rsa:1024 -sha1 \
44 -keyout ${CERTDIR}/clientkey.pem -out ${CERTDIR}/clientreq.pem \
45 -subj "/C=${C}/ST=${S}/L=${L}/O=${O}/OU=${U}/CN=client/emailAddress=${M}"
46
47 # Sign key with root cert
48 openssl x509 -req -in ${CERTDIR}/clientreq.pem -sha1 -extensions usr_cert \
49 -CA ${CERTDIR}/root.pem -CAkey ${CERTDIR}/root.pem -CAcreateserial \
50 -out ${CERTDIR}/clientcert.pem
51
52 # Consolidate Cert and Key
53 cat ${CERTDIR}/clientcert.pem ${CERTDIR}/clientkey.pem \
54 ${CERTDIR}/rootcert.pem > ${CERTDIR}/client.pem
55
server.pl
1 #!/usr/bin/perl
2 # server.pl - our SSL server. It will verify that the client's cert has been
3 # signed by our CA, and is a valid subject.
4
5 use strict;
6 use Data::Dumper;
7 use IO::Socket::SSL;
8
9 # Our Valid Issuer and the Subject for our client cert
10 my $v_issuer = '/C=US/ST=New Jersey/L=lost/O=rdennis.net/OU=Testing/CN=server/emailAddress=rdennis@rdennis.net';
11 my $v_subject = '/C=US/ST=New Jersey/L=lost/O=rdennis.net/OU=Testing/CN=client/emailAddress=rdennis@rdennis.net';
12
13 my ( $sock, $s);
14
15 $IO::Socket::SSL::DEBUG = 1;
16
17 if (
18 !(
19 $sock = IO::Socket::SSL->new(
20 Listen => 5,
21 LocalAddr => 'lisa',
22 LocalPort => 16001,
23 Proto => 'tcp',
24 Reuse => 1,
25 SSL_verify_mode => 0x01,
26 SSL_use_cert => 1,
27 SSL_ca_file => 'certs/root.pem',
28 SSL_cert_file => 'certs/root.pem',
29 SSL_key_file => 'certs/root.pem',
30 )
31 )
32 )
33 {
34 warn "unable to create socket: ", &IO::Socket::SSL::errstr, "\n";
35 exit(0);
36 }
37 warn "socket created: $sock.\n";
38
39 while (1) {
40 warn "waiting for next connection.\n";
41
42 while ( ( $s = $sock->accept() ) ) {
43
44 if ( !$s ) {
45 warn "error: ", $sock->errstr, "\n";
46 next;
47 }
48
49 warn "connection opened ($s).\n";
50
51 my ($subject, $issuer);
52 if ( ref($sock) eq "IO::Socket::SSL" ) {
53 print $s->dump_peer_certificate();
54 $subject = $s->peer_certificate("subject");
55 $issuer = $s->peer_certificate("issuer");
56 }
57
58 warn "HERE";
59 warn $s->peer_certificate('issuer');
60
61 warn "\t subject: '$subject'.\n";
62 warn "\t issuer : '$issuer'.\n";
63
64 if (( $subject eq $v_subject ) && ( $issuer eq $v_issuer )) {
65 my $date = localtime();
66 print $s "VALID: my date command says it's: '$date'";
67 }
68
69 close($s);
70 warn "\t connection closed.\n";
71 }
72 }
73
74 $sock->close();
75
76 warn "loop exited.\n";
client.pl
1 #!/usr/bin/perl
2 # client.pl - our SSL Client. Will need access to it's key and the root CA
3
4 use strict;
5 use IO::Socket::SSL;
6
7 $IO::Socket::SSL::DEBUG = 1;
8
9 my $sock;
10
11 if (
12 !(
13 $sock = IO::Socket::SSL->new(
14 PeerAddr => 'lisa',
15 PeerPort => '16001',
16 Proto => 'tcp',
17 SSL_use_cert => 1,
18
19 SSL_verify_mode => 0x06,
20 SSL_ca_file => 'certs/rootcert.pem',
21 SSL_cert_file => 'certs/clientcert.pem',
22 SSL_key_file => 'certs/clientkey.pem',
23
24 )
25 )
26 )
27 {
28 warn "unable to create socket: ", &IO::Socket::SSL::errstr, "\n";
29 exit(0);
30 }
31 else {
32 warn "connect ($sock).\n" if ($IO::Socket::SSL::DEBUG);
33 }
34
35 # check server cert.
36 my ( $subject_name, $issuer_name, $cipher );
37 if ( ref($sock) eq "IO::Socket::SSL" ) {
38 $subject_name = $sock->peer_certificate("subject");
39 $issuer_name = $sock->peer_certificate("issuer");
40 $cipher = $sock->get_cipher();
41 }
42 warn "cipher: $cipher.\n", "server cert:\n",
43 "\t '$subject_name' \n\t '$issuer_name'.\n\n";
44
45 my ($buf) = $sock->getlines;
46
47 $sock->close();
48
49 print "read: '$buf'.\n";
There you go. You now have the framework needed to create a secure authenticated remote service in Perl.