SSLeay is a freely available implementation of the Netscape 3.0 SSL protocol. It is the cryptographic engine that drives the Apache-SSL server.
The SSLeay system installs in the directory /usr/local/ssl. It contains the following subdirectories:
The certification authority directory, used if you wish to run your own CA.
Contains the executable programs, which make up the SSLeay package.
Holds the actual X.509 server public key certificates, used by SSL servers on your system.
The C language #include files needed for compiling other programs that use the SSLeay library packages.
The actual C language libraries, which are linked with other programs that use SSLeay.
Holds the private key certificates used by the SSL servers on your system.
SSLeay can be freely used outside the United States. Within the United States, its use is governed by the patents on public key cryptography.
Michael Grant has created several small programs that demonstrate how to use SSLeay to create a secure SSL server and client. The programs run under Solaris 2.5. They are included here with his permission.
Here is the program:
/* client.c To compile: cc -g -c -I/usr/local/SSLeay-0.6.4/include client.c cc -g client.o -L/usr/local/SSLeay-0.6.4/lib -lssl -lcrypto -lsocket -lnsl -o client This program implements a simple client which connects to the server by a TCP/IP connection, and then starts SSL on the connection. It sends some data, then waits for some data (which it prints) and then disconnects. There are two arguments: hostname to connect to port number (which the server will tell you when it starts). You will need to supply a certificate for a CA. This is used in CAfile below. */ #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include "buffer.h" #include "crypto.h" #include "../e_os.h" #include "x509.h" #include "ssl.h" #include "err.h" int MS_CALLBACK verify_callback(int ok, X509 *xs, X509 *xi, int depth, int error, char *arg); #define CAfile "demoCA/cacert.pem" #define CApath NULL main(int argc, char **argv) { int sock; /* The TCP/IP socket */ struct sockaddr_in server; struct hostent *hp; char buf[1024]; SSL_CTX *c_ctx=NULL; /* The Client's context */ SSL *c_ssl=NULL; /* The Client's SSL connection */ int rval; if (argc<2) { printf("usage: client hostname port# "); exit(1); } SSL_load_error_strings(); /* Create a new context. This holds information pertinent to the * client's SSL side of the connection. */ c_ctx=SSL_CTX_new(); if (c_ctx == NULL) { printf("SSL_CTX_new() failed "); } /* Tell SSL where the Certificate Authority files are located */ if ((!SSL_load_verify_locations(c_ctx,CAfile,CApath)) || (!SSL_set_default_verify_paths(c_ctx))) { fprintf(stderr,"SSL_load_verify_locations "); ERR_print_errors_fp(stderr); exit(1); } /* Tell SSL to request the server's certificate when we connect. */ SSL_CTX_set_verify(c_ctx,SSL_VERIFY_PEER, verify_callback); /* Now we can create a basic TCP/IP connection */ if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("socket"); exit(1); } server.sin_family = AF_INET; if ((hp = gethostbyname(argv[1])) == NULL) { perror(argv[1]); exit(1); } memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length); server.sin_port = htons(atoi(argv[2])); if (connect(sock, (struct sockaddr *)&server, sizeof(server)) == -1) { perror("connect"); exit(1); } /* We now have a basic TCP/IP connection up. Now we start SSL * on this connection. */ /* Creates a new SSL connection. This holds information pertinent * to this connection. */ if ((c_ssl=SSL_new(c_ctx)) == NULL) { printf("SSL_new() failed "); exit(1); } /* Tell SSL that this connection is to use the socket we just * created above. */ SSL_set_fd(c_ssl, sock); /* Finally, start the SSL connection */ if (SSL_connect(c_ssl) < 1) { fprintf(stderr, "SSL_connect:"); ERR_print_errors_fp(stderr); exit(1); } /* Lets find out who the peer *really* is. We look though the * server's certificate to see who he says he is. */ { X509 *peer_x509; char *s = NULL; peer_x509 = SSL_get_peer_certificate(c_ssl); if (peer_x509==0) { fprintf(stderr, "SSL_get_peer_cert:"); ERR_print_errors_fp(stderr); exit(1); } s=(char *)X509_NAME_oneline(X509_get_subject_name(peer_x509)); if (s==NULL) { fprintf(stderr, "X509_NAME_oneline:"); ERR_print_errors_fp(stderr); exit(1); } printf("Server's subject name is '%s' ', s);stderr } /* Send some data to the server */ printf("sending data "); SSL_write(c_ssl,"hello from client",18); memset(buf, 0, sizeof(buf)); printf("waiting for data "); /* Now we receive some data from the server and print it out */ rval=SSL_read(c_ssl,buf,1024); printf("-->%s ", buf); /* Close the SSL connection */ SSL_free(c_ssl); /* Close the TCP/IP socket */ close(sock); exit(0); } int MS_CALLBACK verify_callback(int ok, X509 *xs, X509 *xi, int depth, int error, char *arg) { char *s; s=(char *)X509_NAME_oneline(X509_get_subject_name(xs)); if (s != NULL) { if (ok) fprintf(stderr,"depth=%d %s ",depth,s); else { fprintf(stderr,"depth=%d error=%d ok=%d %s ", depth,error,ok,s); ERR_print_errors_fp(stderr); } Free(s); } return(ok); }
Here’s what the output from server looks like:
sun% ./server server ready waiting on port 43205 starting connection using RC4-MD5 cipher -->hello from client ending connection
And here is the source code:
/* server.c To compile: cc -c -I/usr/local/SSLeay-0.6.4/include server.c cc server.o -L/usr/local/SSLeay-0.6.4/lib -lssl -lcrypto -lsocket -lnsl -o server This program implements a simple server which accepts TCP/IP connections, starts SSL on the connection, waits for some data (which it prints), sends some data back to the client, then waits for more data. When the connection is closed by the client, it continues to wait for a new connection. There are no arguments. When the server starts, it will tell you what port it is waiting on. This information is used to start the client. You will need to supply a certificate for a CA, the server's certificate, and the server's private key. These are used in CAfile, SERVER_CERT, and SERVER_KEY respectively below. */ #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <stdio.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include "buffer.h" #include "crypto.h" #include "../e_os.h" #include "x509.h" #include "ssl.h" #include "err.h" #define CAfile "demoCA/cacert.pem" #define CApath NULL #define SERVER_CERT "./server_cert.pem" #define SERVER_KEY "./server_key.pem" main() { int sock; /* The TCP/IP socket */ int length; struct sockaddr_in server; int fd; char buf[1024]; int rval; SSL_CTX *s_ctx=NULL; /* The Server's context */ SSL *s_ssl=NULL; /* The Server's SSL connection */ SSL_load_error_strings(); /* Create a new context. This holds information pertinent to the * client's SSL side of the connection. */ s_ctx=SSL_CTX_new(); if (s_ctx == NULL) { printf("SSL_CTX_new() failed "); } /* Tell SSL where the server's public certificate is */ if (SSL_CTX_use_certificate_file(s_ctx,SERVER_CERT, SSL_FILETYPE_PEM) == 0) { fprintf(stderr, "SSL_CTX_use_certificate_file:"); ERR_print_errors_fp(stderr); exit(1); } /* Tell SSL where the server's private key is */ if (SSL_CTX_use_RSAPrivateKey_file(s_ctx,SERVER_KEY, SSL_FILETYPE_PEM) == 0) { fprintf(stderr, "SSL_CTX_use_RSAPrivateKey_file:"); ERR_print_errors_fp(stderr); exit(1); } /* Tell SSL where the Certificate Authority files are located */ if ((!SSL_load_verify_locations(s_ctx,CAfile,CApath)) || (!SSL_set_default_verify_paths(s_ctx))) { fprintf(stderr,"SSL_load_verify_locations "); ERR_print_errors_fp(stderr); exit(1); } /* Now we create a socket and wait for a basic TCP/IP connection */ if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("socket"); exit(1); } server.sin_family = AF_INET; server.sin_addr.s_addr = INADDR_ANY; server.sin_port = 0; if (bind(sock, (struct sockaddr *)&server, sizeof(server)) == -1) { perror("bind"); exit(1); } length = sizeof(server); if (getsockname(sock, (struct sockaddr *)&server, &length) == -1) { perror("getsockname"); exit(1); } printf("server ready waiting on port %d ", ntohs(server.sin_port)); /* We now are ready to wait for a basic TCP/IP connection up. */ listen(sock, 5); while (1) /* Do this for each incoming TCP/IP connection */ { /* Accept the new TCP/IP connection */ if ((fd = accept(sock, NULL, NULL)) == -1) { perror("accept"); exit(1); } /* Creates a new SSL connection. This holds information * pertinent to this * connection. */ if ((s_ssl=SSL_new(s_ctx)) == NULL) { printf("SSL_new() failed "); exit(1); } /* Tell SSL that this connection is to use the socket we * just created above. */ SSL_set_fd(s_ssl, fd); /* Finally, start the SSL connection */ if (SSL_accept(s_ssl)<1) { fprintf(stderr, "SSL_accept failed "); ERR_print_errors_fp(stderr); SSL_free(s_ssl); close (fd); continue; } printf("starting connection using %s cipher ", SSL_get_cipher(s_ssl)); do /* Do this until the client disconnects: */ { /* Receive data from the client and print it out */ rval = SSL_read(s_ssl,buf,1024); if (rval < 0) { fprintf(stderr, "SSL_read: %s ", ERR_reason_error_string (ERR_get_error())); } if (rval==0) { printf("ending connection "); } else { /* If everything is OK, print out data received */ printf("-->%s ", buf); /* Now send some data back to the client */ SSL_write(s_ssl,"hello from server",18); } } while (rval>0); /* Close the SSL connection */ SSL_free(s_ssl); /* Close the TCP/IP socket */ close (fd); } }
Michael Grant has also put together a very simplified CA to create and sign the certificates needed for the demo client and server programs. The ca.conf file is included below.
Here is the program’s operation. First we create a configuration file and a directory to hold the certificates:
% mkdir demoCA
% cp ca.conf demoCA
% cd demoCA
% mkdir new_certs
% touch index.txt
% echo 01 > serial
Now we create the private key and x509 certificate for the CA. The -x509 option makes this a self-signed certificate (issuer and subject are the same).
% ssleay req -config ca.conf -x509 -new -keyout cakey.pem -out
cacert.pem Generating a 1024 bit private key ...............................+++++ ....................+++++ unable to write 'random state' writing new private key to 'cakey.pem' ----- You are about to be asked to enter information that will be incorperated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [US]:US
Organization Name (eg, company) [MegaWidget]:MegaWidget
Organizational Unit Name (eg, section) [Eng]:Eng
Common Name (eg, YOUR name) [Michael Grant]:CA
%ls
ca.conf cakey.pem new_certs/ cacert.pem index.txt serial
Now we generate a request for a certificate and a private key for the server. This request could be emailed to the CA.
% ssleay req -config ca.conf -new -keyout server_key.pem -out
server_req.pem Generating a 1024 bit private key .+++++ ...........................+++++ unable to write 'random state' writing new private key to 'server_key.pem' ----- You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [US]:US
Organization Name (eg, company) [MegaWidget]:MegaWidget
Organizational Unit Name (eg, section) [Eng]:Eng
Common Name (eg, YOUR name) [Michael Grant]:Michael Grant Server
When the certificate request is received, the CA signs it:
%ssleay ca -config ca.conf -keyfile cakey.pem -cert cacert.pem -in
server_req.pem -out server_cert.pem Check that the request matches the signature Signature ok The Subjects Distinguished Name is as follows countryName :PRINTABLE:'US' organizationName :PRINTABLE:'MegaWidget' organizationalUnitName:PRINTABLE:'Eng' commonName :PRINTABLE:'Michael Grant Server' Certificate is to be certified until Jan 24 09:02:06 1998 GMT (365 days) Sign the certificate? [y/n]:y
1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries Data Base Updated [unix% 559]ls
ca.conf index.txt serial server_key.pem cacert.pem index.txt.old serial.old server_req.pem cakey.pem new_certs/ server_cert.pem
Now let’s look at the contents of the CA’s self certifying certificate. Notice that the Issuer (the signer) and the subject (the owner of the key) are the same:
% ssleay x509 -text -noout -in cacert.pem
Certificate:
Data:
Version: 0 (0x0)
Serial Number: 0 (0x0)
Signature Algorithm: md5withRSAEncryption
Issuer: C=US, O=MegaWidget, OU=Eng, CN=CA
Validity
Not Before: Jan 24 08:59:30 1997 GMT
Not After : Feb 23 08:59:30 1997 GMT
Subject: C=US, O=MegaWidget, OU=Eng, CN=CA
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Modulus:
00:d5:c1:40:2d:67:95:c4:99:97:29:39:49:f1:72:
bd:6f:9b:d8:7d:ae:a2:93:ce:f1:d4:e7:ab:df:d4:
50:eb:c6:3a:d0:cf:ce:ff:f0:40:47:b5:8f:58:83:
0c:9b:4a:02:66:1d:f4:dd:67:a0:a1:17:01:ad:d3:
da:f3:3d:08:6b:ad:8d:a7:63:42:f5:5d:3b:b9:99:
2a:9e:88:b6:70:cd:ca:c1:79:5e:93:a0:05:da:24:
15:1a:57:91:b3:5e:03:03:64:b2:3d:98:5b:ba:43:
0e:62:62:29:30:bb:67:4f:99:44:4e:f7:15:3e:70:
c1:97:c0:b2:93:ed:cd:a9:dd
Exponent: 65537 (0x10001)
Signature Algorithm: md5withRSAEncryption
4b:17:78:78:82:5e:7a:aa:00:33:98:6b:ae:4f:e0:36:81:b5:
88:30:a9:6b:60:75:df:3d:23:74:27:cf:87:35:be:2d:b5:50:
64:d9:1b:11:07:e8:19:ff:04:54:11:ce:cd:aa:b4:32:25:97:
21:bb:ac:fa:86:14:2b:e1:85:69:17:4e:64:93:f6:dc:3e:61:
46:5d:1c:4b:ac:2c:c4:1e:07:fe:0c:52:e7:ff:a5:a6:cd:9a:
a3:52:fe:d8:2a:68:a7:ee:bd:2d:8a:20:91:1d:22:ae:a6:4d:
c0:3e:74:04:c9:73:d2:60:56:85:16:c4:af:85:c4:40:66:b9:
b5:8a
This shows the server’s CA certified certificate. Notice that the issuer is the CA (the signer) and the subject (the owner) is the server:
% ssleay x509 -text -noout -in server_cert.pem
Certificate:
Data:
Version: 0 (0x0)
Serial Number: 1 (0x1)
Signature Algorithm: md5withRSAEncryption
Issuer: C=US, O=MegaWidget, OU=Eng, CN=CA
Validity
Not Before: Jan 24 09:02:06 1997 GMT
Not After : Jan 24 09:02:06 1998 GMT
Subject: C=US, O=MegaWidget, OU=Eng, CN=Michael Grant Server
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Modulus:
00:e0:78:86:09:00:93:3d:a0:c8:c9:71:ef:b4:2e:
3a:ce:84:47:ed:e0:c2:8d:aa:ef:53:f8:35:5e:69:
de:5c:b7:88:d1:e1:01:9b:6e:0e:ba:7c:f3:e7:3d:
76:6d:fd:1c:75:28:bd:13:a0:fd:a8:7a:bd:82:36:
dd:fb:8a:9f:80:2f:0f:4f:b2:94:06:82:52:44:7b:
1f:c4:d7:a2:9d:61:e2:59:b8:e0:13:73:af:7b:02:
71:6c:23:23:47:5f:f9:46:3c:d0:49:ee:c7:42:ac:
f0:7a:9b:d1:8f:19:d3:c6:f0:89:71:6c:3c:a0:c7:
77:a4:a9:b3:c3:6b:7c:f7:7b
Exponent: 65537 (0x10001)
Signature Algorithm: md5withRSAEncryption
cc:ec:71:9d:1a:c3:eb:b1:c6:ba:1b:79:f4:46:e8:b7:cd:5b:
bf:bd:47:da:6a:1b:31:59:e1:a5:f6:9d:a3:c0:10:93:f0:b2:
5b:cc:2d:f7:b3:dd:e0:43:df:5a:2a:c8:97:b6:06:b7:ea:af:
7d:1f:a2:f7:13:57:96:ed:70:1a:85:03:7e:b0:3b:ee:f5:d5:
fd:f8:fb:ab:6f:82:86:6a:b7:c8:f1:84:82:00:37:cc:1a:22:
29:42:7a:f0:6c:34:05:24:e5:ec:95:98:ba:4d:c5:1b:ba:55:
16:d5:b2:1c:b6:d0:19:28:ed:97:8b:26:52:13:c9:bb:66:3f:
ff:1c
Now we will move the certificate into the parent directory, which contains the client and server programs:
%mv server_*.pem ..
%cd ..
The server program must be run before the client is started. It prints the number of the port that it is running on:
% ./server
server ready waiting on port 43436
starting connection using RC4-MD5 cipher
-->hello from client
ending connection
The client program should be run in another window. Its argument is the hostname and port where the server is running:
% ./client localhost 43436
depth=0 /C=US/O=MegaWidget/OU=Eng/CN=Michael Grant Server
depth=1 /C=US/O=MegaWidget/OU=Eng/CN=CA
Server's subject name is '/C=US/O=MegaWidget/OU=Eng/CN=Michael Grant Server'
sending data
waiting for data
-->hello from server
There are two certificates, one for a CA (that’s the depth=1) and one for the server (that’s depth=0).
This is the configuration file needed for the example:
# # SSLeay example configuration file. # This is mostly being used for generation of certificate requests. # RANDFILE = $ENV::HOME/.sslrand #################################################################### [ ca ] default_ca = CA_default # The default ca section #################################################################### [ CA_default ] dir = . # Where everything is kept certs = $dir/certs # Where the issued certs are kept crl_dir = $dir/crl # Where the issued crl are kept database = $dir/index.txt # database index file. new_certs_dir = $dir/new_certs # default place for new certs. certificate = $dir/cacert.pem # The CA certificate serial = $dir/serial # The current serial number crl = $dir/crl.pem # The current CRL private_key = $dir/ca_key.pem # The private key RANDFILE = $dir/.rand # private random number file default_days = 365 # how long to certify for default_crl_days= 30 # how long before next CRL default_md = md5 # which md to use. # A few difference way of specifying how similar the request should # look # For type CA, the listed attributes must be the same, and the optional # and supplied fields are just that :-) policy = policy_match # For the CA policy [ policy_match ] countryName = match stateOrProvinceName = optional organizationName = match organizationalUnitName = optional commonName = supplied emailAddress = optional # For the 'anything' policy # At this point in time, you must list all acceptable 'object' # types. [ policy_anything ] countryName = optional stateOrProvinceName = optional localityName = optional organizationName = optional organizationalUnitName = optional organizationalUnitName = optional commonName = supplied emailAddress = optional #################################################################### [ req ] default_bits = 1024 #default_keyfile = newkey.pem distinguished_name = req_distinguished_name encrypt_rsa_key = no [ req_distinguished_name ] countryName = Country Name (2 letter code) countryName_default = US countryName_value = US organizationName = Organization Name (eg, company) organizationName_default = MegaWidget organizationName_value = MegaWidget organizationalUnitName = Organizational Unit Name (eg, section) organizationalUnitName_default = Eng organizationalUnitName_value = Eng commonName = Common Name (eg, YOUR name) commonName_default = Michael Grant #commonName_value = Michael Grant
18.117.111.1