web-dev-qa-db-ja.com

opensslは基本的な制約なしに自己署名証明書を拒否しますか?

2つの異なる方法で生成された2つの非常に類似した自己署名証明書があります。

それらをテストするために私は持っています:

  1. ホストファイルにlocal.mydomain.comのエントリを追加しました
  2. テスト対象の証明書と関連する秘密鍵を使用して、ポート443でそのドメインをリッスンするようにnginxサーバーを設定します(次に、証明書を切り替えてnginxを再起動して比較します)。
  3. 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ビットの基本的な制約を含めますか?

6
junichiro

質問で説明されている問題は、より簡単な設定で再現できます。私はテスト用に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

汎用トラストストアを使用すると、エンドエンティティ証明書が信頼できるものとして明示的に宣言されたため、最後の検証も成功するはずです。

4
Steffen Ullrich

この問題はOpenSSLで本日修正されました( https://github.com/openssl/openssl/issues/1418 を参照)。すぐに利用できるはずです。

2
dvo