Skip to content

Commit

Permalink
deprecate pyOpenSSL (#152) and pkg_resources
Browse files Browse the repository at this point in the history
  • Loading branch information
URenko committed Oct 26, 2023
1 parent 5986dc1 commit f1eecd1
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 86 deletions.
8 changes: 4 additions & 4 deletions accesser/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
import traceback
from contextlib import closing
from urllib import request
from pkg_resources import parse_version
from packaging.version import Version
from tld import get_tld
import dns, dns.asyncresolver

Expand Down Expand Up @@ -177,14 +177,14 @@ def update_checker():
for pypi_url in ['https://pypi.org/pypi/accesser/json', 'https://mirrors.cloud.tencent.com/pypi/json/accesser']:
try:
with request.urlopen(pypi_url) as f:
v2 = parse_version(json.load(f)["info"]["version"])
v2 = Version(json.load(f)["info"]["version"])
break
except Exception:
logger.warning(traceback.format_exc())
else:
with request.urlopen('https://github.com/URenko/Accesser/releases/latest') as f:
v2 = parse_version(f.geturl().rsplit('/', maxsplit=1)[-1])
v1 = parse_version(__version__)
v2 = Version(f.geturl().rsplit('/', maxsplit=1)[-1])
v1 = Version(__version__)
if v2 > v1:
logger.warning("There is a new version, you can update with 'python3 -m pip install -U accesser' or download from GitHub")

Expand Down
157 changes: 83 additions & 74 deletions accesser/utils/certmanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,14 @@
import os
import random
import sys
import ssl
from OpenSSL import crypto
import datetime
from pathlib import Path

from cryptography import x509
from cryptography.x509.oid import NameOID
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import rsa

from . import setting
from .setting import basepath
Expand All @@ -33,78 +39,81 @@
os.makedirs(certpath, exist_ok=True)

def create_root_ca():
pkey = crypto.PKey()
pkey.generate_key(crypto.TYPE_RSA, 4096)

cert = crypto.X509()
cert.set_version(2)
cert.set_serial_number(int(random.random() * sys.maxsize))
cert.gmtime_adj_notBefore(0)
cert.gmtime_adj_notAfter(60 * 60 * 24 * 365 * 10)

subject = cert.get_subject()
subject.CN = "Accesser"
subject.O = "Accesser"

issuer = cert.get_issuer()
issuer.CN = "Accesser"
issuer.O = "Accesser"

cert.set_pubkey(pkey)
cert.add_extensions([
crypto.X509Extension(b"basicConstraints", True,
b"CA:TRUE"),
crypto.X509Extension(b"subjectKeyIdentifier", False, b"hash",
subject=cert)
])
cert.add_extensions([
crypto.X509Extension(b"authorityKeyIdentifier", False, b"keyid:always",
issuer=cert)
key = rsa.generate_private_key(
public_exponent=65537,
key_size=4096,
)

subject = issuer = x509.Name([
x509.NameAttribute(NameOID.ORGANIZATION_NAME, "Accesser"),
x509.NameAttribute(NameOID.COMMON_NAME, "Accesser"),
])
cert.sign(pkey, "sha256")

with open(os.path.join(certpath ,"root.crt"), "wb") as certfile:
certfile.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
certfile.close()

with open(os.path.join(certpath ,"root.key"), "wb") as pkeyfile:
pkeyfile.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, pkey))
pkeyfile.close()

pfx = crypto.PKCS12()
pfx.set_privatekey(pkey)
pfx.set_certificate(cert)
with open(os.path.join(certpath ,"root.pfx"), 'wb') as pfxfile:
pfxfile.write(pfx.export())

pkey = crypto.PKey()
pkey.generate_key(crypto.TYPE_RSA, 2048)
cert = x509.CertificateBuilder().subject_name(
subject
).issuer_name(
issuer
).public_key(
key.public_key()
).serial_number(
x509.random_serial_number()
).not_valid_before(
datetime.datetime.now(datetime.timezone.utc)
).not_valid_after(
datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(days=10*365)
).sign(key, hashes.SHA256())

(Path(certpath) / "root.crt").write_bytes(cert.public_bytes(serialization.Encoding.PEM))

(Path(certpath) / "root.key").write_bytes(key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption(),
))

(Path(certpath) / "root.pfx").write_bytes(serialization.pkcs12.serialize_key_and_certificates(
b"Accesser", key, cert, None, serialization.NoEncryption()
))


pkey = rsa.generate_private_key(
public_exponent=65537,
key_size=4096,
)

