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
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
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,
Optional argument ca indicates a CA certificate.
Optional arguments cert and key indicate a peer
certificate and possibly a separate key file respectively.
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
Also, be sure to store the returned SSL-CONN object for later reference.
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.
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.
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,
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.
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
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 addons.mozilla.org (setq p (open-network-stream "moz" "moz" "addons.mozilla.org" 443)) ⇒ #<network connection "moz" (443 . "addons.mozilla.org") state:run> (setq m (ossl-ssl-handshake p)) ⇒ #<OpenSSL socket layer: TLSv1 on top of #<secure network connection "moz" (443 . "addons.mozilla.org") state:run>> ;; Let’s examine ‘p’ p ⇒ #<secure network connection "moz" (443 . "addons.mozilla.org") state:run> (ossl-ssl-finish m) ⇒ #<OpenSSL socket layer: dead> ;; Let’s examine ‘p’ again p ⇒ #<network connection "moz" (443 . "addons.mozilla.org") 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 CONNECTED(00000003) depth=1 /C=DE/ST=Berlin/O=hlidskjalf.org/OU=local CA/CN=hlid.hli dskjalf.org/emailAddressfirstname.lastname@example.org verify return:1 depth=0 /C=DE/ST=Berlin/O=hlidskjalf.org/OU=ldap client freundt/ CN=hlid.hlidskjalf.org/emailAddressemail@example.com verify return:1 --- Certificate chain 0 s:/C=DE/ST=Berlin/O=hlidskjalf.org/OU=ldap client freundt/CN= hlid.hlidskjalf.org/emailAddressfirstname.lastname@example.org i:/C=DE/ST=Berlin/O=hlidskjalf.org/OU=local CA/CN=hlid.hlidsk jalf.org/emailAddressemail@example.com --- Server certificate -----BEGIN CERTIFICATE----- MIIEQzCCAyugAwIBAgIBAzANBgkqhkiG9w0BAQUFADCBjzELMAkGA1UEBhMCREUx DzANBgNVBAgMBkJlcmxpbjEXMBUGA1UECgwOaGxpZHNramFsZi5vcmcxETAPBgNV BAsMCGxvY2FsIENBMRwwGgYDVQQDDBNobGlkLmhsaWRza2phbGYub3JnMSUwIwYJ KoZIhvcNAQkBFhZmcmV1bmR0QGhsaWRza2phbGYub3JnMB4XDTA2MDcxMjIxMDYy MloXDTA3MDcxMjIxMDYyMlowgZoxCzAJBgNVBAYTAkRFMQ8wDQYDVQQIDAZCZXJs aW4xFzAVBgNVBAoMDmhsaWRza2phbGYub3JnMRwwGgYDVQQLDBNsZGFwIGNsaWVu dCBmcmV1bmR0MRwwGgYDVQQDDBNobGlkLmhsaWRza2phbGYub3JnMSUwIwYJKoZI hvcNAQkBFhZmcmV1bmR0QGhsaWRza2phbGYub3JnMIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEA5CYPHlmyemdoAdNsiemskMm33GYBSCOx1KZEWQ1cfgf0 vVtpwue+/Nw4UbxYvtnS4ES8pWWEx/YeRyrEtbXg9SzXLSsNTrPT35xmysL87kIN nm8F4xGdlFQnvHJ4/55ieUVYi5aSlQtMKOON5HWUWmmWIscNnf3KyGy1lX1mEwhW xFYQ01npIz9az0zdBBqhV6mMejEul2vgwqL9lQy7khmwDwzoVdyyAz7C6Nj/7E6i gaxad9tc8luQJdMw+E6c67Stz68Om7CWfR7IMoqIx/ag7Ycy56dI8Td5LWvZ+JUG KMgHcbJ2mJIjQv3fgp7pIG2McPi91DwNLZhwJheshQIDAQABo4GcMIGZMAkGA1Ud EwQCMAAwEQYJYIZIAYb4QgEBBAQDAgTwMAsGA1UdDwQEAwIF4DAsBglghkgBhvhC AQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFKc+ UFGPNVlARKv02s3Agq2q/2YfMB8GA1UdIwQYMBaAFAZIDPDiOBUx1RM67GJRPh+k y90DMA0GCSqGSIb3DQEBBQUAA4IBAQAAr8FoMuRaP7YVcnsYVR9Vv6wbjuSlO0rk /CtYs5V8QGa7TsGBz+0aBCHeDKegwhEkNowcJrqSlHiLYd4o2sXMqwAyszz1CKF6 9PpZKXlhwZP5A9Hct9R0THV98f2qNCDOTTj9zxObnMIYJW4WLxGpgPTRTiERRdt3 VP0aC2vEKb9xblfUQNAyBZKh6bkeKJVvd9WmnUwYkwGfH1+alNIhqCkRPjv8sw31 ivzqspr2z19mtaYUKIN2u+mddJk7oeJIWNWwpaYicPR0rz9GOmVkgxIxMQAmtLnd ka47rxgbVZXtINcOZCNIcvX1hntqE5ItABunG3PGnNJwnqEQEfqJ -----END CERTIFICATE----- … DONE
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 foo.bar.tld\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 fluch.fresse.org ESMTP Postfix 220 2.0.0 Ready to start TLS 250-fluch.fresse.org 250-PIPELINING 250-SIZE 10240000 250-VRFY 250-ETRN 250-ENHANCEDSTATUSCODES 250-8BITMIME 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.
Convert the underlying process of ssl-conn into a secure network connection object.
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
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 foo.bar.tld\r\n") (ossl-ssl-write sock "QUIT\r\n"))) ⇒ nil
---------- Buffer: smtps ---------- 220 fluch.fresse.org 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
not work after unproselytising. There are special I/O functions for
Return the cleartext of string which is assumed to be a complete block of data sent through ssl-conn.
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.
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.
Return the protocol version of the tunnel ssl-conn.
Return the name of the current cipher used in the tunnel ssl-conn.
Return the names of all supported ciphers in the tunnel ssl-conn.
Return the number of effective bits of the current cipher in 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.
Return the local peer’s certificate of ssl-conn if present,
Return the remote peer’s certificate of ssl-conn if present,
Return the certificate chain of ssl-conn as a list of evp-pkey objects.
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" "www.thawte.com" 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/ CN=www.thawte.com 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.
Return the certificate subject of cert (an evp-pkey object).
This will return a string in LDAP syntax.
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.
Return the certificate serial of cert (an evp-pkey object).
Return the certificate valid-not-before time of cert.
Return the certificate valid-not-after time of cert.
Return the signature type of cert.
(let ((p (open-network-stream "go" "go" "gna.org" 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/CN=www.openssl.org/ emailAddressfirstname.lastname@example.org sub:/ST=The Internet/O=The OpenSSL Project/ OU=Certificate Authority/CN=OpenSSL CA/ emailAddressemail@example.com; RSA public key, size 1024>
(ossl-x509-subject c) ⇒ "/ST=The Internet/O=The OpenSSL Project/CN=www.openssl.org/ emailAddressfirstname.lastname@example.org"
(ossl-x509-issuer c) ⇒ "/ST=The Internet/O=The OpenSSL Project/ OU=Certificate Authority/CN=OpenSSL CA/ emailAddressemail@example.com"
(ossl-x509-serial c) ⇒ 1
(ossl-x509-not-before c) ⇒ "020802062727Z"
(ossl-x509-not-after c) ⇒ "030802062727Z"
(ossl-x509-signature-type c) ⇒ none