SSL certificaat uitlezen in PHP

Soms kan het nodig zijn om een SSL certificaat in PHP uit te lezen. Zo kan bijvoorbeeld de verloop datum van het SSL certificaat uitgelezen worden, wat weer makkelijk kan zijn voor het beheer hiervan. Ik ben een behoorlijk tijd hiermee aan het stoeien geweest, en wil dit daarom graag delen.

Gegevens opvragen

Het opvragen van de gegevens gebeurt met behulp van een stream, en ziet er zo uit:

  1. $url = 'www.ns.nl';
  2.  
  3. $context = stream_context_create();
  4. $res = stream_context_set_option($context, 'ssl', 'capture_peer_cert', true);
  5.  
  6. if ($socket = stream_socket_client("ssl://$url:443/", $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $context)) {
  7.         if ($options = stream_context_get_options($context)) {
  8.                
  9.                 if (isset($options['ssl']) && isset($options['ssl']['peer_certificate'])) {
  10.                         $x509_resource = $options['ssl']['peer_certificate'];
  11.                         $cert_arr = openssl_x509_parse($x509_resource);
  12.                        
  13.                 }
  14.         }
  15. }

Vervolgens staan alle gegevens van het certificaat als een array in de variabele $cert_arr. De inhoud van www.ns.nl ziet er zo uit:

  1. (
  2.     [name] => /C=NL/ST=Utrecht/L=Utrecht/O=NS Groep N.V./OU=IM&T/OU=Terms of use at pki.pinkroccade.com/rpa (c) 04/OU=Authenticated by PinkRoccade/OU=Member, VeriSign Trust Network/CN=www.ns.nl
  3.     [subject] => Array
  4.         (
  5.             [C] => NL
  6.             [ST] => Utrecht
  7.             [L] => Utrecht
  8.             [O] => NS Groep N.V.
  9.             [OU] => Array
  10.                 (
  11.                     [0] => IM&T
  12.                     [1] => Terms of use at pki.pinkroccade.com/rpa (c) 04
  13.                     [2] => Authenticated by PinkRoccade
  14.                     [3] => Member, VeriSign Trust Network
  15.                 )
  16.  
  17.             [CN] => www.ns.nl
  18.         )
  19.  
  20.     [hash] => b8136028
  21.     [issuer] => Array
  22.         (
  23.             [O] => VeriSign Trust Network
  24.             [OU] => Array
  25.                 (
  26.                     [0] => VeriSign, Inc.
  27.                     [1] => VeriSign International Server CA - Class 3
  28.                     [2] => www.verisign.com/CPS Incorp.by Ref. LIABILITY LTD.(c)97 VeriSign
  29.                 )
  30.  
  31.         )
  32.  
  33.     [version] => 2
  34.     [serialNumber] => 13450069566023452376054878293380199295
  35.     [validFrom] => 090813000000Z
  36.     [validTo] => 110813235959Z
  37.     [validFrom_time_t] => 1250121600
  38.     [validTo_time_t] => 1313279999
  39.     [purposes] => Array
  40.         (
  41.             [1] => Array
  42.                 (
  43.                     [0] => 1
  44.                     [1] =>
  45.                     [2] => sslclient
  46.                 )
  47.  
  48.             [2] => Array
  49.                 (
  50.                     [0] => 1
  51.                     [1] =>
  52.                     [2] => sslserver
  53.                 )
  54.  
  55.             [3] => Array
  56.                 (
  57.                     [0] => 1
  58.                     [1] =>
  59.                     [2] => nssslserver
  60.                 )
  61.  
  62.             [4] => Array
  63.                 (
  64.                     [0] =>
  65.                     [1] =>
  66.                     [2] => smimesign
  67.                 )
  68.  
  69.             [5] => Array
  70.                 (
  71.                     [0] =>
  72.                     [1] =>
  73.                     [2] => smimeencrypt
  74.                 )
  75.  
  76.             [6] => Array
  77.                 (
  78.                     [0] =>
  79.                     [1] =>
  80.                     [2] => crlsign
  81.                 )
  82.  
  83.             [7] => Array
  84.                 (
  85.                     [0] => 1
  86.                     [1] => 1
  87.                     [2] => any
  88.                 )
  89.  
  90.             [8] => Array
  91.                 (
  92.                     [0] => 1
  93.                     [1] =>
  94.                     [2] => ocsphelper
  95.                 )
  96.  
  97.         )
  98.  
  99.     [extensions] => Array
  100.         (
  101.             [basicConstraints] => CA:FALSE
  102.             [keyUsage] => Digital Signature, Key Encipherment
  103.             [certificatePolicies] => Policy: 2.16.840.1.113733.1.7.23.3
  104.   CPS: https://pki.pinkroccade.com/rpa
  105.  
  106.             [crlDistributionPoints] => URI:http://SVRIntl-crl.verisign.com/SVRIntl.crl
  107.  
  108.             [extendedKeyUsage] => TLS Web Server Authentication, TLS Web Client Authentication, Netscape Server Gated Crypto, Microsoft Server Gated Crypto
  109.             [authorityInfoAccess] => OCSP - URI:http://ocsp.verisign.com
  110. CA Issuers - URI:http://SVRIntl-aia.verisign.com/SVRIntl-aia.cer
  111.  
  112.             [1.3.6.1.5.5.7.1.12] => 0`¡^ \0Z0X0V      image/gif0!00+Kk¹(– »ÐR8›)¬K‹!0&$http://logo.verisign.com/vslogo1.gif
  113.         )
  114.  
  115. )

Verval dagen

De verval datum van het SSL certificaat is opgeslagen in de array key validTo, en in PHP timestamp formaat in de array key validTo_time_t. Hierdoor kan eenvoudig uitgerekend worden hoeveel dagen er nog over zijn voordat het SSL certificaat verloopt:

  1. $gd_a = getdate( $cert_arr['validTo_time_t'] );
  2. $gd_b = getdate( time() );
  3.  
  4. $a_new = mktime( 12, 0, 0, $gd_a['mon'], $gd_a['mday'], $gd_a['year'] );
  5. $b_new = mktime( 12, 0, 0, $gd_b['mon'], $gd_b['mday'], $gd_b['year'] );
  6.  
  7. echo round( abs( $a_new - $b_new ) / 86400 );

Dit geeft het aantal dagen over terug, bijvoorbeeld 28. Aan de hand hiervan kan dan bijvoorbeeld een waarschuwing naar de SSL beheerder gestuurd worden zodat deze het SSL certificaat vernieuwd.