简体   繁体   中英

PHP: Check if a loaded TLS certificate is trusted

The program fetches a TLS certificate chain from a server and does several checks. It should check if the last part of the chain points to a trusted certificate. Here is an excerpt show the relevant part:

$g = stream_context_create(array("ssl" => array(
  "capture_peer_cert" => true,
  "capture_peer_cert_chain" => true,
  "peer_name" => $domain,
  "verify_peer" => false,
  "verify_peer_name" => false,
  "SNI_enabled" => true,
  )));
$r = @stream_socket_client($url, $errno, $errstr, 5, STREAM_CLIENT_CONNECT, $g);
$cont = stream_context_get_params($r);
$certchain = &$cont["options"]["ssl"]["peer_certificate_chain"];
$ChainAuthorityIds = array();

Snip: Now, there follows some longer code that fills up the array ChainAuthorityIds like that: 0-indexed each index contains an array of two fields: subject containing the key Id of the subject field, and authority , containing the key Id of the authority field. This is done by using openssl_x509_parse() .

Afterwards, we can check for correct order like this:

$correctorder = true;
$previous_authority = null;
foreach ($ChainAuthorityIds as $num => &$details) {
  if ($previous_authority !== null) {
    if ($details['subject'] != $previous_authority) $correctorder = false;
  }
  $previous_authority = $details['authority'];
}
unset($details);

So, in $ChainAuthorityIds[count($ChainAuthorityIds) - 1]['authority'] must be the key Id of a certificate that is stored in OpenSSL's directory of trusted roots. How can I check if this key is part of this truststore? Also, I want to explicitly load this certificate (possibly with something like openssl_x509_parse() ) into memory to check its validity period.

PS: If the chain is over-complete, and the last certificate is the root, then it contains an empty string as authority Id key. This case is properly handled in my program, but for sake of simplicity not shown in this question.

Suprisingly, the answer is quite simple. OpenSSL holds its truststore in a directory containing each root certificate as PEM file - one certificate per file. So, all that needs to be done is finding out which directory this is. This can be done by using the PHP command openssl_get_cert_locations() . It returns an array, of which the index default_cert_dir holds the said directory name.

$locations = opnenssl_get_cert_locations();
$pemfiles = glob($locations['default_cert_dir'] . '/*.pem');
foreach ($permfiles as $pemfile) {
  $rootcert = openssl_x509_parse(openssl_x509_read($pemfile));
  // do something with $rootcert
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM