This document covers how SSL connetions to IRC servers happen. This information was current as of EPIC5-2.1.6.
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.
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.
OpenSSL “verifies” the certificate and the client provides a C function to tag along for the ride. The callback function is called every time:
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:
The client tracks the “most serious error” (if there is one), using the above priorities.
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
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)
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
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.
This information was current as of EPIC5-2.1.6.