2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

[個人メモ][PHP]ドメインのSSL証明書の有効期限の取得(subjectAltNameまで見る)

Last updated at Posted at 2020-08-07

個人メモとして記事っぽくまとめ。

PHPでドメインのSSL証明書の有効期限を取得するコードは先人たちの英知に学ぶとして大幅に前段を省略しますが、最後はopenssl_x509_parseで返ってきた値の[subject][CN]と対象ドメインを比較して有効期限の取得判断をしています。
この時面倒なのが、例えばwww.yahoo.co.jpでこれを調べてみると、

image.png

のように*付きでくるので単純比較では不一致になってしまうことですね。
まぁこれは正規表現でも使ってあげればいいので、脳死コーディングするなら

if( strpos($parsed['subject']['CN'], $domain_name) !== false ||
	preg_match(sprintf('/^.%s$/',$parsed['subject']['CN']), $domain_name) === 1 )
{
	echo '有効期限:' . date('Y/m/d', $parsed['validTo_time_t']);
}

とでもしてあげればよいのですが、面倒なものだと、

image.png

とかあるわけですね。
そんなときは、[extensions]の[subjectAltName]まで見てあげないといけないはずです。

image.png

うわっめんどい、と一瞬思いますが、単純なパース処理なので、難しく考えずexplode、foreach、preg_matchあたりを使えばできるかと。余計な空白もあるのでtrimも忘れずに。

まぁここまで厳密に有効期限チェックするような監視よろしくなバリバリの仕組みでなければ、せいぜい*あたりだけ見てあげればいい気はしますね。知らんけど。

とここで終わるのもなんなので、

$arrDomain = [
	'qiita.com',
	'www.youtube.com',
	'www.google.co.jp',
	'www.yahoo.co.jp',
];

foreach($arrDomain as $domain_name) {
	echo '■' . $domain_name . PHP_EOL;

	$stream_context = stream_context_create(array(
		'ssl' => array('capture_peer_cert' => true)
	));

	$resource = stream_socket_client(
		'ssl://' . $domain_name . ':443',
		$errno,
		$errstr,
		30,
		STREAM_CLIENT_CONNECT,
		$stream_context
	);

	$cont = stream_context_get_params($resource);
	$parsed = openssl_x509_parse($cont['options']['ssl']['peer_certificate']);

	$func_chk_domain = function($cn, $domain) {
		return (strpos($cn, $domain) !== false) ||
			(preg_match(sprintf('/^.%s$/',$cn), $domain) === 1);
	};
	
	// 単純にCNで比較(完全一致と*時の正規表現)
	$check_flg = false;
	if( $func_chk_domain($parsed['subject']['CN'], $domain_name) ) {
		echo 'CNで一致' . PHP_EOL;
		$check_flg = true;
	}
	else {
		// CNで一致しない場合はextensionsのsubjectAltNameを精査
		$arrDNS = explode(',', $parsed['extensions']['subjectAltName']);
		
		foreach($arrDNS as $dns) {
			if( $func_chk_domain(str_ireplace(['DNS:',' '],'',$dns), $domain_name) ) {
				echo 'subjectAltNameで一致' . PHP_EOL;
				$check_flg = true;
				break;
			}
		}
	}
	
	if( $check_flg ) {
		echo '有効期限:' . date('Y/m/d', $parsed['validTo_time_t']) . PHP_EOL;
	}
	else {
		echo '取得NG' . PHP_EOL;
	}
}

で取れました。

image.png

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?