web-dev-qa-db-ja.com

Chrome 58で機能するopensslを使用した自己署名証明書の生成

Chrome 58以降、Common Nameに依存する自己署名証明書を受け付けなくなりました: https://productforums.google.com/forum/#!topic/ chrome/zVo3M8CgKzQ; context-place = topicsearchin/chrome/category $ 3ACanary%7Csort:relevance%7Cspell:false

代わりに、Subject Alt Nameを使用する必要があります。私は以前、自己署名証明書を生成する方法についてこのガイドに従っていました: https://devcenter.heroku.com/articles/ssl-certificate-selfserver.crtおよびserver.keyファイルは、私がやっていることに対応しています。 SANを含む新しい証明書を生成する必要がありますが、これを行うすべての試みはChrome 58。

これが私がやったことです:

上記のHerokuの記事の手順に従ってキーを生成しました。次に、新しいOpenSSL構成ファイルを作成しました。

[ req ]
default_bits        = 2048
distinguished_name  = req_distinguished_name
req_extensions      = san
extensions          = san
[ req_distinguished_name ]
countryName         = US
stateOrProvinceName = Massachusetts
localityName        = Boston
organizationName    = MyCompany
[ san ]
subjectAltName      = DNS:dev.mycompany.com

次に、次のコマンドでserver.crtを生成しました:

openssl req \
-new \
-key server.key \
-out server.csr \
-config config.cnf \
-sha256 \
-days 3650

Macを使用しているので、server.crtファイルをキーチェーンで開いて、システム証明書に追加しました。次に、それをAlways Trustに設定します。

SAN値を設定する構成ファイルを除いて、これらは以前のバージョンのChromeで使用して自己署名証明書を生成および信頼するために使用したものと同様の手順でした。 。

ただし、この後もERR_CERT_COMMON_NAME_INVALID in Chrome 58。

54
bcardarella

私の解決策:

openssl req \
    -newkey rsa:2048 \
    -x509 \
    -nodes \
    -keyout server.key \
    -new \
    -out server.crt \
    -subj /CN=dev.mycompany.com \
    -reqexts SAN \
    -extensions SAN \
    -config <(cat /System/Library/OpenSSL/openssl.cnf \
        <(printf '[SAN]\nsubjectAltName=DNS:dev.mycompany.com')) \
    -sha256 \
    -days 3650

ステータス:うまくいきました

67
bcardarella

Windowsでは、このスクリプトをSSLフォルダーにmakeCERT.batとして保存します。これらのファイルが作成されます:example.cnf、example.crt、example.key

@echo off

REM IN YOUR SSL FOLDER, SAVE THIS FILE AS: makeCERT.bat
REM AT COMMAND LINE IN YOUR SSL FOLDER, RUN: makecert
REM IT WILL CREATE THESE FILES: example.cnf, example.crt, example.key
REM IMPORT THE .crt FILE INTO CHROME Trusted Root Certification Authorities
REM REMEMBER TO RESTART Apache OR NGINX AFTER YOU CONFIGURE FOR THESE FILES

REM PLEASE UPDATE THE FOLLOWING VARIABLES FOR YOUR NEEDS.
SET HOSTNAME=example
SET DOT=com
SET COUNTRY=US
SET STATE=KS
SET CITY=Olathe
SET ORGANIZATION=IT
SET ORGANIZATION_UNIT=IT Department
SET EMAIL=webmaster@%HOSTNAME%.%DOT%

(
echo [req]
echo default_bits = 2048
echo Prompt = no
echo default_md = sha256
echo x509_extensions = v3_req
echo distinguished_name = dn
echo:
echo [dn]
echo C = %COUNTRY%
echo ST = %STATE%
echo L = %CITY%
echo O = %ORGANIZATION%
echo OU = %ORGANIZATION_UNIT%
echo emailAddress = %EMAIL%
echo CN = %HOSTNAME%.%DOT%
echo:
echo [v3_req]
echo subjectAltName = @alt_names
echo:
echo [alt_names]
echo DNS.1 = *.%HOSTNAME%.%DOT%
echo DNS.2 = %HOSTNAME%.%DOT%
)>%HOSTNAME%.cnf

openssl req -new -x509 -newkey rsa:2048 -sha256 -nodes -keyout %HOSTNAME%.key -days 3560 -out %HOSTNAME%.crt -config %HOSTNAME%.cnf
17
STWilson

