Files
dromara--domain-admin/domain_admin/utils/cert_util/cert_ftp.py
T
2026-07-13 12:31:34 +08:00

143 lines
3.7 KiB
Python

import ssl
from ftplib import FTP_TLS
import OpenSSL
from domain_admin.enums.ssl_type_enum import SSLTypeEnum
from domain_admin.utils import domain_util, time_util, json_util
from domain_admin.utils.cert_util import cert_common
# 默认的ftp端口
DEFAULT_FTP_PORT = 21
# www.
WWW_WITH_DOT = 'www.'
def verify_cert(cert, domain):
"""
验证证书和域名是否匹配
:param cert:
:param domain:
:return:
"""
# 检查 颁发对象 域名(CN) 备用域名(SAN)
common_name = cert.get_subject().commonName
dns_names = cert_common.get_certificate_san(cert)
if common_name not in dns_names:
dns_names.insert(0, common_name)
# 申请域名为www.domain.com的证书同时支持保护domain.com
if common_name.startswith(WWW_WITH_DOT):
not_www_common_name = common_name[len(WWW_WITH_DOT):]
if not_www_common_name not in dns_names:
dns_names.append(not_www_common_name)
else:
www_common_name = WWW_WITH_DOT + common_name
if www_common_name not in dns_names:
dns_names.append(www_common_name)
for dns_name in dns_names:
domain_checked = domain_util.verify_cert_common_name(dns_name, domain)
if domain_checked:
return True
return False
def get_ftp_cert(
domain,
host=None,
port=DEFAULT_FTP_PORT,
timeout=3,
#ssl_type=SSLTypeEnum.SSL_TLS
):
"""
不验证证书,仅验证域名
支持通配符
:param ssl_type:
:param domain: str
:param host: str
:param port: int
:param timeout: int
:return:
"""
cert = None
if domain.startswith("https://"):
domain = domain[len("https://"):]
if domain.startswith("http://"):
domain = domain[len("http://"):]
# split port in domain
if ":" in domain:
temp_list = domain.split(":")
domain = temp_list[0]
try:
port = int(temp_list[-1])
except Exception:
print("Illegal port ", temp_list[-1])
# 默认参数
host = host or domain
try:
# 创建 FTPS 连接
ftps = FTP_TLS(context=ssl._create_stdlib_context(cert_reqs=ssl.CERT_REQUIRED))
ftps.connect(host, port)
ftps.auth() # 发送 AUTH TLS 命令
# ftps.prot_p() # 切换到安全数据连接
## 获取 SSL socket 并提取证书
# 获取证书信息的字典
# cert = ftps.sock.getpeercert(binary_form=False) # cert_reqs=ssl.CERT_REQUIRED 才能获取到解析好的字典证书
# # print(cert)
# 获取二进制证书,bytes类型
cert = ftps.sock.getpeercert(binary_form=True)
# 从二进制生产PEM格式
pem_cert = ssl.DER_cert_to_PEM_cert(cert)
print(pem_cert)
cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, pem_cert.encode())
except Exception as e:
print(f"Get cert error: {e}")
try:
ftps.quit()
except Exception as e:
ftps.close()
return cert
def get_ftp_cert_by_ftplib(
domain,
host=None,
port=DEFAULT_FTP_PORT,
timeout=3,
#ssl_type=SSLTypeEnum.SSL_TLS
):
"""
不验证证书,仅验证域名
支持通配符
:param ssl_type:
:param domain: str
:param host: str
:param port: int
:param timeout: int
:return:
"""
# get
cert = get_ftp_cert(domain, host, port, timeout)
# verify
domain_checked = verify_cert(cert, domain)
if not domain_checked:
raise Exception("domain not verified")
return {
'start_date': time_util.parse_time(cert.get_notBefore().decode()),
'expire_date': time_util.parse_time(cert.get_notAfter().decode()),
}