The Python SSLeay interface

1.1. Introduction

There are lots of networked applications that could benefit from added security via encryption. However, a lot of painful rewriting of code would be needed to produce secure versions.

The Secure Socket Layer (SSL) was designed by Netscape Communications Corp. to provide a layer of encryption on top of TCP/IP. The intention is to make it as easy as possible to convert an unsecured application to a secured one, without having to rewrite a lot of the code; you can simply run the old, unsecured protocol on top of SSL, automatically encrypting each transaction before sending it over the wire. The Python SSLeay interface aims for the same goal, but achieves it to an even greater degree thanks to Python's flexibility. Frequently the extra code required to use SSLeay is less than 5 lines!

The SSL standard is publicly available, and hence the door is open for different implementations of it. One such implementation is SSLeay, by Eric A. Young, available at Python interfaces to other SSL implementations (such as Netscape's SSLRef) could also be written.

1.2. The SSL model of the world

The SSL protocol assumes an authentication framework matching that described in the ISO X.509 standard. A simplified description of X.509 as used by SSL follows.

In public-key algorithms, each cryptographic key has two parts: a public and a private component. Armed with only the public component of a key, it's possible to send encrypted messages that only the holder of the private key can decode. The owner of the private key can also produce a signature for a message; anyone can verify the signature as long as they have a copy of the public key.

SSL assumes that the server always has a public/private key pair. The validity of keys is attested to via key signatures, or certificates, from some certification authority (CA). The CA's key may be certified by some higher-level CA, which in turn may be certified by yet other CAs, thus producing a hierarchy. X.509's approach to key certification has a slightly different emphasis from the freeware program Pretty Good Privacy (PGP). PGP adopts a decentralized model where every user is a potential CA; the individual user can select any number of certification authorities, producing a directed graph of certifications called the Web of Trust. X.509 implementations will probably take a more centralized approach and assume that the number of CAs is relatively small.

The root authority has a public key that is trusted by definition; presumably it's so widely disseminated that an adversary has no conceivable chance of substituting his public key for the authority's. For example, the Netscape browser contains keys from both VeriSign and Netscape in its code. Keys certified by either of those authorities will be taken as valid by the browser. (Recent betas allow adding CAs, letting you decide which authorities you trust.)

The client may or may not have a public key; if it does, the client can authenticate itself to the server. If the identity of the other party can't be verified, the code can implement whatever security policy is desired, either proceeding despite the failure or closing the connection immediately.

On initiating an SSL connection, the client and server automatically agree on an encryption method that both of them can use, and a key to use for that algorithm. This is done securely using the server's public key, so that an eavesdropper cannot determine the key being used. All communications between the client and server are then automatically encrypted. Once the initial negotiation is complete, the SSLeay C interface provides SSL_read and SSL_write functions which are quite similar to the POSIX functions read and write. However, some code changes are still required to make an application SSL-aware. The Python interface can do quite a bit better than C; once the socket connection is made, using SSL requires only a few simple additional steps.

1.3. Making a program SSL-aware

  1. Assuming the original socket variable is called s, call SSLeay.fromfd( s.fileno() ) to create an SSLeay object attached to the socket.
  2. If the program is acting as a server, it should at least select a public key with one of the use_RSAkey* functions. If the key has been certified by some CA, the certificates to be used should be set via one of the use_certificate* functions.
  3. Usually server keys will be kept in an encrypted form, and it will be decrypted when required. The decryption password is obtained by calling the function passed to set_getkey_callback.
  4. If desired, set the verification callback. This callback allows you to customize your acceptance/rejection policy.
  5. Call the SSLeay object's connect or accept method, depending on whether you are implementing a client or a server, respectively. This will perform the negotiation process; if no errors occur, an SSLeay object will be returned. Otherwise, an exception is raised.
From this point onward, SSLeay objects support the methods of both ordinary socket objects and file objects. Thus, most programs that use sockets can be modified to use SSL by adding code to perform the 4-5 steps above just after calling the socket's connect or accept method.

For example, here are the changes required to create a version of that can handle secure servers.

  1. Change the __init__ method of the HTTP class to accept an optional parameter SSL.
  2. Add the following block of code to the connect method.
    if self.SSL:
    	import SSLeay 
    	if self.debuglevel > 0: print 'SSL connect'

1.4. Reference Guide

There are only a few module-level functions in the SSLeay interface.

fromfd (fd) -- Function of SSLeay module
Returns an SSLeay object, constructed from the given file descriptor. (The file descriptor for a socket or file object can be obtained by calling the object's fileno() method.) Note that this function simply initializes internal variables; it doesn't actually perform the negotiation required to produce a connection. For that you must call the accept() or connect() methods of the SSLeay object, depending on whether you're implementing a client or a server.
set_getkey_callback (func) -- Function of SSLeay module
Usually RSA keys are stored in an encrypted form, and only decrypted when needed to negotiate an SSL connection. This means the password is needed at irregular intervals, and is obtained by calling the function func, which should return a string corresponding to the password. For example, a secure HTTP server might request the password on starting up, and the callback would then simply return it as a string when requested. In a different application where it's known that the user will be present, one might request the password from the user by displaying a prompt or popping up a dialog box.
set_verify_callback (func) -- Function of SSLeay module
The verification callback lets you customize the verification policy employed by the application; it can limit the depth of a chain of certification, ignore certain untrustworthy CAs, or whatever. I don't yet have a good example to show the use of this feature. :)

1.4.1. SSLeay objects

accept () -- Method on SSLeay objects
Carry out the SSL negotatiation phase, acting as a server.
close () -- Method on SSLeay objects
Terminate the SSL connection and close the socket.
connect () -- Method on SSLeay objects
Carry out the SSL negotatiation phase, acting as a client. No certificate is required, though one may be necessary if the server will attempt to verify the client's identity.
fileno () -- Method on SSLeay objects
Return the file descriptor of the socket being used.
flush () -- Method on SSLeay objects
Theoretically, this should flush the output buffer of the SSLeay socket being used. Currently SSL_flush() isn't implemented in SSLeay.
makefile () -- Method on SSLeay objects
This is to help SSLeay sockets emulate the standard socket objects. This call returns an object that supports the methods of file objects. Since SSLeay objects already support those methods, this simply returns the object itself.
readline (num) -- Method on SSLeay objects
Read a full line of data from the socket, up to num bytes or until a newline or EOF is hit. If EOF is hit immediately, the empty string ('') is returned.
readlines () -- Method on SSLeay objects
Read several lines of data from the socket, and return them in a list. If EOF is hit immediately, the empty list ([]) is returned.
recv (num) -- Method on SSLeay objects
Read num bytes of data from the socket; the data is plaintext, having been automatically decrypted on being received. If num is zero, the empty string is returned; if num is absent or negative, as much data as possible is read.

read() is a synonym for this function, to provide compatibility with file objects.

send (str) -- Method on SSLeay objects
Send the data in str to the socket; the data is plaintext, which will be automatically encrypted and sent to the peer.

write() is a synonym for this function, to provide compatibility with file objects.

use_certificate (X509cert) -- Method on SSLeay objects
use_certificate_DER (str) -- Method on SSLeay objects
use_certificate_file (filename) -- Method on SSLeay objects
use_RSAkey (RSAobj) -- Method on SSLeay objects
use_RSAkey_DER (str) -- Method on SSLeay objects
use_RSAkey_file (filename) -- Method on SSLeay objects
writelines (L) -- Method on SSLeay objects
L should be a list of strings, which will be sent to the socket; the data is considered to be plaintext, which will be automatically encrypted and sent to the peer. No line separators are added to the data. This is the counterpart of readlines().
peer_cert -- Variable of SSLeay objects
Contains the certificate of the peer, the party on the other side of the connection. This is an X.509 object.
cipher -- Variable of SSLeay objects
Contains a human-readable string giving the cipher and hashing algorithms currently in use. Some possible values are:
pending -- Variable of SSLeay objects
timeout -- Variable of SSLeay objects

1.4.2. X509 objects

PEM () -- Method on X509 objects
oneline_issuer_name -- Variable of X509 objects
oneline_subject -- Variable of X509 objects

1.5. Legal ramifications

Writing cryptographic software requires crossing a minefield of patents, copyrights, and export restrictions. Usually, most independent implementations are illegal in the US and other countries because they haven't been approved by the patent holders. SSLeay provides its own implementation of the RSA algorithm; however, it is possible to link SSLeay so that it uses the code in the RSAref library, which is available from RSA Data Security Inc. RSAref is legal to use, and free for non-commercial use. I haven't yet tried using RSAref with Python and SSLeay, though I don't foresee any problems in doing so.

1.6. Bugs and Omissions

As of version 0.04b, there are several parts of the SSLeay interface missing. It's quite possible to use the interface despite the gaps; mostly they affect advanced capabilities.