2つの異なる方法で生成された2つの非常に類似した自己署名証明書があります。
それらをテストするために私は持っています:
openssl s_client -connect local.mydomain.com -CAfile /path/to/the/ca/cert.pem
を使用してnginxに接続しました1つの証明書が失敗しました:
CONNECTED(00000003)
depth=0 CN = local.mydomain.com
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 CN = local.mydomain.com
verify error:num=21:unable to verify the first certificate
verify return:1
---
Certificate chain
0 s:/CN=local.mydomain.com
i:/CN=local.mydomain.com
---
1つの証明書が成功します。
CONNECTED(00000003)
depth=0 CN = local.mydomain.com
verify return:1
---
Certificate chain
0 s:/CN = local.mydomain.com
i:/CN = local.mydomain.com
---
証明書の詳細をopenssl x509 -in /path/to/the/ca/cert.pem -text -noout
と比較します
失敗した証明書:
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
47:dc:02:c7:11:fc:8e:96:45:22:aa:6b:23:79:32:ca
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN=local.mydomain.com
Validity
Not Before: Nov 18 11:55:31 2016 GMT
Not After : Nov 18 12:15:31 2017 GMT
Subject: CN=local.mydomain.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
<stuff>
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Client Authentication, TLS Web Server Authentication
X509v3 Subject Alternative Name:
DNS:local.mydomain.com
X509v3 Subject Key Identifier:
6D:4F:AF:E4:60:23:72:E5:83:27:91:7D:1D:5F:E9:7C:D9:B6:00:2A
Signature Algorithm: sha256WithRSAEncryption
<stuff>
作業証明書:
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
9b:6b:3d:a3:b9:a3:a4:b4
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN=local.mydomain.com
Validity
Not Before: Nov 19 13:27:30 2016 GMT
Not After : Nov 19 13:27:30 2017 GMT
Subject: CN=local.mydomain.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
<stuff>
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
03:E7:DA:AA:2E:CC:23:ED:C5:07:3D:E1:33:86:F5:22:D4:76:EB:CB
X509v3 Authority Key Identifier:
keyid:03:E7:DA:AA:2E:CC:23:ED:C5:07:3D:E1:33:86:F5:22:D4:76:EB:CB
X509v3 Basic Constraints:
CA:TRUE
Signature Algorithm: sha256WithRSAEncryption
57<stuff>
これを見ると最も明白な違いは、作業証明書にはCA:TRUE
の下にX509v3 Basic Constraints
があることです。ただし、Webを読んでいると、自己署名証明書はCAである必要はないという印象を受けました。特に、これは通常はそうではないことを示しています。
そこでの答えは、自己署名されているのでCAは関与していないということです。しかし、おそらくopensslはそれを設定するために自己署名証明書を必要としますか?または、証明書が他の関連する方法で異なる場合がありますか?
更新:
私は、opensslの内部をprintfデバッグしようとするのにしばらく時間を費やしました。ファイルv3_purp.cには、次のマクロがあります。
#define ku_reject(x, usage) \
(((x)->ex_flags & EXFLAG_KUSAGE) && !((x)->ex_kusage & (usage)))
これは、自己署名証明書をチェックする次のコードで使用されます。
/* Does subject name match issuer ? */
if (X509_check_akid(x, x->akid) == X509_V_OK &&
!ku_reject(x, KU_KEY_CERT_SIGN))
x->ex_flags |= EXFLAG_SS;
失敗した証明書の場合、(x)->ex_flags & EXFLAG_KUSAGE
は2に等しい
EXFLAG_KUSAGE
は、失敗した証明書に対してここで設定されます。前の同じファイルで:
static void x509v3_cache_extensions(X509 *x)
{
......
if ((usage = X509_get_ext_d2i(x, NID_key_usage, NULL, NULL))) {
if (usage->length > 0) {
x->ex_kusage = usage->data[0];
if (usage->length > 1)
x->ex_kusage |= usage->data[1] << 8;
} else
x->ex_kusage = 0;
x->ex_flags |= EXFLAG_KUSAGE;
ASN1_BIT_STRING_free(usage);
}
....
したがって、問題のある証明書にはX509v3 Key Usage
拡張子が付いているようですが、その拡張子にKU_KEY_CERT_SIGNが指定されていませんか?
更新2:
https://tools.ietf.org/html/rfc5280#section-4.2.1. によると:
「サブジェクトの公開鍵が公開鍵証明書の署名の検証に使用されると、keyCertSignビットがアサートされます。keyCertSignビットがアサートされる場合、基本制約拡張(セクション4.2.1.9)のcAビットもアサートする必要があります。」
したがって、基本的な制約のCAビットは存在する必要はありませんが、X509v3キー使用法セクションを証明書に含める場合、opensslコードベースに従って、keyCertSignを指定する必要があり、RFCに従って、keyCertSignを指定する場合は、次のことも行う必要があります。 CAビットの基本的な制約を含めますか?
質問で説明されている問題は、より簡単な設定で再現できます。私はテスト用に2つの自己署名証明書を作成しましたが、1つはCAフラグ(ss-ca.pem
)を持っているが、もう1つは持っていない(ss-noca.pem
)だけが異なります。 openssl verify
を使用すると、特定のCAパスに対して証明書を検証できるかどうかを確認できます。
CA:trueを使用した自己署名証明書は、チェーンの検証中にX509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT(エラー18)に出くわしますが、それ自体に対して正常に検証されます( 'OK')。
$ openssl verify -CAfile ss-ca.pem ss-ca.pem
ss-ca.pem: CN = test CA
error 18 at 0 depth lookup:self signed certificate
OK
CA:falseの自己署名証明書では、検証は成功せず(「OK」ではありません)、エラーX509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY(エラー20)が表示されます。
$ openssl verify -CAfile ss-noca.pem ss-noca.pem
ss-noca.pem: CN = test no CA
error 20 at 0 depth lookup:unable to get local issuer certificate
私の理論では、OpenSSLは-CAfile
で指定された証明書への信頼チェーンを構築しようとします。信頼チェーンを構築するには、発行者の証明書のサブジェクトが証明書の発行者と一致する必要があり、署名が有効である(つまり、発行者の公開鍵を使用して検証される)必要があり、発行者の証明書に証明書への署名を許可する必要があります(CA:trueなど)。最初の2つのチェックは両方の証明書で問題を返しませんが、CA:trueのチェックはss-ca.pem
に対してのみ有効です。
OpenSSL -CAfile
とトラストストアの他の概念との主な違いは、-CAfile
は、その名前が示すことのみを実行することです。これには、信頼チェーンの検証に使用される信頼できるCAのリストが含まれます。この他のトラストストアの実装とは異なり、サーバーが送信した証明書がトラストストアに含まれているため、証明書がどのような種類のフラグを持っているか、または期限切れの場合。
汎用トラストストアとOpenSSL -CAfile
のこの違いは、CA以外のエンドエンティティ証明書を信頼できるものとしてストアに配置した場合にも見られます。この例では、CA:trueを持たないエンドエンティティ証明書ca.pem
を発行したCA証明書server.pem
を使用しています。
CA証明書に対するエンドエンティティ証明書の検証は期待どおりに機能します。
$ openssl verify -CAfile ca.pem server.pem
server.pem: OK
ただし、CAストアは汎用の信頼ストアではなく、CA証明書に限定されているため、CAストアにエンドエンティティ証明書を入れて直接信頼しようとしても機能しません。
$ openssl verify -CAfile server.pem server.pem
error 20 at 0 depth lookup:unable to get local issuer certificate
汎用トラストストアを使用すると、エンドエンティティ証明書が信頼できるものとして明示的に宣言されたため、最後の検証も成功するはずです。
この問題はOpenSSLで本日修正されました( https://github.com/openssl/openssl/issues/1418 を参照)。すぐに利用できるはずです。