Previous: , Up: SXEmacs OpenSSL API   [Contents][Index]

62.2.7 Secure Network Layers

The SSL/TLS support in this API is definitely not a copy of the underlying libssl functions. Instead we chose a higher level of access methods because for example SSL_connect does not work standalone, and having an elisp loop to check socket messages is probably not desirable.

Also we chose to actually do what SSL/TLS stands for, namely to establish a transparent security layer on top of an existing network connection. That is, you can use the usual open-network-stream+ set-process-filter + process-send-string chain and at some point after the establishment of the connection you can coat that connection with a secure layer. Of course, this is done transparently and your existing process filter or send-string commands will not notice the change.

Function: ossl-ssl-handshake process &optional method ca cert key serverp

Perform a handshake on the network connection process.

Return a ssl-conn object, or nil if the handshake failed. In the latter case, most likely the remote site cannot handle the specified method, requires a client certificate, or cannot handle ssl at all.

Optional argument method indicates the SSL connection method, it can be one of tls1 which is the default, ssl23, ssl2, or ssl3.

Optional argument ca indicates a CA certificate. See ossl-ssl-inject-ca.

Optional arguments cert and key indicate a peer certificate and possibly a separate key file respectively. See ossl-ssl-inject-peer-cert.

Optional argument serverp indicates whether to perform the handshake as a server if non-nil, and as a client otherwise. Note: In case of a handshake as server it is mandatory to provide a valid certificate and a corresponding key.

Currently there are no high level ‘open-ssl-stream’ (and such) functions. You have to invoke open-network-stream first and after establishing that connection ossl-ssl-handshake should be performed.

Also, be sure to store the returned SSL-CONN object for later reference.

Function: ossl-ssl-finish ssl-conn

Finish an SSL connection ssl-conn.

Note: This may also finish the network connection.

As noted above, not all peers finish the connection after finishing the SS-Layer but it is highly suggested to do so. Unpredictible results may occur when you keep using that connection.

Function: ossl-ssl-inject-cert ssl_conn cert &optional key

Add cert as the local certificate of ssl-conn. Optional argument key specifies a key file or evp-pkey, if cert does not contain it.

Both, cert and key may be either a filename pointing to a PEM-encoded certificate and key respectively, or may be an evp-pkey object.

Function: ossl-ssl-inject-ca ssl-conn ca

Add ca to the pile of certificate authorities of ssl-conn. Also force a (re)verification of the remote peer certificate against ca. Return t if the injection was successful, nil otherwise.

ca may be either a file name pointing to a PEM-encoded CA certificate, or may be a directory containing a valid bunch of CA certificates according to OpenSSL’s CA path layout, or may also be an evp-pkey object.

While ossl-ssl-inject-ca may be used even after handshaking with the remote peer, for example to introduce a certificate authority to verify the remote peer’s identity with hindsight, the same does not apply to ossl-ssl-inject-peer-cert since local peer verification at the remote site can only take place at handshake time. Regard that function as convenience function.

;; open a https connection to
(setq p (open-network-stream "moz" "moz" "" 443))
  ⇒ #<network connection "moz" (443 . "") state:run>

(setq m (ossl-ssl-handshake p))
  ⇒ #<OpenSSL socket layer: TLSv1 on top of
       #<secure network connection "moz"
         (443 . "") state:run>>

;; Let’s examine ‘p
  ⇒ #<secure network connection "moz"
       (443 . "") state:run>

(ossl-ssl-finish m)
  ⇒ #<OpenSSL socket layer: dead>

;; Let’s examine ‘p’ again
  ⇒ #<network connection "moz"
       (443 . "") state:exit>

Offering a secure listening socket works quite similar as the following example shows.

;; build the acceptor function
(defun my-acceptor (proc)
  (ossl-ssl-handshake proc 'ssl23 nil
   "/path/to/server.cert" "/path/to/server.key" t))
  ⇒ my-acceptor

;; establish the listening socket
(open-network-server-stream "listen" "listen"
 "localhost" 4432 'tcp #'my-acceptor)
  ⇒ #<network server accepting connections "listen"
       (4432 . "localhost") state:run>
We connect using the OpenSSL command line interface.

