Table of Contents

Synopsis:

This document covers how SSL connetions to IRC servers happen. This information was current as of EPIC5-2.1.6.

Step One -- You connect to an SSL server

You connect to an irc server doing something like

/SERVER irc.example.com:6697:type=irc-ssl

This goes through connect()ing to the server, and then doing an SSL_connect() to set up the certificate exchange and TLS negotiation.

Step Two -- The SSL handshake is completed

After the SSL_connect() step has completed, we now have a fully functioning TLS socket with an SSL certificate. Before we use the TLS socket, we're supposed to verify we trust the SSL certificate, to ensure we're talking to who we think we are.

Step Three -- The client watches the certificate verification

OpenSSL “verifies” the certificate and the client provides a C function to tag along for the ride. The callback function is called every time:

  1. An error is discovered, or
  2. There are no (further) errors in a certificate.

Thus, if a certificate is trusted, it will only report “no problems” for each link in the chain.

This permits the client to trap and categorize every error that happens - some certificates have multiple problems! There are three buckets the client uses:

  1. Self-signed certificates
  2. Incorrect-hostname certificates
  3. Any other (serious) error

The client tracks the “most serious error” (if there is one), using the above priorities.

Step Four - The client offers you /ON SSL_SERVER_CERT

The client sets $serverctl(SET <refnum> SSL_ACCEPT_CERT -1) and then throws /ON SSL_SERVER_CERT. The use of -1 is on purpose so the client can determine whether your /ON handler sets it to 0 or 1.

If your handler does a $serverctl(SET <retval> SSL_ACCEPT_CERT 0|1) then that is taken as the final disposition of the handling, and nothing further occurs. (ie, it skips the rest of the steps)

Parameters of /ON SSL_SERVER_CERT

              $0  The fd of the socket
                  (Use $serverctl(FROM_SERVER) to get the server refnum)
              $1  Certificate Subject, url-encoded
              $2  Certificate Issuer, url-encoded
              $3  Bits used in the public key
              $4  OpenSSL error code of the "most serious error"
                      (18 is "Self-signed certificate",
                       62 is "Hostname mismatch",
                       everything else is irregular/bad)
              $5  The SSL regime being used (ie, TLSv1.2)
              $6  The Certificate Hash
              $7  Was there a hostname mismatch?  0 = no error, 1 = error
              $8  Was there a self-signed error?  0 = no error, 1 = error
              $9  Was there another (serious) error?
                      0 = no other error 1 = other error
              $10 Was there any error of any kind?
                      0 = no errors of any kind, 1 = some kind of error

Step Five -- The client makes a provisional decision

Next, the client looks at the errors and decides whether it thinks the cert is ok.

Description Outcome
Cert has no errors ACCEPT
Cert has “self signed” or “wrong hostname” error and /SET ACCEPT_INVALID_SSL_CERT ON ACCEPT
Cert has “self signed” or “wrong hostname” error aand /SET ACCEPT_INVALID_SSL_CERT OFF REJECT
Cert has any serious error REJECT

The client sets this provisional value with

$serverctl(SET <refnum> SSL_ACCEPT_CERT 0|1)

Step Six - The client offers you ON SERVER_SSL_EVAL

Then, the client hooks /ON SERVER_SSL_EVAL. At this point, all of the information your script needs to make a fully informed decision to accept or overrule the client's choice is available. Your handler is not obligated to make any change, but it certainly can if it wants to

Parameters of /ON SERVER_SSL_EVAL

              $0  The server refnum
              $1  The "ourname" of the server (what you /server'd to)
              $2  Was there any error at all?
                      0 = no errors of any kind   1 = some kind of error
              $3  Was there a hostname mismatch?  0 = no error, 1 = error
              $4  Was there a self-signed error?  0 = no error, 1 = error
              $5  Was there another (serious) error?
                      0 = no other error, 1 = other error
              $6  What does the client suggest?
                      0 = reject certificate, 1 = accept certificate

Using $serverctl() to get info about the certificate Use $serverctl(GET <refnum> <item>) where <item> is:

SSL_CIPHER The encryption cipher being used
SSL_PEM The certificate (in PEM format)
SSL_CERT_HASH The certificate's hash
SSL_PKEY_BITS The bits in the public key
SSL_SUBJECT Who the cert was issued to
SSL_SUBJECT_URL Who the cert was issued to (url-encoded)
SSL_ISSUER Who issued the cert
SSL_ISSUER_URL Who issued the cert (url-encoded)
SSL_VERSION What version of SSL being used (ie, TLSv1.2)
SSL_SANS Subject Alternate Names in the cert
SSL_CHECKHOST_ERROR Hostname Mismatch error - 0 (no) 1 (yes)
SSL_SELF_SIGNED_ERROR Self-signed error - 0 (no) 1 (yes)
SSL_OTHER_ERROR Any other (serious) error - 0 (no) 1 (yes)
SSL_MOST_SERIOUS_ERROR The OpenSSL error code of the most serious error 18 (self-signed) and 62 (hostname mismatch) are considered non-serious (routine) errors
SSL_VERIFY_ERROR Any error at all - 0 (no) 1 (yes)
SSL_ACCEPT_CERT Is this cert headed for acceptance? 0 (no) 1 (yes)

To reject the cert:

$serverctl(SET <refnum> SSL_ACCEPT_CERT 0) 

To accept the cert:

$serverctl(SET <refnum> SSL_ACCEPT_CERT 1) 

If you don't do anything, the client will do the most reasonable thing

Step Seven - The client moves forward

Finally, everyone has had a chance to weigh in. Whatever the value of

$serverctl(GET <refnum> SSL_ACCEPT_CERT)

is after all this, is used to accept or reject the SSL connection.

History:

This information was current as of EPIC5-2.1.6.