Feedback on the new certificate options.
I see that it's now possible to have a server ignore the global certificate by going to the serverlist and unchecking 'use global certificate' without defining one for that entry. However, if there's now a way to do the same thing with the /server command, I don't see it. If I use the /server command with -key $null for a server not in the serverlist, it will either use the global certificate, or it will go to the [recent] section of servers.ini to use a setting from there.
If I use alt+E to look at the serverlist, it lies to me as if my current server connection is in the serverlist when it's not really there, giving it a label like $network $servertarget. And, if I try to delete it from the serverlist menu, it always comes back again.
Some issues remain from the
https://forums.mirc.com/ubbthreads.php/ubb/showflat/Number/263699/ thread, where using the /server command to connect to a server that's not in the serverlist means that you can't find info about the current connection because $server($servertarget) is blank. The only way to figure out what certificate you're actually using is to use $sslhash(sha512,p) then compare that against a saved list of fingerprints. Maybe having $server(-1) return properties for whatever is the active connection.
Something else that could be confusing to users is that $server().property is returning things it gets by looking at the serverlist instead of looking at the current connection. For example, when the current connection is in the serverlist, $server($servertarget).cert returns the name of the certificate listed for that serverlist entry in servers.ini, but you'd need to use $server($servertarget).certglobal to see whether that certificate is being used or not. The only way to see what the global certificate is, is to check $readini($mircini,ssl,key)
However, if you edit the serverlist or the config for the global cert after you've connected, neither $readini($mircini,ssl,key) or $server($servertarget).cert or $server($servertarget).certglobal are guaranteed to tell you what cert.pem was used to connect to the active server window.
--
There still isn't a way for people to know how long until their cert expires, and for finding out how long the cert has been used, they can only use the filename.pem's timestamp. The certs are being created with a 3 year lifetime, which is the max time generally accepted for certificates, but some people might want to change them anually. I tested the new beta with a certificate that's expired, and mIRC silently uses it in the handshake which will fail.
The script below is a quick/dirty attempt to examine a .pem to see when it expires or was issued. If there's more than 1 certificate in the file, it sees just the 1st one.
$CertExpire(client.pem) returns the number of days until it expires, with a negative number indicating that it expired
$CertExpire(client.pem,i) returns the number of days since it was issued.
I noticed that cacert.pem contains a certificate that's expiring in Jan 2028, which is the same expiration date contained in the cacert.pem back in v7.45 too, so it look like users of all versions will eventually need a new cacert.pem
/*
{
$CertExpire( [filename.pem] , [i] ) by maroon 2022
By default, this looks at filename stored as the global cert in mirc.ini
but you can set $1 to be another filename instead
It assumes the file contains a Certificate in .pem format, then makes a very simplistic check
to see if there's a valid expiration timestamp. If so, it compares against the current time
to see how long until the certificate expires, returning a float containing the number of days
until the cert expires. If it returns a negative number, the cert has expired.
If $2 is 'i' it instead returns the number of days since the cert was issued
mIRC seesm to issue certs with approximately 3 years of life from when they were created,
but it doesn't offer syntax to warn when your cert has expired or will expire soon
In addition to that, some users may wish to change certificates more often than 3 year intervals
Examples:
$certexpire
result: number of days until the global certificate expires
$certexpire(libera.pem)
result: number of days until the certificate in libera.pem expires
$certexpire(libera.pem,i)
result: number of days since the certificate in libera.pem was first valid
}
*/
certexpire {
var %f $readini($mircini,ssl,key)
if ($isfile($1)) var %f $1
var %i $read(%f,ntw,-*-BEGIN CERTIFICATE-*-)
if (!%i) goto syntax | var %i 1 + $readn
bunset &maroon.cert
while (1) {
var %a $read(%f,nt,%i) | if (!$regex(%a,^[a-zA-Z0-9/+]+=*$)) break
bset -t &maroon.cert $calc(1+$bvar(&maroon.cert,0)) %a | inc %i
}
if (!$bvar(&maroon.cert,0)) goto syntax | noop $decode(&maroon.cert,bm)
var %i 1
:findtime
; 0x30 0x1e 0x17 0x0d
var %a $bfind(&maroon.cert,%i,48 30 23 13)
if (!%a) goto syntax
var %notbefore $bvar(&maroon.cert,$calc(%a + 4 ),13).text
var %notafter $bvar(&maroon.cert,$calc(%a + 4+15),13).text
if ( !$regex(foo,%notbefore $+ %notafter,^\d{12}Z\d{12}Z$)) goto findtime
if ( $bvar(&maroon.cert,$calc(%a + 17-1),3 ) != 90 23 13) { inc %i | goto findtime }
var %expire $regsubex(foo,20xx/xx/xx xx:xx:xx,/(x)/g,$mid(%notafter ,\n,1) )
var %issued $regsubex(foo,20xx/xx/xx xx:xx:xx,/(x)/g,$mid(%notbefore,\n,1) )
var %expire $ctime( %expire ) , %now $gmt , %issued $ctime( %issued )
;echo -a $asctime(%now) vs $asctime(%expire) vs $asctime(%issued)
var %days $calc( (%expire - %now)/86400 )
if ($2 == i) { var %days $calc( (%now - %issued)/86400 )
echo -sc info Cert %f issued %days days ago | return %days }
if (%days < 0) echo -s 8,13 Cert %f expired %days ago!
elseif (%days <= 31) echo 4 -s Cert %f expires in %days days!
else echo -sc info Cert %f expires in %days days
return %days
:syntax
echo -sc info days until expire: *$certexpire( [filename] , [i]) default=client.pem i=$2=days since issued
}