Coding - Crypto - Data Security - Digital Signature - OpenSSL - PHP - Software

電子署名(サーバー証明書)

 電子署名はHTTP通信の暗号化であるSSLやTLSを使う際に必要な「サーバー証明書(Server Certificate)」で20年以上前から使われています。

 署名リクエストの記事で「サーバー証明書はCertficate Authorityに署名された署名リクエストである」と言及しました。サーバー証明書というのは、CSR(署名リクエスト)に対して特定の秘密鍵を使って署名したX.509証明書です。X.509証明書というのは「証明される組織の名前や住所や連絡先と公開鍵」と「それを証明する組織の名前や住所や連絡先と公開鍵」が含まれます。これに対して特定(ブラウザには予め「これらは大丈夫な認証局」というリストが入っています)の認証局が「これは正しい情報ですよ」とお墨付きを与える署名をするとブラウザで「大丈夫なサイトです」と表示されます。

下記でサーバー証明書の内容をパースして閲覧しますが、サーバー証明書の取得方法としては「サーバー側に置いてあるもの」もしくは「ブラウザ等で取得する」の2種類があります。今回はあまり触れられない後者で行います。

1. サーバー証明書の取得

 ブラウザを使ってサーバーの証明書を取得するには、まずそのサーバーで配信されているウェブサイトをHTTPSで開きます。Chromeの場合、URLの左端に閉じた鍵🔐のアイコンがあるのでそれをクリックし、開いたメニューで「Certificate」そクリックします。開いた小さな画面で証明書のアイコンを選択してデスクトップにドラッグすればデスクトップにサーバー証明書が保存されます。弊社のサーバー証明書であればデスクトップに「electric-blue-industries.com.cer」というファイルが保存されます。

 上記のサーバ証明書はMacやWindowsに標準装備されたキーチェーン管理アプリではそのまま開けますが、PHPで処理をする際にはそのままではサーバー証明書とは認識されません。サーバー証明書として判別するヘッダーとフッターと64文字ごとの改行がないからです。そこで、下記のコードを使ってPHPで正常に判別されるための前処理を行います。

<?php

$data = file_get_contents('electric-blue-industries.com.cer');

// base64エンコードして可読な状態にします
$data_encoded = base64_encode($data);
// 64文字ごとに改行します
$data_encoded = wordwrap($data_encoded, 64, "\n", true);
// ヘッダーとフッターを付加します
$data_encoded = "-----BEGIN CERTIFICATE-----\n" . $data_encoded . "\n-----END CERTIFICATE-----";

echo $data_encoded;

?>

下記が上記の処理の結果で得たPHPのOpenSSLで処理できる弊社(electric-blue-industries.com)のサーバー証明書です。

-----BEGIN CERTIFICATE-----
MIIF6TCCBNGgAwIBAgIQT7Vf++g+dEcBKE6JModOqzANBgkqhkiG9w0BAQsFADCB
jzELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
A1UEBxMHU2FsZm9yZDEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTcwNQYDVQQD
Ey5TZWN0aWdvIFJTQSBEb21haW4gVmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENB
MB4XDTIwMDQxMzAwMDAwMFoXDTIxMDQxMzIzNTk1OVowJzElMCMGA1UEAxMcZWxl
Y3RyaWMtYmx1ZS1pbmR1c3RyaWVzLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEP
ADCCAQoCggEBANyQuaVKcCIizOuJ+TODZ2UX66ODeMbPRgfnB7axcm6x8m63m9+m
BH/0jM8vopoZFwYj9v3pbkCUssBgE5ZBCi1yWyEj/s4v8xM0OWCynm1BFVOs2L9h
YARncvv38EGXvK+jf1Gxig0HA50DYN3gVDTTfeaNG6D4+Mxhc529ae0P8fMdGD1L
4oN5Ox+DxKKCk4TRgY/ZD4iIAuwC2gtshfh0Ewvx9HM+9EGkgGyeP6iSmyLa8vzm
Q0klUPfK+4gVwiwo2GgfpEQTIUz08mYZd9kQHvCiWKwa6x8TU/EuwkuRjmIw4G1f
/m+NeQ4IhGo2aSeM65Nl2BoZ/kOebYDl5N0CAwEAAaOCAqYwggKiMB8GA1UdIwQY
MBaAFI2MXsRUrYrhd+mb+ZsF4bgBjWHhMB0GA1UdDgQWBBQhWiyXId3pg0mf//KM
tWzZmD5zSjAOBgNVHQ8BAf8EBAMCBaAwDAYDVR0TAQH/BAIwADAdBgNVHSUEFjAU
BggrBgEFBQcDAQYIKwYBBQUHAwIwSQYDVR0gBEIwQDA0BgsrBgEEAbIxAQICBzAl
MCMGCCsGAQUFBwIBFhdodHRwczovL3NlY3RpZ28uY29tL0NQUzAIBgZngQwBAgEw
gYQGCCsGAQUFBwEBBHgwdjBPBggrBgEFBQcwAoZDaHR0cDovL2NydC5zZWN0aWdv
LmNvbS9TZWN0aWdvUlNBRG9tYWluVmFsaWRhdGlvblNlY3VyZVNlcnZlckNBLmNy
dDAjBggrBgEFBQcwAYYXaHR0cDovL29jc3Auc2VjdGlnby5jb20wSQYDVR0RBEIw
QIIcZWxlY3RyaWMtYmx1ZS1pbmR1c3RyaWVzLmNvbYIgd3d3LmVsZWN0cmljLWJs
dWUtaW5kdXN0cmllcy5jb20wggEEBgorBgEEAdZ5AgQCBIH1BIHyAPAAdgB9PvL4
j/+IVWgkwsDKnlKJeSvFDngJfy5ql2iZfiLw1wAAAXF1Q7goAAAEAwBHMEUCIQC8
fprKr3M9JLe9VpJoHuR08BMLKKugmXBGrsXXJd7M+AIgEswb1NtuZHq1leyDGQ/z
KhN/dU6/Q3jQjFTkCJA2+HsAdgCUILwejtWNbIhzH4KLIiwN0dpNXmxPlD1h204v
WE2iwgAAAXF1Q7jSAAAEAwBHMEUCIQD71Y9Fvg2a41GHH5cg5oIryjtYsADFFbjT
pMB8tjVRmQIgXmiSVVdili7i+BUqOi5EB7ovwDHycxOEQ1gvVLFwBowwDQYJKoZI
hvcNAQELBQADggEBAJ6v7PYKobYs+uJxwql/kJkzdfr4LY4xdd0IEeg2zUAehdZM
9LmI7EM18Cx56bqpi9+cPS08m7RpccyFVbCrPs7Vby+BFF8AyjLiGiGr/0xgygJW
33dFrGS00IhWMJ8cFazNpLysphih1Sxt5teGuXUVvJLp8y9xcWzCToN068aoRBXR
7UShE9znzxGEAhxDEWifh/lg5YaIJm4JaOvbraojr81eP0cM95+viqs1Ai/irdyi
x1Qbjt9qkkMl1vaVNyIDi8r0JRsVIiyh/jvk6CspJCSeO/Y8aYWXBA/ngsB9MuWC
+JTFL7KC+9QFO4aQjjsgNZQIUumiDcXdbiDKlAo=
-----END CERTIFICATE-----

