atomicshop 2.16.14__py3-none-any.whl → 2.16.15__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of atomicshop might be problematic. Click here for more details.
- atomicshop/__init__.py +1 -1
- atomicshop/certificates.py +146 -51
- atomicshop/mitm/config_static.py +12 -3
- atomicshop/mitm/import_config.py +8 -0
- atomicshop/mitm/mitm_main.py +7 -4
- atomicshop/wrappers/cryptographyw.py +3 -1
- atomicshop/wrappers/pywin32w/cert_store.py +89 -0
- atomicshop/wrappers/socketw/socket_wrapper.py +71 -2
- atomicshop/wrappers/socketw/ssl_base.py +1 -1
- {atomicshop-2.16.14.dist-info → atomicshop-2.16.15.dist-info}/METADATA +1 -1
- {atomicshop-2.16.14.dist-info → atomicshop-2.16.15.dist-info}/RECORD +14 -13
- {atomicshop-2.16.14.dist-info → atomicshop-2.16.15.dist-info}/LICENSE.txt +0 -0
- {atomicshop-2.16.14.dist-info → atomicshop-2.16.15.dist-info}/WHEEL +0 -0
- {atomicshop-2.16.14.dist-info → atomicshop-2.16.15.dist-info}/top_level.txt +0 -0
atomicshop/__init__.py
CHANGED
atomicshop/certificates.py
CHANGED
|
@@ -5,8 +5,10 @@ https://oidref.com/1.3.6.1.5.5.7.3.1
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
import ssl
|
|
8
|
+
from typing import Literal
|
|
8
9
|
|
|
9
10
|
from .wrappers import cryptographyw
|
|
11
|
+
from .wrappers.pywin32w import cert_store
|
|
10
12
|
from .print_api import print_api
|
|
11
13
|
|
|
12
14
|
|
|
@@ -16,72 +18,165 @@ from .print_api import print_api
|
|
|
16
18
|
SECONDS_NOT_AFTER_3_YEARS = 3 * 365 * 24 * 60 * 60
|
|
17
19
|
|
|
18
20
|
|
|
19
|
-
def
|
|
21
|
+
def get_pem_certificate_from_string(certificate: str) -> str:
|
|
20
22
|
"""
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
:param certificate:
|
|
24
|
-
:
|
|
25
|
-
The problem that the issuer common name is not unique, so it can be installed multiple times.
|
|
26
|
-
:param thumbprint_only: bool, if True, will check only by the certificate thumbprint is installed in the store.
|
|
27
|
-
The problem that searching by the thumbprint will not tell you if there are multiple certificates with the same
|
|
28
|
-
issuer name.
|
|
29
|
-
:return: bool, True if certificate is installed, False if not.
|
|
23
|
+
Some PEM certificates can contain a private key. This function will return only the certificate part.
|
|
24
|
+
|
|
25
|
+
:param certificate: string, PEM certificate.
|
|
26
|
+
:return: string, certificate part.
|
|
30
27
|
"""
|
|
31
28
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
29
|
+
certificate_lines = certificate.split('\n')
|
|
30
|
+
certificate_part = ''
|
|
31
|
+
start = False
|
|
32
|
+
for line in certificate_lines:
|
|
33
|
+
if 'BEGIN CERTIFICATE' in line:
|
|
34
|
+
start = True
|
|
35
|
+
if start:
|
|
36
|
+
certificate_part += line + '\n'
|
|
37
|
+
if 'END CERTIFICATE' in line:
|
|
38
|
+
break
|
|
37
39
|
|
|
38
|
-
|
|
39
|
-
for cert, encoding, trust in ssl.enum_certificates("ROOT"):
|
|
40
|
-
store_certificate = cryptographyw.convert_object_to_x509(cert)
|
|
41
|
-
store_issuer_common_name: str = cryptographyw.get_issuer_common_name_from_x509(store_certificate)
|
|
42
|
-
store_thumbprint = cryptographyw.get_sha1_thumbprint_from_x509(store_certificate)
|
|
43
|
-
|
|
44
|
-
if issuer_only:
|
|
45
|
-
if store_issuer_common_name == issuer_common_name:
|
|
46
|
-
return True, certificate
|
|
47
|
-
elif thumbprint_only:
|
|
48
|
-
if store_thumbprint == thumbprint:
|
|
49
|
-
return True, certificate
|
|
50
|
-
elif not issuer_only and not thumbprint_only:
|
|
51
|
-
if store_thumbprint == thumbprint and store_issuer_common_name == issuer_common_name:
|
|
52
|
-
return True, certificate
|
|
40
|
+
return certificate_part
|
|
53
41
|
|
|
54
42
|
|
|
55
|
-
def
|
|
43
|
+
def write_crt_certificate_file_in_pem_format_from_pem_file(
|
|
44
|
+
pem_file_path: str,
|
|
45
|
+
crt_file_path: str
|
|
46
|
+
):
|
|
56
47
|
"""
|
|
57
|
-
The function will
|
|
48
|
+
The function will read the PEM certificate file and write it to the CRT file in PEM format.
|
|
49
|
+
The function is used to convert the PEM certificate file to the CRT file.
|
|
58
50
|
|
|
59
|
-
|
|
60
|
-
|
|
51
|
+
Basically the point here is that the CRT file is the same as the PEM file, but the extension is different,
|
|
52
|
+
and it doesn't support integrated private key.
|
|
61
53
|
|
|
62
|
-
:
|
|
54
|
+
:param pem_file_path: string, path to the PEM certificate file.
|
|
55
|
+
:param crt_file_path: string, path to the CRT certificate file.
|
|
63
56
|
"""
|
|
64
57
|
|
|
65
|
-
|
|
66
|
-
|
|
58
|
+
with open(pem_file_path, 'r') as f:
|
|
59
|
+
certificate_string = f.read()
|
|
60
|
+
|
|
61
|
+
certificate_pem = get_pem_certificate_from_string(certificate_string)
|
|
62
|
+
|
|
63
|
+
with open(crt_file_path, 'w') as f:
|
|
64
|
+
f.write(certificate_pem)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def is_certificate_in_store(
|
|
68
|
+
certificate: any = None,
|
|
69
|
+
by_cert_issuer: bool = True,
|
|
70
|
+
by_cert_thumbprint: bool = True,
|
|
71
|
+
issuer_name: str = None,
|
|
72
|
+
store_location: str = "ROOT"
|
|
73
|
+
) -> tuple[bool, list]:
|
|
74
|
+
"""
|
|
75
|
+
The function will check if the CA certificate is installed in the Windows certificate Trusted Root store.
|
|
76
|
+
NO ADMIN RIGHTS NEEDED.
|
|
77
|
+
|
|
78
|
+
:param certificate: x509 object, certificate to check. You can search by certificate or by issuer name.
|
|
79
|
+
Supported types:
|
|
80
|
+
string that is path to file will be imported as bytes object abd converted to x509.Certificate
|
|
81
|
+
After check if it's PEM or DER format.
|
|
82
|
+
string that is PEM certificate will be converted to bytes, then x509.Certificate
|
|
83
|
+
bytes of PEM or DER will be converted to x509.Certificate.
|
|
84
|
+
x509.Certificate will be returned as is.
|
|
85
|
+
:param by_cert_issuer: bool, if True, will check only by the certificate issuer common name is installed in the store.
|
|
86
|
+
The problem if the search will be by issuer alone, that the issuer common name is not unique,
|
|
87
|
+
so it can be installed multiple times.
|
|
88
|
+
:param by_cert_thumbprint: bool, if True, will check only by the certificate thumbprint is installed in the store.
|
|
89
|
+
The problem that searching by the thumbprint alone will not tell you if there are multiple
|
|
90
|
+
certificates with the same issuer name.
|
|
91
|
+
:param issuer_name: string, issuer name to search for. You can search by certificate or by issuer name.
|
|
92
|
+
:param store_location: string, store location to search in. Default is "ROOT".
|
|
93
|
+
:return: tuple(bool - True if certificate is installed and False if not, list of certificates found)
|
|
94
|
+
"""
|
|
67
95
|
|
|
68
|
-
|
|
96
|
+
if not by_cert_issuer and not by_cert_thumbprint:
|
|
97
|
+
raise ValueError('At least one of the parameters "by_issuer" or "by_thumbprint" must be True.')
|
|
98
|
+
|
|
99
|
+
if not certificate and not issuer_name:
|
|
100
|
+
raise ValueError('At least one of the parameters "certificate" or "issuer_name" must be provided.')
|
|
101
|
+
elif certificate and issuer_name:
|
|
102
|
+
raise ValueError('Only one of the parameters "certificate" or "issuer_name" must be provided.')
|
|
103
|
+
|
|
104
|
+
if certificate:
|
|
105
|
+
# Make sure the certificate is x509.Certificate object.
|
|
106
|
+
certificate_x509 = cryptographyw.convert_object_to_x509(certificate)
|
|
107
|
+
# Get the certificate thumbprint.
|
|
108
|
+
provided_thumbprint = cryptographyw.get_sha1_thumbprint_from_x509(certificate_x509)
|
|
109
|
+
provided_issuer_common_name: str = cryptographyw.get_issuer_common_name_from_x509(certificate_x509)
|
|
110
|
+
elif issuer_name:
|
|
111
|
+
provided_thumbprint = None
|
|
112
|
+
provided_issuer_common_name = issuer_name
|
|
113
|
+
else:
|
|
114
|
+
raise ValueError('At least one of the parameters "certificate" or "issuer_name" must be provided.')
|
|
69
115
|
|
|
70
|
-
|
|
116
|
+
# Iterate over all certificates in the store specifically in the ROOT.
|
|
117
|
+
# for store in ["CA", "ROOT", "MY"]:
|
|
118
|
+
result_found_list: list = []
|
|
119
|
+
found: bool = False
|
|
120
|
+
for cert, encoding, trust in ssl.enum_certificates(store_location):
|
|
71
121
|
store_certificate = cryptographyw.convert_object_to_x509(cert)
|
|
72
122
|
store_issuer_common_name: str = cryptographyw.get_issuer_common_name_from_x509(store_certificate)
|
|
123
|
+
store_thumbprint = cryptographyw.get_sha1_thumbprint_from_x509(store_certificate)
|
|
73
124
|
|
|
74
|
-
if
|
|
75
|
-
|
|
125
|
+
if certificate:
|
|
126
|
+
if by_cert_issuer and not by_cert_thumbprint:
|
|
127
|
+
if store_issuer_common_name == provided_issuer_common_name:
|
|
128
|
+
result_found_list.append(store_certificate)
|
|
129
|
+
found = True
|
|
130
|
+
elif by_cert_thumbprint and not by_cert_issuer:
|
|
131
|
+
if store_thumbprint == provided_thumbprint:
|
|
132
|
+
result_found_list.append(store_certificate)
|
|
133
|
+
found = True
|
|
134
|
+
elif by_cert_issuer and by_cert_thumbprint:
|
|
135
|
+
if store_thumbprint == provided_thumbprint and store_issuer_common_name == provided_issuer_common_name:
|
|
136
|
+
result_found_list.append(store_certificate)
|
|
137
|
+
found = True
|
|
138
|
+
elif issuer_name:
|
|
139
|
+
if store_issuer_common_name == provided_issuer_common_name:
|
|
140
|
+
result_found_list.append(store_certificate)
|
|
141
|
+
found = True
|
|
142
|
+
|
|
143
|
+
return found, result_found_list
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def delete_certificate_by_issuer_name(
|
|
147
|
+
issuer_name: str,
|
|
148
|
+
store_location: Literal[
|
|
149
|
+
"ROOT",
|
|
150
|
+
"CA",
|
|
151
|
+
"MY"] = "ROOT",
|
|
152
|
+
print_kwargs: dict = None
|
|
153
|
+
):
|
|
154
|
+
"""
|
|
155
|
+
NEED ADMIN RIGHTS.
|
|
156
|
+
The function will remove all certificates with the specified issuer name.
|
|
157
|
+
There can be several certificates with this name.
|
|
76
158
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
159
|
+
:param issuer_name: string, issuer name to search for.
|
|
160
|
+
:param store_location: string, store location to search in. Default is "ROOT".
|
|
161
|
+
:param print_kwargs: dict, print_api kwargs.
|
|
162
|
+
"""
|
|
163
|
+
|
|
164
|
+
cert_store.delete_certificate_by_issuer_name(issuer_name, store_location, print_kwargs)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def install_certificate_file(
|
|
168
|
+
file_path: str,
|
|
169
|
+
store_location: Literal[
|
|
170
|
+
"ROOT", "CA", "MY"] = "ROOT",
|
|
171
|
+
print_kwargs: dict = None
|
|
172
|
+
):
|
|
173
|
+
"""
|
|
174
|
+
The function will install the certificate from the file to the specified store location.
|
|
175
|
+
NEED ADMIN RIGHTS.
|
|
176
|
+
|
|
177
|
+
:param file_path: string, full file path to the certificate file.
|
|
178
|
+
:param store_location: string, store location to install the certificate. Default is "ROOT".
|
|
179
|
+
:param print_kwargs: dict, print_api kwargs.
|
|
180
|
+
"""
|
|
86
181
|
|
|
87
|
-
|
|
182
|
+
cert_store.install_certificate_file(file_path, store_location, print_kwargs)
|
atomicshop/mitm/config_static.py
CHANGED
|
@@ -4,9 +4,9 @@ from dataclasses import dataclass
|
|
|
4
4
|
from . import import_config
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
SCRIPT_VERSION: str = '1.7.
|
|
7
|
+
SCRIPT_VERSION: str = '1.7.6'
|
|
8
8
|
"""
|
|
9
|
-
|
|
9
|
+
added ca cert check and installation
|
|
10
10
|
"""
|
|
11
11
|
|
|
12
12
|
|
|
@@ -23,6 +23,8 @@ LIST_OF_BOOLEANS: list = [
|
|
|
23
23
|
('tcp', 'engines_usage'),
|
|
24
24
|
('tcp', 'server_response_mode'),
|
|
25
25
|
('logrec', 'enable_request_response_recordings_in_logs'),
|
|
26
|
+
('certificates', 'install_ca_certificate_to_root_store'),
|
|
27
|
+
('certificates', 'uninstall_unused_ca_certificates_with_mitm_ca_name'),
|
|
26
28
|
('certificates', 'default_server_certificate_usage'),
|
|
27
29
|
('certificates', 'sni_add_new_domains_to_default_server_certificate'),
|
|
28
30
|
('certificates', 'custom_server_certificate_usage'),
|
|
@@ -55,8 +57,11 @@ class MainConfig:
|
|
|
55
57
|
# Certificates.
|
|
56
58
|
default_server_certificate_name: str = 'default'
|
|
57
59
|
ca_certificate_name: str = 'ElaborateCA'
|
|
60
|
+
ca_certificate_pem_filename: str = f'{ca_certificate_name}.pem'
|
|
61
|
+
ca_certificate_crt_filename: str = f'{ca_certificate_name}_for_manual_installation_not_used_by_script.crt'
|
|
58
62
|
# CA Certificate name and file name without extension.
|
|
59
63
|
ca_certificate_filepath: str = None
|
|
64
|
+
ca_certificate_crt_filepath: str = None
|
|
60
65
|
# Default server certificate file name and path.
|
|
61
66
|
default_server_certificate_filename = f'{default_server_certificate_name}.pem'
|
|
62
67
|
default_server_certificate_filepath: str = None
|
|
@@ -65,7 +70,8 @@ class MainConfig:
|
|
|
65
70
|
def update(cls):
|
|
66
71
|
# This runs after the dataclass is initialized
|
|
67
72
|
cls.ENGINES_DIRECTORY_PATH = cls.SCRIPT_DIRECTORY + os.sep + cls.ENGINES_DIRECTORY_NAME
|
|
68
|
-
cls.ca_certificate_filepath = f'{cls.SCRIPT_DIRECTORY}{os.sep}{cls.
|
|
73
|
+
cls.ca_certificate_filepath = f'{cls.SCRIPT_DIRECTORY}{os.sep}{cls.ca_certificate_pem_filename}'
|
|
74
|
+
cls.ca_certificate_crt_filepath = f'{cls.SCRIPT_DIRECTORY}{os.sep}{cls.ca_certificate_crt_filename}'
|
|
69
75
|
cls.default_server_certificate_filepath = \
|
|
70
76
|
f'{cls.SCRIPT_DIRECTORY}{os.sep}{cls.default_server_certificate_filename}'
|
|
71
77
|
|
|
@@ -115,6 +121,9 @@ class LogRec:
|
|
|
115
121
|
|
|
116
122
|
@dataclass
|
|
117
123
|
class Certificates:
|
|
124
|
+
install_ca_certificate_to_root_store: bool
|
|
125
|
+
uninstall_unused_ca_certificates_with_mitm_ca_name: bool
|
|
126
|
+
|
|
118
127
|
default_server_certificate_usage: bool
|
|
119
128
|
sni_add_new_domains_to_default_server_certificate: bool
|
|
120
129
|
|
atomicshop/mitm/import_config.py
CHANGED
|
@@ -117,6 +117,14 @@ def check_configurations() -> int:
|
|
|
117
117
|
print_api(message, color='red')
|
|
118
118
|
return 1
|
|
119
119
|
|
|
120
|
+
# This is checked directly in the SocketWrapper.
|
|
121
|
+
# if (config_static.Certificates.install_ca_certificate_to_root_store and not is_admin) or \
|
|
122
|
+
# (config_static.Certificates.uninstall_unused_ca_certificates_with_mitm_ca_name and not is_admin):
|
|
123
|
+
# message: str = \
|
|
124
|
+
# "Need to run the script with administrative rights to install or uninstall CA certificate.\nExiting..."
|
|
125
|
+
# print_api(message, color='red')
|
|
126
|
+
# return 1
|
|
127
|
+
|
|
120
128
|
return 0
|
|
121
129
|
|
|
122
130
|
|
atomicshop/mitm/mitm_main.py
CHANGED
|
@@ -263,6 +263,10 @@ def mitm_server_main(config_file_path: str):
|
|
|
263
263
|
listening_port_list=config_static.TCPServer.listening_port_list,
|
|
264
264
|
ca_certificate_name=config_static.MainConfig.ca_certificate_name,
|
|
265
265
|
ca_certificate_filepath=config_static.MainConfig.ca_certificate_filepath,
|
|
266
|
+
ca_certificate_crt_filepath=config_static.MainConfig.ca_certificate_crt_filepath,
|
|
267
|
+
install_ca_certificate_to_root_store=config_static.Certificates.install_ca_certificate_to_root_store,
|
|
268
|
+
uninstall_unused_ca_certificates_with_ca_certificate_name=(
|
|
269
|
+
config_static.Certificates.uninstall_unused_ca_certificates_with_mitm_ca_name),
|
|
266
270
|
default_server_certificate_usage=config_static.Certificates.default_server_certificate_usage,
|
|
267
271
|
default_server_certificate_name=config_static.MainConfig.default_server_certificate_name,
|
|
268
272
|
default_certificate_domain_list=config_static.Certificates.domains_all_times,
|
|
@@ -316,11 +320,10 @@ def mitm_server_main(config_file_path: str):
|
|
|
316
320
|
dns_gateway_server_list = [base.DEFAULT_IPV4]
|
|
317
321
|
set_dns_gateway = True
|
|
318
322
|
|
|
323
|
+
# Get current network interface state.
|
|
324
|
+
global NETWORK_INTERFACE_IS_DYNAMIC, NETWORK_INTERFACE_IPV4_ADDRESS_LIST
|
|
325
|
+
NETWORK_INTERFACE_IS_DYNAMIC, NETWORK_INTERFACE_IPV4_ADDRESS_LIST = dns.get_default_dns_gateway()
|
|
319
326
|
if set_dns_gateway:
|
|
320
|
-
# Get current network interface state.
|
|
321
|
-
global NETWORK_INTERFACE_IS_DYNAMIC, NETWORK_INTERFACE_IPV4_ADDRESS_LIST
|
|
322
|
-
NETWORK_INTERFACE_IS_DYNAMIC, NETWORK_INTERFACE_IPV4_ADDRESS_LIST = dns.get_default_dns_gateway()
|
|
323
|
-
|
|
324
327
|
# Set the DNS gateway to the specified one only if the DNS gateway is dynamic or it is static but different
|
|
325
328
|
# from the one specified in the configuration file.
|
|
326
329
|
if (NETWORK_INTERFACE_IS_DYNAMIC or (not NETWORK_INTERFACE_IS_DYNAMIC and
|
|
@@ -36,7 +36,9 @@ def convert_object_to_x509(certificate):
|
|
|
36
36
|
"""
|
|
37
37
|
|
|
38
38
|
# Check if 'certificate' is a string and a path.
|
|
39
|
-
if isinstance(certificate, str)
|
|
39
|
+
if isinstance(certificate, str):
|
|
40
|
+
if not os.path.isfile(certificate):
|
|
41
|
+
raise FileNotFoundError(f'File not found: {certificate}')
|
|
40
42
|
# Import the certificate from the path.
|
|
41
43
|
certificate = file_io.read_file(certificate, file_mode='rb')
|
|
42
44
|
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
from typing import Literal
|
|
2
|
+
import win32crypt as wcrypt
|
|
3
|
+
|
|
4
|
+
from ...print_api import print_api
|
|
5
|
+
from ... import certificates
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# lpszStoreProvider
|
|
9
|
+
CERT_STORE_PROV_SYSTEM = 0x0000000A
|
|
10
|
+
# dwFlags
|
|
11
|
+
CERT_SYSTEM_STORE_LOCAL_MACHINE = 0x00020000
|
|
12
|
+
CERT_SYSTEM_STORE_CURRENT_USER = 0x00010000
|
|
13
|
+
CERT_CLOSE_STORE_FORCE_FLAG = 0x00000001
|
|
14
|
+
CRYPT_STRING_BASE64HEADER = 0x00000000
|
|
15
|
+
X509_ASN_ENCODING = 0x00000001
|
|
16
|
+
CERT_STORE_ADD_REPLACE_EXISTING = 3
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
STORE_LOCATION_TO_CERT_SYSTEM_STORE: dict = {
|
|
20
|
+
"ROOT": CERT_SYSTEM_STORE_LOCAL_MACHINE,
|
|
21
|
+
"CA": CERT_SYSTEM_STORE_LOCAL_MACHINE,
|
|
22
|
+
"MY": CERT_SYSTEM_STORE_CURRENT_USER
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def delete_certificate_by_issuer_name(
|
|
27
|
+
issuer_name: str,
|
|
28
|
+
store_location: Literal[
|
|
29
|
+
"ROOT",
|
|
30
|
+
"CA",
|
|
31
|
+
"MY"] = "ROOT",
|
|
32
|
+
print_kwargs: dict = None
|
|
33
|
+
):
|
|
34
|
+
"""
|
|
35
|
+
NEED ADMIN RIGHTS.
|
|
36
|
+
The function will remove all certificates with the specified issuer name.
|
|
37
|
+
There can be several certificates with this name.
|
|
38
|
+
|
|
39
|
+
:param issuer_name: string, issuer name to search for.
|
|
40
|
+
:param store_location: string, store location to search in. Default is "ROOT".
|
|
41
|
+
:param print_kwargs: dict, print_api kwargs.
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
store = wcrypt.CertOpenStore(
|
|
45
|
+
CERT_STORE_PROV_SYSTEM, 0, None, STORE_LOCATION_TO_CERT_SYSTEM_STORE[store_location], store_location)
|
|
46
|
+
|
|
47
|
+
for cert in store.CertEnumCertificatesInStore():
|
|
48
|
+
# Certificate properties.
|
|
49
|
+
# cert.CertEnumCertificateContextProperties()
|
|
50
|
+
subject_string: str = wcrypt.CertNameToStr(cert.Subject)
|
|
51
|
+
if subject_string == issuer_name:
|
|
52
|
+
# Remove the certificate.
|
|
53
|
+
cert.CertDeleteCertificateFromStore()
|
|
54
|
+
print_api(f"Removed the Certificate with issuer: {issuer_name}", **(print_kwargs or {}))
|
|
55
|
+
|
|
56
|
+
# There is an exception about store close.
|
|
57
|
+
# store.CertCloseStore()
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def install_certificate_file(
|
|
61
|
+
file_path: str,
|
|
62
|
+
store_location: Literal[
|
|
63
|
+
"ROOT", "CA", "MY"] = "ROOT",
|
|
64
|
+
print_kwargs: dict = None
|
|
65
|
+
):
|
|
66
|
+
"""
|
|
67
|
+
NEED ADMIN RIGHTS.
|
|
68
|
+
The function will install the certificate from the file to the specified store location.
|
|
69
|
+
|
|
70
|
+
:param file_path: string, full file path to the certificate file.
|
|
71
|
+
:param store_location: string, store location to install the certificate. Default is "ROOT".
|
|
72
|
+
:param print_kwargs: dict, print_api kwargs.
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
with open(file_path, 'r') as f:
|
|
76
|
+
certificate_string = f.read()
|
|
77
|
+
|
|
78
|
+
certificate_pem = certificates.get_pem_certificate_from_string(certificate_string)
|
|
79
|
+
|
|
80
|
+
certificate_bytes = wcrypt.CryptStringToBinary(certificate_pem, CRYPT_STRING_BASE64HEADER)[0]
|
|
81
|
+
|
|
82
|
+
store = wcrypt.CertOpenStore(
|
|
83
|
+
CERT_STORE_PROV_SYSTEM, 0, None, STORE_LOCATION_TO_CERT_SYSTEM_STORE[store_location], store_location)
|
|
84
|
+
|
|
85
|
+
store.CertAddEncodedCertificateToStore(X509_ASN_ENCODING, certificate_bytes, CERT_STORE_ADD_REPLACE_EXISTING)
|
|
86
|
+
store.CertCloseStore(CERT_CLOSE_STORE_FORCE_FLAG)
|
|
87
|
+
|
|
88
|
+
message = f"Certificate installed to the store: [{store_location}] from file: [{file_path}]"
|
|
89
|
+
print_api(message, **(print_kwargs or {}))
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import threading
|
|
2
2
|
import select
|
|
3
3
|
from typing import Literal, Union
|
|
4
|
+
from pathlib import Path
|
|
4
5
|
|
|
5
6
|
from ..psutilw import networks
|
|
7
|
+
from ..certauthw import certauthw
|
|
6
8
|
from ...script_as_string_processor import ScriptAsStringProcessor
|
|
7
|
-
from ... import
|
|
9
|
+
from ...permissions import permissions
|
|
10
|
+
from ... import queues, filesystem, certificates
|
|
8
11
|
from ...basics import booleans
|
|
9
12
|
from ...print_api import print_api
|
|
10
13
|
|
|
@@ -30,6 +33,9 @@ class SocketWrapper:
|
|
|
30
33
|
forwarding_dns_service_ipv4_list___only_for_localhost: list = None,
|
|
31
34
|
ca_certificate_name: str = None,
|
|
32
35
|
ca_certificate_filepath: str = None,
|
|
36
|
+
ca_certificate_crt_filepath: str = None,
|
|
37
|
+
install_ca_certificate_to_root_store: bool = False,
|
|
38
|
+
uninstall_unused_ca_certificates_with_ca_certificate_name: bool = False,
|
|
33
39
|
default_server_certificate_usage: bool = False,
|
|
34
40
|
default_server_certificate_name: str = None,
|
|
35
41
|
default_certificate_domain_list: list = None,
|
|
@@ -68,7 +74,13 @@ class SocketWrapper:
|
|
|
68
74
|
Example: '0.0.0.0'. For all interfaces.
|
|
69
75
|
:param listening_port_list: list, of ports that will be listened on.
|
|
70
76
|
:param ca_certificate_name: CA certificate name.
|
|
71
|
-
:param ca_certificate_filepath: CA certificate file path.
|
|
77
|
+
:param ca_certificate_filepath: CA certificate file path with '.pem' extension.
|
|
78
|
+
:param ca_certificate_crt_filepath: CA certificate file path with '.crt' extension.
|
|
79
|
+
This file will be created from the PEM file 'ca_certificate_filepath' for manual installation.
|
|
80
|
+
:param install_ca_certificate_to_root_store: boolean, if True, CA certificate will be installed
|
|
81
|
+
to the root store.
|
|
82
|
+
:param uninstall_unused_ca_certificates_with_ca_certificate_name: boolean, if True, unused CA certificates
|
|
83
|
+
with provided 'ca_certificate_name' will be uninstalled.
|
|
72
84
|
:param default_server_certificate_usage: boolean, if True, default server certificate will be used
|
|
73
85
|
for each incoming socket.
|
|
74
86
|
:param sni_custom_callback_function: callable, custom callback function that will be executed when
|
|
@@ -150,6 +162,10 @@ class SocketWrapper:
|
|
|
150
162
|
self.listening_port_list: list[int] = listening_port_list
|
|
151
163
|
self.ca_certificate_name: str = ca_certificate_name
|
|
152
164
|
self.ca_certificate_filepath: str = ca_certificate_filepath
|
|
165
|
+
self.ca_certificate_crt_filepath: str = ca_certificate_crt_filepath
|
|
166
|
+
self.install_ca_certificate_to_root_store: bool = install_ca_certificate_to_root_store
|
|
167
|
+
self.uninstall_unused_ca_certificates_with_ca_certificate_name: bool = \
|
|
168
|
+
uninstall_unused_ca_certificates_with_ca_certificate_name
|
|
153
169
|
self.default_server_certificate_usage: bool = default_server_certificate_usage
|
|
154
170
|
self.default_server_certificate_name: str = default_server_certificate_name
|
|
155
171
|
self.default_certificate_domain_list: list = default_certificate_domain_list
|
|
@@ -270,6 +286,59 @@ class SocketWrapper:
|
|
|
270
286
|
error_messages.append(f"Port [{port}] is already in use by process: {process_info}")
|
|
271
287
|
raise SocketWrapperPortInUseError("\n".join(error_messages))
|
|
272
288
|
|
|
289
|
+
if not filesystem.is_file_exists(file_path=self.ca_certificate_filepath):
|
|
290
|
+
# Initialize CertAuthWrapper.
|
|
291
|
+
ca_certificate_directory: str = str(Path(self.ca_certificate_filepath).parent)
|
|
292
|
+
certauth_wrapper = certauthw.CertAuthWrapper(
|
|
293
|
+
ca_certificate_name=self.ca_certificate_name,
|
|
294
|
+
ca_certificate_filepath=self.ca_certificate_filepath,
|
|
295
|
+
server_certificate_directory=ca_certificate_directory
|
|
296
|
+
)
|
|
297
|
+
|
|
298
|
+
# Create CA certificate if it doesn't exist.
|
|
299
|
+
certauth_wrapper.create_use_ca_certificate()
|
|
300
|
+
|
|
301
|
+
certificates.write_crt_certificate_file_in_pem_format_from_pem_file(
|
|
302
|
+
pem_file_path=self.ca_certificate_filepath,
|
|
303
|
+
crt_file_path=self.ca_certificate_crt_filepath)
|
|
304
|
+
|
|
305
|
+
if self.install_ca_certificate_to_root_store:
|
|
306
|
+
if not self.ca_certificate_filepath:
|
|
307
|
+
message = "You set [install_ca_certificate_to_root_store = True],\n" \
|
|
308
|
+
"But you didn't set [ca_certificate_filepath]."
|
|
309
|
+
raise SocketWrapperConfigurationValuesError(message)
|
|
310
|
+
|
|
311
|
+
# Before installation check if there are any unused certificates with the same name.
|
|
312
|
+
if self.uninstall_unused_ca_certificates_with_ca_certificate_name:
|
|
313
|
+
# Check how many certificates with our ca certificate name are installed.
|
|
314
|
+
is_installed_by_name, certificate_list_by_name = certificates.is_certificate_in_store(
|
|
315
|
+
issuer_name=self.ca_certificate_name)
|
|
316
|
+
# If there is more than one certificate with the same name, delete them all.
|
|
317
|
+
if is_installed_by_name and len(certificate_list_by_name) > 1:
|
|
318
|
+
certificates.delete_certificate_by_issuer_name(self.ca_certificate_name)
|
|
319
|
+
# If there is only one certificate with the same name, check if it is the same certificate.
|
|
320
|
+
elif is_installed_by_name and len(certificate_list_by_name) == 1:
|
|
321
|
+
is_installed_by_file, certificate_list_by_file = certificates.is_certificate_in_store(
|
|
322
|
+
certificate=self.ca_certificate_filepath, by_cert_thumbprint=True, by_cert_issuer=True)
|
|
323
|
+
# If the certificate is not the same, delete it.
|
|
324
|
+
if not is_installed_by_file:
|
|
325
|
+
if not permissions.is_admin():
|
|
326
|
+
raise SocketWrapperConfigurationValuesError(
|
|
327
|
+
"You need to run the script with admin rights to uninstall the unused certificates.")
|
|
328
|
+
certificates.delete_certificate_by_issuer_name(
|
|
329
|
+
self.ca_certificate_name, store_location="ROOT", print_kwargs={'logger': self.logger})
|
|
330
|
+
|
|
331
|
+
if self.install_ca_certificate_to_root_store:
|
|
332
|
+
# Install CA certificate to the root store if it is not installed.
|
|
333
|
+
is_installed_by_file, certificate_list_by_file = certificates.is_certificate_in_store(
|
|
334
|
+
certificate=self.ca_certificate_filepath, by_cert_thumbprint=True, by_cert_issuer=True)
|
|
335
|
+
if not is_installed_by_file:
|
|
336
|
+
if not permissions.is_admin():
|
|
337
|
+
raise SocketWrapperConfigurationValuesError(
|
|
338
|
+
"You need to run the script with admin rights to install the CA certificate.")
|
|
339
|
+
certificates.install_certificate_file(
|
|
340
|
+
self.ca_certificate_filepath, store_location="ROOT", print_kwargs={'logger': self.logger})
|
|
341
|
+
|
|
273
342
|
# Creating listening sockets.
|
|
274
343
|
def create_socket_ipv4_tcp(self, ip_address: str, port: int):
|
|
275
344
|
self.sni_execute_extended = True
|
|
@@ -60,7 +60,7 @@ def is_tls(client_socket) -> Optional[Tuple[str, str]]:
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
# Get the tuple of the type and version as strings.
|
|
63
|
-
tls_content_and_version_tuple: tuple
|
|
63
|
+
tls_content_and_version_tuple: tuple = \
|
|
64
64
|
content_type_map.get(content_type), version_map.get((version_major, version_minor))
|
|
65
65
|
|
|
66
66
|
# If both parts of the tuple are not None, return the protocol type.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
atomicshop/__init__.py,sha256=
|
|
1
|
+
atomicshop/__init__.py,sha256=UzNeZyRkmLnYywv5edPjB0_p7zEgYfoGzcusp1FpodI,124
|
|
2
2
|
atomicshop/_basics_temp.py,sha256=6cu2dd6r2dLrd1BRNcVDKTHlsHs_26Gpw8QS6v32lQ0,3699
|
|
3
3
|
atomicshop/_create_pdf_demo.py,sha256=Yi-PGZuMg0RKvQmLqVeLIZYadqEZwUm-4A9JxBl_vYA,3713
|
|
4
4
|
atomicshop/_patch_import.py,sha256=ENp55sKVJ0e6-4lBvZnpz9PQCt3Otbur7F6aXDlyje4,6334
|
|
5
5
|
atomicshop/appointment_management.py,sha256=BsYH_PClTGLVazcuNjt30--hpXKYjSmHp1R1iQbM4Hc,7330
|
|
6
|
-
atomicshop/certificates.py,sha256=
|
|
6
|
+
atomicshop/certificates.py,sha256=ssOTD1uN4OaB9TU7mI0Dg_sSGFb6Xxw28A7TtyKmMMY,7637
|
|
7
7
|
atomicshop/command_line_processing.py,sha256=u5yT9Ger_cu7ni5ID0VFlRbVD46ARHeNC9tRM-_YXrQ,1038
|
|
8
8
|
atomicshop/config_init.py,sha256=BSxc2FhytQPv06g5z9wbAXuA6oYCAsAJLxu_mTExhwI,2491
|
|
9
9
|
atomicshop/console_output.py,sha256=AOSJjrRryE97PAGtgDL03IBtWSi02aNol8noDnW3k6M,4667
|
|
@@ -122,13 +122,13 @@ atomicshop/file_io/tomls.py,sha256=ol8EvQPf9sryTmZUf1v55BYSUQ6ml7HVVBHpNKbsIlA,9
|
|
|
122
122
|
atomicshop/file_io/xlsxs.py,sha256=v_dyg9GD4LqgWi6wA1QuWRZ8zG4ZwB6Dz52ytdcmmmI,2184
|
|
123
123
|
atomicshop/file_io/xmls.py,sha256=zh3SuK-dNaFq2NDNhx6ivcf4GYCfGM8M10PcEwDSpxk,2104
|
|
124
124
|
atomicshop/mitm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
125
|
-
atomicshop/mitm/config_static.py,sha256=
|
|
125
|
+
atomicshop/mitm/config_static.py,sha256=UNvRTb3ZuFVGZpF33fvaIf0xw_VGyml2ExIwqW_uYcg,7777
|
|
126
126
|
atomicshop/mitm/config_toml_editor.py,sha256=2p1CMcktWRR_NW-SmyDwylu63ad5e0-w1QPMa8ZLDBw,1635
|
|
127
127
|
atomicshop/mitm/connection_thread_worker.py,sha256=1MBpRoLpzWJMvxqQKizo6IVQ4XYsbKGsjxianNQLUlE,20051
|
|
128
|
-
atomicshop/mitm/import_config.py,sha256=
|
|
128
|
+
atomicshop/mitm/import_config.py,sha256=_nu8mgA-M4s6dZ8_QWx3x0aVb75upvsCuX_PIUg4X2w,8345
|
|
129
129
|
atomicshop/mitm/initialize_engines.py,sha256=kBG8TBnyFuwlJ1uKaWDzc5AiZNpwdvouq2pr-PYrdEA,8349
|
|
130
130
|
atomicshop/mitm/message.py,sha256=d_sm3O_aoZf87dDQP44xOMNEG-uZBN1ZecQgMCacbZs,1814
|
|
131
|
-
atomicshop/mitm/mitm_main.py,sha256=
|
|
131
|
+
atomicshop/mitm/mitm_main.py,sha256=CdCv4nYt_jwd23AI14v6lC2H8SZeIZqsXjFhwq61UtM,21285
|
|
132
132
|
atomicshop/mitm/recs_files.py,sha256=btOuYQca4DuBOAKp9OY21HGjeEVOx9r_k-AnZOqs3Dk,3007
|
|
133
133
|
atomicshop/mitm/shared_functions.py,sha256=hplm98tz8pgJ4WHUVI9sf_oVqUM2KJ1Y2pD6EFSb8P0,1879
|
|
134
134
|
atomicshop/mitm/statistic_analyzer.py,sha256=AzL9rQhg0tLJj33gZfxdwWghmbXGLh_HyMBDpzuBmsQ,24709
|
|
@@ -178,7 +178,7 @@ atomicshop/wrappers/_process_wrapper_curl.py,sha256=XkZZXYl7D0Q6UfdWqy-18AvpU0yV
|
|
|
178
178
|
atomicshop/wrappers/_process_wrapper_tar.py,sha256=WUMZFKNrlG4nJP9tWZ51W7BR1j_pIjsjgyAStmWjRGs,655
|
|
179
179
|
atomicshop/wrappers/astw.py,sha256=VkYfkfyc_PJLIOxByT6L7B8uUmKY6-I8XGZl4t_z828,4239
|
|
180
180
|
atomicshop/wrappers/configparserw.py,sha256=JwDTPjZoSrv44YKwIRcjyUnpN-FjgXVfMqMK_tJuSgU,22800
|
|
181
|
-
atomicshop/wrappers/cryptographyw.py,sha256=
|
|
181
|
+
atomicshop/wrappers/cryptographyw.py,sha256=LfzTnwvJE03G6WZryOOf43VKhhnyMakzHpn8DPPCoy4,13252
|
|
182
182
|
atomicshop/wrappers/ffmpegw.py,sha256=wcq0ZnAe0yajBOuTKZCCaKI7CDBjkq7FAgdW5IsKcVE,6031
|
|
183
183
|
atomicshop/wrappers/githubw.py,sha256=AQcFuT5mvDUNT_cI31MwkJ7srdhMtttF8FyXS8vs5cU,12270
|
|
184
184
|
atomicshop/wrappers/msiw.py,sha256=GQLqud72nfex3kvO1bJSruNriCYTYX1_G1gSf1MPkIA,6118
|
|
@@ -278,6 +278,7 @@ atomicshop/wrappers/pycharmw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NM
|
|
|
278
278
|
atomicshop/wrappers/pycharmw/ubuntu.py,sha256=l2_9SXrw7ApSvFOROGZdPZa5ylZBKofk4sYqf4IugQs,1223
|
|
279
279
|
atomicshop/wrappers/pycharmw/win.py,sha256=jdnTkUqZX_BrMW8AmW-xGtxdV-wmmNr_NMA2jB6JHsQ,2725
|
|
280
280
|
atomicshop/wrappers/pywin32w/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
281
|
+
atomicshop/wrappers/pywin32w/cert_store.py,sha256=bpFm5nH9j6I9eJdLjPnSvo-g4OyJO7Sb5VddzVE9-UM,3156
|
|
281
282
|
atomicshop/wrappers/pywin32w/console.py,sha256=LstHajPLgXp9qQxFNR44QfH10nOnNp3bCJquxaTquns,1175
|
|
282
283
|
atomicshop/wrappers/pywin32w/winshell.py,sha256=i2bKiMldPU7_azsD5xGQDdMwjaM7suKJd3k0Szmcs6c,723
|
|
283
284
|
atomicshop/wrappers/pywin32w/win_event_log/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -303,13 +304,13 @@ atomicshop/wrappers/socketw/sender.py,sha256=d7YQFlCBMFTYtkGxbS-8cm5rh5WWFeBVvrE
|
|
|
303
304
|
atomicshop/wrappers/socketw/sni.py,sha256=fVwyh3h9IqfLMnf4__bMIzcF4c-Kk9mlbDWMRXKN-ow,17155
|
|
304
305
|
atomicshop/wrappers/socketw/socket_client.py,sha256=FNmTt94YvjZP0X4RPb7icO3xD_nBHQ_XynnObdWFiAU,19682
|
|
305
306
|
atomicshop/wrappers/socketw/socket_server_tester.py,sha256=wAwyst8YdVyVfZfERav1A9_OnMJAiVBy-4uY0RpNqkU,6339
|
|
306
|
-
atomicshop/wrappers/socketw/socket_wrapper.py,sha256=
|
|
307
|
-
atomicshop/wrappers/socketw/ssl_base.py,sha256=
|
|
307
|
+
atomicshop/wrappers/socketw/socket_wrapper.py,sha256=DiDzg9OlgahxpqAsnOkCKHNcE-H-YAY3ndVMeU-oCjw,33363
|
|
308
|
+
atomicshop/wrappers/socketw/ssl_base.py,sha256=kmiif84kMhBr5yjQW17p935sfjR5JKG0LxIwBA4iVvU,2275
|
|
308
309
|
atomicshop/wrappers/socketw/statistics_csv.py,sha256=V_m1D0KpizQox3IEWp2AUcncwWy5kG25hbFrc-mBSJE,3029
|
|
309
310
|
atomicshop/wrappers/winregw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
310
311
|
atomicshop/wrappers/winregw/winreg_network.py,sha256=bQ8Jql8bVGBJ0dt3VQ56lga_1LBOMLI3Km_otvvbU6c,7138
|
|
311
|
-
atomicshop-2.16.
|
|
312
|
-
atomicshop-2.16.
|
|
313
|
-
atomicshop-2.16.
|
|
314
|
-
atomicshop-2.16.
|
|
315
|
-
atomicshop-2.16.
|
|
312
|
+
atomicshop-2.16.15.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
|
|
313
|
+
atomicshop-2.16.15.dist-info/METADATA,sha256=i5Xgtqpn2TfPbeSQ_L3nAryipoFyy2Z6whmJsDFQyD4,10503
|
|
314
|
+
atomicshop-2.16.15.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
315
|
+
atomicshop-2.16.15.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
|
|
316
|
+
atomicshop-2.16.15.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|