Upgrade to Pro — share decks privately, control downloads, hide ads and more …

PHPでローカル環境用のSSL/TLS証明書を発行することはできるのか? #phpconkagawa

PHPでローカル環境用のSSL/TLS証明書を発行することはできるのか? #phpconkagawa

PHPカンファレンス香川2026で発表したスライドです。

Avatar for akase244

akase244

May 08, 2026

More Decks by akase244

Other Decks in Programming

Transcript

  1. HTTP / HTTPS で動作が異なる機能の開発には注意が必要 • Mixed Content • Cookie の

    Secure 属性 • SameSite Cookie • HSTS • CORS • Service Worker • WebSocket • getUserMedia • navigator.geolocation • navigator.clipboard • などなど
  2. ローカル環境におけるSSL/TLS証明書の発行手順の例 • ルート証明書 ◦ ルートCAの秘密鍵を作成 ◦ ルートCAの秘密鍵で署名してルート証明書を作成 • 中間CA証明書 ◦

    中間CAの秘密鍵を作成 ◦ 中間CA証明書用のCSRを作成 ◦ ルートCAの秘密鍵で署名して中間証明書を作成 • サーバー証明書 ◦ サーバー証明書用の秘密鍵を作成 ◦ サーバー証明書用のCSRを作成 ◦ 中間CAの秘密鍵で署名してサーバー証明書を作成
  3. ローカル環境におけるSSL/TLS証明書の発行手順の例 • ルート証明書 ◦ ルートCAの秘密鍵を作成 ◦ ルートCAの秘密鍵で署名してルート証明書を作成 • 中間CA証明書 ◦

    中間CAの秘密鍵を作成 ◦ 中間CA証明書用のCSRを作成 ◦ ルートCAの秘密鍵で署名して中間証明書を作成 • サーバー証明書 ◦ サーバー証明書用の秘密鍵を作成 ◦ サーバー証明書用のCSRを作成 ◦ 中間CAの秘密鍵で署名してサーバー証明書を作成
  4. ローカル環境におけるSSL/TLS証明書の発行手順の例 • ルート証明書 ◦ ルートCAの秘密鍵を作成 ◦ ルートCAの秘密鍵で署名してルート証明書を作成 • 中間CA証明書 ◦

    中間CAの秘密鍵を作成 ◦ 中間CA証明書用のCSRを作成 ◦ ルートCAの秘密鍵で署名して中間証明書を作成 • サーバー証明書 ◦ サーバー証明書用の秘密鍵を作成 ◦ サーバー証明書用のCSRを作成 ◦ 中間CAの秘密鍵で署名してサーバー証明書を作成
  5. ローカル環境におけるSSL/TLS証明書の発行手順の例 • ルート証明書 ◦ ルートCAの秘密鍵を作成 ◦ ルートCAの秘密鍵で署名してルート証明書を作成 • 中間CA証明書 ◦

    中間CAの秘密鍵を作成 ◦ 中間CA証明書用のCSRを作成 ◦ ルートCAの秘密鍵で署名して中間証明書を作成 • サーバー証明書 ◦ サーバー証明書用の秘密鍵を作成 ◦ サーバー証明書用のCSRを作成 ◦ 中間CAの秘密鍵で署名してサーバー証明書を作成
  6. ローカル環境におけるSSL/TLS証明書の発行手順の例 • ルート証明書 ◦ ルートCAの秘密鍵を作成 ◦ ルートCAの秘密鍵で署名してルート証明書を作成 • 中間CA証明書 ◦

    中間CAの秘密鍵を作成 ◦ 中間CA証明書用のCSRを作成 ◦ ルートCAの秘密鍵で署名して中間証明書を作成 • サーバー証明書 ◦ サーバー証明書用の秘密鍵を作成 ◦ サーバー証明書用のCSRを作成 ◦ 中間CAルートCAの秘密鍵で署名してサーバー証明書を作成 中間CAの秘密鍵がなくても、ルートCAの秘密鍵で 署名を行えばサーバー証明書は作成可能
  7. ローカル環境におけるSSL/TLS証明書の発行手順の例 • ルート証明書 ◦ ルートCAの秘密鍵を作成 ◦ ルートCAの秘密鍵で署名してルート証明書を作成 • 中間CA証明書 ◦

    中間CAの秘密鍵を作成 ◦ 中間CA証明書用のCSRを作成 ◦ ルートCAの秘密鍵で署名して中間証明書を作成 • サーバー証明書 ◦ サーバー証明書用の秘密鍵を作成 ◦ サーバー証明書用のCSRを作成 ◦ 中間CAの秘密鍵で署名してサーバー証明書を作成
  8. ローカル環境におけるSSL/TLS証明書の発行手順の例 • ルート証明書 ◦ ルートCAの秘密鍵を作成 ◦ ルートCAの秘密鍵で署名してルート証明書を作成 • 中間CA証明書 ◦

    中間CAの秘密鍵を作成 ◦ 中間CA証明書用のCSRを作成 ◦ ルートCAの秘密鍵で署名して中間証明書を作成 • サーバー証明書 ◦ サーバー証明書用の秘密鍵を作成 ◦ サーバー証明書用のCSRを作成 ◦ 中間CAの秘密鍵で署名してサーバー証明書を作成
  9. ローカル環境におけるSSL/TLS証明書の発行手順の例 • ルート証明書 ◦ ルートCAの秘密鍵を作成 ◦ ルートCAの秘密鍵で署名してルート証明書を作成 • 中間CA証明書 ◦

    中間CAの秘密鍵を作成 ◦ 中間CA証明書用のCSRを作成 ◦ ルートCAの秘密鍵で署名して中間証明書を作成 • サーバー証明書 ◦ サーバー証明書用の秘密鍵を作成 ◦ サーバー証明書用のCSRを作成 ◦ 中間CAの秘密鍵で署名してサーバー証明書を作成
  10. ルートCAは誰がどのように信頼しているのか? • 誰が ◦ OSベンダ ◦ ブラウザベンダ • どのように ◦

    Root Storeプログラムへの申請と審査 ◦ CA/Browser Forum が策定している Baseline Requirements への準拠 ◦ WebTrust 、 ETSI による定期的な第三者監査
  11. Linux(Ubuntu)の場合 (/etc/ssl/certs) $ ls -1 /etc/ssl/certs/ |sort ・ ・ Amazon_Root_CA_4.pem

    Atos_TrustedRoot_2011.pem Atos_TrustedRoot_Root_CA_ECC_TLS_2021.pem Atos_TrustedRoot_Root_CA_RSA_TLS_2021.pem Autoridad_de_Certificacion_Firmaprofesional_CIF_A62634068.pem BJCA_Global_Root_CA1.pem ・ ・
  12. 証明書に関連するインシデント例 • Comodo(2011年) ◦ 証明書発行申請者の情報を確認し、証明書を発行しても問題がないか 審査を行う機関である登録局がハッキング被害により、不正な証明書 の発行依頼が行われた ◦ 中間CAを介さずルートCAから直接発行していたという問題も発覚 •

    DigiNotar(2011年) ◦ オランダの認証局がハッキング被害によりGoogleなどの著名なドメイ ンの偽証明書が500枚以上も発行された • Symantec(2015〜2017年) ◦ Google、Operaなどの証明書をドメイン所有者に知らせず誤発行した
  13. 不正発行への対応 • CRL (Certificate Revocation List) ◦ ローカルに証明書失効リストをダウンロードして照合する。 ◦ 対象件数が多いのでダウンロードサイズが大きくなってしまう。

    ◦ リアルタイム性がない。 • OCSP (Online Certificate Status Protocol) ◦ リクエスト時にOCSPサーバに有効な証明書か照合する。 ◦ OCSPサーバーがダウンした場合に照合できない。 ◦ レイテンシ、プライバシーの問題。 • CT (Certificate Transparency) ログ ◦ すべての証明書の発行を記録しておいて、事後にチェックする。 ◦ 不正な証明書の発行は防げない。 • CAA レコード ◦ CAが発行可能なドメインをDNSで照合する。 ◦ DNSレコードに誤りや改ざんが発生すると破綻する。
  14. ルートCAの秘密鍵で署名してルート証明書を作成 openssl req -x509 \ ・・・証明書を作成(=自己署名) -key /etc/nginx/certs/snakeoil_root_ca.key \ ・・・秘密鍵のファイル名

    -sha256 \ ・・・ハッシュアルゴリズム -days 3650 \ ・・・有効期限 -out /etc/nginx/certs/snakeoil_root_ca.crt \ ・・・証明書のファイル名 -config /etc/nginx/certs/snakeoil_root_ca.cnf ・・・設定ファイルのファイル名
  15. ルートCAの秘密鍵で署名してルート証明書を作成 openssl req -x509 \ ・・・証明書を作成(=自己署名) -key /etc/nginx/certs/snakeoil_root_ca.key \ ・・・秘密鍵のファイル名

    -sha256 \ ・・・ハッシュアルゴリズム -days 3650 \ ・・・有効期限 -out /etc/nginx/certs/snakeoil_root_ca.crt \ ・・・証明書のファイル名 -config /etc/nginx/certs/snakeoil_root_ca.cnf ・・・設定ファイルのファイル名
  16. ルートCAの秘密鍵で署名してルート証明書を作成 openssl req -x509 \ ・・・証明書を作成(=自己署名) -key /etc/nginx/certs/snakeoil_root_ca.key \ ・・・秘密鍵のファイル名

    -sha256 \ ・・・ハッシュアルゴリズム -days 3650 \ ・・・有効期限 -out /etc/nginx/certs/snakeoil_root_ca.crt \ ・・・証明書のファイル名 -config /etc/nginx/certs/snakeoil_root_ca.cnf ・・・設定ファイルのファイル名
  17. snakeoil_root_ca.cnf の内容(抜粋) cat /etc/nginx/certs/snakeoil_root_ca.cnf ・ ・ [v3_root_ca] basicConstraints = critical,CA:TRUE,pathlen:1

    keyUsage = critical,keyCertSign,cRLSign subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer
  18. snakeoil_root_ca.cnf の内容(抜粋) cat /etc/nginx/certs/snakeoil_root_ca.cnf ・ ・ [v3_root_ca] basicConstraints = critical,CA:TRUE,pathlen:1

    keyUsage = critical,keyCertSign,cRLSign subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer
  19. ルート証明書の内容を確認 openssl x509 \ ・・・証明書の内容を表示 -in certs/snakeoil_root_ca.crt \ ・・・証明書のファイル名 -noout

    \ ・・・指定オプション以外の表示を抑制 -issuer \ ・・・証明書の署名者(発行者) -subject \ ・・・証明書の主体者 -serial \ ・・・シリアル番号 -ext basicConstraints \ ・・・基本制約 -dates ・・・有効期限
  20. ルート証明書の内容を確認 openssl x509 -in certs/snakeoil_root_ca.crt -noout -issuer -subject -serial -ext

    basicConstraints -dates issuer=C = JP, ST = Tokyo, L = Chiyoda, O = Local Development, CN = Local Development Root CA subject=C = JP, ST = Tokyo, L = Chiyoda, O = Local Development, CN = Local Development Root CA serial=249019A1E67522361F1265075B70EB6ABCE400F1 X509v3 Basic Constraints: critical CA:TRUE, pathlen:1 notBefore=Apr 27 14:42:11 2026 GMT notAfter=Apr 24 14:42:11 2036 GMT
  21. ルート証明書の内容を確認 openssl x509 -in certs/snakeoil_root_ca.crt -noout -issuer -subject -serial -ext

    basicConstraints -dates issuer=C = JP, ST = Tokyo, L = Chiyoda, O = Local Development, CN = Local Development Root CA subject=C = JP, ST = Tokyo, L = Chiyoda, O = Local Development, CN = Local Development Root CA serial=249019A1E67522361F1265075B70EB6ABCE400F1 X509v3 Basic Constraints: critical CA:TRUE, pathlen:1 notBefore=Apr 27 14:42:11 2026 GMT notAfter=Apr 24 14:42:11 2036 GMT
  22. ルート証明書の内容を確認 openssl x509 -in certs/snakeoil_root_ca.crt -noout -issuer -subject -serial -ext

    basicConstraints -dates issuer=C = JP, ST = Tokyo, L = Chiyoda, O = Local Development, CN = Local Development Root CA subject=C = JP, ST = Tokyo, L = Chiyoda, O = Local Development, CN = Local Development Root CA serial=249019A1E67522361F1265075B70EB6ABCE400F1 X509v3 Basic Constraints: critical CA:TRUE, pathlen:1 notBefore=Apr 27 14:42:11 2026 GMT notAfter=Apr 24 14:42:11 2036 GMT
  23. ルート証明書の内容を確認 openssl x509 -in certs/snakeoil_root_ca.crt -noout -issuer -subject -serial -ext

    basicConstraints -dates issuer=C = JP, ST = Tokyo, L = Chiyoda, O = Local Development, CN = Local Development Root CA subject=C = JP, ST = Tokyo, L = Chiyoda, O = Local Development, CN = Local Development Root CA serial=249019A1E67522361F1265075B70EB6ABCE400F1 X509v3 Basic Constraints: critical CA:TRUE, pathlen:1 notBefore=Apr 27 14:42:11 2026 GMT notAfter=Apr 24 14:42:11 2036 GMT
  24. ルート証明書の内容を確認 openssl x509 -in certs/snakeoil_root_ca.crt -noout -issuer -subject -serial -ext

    basicConstraints -dates issuer=C = JP, ST = Tokyo, L = Chiyoda, O = Local Development, CN = Local Development Root CA subject=C = JP, ST = Tokyo, L = Chiyoda, O = Local Development, CN = Local Development Root CA serial=249019A1E67522361F1265075B70EB6ABCE400F1 X509v3 Basic Constraints: critical CA:TRUE, pathlen:1 notBefore=Apr 27 14:42:11 2026 GMT notAfter=Apr 24 14:42:11 2036 GMT
  25. 中間CA証明書用のCSRを作成 openssl req -new \ ・・・CSRを作成 -key /etc/nginx/certs/snakeoil_intermediate_ca.key \ ・・・秘密鍵のファイル名

    -out /etc/nginx/certs/snakeoil_intermediate_ca.csr \ ・・・CSRのファイル名 -config /etc/nginx/certs/snakeoil_intermediate_ca.cnf ・・・設定ファイルのファイル名
  26. 中間CA証明書用のCSRを作成 openssl req -new \ ・・・CSRを作成 -key /etc/nginx/certs/snakeoil_intermediate_ca.key \ ・・・秘密鍵のファイル名

    -out /etc/nginx/certs/snakeoil_intermediate_ca.csr \ ・・・CSRのファイル名 -config /etc/nginx/certs/snakeoil_intermediate_ca.cnf ・・・設定ファイルのファイル名
  27. ルートCAの秘密鍵で署名して中間証明書を作成 openssl x509 -req \ ・・・証明書を作成(≠自己署名) -in /etc/nginx/certs/snakeoil_intermediate_ca.csr \ ・・・CSRのファイル名

    -CA /etc/nginx/certs/snakeoil_root_ca.crt \ ・・・署名を行うCAの証明書 -CAkey /etc/nginx/certs/snakeoil_root_ca.key \ ・・・署名を行うCAの秘密鍵 -CAcreateserial \ ・・・シリアル番号ファイルを作成 -sha256 \ ・・・ハッシュアルゴリズム -days 1825 \ ・・・有効期限 -out /etc/nginx/certs/snakeoil_intermediate_ca.crt \ ・・・証明書のファイル名 -extfile /etc/nginx/certs/snakeoil_intermediate_ca.cnf \ ・・・設定ファイルのファイル名 -extensions v3_intermediate_ca ・・・設定ファイルのセクション名
  28. ルートCAの秘密鍵で署名して中間証明書を作成 openssl x509 -req \ ・・・証明書を作成(≠自己署名) -in /etc/nginx/certs/snakeoil_intermediate_ca.csr \ ・・・CSRのファイル名

    -CA /etc/nginx/certs/snakeoil_root_ca.crt \ ・・・署名を行うCAの証明書 -CAkey /etc/nginx/certs/snakeoil_root_ca.key \ ・・・署名を行うCAの秘密鍵 -CAcreateserial \ ・・・シリアル番号ファイルを作成 -sha256 \ ・・・ハッシュアルゴリズム -days 1825 \ ・・・有効期限 -out /etc/nginx/certs/snakeoil_intermediate_ca.crt \ ・・・証明書のファイル名 -extfile /etc/nginx/certs/snakeoil_intermediate_ca.cnf \ ・・・設定ファイルのファイル名 -extensions v3_intermediate_ca ・・・設定ファイルのセクション名
  29. 中間CA証明書の内容を確認 openssl x509 \ ・・・証明書の内容を表示 -in certs/snakeoil_intermediate_ca.crt \ ・・・証明書のファイル名 -noout

    \ ・・・指定オプション以外の表示を抑制 -issuer \ ・・・証明書の署名者(発行者) -subject \ ・・・証明書の主体者 -serial \ ・・・シリアル番号 -ext basicConstraints \ ・・・基本制約 -dates ・・・有効期限
  30. 中間CA証明書の内容を確認 openssl x509 -in certs/snakeoil_intermediate_ca.crt -noout -issuer -subject -serial -ext

    basicConstraints -dates issuer=C = JP, ST = Tokyo, L = Chiyoda, O = Local Development, CN = Local Development Root CA subject=C = JP, ST = Tokyo, L = Chiyoda, O = Local Development, CN = Local Development Intermediate CA serial=169B4D55B1A55713AA53CD5D29AE37B8ECD005FE X509v3 Basic Constraints: critical CA:TRUE, pathlen:0 notBefore=Apr 27 14:42:11 2026 GMT notAfter=Apr 26 14:42:11 2031 GMT
  31. 中間CA証明書の内容を確認 openssl x509 -in certs/snakeoil_intermediate_ca.crt -noout -issuer -subject -serial -ext

    basicConstraints -dates issuer=C = JP, ST = Tokyo, L = Chiyoda, O = Local Development, CN = Local Development Root CA subject=C = JP, ST = Tokyo, L = Chiyoda, O = Local Development, CN = Local Development Intermediate CA serial=169B4D55B1A55713AA53CD5D29AE37B8ECD005FE X509v3 Basic Constraints: critical CA:TRUE, pathlen:0 notBefore=Apr 27 14:42:11 2026 GMT notAfter=Apr 26 14:42:11 2031 GMT
  32. 中間CA証明書の内容を確認 openssl x509 -in certs/snakeoil_intermediate_ca.crt -noout -issuer -subject -serial -ext

    basicConstraints -dates issuer=C = JP, ST = Tokyo, L = Chiyoda, O = Local Development, CN = Local Development Root CA subject=C = JP, ST = Tokyo, L = Chiyoda, O = Local Development, CN = Local Development Intermediate CA serial=169B4D55B1A55713AA53CD5D29AE37B8ECD005FE X509v3 Basic Constraints: critical CA:TRUE, pathlen:0 notBefore=Apr 27 14:42:11 2026 GMT notAfter=Apr 26 14:42:11 2031 GMT
  33. 中間CA証明書の内容を確認 openssl x509 -in certs/snakeoil_intermediate_ca.crt -noout -issuer -subject -serial -ext

    basicConstraints -dates issuer=C = JP, ST = Tokyo, L = Chiyoda, O = Local Development, CN = Local Development Root CA subject=C = JP, ST = Tokyo, L = Chiyoda, O = Local Development, CN = Local Development Intermediate CA serial=169B4D55B1A55713AA53CD5D29AE37B8ECD005FE X509v3 Basic Constraints: critical CA:TRUE, pathlen:0 notBefore=Apr 27 14:42:11 2026 GMT notAfter=Apr 26 14:42:11 2031 GMT
  34. 中間CA証明書の内容を確認 openssl x509 -in certs/snakeoil_intermediate_ca.crt -noout -issuer -subject -serial -ext

    basicConstraints -dates issuer=C = JP, ST = Tokyo, L = Chiyoda, O = Local Development, CN = Local Development Root CA subject=C = JP, ST = Tokyo, L = Chiyoda, O = Local Development, CN = Local Development Intermediate CA serial=169B4D55B1A55713AA53CD5D29AE37B8ECD005FE X509v3 Basic Constraints: critical CA:TRUE, pathlen:0 notBefore=Apr 27 14:42:11 2026 GMT notAfter=Apr 26 14:42:11 2031 GMT
  35. サーバー証明書用のCSRを作成 openssl req -new \ ・・・CSRを作成 -key /etc/nginx/certs/snakeoil.key \ ・・・秘密鍵のファイル名

    -out /etc/nginx/certs/snakeoil.csr \ ・・・CSRのファイル名 -config /etc/nginx/certs/snakeoil.cnf ・・・設定ファイルのファイル名
  36. 中間CAの秘密鍵で署名してサーバー証明書を作成 openssl x509 -req \ ・・・証明書を作成(≠自己署名) -in /etc/nginx/certs/snakeoil.csr \ ・・・CSRのファイル名

    -CA /etc/nginx/certs/snakeoil_intermediate_ca.crt \ ・・・署名を行うCAの証明書 -CAkey /etc/nginx/certs/snakeoil_intermediate_ca.key \ ・・・署名を行うCAの秘密鍵 -CAcreateserial \ ・・・シリアル番号ファイルを作成 -sha256 \ ・・・ハッシュアルゴリズム -days 365 \ ・・・有効期限 -out /etc/nginx/certs/snakeoil.crt \ ・・・証明書のファイル名 -extfile /etc/nginx/certs/snakeoil.cnf \ ・・・設定ファイルのファイル名 -extensions v3_req ・・・設定ファイルのセクション名
  37. snakeoil.cnf の内容(抜粋) cat /etc/nginx/certs/snakeoil.cnf ・ ・ [v3_req] basicConstraints = CA:FALSE

    keyUsage = digitalSignature,keyEncipherment extendedKeyUsage = serverAuth subjectAltName = @alt_names [alt_names] DNS.1 = localhost IP.1 = 127.0.0.1 IP.2 = ::1
  38. snakeoil.cnf の内容(抜粋) cat /etc/nginx/certs/snakeoil.cnf ・ ・ [v3_req] basicConstraints = CA:FALSE

    keyUsage = digitalSignature,keyEncipherment extendedKeyUsage = serverAuth subjectAltName = @alt_names [alt_names] DNS.1 = localhost IP.1 = 127.0.0.1 IP.2 = ::1
  39. snakeoil.cnf の内容(抜粋) cat /etc/nginx/certs/snakeoil.cnf ・ ・ [v3_req] basicConstraints = CA:FALSE

    keyUsage = digitalSignature,keyEncipherment extendedKeyUsage = serverAuth subjectAltName = @alt_names [alt_names] DNS.1 = localhost IP.1 = 127.0.0.1 IP.2 = ::1
  40. サーバー証明書の内容を確認 openssl x509 \ ・・・証明書の内容を表示 -in certs/snakeoil.crt \ ・・・証明書のファイル名 -noout

    \ ・・・指定オプション以外の表示を抑制 -issuer \ ・・・証明書の署名者(発行者) -subject \ ・・・証明書の主体者 -serial \ ・・・シリアル番号 -ext basicConstraints,subjectAltName \ ・・・基本制約、SAN -dates ・・・有効期限
  41. サーバー証明書の内容を確認 openssl x509 -in certs/snakeoil.crt -noout -issuer -subject -serial -ext

    basicConstraints,subjectAltName -dates issuer=C = JP, ST = Tokyo, L = Chiyoda, O = Local Development, CN = Local Development Intermediate CA subject=C = JP, ST = Tokyo, L = Chiyoda, O = Local Development, CN = localhost serial=7B2204794683F8B181DA49D87DD8E630FF8AE0D7 X509v3 Basic Constraints: CA:FALSE X509v3 Subject Alternative Name: DNS:localhost, IP Address:127.0.0.1, IP Address:0:0:0:0:0:0:0:1 notBefore=Apr 27 14:42:11 2026 GMT notAfter=Apr 27 14:42:11 2027 GMT
  42. サーバー証明書の内容を確認 openssl x509 -in certs/snakeoil.crt -noout -issuer -subject -serial -ext

    basicConstraints,subjectAltName -dates issuer=C = JP, ST = Tokyo, L = Chiyoda, O = Local Development, CN = Local Development Intermediate CA subject=C = JP, ST = Tokyo, L = Chiyoda, O = Local Development, CN = localhost serial=7B2204794683F8B181DA49D87DD8E630FF8AE0D7 X509v3 Basic Constraints: CA:FALSE X509v3 Subject Alternative Name: DNS:localhost, IP Address:127.0.0.1, IP Address:0:0:0:0:0:0:0:1 notBefore=Apr 27 14:42:11 2026 GMT notAfter=Apr 27 14:42:11 2027 GMT
  43. サーバー証明書の内容を確認 openssl x509 -in certs/snakeoil.crt -noout -issuer -subject -serial -ext

    basicConstraints,subjectAltName -dates issuer=C = JP, ST = Tokyo, L = Chiyoda, O = Local Development, CN = Local Development Intermediate CA subject=C = JP, ST = Tokyo, L = Chiyoda, O = Local Development, CN = localhost serial=7B2204794683F8B181DA49D87DD8E630FF8AE0D7 X509v3 Basic Constraints: CA:FALSE X509v3 Subject Alternative Name: DNS:localhost, IP Address:127.0.0.1, IP Address:0:0:0:0:0:0:0:1 notBefore=Apr 27 14:42:11 2026 GMT notAfter=Apr 27 14:42:11 2027 GMT
  44. サーバー証明書の内容を確認 openssl x509 -in certs/snakeoil.crt -noout -issuer -subject -serial -ext

    basicConstraints,subjectAltName -dates issuer=C = JP, ST = Tokyo, L = Chiyoda, O = Local Development, CN = Local Development Intermediate CA subject=C = JP, ST = Tokyo, L = Chiyoda, O = Local Development, CN = localhost serial=7B2204794683F8B181DA49D87DD8E630FF8AE0D7 X509v3 Basic Constraints: CA:FALSE X509v3 Subject Alternative Name: DNS:localhost, IP Address:127.0.0.1, IP Address:0:0:0:0:0:0:0:1 notBefore=Apr 27 14:42:11 2026 GMT notAfter=Apr 27 14:42:11 2027 GMT
  45. サーバー証明書の内容を確認 openssl x509 -in certs/snakeoil.crt -noout -issuer -subject -serial -ext

    basicConstraints,subjectAltName -dates issuer=C = JP, ST = Tokyo, L = Chiyoda, O = Local Development, CN = Local Development Intermediate CA subject=C = JP, ST = Tokyo, L = Chiyoda, O = Local Development, CN = localhost serial=7B2204794683F8B181DA49D87DD8E630FF8AE0D7 X509v3 Basic Constraints: CA:FALSE X509v3 Subject Alternative Name: DNS:localhost, IP Address:127.0.0.1, IP Address:0:0:0:0:0:0:0:1 notBefore=Apr 27 14:42:11 2026 GMT notAfter=Apr 27 14:42:11 2027 GMT
  46. サーバー証明書の内容を確認 openssl x509 -in certs/snakeoil.crt -noout -issuer -subject -serial -ext

    basicConstraints,subjectAltName -dates issuer=C = JP, ST = Tokyo, L = Chiyoda, O = Local Development, CN = Local Development Intermediate CA subject=C = JP, ST = Tokyo, L = Chiyoda, O = Local Development, CN = localhost serial=7B2204794683F8B181DA49D87DD8E630FF8AE0D7 X509v3 Basic Constraints: CA:FALSE X509v3 Subject Alternative Name: DNS:localhost, IP Address:127.0.0.1, IP Address:0:0:0:0:0:0:0:1 notBefore=Apr 27 14:42:11 2026 GMT notAfter=Apr 27 14:42:11 2027 GMT
  47. 自己署名で証明書を作成 $csr = openssl_csr_new($dn, $rootKey, [ 'config' => $configPath, 'digest_alg'

    => 'sha256', ]); $cert = openssl_csr_sign($csr, null, $rootKey, 3650, [ 'config' => $configPath, 'x509_extensions' => 'v3_root_ca', 'digest_alg' => 'sha256', ], $serial); openssl_x509_export_to_file($cert, $certPath);
  48. 自己署名で証明書を作成 $csr = openssl_csr_new($dn, $rootKey, [ 'config' => $configPath, 'digest_alg'

    => 'sha256', ]); $cert = openssl_csr_sign($csr, null, $rootKey, 3650, [ 'config' => $configPath, 'x509_extensions' => 'v3_root_ca', 'digest_alg' => 'sha256', ], $serial); openssl_x509_export_to_file($cert, $certPath);
  49. 自己署名で証明書を作成 $csr = openssl_csr_new($dn, $rootKey, [ 'config' => $configPath, 'digest_alg'

    => 'sha256', ]); $cert = openssl_csr_sign($csr, null, $rootKey, 3650, [ 'config' => $configPath, 'x509_extensions' => 'v3_root_ca', 'digest_alg' => 'sha256', ], $serial); openssl_x509_export_to_file($cert, $certPath);
  50. 自己署名で証明書を作成 $csr = openssl_csr_new($dn, $rootKey, [ 'config' => $configPath, 'digest_alg'

    => 'sha256', ]); $cert = openssl_csr_sign($csr, null, $rootKey, 3650, [ 'config' => $configPath, 'x509_extensions' => 'v3_root_ca', 'digest_alg' => 'sha256', ], $serial); openssl_x509_export_to_file($cert, $certPath);
  51. CAによる署名で証明書を作成 $csr = openssl_csr_new($dn, $key, [ 'config' => $configPath, 'digest_alg'

    => 'sha256', ]); $cert = openssl_csr_sign($csr, $rootCert, $rootKey, 1825, [ 'config' => $configPath, 'x509_extensions' => 'v3_intermediate_ca', 'digest_alg' => 'sha256', ], $serial); openssl_x509_export_to_file($cert, $certPath);
  52. CAによる署名で証明書を作成 $csr = openssl_csr_new($dn, $key, [ 'config' => $configPath, 'digest_alg'

    => 'sha256', ]); $cert = openssl_csr_sign($csr, $rootCert, $rootKey, 1825, [ 'config' => $configPath, 'x509_extensions' => 'v3_intermediate_ca', 'digest_alg' => 'sha256', ], $serial); openssl_x509_export_to_file($cert, $certPath);
  53. CAによる署名で証明書を作成 $csr = openssl_csr_new($dn, $key, [ 'config' => $configPath, 'digest_alg'

    => 'sha256', ]); $cert = openssl_csr_sign($csr, $rootCert, $rootKey, 1825, [ 'config' => $configPath, 'x509_extensions' => 'v3_intermediate_ca', 'digest_alg' => 'sha256', ], $serial); openssl_x509_export_to_file($cert, $certPath);
  54. PHP 8.0.0 以降でOpenSSL関係のクラスが謎に充実している • OpenSSLAsymmetricKey ◦ https://www.php.net/manual/ja/class.opensslasymmetrickey.php • OpenSSLCertificate ◦

    https://www.php.net/manual/ja/class.opensslcertificate.php • OpenSSLCertificateSigningRequest ◦ https://www.php.net/manual/ja/class.opensslcertificatesigningrequest.php
  55. openssl_csr_sign にはシリアル番号の採番機能がない $cert = openssl_csr_sign($csr, $rootCert, $rootKey, 1825, [ 'config'

    => $configPath, 'x509_extensions' => 'v3_intermediate_ca', 'digest_alg' => 'sha256', ], $serial);
  56. PHP で openssl コマンド / OpenSSL 関数を利用した実装 • spomky-labs/pki-framework ◦

    https://github.com/spomky-labs/pki-framework • adaopedro/php-openssl-proxy ◦ https://github.com/AdaoPedro/php-openssl-proxy • marguskaidja/php-openssl-wrapper ◦ https://github.com/marguskaidja/php-openssl-wrapper • fyrkat/php-openssl ◦ https://github.com/fyrkat/php-openssl • hsdn/phpopenssl ◦ https://github.com/hsdn/phpopenssl • madeny/lhttps ◦ https://github.com/madeny/lhttps • ryoluo/sail-ssl ◦ https://github.com/ryoluo/sail-ssl
  57. 世の中には OpenSSL に頼らない実装がたくさんある • square/certstrap (Golang) • cloudflare/cfssl (Golang) •

    caddyserver/caddy (Golang) • jsha/minica (Golang) • smallstep/cli (Golang) • traefik/traefik (Golang) • rustls/rcgen (Rust) • atgreen/pure-tls (Common Lisp) • The Bouncy Castle Crypto package (Java) • phpseclib/phpseclib (PHP)
  58. AIに以下のキーワードを元に証明書発行を実装してもらった • X.509 (RFC 5280) ◦ 公開鍵証明書のフォーマットと検証ルールを定義する標準規格 • X.680 (ASN.1)

    ◦ データ構造を言語・プラットフォーム非依存に記述するための表記法 ◦ X.509 証明書の構造は ASN.1 で記述されている • X.690 (BER / CER / DER) ◦ ASN.1で定義されたデータ構造を実際のバイト列に符号化(エンコー ド)するルールを定めた規格 ◦ 実際のファイル(.crt 等)は DER エンコードされたバイト列
  59. なんかわからんけど ヨシッ! とコミットしたコードたち(抜粋) $n = gmp_mul($p, $q); $p1 = gmp_sub($p,

    1); $q1 = gmp_sub($q, 1); // λ(n) = lcm(p-1, q-1) $lambda = gmp_div(gmp_mul($p1, $q1), gmp_gcd($p1, $q1)); // gcd(e, λ(n)) = 1 を確認 if (gmp_cmp(gmp_gcd($e, $lambda), 1) !== 0) { continue; }
  60. なんかわからんけど ヨシッ! とコミットしたコードたち(抜粋) final class X509Builder { // 署名アルゴリズム OID

    private const OID_SHA256_WITH_RSA = '1.2.840.113549.1.1.11'; // RDN 属性 OID private const OID_COUNTRY = '2.5.4.6'; private const OID_STATE = '2.5.4.8'; private const OID_LOCALITY = '2.5.4.7'; private const OID_ORGANIZATION = '2.5.4.10'; private const OID_COMMON_NAME = '2.5.4.3';
  61. なんかわからんけど ヨシッ! とコミットしたコードたち(抜粋) private static function oidComponent(int $val): string {

    if ($val < 0x80) { return chr($val); } // Base-128 エンコーディング (最下位グループ以外は MSB を立てる) $bytes = chr($val & 0x7F); $val >>= 7; while ($val > 0) { $bytes = chr(0x80 | ($val & 0x7F)) . $bytes; $val >>= 7; } return $bytes;
  62. AI実装によって発行したサーバー証明書の内容を確認 $ openssl x509 -in certs/snakeoil.crt -noout -issuer -subject -serial

    -ext basicConstraints,subjectAltName -dates issuer=C = JP, ST = Tokyo, L = Chiyoda, O = Local Development, CN = Local Development Intermediate CA subject=C = JP, ST = Tokyo, L = Chiyoda, O = Local Development, CN = localhost serial=03 X509v3 Basic Constraints: critical CA:FALSE X509v3 Subject Alternative Name: critical DNS:localhost, IP Address:127.0.0.1, IP Address:0:0:0:0:0:0:0:1 notBefore=Apr 27 16:07:49 2026 GMT notAfter=Apr 27 16:07:49 2027 GMT
  63. AI実装によって発行したサーバー証明書の内容を確認 $ openssl x509 -in certs/snakeoil.crt -noout -issuer -subject -serial

    -ext basicConstraints,subjectAltName -dates issuer=C = JP, ST = Tokyo, L = Chiyoda, O = Local Development, CN = Local Development Intermediate CA subject=C = JP, ST = Tokyo, L = Chiyoda, O = Local Development, CN = localhost serial=03 X509v3 Basic Constraints: critical CA:FALSE X509v3 Subject Alternative Name: critical DNS:localhost, IP Address:127.0.0.1, IP Address:0:0:0:0:0:0:0:1 notBefore=Apr 27 16:07:49 2026 GMT notAfter=Apr 27 16:07:49 2027 GMT
  64. AI実装によって発行したサーバー証明書の内容を確認 $ openssl x509 -in certs/snakeoil.crt -noout -issuer -subject -serial

    -ext basicConstraints,subjectAltName -dates issuer=C = JP, ST = Tokyo, L = Chiyoda, O = Local Development, CN = Local Development Intermediate CA subject=C = JP, ST = Tokyo, L = Chiyoda, O = Local Development, CN = localhost serial=03 X509v3 Basic Constraints: critical CA:FALSE X509v3 Subject Alternative Name: critical DNS:localhost, IP Address:127.0.0.1, IP Address:0:0:0:0:0:0:0:1 notBefore=Apr 27 16:07:49 2026 GMT notAfter=Apr 27 16:07:49 2027 GMT
  65. AI実装によって発行したサーバー証明書の内容を確認 $ openssl x509 -in certs/snakeoil.crt -noout -issuer -subject -serial

    -ext basicConstraints,subjectAltName -dates issuer=C = JP, ST = Tokyo, L = Chiyoda, O = Local Development, CN = Local Development Intermediate CA subject=C = JP, ST = Tokyo, L = Chiyoda, O = Local Development, CN = localhost serial=03 X509v3 Basic Constraints: critical CA:FALSE X509v3 Subject Alternative Name: critical DNS:localhost, IP Address:127.0.0.1, IP Address:0:0:0:0:0:0:0:1 notBefore=Apr 27 16:07:49 2026 GMT notAfter=Apr 27 16:07:49 2027 GMT
  66. AI実装によって発行したサーバー証明書の内容を確認 $ openssl x509 -in certs/snakeoil.crt -noout -issuer -subject -serial

    -ext basicConstraints,subjectAltName -dates issuer=C = JP, ST = Tokyo, L = Chiyoda, O = Local Development, CN = Local Development Intermediate CA subject=C = JP, ST = Tokyo, L = Chiyoda, O = Local Development, CN = localhost serial=03 X509v3 Basic Constraints: critical CA:FALSE X509v3 Subject Alternative Name: critical DNS:localhost, IP Address:127.0.0.1, IP Address:0:0:0:0:0:0:0:1 notBefore=Apr 27 16:07:49 2026 GMT notAfter=Apr 27 16:07:49 2027 GMT
  67. AI実装によって発行したサーバー証明書の内容を確認 $ openssl x509 -in certs/snakeoil.crt -noout -issuer -subject -serial

    -ext basicConstraints,subjectAltName -dates issuer=C = JP, ST = Tokyo, L = Chiyoda, O = Local Development, CN = Local Development Intermediate CA subject=C = JP, ST = Tokyo, L = Chiyoda, O = Local Development, CN = localhost serial=03 X509v3 Basic Constraints: critical CA:FALSE X509v3 Subject Alternative Name: critical DNS:localhost, IP Address:127.0.0.1, IP Address:0:0:0:0:0:0:0:1 notBefore=Apr 27 16:07:49 2026 GMT notAfter=Apr 27 16:07:49 2027 GMT
  68. AI実装によって発行したサーバー証明書の内容を確認 $ openssl x509 -in certs/snakeoil.crt -noout -issuer -subject -serial

    -ext basicConstraints,subjectAltName -dates issuer=C = JP, ST = Tokyo, L = Chiyoda, O = Local Development, CN = Local Development Intermediate CA subject=C = JP, ST = Tokyo, L = Chiyoda, O = Local Development, CN = localhost serial=03 X509v3 Basic Constraints: critical CA:FALSE X509v3 Subject Alternative Name: critical DNS:localhost, IP Address:127.0.0.1, IP Address:0:0:0:0:0:0:0:1 notBefore=Apr 27 16:07:49 2026 GMT notAfter=Apr 27 16:07:49 2027 GMT
  69. まとめ・感想 • SSL/TLS 証明書周りの技術は少々とっつきにくい。 • セキュリティ侵害を経て改善してきた歴史が興味深い。 • SSL/TLS 証明書の有効期限の短縮については早めの検討と対策をやっ ていきましょう。

    • PHPによる実装は個人の趣味の範囲による活動です。実際の開発環境で は「なんかわからんけど ヨシッ!」 とコミットしてはいけません。 • ローカル環境で SSL/TLS 証明書を発行するのであれば openssl よりも mkcert がオススメです。