上記から情報を抽出します。

<?php

$data = file_get_contents('electric-blue-industries.com.cer');
 
// base64エンコードして可読な状態にします
$data_encoded = base64_encode($data);
// 64文字ごとに改行します
$data_encoded = wordwrap($data_encoded, 64, "\n", true);
// ヘッダーとフッターを付加します
$data_encoded = "-----BEGIN CERTIFICATE-----\n" . $data_encoded . "\n-----END CERTIFICATE-----";

// サーバー証明書をパースして含まれる情報を抽出
$cert = openssl_x509_read($data_encoded);
$cert_data = openssl_x509_parse($cert);

var_dump($cert_data);

// サーバー証明書から公開鍵を抽出
$pubKey = openssl_pkey_get_public($cert);
$keyData = openssl_pkey_get_details($pubKey);

echo $keyData['key'];

?>

その出力結果です。

array(16) {
  ["name"]=>
  string(32) "/CN=electric-blue-industries.com"
  ["subject"]=>
  array(1) {
    ["CN"]=>
    string(28) "electric-blue-industries.com"
  }
  ["hash"]=>
  string(8) "d6c6198e"
  ["issuer"]=>
  array(5) {
    ["C"]=>
    string(2) "GB"
    ["ST"]=>
    string(18) "Greater Manchester"
    ["L"]=>
    string(7) "Salford"
    ["O"]=>
    string(15) "Sectigo Limited"
    ["CN"]=>
    string(46) "Sectigo RSA Domain Validation Secure Server CA"
  }
  ["version"]=>
  int(2)
  ["serialNumber"]=>
  string(39) "105950764185460320532886196575615274667"
  ["serialNumberHex"]=>
  string(32) "4FB55FFBE83E744701284E8932874EAB"
  ["validFrom"]=>
  string(13) "200413000000Z"
  ["validTo"]=>
  string(13) "210413235959Z"
  ["validFrom_time_t"]=>
  int(1586736000)
  ["validTo_time_t"]=>
  int(1618358399)
  ["signatureTypeSN"]=>
  string(10) "RSA-SHA256"
  ["signatureTypeLN"]=>
  string(23) "sha256WithRSAEncryption"
  ["signatureTypeNID"]=>
  int(668)
  ["purposes"]=>
  array(9) {
    [1]=>
    array(3) {
      [0]=>
      bool(true)
      [1]=>
      bool(false)
      [2]=>
      string(9) "sslclient"
    }
    [2]=>
    array(3) {
      [0]=>
      bool(true)
      [1]=>
      bool(false)
      [2]=>
      string(9) "sslserver"
    }
    [3]=>
    array(3) {
      [0]=>
      bool(true)
      [1]=>
      bool(false)
      [2]=>
      string(11) "nssslserver"
    }
    [4]=>
    array(3) {
      [0]=>
      bool(false)
      [1]=>
      bool(false)
      [2]=>
      string(9) "smimesign"
    }
    [5]=>
    array(3) {
      [0]=>
      bool(false)
      [1]=>
      bool(false)
      [2]=>
      string(12) "smimeencrypt"
    }
    [6]=>
    array(3) {
      [0]=>
      bool(false)
      [1]=>
      bool(false)
      [2]=>
      string(7) "crlsign"
    }
    [7]=>
    array(3) {
      [0]=>
      bool(true)
      [1]=>
      bool(true)
      [2]=>
      string(3) "any"
    }
    [8]=>
    array(3) {
      [0]=>
      bool(true)
      [1]=>
      bool(false)
      [2]=>
      string(10) "ocsphelper"
    }
    [9]=>
    array(3) {
      [0]=>
      bool(false)
      [1]=>
      bool(false)
      [2]=>
      string(13) "timestampsign"
    }
  }
  ["extensions"]=>
  array(9) {
    ["authorityKeyIdentifier"]=>
    string(66) "keyid:8D:8C:5E:C4:54:AD:8A:E1:77:E9:9B:F9:9B:05:E1:B8:01:8D:61:E1
"
    ["subjectKeyIdentifier"]=>
    string(59) "21:5A:2C:97:21:DD:E9:83:49:9F:FF:F2:8C:B5:6C:D9:98:3E:73:4A"
    ["keyUsage"]=>
    string(35) "Digital Signature, Key Encipherment"
    ["basicConstraints"]=>
    string(8) "CA:FALSE"
    ["extendedKeyUsage"]=>
    string(60) "TLS Web Server Authentication, TLS Web Client Authentication"
    ["certificatePolicies"]=>
    string(87) "Policy: 1.3.6.1.4.1.6449.1.2.2.7
  CPS: https://sectigo.com/CPS
Policy: 2.23.140.1.2.1
"
    ["authorityInfoAccess"]=>
    string(120) "CA Issuers - URI:http://crt.sectigo.com/SectigoRSADomainValidationSecureServerCA.crt
OCSP - URI:http://ocsp.sectigo.com
"
    ["subjectAltName"]=>
    string(70) "DNS:electric-blue-industries.com, DNS:www.electric-blue-industries.com"
    ["1.3.6.1.4.1.11129.2.4.2"]=>
    string(245) "���v}>�����Uh$��ʞR�y+�x	.j�h�~"��quC�(G0E!�~�ʯs=$��V�h�t�(���pF���%��� ���ndz����*uN�CxЌT��6�{v� ��Սl�s��",
��M^lO�=a�N/XM��quC��G0E!�ՏE�
��Q�� �+�;X���Ӥ�|�5Q� ^h�UWb�.��*:.D�/�1�s�CX/T�p�"
  }
}

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3JC5pUpwIiLM64n5M4Nn
ZRfro4N4xs9GB+cHtrFybrHybreb36YEf/SMzy+imhkXBiP2/eluQJSywGATlkEK
LXJbISP+zi/zEzQ5YLKebUEVU6zYv2FgBGdy+/fwQZe8r6N/UbGKDQcDnQNg3eBU
NNN95o0boPj4zGFznb1p7Q/x8x0YPUvig3k7H4PEooKThNGBj9kPiIgC7ALaC2yF
+HQTC/H0cz70QaSAbJ4/qJKbItry/OZDSSVQ98r7iBXCLCjYaB+kRBMhTPTyZhl3
2RAe8KJYrBrrHxNT8S7CS5GOYjDgbV/+b415DgiEajZpJ4zrk2XYGhn+Q55tgOXk
3QIDAQAB
-----END PUBLIC KEY-----

 上記の上の方を見てもらうと弊社の情報が書かれているわけなのですが、弊社の住所も連絡先も書かれていないことがわかりますか?それでは、この「サーバー証明書」というのは何を証明しているものなのでしょうか?

 サーバー証明書は、暗号化通信に使われる公開鍵ペアの公開鍵について「この公開鍵はelectric-blue-industries.comというドメインがSSL/TLS通信をするうえで使用するものであると証明します by 認証局」というだけのものであって、そのドメインの管理者の住所が正しいとか、公的機関が安全と認めたとかの証明ではないのです。

2. 自己署名または認証局ではない署名がされたサーバ証明書は「危険」なのか?

 結論から言うと「一概に危険とは言えない」です。このサーバー証明書にまつわるリスクは主に「なりすまし」であり、例えばapple.comのサーバ証明書を誰でも作って自分のサイト(例 sagidayo.apple.com)にインストールしてapple社管轄のサイトであるようになりすませたというケースです。これを防ぐために認証局(Certificate Authority)が存在しているのであって、自己署名または認証局ではない署名がされたサーバ証明書が危険というのは「公開鍵の証明」という本来の趣旨とは解離があると考えます。

 数年前からGoogle Chromeでは、予めGoogleが登録した認証局ではない誰かが署名したサーバー証明書がSSL/TLS通信に使われている場合「このサイトは安全ではありません」と画面表示をするようにしていますが、正直これはやりすぎだと私は考えています。


 私たちが当たり前に使っているブラウザの暗号通信でも電子署名は重要な要素となっています。

Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments