raannakasturi commited on
Commit
a21cd42
·
verified ·
1 Parent(s): acccfce

Upload 15 files

Browse files
Files changed (15) hide show
  1. .gitattributes +35 -35
  2. .gitignore +8 -0
  3. acme_tools.py +71 -0
  4. app.py +81 -0
  5. dns_cf.py +62 -0
  6. genPVTCSR.py +82 -0
  7. gen_client_cnames.py +8 -0
  8. gen_records.py +45 -0
  9. getGoogleEAB.py +32 -0
  10. getTokenCert.py +87 -0
  11. getZeroSSLEAB.py +17 -0
  12. main.py +167 -0
  13. requirements.txt +6 -0
  14. tools.py +74 -0
  15. verify_txt.py +23 -0
.gitattributes CHANGED
@@ -1,35 +1,35 @@
1
- *.7z filter=lfs diff=lfs merge=lfs -text
2
- *.arrow filter=lfs diff=lfs merge=lfs -text
3
- *.bin filter=lfs diff=lfs merge=lfs -text
4
- *.bz2 filter=lfs diff=lfs merge=lfs -text
5
- *.ckpt filter=lfs diff=lfs merge=lfs -text
6
- *.ftz filter=lfs diff=lfs merge=lfs -text
7
- *.gz filter=lfs diff=lfs merge=lfs -text
8
- *.h5 filter=lfs diff=lfs merge=lfs -text
9
- *.joblib filter=lfs diff=lfs merge=lfs -text
10
- *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
- *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
- *.model filter=lfs diff=lfs merge=lfs -text
13
- *.msgpack filter=lfs diff=lfs merge=lfs -text
14
- *.npy filter=lfs diff=lfs merge=lfs -text
15
- *.npz filter=lfs diff=lfs merge=lfs -text
16
- *.onnx filter=lfs diff=lfs merge=lfs -text
17
- *.ot filter=lfs diff=lfs merge=lfs -text
18
- *.parquet filter=lfs diff=lfs merge=lfs -text
19
- *.pb filter=lfs diff=lfs merge=lfs -text
20
- *.pickle filter=lfs diff=lfs merge=lfs -text
21
- *.pkl filter=lfs diff=lfs merge=lfs -text
22
- *.pt filter=lfs diff=lfs merge=lfs -text
23
- *.pth filter=lfs diff=lfs merge=lfs -text
24
- *.rar filter=lfs diff=lfs merge=lfs -text
25
- *.safetensors filter=lfs diff=lfs merge=lfs -text
26
- saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
- *.tar.* filter=lfs diff=lfs merge=lfs -text
28
- *.tar filter=lfs diff=lfs merge=lfs -text
29
- *.tflite filter=lfs diff=lfs merge=lfs -text
30
- *.tgz filter=lfs diff=lfs merge=lfs -text
31
- *.wasm filter=lfs diff=lfs merge=lfs -text
32
- *.xz filter=lfs diff=lfs merge=lfs -text
33
- *.zip filter=lfs diff=lfs merge=lfs -text
34
- *.zst filter=lfs diff=lfs merge=lfs -text
35
- *tfevents* filter=lfs diff=lfs merge=lfs -text
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ .env
2
+ certificate*
3
+ /raanna*
4
+ /thenayankasturi*
5
+ /__pycache__
6
+ *.json
7
+ /venv
8
+ /error
acme_tools.py ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sys
2
+ import josepy as jose
3
+ from acme import messages, jose
4
+ from acme import client, messages
5
+ from cryptography.hazmat.primitives.asymmetric import rsa, ec
6
+ from cryptography.hazmat.backends import default_backend
7
+
8
+ def pg_client(directory, key_type="rsa", key_size=None, key_curve=None):
9
+ try:
10
+ if key_type.lower() == "rsa":
11
+ if key_size == "" or key_size == None:
12
+ key_size = 4096
13
+ rsa_key = rsa.generate_private_key(public_exponent=65537, key_size=key_size, backend=default_backend())
14
+ account_key = jose.JWKRSA(key=rsa_key)
15
+ net = client.ClientNetwork(account_key, user_agent='project-gatekeeper/v1.5')
16
+ directory_obj = messages.Directory.from_json(net.get(directory).json())
17
+ acme_client = client.ClientV2(directory_obj, net=net)
18
+ return acme_client
19
+ elif key_type.lower() == "ec":
20
+ if key_curve == "" or key_curve == None:
21
+ key_curve = "ec256"
22
+ if key_curve == 'SECP256R1' or key_curve == 'ec256':
23
+ ec_key = ec.generate_private_key(ec.SECP256R1(), default_backend())
24
+ algo=jose.ES256
25
+ elif key_curve == 'SECP384R1' or key_curve == 'ec384':
26
+ ec_key = ec.generate_private_key(ec.SECP384R1(), default_backend())
27
+ algo=jose.ES384
28
+ account_key = jose.JWKEC(key=ec_key)
29
+ net = client.ClientNetwork(account_key, alg=algo, user_agent='project-gatekeeper/v2')
30
+ response = net.get(directory)
31
+ directory_obj = messages.Directory.from_json(response.json())
32
+ acme_client = client.ClientV2(directory_obj, net=net)
33
+ return acme_client
34
+ else:
35
+ print("Invalid key_type")
36
+ return False
37
+ except:
38
+ print("Error in initialization")
39
+ return False
40
+
41
+ def new_account(pgclient, email, kid=None, hmac=None):
42
+ external_account_binding = None
43
+ if kid and hmac:
44
+ if isinstance(hmac, bytes):
45
+ hmac = hmac.decode('utf-8')
46
+ if not isinstance(hmac, str):
47
+ print("Error: HMAC is not a string after decoding.")
48
+ return False
49
+ try:
50
+ hmac_bytes = jose.b64.b64decode(hmac)
51
+ except Exception as e:
52
+ print(f"Error decoding HMAC key: {e}")
53
+ return False
54
+ hmac_key_b64 = jose.b64.b64encode(hmac_bytes).decode('utf-8')
55
+ external_account_binding = messages.ExternalAccountBinding.from_data(
56
+ account_public_key=pgclient.net.key,
57
+ kid=kid,
58
+ hmac_key=hmac_key_b64,
59
+ directory=pgclient.directory
60
+ )
61
+ registration = messages.NewRegistration.from_data(
62
+ email=email,
63
+ terms_of_service_agreed=True,
64
+ external_account_binding=external_account_binding
65
+ )
66
+ try:
67
+ account = pgclient.new_account(registration)
68
+ return account
69
+ except Exception as e:
70
+ print(f"Error creating account: {e}")
71
+ return False
app.py ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import sys
3
+ import gradio as gr
4
+ from main import main
5
+ from tools import write_file
6
+
7
+ def gen_ssl(i_domains, wildcard, email, ca_server, key_type, key_size=None, key_curve=None):
8
+ if key_type == "rsa":
9
+ key_curve = None
10
+ elif key_type == "ec":
11
+ key_size = None
12
+ else:
13
+ key_curve = None
14
+ if key_size is not None:
15
+ key_size = int(key_size)
16
+ pvt, csr, cert = main(i_domains, wildcard, email, ca_server, key_type, key_size, key_curve)
17
+ if email == "":
18
+ path = "error"
19
+ else:
20
+ path = email.split("@")[0]
21
+ try:
22
+ os.makedirs(path, exist_ok=True)
23
+ except:
24
+ print("Error creating directory")
25
+ write_file(f"{path}/private.pem", pvt)
26
+ write_file(f"{path}/domain.csr", csr)
27
+ write_file(f"{path}/cert.pem", cert)
28
+ try:
29
+ return pvt.decode('utf-8'), csr.decode('utf-8'), cert.decode('utf-8')
30
+ except:
31
+ return pvt, csr, cert
32
+
33
+ def update_key_options(key_type):
34
+ if key_type == "rsa":
35
+ return gr.update(visible=True), gr.update(visible=False)
36
+ else:
37
+ return gr.update(visible=False), gr.update(visible=True)
38
+
39
+ def update_ca_server(wildcard: bool):
40
+ if wildcard == False:
41
+ return gr.update(choices=["Let's Encrypt (Testing)","Let's Encrypt", "Buypass (Testing)", "Buypass", "ZeroSSL", "Google (Testing)","Google", "SSL.com"], value="Let's Encrypt (Testing)")
42
+ else:
43
+ return gr.update(choices=["Let's Encrypt (Testing)","Let's Encrypt", "ZeroSSL", "Google (Testing)","Google", "SSL.com"], value="Let's Encrypt")
44
+
45
+ def update_buypass_options(ca_server):
46
+ if ca_server == "Buypass (Testing)" or ca_server == "Buypass":
47
+ return gr.update(choices=['SECP256R1'])
48
+ else:
49
+ return gr.update(choices=['SECP256R1', 'SECP384R1'])
50
+
51
+ def app():
52
+ with gr.Blocks(title="Project Gatekeeper - Get free SSL Certificates") as webui:
53
+ with gr.Row():
54
+ with gr.Column():
55
+ domains_input = gr.Textbox(label="Enter Domains", placeholder="thenayankasturi.eu.org, dash.thenayankasturi.eu.org, www.thenayankasturi.eu.org", type="text", interactive=True)
56
+ wildcard = gr.Checkbox(label="Wildcard SSL", interactive=True, value=False)
57
+ email_input = gr.Textbox(label="Enter your Email ID", placeholder="[email protected]", type="text", interactive=True)
58
+ with gr.Row():
59
+ ca_server = gr.Dropdown(label="Select Certificate Authority", choices=["Let's Encrypt (Testing)","Let's Encrypt", "Google (Testing)","Google", "Buypass (Testing)", "Buypass", "ZeroSSL", "SSL.com"], interactive=True, value="Let's Encrypt (Testing)")
60
+ key_type = gr.Radio(label="Select SSL key type", choices=["rsa", "ec"], interactive=True, value='ec')
61
+ key_size_dropdown = gr.Dropdown(label="Select Key Size", choices=['2048', '4096'], value='4096', visible=False) # Initially visible
62
+ key_curve_dropdown = gr.Dropdown(label="Select Key Curve", choices=['SECP256R1', 'SECP384R1'], value='SECP256R1', visible=True) # Initially hidden
63
+ ca_server.change(fn=update_buypass_options, inputs=ca_server, outputs=key_curve_dropdown)
64
+ key_type.change(fn=update_key_options, inputs=key_type, outputs=[key_size_dropdown, key_curve_dropdown])
65
+ wildcard.change(fn=update_ca_server, inputs=wildcard, outputs=ca_server)
66
+ btn = gr.Button(value="Generate SSL Certificate")
67
+ with gr.Row():
68
+ with gr.Column():
69
+ pvt = gr.Textbox(label="Your Private Key", placeholder="Your Private Key will appear here, after successful SSL generation", type="text", interactive=False, show_copy_button=True, lines=10, max_lines=10)
70
+ with gr.Column():
71
+ csr = gr.Textbox(label="Your CSR", placeholder="Your CSR will appear here, after successful SSL generation", type="text", interactive=False, show_copy_button=True, lines=10, max_lines=10)
72
+ with gr.Column():
73
+ crt = gr.Textbox(label="Your SSL Certificate", placeholder="Your SSL Certificate will appear here, after successful SSL generation", type="text", interactive=False, show_copy_button=True, lines=10, max_lines=10)
74
+ btn.click(gen_ssl, inputs=[domains_input, wildcard, email_input, ca_server, key_type, key_size_dropdown, key_curve_dropdown], outputs=[pvt, csr, crt])
75
+ try:
76
+ webui.queue(default_concurrency_limit=15).launch()
77
+ except Exception as e:
78
+ print(f"Error: {e}")
79
+
80
+ if __name__ == "__main__":
81
+ app()
dns_cf.py ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ import os
3
+ from dotenv import load_dotenv
4
+
5
+ load_dotenv()
6
+ cf_token = os.environ.get("CF_TOKEN")
7
+ cf_zone_id = os.environ.get("CF_ZONE_ID")
8
+ cf_email = os.environ.get("CF_EMAIL_ID")
9
+ cf_api = "https://api.cloudflare.com/client/v4/"
10
+
11
+ headers = {
12
+ "Content-Type": "application/json",
13
+ "X-Auth-Email": cf_email,
14
+ "X-Auth-Key": cf_token
15
+ }
16
+
17
+ def check_txt():
18
+ cf_endpoint = f"zones/{cf_zone_id}/dns_records"
19
+ url = f"{cf_api}{cf_endpoint}"
20
+ response = requests.request("GET", url, headers=headers)
21
+ data = response.json()
22
+ record_ids = []
23
+ record_names = []
24
+ for record in data['result']:
25
+ if record['type'] == "TXT":
26
+ record_id = record['id']
27
+ record_name = record['name']
28
+ record_ids.append(record_id)
29
+ record_names.append(record_name)
30
+ else:
31
+ continue
32
+ return record_ids, record_names
33
+
34
+ def add_txt(txt_rec, txt_value, ssl_email):
35
+ cf_endpoint = f"zones/{cf_zone_id}/dns_records"
36
+ url = f"{cf_api}{cf_endpoint}"
37
+ name = txt_rec
38
+ data = {
39
+ "type": "TXT",
40
+ "name": name,
41
+ "content": txt_value,
42
+ "proxied": False,
43
+ "comment": f"SSL Verification for {ssl_email}"
44
+ }
45
+ response = requests.request("POST", url, headers=headers, json=data)
46
+ return response.json()
47
+
48
+ def del_txt(txt_name):
49
+ res = None
50
+ record_ids, record_names = check_txt()
51
+ for record_id, record_name in zip(record_ids, record_names):
52
+ if record_name.startswith(txt_name):
53
+ try:
54
+ cf_endpoint = f"zones/{cf_zone_id}/dns_records/{record_id}"
55
+ url = f"{cf_api}{cf_endpoint}"
56
+ requests.request("DELETE", url, headers=headers)
57
+ res = "records deleted"
58
+ except Exception as e:
59
+ res = f"Error deleting records: {e}"
60
+ else:
61
+ res = "records not found"
62
+ return res
genPVTCSR.py ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from cryptography.hazmat.primitives import serialization, hashes
2
+ from cryptography import x509
3
+ from cryptography.hazmat.primitives.asymmetric import ec, rsa
4
+ from cryptography.hazmat.backends import default_backend
5
+ from cryptography.x509.oid import NameOID
6
+ from typing import List, Tuple
7
+
8
+ def gen_pvt(key_type: str, key_size: int = None, key_curve: str = None) -> bytes:
9
+ if key_type.lower() == "ec":
10
+ if key_curve == 'SECP256R1' or key_curve == 'ec256':
11
+ key = ec.generate_private_key(ec.SECP256R1(), default_backend())
12
+ elif key_curve == 'SECP384R1' or key_curve == 'ec384':
13
+ key = ec.generate_private_key(ec.SECP384R1(), default_backend())
14
+ else:
15
+ key = ec.generate_private_key(ec.SECP256R1(), default_backend())
16
+ private_key = key.private_bytes(
17
+ encoding=serialization.Encoding.PEM,
18
+ format=serialization.PrivateFormat.TraditionalOpenSSL,
19
+ encryption_algorithm=serialization.NoEncryption()
20
+ )
21
+ elif key_type.lower() == "rsa":
22
+ if key_size not in [2048, 4096]:
23
+ key_size = 4096
24
+ key = rsa.generate_private_key(
25
+ public_exponent=65537,
26
+ key_size=key_size,
27
+ backend=default_backend()
28
+ )
29
+ private_key = key.private_bytes(
30
+ encoding=serialization.Encoding.PEM,
31
+ format=serialization.PrivateFormat.TraditionalOpenSSL,
32
+ encryption_algorithm=serialization.NoEncryption()
33
+ )
34
+ else:
35
+ raise ValueError("Unsupported key type or parameters")
36
+ return private_key
37
+
38
+ def gen_csr(private_key: bytes, domains: List[str], email: str, common_name: str = None, country: str = None,
39
+ state: str = None, locality: str = None, organization: str = None, organization_unit: str = None) -> bytes:
40
+
41
+ ssl_domains = [x509.DNSName(domain.strip()) for domain in domains]
42
+ private_key_obj = serialization.load_pem_private_key(private_key, password=None, backend=default_backend())
43
+ try:
44
+ if email.split("@")[1] in ["demo.com", "example.com"] or email.count("@") > 1 or email.count(".") < 1 or email is None:
45
+ print("Invalid email address")
46
+ email = f"admin@{domains[0]}"
47
+ except Exception as e:
48
+ print(f"Error in email address: {e}")
49
+ email = f"admin@{domains[0]}"
50
+ country: str = country or "IN"
51
+ state: str = state or "Maharashtra"
52
+ locality: str = locality or "Mumbai"
53
+ organization_unit: str = organization_unit or "IT Department"
54
+ common_name: str = common_name or domains[0]
55
+ organization: str = organization or common_name.split(".")[0]
56
+ subject = x509.Name([
57
+ x509.NameAttribute(NameOID.COUNTRY_NAME, country),
58
+ x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, state),
59
+ x509.NameAttribute(NameOID.LOCALITY_NAME, locality),
60
+ x509.NameAttribute(NameOID.EMAIL_ADDRESS, email),
61
+ x509.NameAttribute(NameOID.ORGANIZATION_NAME, organization),
62
+ x509.NameAttribute(NameOID.ORGANIZATIONAL_UNIT_NAME, organization_unit),
63
+ x509.NameAttribute(NameOID.COMMON_NAME, common_name),
64
+ ])
65
+ builder = x509.CertificateSigningRequestBuilder()
66
+ builder = builder.subject_name(subject)
67
+ builder = builder.add_extension(
68
+ x509.SubjectAlternativeName(ssl_domains),
69
+ critical=False,
70
+ )
71
+ csr = builder.sign(private_key_obj, hashes.SHA256(), default_backend())
72
+ return csr.public_bytes(serialization.Encoding.PEM)
73
+
74
+ def gen_pvt_csr(domains: List[str], key_type: str, key_size: int = None, key_curve: str = None, email: str = None,
75
+ common_name: str = None, country: str = None, state: str = None, locality: str = None,
76
+ organization: str = None, organization_unit: str = None) -> Tuple[bytes, bytes]:
77
+ if key_type.lower() == "rsa":
78
+ private_key = gen_pvt(key_type, key_size)
79
+ else:
80
+ private_key = gen_pvt(key_type, key_curve)
81
+ csr = gen_csr(private_key, domains, email, common_name, country, state, locality, organization, organization_unit)
82
+ return private_key, csr
gen_client_cnames.py ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ from gen_records import gen_cname
2
+ from tools import get_domains, extract_subdomains
3
+
4
+ def gen_client_cnames(i_domains, cf_domain):
5
+ domains = get_domains(i_domains)
6
+ exchange = extract_subdomains(domains=domains)
7
+ cname_recs, cname_values = gen_cname(domains, cf_domain, exchange)
8
+ return cname_recs, cname_values
gen_records.py ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import hashlib
2
+
3
+ def get_domains(i_domains):
4
+ domains = []
5
+ for domain in i_domains.split(","):
6
+ domain = domain.strip()
7
+ domains.append(domain)
8
+ return domains
9
+
10
+ def prefix(domain):
11
+ domain_bytes = domain.encode()
12
+ prefix = hashlib.blake2b(domain_bytes, digest_size=12).hexdigest()
13
+ return prefix
14
+
15
+ def gen_cname_recs(domains):
16
+ cname_recs = []
17
+ for domain in domains:
18
+ cname_rec = f"_acme-challenge.{domain}"
19
+ cname_recs.append(cname_rec)
20
+ return cname_recs
21
+
22
+ def gen_cname_values(domains, cf_domain, exchange):
23
+ temp_cname_values = []
24
+ cname_values = []
25
+ for domain in domains:
26
+ cname_value = prefix(domain)
27
+ cname_value = f"{cname_value}.{domain}"
28
+ temp_cname_values.append(cname_value)
29
+ for cname_value in temp_cname_values:
30
+ modified_cname_value = cname_value.replace(exchange, cf_domain)
31
+ cname_values.append(modified_cname_value)
32
+ return cname_values
33
+
34
+ def gen_cname(domains, cf_domain, exchange):
35
+ cname_recs = gen_cname_recs(domains)
36
+ cname_values = gen_cname_values(domains, cf_domain, exchange)
37
+ return cname_recs, cname_values
38
+
39
+ def txt_recs(txt_records, exchange):
40
+ txt_record = txt_records.replace("_acme-challenge.", "")
41
+ txt_rec = txt_record.replace(f"{exchange}", "")
42
+ pre = prefix(txt_record)
43
+ rec = f"{pre}.{txt_rec}"
44
+ rec = rec.strip(".")
45
+ return rec
getGoogleEAB.py ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from dotenv import load_dotenv
3
+ from google.oauth2 import service_account
4
+ from google.cloud.security.publicca import PublicCertificateAuthorityServiceClient
5
+
6
+ def gen_google_eab_data():
7
+ load_dotenv()
8
+ data = {
9
+ "type": "service_account",
10
+ "project_id": os.getenv("PROJECT_ID"),
11
+ "private_key_id": os.getenv("PRIVATE_KEY_ID"),
12
+ "private_key": os.getenv("PRIVATE_KEY"),
13
+ "client_email": os.getenv("CLIENT_EMAIL"),
14
+ "client_id": os.getenv("CLIENT_ID"),
15
+ "auth_uri": os.getenv("AUTH_URI"),
16
+ "token_uri": os.getenv("TOKEN_URI"),
17
+ "auth_provider_x509_cert_url": os.getenv("AUTH_PROVIDER_X509_CERT_URL"),
18
+ "client_x509_cert_url": os.getenv("CLIENT_X509_CERT_URL"),
19
+ "universe_domain": os.getenv("UNIVERSE_DOMAIN")
20
+ }
21
+ return data
22
+
23
+ def gen_google_eab():
24
+ service_account_info = gen_google_eab_data()
25
+ credentials = service_account.Credentials.from_service_account_info(service_account_info)
26
+ client = PublicCertificateAuthorityServiceClient(credentials=credentials)
27
+ project_id = service_account_info['project_id']
28
+ parent = f"projects/{project_id}"
29
+ response = client.create_external_account_key(parent=parent)
30
+ kid = response.key_id
31
+ hmac = response.b64_mac_key
32
+ return kid, hmac
getTokenCert.py ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import datetime
2
+ from acme import errors, challenges
3
+
4
+ def challens(order, directory) -> dict:
5
+ challs = {}
6
+ for auth in list(order.authorizations):
7
+ for challenge in auth.body.challenges:
8
+ if isinstance(challenge.chall, challenges.DNS01):
9
+ domain = auth.body.identifier.value
10
+ challs[domain] = challs[domain] if domain in challs else []
11
+ challs[domain].append(challenge)
12
+ if not challs:
13
+ msg = f"ACME server at '{directory}' does not support DNS-01 challenge."
14
+ raise errors.ChallengeUnavailable(msg.format(directory=str(directory)))
15
+ return challs
16
+
17
+ def get_tokens(client, csr, directory):
18
+ verification_tokens = {}
19
+ responses = {}
20
+ order = client.new_order(csr)
21
+ challs = challens(order, directory)
22
+ for domain, challenge_items in challs.items():
23
+ domain = f"_acme-challenge.{domain}"
24
+ for challenge in challenge_items:
25
+ verification_tokens[domain] = verification_tokens[domain] if domain in verification_tokens else []
26
+ response, validation = challenge.response_and_validation(client.net.key)
27
+ verification_tokens[domain].append(validation)
28
+ responses[challenge.chall.token] = response
29
+ _verification_tokens = verification_tokens
30
+ return verification_tokens, challs, order
31
+
32
+ def process_challenge(client, challenge, domain):
33
+ try:
34
+ response, _validation = challenge.response_and_validation(client.net.key)
35
+ print(f"Challenge verified for domain: {domain}")
36
+ token = challenge.chall.token
37
+ if isinstance(token, bytes):
38
+ token = token.decode('utf-8', errors='replace')
39
+ return response, token
40
+ except Exception as e:
41
+ print(f"Error processing challenge for domain {domain}: {e}")
42
+ return None, None
43
+
44
+ def answer_challenge(client, challenge, response, domain):
45
+ try:
46
+ answer = client.answer_challenge(challenge, response)
47
+ print(f"Challenge answered for domain: {domain}")
48
+ return answer
49
+ except Exception as e:
50
+ print(f"Error answering challenge for domain {domain}: {e}")
51
+ return None
52
+
53
+ def finalize_order(client, order, deadline):
54
+ try:
55
+ data = client.poll_and_finalize(order, deadline=deadline)
56
+ return data
57
+ except Exception as e:
58
+ data = client.poll_and_finalize(order, deadline=deadline)
59
+ print(f"Error finalizing order: {e}")
60
+ return None
61
+
62
+ def retrieve_certificate(final_order):
63
+ try:
64
+ return final_order.fullchain_pem.encode()
65
+ except Exception as e:
66
+ print(f"Error retrieving certificate: {e}")
67
+ return None
68
+
69
+ def verify_tokens(client, challs, order):
70
+ deadline = datetime.datetime.now() + datetime.timedelta(seconds=180)
71
+ answers = []
72
+ responses = {}
73
+ for domain, challenge_list in challs.items():
74
+ print(f"Fetching challenges for domain: {domain}")
75
+ for challenge in challenge_list:
76
+ response, token = process_challenge(client, challenge, domain)
77
+ if response is None:
78
+ continue
79
+ responses[token] = response
80
+ answer = answer_challenge(client, challenge, response, domain)
81
+ if answer is not None:
82
+ answers.append(answer)
83
+ final_order = finalize_order(client, order, deadline)
84
+ if final_order is None:
85
+ return None
86
+ cert = retrieve_certificate(final_order)
87
+ return cert
getZeroSSLEAB.py ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ import os
3
+ from dotenv import load_dotenv
4
+
5
+ def gen_zero_ssl_eab():
6
+ load_dotenv()
7
+ apikey = os.getenv("ZEROSSLAPI")
8
+ url = "https://api.zerossl.com/acme/eab-credentials"
9
+ headers = {'Content-Type': 'application/json'}
10
+ resp = requests.post(url, params={'access_key': apikey}, headers=headers)
11
+ if resp.json()['success'] == False:
12
+ print("Error: ", resp.json()['error'])
13
+ return "Error", "Error"
14
+ else:
15
+ kid = resp.json()['eab_kid']
16
+ hmac = resp.json()['eab_hmac_key']
17
+ return kid, hmac
main.py ADDED
@@ -0,0 +1,167 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import re
2
+ import sys
3
+ import time
4
+ from genPVTCSR import gen_pvt_csr
5
+ from tools import get_domains, get_ca_server, get_kid_hmac, extract_subdomains
6
+ from acme_tools import pg_client, new_account
7
+ from getTokenCert import get_tokens, verify_tokens
8
+ from gen_records import txt_recs
9
+ from dns_cf import add_txt, del_txt
10
+ from verify_txt import verify_txt
11
+
12
+ def cf_non_wildcard(verification_tokens, email, exchange):
13
+ tokens = verification_tokens
14
+ for key, value in tokens.items():
15
+ txt_rec = txt_recs(key, exchange)
16
+ txt_value = value[0].strip()
17
+ try:
18
+ del_txt(txt_rec)
19
+ except Exception as e:
20
+ print(f"Error deleting TXT records or no TXT records exists: {e}")
21
+ add_txt(txt_rec, txt_value, ssl_email=email)
22
+
23
+ def cf_wildcard(verification_tokens, email, exchange):
24
+ tokens = verification_tokens
25
+ for key, value in tokens.items():
26
+ txt_rec = txt_recs(key, exchange)
27
+ try:
28
+ del_txt(txt_rec)
29
+ except Exception as e:
30
+ print(f"Error deleting TXT records or no TXT records exists: {e}")
31
+ for txt_value in value:
32
+ add_txt(txt_rec, txt_value, ssl_email=email)
33
+
34
+ def verify_email(email):
35
+ pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
36
+ return re.match(pattern, email)
37
+
38
+ def validate_domains(i_domains):
39
+ domains = []
40
+ try:
41
+ domains = get_domains(i_domains)
42
+ except:
43
+ domains = i_domains
44
+ pattern = r'^[a-zA-Z0-9][a-zA-Z0-9-]{1,61}[a-zA-Z0-9](?:\.[a-zA-Z]{2,})+$'
45
+ for domain in domains:
46
+ if re.match(pattern, domain):
47
+ continue
48
+ else:
49
+ return False
50
+ return True
51
+
52
+ def verify_txt_records(verification_tokens, exchange):
53
+ tokens = verification_tokens
54
+ for key, value in tokens.items():
55
+ txt_rec = key
56
+ txt_value = value[0].strip()
57
+ if not verify_txt(txt_rec, txt_value):
58
+ return False
59
+ else:
60
+ continue
61
+ return True
62
+
63
+ def handle_error(message):
64
+ err = f"Error: {message}"
65
+ return err, err, err
66
+
67
+ def main(i_domains, wildcard, email, ca_server, key_type, key_size=None, key_curve=None, kid=None, hmac=None):
68
+ if i_domains == "":
69
+ print("domain", i_domains)
70
+ return handle_error("No domain provided")
71
+ elif not validate_domains(i_domains):
72
+ print("domain", i_domains)
73
+ return handle_error("Invalid domains provided")
74
+ else:
75
+ print("domain", i_domains)
76
+ if email == "":
77
+ print("email", email)
78
+ return handle_error("No email provided")
79
+ elif not verify_email(email):
80
+ print("email", email)
81
+ return handle_error("Invalid email provided")
82
+ else:
83
+ print("email", email)
84
+ if ca_server == "":
85
+ print("ca", ca_server)
86
+ return handle_error("No CA server provided")
87
+ else:
88
+ print("ca", ca_server)
89
+ if key_type == "":
90
+ print("key type", key_type)
91
+ return handle_error("No key type provided")
92
+ else:
93
+ print("key type", key_type)
94
+ if key_curve == "":
95
+ print("size", key_size)
96
+ print("curve", key_curve)
97
+ return handle_error("No key size or curve provided")
98
+ else:
99
+ print("size", key_size)
100
+ print("curve", key_curve)
101
+ print("All data filled")
102
+
103
+ domains = get_domains(i_domains)
104
+ exchange = extract_subdomains(domains=domains)
105
+ if wildcard:
106
+ domains = [exchange, f'*.{exchange}']
107
+ ca_server_url = get_ca_server(ca_server, key_type)
108
+ pgk_client = pg_client(ca_server_url, key_type=key_type, key_size=key_size, key_curve=key_curve)
109
+ if pgk_client is None:
110
+ return handle_error("Cannot create client access")
111
+ nkid, nhmac = get_kid_hmac(ca_server)
112
+ if nkid == 'Error' or nhmac == 'Error':
113
+ return handle_error("Try with another provider or contact us")
114
+ kid = nkid
115
+ hmac = nhmac
116
+ account = new_account(pgk_client, email, kid=kid, hmac=hmac)
117
+ if not account:
118
+ return handle_error("Cannot generate your SSL. Too many requests for this domain.")
119
+ private_key, csr = gen_pvt_csr(domains=domains, email=email, key_type=key_type, key_curve=key_curve, key_size=key_size)
120
+ verification_tokens, challs, order = get_tokens(pgk_client, csr, ca_server_url)
121
+ try:
122
+ if wildcard:
123
+ cf_wildcard(verification_tokens, email, exchange)
124
+ else:
125
+ cf_non_wildcard(verification_tokens, email, exchange)
126
+ except Exception as e:
127
+ print(f"Error adding TXT records: {e}")
128
+ # verify TXT
129
+ '''
130
+ for i in range(60):
131
+ print(f"Waiting for {60-i} seconds", end="\r")
132
+ time.sleep(1)
133
+ '''
134
+ while not verify_txt_records(verification_tokens, exchange):
135
+ print("TXT records not verified yet")
136
+ time.sleep(5)
137
+ cert = verify_tokens(pgk_client, challs, order)
138
+ for key in verification_tokens:
139
+ txt_rec = txt_recs(key, exchange)
140
+ try:
141
+ del_txt(txt_rec)
142
+ print("TXT records deleted successfully")
143
+ except Exception as e:
144
+ print(f"Error deleting TXT records or no TXT records exist: {e}")
145
+ private_key = private_key.decode("utf-8")
146
+ csr = csr.decode("utf-8")
147
+ cert = cert.decode("utf-8")
148
+ return private_key, csr, cert
149
+
150
+ if __name__ == "__main__":
151
+ DOMAINS = 'raannakasturi.eu.org'
152
+ ca_server = "Google" #Let's Encrypt (Testing), Let's Encrypt, Google (Testing), Google, Buypass (Testing), Buypass, ZeroSSL, SSL.com
153
+ EMAIL = "[email protected]"
154
+ key_type = "ec"
155
+ key_curve = "ec384"
156
+ key_size = None
157
+ KID = None
158
+ HMAC = None
159
+ private_key, csr, cert = main(i_domains=DOMAINS, wildcard=True, email=EMAIL, ca_server=ca_server, key_type=key_type, key_size=key_size,key_curve=key_curve, kid=KID, hmac=HMAC)
160
+ print("Private Key:")
161
+ print(private_key)
162
+ print()
163
+ print("CSR:")
164
+ print(csr)
165
+ print()
166
+ print("Certificate:")
167
+ print(cert)
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ josepy==1.14.0
2
+ python-dotenv
3
+ acme==2.11.0
4
+ google-cloud-public-ca==0.3.9
5
+ gradio==4.41.0
6
+ dnspython==2.6.1
tools.py ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+
3
+ from getGoogleEAB import gen_google_eab
4
+ from getZeroSSLEAB import gen_zero_ssl_eab
5
+
6
+
7
+ def get_domains(i_domains):
8
+ domains = []
9
+ for domain in i_domains.split(","):
10
+ domain = domain.strip()
11
+ domains.append(domain)
12
+ return domains
13
+
14
+ def extract_subdomains(domains):
15
+ exchange = min(domains, key=len)
16
+ return exchange
17
+
18
+ def get_ca_server(caserver, key_type):
19
+ DEFAULT_LET_ENCRYPT_URL = "https://acme-v02.api.letsencrypt.org/directory"
20
+ urls = {
21
+ "SSL.com": {
22
+ "rsa": "https://acme.ssl.com/sslcom-dv-rsa",
23
+ "ec": "https://acme.ssl.com/sslcom-dv-ecc"
24
+ },
25
+ "Let's Encrypt (Testing)": "https://acme-staging-v02.api.letsencrypt.org/directory",
26
+ "Let's Encrypt": DEFAULT_LET_ENCRYPT_URL,
27
+ "Buypass (Testing)": "https://api.test4.buypass.no/acme/directory",
28
+ "Buypass": "https://api.Buypass.com/acme/directory",
29
+ "ZeroSSL": "https://acme.zerossl.com/v2/DV90",
30
+ "Google (Testing)": "https://dv.acme-v02.test-api.pki.goog/directory",
31
+ "Google": "https://dv.acme-v02.api.pki.goog/directory"
32
+ }
33
+ if caserver in urls:
34
+ if isinstance(urls[caserver], dict):
35
+ return urls[caserver].get(key_type, DEFAULT_LET_ENCRYPT_URL)
36
+ else:
37
+ return urls[caserver]
38
+ return DEFAULT_LET_ENCRYPT_URL
39
+
40
+ def get_kid_hmac(server):
41
+ if server == "SSL.com":
42
+ return None, None
43
+ elif server == "Let's Encrypt (Testing)":
44
+ return None, None
45
+ elif server == "Let's Encrypt":
46
+ return None, None
47
+ elif server == "Buypass (Testing)":
48
+ return None, None
49
+ elif server == "Buypass":
50
+ return None, None
51
+ elif server == "ZeroSSL":
52
+ kid, hmac = gen_zero_ssl_eab()
53
+ return kid, hmac
54
+ elif server == "Google (Testing)":
55
+ kid, hmac = gen_google_eab()
56
+ return kid, hmac
57
+ elif server == "Google":
58
+ kid, hmac = gen_google_eab()
59
+ return kid, hmac
60
+ else:
61
+ return None, None
62
+
63
+ def write_file(filename, data):
64
+ try:
65
+ try:
66
+ with open(filename, 'wb') as f:
67
+ f.write(data)
68
+ except:
69
+ with open(filename, 'w') as f:
70
+ f.write(data)
71
+ print(filename, " successfully written")
72
+ except Exception as e:
73
+ print("Error writing file: ", filename)
74
+ print(e)
verify_txt.py ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from dns import resolver
2
+
3
+ def get_txt(rec):
4
+ redirect_domain = None
5
+ try:
6
+ txt_answers = resolver.resolve(rec, 'TXT')
7
+ for answer in txt_answers:
8
+ txt_record = answer.to_text().rstrip(".")
9
+ if txt_record.startswith('_acme-challenge'):
10
+ redirect_domain = txt_record.split('.')[-1]
11
+ else:
12
+ redirect_domain = txt_record
13
+ return redirect_domain.strip('"').strip('.')
14
+ except Exception as e:
15
+ print(f"An error occurred while resolving {rec}: {e}")
16
+ return redirect_domain
17
+
18
+ def verify_txt(rec, expected):
19
+ found = get_txt(rec)
20
+ if found == expected:
21
+ return True
22
+ else:
23
+ return False