これを機能させる方法の例を示す素晴らしい答えはいくつかありますが、あなたの試みのどこがうまくいかなかったかを説明する答えはありません。 OpenSSLはかなり直感的でない場合があるため、一通り説明する価値があります。

まず、余談ですが、OpenSSLはデフォルトで、構成で指定した識別名の値を無視します。それらを使用する場合は、Prompt = noを構成に追加する必要があります。さらに、記述されたコマンドは証明書requestのみを生成し、証明書自体は生成しないため、-daysコマンドは何も実行しません。

このコマンドを使用して証明書要求を生成し、結果を検査すると、サブジェクトの代替名が存在します。

$ openssl req -new -key server.key -out server.csr -config config.cnf -sha256
$ openssl req -text -noout -in server.csr
Certificate Request:
    Data:
        Version: 1 (0x0)
        Subject: C = US, ST = Massachusetts, L = Boston, O = MyCompany
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    ...
                Exponent: 65537 (0x10001)
        Attributes:
        Requested Extensions:
            X509v3 Subject Alternative Name:
                DNS:dev.mycompany.com
    Signature Algorithm: sha256WithRSAEncryption
         ...

ただし、herokuリンクのコマンドを使用して証明書を生成し、結果を検査すると、サブジェクトの代替名がありません。

$ openssl x509 -req -sha256 -days 365 -in server.csr -signkey server.key -out server.crt
$ openssl x509 -text -noout -in server.crt
Certificate:
    Data:
        Version: 1 (0x0)
        Serial Number:
            89:fd:75:26:43:08:04:61
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C = US, ST = Massachusetts, L = Boston, O = MyCompany
        Validity
            Not Before: Jan 21 04:27:21 2018 GMT
            Not After : Jan 21 04:27:21 2019 GMT
        Subject: C = US, ST = Massachusetts, L = Boston, O = MyCompany
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    ...
                Exponent: 65537 (0x10001)
    Signature Algorithm: sha256WithRSAEncryption
         ...

その理由は、デフォルトではOpenSSLがリクエストから証明書に拡張機能をコピーしないためです。通常、証明書は顧客からの要求に基づいてCAによって作成/署名され、一部の拡張機能は、要求で定義された拡張機能を盲目的に信頼する場合、CAが意図していた以上の能力を証明書に付与できます。

OpenSSLに拡張機能をコピーするように指示する方法はありますが、IMHOは、証明書を生成するときに、構成ファイルで拡張機能を提供するだけの作業よりも作業が多くなります。

既存の構成ファイルを使用しようとしても、最上位セクションが[req]とマークされているため、これらの設定はreqコマンドにのみ適用され、x509コマンドには適用されません。トップレベルのセクションマーカーを設定する必要はないので、最初の行を削除するだけで、要求または証明書の生成の両方で正常に機能します。

$ openssl x509 -req -sha256 -days 365 -in server.csr -signkey server.key -out server.crt -extfile config.cnf

または、-x509引数をreqコマンドに使用して、最初に要求を作成してから証明書を作成するのではなく、単一のコマンドで自己署名証明書を生成できます。この場合、[req]セクション行を削除する必要はありません。そのセクションがreqコマンドによって読み取られて使用されるためです。

$ openssl req -x509 -sha256 -days 365 -key server.key -out server.crt -config config.cnf

要約すると、上記のコマンドで使用されている変更された構成ファイルは次のとおりです。

default_bits        = 2048
distinguished_name  = dn
x509_extensions     = san
req_extensions      = san
extensions          = san
Prompt              = no
[ dn ]
countryName         = US
stateOrProvinceName = Massachusetts
localityName        = Boston
organizationName    = MyCompany
[ san ]
subjectAltName      = DNS:dev.mycompany.com
13
pavon

ここに私のために働く解決策があります:

CAキーと証明書を作成します

# openssl genrsa -out server_rootCA.key 2048
# openssl req -x509 -new -nodes -key server_rootCA.key -sha256 -days 3650 -out server_rootCA.pem

server_rootCA.csr.cnfを作成します

# server_rootCA.csr.cnf
[req]
default_bits = 2048
Prompt = no
default_md = sha256
distinguished_name = dn

[dn]
C=DE
ST=Berlin
L=NeuKoelln
O=Weisestrasse
OU=local_RootCA
[email protected]
CN = server.berlin

v3.ext構成ファイルを作成します

# v3.ext
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names

[alt_names]
DNS.1 = server.berlin

サーバーキーを作成します

# openssl req -new -sha256 -nodes -out server.csr -newkey rsa:2048 -keyout server.key -config <( cat server_rootCA.csr.cnf )