freundt@hlid:~$ openssl s_client -ssl3 -connect localhost:4432 \
  -CAfile /etc/ssl/CA/cacert.pem
depth=1 /C=DE/ST=Berlin/ CA/CN=hlid.hli
verify return:1
depth=0 /C=DE/ST=Berlin/ client freundt/
verify return:1
Certificate chain
 0 s:/C=DE/ST=Berlin/ client freundt/CN=
   i:/C=DE/ST=Berlin/ CA/CN=hlid.hlidsk
Server certificate

which is exactly the expected output.

At the moment it is not possible to establish a server socket with an SSL acceptor and connect to this with another network stream from within the same SXEmacs instance. This is because the SSL handshake is entirely on top of the process system and the event stream does not know about a special treatmeant of handshakes. In the above scenario both connections would block each other since the handshake is a multiple turn procedure with a fixed order, but the event loop does not know about the correct order, hence both networks streams would exit prematurely because of timeouts.

However, the above examples are actually all you need to acquire secure sockets. In order to communicate over the socket the usual tools can be used. See Processes.

;; invoke a local postfix and negotiate a TLSv1 session
(let ((p (open-network-stream "smtps" "smtps" "localhost" 25)))
  (process-send-string p "STARTTLS\r\n")
  (ossl-ssl-handshake p)
  (process-send-string p "EHLO\r\n")
  (process-send-string p "QUIT\r\n"))
  ⇒ nil
we look at the resulting process buffer
TLS becomes active at the third line (reply code 250)
---------- Buffer: smtps ----------
220 ESMTP Postfix
220 2.0.0 Ready to start TLS
250-SIZE 10240000
250 DSN
221 2.0.0 Bye

Process smtps exited abnormally with code 256
---------- Buffer: smtps ----------

Once a successful handshake has been done the returned ssl-conn object can be used to determine and tune useful things. The following two functions affect the interlinkage between the secure socket and the ordinary network socket.

Function: ossl-ssl-proselytise-process ssl-conn

Convert the underlying process of ssl-conn into a secure network connection object.

Function: ossl-ssl-unproselytise-process ssl-conn

Convert the underlying process of ssl-conn into an ordinary network connection object.

After handshaking the secure layer is transparently linked to the network socket automatically hence ossl-ssl-proselytise-process need not be called explicitly. That is also why the buffer output in the above example remained readable. In contrast ossl-ssl-unproselytise-process unleashes the link between secure socket and network stream. Having access to the raw (encrypted) SSL stream may have advantages when a program is supposed to just forward the stream to somewhere.

(let ((p (open-network-stream "smtps" "smtps" "localhost" 25)))
  (process-send-string p "STARTTLS\r\n")
  (let ((sock (ossl-ssl-handshake p)))
    (ossl-ssl-unproselytise-process sock)
    (ossl-ssl-write sock "EHLO\r\n")
    (ossl-ssl-write sock "QUIT\r\n")))
  ⇒ nil
---------- Buffer: smtps ----------
220 ESMTP Postfix
220 2.0.0 Ready to start TLS
< < < < < < < < < <
< raw binary data >
> > > > > > > > > >

Process smtps exited abnormally with code 256
---------- Buffer: smtps ----------

The snipped portion is a bunch of binary data. Nonetheless, as can be seen in the example sending data via process-send-string will not work after unproselytising. There are special I/O functions for this case.

Function: ossl-ssl-read ssl-conn string

Return the cleartext of string which is assumed to be a complete block of data sent through ssl-conn.

Function: ossl-ssl-write ssl-conn string

Send string to the tunnel ssl-conn.

After all, unlinking the two layers currently only works in one direction. The ssl-conn object will always know its parent network-stream.

Function: ossl-ssl-parent ssl-conn

Return the underlying parent layer of ssl-conn.

In the linked case the converse can be determined by process-type-data, see Processes.

In order to obtain information about the ciphers which protect the tunnel communication we provide a bunch of useful functions. At the moment ssl-ciphers are automatically negotiated with the remote site during the handshake procedure and cannot be explicitly requested or set by the user.

Function: ossl-ssl-cipher-version ssl-conn

Return the protocol version of the tunnel ssl-conn.

Function: ossl-ssl-cipher-name ssl-conn

