CA系统的设计(CA证书生成,吊销,数字签名生成)
CA系统概述
CA认证系统是一种基于公钥密码基础设施(PKI)的信息安全技术,它可以为网络通信双方提供身份认证、数据加密、数字签名等功能。CA认证系统的核心是证书授权机构(CA),它负责为用户(节点)颁发数字证书,证明其身份和公钥的合法性。数字证书是一种包含用户信息和公钥的电子文件,它由CA用私钥签名,可以被其他用户或系统验证。数字证书的有效性由证书吊销列表(CRL)或在线证书状态协议(OCSP)来维护。
服务端(CA证书中心)功能:
1.接受CSR文件申请(申请CA证书的请求)
2.签发CSR文件形成数字证书
3.撤销CA数字证书文件
4.查看CA证书文件
5.CA客户端用户信息增删改查
CA客户端功能:
1.门限密钥的生成与分发
2.生成CSR文件、发送CA证书申请
3.CA证书验证等功能
4.CA证书吊销申请
5.数字签名生成
证书的生成
1.密钥生成
使用RSA模块生成密钥对
#生成密钥函数
def generate_cakey(keysize):# 生成 CA 密钥对private_key = rsa.generate_private_key(public_exponent=65537,key_size=keysize,backend=default_backend())ca_private_key = private_key.private_bytes(encoding=Encoding.PEM,format=PrivateFormat.PKCS8,encryption_algorithm=NoEncryption())ca_public_key = private_key.public_key().public_bytes(encoding=Encoding.PEM,format=serialization.PublicFormat.SubjectPublicKeyInfo)print("生成密钥成功")return private_key,ca_private_key,ca_public_key
密钥对的保存和读取
密钥对需要保存为pem格式以便于后续的使用,密钥对的读取也是从pem格式的密钥读取密钥信息
def save_key(ca_private_key,ca_public_key):# 将私钥保存到文件with open('ca_private_key_4.pem', 'wb') as f:f.write(ca_private_key)# 将公钥保存到文件with open('ca_public_key_4.pem', 'wb') as f:f.write(ca_public_key)# 打印保存的密钥对文件名print("key saved successfully -------------------------------")def load_key(key_path):with open(key_path, 'rb') as f:ca_key = f.read()return ca_key
2.数字证书的签发
因为是数字证书系统,服务端先要生成CA根证书,后签发中间证书给客户端,所以需要生成2组RSA密钥对,即用户公私钥,服务端公私钥,进行一个证书的发放。
def generate_ca_certificate(name,province,country,user_private_key_pem, ca_private_key_pem, deadline):#加载CA服务端密钥ca_private_key = serialization.load_pem_private_key(ca_private_key_pem, password=None, backend=default_backend())#加载用户密钥user_private_key = serialization.load_pem_private_key(user_private_key_pem, password=None,backend=default_backend())#生成CA服务端证书root_subject = x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, 'CN'),x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, 'Guangxi'),x509.NameAttribute(NameOID.LOCALITY_NAME, 'Guangxi'),x509.NameAttribute(NameOID.ORGANIZATION_NAME, 'CA'),x509.NameAttribute(NameOID.COMMON_NAME, 'CA'),])root_issuer = root_subject #颁发者和主题一样before_now = datetime.datetime.utcnow()if deadline <= before_now:raise ValueError("Deadline must be in the future.")serial_number = x509.random_serial_number()# 根证书root_certificate = (x509.CertificateBuilder().subject_name(root_subject).issuer_name(root_issuer).public_key(ca_private_key.public_key()).serial_number(serial_number).not_valid_before(before_now).not_valid_after(deadline).add_extension(x509.BasicConstraints(ca=True, path_length=None), critical=True).sign(ca_private_key, hashes.SHA256(), default_backend()))#生成中间证书intermediate_subject = x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME,country),x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME,province),x509.NameAttribute(NameOID.LOCALITY_NAME,province),x509.NameAttribute(NameOID.ORGANIZATION_NAME,name),x509.NameAttribute(NameOID.COMMON_NAME,name),])intermediate_issuer = root_subjectintermediate_certificate = (x509.CertificateBuilder().subject_name(intermediate_subject).issuer_name(intermediate_issuer).public_key(user_private_key.public_key()).serial_number(x509.random_serial_number()).not_valid_before(before_now).not_valid_after(deadline).add_extension(x509.BasicConstraints(ca=True, path_length=None), critical=True).sign(ca_private_key, hashes.SHA256(), default_backend()))# 转换为 PEM 格式root_cert_pem = root_certificate.public_bytes(serialization.Encoding.PEM)intermediate_cert_pem = intermediate_certificate.public_bytes(serialization.Encoding.PEM)# 私钥导出user_private_key_pem = user_private_key.private_bytes(encoding=serialization.Encoding.PEM,format=serialization.PrivateFormat.TraditionalOpenSSL,encryption_algorithm=serialization.NoEncryption())ca_private_key_pem = ca_private_key.private_bytes(encoding=serialization.Encoding.PEM,format=serialization.PrivateFormat.TraditionalOpenSSL,encryption_algorithm=serialization.NoEncryption())# 证书链(根证书 + 中间证书)cert_chain_pem = root_cert_pem + intermediate_cert_pemprint("证书链----------------------------------------------------")print(cert_chain_pem)print("cert_chain_pem",cert_chain_pem)print("Intermediate_CA", intermediate_certificate)return intermediate_certificate
3.数字签名生成
可以利用用户私钥生成数字签名,后使用服务端签发的证书对数字签名进行一个验证。
def sign_data(data, private_key):# 加载私钥loaded_private_key = serialization.load_pem_private_key(private_key,password=None,backend=default_backend())# 计算数据的哈希值digest = hashes.Hash(hashes.SHA256(), backend=default_backend())#data = b'some bytes data'if isinstance(data, str):digest.update(data.encode())#digest.update(data.encode())hashed_data = digest.finalize()# 使用私钥对哈希值进行签名signature = loaded_private_key.sign(hashed_data,padding.PKCS1v15(),hashes.SHA256())return signature
4.数字证书验证数字签名的有效性
这里利用证书的公钥验证之前生成的数字签名的有效性。只是验证证书公钥有效性,未判断证书有无被吊销情况。
import datetime
from cryptography import x509
from cryptography.x509.oid import NameOID
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives.serialization import Encoding, PrivateFormat, NoEncryption
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives.serialization import load_pem_private_key
from OpenSSL import crypto
import OpenSSL.crypto
import os
import base64
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization#生成密钥函数
def generate_cakey(keysize):# 生成 CA 密钥对private_key = rsa.generate_private_key(public_exponent=65537,key_size=keysize,backend=default_backend())ca_private_key = private_key.private_bytes(encoding=Encoding.PEM,format=PrivateFormat.PKCS8,encryption_algorithm=NoEncryption())ca_public_key = private_key.public_key().public_bytes(encoding=Encoding.PEM,format=serialization.PublicFormat.SubjectPublicKeyInfo)print("生成密钥成功")return private_key,ca_private_key,ca_public_keydef load_key(key_path):with open(key_path, 'rb') as f:ca_key = f.read()return ca_keydef save_key(ca_private_key, ca_public_key):# 将私钥保存到文件with open('ca_private_key.pem', 'wb') as f:f.write(ca_private_key)# 将公钥保存到文件with open('ca_public_key.pem', 'wb') as f:f.write(ca_public_key)# 打印保存的密钥对文件名print("CA-key saved successfully -------------------------------")def save_key2(ca_private_key, ca_public_key):# 将私钥保存到文件with open('usr_private_key.pem', 'wb') as f:f.write(ca_private_key)# 将公钥保存到文件with open('usr_public_key.pem', 'wb') as f:f.write(ca_public_key)# 打印保存的密钥对文件名print("USER-key saved successfully -------------------------------")def generate_ca_certificate(name, province, country, user_private_key_pem, ca_private_key_pem, deadline):# 加载CA服务端密钥ca_private_key = serialization.load_pem_private_key(ca_private_key_pem, password=None, backend=default_backend())# 加载用户密钥user_private_key = serialization.load_pem_private_key(user_private_key_pem, password=None,backend=default_backend())# 生成CA服务端证书root_subject = x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, 'CN'),x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, 'Guangxi'),x509.NameAttribute(NameOID.LOCALITY_NAME, 'Guangxi'),x509.NameAttribute(NameOID.ORGANIZATION_NAME, 'CA'),x509.NameAttribute(NameOID.COMMON_NAME, 'CA'),])root_issuer = root_subject # 颁发者和主题一样before_now = datetime.datetime.utcnow()if deadline <= before_now:raise ValueError("Deadline must be in the future.")serial_number = x509.random_serial_number()# 根证书root_certificate = (x509.CertificateBuilder().subject_name(root_subject).issuer_name(root_issuer).public_key(ca_private_key.public_key()).serial_number(serial_number).not_valid_before(before_now).not_valid_after(deadline).add_extension(x509.BasicConstraints(ca=True, path_length=None), critical=True).sign(ca_private_key, hashes.SHA256(), default_backend()))# 生成中间证书intermediate_subject = x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, country),x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, province),x509.NameAttribute(NameOID.LOCALITY_NAME, province),x509.NameAttribute(NameOID.ORGANIZATION_NAME, name),x509.NameAttribute(NameOID.COMMON_NAME, name),])intermediate_issuer = root_subjectintermediate_certificate = (x509.CertificateBuilder().subject_name(intermediate_subject).issuer_name(intermediate_issuer).public_key(user_private_key.public_key()).serial_number(x509.random_serial_number()).not_valid_before(before_now).not_valid_after(deadline).add_extension(x509.BasicConstraints(ca=True, path_length=None), critical=True).sign(ca_private_key, hashes.SHA256(), default_backend()))# 转换为 PEM 格式root_cert_pem = root_certificate.public_bytes(serialization.Encoding.PEM)intermediate_cert_pem = intermediate_certificate.public_bytes(serialization.Encoding.PEM)# 私钥导出user_private_key_pem = user_private_key.private_bytes(encoding=serialization.Encoding.PEM,format=serialization.PrivateFormat.TraditionalOpenSSL,encryption_algorithm=serialization.NoEncryption())ca_private_key_pem = ca_private_key.private_bytes(encoding=serialization.Encoding.PEM,format=serialization.PrivateFormat.TraditionalOpenSSL,encryption_algorithm=serialization.NoEncryption())# 证书链(根证书 + 中间证书)cert_chain_pem = root_cert_pem + intermediate_cert_pemprint("证书链----------------------------------------------------")print(cert_chain_pem)print("cert_chain_pem", cert_chain_pem)print("Intermediate_CA", intermediate_certificate)return intermediate_certificate
#保存证书
def save_certificate_to_file(certificate, filename):with open(filename, "wb") as file:file.write(certificate)def sign_data(data, private_key):# 加载私钥loaded_private_key = serialization.load_pem_private_key(private_key,password=None,backend=default_backend())# 计算数据的哈希值digest = hashes.Hash(hashes.SHA256(), backend=default_backend())#data = b'some bytes data'if isinstance(data, str):digest.update(data.encode())#digest.update(data.encode())hashed_data = digest.finalize()# 使用私钥对哈希值进行签名signature = loaded_private_key.sign(hashed_data,padding.PKCS1v15(),hashes.SHA256())return signaturedef verify_signature(data, signature, certificate):# 加载证书loaded_certificate = x509.load_pem_x509_certificate(certificate,default_backend())# 提取公钥public_key = loaded_certificate.public_key()# 计算数据的哈希值digest = hashes.Hash(hashes.SHA256(), backend=default_backend())hashed_data = digest.finalize()try:# 使用公钥验证签名public_key.verify(signature,hashed_data,padding.PKCS1v15(),hashes.SHA256())print("签名验证成功")return Trueexcept Exception:print("签名验证失败")return Falseif __name__ == "__main__":keysize = 2048 # 密钥长度time0 = "2026-1-1"time1 = "00:00:00"date_string = time0 + " " + time1format_string = '%Y-%m-%d %H:%M:%S' # 把时间转换为标准时间datetime_obj = datetime.datetime.strptime(date_string, format_string)print('datetime_obj', datetime_obj)# 生成服务端公私钥private_key, ca_private_key, ca_public_key = generate_cakey(keysize)# 生成用户端公私钥private_key2, usr_private_key2, usr_public_key2 = generate_cakey(keysize)# 保存密钥为pem格式save_key(ca_private_key,ca_public_key)save_key2(usr_private_key2,usr_public_key2)ca_private_key_path = 'ca_private_key.pem' # 密钥文件的路径ca_public_key_path = 'ca_public_key.pem'#加载密钥文件ca_private_key = load_key(ca_private_key_path)ca_public_key = load_key(ca_public_key_path)#先保存再打开看似有点奇怪,利于后面写系统usr_private_key_path = 'usr_private_key.pem'usr_public_key_path = 'usr_public_key.pem'user_private_key = load_key(usr_private_key_path)user_public_key = load_key(usr_public_key_path)# 打印密钥内容print("ca_private_key", ca_private_key)print("ca_public_key", ca_public_key)print("user_private_key", user_private_key)print("user_public_key", user_public_key)# 生成 CA 证书name = 'xiaoxi'province = "Guangxi"country = "CN"ca_certificate = generate_ca_certificate(name, province, country, user_private_key,ca_private_key, datetime_obj)print("ca_certificate", ca_certificate)ca_certificate_bytes = ca_certificate.public_bytes(encoding=serialization.Encoding.PEM)script_dir = os.path.dirname(os.path.abspath(__file__))# 构建保存证书的文件夹路径ca_folder = os.path.join(script_dir, 'my_ca')os.makedirs(ca_folder, exist_ok=True)ca_path = os.path.join(ca_folder, "ca_certificate.crt")save_certificate_to_file(ca_certificate_bytes, ca_path)#数字签名data文件data = b'hello'signature = sign_data(data, user_private_key)# 使用签发的证书对数字签名进行验证is_valid = verify_signature(data, signature, ca_certificate_bytes)
算法运行截图
生成的证书
完整算法代码
import datetime
from cryptography import x509
from cryptography.x509.oid import NameOID
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives.serialization import Encoding, PrivateFormat, NoEncryption
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives.serialization import load_pem_private_key
from OpenSSL import crypto
import OpenSSL.crypto
import os
import base64
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization#生成密钥函数
def generate_cakey(keysize):# 生成 CA 密钥对private_key = rsa.generate_private_key(public_exponent=65537,key_size=keysize,backend=default_backend())ca_private_key = private_key.private_bytes(encoding=Encoding.PEM,format=PrivateFormat.PKCS8,encryption_algorithm=NoEncryption())ca_public_key = private_key.public_key().public_bytes(encoding=Encoding.PEM,format=serialization.PublicFormat.SubjectPublicKeyInfo)print("生成密钥成功")return private_key,ca_private_key,ca_public_keydef load_key(key_path):with open(key_path, 'rb') as f:ca_key = f.read()return ca_keydef save_key(ca_private_key, ca_public_key):# 将私钥保存到文件with open('ca_private_key.pem', 'wb') as f:f.write(ca_private_key)# 将公钥保存到文件with open('ca_public_key.pem', 'wb') as f:f.write(ca_public_key)# 打印保存的密钥对文件名print("CA-key saved successfully -------------------------------")def save_key2(ca_private_key, ca_public_key):# 将私钥保存到文件with open('usr_private_key.pem', 'wb') as f:f.write(ca_private_key)# 将公钥保存到文件with open('usr_public_key.pem', 'wb') as f:f.write(ca_public_key)# 打印保存的密钥对文件名print("USER-key saved successfully -------------------------------")def generate_ca_certificate(name, province, country, user_private_key_pem, ca_private_key_pem, deadline):# 加载CA服务端密钥ca_private_key = serialization.load_pem_private_key(ca_private_key_pem, password=None, backend=default_backend())# 加载用户密钥user_private_key = serialization.load_pem_private_key(user_private_key_pem, password=None,backend=default_backend())# 生成CA服务端证书root_subject = x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, 'CN'),x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, 'Guangxi'),x509.NameAttribute(NameOID.LOCALITY_NAME, 'Guangxi'),x509.NameAttribute(NameOID.ORGANIZATION_NAME, 'CA'),x509.NameAttribute(NameOID.COMMON_NAME, 'CA'),])root_issuer = root_subject # 颁发者和主题一样before_now = datetime.datetime.utcnow()if deadline <= before_now:raise ValueError("Deadline must be in the future.")serial_number = x509.random_serial_number()# 根证书root_certificate = (x509.CertificateBuilder().subject_name(root_subject).issuer_name(root_issuer).public_key(ca_private_key.public_key()).serial_number(serial_number).not_valid_before(before_now).not_valid_after(deadline).add_extension(x509.BasicConstraints(ca=True, path_length=None), critical=True).sign(ca_private_key, hashes.SHA256(), default_backend()))# 生成中间证书intermediate_subject = x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, country),x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, province),x509.NameAttribute(NameOID.LOCALITY_NAME, province),x509.NameAttribute(NameOID.ORGANIZATION_NAME, name),x509.NameAttribute(NameOID.COMMON_NAME, name),])intermediate_issuer = root_subjectintermediate_certificate = (x509.CertificateBuilder().subject_name(intermediate_subject).issuer_name(intermediate_issuer).public_key(user_private_key.public_key()).serial_number(x509.random_serial_number()).not_valid_before(before_now).not_valid_after(deadline).add_extension(x509.BasicConstraints(ca=True, path_length=None), critical=True).sign(ca_private_key, hashes.SHA256(), default_backend()))# 转换为 PEM 格式root_cert_pem = root_certificate.public_bytes(serialization.Encoding.PEM)intermediate_cert_pem = intermediate_certificate.public_bytes(serialization.Encoding.PEM)# 私钥导出user_private_key_pem = user_private_key.private_bytes(encoding=serialization.Encoding.PEM,format=serialization.PrivateFormat.TraditionalOpenSSL,encryption_algorithm=serialization.NoEncryption())ca_private_key_pem = ca_private_key.private_bytes(encoding=serialization.Encoding.PEM,format=serialization.PrivateFormat.TraditionalOpenSSL,encryption_algorithm=serialization.NoEncryption())# 证书链(根证书 + 中间证书)cert_chain_pem = root_cert_pem + intermediate_cert_pemprint("证书链----------------------------------------------------")print(cert_chain_pem)print("cert_chain_pem", cert_chain_pem)print("Intermediate_CA", intermediate_certificate)return intermediate_certificate
#保存证书
def save_certificate_to_file(certificate, filename):with open(filename, "wb") as file:file.write(certificate)def sign_data(data, private_key):# 加载私钥loaded_private_key = serialization.load_pem_private_key(private_key,password=None,backend=default_backend())# 计算数据的哈希值digest = hashes.Hash(hashes.SHA256(), backend=default_backend())#data = b'some bytes data'if isinstance(data, str):digest.update(data.encode())#digest.update(data.encode())hashed_data = digest.finalize()# 使用私钥对哈希值进行签名signature = loaded_private_key.sign(hashed_data,padding.PKCS1v15(),hashes.SHA256())return signaturedef verify_signature(data, signature, certificate):# 加载证书loaded_certificate = x509.load_pem_x509_certificate(certificate,default_backend())# 提取公钥public_key = loaded_certificate.public_key()# 计算数据的哈希值digest = hashes.Hash(hashes.SHA256(), backend=default_backend())hashed_data = digest.finalize()try:# 使用公钥验证签名public_key.verify(signature,hashed_data,padding.PKCS1v15(),hashes.SHA256())print("签名验证成功")return Trueexcept Exception:print("签名验证失败")return Falseif __name__ == "__main__":keysize = 2048 # 密钥长度time0 = "2026-1-1"time1 = "00:00:00"date_string = time0 + " " + time1format_string = '%Y-%m-%d %H:%M:%S' # 把时间转换为标准时间datetime_obj = datetime.datetime.strptime(date_string, format_string)print('datetime_obj', datetime_obj)# 生成服务端公私钥private_key, ca_private_key, ca_public_key = generate_cakey(keysize)# 生成用户端公私钥private_key2, usr_private_key2, usr_public_key2 = generate_cakey(keysize)# 保存密钥为pem格式save_key(ca_private_key,ca_public_key)save_key2(usr_private_key2,usr_public_key2)ca_private_key_path = 'ca_private_key.pem' # 密钥文件的路径ca_public_key_path = 'ca_public_key.pem'#加载密钥文件ca_private_key = load_key(ca_private_key_path)ca_public_key = load_key(ca_public_key_path)#先保存再打开看似有点奇怪,利于后面写系统usr_private_key_path = 'usr_private_key.pem'usr_public_key_path = 'usr_public_key.pem'user_private_key = load_key(usr_private_key_path)user_public_key = load_key(usr_public_key_path)# 打印密钥内容print("ca_private_key", ca_private_key)print("ca_public_key", ca_public_key)print("user_private_key", user_private_key)print("user_public_key", user_public_key)# 生成 CA 证书name = 'xiaoxi'province = "Guangxi"country = "CN"ca_certificate = generate_ca_certificate(name, province, country, user_private_key,ca_private_key, datetime_obj)print("ca_certificate", ca_certificate)ca_certificate_bytes = ca_certificate.public_bytes(encoding=serialization.Encoding.PEM)script_dir = os.path.dirname(os.path.abspath(__file__))# 构建保存证书的文件夹路径ca_folder = os.path.join(script_dir, 'server_ca')os.makedirs(ca_folder, exist_ok=True)ca_path = os.path.join(ca_folder, "ca_certificate.crt")save_certificate_to_file(ca_certificate_bytes, ca_path)#数字签名data文件data = b'hello'signature = sign_data(data, user_private_key)# 使用签发的证书对数字签名进行验证is_valid = verify_signature(data, signature, ca_certificate_bytes)
证书的吊销
证书的吊销参考这篇文章
证书吊销列表(CRL) - 程翔北 - 博客园
需要生成一个证书吊销列表CRL然后把吊销的证书序列号添加进去。
完整算法代码
import os
from cryptography import x509
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.backends import default_backend
from datetime import datetime, timedeltadef add_certificate_to_crl():crl_file_path = "H:/CA_demo/crl_list.crl"ca_private_key_path = "H:/CA_demo/ca_private_key.pem"# 要吊销的证书序列号target_serial_number = 1234 #会转化为16进制try:if not os.path.exists(crl_file_path):# 构建 CRL 发布者/颁发者名称issuer_name = x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, "CN"),x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, "Guangxi"),x509.NameAttribute(NameOID.LOCALITY_NAME, "Guangxi"),x509.NameAttribute(NameOID.ORGANIZATION_NAME, "CA"),])# 构建 CRL 列表生成器builder = x509.CertificateRevocationListBuilder().issuer_name(x509.Name(issuer_name))# 设置 CRL 的有效期this_update = datetime.utcnow()next_update = this_update + timedelta(days=1)builder = builder.last_update(this_update).next_update(next_update)else:with open(crl_file_path, "rb") as crl_file:crl_data = crl_file.read()# 解析现有的 CRL 数据crl = x509.load_pem_x509_crl(crl_data, default_backend())builder = x509.CertificateRevocationListBuilder().issuer_name(crl.issuer)# 将现有的吊销证书添加到新的 CRL 中for revoked_certificate in crl:builder = builder.add_revoked_certificate(revoked_certificate)# 更新最后更新时间this_update = datetime.utcnow()# 设置下一次更新时间next_update = this_update + timedelta(days=1)builder = builder.last_update(this_update).next_update(next_update)# 创建新的吊销证书now = datetime.utcnow()revoked_certificate = x509.RevokedCertificateBuilder().serial_number(target_serial_number).revocation_date(now).build()builder = builder.add_revoked_certificate(revoked_certificate)# 使用 CA 私钥对 CRL 进行签名with open(ca_private_key_path, 'rb') as key_file:private_key = serialization.load_pem_private_key(key_file.read(),password=None,backend=default_backend())crl = builder.sign(private_key=private_key,algorithm=hashes.SHA256(),backend=default_backend())# 将更新后的 CRL 列表保存到文件with open(crl_file_path, "wb") as crl_file:crl_file.write(crl.public_bytes(serialization.Encoding.PEM))print(f"证书序列号 {target_serial_number} 已添加到 CRL 中。")except Exception as e:print(f"发生错误: {e}")if __name__ == "__main__":add_certificate_to_crl()
算法运行截图
CRL文件里面有新的吊销的序列号和日期,此处为了简化演示才输入1234,正常情况是要需要吊销证书的真实序列号。
系统测试
客户端界面
服务端界面
相关文章:
CA系统的设计(CA证书生成,吊销,数字签名生成)
CA系统概述 CA认证系统是一种基于公钥密码基础设施(PKI)的信息安全技术,它可以为网络通信双方提供身份认证、数据加密、数字签名等功能。CA认证系统的核心是证书授权机构(CA),它负责为用户(节点…...
流计算需要框架吗?SPL 可能是更好的选择
流数据源通常是动态、无界的,看起来与静态、有限的批数据源区别较大,传统的数据库技术在架构上难以直接处理流数据源,只能让位于后来者。heron\samza\storm\spark\flink等计算框架最先完成突破,在流计算技术中占得先发优势。这些框…...
Vue-Router之嵌套路由
在路由配置中,配置children import Vue from vue import VueRouter from vue-routerVue.use(VueRouter)const router new VueRouter({mode: history,base: import.meta.env.BASE_URL,routes: [{path: /,redirect: /home},{path: /home,name: home,component: () &…...
MySQL 读写分离
MySQL 读写分离 一、配置主库(Master) 1.修改主库的配置文件 修改主库的 my.cnf 配置文件,生成二进制日志 (binary log) 和服务器唯一ID,这是实现主从复制的必要配置 [mysqld] # skip-grant-tables userroot port3306 basedir/usr/local/mysql datad…...
记一次音频无输出的解决方案
啊啊啊,刷个抖音就发现个死电脑死都不出声,捣鼓了一天才解决 打开wav文件时,提示错误找不到音频播放设备 0xc00d36fa 起初以为是声卡坏了,就到官网下载、更新了声卡驱动。无用什么驱动精灵也检测了,但也测不出啥来。…...
3D数学基础2
矩阵的行列式 在任意方阵中都存在至少一个标量,称作该方阵的行列式。在线性代数中,行列式有很多有用的性质 线性运算法则 方阵 M M M的行列式记作 ∣ M ∣ |M| ∣M∣或“det M”。非方阵矩阵的行列式是未定义的。 注意,在书写行列式时&…...
Java开发生态2024年度总结报告
1 关键要点 尽管数据显示 Java 17 是最常用 JDK,但其用户占比并未超过半数。根据 New Relic 2024 Java 生态系统状态报告,Java 17、11 和 8 的用户比例分别为 35%、33% 和 29%。New Relic 数据中所谓“快速采用”指 Java 21 的采用率仅为 1.4%。虽相较 J…...
1月第三讲:Java子线程无法获取Attributes的解决方法
在Java多线程编程中,开发者经常会遇到子线程无法获取主线程设置的Attributes的问题。Attributes通常用于存储与当前线程相关的数据,尤其在Web应用中,它们常用于请求上下文的管理。然而,由于Java线程是独立运行的,每个线…...
更新金碟云星空单据供应商和币别
--应付单 select FSUPPLIERID from [dbo].[T_AP_PAYABLE] where FBILLNO=AP2024121670 select FSUPPLIERID,FCURRENCYID,* from [dbo].[T_AP_PAYABLE] where FBILLNO=AP2024121670 -- update T_AP_PAYABLE set FSUPPLIERID=100567 where FBILLNO=AP2024121670 -- update T_…...
from memory cache 修复记录
背景 浏览器的页签图标,不想要了 改代码:设置浏览器页签的代码 本地环境测试,没有问题,一次性修改成功 于是打包,部署到测试环境,然而,还是有 接下的解决方法: 1、清除浏览器缓…...
spring入门程序
安装eclipse https://blog.csdn.net/qq_36437991/article/details/131644570 新建maven项目 安装依赖包 pom.xml <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation&quo…...
用于实现无缝滚动效果的vue-seamless-scroll插件
它通常用于在网页或应用中实现内容的自动滚动效果,如新闻公告、图片轮播等,支持横向和纵向滚动,并且可以自定义滚动速度、方向等参数,适合展示一些需要持续循环展示的信息。 在Vue2项目中使用vue-seamless-scroll插件的步骤如下&…...
借助 FinClip 跨端技术探索鸿蒙原生应用开发之旅
在当今数字化浪潮汹涌澎湃的时代,移动应用开发领域正经历着深刻的变革与创新。鸿蒙操作系统的崛起,以其独特的分布式架构和强大的性能表现,吸引了众多开发者的目光。而FinClip 跨端技术的出现,为开发者涉足鸿蒙原生应用开发提供了…...
【机器学习】机器学习的基本分类-自监督学习-对比学习(Contrastive Learning)
对比学习是一种自监督学习方法,其目标是学习数据的表征(representation),使得在表征空间中,相似的样本距离更近,不相似的样本距离更远。通过设计对比损失函数(Contrastive Loss)&…...
python之eval函数
功能:将字符串str当成有效的表达式来求值并返回计算结果 语法:eval(source,[,globals[,locals]])->value 参数: source:一个python表达式或函数compile()返回的代码对象globals:可选。必须是dictionarylocals&am…...
NXP i.MX8系列平台开发讲解 - 5.3 调试篇(二) - 掌握Dynamic debug调试
专栏文章目录传送门:返回专栏目录 Hi, 我是你们的老朋友,主要专注于嵌入式软件开发,有兴趣不要忘记点击关注【码思途远】 文章目录 目录 掌握Dynamic debug调试 1. 认识Dynamic debug 2. 内核配置 3. 使用Dynamic debug 3.1 查看当前的…...
QT----------常用界面组件的使用
一、QComboBox 类 主要功能:提供一个下拉列表,用户可以从中选择一个或多个选项。 #include <QApplication> #include <QComboBox> #include <QVBoxLayout> #include <QWidget> #include <QMessageBox>int main(int argc…...
重新整理机器学习和神经网络框架
本篇重新梳理了人工智能(AI)、机器学习(ML)、神经网络(NN)和深度学习(DL)之间存在一定的包含关系,以下是它们的关系及各自内容,以及人工智能领域中深度学习分支对比整理。…...
AJAX详解
AJAX是前后端交互的重要工具 结合前后端交互基础理解:前后端交互详解(建议收藏)-CSDN博客 1. AJAX - 到底什么是Ajax? ajax 全名 async javascript and XML(异步JavaScript和XML),是一种用于向服务器异步发送 HTTP 请求并接收响应的技术。 XML 指可扩…...
golang中的异常处理机制
今天是2024最后一天,祝大家新年梦想成真,继续我的魅力golang,昨天发的错误处理,是明显的可预见、可恢复的问题,然而,不可预见的问题,往往更多,golang也有自己的一套,完全…...
HTML5 开关(Toggle Switch)详细讲解
HTML5 开关(Toggle Switch)详细讲解 1. 任务概述 开关(Toggle Switch)是一种用于表示二元状态(如开/关)的用户界面控件。用户可以通过点击开关来切换状态,常见于设置选项、开关功能等场景。 2…...
【前端】Node.js使用教程
目录 一、?Node.js开发环境和编译 1.1 安装Node.js 1.2 创建一个Node.js项目 1.3 编写Node.js程序 1.4 运行Node.js程序 1.5 使用Node.js模块 二、高级的Node.js编程概念和示例 2.1 异步编程 2.2 错误处理 2.3 网络请求 2.4 构建Web服务器 2.5 数据库交互 三、No…...
在CodeBlocks搭建SDL2工程构建TFT彩屏模拟器虚拟TFT彩屏幕显示
在CodeBlocks搭建SDL2工程构建TFT彩屏模拟器虚拟TFT彩屏幕显示 参考文章源码下载地址一、SDL2的创建、初始化、退出二、系统基本Tick、彩屏刷新、按键事件三、彩屏获取与设置颜色四、彩屏填充颜色及清屏五、彩屏显示中文和英文字符串六、彩屏显示数字七、彩屏初始化八、主函数测…...
BurstAttention:高效的分布式注意力计算框架
BurstAttention:高效的分布式注意力计算框架 在现代大型语言模型(LLMs)的应用中,提升注意力机制的计算效率已成为研究的热点。当前,提升计算效率主要有两种方法:一种是优化单设备的计算和存储能力…...
sentinel集成nacos启动报[check-update] get changed dataId error, code: 403错误排查及解决
整合nacos报403错误 因为平台写的一个限流代码逻辑有问题,所以准备使用sentinel来限流。平台依赖里面已经引入了,之前也测试过,把sentinel关于nacos的配置加上后,启动一直输出403错误 [fixed-10.0.20.188_8848-test] [check-upda…...
[TOTP]android kotlin实现 totp身份验证器 类似Google身份验证器
背景:自己或者公司用一些谷歌身份验证器或者microsoft身份验证器,下载来源不明,或者有广告,使用不安全。于是自己写一个,安全放心使用。 代码已开源:shixiaotian/sxt-android-totp: android totp authenti…...
IDEA+Docker一键部署项目SpringBoot项目
文章目录 1. 部署项目的传统方式2. 前置工作3. SSH配置4. 连接Docker守护进程5. 创建简单的SpringBoot应用程序6. 编写Dockerfile文件7. 配置远程部署 7.1 创建配置7.2 绑定端口7.3 添加执行前要运行的任务 8. 部署项目9. 开放防火墙的 11020 端口10. 访问项目11. 可能遇到的问…...
【发票提取明细+发票号改名】批量提取PDF电子发票明细导出Excel表格并改名技术难点,批量PDF多区域内容识别提取明细并用内容改名的小结
1、图片版的发票提取表格改名 【批量图片发票识别表格】批量图片发票的提取Excel表格和提取字段改名,扫描发票识别表格,拍照发票识别表格,图片发票识别改名我们在工作中很多扫描发票,拍照发票,需要整理成excel表格&am…...
pyQT + OpenCV相关练习
一、设计思路 1、思路分析与设计 本段代码是一个使用 PyQt6 和 OpenCV 创建的图像处理应用程序。其主要功能是通过一个图形界面让用户对图片进行基本的图像处理操作,如灰度化、翻转、旋转、亮度与对比度调整,以及一些滤镜效果(模糊、锐化、边…...
石岩路边理发好去处
周末带娃去罗租公园玩,罗租公园旁边就是百佳华和如意豪庭小区,发现如意豪庭小区对面挺多路边理发摊点 理发摊点聚焦在这里的原因是刚好前面城管来了暂时避避,例如还有一个阿姨剪到一半就跟着过来。这里的城管只是拍了一处没有摊位的地方&…...
音视频入门基础:MPEG2-PS专题(2)——使用FFmpeg命令生成ps文件
一、错误的命令 通过FFmpeg命令可以将mp4文件转换为ps文件,PS文件中包含PS流数据。 由于PS流/PS文件对应的FFInputFormat结构为: const FFInputFormat ff_mpegps_demuxer {.p.name "mpeg",.p.long_name NULL_IF_CONFIG_SMALL…...
整合版canal ha搭建--基于1.1.4版本
开启MySql Binlog(1)修改MySql配置文件(2)重启MySql服务,查看配置是否生效(3)配置起效果后,创建canal用户,并赋予权限安装canal-admin(1)解压 canal.admin-1…...
[python SQLAlchemy数据库操作入门]-15.联合查询,跨表获取股票数据
哈喽,大家好,我是木头左! 在开始探讨如何利用SQLAlchemy实现复杂的联合查询之前,首先需要深入理解其核心组件——对象关系映射(ORM)。ORM允许开发者使用Python类来表示数据库中的表,从而以一种更直观、面向对象的方式来操作数据库。 SQLAlchemy中的JOIN操作详解 在SQLA…...
PTA数据结构作业一
6-1 链表的插入算法 本题要求实现一个插入函数,实现在链表llist中的元素x之后插入一个元素y的操作。 函数接口定义: int InsertPost_link(LinkList llist, DataType x, DataType y); 其中 llist是操作的链表,x是待插入元素y的前驱节点元素…...
前端(九)js介绍(2)
js介绍(2) 文章目录 js介绍(2)一、函数1.1函数的两种形式1.2函数的作用域1.3声明与提升 二、bom操作三、dom操作 一、函数 1.1函数的两种形式 //有参函数 //js中的函数只能返回一个值,如果要返回多个需要放在数组或对象中 function func(a,b){return ab } func(1,…...
CUTLASS:高性能 CUDA 线性代数模板库详解
CUTLASS:高性能 CUDA 线性代数模板库详解 引言什么是 CUTLASS?CUTLASS 的主要特点: CUTLASS 的用途如何安装 CUTLASS1. 环境准备2. 下载 CUTLASS3. 构建 CUTLASS4. 设置环境变量5. 验证安装 使用 CUTLASSCUTLASS 的优势总结 引言 在深度学习…...
关于CISP报名费用详情
CISP即“注册信息安全专业人员”,是中国信息安全测评中心实施的国家认证项目,旨在培养信息安全领域的专业人才。对于有意报考CISP的考生而言,了解报名考试费用是备考过程中不可或缺的一环。 CISP的报名考试费用主要包括培训费用、考试费用、…...
css 关于flex布局中子元素的属性flex
css flex布局中子元素的属性flex 1. flex 是 flex-grow、flex-shrink 和 flex-basis 的简写 语法格式: flex: [flex-grow] [flex-shrink] [flex-basis];各属性解析: flex-grow: 子元素如何按比例分配父元素的 剩余空间。 默认值:0&#…...
功率器件热设计基础(四)——功率半导体芯片温度和测试方法
/ 前言 / 功率半导体热设计是实现IGBT、碳化硅SiC高功率密度的基础,只有掌握功率半导体的热设计基础知识,才能完成精确热设计,提高功率器件的利用率,降低系统成本,并保证系统的可靠性。 功率器件热设计基础系列文章会…...
OpenStack系列第四篇:云平台基础功能与操作(Dashboard)
文章目录 1. 镜像(Image)添加镜像查看镜像删除镜像 2. 卷(Volume)创建卷查看卷删除卷 3. 网络(虚拟网络)创建网络查看网络删除网络 4. 实例类型创建实例类型查看实例类型删除实例类型 4. 密钥对(…...
WebSocket封装
提示:记录工作中遇到的需求及解决办法 文章目录 前言二、背景三、WebSocket3.1 什么是 WebSocket ?为什么使用他?四、封装 WebSocket4.1 Javascript 版本4.2 Typescript 版本4.3 如何使用?五、我的痛点如何处理前言 本文将介绍 WebSocket 的封装,比如:心跳机制,重连和一…...
面试题解,JVM的运行时数据区
一、请简述JVM运行时数据区的组成结构及各部分作用 总览 从线程持有的权限来看 线程私有区 虚拟机栈 虚拟机栈是一个栈结构,由许多个栈帧组成,一个方法分配一个栈帧,线程每执行一个方法时都会有一个栈帧入栈,方法执行结束后栈帧…...
【Ubuntu使用技巧】Ubuntu22.04无人值守Crontab工具实战详解
一个愿意伫立在巨人肩膀上的农民...... Crontab是Linux和类Unix操作系统下的一个任务调度工具,用于周期性地执行指定的任务或命令。Crontab允许用户创建和管理计划任务,以便在特定的时间间隔或时间点自动运行命令或脚本。这些任务可以按照分钟、小时、日…...
Caffeine Cache Java缓存组件
缓存组件Caffeine Cache 定义介绍整合springboot用法整合spring-boot-starter-cache用法 定义介绍 特性 高性能:基于高效并发设计和 TinyLFU 算法,命中率高。 丰富策略:支持容量限制、过期时间、异步加载、自定义清理策略。 统计监控&#x…...
电子电气架构 --- 什么是自动驾驶技术中的域控制单元(DCU)?
我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 所谓鸡汤,要么蛊惑你认命,要么怂恿你拼命,但都是回避问题的根源,以现象替代逻辑,以情绪代替思考,把消极接受现实的懦弱,伪装成乐观面对不幸的…...
Redis核心技术知识点全集
Redis数据结构和常用命令 1. String字符串2. Hash哈希3. List列表4. Set集合5. Sorted Set有序集合6. Redis常用命令参考Redis事务机制...
【每日学点鸿蒙知识】文件读写、屏幕宽度亮度、扫一扫权限、编码器问题、wlan设置
1、参照文档,在操作文件时,读取不到内容或出现程序闪退? 参照文档,进行文件写入和读取时,出现读取不到或闪退 export function createFile() {// 获取应用文件路径let context getContext(this) as common.UIAbilit…...
后端开发-Maven
环境说明: windows系统:11版本 idea版本:2023.3.2 Maven 介绍 Apache Maven 是一个 Java 项目的构建管理和理解工具。Maven 使用一个项目对象模型(POM),通过一组构建规则和约定来管理项目的构建…...
LiteFlow 流程引擎引入Spring boot项目集成pg数据库
文章目录 官网地址简要项目引入maven 所需jar包配置 PostgreSQL 数据库表使用LiteFlow配置 yml 文件通过 代码方式使用 liteflow数据库sql 数据在流程中周转 官网地址 https://liteflow.cc/ 简要 如果你要对复杂业务逻辑进行新写或者重构,用LiteFlow最合适不过。…...
电子电气架构 --- 汽车电子电器设计概述
我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 所谓鸡汤,要么蛊惑你认命,要么怂恿你拼命,但都是回避问题的根源,以现象替代逻辑,以情绪代替思考,把消极接受现实的懦弱,伪装成乐观面对不幸的…...