Python 密码学 -- 如何在自签名证书中包含 "Subject Key Identifier" 和 "Authority Key Identifier" 的 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/cryptography 生成 key_identifier。据我了解,此值需要根据 private_key.
中的 RFC5280 (4.2.1.2, 4.2.1.1) 从 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 在其构造函数中不使用 public 键。如果你想通过 public 键构造一个典型的标识符,那么你应该使用 AuthorityKeyIdentifier.from_issuer_public_key and SubjectKeyIdentifier.from_public_key.
是的,成功了。
像这样修改行 --
subject_key = x509.SubjectKeyIdentifier.from_public_key(key.public_key())
authority_key = x509.AuthorityKeyIdentifier.from_issuer_public_key(key.public_key())
谢谢保罗!
我正在使用 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/cryptography 生成 key_identifier。据我了解,此值需要根据 private_key.
中的 RFC5280 (4.2.1.2, 4.2.1.1) 从 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 在其构造函数中不使用 public 键。如果你想通过 public 键构造一个典型的标识符,那么你应该使用 AuthorityKeyIdentifier.from_issuer_public_key and SubjectKeyIdentifier.from_public_key.
是的,成功了。 像这样修改行 --
subject_key = x509.SubjectKeyIdentifier.from_public_key(key.public_key())
authority_key = x509.AuthorityKeyIdentifier.from_issuer_public_key(key.public_key())
谢谢保罗!