def create_certificate(server_name):
rootpem = open(os.path.join(certpath ,"root.crt"), "rb").read()
rootkey = open(os.path.join(certpath ,"root.key"), "rb").read()
ca_cert = crypto.load_certificate(crypto.FILETYPE_PEM, rootpem)
ca_key = crypto.load_privatekey(crypto.FILETYPE_PEM, rootkey)

cert = crypto.X509()
cert.set_serial_number(int(random.random() * sys.maxsize))
cert.gmtime_adj_notBefore(-600)
cert.gmtime_adj_notAfter(60 * 60 * 24 * 365)
cert.set_version(2)

subject = cert.get_subject()
subject.CN = "Accesser_Proxy"
subject.O = "Accesser"

cert.add_extensions([crypto.X509Extension(b"subjectAltName", False, ('DNS:'+server_name+',DNS:*.'+server_name).encode())])

cert.set_issuer(ca_cert.get_subject())

cert.set_pubkey(pkey)
cert.sign(ca_key, "sha256")


with open(os.path.join(certpath ,'{}.crt'.format(server_name)), "wb") as certfile:
certfile.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
certfile.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, pkey))
certfile.close()
rootpem = (Path(certpath) / "root.crt").read_bytes()
rootkey = (Path(certpath) / "root.key").read_bytes()
ca_cert = x509.load_pem_x509_certificate(rootpem)
ca_key = serialization.load_pem_private_key(rootkey, password=None)

cert = x509.CertificateBuilder().subject_name(x509.Name([
x509.NameAttribute(NameOID.ORGANIZATION_NAME, "Accesser"),
x509.NameAttribute(NameOID.COMMON_NAME, "Accesser_Proxy"),
])
).issuer_name(
ca_cert.subject
).public_key(
pkey.public_key()
).serial_number(
x509.random_serial_number()
).not_valid_before(
datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(seconds=600)
).not_valid_after(
datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(days=365)
).add_extension(
x509.SubjectAlternativeName([
x509.DNSName(server_name),
x509.DNSName('*.'+server_name),
]),
critical=False,
).sign(ca_key, hashes.SHA256())


(Path(certpath) / f"{server_name}.crt").write_bytes(
cert.public_bytes(serialization.Encoding.PEM) +
pkey.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption(),
)
)
15 changes: 9 additions & 6 deletions accesser/utils/importca.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

from OpenSSL import crypto
import os, sys
import subprocess
import locale

from cryptography.hazmat.primitives import serialization

from . import setting
from . import certmanager as cm
from .setting import basepath
Expand Down Expand Up @@ -58,13 +59,15 @@ def import_windows_ca():
logger.warning('Try to manually import the certificate')
else:
with open(os.path.join(certpath ,"root.pfx"), 'rb') as pfxfile:
p12 = crypto.load_pkcs12(pfxfile.read())
private_key, certificate, _ = serialization.pkcs12.load_key_and_certificates(pfxfile.read(), password=None)
with open(os.path.join(certpath ,"root.crt"), "wb") as certfile:
certfile.write(crypto.dump_certificate(crypto.FILETYPE_PEM, p12.get_certificate()))
certfile.close()
certfile.write(certificate.public_bytes(serialization.Encoding.PEM))
with open(os.path.join(certpath ,"root.key"), "wb") as pkeyfile:
pkeyfile.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, p12.get_privatekey()))
pkeyfile.close()
pkeyfile.write(private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption(),
))

def import_mac_ca():
ca_hash = CertUtil.ca_thumbprint.replace(':', '')
Expand Down
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ classifiers = [
"Operating System :: OS Independent",
]
dependencies = [
"pyopenssl",
'packaging',
'cryptography',
'tld',
'dnspython < 2.4',
'tomli >= 1.1.0 ; python_version < "3.11"'
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pyopenssl
cryptography
tld
dnspython < 2.4
tomli >= 1.1.0 ; python_version < "3.11"

3 comments on commit f1eecd1

@UjuiUjuMandan
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@URenko
Copy link
Owner Author

@URenko URenko commented on f1eecd1 Oct 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@URenko 没有CA:TRUE这个属性的证书不能在 Android 上被安装。

https://android.stackexchange.com/questions/237141/how-to-get-android-11-to-trust-a-user-root-ca-without-a-private-key

b91af6f

暂不确定 subjectKeyIdentifierauthorityKeyIdentifier 是否是必须的

@UjuiUjuMandan
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

刚才在 Android 14 上测试了可以的,后两者并不必须。

Please sign in to comment.