certapi 0.1.0__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.
certapi/crypto.py ADDED
@@ -0,0 +1,222 @@
1
+ from typing import List, Union
2
+
3
+ from cryptography.hazmat.backends import default_backend
4
+ from cryptography.hazmat.primitives import serialization
5
+ from cryptography.hazmat.primitives.asymmetric import rsa, ec, padding, ed25519
6
+ from cryptography import x509
7
+ from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePrivateKey
8
+ from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
9
+ from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey
10
+ from cryptography.x509 import Certificate, CertificateSigningRequestBuilder, CertificateSigningRequest
11
+
12
+ from cryptography.x509.oid import NameOID
13
+ from cryptography.hazmat.primitives import hashes
14
+ import datetime
15
+
16
+ from .util import b64_encode, b64_string
17
+
18
+ __no_enc = serialization.NoEncryption()
19
+
20
+
21
+ def gen_key_rsa(key_size=4096):
22
+ return rsa.generate_private_key(public_exponent=65537, key_size=key_size)
23
+
24
+
25
+ def gen_key_secp256r1():
26
+ curve = ec.SECP256R1()
27
+ return ec.generate_private_key(curve, default_backend())
28
+
29
+
30
+ def gen_key_ed25519():
31
+ return ed25519.Ed25519PrivateKey.generate()
32
+
33
+
34
+ def get_algorithm_name(key):
35
+ if isinstance(key, RSAPrivateKey):
36
+ return "RS256"
37
+ elif isinstance(key, Ed25519PrivateKey):
38
+ return "EdDSA"
39
+ elif isinstance(key, ec.EllipticCurvePrivateKey):
40
+ curve_name = key.curve.name
41
+ if curve_name == "secp256r1":
42
+ return "ES256"
43
+ elif curve_name == "secp384r1":
44
+ return "ES384"
45
+ elif curve_name == "secp521r1":
46
+ return "ES512"
47
+ else:
48
+ raise ValueError("Unsupported key type")
49
+
50
+
51
+ def jwk(key: Union[RSAPrivateKey, Ed25519PrivateKey, EllipticCurvePrivateKey]):
52
+ if isinstance(key, RSAPrivateKey):
53
+ return jwk_rsa(key)
54
+ elif isinstance(key, Ed25519PrivateKey):
55
+ return jwk_ed25519(key)
56
+ elif isinstance(key, EllipticCurvePrivateKey):
57
+ return jwk_secp256r1(key)
58
+
59
+
60
+ def jwk_ed25519(private_key: Ed25519PrivateKey):
61
+ public_key_bytes = private_key.public_key().public_bytes(
62
+ encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw
63
+ )
64
+ # Create the JWK for the Ed25519 public key
65
+ return {"crv": "Ed25519", "kty": "OKP", "x": b64_string(public_key_bytes)}
66
+
67
+
68
+ def jwk_secp256r1(key: ec.EllipticCurvePrivateKey):
69
+
70
+ numbers = key.public_key().public_numbers()
71
+
72
+ # Create a JSON Web Key (JWK) representation of the public key
73
+ return {
74
+ "kty": "EC",
75
+ "crv": "P-256",
76
+ "x": b64_string(numbers.x.to_bytes(32, "big")),
77
+ "y": b64_string(numbers.y.to_bytes(32, "big")),
78
+ }
79
+
80
+
81
+ def jwk_rsa(account_key: RSAPrivateKey):
82
+ public = account_key.public_key().public_numbers()
83
+ # json web key format for public key
84
+ return {
85
+ "e": b64_string((public.e).to_bytes((public.e.bit_length() + 7) // 8, "big")),
86
+ "kty": "RSA",
87
+ "n": b64_string((public.n).to_bytes((public.n.bit_length() + 7) // 8, "big")),
88
+ }
89
+
90
+
91
+ def key_from_der(bytes):
92
+ return serialization.load_der_private_key(bytes, None)
93
+
94
+
95
+ def key_from_pem(data: bytes):
96
+ return serialization.load_pem_private_key(data, None)
97
+
98
+
99
+ def cert_from_pem(data: bytes) -> Certificate:
100
+ return x509.load_pem_x509_certificate(data)
101
+
102
+
103
+ def cert_to_pem(cert):
104
+ return cert.public_bytes(serialization.Encoding.PEM)
105
+
106
+
107
+ def cert_from_der(data: bytes) -> Certificate:
108
+ return x509.load_der_x509_certificate(data)
109
+
110
+
111
+ def key_to_pem(key: RSAPrivateKey):
112
+ return key.private_bytes(
113
+ serialization.Encoding.PEM, serialization.PrivateFormat.PKCS8, serialization.NoEncryption()
114
+ )
115
+
116
+
117
+ def csr_to_pem(csr) -> bytes:
118
+ return csr.public_bytes(serialization.Encoding.PEM)
119
+
120
+
121
+ def csr_to_der(csr) -> bytes:
122
+ return csr.public_bytes(serialization.Encoding.DER)
123
+
124
+
125
+ def sign(key: Union[RSAPrivateKey, Ed25519PrivateKey, EllipticCurvePrivateKey], message, hasher=hashes.SHA256()):
126
+ # return key.sign(message,padding.PSS(mgf=padding.(hashes.SHA256()),salt_length=padding.PSS.MAX_LENGTH),hashes.SHA256())
127
+ if isinstance(key, RSAPrivateKey):
128
+ return key.sign(message, padding.PKCS1v15(), hasher)
129
+ elif isinstance(key, Ed25519PrivateKey):
130
+ return key.sign(message)
131
+ elif isinstance(key, EllipticCurvePrivateKey):
132
+ return key.sign(message, ec.ECDSA(hasher))
133
+
134
+
135
+ def sign_jws(key: RSAPrivateKey, data: object):
136
+ pass
137
+
138
+
139
+ def key_to_der(key: [RSAPrivateKey, Ed25519PrivateKey, EllipticCurvePrivateKey]) -> bytes:
140
+ return key.private_bytes(
141
+ encoding=serialization.Encoding.DER, format=serialization.PrivateFormat.PKCS8, encryption_algorithm=__no_enc
142
+ )
143
+
144
+
145
+ def create_csr(
146
+ private_key: Union[RSAPrivateKey, Ed25519PrivateKey, EllipticCurvePrivateKey],
147
+ main_domain: str,
148
+ alternatives: List[str] = None,
149
+ ) -> CertificateSigningRequest:
150
+ subject = x509.Name(
151
+ [
152
+ # Provide various details about who we are.
153
+ x509.NameAttribute(NameOID.COUNTRY_NAME, "NP"),
154
+ x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, "Bagmati"),
155
+ x509.NameAttribute(NameOID.LOCALITY_NAME, "Kathmandu"),
156
+ x509.NameAttribute(NameOID.ORGANIZATION_NAME, "Sireto Technology"),
157
+ x509.NameAttribute(NameOID.COMMON_NAME, main_domain),
158
+ ]
159
+ )
160
+ builder = x509.CertificateSigningRequestBuilder().subject_name(subject)
161
+ if alternatives is not None:
162
+ builder = builder.add_extension(
163
+ x509.SubjectAlternativeName([x509.DNSName(alt) for alt in alternatives]), critical=True
164
+ )
165
+ return builder.sign(private_key, hashes.SHA256())
166
+
167
+
168
+ def self_sign():
169
+ key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
170
+ csr = create_csr(key, "host4.sireto.dev", []).sign(key, hashes.SHA256())
171
+ with open("test.csr", "wb") as f:
172
+ f.write(csr_to_pem(csr))
173
+
174
+ # Various details about who we are. For a self-signed certificate the
175
+ # subject and issuer are always the same.
176
+ subject = issuer = x509.Name(
177
+ [
178
+ x509.NameAttribute(NameOID.COUNTRY_NAME, "US"),
179
+ x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, "California"),
180
+ x509.NameAttribute(NameOID.LOCALITY_NAME, "San Francisco"),
181
+ x509.NameAttribute(NameOID.ORGANIZATION_NAME, "My Company"),
182
+ x509.NameAttribute(NameOID.COMMON_NAME, "domain3.sireto.dev"),
183
+ ]
184
+ )
185
+ now = datetime.datetime.utcnow()
186
+ cert = (
187
+ x509.CertificateBuilder()
188
+ .subject_name(subject)
189
+ .issuer_name(issuer)
190
+ .public_key(key.public_key())
191
+ .serial_number(x509.random_serial_number())
192
+ .not_valid_before(now)
193
+ .not_valid_after(now + datetime.timedelta(days=10))
194
+ .add_extension(
195
+ x509.SubjectAlternativeName([x509.DNSName("localhost")]),
196
+ critical=False,
197
+ # Sign our certificate with our private key
198
+ )
199
+ .sign(key, hashes.SHA256())
200
+ )
201
+ # Write our certificate out to disk.
202
+
203
+ with open("certificate.pem", "wb") as f:
204
+ f.write(cert.public_bytes(serialization.Encoding.PEM))
205
+
206
+ # getting public key from certificate.
207
+ public_key = cert.public_key()
208
+ if isinstance(public_key, rsa.RSAPublicKey):
209
+ # Do something RSA specific
210
+ pass
211
+ elif isinstance(public_key, ec.EllipticCurvePublicKey):
212
+ # Do something EC specific
213
+ pass
214
+ else:
215
+ # Remember to handle this case
216
+ pass
217
+
218
+
219
+ def digest_sha256(data: bytes) -> bytes:
220
+ h = hashes.Hash(hashes.SHA256())
221
+ h.update(data)
222
+ return h.finalize()
@@ -0,0 +1,135 @@
1
+ from abc import ABC, abstractmethod
2
+ from cryptography.hazmat.primitives.asymmetric import rsa, ed25519, ec
3
+ from cryptography.hazmat.primitives import serialization, hashes, hmac, padding
4
+ from typing import Union
5
+
6
+ from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
7
+
8
+ from .crypto import key_to_der, key_to_pem
9
+ from .util import b64_string
10
+
11
+
12
+ class Key(ABC):
13
+ @abstractmethod
14
+ def jwk(self):
15
+ pass
16
+
17
+ @abstractmethod
18
+ def sign(self, message):
19
+ pass
20
+
21
+ @abstractmethod
22
+ def sign_csr(self, csr):
23
+ pass
24
+
25
+ @staticmethod
26
+ def from_der(der_bytes):
27
+ key = serialization.load_der_private_key(der_bytes, password=None)
28
+ if isinstance(key, rsa.RSAPrivateKey):
29
+ return RSAKey(key)
30
+ elif isinstance(key, ec.EllipticCurvePrivateKey):
31
+ return ECDSAKey(key)
32
+ elif isinstance(key, Ed25519PrivateKey):
33
+ return Ed25519Key(key)
34
+ else:
35
+ raise ValueError("Unsupported key type")
36
+
37
+ @staticmethod
38
+ def from_pem(der_bytes):
39
+ key = serialization.load_pem_private_key(der_bytes, password=None)
40
+ if isinstance(key, rsa.RSAPrivateKey):
41
+ return RSAKey(key)
42
+ elif isinstance(key, ec.EllipticCurvePrivateKey):
43
+ return ECDSAKey(key)
44
+ elif isinstance(key, Ed25519PrivateKey):
45
+ return Ed25519Key(key)
46
+ else:
47
+ raise ValueError("Unsupported key type")
48
+
49
+ def to_der(self) -> bytes:
50
+ return key_to_der(self.key)
51
+
52
+ def to_pem(self) -> bytes:
53
+ return key_to_pem(self.key)
54
+
55
+
56
+ class RSAKey(Key):
57
+ def __init__(self, key: rsa.RSAPrivateKey, hasher=hashes.SHA256()):
58
+ self.key = key
59
+ self.hasher = hasher
60
+
61
+ def jwk(self):
62
+ public = self.key.public_key().public_numbers()
63
+ return {
64
+ "e": b64_string((public.e).to_bytes((public.e.bit_length() + 7) // 8, "big")),
65
+ "kty": "RSA",
66
+ "n": b64_string((public.n).to_bytes((public.n.bit_length() + 7) // 8, "big")),
67
+ }
68
+
69
+ def sign(self, message):
70
+ return self.key.sign(message, padding.PKCS1v15(), self.hasher)
71
+
72
+ def sign_csr(self, csr):
73
+ return csr.sign(self.key, self.hasher)
74
+
75
+ def algorithm_name(self):
76
+ return "RS" + str(self.hasher.digest_size * 8)
77
+
78
+
79
+ class Ed25519Key(Key):
80
+
81
+ def __init__(self, key: ed25519.Ed25519PrivateKey):
82
+ self.key = key
83
+ self.keyid = "e"
84
+ public = self.key.public_key().public_bytes(
85
+ encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw
86
+ )
87
+ self.jwk = {
88
+ "crv": "Ed25519",
89
+ "kty": "OKP",
90
+ "x": b64_string(public),
91
+ }
92
+
93
+ def jwk(self):
94
+ return self.jwk
95
+
96
+ def sign(self, message):
97
+ return self.key.sign(message)
98
+
99
+ def sign_csr(self, csr):
100
+ return csr.sign(self.key, hashes.SHA256())
101
+
102
+
103
+ class ECDSAKey(Key):
104
+
105
+ def __init__(self, key: ec.EllipticCurvePrivateKey):
106
+ self.key = key
107
+ public_key = self.key.public_key()
108
+ public_numbers = public_key.public_numbers()
109
+ self.jwk = {
110
+ "kty": "EC",
111
+ "crv": self.key.curve.name,
112
+ "x": b64_string(public_numbers.x.to_bytes((public_numbers.x.bit_length() + 7) // 8, "big")),
113
+ "y": b64_string(public_numbers.y.to_bytes((public_numbers.y.bit_length() + 7) // 8, "big")),
114
+ }
115
+
116
+ def jwk(self):
117
+ return self.jwk
118
+
119
+ def algorithm_name(self):
120
+ return self.key.curve.name
121
+
122
+ def sign(self, message):
123
+ key_size = self.key.curve.key_size
124
+ if key_size == 256:
125
+ algorithm = hashes.SHA256()
126
+ elif key_size == 384:
127
+ algorithm = hashes.SHA384()
128
+ elif key_size == 521:
129
+ algorithm = hashes.SHA512()
130
+ else:
131
+ raise ValueError(f"Unsupported curve with key size {key_size}")
132
+ return self.key.sign(message, ec.ECDSA(algorithm))
133
+
134
+ def sign_csr(self, csr):
135
+ return csr.sign(self.key, hashes.SHA256())
@@ -0,0 +1,94 @@
1
+ import json
2
+ import time
3
+ from datetime import datetime, timedelta
4
+ from typing import Union, Callable, List
5
+
6
+ import requests
7
+ from cryptography import x509
8
+ from cryptography.hazmat._oid import NameOID
9
+ from cryptography.hazmat.primitives import hashes, serialization
10
+ from cryptography.hazmat.primitives.asymmetric.dsa import DSAPrivateKey
11
+ from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey
12
+ from cryptography.x509 import Certificate
13
+ from requests import Response
14
+
15
+ from . import Acme
16
+ from . import db
17
+ from . import crypto
18
+ from . import challenge
19
+ from .crypto import csr_to_pem, create_csr, gen_key_secp256r1
20
+ from cryptography.hazmat.primitives.asymmetric import rsa, ec, padding, ed25519, dsa
21
+
22
+
23
+ # pathlib.Path.mkdir("/var/www/html/.acme/well-known")
24
+
25
+
26
+ class CustomCertAuthority:
27
+ def __init__(self, key: Union[RSAPrivateKey, DSAPrivateKey, ec.EllipticCurvePrivateKey]):
28
+ self.root_key = key
29
+ self.issuer = x509.Name(
30
+ [
31
+ x509.NameAttribute(NameOID.COUNTRY_NAME, "NP"),
32
+ x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, "Kathmandu"),
33
+ x509.NameAttribute(NameOID.LOCALITY_NAME, "Buddhanagar"),
34
+ x509.NameAttribute(NameOID.ORGANIZATION_NAME, "Sireto Technology"),
35
+ x509.NameAttribute(NameOID.COMMON_NAME, "sireto.io"),
36
+ ]
37
+ )
38
+
39
+ def get_ca_cert(self):
40
+
41
+ # Assuming self.root_key is the CA private key
42
+ cert = (
43
+ x509.CertificateBuilder()
44
+ .subject_name(self.issuer)
45
+ .issuer_name(self.issuer)
46
+ .public_key(self.root_key.public_key())
47
+ .serial_number(x509.random_serial_number())
48
+ .not_valid_before(datetime.utcnow())
49
+ .not_valid_after(datetime.utcnow() + timedelta(days=365))
50
+ .add_extension(x509.BasicConstraints(ca=True, path_length=None), critical=True)
51
+ .sign(self.root_key, hashes.SHA256())
52
+ )
53
+
54
+ return cert
55
+
56
+ # Assuming CustomCertAuthority is your class
57
+
58
+ def create_cert(self, domain: str, alt_names: List[str] = (), key_type: str = "rsa", expiry_days=90):
59
+ if key_type == "rsa":
60
+ key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
61
+ elif key_type == "dsa":
62
+ key = dsa.generate_private_key(key_size=2048)
63
+ elif key_type == "ecdsa":
64
+ key = gen_key_secp256r1()
65
+ else:
66
+ raise ValueError("Unsupported key type")
67
+
68
+ subject = x509.Name(
69
+ [
70
+ x509.NameAttribute(NameOID.COUNTRY_NAME, "NP"),
71
+ x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, "Kathmandu"),
72
+ x509.NameAttribute(NameOID.LOCALITY_NAME, "Buddhanagar"),
73
+ x509.NameAttribute(NameOID.ORGANIZATION_NAME, "Sireto Technology"),
74
+ x509.NameAttribute(NameOID.USER_ID, domain),
75
+ ]
76
+ )
77
+
78
+ now = datetime.utcnow()
79
+ cert_builder = (
80
+ x509.CertificateBuilder()
81
+ .subject_name(subject)
82
+ .issuer_name(self.issuer)
83
+ .public_key(key.public_key())
84
+ .serial_number(x509.random_serial_number())
85
+ .not_valid_before(now)
86
+ .not_valid_after(now + timedelta(days=expiry_days))
87
+ )
88
+
89
+ for alt_name in alt_names:
90
+ cert_builder.add_extension(x509.SubjectAlternativeName([x509.DNSName(alt_name)]), critical=False)
91
+
92
+ cert = cert_builder.sign(self.root_key, hashes.SHA256())
93
+
94
+ return (key, cert)