モーダルを閉じる工作HardwareHub ロゴ画像

工作HardwareHubは、ロボット工作や電子工作に関する情報やモノが行き交うコミュニティサイトです。さらに詳しく

利用規約プライバシーポリシー に同意したうえでログインしてください。

目次目次を開く/閉じる

オレオレ (サーバ/クライアント) 証明書の発行

モーダルを閉じる

ステッカーを選択してください

お支払い手続きへ
モーダルを閉じる

お支払い内容をご確認ください

購入商品
」ステッカーの表示権
メッセージ
料金
(税込)
決済方法
GooglePayマーク
決済プラットフォーム
確認事項

利用規約をご確認のうえお支払いください

※カード情報はGoogleアカウント内に保存されます。本サイトやStripeには保存されません

※記事の執筆者は購入者のユーザー名を知ることができます

※購入後のキャンセルはできません

作成日作成日
2015/07/08
最終更新最終更新
2021/09/05
記事区分記事区分
一般公開

目次

    サイバーセキュリティエンジニア

    証明書は認証局 (CA) が公開鍵 (をもとに情報を付加した証明書署名要求 (CSR; certificate signing request)) に署名をしたものです。一般的に証明書は公開鍵を内包しています。
    サーバ証明書およびクライアント証明書を実際にコマンド例を示しつつ発行します。

    認証局 (CA) を構築

    証明書は認証局 (CA) が 証明書署名要求 (CSR; certificate signing request) に署名をしたものです。認証局 (CA) は秘密鍵を持っています。署名にはその秘密鍵を使用します。つまり、署名に必要なものは秘密鍵だけです。認証局の秘密鍵以外の適当な秘密鍵で署名すると形式的には証明書が完成します。しかしながらその適当な秘密鍵の保持者は証明書の信頼性を第三者に一般に保証することができないためオレオレ証明書などと称されます。

    • 認証局の秘密鍵を使用する場合
      • サーバ証明書の運用が可能
      • クライアント証明書の運用が可能
    • 認証局のものでない単なる秘密鍵を使用する場合
      • サーバ証明書の運用が可能 (オレオレ証明書)
      • クライアント証明書の運用が不可能

    認証局は自分で構築することができます。これを俗にオレオレ認証局と称します。

    • 認証局の秘密鍵を使用する場合
      • サーバ証明書の運用が可能
      • クライアント証明書の運用が可能
    • オレオレ認証局の秘密鍵を使用する場合
      • サーバ証明書の運用が可能 (これもオレオレ証明書です。オレオレサーバ証明書)
      • クライアント証明書の運用が可能 (オレオレクライアント証明書)

    クライアント証明書の運用を考える場合は必ず認証局が必要です。ここではベリサインなどの認証局は使用せず、独自にオレオレ認証局を構築します。オレオレクライアント証明書の運用を考えているということになります。オレオレサーバ証明書の運用のみを考える場合は以降の手順は不要です。

    構築コマンド例

    root で作業します。なお、作業環境は CentOS 6.6 です。

    $ sudo su -l
    

    PKI ディレクトリに移動します。

    $ cd /etc/pki/
    

    独自認証局を構築するためのディレクトリが用意されています。中身は空です。

    $ ls /etc/pki/CA/
    certs  crl  newcerts  private
    

    必要なファイルをコピーしてきます。

    $ cp tls/misc/CA CA/
    $ cp tls/openssl.cnf CA/
    

    内容を編集します。

    • CA
      • $SSLEAY_CONFIG が最初に登場する前に一行 SSLEAY_CONFIG="-config /etc/pki/CA/openssl.cnf" 追加
      • DAYS および CADAYS の既定値をそれぞれ 100 年 (36500 日) に変更して事実上無期限にする
      • REQREQ="$OPENSSL req $SSLEAY_CONFIG -sha256" に変更 (sha256 を既定値にする)
      • CACA="$OPENSSL ca $SSLEAY_CONFIG -md sha256" に変更 (sha256 を既定値にする)
    • openssl.cnf
      • req_distinguished_name セクションの既定値を変更 countryName_default, stateOrProvinceName_default, localityName_default, 0.organizationName_default
      • default_days を 100 年 (36500 日) に変更して事実上無期限にする

    認証局用の秘密鍵を生成して、更にその秘密鍵をもとに作成した公開鍵と国情報などを合わせた CSR を生成します。更に自分の秘密鍵で署名します。/etc/pki/CA/CA には CATOP=/etc/pki/CA という一行があります。ルート CA は自分で自分の CSR に署名します。これらの処理はコマンド一つで実行できるようになっています。

    $ cd /etc/pki/CA
    $ ./CA -newca (最初はそのままエンターです)
    

    作成中に求められるコモンネームは認証局の識別子です。ここでは "MyCA" としました。また、認証局の秘密鍵のパスワードは my_ca_pass としました。認証局用の CSR を生成するときに認証局秘密鍵のパスワードが早速必要になります。

    成果物

    • private/cakey.pem (認証局秘密鍵)
    • cacert.pem (自分の秘密鍵で署名した認証局証明書)
    • newcerts/DB04B363DA63FFA3.pem (内容は cacert.pem と同じ。newcerts/ には今後新規発行した証明書が格納されていきます。証明書ディレクトリ。内容は index.txt で管理されます)
    • careq.pem (cacert.pem の発行に使用した CSR)

    証明書破棄リスト (CRL)

    将来的に証明書を無効にする場合に備えて破棄リストを生成しておきます。

    $ cd /etc/pki/CA
    $ echo 00 > crlnumber
    $ openssl ca -config openssl.cnf -gencrl -out crl.pem
    

    成果物

    • crl.pem (証明書破棄リスト)
    • crlnumber (内容がインクリメントされて "01" になった)

    以上で CA が構築されました。

    サーバ証明書の発行

    CA を構築していない場合

    こちらのページなどを参考にします。一般的にオレオレ証明書の作成といった場合は CA を構築せずに以下のようなコマンドで発行する場合が多いようです。

    秘密鍵の作成

    $ openssl genrsa -out my-private-key.pem 2048
    

    CSR の作成 (コモンネームなどの情報を入力)

    $ openssl req -sha256 -new -key my-private-key.pem -out csr.pem
    

    認証局 CA がないため自分の秘密鍵を流用して署名 (100 年の有効期間)

    $ openssl x509 -sha256 -req -days 36500 -in csr.pem -signkey my-private-key.pem -out my-certificate.crt
    

    成果物

    • my-certificate.crt (オレオレサーバ証明書)
    • my-private-key.pem (サーバに設置する秘密鍵。パスフレーズなし)

    それぞれ以下のコマンドで情報確認が可能

    秘密鍵

    $ openssl rsa -text -in my-private-key.pem
    Private-Key: (2048 bit)
    ...
    

    CSR

    $ openssl req -text -in csr.pem
    

    証明書

    $ openssl x509 -text -in my-certificate.crt
    

    CA を構築した場合

    「CA を構築していない場合」の手順または以下のバッチコマンドで秘密鍵と CSR を準備します。

    $ sudo su -l
    $ cd /etc/pki/CA
    $ ./CA -newreq
    

    パスフレーズは my_server_pass としました。CN は localhost としました。成果物は newreq.pem および newkey.pem です。次に構築した CA で署名します。

    $ sudo su -l
    $ cd /etc/pki/CA
    $ ./CA -sign
    

    成果物 newcert.pem が生成されました。同じ内容のファイルが newcerts/DB04B363DA63FFA4.pem (ファイル名はシリアル番号で環境依存) にも生成されています。シリアル連番 serial や発行証明書のリスト index.txt も更新されました。カレントディレクトリに生成されたままのファイルを移動させて整理します。newcerts のシリアル番号とファイル名を同じにしておきます。

    $ mkdir csr
    $ mv newreq.pem csr/DB04B363DA63FFA4.pem
    $ mv newkey.pem private/DB04B363DA63FFA4.pem
    

    内容としては同じではありますが、使い勝手をよくするために秘密鍵からパスワードを解除して証明書からは余分な文字列を除去して依頼主に渡します。

    $ cd /etc/pki/CA
    $ mkdir share
    
    $ openssl rsa -in private/DB04B363DA63FFA4.pem -out share/localhost.key
    
    $ mv newcert.pem share/localhost.crt
    $ openssl x509 -in share/localhost.crt -out share/localhost.crt
    

    証明書から削除した余分な文字列は上述の通りコマンドで再確認できます。

    $ openssl x509 -text -in share/localhost.crt
    

    サーバ証明書の使用

    Apache の設定例

    必要なソフトウェアをインストールします。

    $ sudo yum install httpd mod_ssl
    

    用意したサーバ証明書を設定します。

    $ sudo vi /etc/httpd/conf.d/ssl.conf
    SSLCertificateFile /etc/pki/CA/share/localhost.crt
    SSLCertificateKeyFile /etc/pki/CA/share/localhost.key
    

    サービスを起動します。

    $ sudo service httpd start
    

    アクセスしてみましょう。

    $ curl https://localhost/  ←オレオレサーバ証明書のためエラー
    $ curl https://localhost/ -k  ←証明書を強制的に信頼するオプション
    $ curl https://localhost/ --cacert /etc/pki/CA/cacert.pem  ←指定した認証局証明書を信頼するオプション
    

    上記 curl コマンドの二つ目はブラウザで信頼性のないサーバ証明書を個別に信頼する処理に相当します。三つめは構築した CA の証明書をブラウザにインポートすることに相当します。Firefox の場合は以下のようになります。

    Firefox → オプション → 詳細 → 証明書 → 証明書を表示 → 認証局証明書 → インポート → cacert.pem → すべてチェックして OK

    証明書をインポートした CA で署名された証明書であればブラウザは信頼のある証明書として扱うようになります。ただし、コモンネーム (CN) が一致しない場合はやはりブラウザに信頼されないことに注意してください。他人のサイトの証明書を勝手に利用したなりすまし防止のためです。

    nginx の設定例

    必要なソフトウェアをインストールします。

    $ sudo yum install epel-release (環境によっては不要)
    $ sudo yum install nginx
    

    用意したサーバ証明書を設定します。コメントアウトをすべて解除して以下のように編集します。

    $ sudo vi /etc/nginx/conf.d/ssl.conf
    ssl_certificate /etc/pki/CA/share/localhost.crt;
    ssl_certificate_key /etc/pki/CA/share/localhost.key;
    

    サービスを起動します。

    $ sudo service nginx start
    

    アクセスしてみましょう。

    $ curl https://localhost/  ←オレオレサーバ証明書のためエラー
    $ curl https://localhost/ -k  ←証明書を強制的に信頼するオプション
    $ curl https://localhost/ --cacert /etc/pki/CA/cacert.pem  ←指定した認証局証明書を信頼するオプション
    

    AWS ELB の設定例

    Apache や nginx は HTTP で動作させて ELB にサーバ証明書をアップロードすることができます。クライアントは HTTPS 通信を ELB に対して行います。

    クライアント証明書の発行

    以下のバッチコマンドで秘密鍵と CSR を作成します。あるいはサーバ証明書の発行における「CA を構築していない場合」の手順でも可能です。

    $ sudo su -l
    $ cd /etc/pki/CA
    $ ./CA -newreq
    

    パスフレーズは my_client_pass としました。CN は myuser としました。newreq.pem および newkey.pem が生成されます。構築した CA で署名します。

    $ sudo su -l
    $ cd /etc/pki/CA
    $ ./CA -sign
    

    成果物 newcert.pem が生成されました。同じ内容のファイルが newcerts/CF1EC9646459BA80.pem (ファイル名はシリアル番号で環境依存) にも生成されています。シリアル連番 serial や発行証明書のリスト index.txt も更新されました。カレントディレクトリに生成されたままのファイルを移動させて整理します。newcerts のシリアル番号とファイル名を同じにしておきます。

    $ mkdir csr
    $ mv newreq.pem csr/CF1EC9646459BA80.pem
    $ mv newkey.pem private/CF1EC9646459BA80.pem
    

    最後にユーザへ配布するために秘密鍵と証明書をパッケージングして .p12 ファイルを作ります。

    $ openssl pkcs12 -export -in newcert.pem -inkey private/CF1EC9646459BA80.pem -out myuser.p12
    $ rm newcert.pem
    

    まず private/DB04B363DA63FFA6.pem のパスワードを入力する必要があります。その次に .p12 ファイルを開封してクライアントにインストールする際に必要なパスワードを設定します。my_p12_pass としました。

    成果物

    $ mv myuser.p12 share/
    

    クライアント証明書の使用

    クライアント証明書を利用した認証は Basic/Digest 認証と対比させて考えると理解しやすいかもしれません。「Digest 認証」や「Basic 認証 + HTTPS」よりもセキュアな認証を実現できます。サーバ証明書の場合は、オレオレ認証局をクライアントに信頼させることで、オレオレ認証局が署名したサーバ証明書の信頼性を保証しました。クライアント証明書の場合は、オレオレ認証局をサーバに信頼させることで、オレオレ認証局が署名したクライアント証明書の信頼性を保証します。「オレオレクライアント証明書をサーバが信頼する」は誤りであることに注意してください。ちなみに「オレオレサーバ証明書をクライアントが信頼する」ことは前述の通り可能ですので混乱しないでください。

    Apache の設定例

    前述のサーバ証明書の設定をまずは行ってください。そのうえで、クライアント証明書に署名した CA の証明書を設定します。クライアント証明書だけの使用はできないことに注意してください。

    $ sudo vi /etc/httpd/conf.d/ssl.conf
    

    以下のように設定を変更します。

    #SSLCACertificateFile /etc/pki/tls/certs/ca-bundle.crt
    ↓
    SSLCACertificateFile /etc/pki/CA/cacert.pem
    SSLCARevocationFile /etc/pki/CA/crl.pem (証明書破棄リストを利用したい場合です。必須ではありません)
    
    #SSLVerifyClient require
    ↓
    SSLVerifyClient require
    
    #SSLVerifyDepth 10
    ↓
    SSLVerifyDepth 1
    

    クライアント証明書のないユーザはそもそもアクセスできません。ただ、同じ CA が署名したクライアント証明書であれば無作為に許可することは避けたいため CN でも制限をかけます。アクセス制限をかけたいディレクトリおよび許可するユーザ一覧を登録します。

    <VirtualHost _default_:443>
    ...
    
    <Directory "/var/www/html">
        SSLRequire %{SSL_CLIENT_S_DN_CN} in {"myuser", "hoge", "fuga"}
    </Directory>
    ...
    
    </VirtualHost>
    

    Welcome ページだけは閲覧できてしまうためファイル内の指示に従い内容をコメントアウトします。

    $ sudo vi /etc/httpd/conf.d/welcome.conf
    

    サービスを起動します。

    $ sudo service httpd start
    

    クライアント証明書のインストール

    ブラウザからアクセスすると以下のようなエラーが出て制限されていることが確認できます。

    Firefox

    SSL peer was unable to negotiate an acceptable set of security parameters. (エラーコード: ssl_error_handshake_failure_alert) 受信したデータの真正性を検証できなかったため、このページは表示できませんでした。

    Chrome

    サーバーとの安全な接続を確立できません。サーバー側に問題があるか、サーバーが必要とするクライアント認証証明書を所持していない可能性があります。

    クライアント証明書をブラウザにインストールします。Firefox の場合の手順を示します。

    Firefox → オプション → 詳細 → 証明書 → 証明書を表示 → あなたの証明書 → インポート → myuser.p12 → my_p12_pass → 証明書と鍵が正常に復元されました

    アクセスできるようになったことを確認します。

    nginx の設定例

    前述のサーバ証明書の設定をまずは行ってください。そのうえで、クライアント証明書に署名した CA の証明書を設定します。クライアント証明書だけの使用はできないことに注意してください。サーバ証明書は必要になります。

    $ sudo vi /etc/nginx/conf.d/ssl.conf
    

    以下のように編集します。

    server {
        listen 443;
        ...
    
        ssl_certificate /etc/pki/CA/share/localhost.crt;
        ssl_certificate_key /etc/pki/CA/share/localhost.key;
        ...
    
        # ここから追記
        ssl_verify_client on;
        ssl_client_certificate /etc/pki/CA/cacert.pem;
        ssl_crl /etc/pki/CA/crl.pem; (証明書破棄リストを利用したい場合です。必須ではありません)
        ssl_verify_depth 1;
    
        if ($ssl_client_s_dn !~ "CN=myuser") {
            return 403;
        }
        # ここまで追記
    
        location / {
            ...
        }
    }
    

    前述 Apache の手順を参考に動作検証を行います。

    AWS ELB を利用する場合

    ELB はサーバ証明書の登録をサポートしています。しかしながら 2015/07/10 現在のところ ELB が信頼する CA の証明書を変更できないため、オレオレ認証局が署名したクライアント証明書を利用することができません。商用の CA にクライアント証明書の発行を依頼する、もしくは ELB では HTTPS を復号化せずに単純に TCP 通信を転送して、ELB 配下の EC2 インスタンスで認証および復号化を行います。前者の場合は SSL アクセラレータという観点からサーバの負荷的には有利にはなりますが、CN による制限が ELB では実現できません。後者の場合は以下のように ELB を設定します。

    • ELB および EC2 の SecurityGroup で 443 からの Inbound を許可
    • ELB のリスナー設定を TCP(443) → TCP(443) と設定
    • ELB のヘルスチェック設定を TCP 443 と設定

    curl コマンドで p12 ファイルを利用

    クライアント証明書を取り出します。秘密鍵は別ファイルとして取り出したいため -nokeys を付与します。

    $ sudo openssl pkcs12 -in myuser.p12 -out myuser.crt -nokeys
    

    秘密鍵を取り出します。証明書は別ファイルとして取り出したため -nocerts を付与します。秘密鍵には DES 暗号をかけたくないため -nodes を付与します。

    $ sudo openssl pkcs12 -in myuser.p12 -out myuser.key -nocerts -nodes
    

    クライアント証明書および秘密鍵を用いて curl を実行します。

    $ curl https://localhost/ --cert ./myuser.crt --key ./myuser.key
    ↑信頼のない CA が署名した localhost のサーバ証明書は使用できずエラー
    $ curl https://localhost/ --cert ./myuser.crt --key ./myuser.key -k
    ↑強制的に localhost のサーバ証明書を curl に信頼させて使用
    $ curl https://localhost/ --cert ./myuser.crt --key ./myuser.key --cacert /etc/pki/CA/cacert.pem
    ↑localhost のサーバ証明書に署名した CA を信頼のあるものとして設定
    

    ruby スクリプトで p12 ファイルを利用

    #!/bin/env ruby
    require 'net/https'
    
    # p12 ファイルを復元
    p12 = OpenSSL::PKCS12.new(File.read('/etc/pki/CA/share/myuser.p12'), "my_p12_pass")
    
    # HTTP クライアント
    https = Net::HTTP.new('localhost', 443)
    
    # HTTPS を利用
    https.use_ssl = true
    
    # クライアント証明書を利用
    https.cert = p12.certificate
    https.key = p12.key
    
    # localhost のサーバ証明書に署名した CA を信頼のあるものとして設定
    https.ca_file = '/etc/pki/CA/cacert.pem'
    https.verify_mode = OpenSSL::SSL::VERIFY_PEER
    
    # あるいは強制的に localhost のサーバ証明書を信頼のあるものとして扱う
    #https.verify_mode = OpenSSL::SSL::VERIFY_NONE
    
    # HTTPS 接続を行う
    https.start {|h|
      response = h.get('/')
      puts response.body
    }
    

    発行したクライアント証明書の無効化

    破棄したい証明書に署名した CA に移動します。

    $ sudo su -l
    $ cd /etc/pki/CA
    

    発行済み証明書の一覧を見て、破棄したい証明書のシリアルを探します。

    $ less /etc/pki/CA/index.txt
    

    破棄を実行します。

    $ openssl ca -config openssl.cnf -revoke newcerts/A873F5D1CCC7EB36.pem
    

    'V' が 'R' に変更されたことを確認します。

    $ less /etc/pki/CA/index.txt
    

    HTTP サーバで参照する証明書破棄リスト (CRL) を作成します。

    $ openssl ca -config openssl.cnf -gencrl -out crl.pem
    

    これを Apache や nginx の設定ファイルで参照している場合、サーバに再読み込みさせることによって crl.pem に記載されたクライアント証明書を用いたアクセスを許可しないようになります。

    $ service httpd reload (Apache の場合)
    $ service nginx reload (nginx の場合)
    

    crl.pem を参照している場合は "CN=myuser" のクライアント証明書ではアクセスできないことを、上述のブラウザ, curl, ruby スクリプトなどで確認します。

    Likeボタン(off)0
    詳細設定を開く/閉じる
    アカウント プロフィール画像

    サイバーセキュリティエンジニア

    記事の執筆者にステッカーを贈る

    有益な情報に対するお礼として、またはコメント欄における質問への返答に対するお礼として、 記事の読者は、執筆者に有料のステッカーを贈ることができます。

    >>さらに詳しくステッカーを贈る
    ステッカーを贈る コンセプト画像

    Feedbacks

    Feedbacks コンセプト画像

      ログインするとコメントを投稿できます。

      ログインする

      関連記事

      • クロスルート証明書の具体例
        サムネイル画像-1b1965666c
        クロスルート証明書とは、中間証明書を署名したルート CA を更に別のルート CA が署名したものです。中間証明書を署名したルート CA の証明書がインストールされていないクライアントであっても、クロスルート証明書を署名したルート CA の証明書がインストールされていれば、サーバー証明書の信頼性を確認できます。 具体例 openssl コマンドで実際にサーバー証明書を取得しました。 $ openss...
        ほんわかパンダほんわかパンダ4/21/2018に更新
        いいねアイコン画像0
      • JDK keytool の基本的な使い方 (openssl との対比)
        JDK でインストールされる keytool コマンドの利用方法を、openssl コマンドと対比してまとめます。keytool コマンドは、Android Studio のドキュメントでも使用される、Java における一般的なツールです。 秘密鍵、公開鍵 (、自己署名証明書) の生成 keytool は openssl と異なり、秘密鍵と公開鍵の片方のみを生
      • 証明書、認証局とは? (PKI や ルートCA について)
        証明書とは 公開鍵証明書 (単に証明書とも) は以下の2つのセットのことです。信頼を有するある者が、信頼のないある者の公開鍵の信頼性を第三者に保証するために発行します。 デジタル署名: 信頼を有するある者がその秘密鍵で、信頼のないある者の公開鍵 (のハッシュ値) を暗号化した結果。電子署名とも。 信頼のないある者の公開鍵 第三者が証明書を利用する手順は以下の通りです。 公開鍵証明書から、デジタル署...
      • 暗号技術まわりの用語の簡単なまとめ
        暗号方式の分類 暗号化に用いる鍵と復号化に用いる鍵が異なるかどうかで2種類に分類されます。 対称暗号 暗号化と復号化に同じ鍵を用います。共通鍵暗号、共有鍵暗号、秘密鍵暗号ともよばれます。 具体例 DES (Data Encryption Standard): ブルートフォースアタックで現実的な時間内に解読されることが分かっています 3DES: トリプルデス。DESを三段重ねにしたもので処理スピード...
        トムトム8/20/2017に更新
        いいねアイコン画像0