Python 创建电子证书

这段代码实现了自动生成X509证书和SSL密钥对的功能。通过cryptography库,可以创建自签名证书或使用已有CA证书进行签名。用户可以选择是否创建CA证书,并提供组织名、通用名和国家等信息。生成的私钥和证书以PEM格式保存到文件中。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

import OpenSSL
import os
from cryptography.hazmat.primitives import serialization
import random
from datetime import datetime as dt
from datetime import timedelta
try:
    from cryptography import x509
    from cryptography.x509.oid import NameOID
    from cryptography.hazmat.backends import default_backend
    from cryptography.hazmat.primitives import hashes
    from cryptography.hazmat.primitives.asymmetric import rsa
except ImportError:
    raise TypeError("Using ad-hoc certificates requires the cryptography library.")
def generate_key(public_exponent=100253,key_size=2048):
    pkey = rsa.generate_private_key(
        public_exponent=65537, key_size=2048, backend=default_backend()
    )
    return pkey
def generate_adhoc_ssl_pair(cn=None,pkey=None,
                            sub_user_name='A',sub_common_name='local_host',sub_country_name='cn',
                            isr_user_name='A',isr_common_name='local_host',isr_country_name='cn',
                            sign=None
                            ):
    if pkey == None:
        pkey = rsa.generate_private_key(
            public_exponent=65537, key_size=2048, backend=default_backend()
        )

    # pretty damn sure that this is not actually accepted by anyone
    if cn is None:
        cn = u"*"
    # subject:使用者
    subject = x509.Name(
        [
            x509.NameAttribute(NameOID.ORGANIZATION_NAME, sub_user_name),
            x509.NameAttribute(NameOID.COMMON_NAME, sub_common_name),
            x509.NameAttribute(NameOID.COUNTRY_NAME, sub_country_name)
        ]
    )

    # issuer:颁发者
    issuer = x509.Name(
        [
            x509.NameAttribute(NameOID.ORGANIZATION_NAME, isr_user_name),
            x509.NameAttribute(NameOID.COMMON_NAME, isr_common_name),
            x509.NameAttribute(NameOID.COUNTRY_NAME, isr_country_name),
        ]
    )

    # cert使用私钥签名(.sign(私钥,摘要生成算法,填充方式)),使用x509.CertificateBuilder()方法生成证书,证书属性使用下列函数叠加补充
    if sign == None:
        private_key = pkey
    else:
        private_key = sign
    cert = (
        x509.CertificateBuilder()
            .subject_name(subject)
            .issuer_name(issuer)
            .public_key(pkey.public_key())
            .serial_number(x509.random_serial_number())
            .not_valid_before(dt.utcnow() + timedelta())
            .not_valid_after(dt.utcnow() + timedelta(days=365))
            .sign(private_key, hashes.SHA256(), default_backend())
    )
    # 最终生成的证书与密钥对为类对象,要保存在文件中还需要进一步转换成字节格式
    return cert
if __name__ == '__main__':
    print('创建X509证书')
    print('是否建立CA证书(Y/N)')
    C=input()
    if C =="Y":
        print('开始创建密钥对')
        pkey = generate_key(random.randint(0,10000000),2048)
        print('机构名: ')
        orgName=input()
        print('通用名: ')
        comName=input()
        print('国家: ')
        countryName=input()
        cert=generate_adhoc_ssl_pair(cn=None, pkey=pkey,
                                    sub_user_name=orgName, sub_common_name=comName, sub_country_name=countryName,
                                    isr_user_name=orgName, isr_common_name=comName, isr_country_name=countryName
                                    )
        private_text = pkey.private_bytes(
            encoding=serialization.Encoding.PEM,
            format=serialization.PrivateFormat.TraditionalOpenSSL,
            encryption_algorithm=serialization.NoEncryption()
        )
        print(private_text)

        # 将私钥字节串保存到文件中
        with open(orgName+'_signed_pkey.key', mode='wb') as pkey_file:
            pkey_file.write(private_text)

        cert_text = cert.public_bytes(serialization.Encoding.PEM)
        print(cert_text)
        # 将证书字节串保存到文件中
        with open(orgName+'_signed.cer', mode='wb') as cert_file:
            cert_file.write(cert_text)
    if C == "N":
        print('请输入颁发机构:')
        lsr=input()
        if not os.path.exists(lsr+'_signed.cer') or not os.path.exists(lsr+'_signed_pkey.key'):
            print('未发现颁发者')
        else:
            print('载入CA证书')
            with open(lsr+'_signed.cer', mode='r') as cert_file:
                isr_cert_text=cert_file.read()
            #print(cert_text)
            isr_cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
                                                   isr_cert_text)
            isr_certIssue = isr_cert.get_issuer()

            for item in isr_certIssue.get_components():
                if item[0].decode("utf-8") == 'O':
                    lsr_org_name = item[1].decode("utf-8")
                elif item[0].decode("utf-8") == 'CN':
                    lsr_common_name = item[1].decode("utf-8")
                elif item[0].decode("utf-8") == 'C':
                    lsr_country_name = item[1].decode("utf-8")
            print('开始创建密钥对')
            pkey = generate_key(random.randint(0, 10000000), 2048)
            print('机构名: ')
            orgName = input()
            print('通用名: ')
            comName = input()
            print('国家: ')
            countryName = input()

            with open(lsr+'_signed_pkey.key', 'r') as f:
                lsr_private_key_text = f.read()
            lsr_private_key = OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM,
                                                     lsr_private_key_text)
            lsr_private_key = lsr_private_key.to_cryptography_key()
            cert = generate_adhoc_ssl_pair(cn=None, pkey=pkey,
                                       sub_user_name=orgName, sub_common_name=comName, sub_country_name=countryName,
                                       isr_user_name=lsr_org_name, isr_common_name=lsr_common_name, isr_country_name=lsr_country_name,
                                        sign=lsr_private_key
                                       )
            private_text = pkey.private_bytes(
                encoding=serialization.Encoding.PEM,
                format=serialization.PrivateFormat.TraditionalOpenSSL,
                encryption_algorithm=serialization.NoEncryption()
            )
            print(private_text)

            # 将私钥字节串保存到文件中
            with open(orgName + '_signed_pkey.key', mode='wb') as pkey_file:
                pkey_file.write(private_text)

            cert_text = cert.public_bytes(serialization.Encoding.PEM)
            print(cert_text)
            # 将证书字节串保存到文件中
            with open(orgName + '_signed.cer', mode='wb') as cert_file:
                cert_file.write(cert_text)