Return the name of the current cipher used in the tunnel ssl-conn.

Function: ossl-ssl-cipher-names ssl-conn

Return the names of all supported ciphers in the tunnel ssl-conn.

Function: ossl-ssl-cipher-bits ssl-conn

Return the number of effective bits of the current cipher in ssl-conn.

Function: ossl-ssl-cipher-description ssl-conn

Return a description of the current cipher used in the tunnel ssl-conn.

Nowadays secure socket layers not only provide security but also authenticity. While ciphers are the atoms for the former, certificates play the major role for the latter. However, authenticity is quite optional within the SSL protocol. That is why we often append the phrase “if present” in the documentation strings of the following functions.

Function: ossl-ssl-cert ssl-conn

Return the local peer’s certificate of ssl-conn if present, nil otherwise.

Function: ossl-ssl-peer-cert ssl-conn

Return the remote peer’s certificate of ssl-conn if present, nil otherwise.

Function: ossl-ssl-peer-cert-chain ssl-conn

Return the certificate chain of ssl-conn as a list of evp-pkey objects.

Function: ossl-ssl-verify-certificate ssl-conn

Return a verify code of ssl-conn.

The result is a cons cell with the numeric verify code in the car and a verbose string in the cdr.

(let* ((str (open-network-stream "th" "th" "" 443))
       (sslc (ossl-ssl-handshake str 'ssl3)))
  (ossl-ssl-peer-cert-chain sslc)
  ⇒ (#<OpenSSL X509 Certificate iss:/C=ZA/
        O=Thawte Consulting (Pty) Ltd./CN=Thawte SGC CA
        sub:/C=US/O=VeriSign, Inc./OU=Class 3 Public Primary
        Certification Authority; RSA public key, size 1024>
      #<OpenSSL X509 Certificate iss:/C=ZA/ST=Western Cape/
        L=Cape Town/O=Thawte Consulting (Pty) Ltd/OU=Security/ sub:/C=ZA/O=Thawte Consulting (Pty) Ltd./
        CN=Thawte SGC CA; RSA public key, size 1024>)

Certificates which stem from one of these functions are usually wrapped in an evp-pkey object. In contrast to the public-key handling functions above, certificates usually carry a lot more information. Hence evp-pkey objects with certificate data occupy an additional slot to store X509- and ASN1-specific data. Nonetheless, passing evp-pkey objects without X509/ASN1 data will not do harm.

Again, certificate specific data in an SSL connection are read-only at the moment. Only the two injection functions, and the handshake function provide a limited form of influence.

Function: ossl-x509-subject cert

Return the certificate subject of cert (an evp-pkey object).

This will return a string in LDAP syntax.

Function: ossl-x509-issuer cert

Return the certificate issuer of cert (an evp-pkey object), that is the organisation which signed the certificate.

This will return a string in LDAP syntax.

Function: ossl-x509-serial cert

Return the certificate serial of cert (an evp-pkey object).

Function: ossl-x509-not-before cert

Return the certificate valid-not-before time of cert.

Function: ossl-x509-not-after cert

Return the certificate valid-not-after time of cert.

Function: ossl-x509-signature-type cert

Return the signature type of cert.

(let ((p (open-network-stream "go" "go" "" 443))
      (s (ossl-ssl-handshake p 'tls1)))
  (setq c (ossl-ssl-peer-cert s)))
  ⇒ #<OpenSSL X509 Certificate iss:/ST=The Internet/
       O=The OpenSSL Project/
       sub:/ST=The Internet/O=The OpenSSL Project/
       OU=Certificate Authority/CN=OpenSSL CA/;
       RSA public key, size 1024>
(ossl-x509-subject c)
  ⇒ "/ST=The Internet/O=The OpenSSL Project/"
(ossl-x509-issuer c)
  ⇒ "/ST=The Internet/O=The OpenSSL Project/
      OU=Certificate Authority/CN=OpenSSL CA/"
(ossl-x509-serial c)
  ⇒ 1
(ossl-x509-not-before c)
  ⇒ "020802062727Z"
(ossl-x509-not-after c)
  ⇒ "030802062727Z"
(ossl-x509-signature-type c)
  ⇒ none

Previous: , Up: SXEmacs OpenSSL API   [Contents][Index]