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
ftp://psych.psy.uq.oz.au/pub/Crypto/SSL/
. 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
- Assuming the original socket variable is called
s
, call SSLeay.fromfd( s.fileno() )
to create an SSLeay object attached
to the socket.
- 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.
- 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
.
- If desired, set the verification callback. This callback allows you to customize your acceptance/rejection policy.
- 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
httplib.py that can handle secure servers.
- Change the __init__ method of the HTTP class to accept an
optional parameter SSL.
- Add the following block of code to the connect method.
if self.SSL:
import SSLeay
self.sock=SSLeay.fromfd(self.sock.fileno())
if self.debuglevel > 0: print 'SSL connect'
self.sock.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:
- NULL-MD5
- CBC-IDEA-MD5
- EXP-RC4-MD5
- RC4-MD5
- EXP-RC2-MD5
- RC2-MD5
- CBC-DES-MD5
- CBC3-DES-MD5
- CFB-DES-M1
- 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.
- SSLeay can be used with non-blocking I/O to handle multiple
connections simultaneously. While reading and writing on non-blocking
SSL connections appears to work, the
accept()
and
connect()
functions fail mysteriously.
- Lots of things are unimplemented or only partially implemented: for example, RSA objects and X.509 objects.
- Interfaces to RC4, DES, IDEA, MD{2,4,5} mimicking those in the PCT should be written so the SSLeay interface can stand on its own.