最简单的方法,直接用java里的keytool工具生成一个keystore文件,然后直接用这个文件启用https就可以了。 方法如下: 命令行执行%JAVA_HOME%\bin\keytool -genkey -alias tomcat -keyalg RSA 执行过程中会询问你一些信息,比如国家代码,省市等,其中需要填写两个密码,一次在开头,一次在最后,请保持两个密码相同。比如,我将密码都设成s3cret。 如果不同,启动会报错,大概是下面这样的 java.io.IOException: Cannot recover key 执行完成后会生成一个.keystore文件,将它复制到tomcat的bin目录下(并不一定,放哪里都可以) 打开conf目录下的server.xml文件,找到以下这一段 它被注释掉了,将注释去掉,并将这一段改成以下 maxThreads="150" scheme="https" secure="true" keystoreFile="bin/.keystore" keystorePass=" s3cret" clientAuth="false" sslProtocol="TLS" /> 之后启动tomcat就可以了,通过https方式访问8443端口,就能看到效果。如果用http访问之前的端口,那么还是普通的未加密连接。 到这里问题来了,我的目的是启用https,但现在http还能访问,那么就可以绕开https。https也就起不了什么作用了。因此要强制访问https。 打开你的web应用的web.xml文件,在最后加上这样一段 Protected Context /* CONFIDENTIAL 重启tomcat,现在你放问原来的地址,假设是http://localhost:8080/mywebapp/,可以看到,连接被重定向到了https的连接 https://localhost:8443/mywebapp/。这样,我们的目的达到了。 但似乎还有点小问题,keystorePass="s3cret",这个密码直接被明码方式卸载server.xml里。总觉得有还是有点不爽。 那么还有一种稍微复杂点的方式,我们使用openssl。 首先,需要下载openssl,为了方便,可以下载一个绿色版, 加压后除了openssl.exe以外,还有一个bat文件,这个可以帮助我们快速创建证书申请文件。 运行autocsr.bat,按照提示输入信息,之后按任意键确认。你会得到两个文件,一个server.key,这是私钥文件,还有一个名为certreq.csr的证书请求文件。 如果你要向证书颁发机构申请正式的安全证书,那么就把这个certreq.csr文件发给他们就行了。他们会给你发来两个cer文件,一个是服务器证书,一个是根证书 如果你只是要使用https,那么证书自己签署就可以了。 在命令行下进入刚才解压的目录,找到openssl.exe所在的目录,执行以下命令 openssl x509 -req -in certreq.csr -out cert.cer -signkey server.key -days 3650 现在你将得到一个名为cert.cer的证书文件。 修改server.xml将 maxThreads="150" scheme="https" secure="true" keystoreFile="bin/.keystore" keystorePass=" s3cret" clientAuth="false" sslProtocol="TLS" /> 修改为以下内容(假设cert.cer和server.key文件都放在tomcat的conf目录下) maxThreads="150" scheme="https" secure="true" SSLCertificateFile="conf/cert.cer" SSLCertificateKeyFile="conf/server.key" sslProtocol="TLS" /> PS.如果真的向证书颁发机构申请到了正式的安全证书,那么配置还有点不同,如下 maxThreads="150" scheme="https" secure="true" SSLCertificateFile="conf/server.cer" SSLCertificateKeyFile="conf/server.key" SSLCertificateChainFile="conf/intermediate.cer" sslProtocol="TLS" /> 因为证书颁发机构会给两个整数,一个是签署后的服务器证书,还有一个中级CA证书,所以要多一行配置。 可能证书颁发机构只会给你服务器证书也就是server.cer, 中级的CA证书即 intermediate.cer 需要到 证书颁发机构提供的网站中去下载,具体的操作会为证书颁发机构给发的邮箱中会有相关的提示 好了,到这里都配置完了,重启tomcat,就可以看到效果。不过,看到的通常会是一个exception,大概是说APR not available 如果遇到这个异常,说明你的tomcat没有安装apr支持 apr安装详见:http://www.blogjava.net/yongboy/archive/2009/08/31/293343.html 之后启动tomcat,问题应该解决了,看起来效果和第一种方式没什么不同。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值