サーバー証明書を作成

# openssl x509 -req -in server.csr -CA server_rootCA.pem -CAkey server_rootCA.key -CAcreateserial -out server.crt -days 3650 -sha256 -extfile v3.ext

Apache2サイトファイル、HTTPS(ポート443)セクションに証明書とキーを追加します

SSLCertificateFile    /etc/Apache2/ssl/server.crt
SSLCertificateKeyFile    /etc/Apache2/ssl/server.key

server_rootCA.pemをサーバーからマシンにコピーします。

# scp [email protected]:~/server_rootCA.pem .

..そして、それをChromiumブラウザに追加します

Chromium -> Setting -> (Advanced) Manage Certificates -> Import -> 'server_rootCA.pem'

あなたはすべて完了です!

P.S。機能的なCAとサーバーの証明書ペアを作成する代わりに(上記の手順に従って)、HTTPサーバー構成でHSTSヘッダーを無効にするだけで済みます。これにより、ChromiumがHTTPSを強制するのを防ぎ、ユーザーがカスタムCA(server_rootCA.pem)証明書を取得してインストールしなくても、「詳細設定→your.url(安全でない)に進む」をクリックできるようになります。言い換えると、HSTSを無効にする必要があると、HTTPおよび/または安全でないHTTPS接続を介してサイトを公開することができます(注意してください)。

Apache2の場合、以下をサイトファイルのHTTP(ポート80)セクションに追加します

Header unset Strict-Transport-Security
Header always set Strict-Transport-Security "max-age=0;includeSubDomains"

Debian/Apache2.4 + Debian/Chromium 59でテスト済み

https://ram.k0a1a.net/self-signed_https_cert_after_chrome_58

13
binary.koala

私の解決策は、メインのopenssl.cnfをそのままにし、最後に[ cert_www.example.com ]のような新しいセクションを追加することです。ここで、www.example.comは、証明書を作成するWebサイトです。その中に、私が必要とするsubjectAltName(およびその他すべて)を入れます。もちろん、セクションには任意の名前を付けることができます。

その後、以前と同じようにopenssl reqコマンドを実行し、そのコンテンツを取得するために-extensions cert_www.example.comを追加し、-subjを追加してすべてのDN情報を直接追加します。

openssl x509 -textを使用して、証明書の作成後、使用前に証明書の内容を確認することを忘れないでください

2
Patrick Mevzek

設定が組み込まれたBashスクリプト

Bashを使用してプラットフォーム間で機能するシェルスクリプトとして。シェルにHOSTNAME envが設定されていると想定するか、選択したホスト名を指定します。 self_signed_cert.sh test

set -e

if [ -z "$1" ]; then
  hostname="$HOSTNAME"
else
  hostname="$1"
fi

local_openssl_config="
[ req ]
Prompt = no
distinguished_name = req_distinguished_name
x509_extensions = san_self_signed
[ req_distinguished_name ]
CN=$hostname
[ san_self_signed ]
subjectAltName = DNS:$hostname, DNS:localhost
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = CA:true
keyUsage = nonRepudiation, digitalSignature, keyEncipherment, dataEncipherment, keyCertSign, cRLSign
extendedKeyUsage = serverAuth, clientAuth, timeStamping
"

openssl req \
  -newkey rsa:2048 -nodes \
  -keyout "$hostname.key.pem" \
  -x509 -sha256 -days 3650 \
  -config <(echo "$local_openssl_config") \
  -out "$hostname.cert.pem"
openssl x509 -noout -text -in "$hostname.cert.pem"

上記は多かれ少なかれ最小限の設定ファイル情報opensslニーズを注入します。

注、追加のDNS:localhostをSANとして含めて、localhostを介したテストをより簡単に行えるようにしました。不要な場合は、スクリプトから余分なビットを削除してください。

クレジット

bcardarellaの回答 はすばらしい(担当者が不十分なためコメント/賛成投票できません)。ただし、答えはプラットフォーム固有の既存のopenssl構成ファイルの場所を使用します...したがって:

私のために働く

明らかに、自分のプラットフォーム用のopenssl設定ファイルを見つけて、正しい場所に置き換えるだけで済みます。

テスト

テストする方法として、test.cert.pemchrome://settings/certificatesのc​​hromeの権限にインポートします。

openssl s_server -key test.key.pem -cert test.cert.pem -accept 20443 -www &
openssl_pid=$!
google-chrome https://localhost:20443

そしてテストの後

kill $openssl_pid
2
JPvRiel