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
Code
/*
{
  $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
}