簡體   English   中英

Python cryptography — 如何在自簽名證書中包含“主題密鑰標識符”和“授權密鑰標識符”的 X509 擴展?

[英]Python cryptography — How to include X509 extensions for “Subject Key Identifier” and “Authority Key Identifier” in a self-signed cert?

我正在使用 Python 中的“密碼學”模塊來創建用於測試的自簽名證書。 我按照這里的例子“https://cryptography.io/en/latest/x509/tutorial.html”和“https://gist.github.com/bloodearnest/9017111a313777b9cce5”,到目前為止有以下代碼——

    def generate_selfsigned_cert(hostname, san_list=None):
        """Generates self signed certificate for a hostname, and optional IP addresses."""
        from cryptography import x509
        from cryptography.x509.oid import NameOID
        from cryptography.hazmat.primitives import hashes
        from cryptography.hazmat.backends import default_backend
        from cryptography.hazmat.primitives import serialization
        from cryptography.hazmat.primitives.asymmetric import rsa
        from datetime import datetime
        from datetime import timedelta
        import ipaddress


        # Generate pvt key
        key = rsa.generate_private_key(
                public_exponent=65537,
                key_size=2048
                )
        # Write key to file
        pvt_key = self.log_directory + '/server.key.pem'
        with open(pvt_key, 'wb') as f:
            f.write(key.private_bytes(
            encoding=serialization.Encoding.PEM,
            format=serialization.PrivateFormat.TraditionalOpenSSL,
            encryption_algorithm=serialization.NoEncryption(),
            ))

        # Create cert
        subject = issuer = x509.Name([
            x509.NameAttribute(NameOID.COMMON_NAME, hostname),
            x509.NameAttribute(NameOID.COUNTRY_NAME, 'X'),
            x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, 'X'),
            x509.NameAttribute(NameOID.LOCALITY_NAME, 'X'),
            x509.NameAttribute(NameOID.ORGANIZATION_NAME, 'X'),
            x509.NameAttribute(NameOID.ORGANIZATIONAL_UNIT_NAME, 'X'),
            x509.NameAttribute(NameOID.EMAIL_ADDRESS, 'X')
        ])

        # best practice seem to be to include the hostname in the SAN, which *SHOULD* mean COMMON_NAME is ignored.
        alt_names = [x509.DNSName(hostname)]

        # allow addressing by IP, for when you don't have real DNS (common in most testing scenarios)
        if san_list:
            for addr in san_list:
                # openssl wants DNSnames for ips...
                alt_names.append(x509.DNSName(addr))
                # ... whereas golang's crypto/tls is stricter, and needs IPAddresses
                # note: older versions of cryptography do not understand ip_address objects
                alt_names.append(x509.IPAddress(ipaddress.ip_address(addr)))

        san = x509.SubjectAlternativeName(alt_names)

        # path_len=0 means this cert can only sign itself, not other certs.
        basic_contraints = x509.BasicConstraints(ca=True, path_length=0)
        key_usage = x509.KeyUsage(digital_signature=True, key_encipherment=True, key_cert_sign=True,
                                  key_agreement=False, content_commitment=False, data_encipherment=False,
                                  crl_sign=False, encipher_only=False, decipher_only=False)
        extended_key_usage = x509.ExtendedKeyUsage([x509.oid.ExtendedKeyUsageOID.SERVER_AUTH])
        subject_key = x509.SubjectKeyIdentifier(digest=key.public_key())
        authority_key = x509.AuthorityKeyIdentifier(key_identifier=key.public_key(), authority_cert_issuer=None, authority_cert_serial_number=None)**

        cert = x509.CertificateBuilder()\
            .subject_name(subject)\
            .issuer_name(issuer)\
            .public_key(key.public_key())\
            .serial_number(x509.random_serial_number())\
            .not_valid_before(datetime.utcnow())\
            .not_valid_after(datetime.utcnow() + timedelta(days=10 * 365))\
            .add_extension(basic_contraints, False)\
            .add_extension(san, False)\
            .add_extension(key_usage, True)\
            .add_extension(extended_key_usage, False)\
            .sign(key, hashes.SHA256())
        **  .add_extension(subject_key, False)
            .add_extension(authority_key, False)**

        # Write cert to file
        server_cert = self.log_directory + '/server.cert.pem'
        with open(server_cert, 'wb') as f:
            f.write(cert.public_bytes(encoding=serialization.Encoding.PEM))

當我運行它時,我得到一個錯誤——

> File
> "/teams/subhish/pyuniti/projects/sqa/scripts/BSL/TC_31v03_03_01_02_01_ASCG_configuration_and_bring_up.py",
> line 219, in generate_selfsigned_cert
>     x509.CertificateBuilder()   File "/venvs/subhish/lib/python3.8/site-packages/cryptography/x509/base.py",
> line 723, in sign
>     return backend.create_x509_certificate(self, private_key, algorithm)   File
> "/venvs/subhish/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/backend.py",
> line 1035, in create_x509_certificate
>     self._create_x509_extensions(   File "/venvs/subhish/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/backend.py",
> line 1141, in _create_x509_extensions
>     x509_extension = self._create_x509_extension(handlers, extension)   File
> "/venvs/subhish/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/backend.py",
> line 1182, in _create_x509_extension
>     ext_struct = encode(self, extension.value)   File "/venvs/subhish/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/encode_asn1.py",
> line 393, in _encode_subject_key_identifier
>     return _encode_asn1_str_gc(backend, ski.digest)   File "/venvs/subhish/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/encode_asn1.py",
> line 74, in _encode_asn1_str_gc
>     s = _encode_asn1_str(backend, data)   File "/venvs/subhish/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/encode_asn1.py",
> line 54, in _encode_asn1_str
>     res = backend._lib.ASN1_OCTET_STRING_set(s, data, len(data)) TypeError: object of type '_RSAPublicKey' has no len()

文檔是這樣說的——

digest    
Type:   bytes    
The binary value of the identifier. An alias of key_identifier.

但我不知道如何使用 python/密碼生成 key_identifier。 我的理解是,這個值需要根據 RFC5280(4.2.1.2、4.2.1.1)從 private_key 中從 public_key 生成。

最后我想生成一個帶有以下 X509 擴展的證書——

X509v3 extensions:
            X509v3 Subject Key Identifier:
                CA:38:62:01:AA:0D:AA:EC:18:55:E4:A6:93:36:32:F5:97:F2:5F:88
            X509v3 Authority Key Identifier:
                keyid:CA:38:62:01:AA:0D:AA:EC:18:55:E4:A6:93:36:32:F5:97:F2:5F:88
            X509v3 Basic Constraints:
                CA:TRUE, pathlen:0
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment, Certificate Sign
            X509v3 Extended Key Usage:
                TLS Web Server Authentication
            X509v3 Subject Alternative Name:
                DNS:abcd.xyz.net

任何幫助將不勝感激。 謝謝-Subhish

SubjectKeyIdentifier 和 AuthorityKeyIdentifier 在其構造函數中不使用公鑰。 如果你想通過公鑰構造一個典型的標識符,那么你應該使用AuthorityKeyIdentifier.from_issuer_public_keySubjectKeyIdentifier.from_public_key

是的,這行得通。 修改了這樣的行 -

    subject_key = x509.SubjectKeyIdentifier.from_public_key(key.public_key())
    authority_key = x509.AuthorityKeyIdentifier.from_issuer_public_key(key.public_key())

謝謝保羅!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM