143 lines
3.7 KiB
Python
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()),
|
|
}
|