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/Acme.py +386 -0
- certapi/__init__.py +5 -0
- certapi/certauthority.py +154 -0
- certapi/challenge.py +121 -0
- certapi/crypto.py +222 -0
- certapi/crypto_classes.py +135 -0
- certapi/custom_certauthority.py +94 -0
- certapi/db.py +365 -0
- certapi/util.py +19 -0
- certapi-0.1.0.dist-info/METADATA +45 -0
- certapi-0.1.0.dist-info/RECORD +13 -0
- certapi-0.1.0.dist-info/WHEEL +5 -0
- certapi-0.1.0.dist-info/top_level.txt +1 -0
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)
|