base.py 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834
  1. # This file is dual licensed under the terms of the Apache License, Version
  2. # 2.0, and the BSD License. See the LICENSE file in the root of this repository
  3. # for complete details.
  4. from __future__ import annotations
  5. import datetime
  6. import os
  7. import typing
  8. from collections.abc import Iterable
  9. from cryptography import utils
  10. from cryptography.hazmat.bindings._rust import x509 as rust_x509
  11. from cryptography.hazmat.primitives import hashes
  12. from cryptography.hazmat.primitives.asymmetric import (
  13. dsa,
  14. ec,
  15. ed448,
  16. ed25519,
  17. mldsa,
  18. mlkem,
  19. padding,
  20. rsa,
  21. x448,
  22. x25519,
  23. )
  24. from cryptography.hazmat.primitives.asymmetric.types import (
  25. CertificateIssuerPrivateKeyTypes,
  26. CertificatePublicKeyTypes,
  27. )
  28. from cryptography.x509.extensions import (
  29. Extension,
  30. ExtensionType,
  31. _make_sequence_methods,
  32. )
  33. from cryptography.x509.name import Name, _ASN1Type
  34. from cryptography.x509.oid import ObjectIdentifier
  35. _EARLIEST_UTC_TIME = datetime.datetime(1950, 1, 1)
  36. # This must be kept in sync with sign.rs's list of allowable types in
  37. # identify_hash_type
  38. _AllowedHashTypes = typing.Union[
  39. hashes.SHA224,
  40. hashes.SHA256,
  41. hashes.SHA384,
  42. hashes.SHA512,
  43. hashes.SHA3_224,
  44. hashes.SHA3_256,
  45. hashes.SHA3_384,
  46. hashes.SHA3_512,
  47. ]
  48. class AttributeNotFound(Exception):
  49. def __init__(self, msg: str, oid: ObjectIdentifier) -> None:
  50. super().__init__(msg)
  51. self.oid = oid
  52. def _reject_duplicate_extension(
  53. extension: Extension[ExtensionType],
  54. extensions: list[Extension[ExtensionType]],
  55. ) -> None:
  56. # This is quadratic in the number of extensions
  57. for e in extensions:
  58. if e.oid == extension.oid:
  59. raise ValueError("This extension has already been set.")
  60. def _reject_duplicate_attribute(
  61. oid: ObjectIdentifier,
  62. attributes: list[tuple[ObjectIdentifier, bytes, int | None]],
  63. ) -> None:
  64. # This is quadratic in the number of attributes
  65. for attr_oid, _, _ in attributes:
  66. if attr_oid == oid:
  67. raise ValueError("This attribute has already been set.")
  68. def _convert_to_naive_utc_time(time: datetime.datetime) -> datetime.datetime:
  69. """Normalizes a datetime to a naive datetime in UTC.
  70. time -- datetime to normalize. Assumed to be in UTC if not timezone
  71. aware.
  72. """
  73. if time.tzinfo is not None:
  74. offset = time.utcoffset()
  75. offset = offset if offset else datetime.timedelta()
  76. return time.replace(tzinfo=None) - offset
  77. else:
  78. return time
  79. class Attribute:
  80. def __init__(
  81. self,
  82. oid: ObjectIdentifier,
  83. value: bytes,
  84. _type: int = _ASN1Type.UTF8String.value,
  85. ) -> None:
  86. self._oid = oid
  87. self._value = value
  88. self._type = _type
  89. @property
  90. def oid(self) -> ObjectIdentifier:
  91. return self._oid
  92. @property
  93. def value(self) -> bytes:
  94. return self._value
  95. def __repr__(self) -> str:
  96. return f"<Attribute(oid={self.oid}, value={self.value!r})>"
  97. def __eq__(self, other: object) -> bool:
  98. if not isinstance(other, Attribute):
  99. return NotImplemented
  100. return (
  101. self.oid == other.oid
  102. and self.value == other.value
  103. and self._type == other._type
  104. )
  105. def __hash__(self) -> int:
  106. return hash((self.oid, self.value, self._type))
  107. class Attributes:
  108. def __init__(
  109. self,
  110. attributes: Iterable[Attribute],
  111. ) -> None:
  112. self._attributes = list(attributes)
  113. __len__, __iter__, __getitem__ = _make_sequence_methods("_attributes")
  114. def __repr__(self) -> str:
  115. return f"<Attributes({self._attributes})>"
  116. def get_attribute_for_oid(self, oid: ObjectIdentifier) -> Attribute:
  117. for attr in self:
  118. if attr.oid == oid:
  119. return attr
  120. raise AttributeNotFound(f"No {oid} attribute was found", oid)
  121. class Version(utils.Enum):
  122. v1 = 0
  123. v3 = 2
  124. class InvalidVersion(Exception):
  125. def __init__(self, msg: str, parsed_version: int) -> None:
  126. super().__init__(msg)
  127. self.parsed_version = parsed_version
  128. Certificate = rust_x509.Certificate
  129. RevokedCertificate = rust_x509.RevokedCertificate
  130. CertificateRevocationList = rust_x509.CertificateRevocationList
  131. CertificateSigningRequest = rust_x509.CertificateSigningRequest
  132. load_pem_x509_certificate = rust_x509.load_pem_x509_certificate
  133. load_der_x509_certificate = rust_x509.load_der_x509_certificate
  134. load_pem_x509_certificates = rust_x509.load_pem_x509_certificates
  135. load_pem_x509_csr = rust_x509.load_pem_x509_csr
  136. load_der_x509_csr = rust_x509.load_der_x509_csr
  137. load_pem_x509_crl = rust_x509.load_pem_x509_crl
  138. load_der_x509_crl = rust_x509.load_der_x509_crl
  139. class CertificateSigningRequestBuilder:
  140. def __init__(
  141. self,
  142. subject_name: Name | None = None,
  143. extensions: list[Extension[ExtensionType]] = [],
  144. attributes: list[tuple[ObjectIdentifier, bytes, int | None]] = [],
  145. ):
  146. """
  147. Creates an empty X.509 certificate request (v1).
  148. """
  149. self._subject_name = subject_name
  150. self._extensions = extensions
  151. self._attributes = attributes
  152. def subject_name(self, name: Name) -> CertificateSigningRequestBuilder:
  153. """
  154. Sets the certificate requestor's distinguished name.
  155. """
  156. if not isinstance(name, Name):
  157. raise TypeError("Expecting x509.Name object.")
  158. if self._subject_name is not None:
  159. raise ValueError("The subject name may only be set once.")
  160. return CertificateSigningRequestBuilder(
  161. name, self._extensions, self._attributes
  162. )
  163. def add_extension(
  164. self, extval: ExtensionType, critical: bool
  165. ) -> CertificateSigningRequestBuilder:
  166. """
  167. Adds an X.509 extension to the certificate request.
  168. """
  169. if not isinstance(extval, ExtensionType):
  170. raise TypeError("extension must be an ExtensionType")
  171. extension = Extension(extval.oid, critical, extval)
  172. _reject_duplicate_extension(extension, self._extensions)
  173. return CertificateSigningRequestBuilder(
  174. self._subject_name,
  175. [*self._extensions, extension],
  176. self._attributes,
  177. )
  178. def add_attribute(
  179. self,
  180. oid: ObjectIdentifier,
  181. value: bytes,
  182. *,
  183. _tag: _ASN1Type | None = None,
  184. ) -> CertificateSigningRequestBuilder:
  185. """
  186. Adds an X.509 attribute with an OID and associated value.
  187. """
  188. if not isinstance(oid, ObjectIdentifier):
  189. raise TypeError("oid must be an ObjectIdentifier")
  190. if not isinstance(value, bytes):
  191. raise TypeError("value must be bytes")
  192. if _tag is not None and not isinstance(_tag, _ASN1Type):
  193. raise TypeError("tag must be _ASN1Type")
  194. _reject_duplicate_attribute(oid, self._attributes)
  195. if _tag is not None:
  196. tag = _tag.value
  197. else:
  198. tag = None
  199. return CertificateSigningRequestBuilder(
  200. self._subject_name,
  201. self._extensions,
  202. [*self._attributes, (oid, value, tag)],
  203. )
  204. def sign(
  205. self,
  206. private_key: CertificateIssuerPrivateKeyTypes,
  207. algorithm: _AllowedHashTypes | None,
  208. backend: typing.Any = None,
  209. *,
  210. rsa_padding: padding.PSS | padding.PKCS1v15 | None = None,
  211. ecdsa_deterministic: bool | None = None,
  212. ) -> CertificateSigningRequest:
  213. """
  214. Signs the request using the requestor's private key.
  215. """
  216. if self._subject_name is None:
  217. raise ValueError("A CertificateSigningRequest must have a subject")
  218. if rsa_padding is not None:
  219. if not isinstance(rsa_padding, (padding.PSS, padding.PKCS1v15)):
  220. raise TypeError("Padding must be PSS or PKCS1v15")
  221. if not isinstance(private_key, rsa.RSAPrivateKey):
  222. raise TypeError("Padding is only supported for RSA keys")
  223. if ecdsa_deterministic is not None:
  224. if not isinstance(private_key, ec.EllipticCurvePrivateKey):
  225. raise TypeError(
  226. "Deterministic ECDSA is only supported for EC keys"
  227. )
  228. return rust_x509.create_x509_csr(
  229. self,
  230. private_key,
  231. algorithm,
  232. rsa_padding,
  233. ecdsa_deterministic,
  234. )
  235. class CertificateBuilder:
  236. _extensions: list[Extension[ExtensionType]]
  237. def __init__(
  238. self,
  239. issuer_name: Name | None = None,
  240. subject_name: Name | None = None,
  241. public_key: CertificatePublicKeyTypes | None = None,
  242. serial_number: int | None = None,
  243. not_valid_before: datetime.datetime | None = None,
  244. not_valid_after: datetime.datetime | None = None,
  245. extensions: list[Extension[ExtensionType]] = [],
  246. public_key_rsa_padding: type[padding.PSS] | None = None,
  247. ) -> None:
  248. self._version = Version.v3
  249. self._issuer_name = issuer_name
  250. self._subject_name = subject_name
  251. self._public_key = public_key
  252. self._serial_number = serial_number
  253. self._not_valid_before = not_valid_before
  254. self._not_valid_after = not_valid_after
  255. self._extensions = extensions
  256. self._public_key_rsa_padding = public_key_rsa_padding
  257. def issuer_name(self, name: Name) -> CertificateBuilder:
  258. """
  259. Sets the CA's distinguished name.
  260. """
  261. if not isinstance(name, Name):
  262. raise TypeError("Expecting x509.Name object.")
  263. if self._issuer_name is not None:
  264. raise ValueError("The issuer name may only be set once.")
  265. return CertificateBuilder(
  266. name,
  267. self._subject_name,
  268. self._public_key,
  269. self._serial_number,
  270. self._not_valid_before,
  271. self._not_valid_after,
  272. self._extensions,
  273. self._public_key_rsa_padding,
  274. )
  275. def subject_name(self, name: Name) -> CertificateBuilder:
  276. """
  277. Sets the requestor's distinguished name.
  278. """
  279. if not isinstance(name, Name):
  280. raise TypeError("Expecting x509.Name object.")
  281. if self._subject_name is not None:
  282. raise ValueError("The subject name may only be set once.")
  283. return CertificateBuilder(
  284. self._issuer_name,
  285. name,
  286. self._public_key,
  287. self._serial_number,
  288. self._not_valid_before,
  289. self._not_valid_after,
  290. self._extensions,
  291. self._public_key_rsa_padding,
  292. )
  293. def public_key(
  294. self,
  295. key: CertificatePublicKeyTypes,
  296. *,
  297. rsa_padding: type[padding.PSS] | None = None,
  298. ) -> CertificateBuilder:
  299. """
  300. Sets the requestor's public key (as found in the signing request).
  301. """
  302. if not isinstance(
  303. key,
  304. (
  305. dsa.DSAPublicKey,
  306. rsa.RSAPublicKey,
  307. ec.EllipticCurvePublicKey,
  308. ed25519.Ed25519PublicKey,
  309. ed448.Ed448PublicKey,
  310. mldsa.MLDSA44PublicKey,
  311. mldsa.MLDSA65PublicKey,
  312. mldsa.MLDSA87PublicKey,
  313. mlkem.MLKEM768PublicKey,
  314. mlkem.MLKEM1024PublicKey,
  315. x25519.X25519PublicKey,
  316. x448.X448PublicKey,
  317. ),
  318. ):
  319. raise TypeError(
  320. "Expecting one of DSAPublicKey, RSAPublicKey,"
  321. " EllipticCurvePublicKey, Ed25519PublicKey,"
  322. " Ed448PublicKey, MLDSA44PublicKey, MLDSA65PublicKey,"
  323. " MLDSA87PublicKey, MLKEM768PublicKey, MLKEM1024PublicKey,"
  324. " X25519PublicKey or X448PublicKey."
  325. )
  326. if rsa_padding is not None:
  327. if rsa_padding is not padding.PSS:
  328. raise TypeError(
  329. "rsa_padding must be the PSS class, not an instance"
  330. )
  331. if not isinstance(key, rsa.RSAPublicKey):
  332. raise TypeError(
  333. "rsa_padding is only supported with RSA public keys"
  334. )
  335. if self._public_key is not None:
  336. raise ValueError("The public key may only be set once.")
  337. return CertificateBuilder(
  338. self._issuer_name,
  339. self._subject_name,
  340. key,
  341. self._serial_number,
  342. self._not_valid_before,
  343. self._not_valid_after,
  344. self._extensions,
  345. rsa_padding,
  346. )
  347. def serial_number(self, number: int) -> CertificateBuilder:
  348. """
  349. Sets the certificate serial number.
  350. """
  351. if not isinstance(number, int):
  352. raise TypeError("Serial number must be of integral type.")
  353. if self._serial_number is not None:
  354. raise ValueError("The serial number may only be set once.")
  355. if number <= 0:
  356. raise ValueError("The serial number should be positive.")
  357. # ASN.1 integers are always signed, so most significant bit must be
  358. # zero.
  359. if number.bit_length() >= 160: # As defined in RFC 5280
  360. raise ValueError(
  361. "The serial number should not be more than 159 bits."
  362. )
  363. return CertificateBuilder(
  364. self._issuer_name,
  365. self._subject_name,
  366. self._public_key,
  367. number,
  368. self._not_valid_before,
  369. self._not_valid_after,
  370. self._extensions,
  371. self._public_key_rsa_padding,
  372. )
  373. def not_valid_before(self, time: datetime.datetime) -> CertificateBuilder:
  374. """
  375. Sets the certificate activation time.
  376. """
  377. if not isinstance(time, datetime.datetime):
  378. raise TypeError("Expecting datetime object.")
  379. if self._not_valid_before is not None:
  380. raise ValueError("The not valid before may only be set once.")
  381. time = _convert_to_naive_utc_time(time)
  382. if time < _EARLIEST_UTC_TIME:
  383. raise ValueError(
  384. "The not valid before date must be on or after"
  385. " 1950 January 1)."
  386. )
  387. if self._not_valid_after is not None and time > self._not_valid_after:
  388. raise ValueError(
  389. "The not valid before date must be before the not valid after "
  390. "date."
  391. )
  392. return CertificateBuilder(
  393. self._issuer_name,
  394. self._subject_name,
  395. self._public_key,
  396. self._serial_number,
  397. time,
  398. self._not_valid_after,
  399. self._extensions,
  400. self._public_key_rsa_padding,
  401. )
  402. def not_valid_after(self, time: datetime.datetime) -> CertificateBuilder:
  403. """
  404. Sets the certificate expiration time.
  405. """
  406. if not isinstance(time, datetime.datetime):
  407. raise TypeError("Expecting datetime object.")
  408. if self._not_valid_after is not None:
  409. raise ValueError("The not valid after may only be set once.")
  410. time = _convert_to_naive_utc_time(time)
  411. if time < _EARLIEST_UTC_TIME:
  412. raise ValueError(
  413. "The not valid after date must be on or after 1950 January 1."
  414. )
  415. if (
  416. self._not_valid_before is not None
  417. and time < self._not_valid_before
  418. ):
  419. raise ValueError(
  420. "The not valid after date must be after the not valid before "
  421. "date."
  422. )
  423. return CertificateBuilder(
  424. self._issuer_name,
  425. self._subject_name,
  426. self._public_key,
  427. self._serial_number,
  428. self._not_valid_before,
  429. time,
  430. self._extensions,
  431. self._public_key_rsa_padding,
  432. )
  433. def add_extension(
  434. self, extval: ExtensionType, critical: bool
  435. ) -> CertificateBuilder:
  436. """
  437. Adds an X.509 extension to the certificate.
  438. """
  439. if not isinstance(extval, ExtensionType):
  440. raise TypeError("extension must be an ExtensionType")
  441. extension = Extension(extval.oid, critical, extval)
  442. _reject_duplicate_extension(extension, self._extensions)
  443. return CertificateBuilder(
  444. self._issuer_name,
  445. self._subject_name,
  446. self._public_key,
  447. self._serial_number,
  448. self._not_valid_before,
  449. self._not_valid_after,
  450. [*self._extensions, extension],
  451. self._public_key_rsa_padding,
  452. )
  453. def sign(
  454. self,
  455. private_key: CertificateIssuerPrivateKeyTypes,
  456. algorithm: _AllowedHashTypes | None,
  457. backend: typing.Any = None,
  458. *,
  459. rsa_padding: padding.PSS | padding.PKCS1v15 | None = None,
  460. ecdsa_deterministic: bool | None = None,
  461. ) -> Certificate:
  462. """
  463. Signs the certificate using the CA's private key.
  464. """
  465. if self._subject_name is None:
  466. raise ValueError("A certificate must have a subject name")
  467. if self._issuer_name is None:
  468. raise ValueError("A certificate must have an issuer name")
  469. if self._serial_number is None:
  470. raise ValueError("A certificate must have a serial number")
  471. if self._not_valid_before is None:
  472. raise ValueError("A certificate must have a not valid before time")
  473. if self._not_valid_after is None:
  474. raise ValueError("A certificate must have a not valid after time")
  475. if self._public_key is None:
  476. raise ValueError("A certificate must have a public key")
  477. if private_key is None:
  478. raise TypeError("Need private key to sign certificate")
  479. if rsa_padding is not None:
  480. if not isinstance(rsa_padding, (padding.PSS, padding.PKCS1v15)):
  481. raise TypeError("Padding must be PSS or PKCS1v15")
  482. if not isinstance(private_key, rsa.RSAPrivateKey):
  483. raise TypeError("Padding is only supported for RSA keys")
  484. if ecdsa_deterministic is not None:
  485. if not isinstance(private_key, ec.EllipticCurvePrivateKey):
  486. raise TypeError(
  487. "Deterministic ECDSA is only supported for EC keys"
  488. )
  489. return rust_x509.create_x509_certificate(
  490. self,
  491. private_key,
  492. algorithm,
  493. rsa_padding,
  494. ecdsa_deterministic,
  495. )
  496. def create_unsigned(self) -> Certificate:
  497. """
  498. Creates an unsigned certificate, per RFC 9925.
  499. """
  500. if self._subject_name is None:
  501. raise ValueError("A certificate must have a subject name")
  502. if self._issuer_name is None:
  503. raise ValueError("A certificate must have an issuer name")
  504. if self._serial_number is None:
  505. raise ValueError("A certificate must have a serial number")
  506. if self._not_valid_before is None:
  507. raise ValueError("A certificate must have a not valid before time")
  508. if self._not_valid_after is None:
  509. raise ValueError("A certificate must have a not valid after time")
  510. if self._public_key is None:
  511. raise ValueError("A certificate must have a public key")
  512. return rust_x509.create_x509_certificate(
  513. self,
  514. private_key=None,
  515. hash_algorithm=None,
  516. rsa_padding=None,
  517. ecdsa_deterministic=None,
  518. )
  519. class CertificateRevocationListBuilder:
  520. _extensions: list[Extension[ExtensionType]]
  521. _revoked_certificates: list[RevokedCertificate]
  522. def __init__(
  523. self,
  524. issuer_name: Name | None = None,
  525. last_update: datetime.datetime | None = None,
  526. next_update: datetime.datetime | None = None,
  527. extensions: list[Extension[ExtensionType]] = [],
  528. revoked_certificates: list[RevokedCertificate] = [],
  529. ):
  530. self._issuer_name = issuer_name
  531. self._last_update = last_update
  532. self._next_update = next_update
  533. self._extensions = extensions
  534. self._revoked_certificates = revoked_certificates
  535. def issuer_name(
  536. self, issuer_name: Name
  537. ) -> CertificateRevocationListBuilder:
  538. if not isinstance(issuer_name, Name):
  539. raise TypeError("Expecting x509.Name object.")
  540. if self._issuer_name is not None:
  541. raise ValueError("The issuer name may only be set once.")
  542. return CertificateRevocationListBuilder(
  543. issuer_name,
  544. self._last_update,
  545. self._next_update,
  546. self._extensions,
  547. self._revoked_certificates,
  548. )
  549. def last_update(
  550. self, last_update: datetime.datetime
  551. ) -> CertificateRevocationListBuilder:
  552. if not isinstance(last_update, datetime.datetime):
  553. raise TypeError("Expecting datetime object.")
  554. if self._last_update is not None:
  555. raise ValueError("Last update may only be set once.")
  556. last_update = _convert_to_naive_utc_time(last_update)
  557. if last_update < _EARLIEST_UTC_TIME:
  558. raise ValueError(
  559. "The last update date must be on or after 1950 January 1."
  560. )
  561. if self._next_update is not None and last_update > self._next_update:
  562. raise ValueError(
  563. "The last update date must be before the next update date."
  564. )
  565. return CertificateRevocationListBuilder(
  566. self._issuer_name,
  567. last_update,
  568. self._next_update,
  569. self._extensions,
  570. self._revoked_certificates,
  571. )
  572. def next_update(
  573. self, next_update: datetime.datetime
  574. ) -> CertificateRevocationListBuilder:
  575. if not isinstance(next_update, datetime.datetime):
  576. raise TypeError("Expecting datetime object.")
  577. if self._next_update is not None:
  578. raise ValueError("Last update may only be set once.")
  579. next_update = _convert_to_naive_utc_time(next_update)
  580. if next_update < _EARLIEST_UTC_TIME:
  581. raise ValueError(
  582. "The last update date must be on or after 1950 January 1."
  583. )
  584. if self._last_update is not None and next_update < self._last_update:
  585. raise ValueError(
  586. "The next update date must be after the last update date."
  587. )
  588. return CertificateRevocationListBuilder(
  589. self._issuer_name,
  590. self._last_update,
  591. next_update,
  592. self._extensions,
  593. self._revoked_certificates,
  594. )
  595. def add_extension(
  596. self, extval: ExtensionType, critical: bool
  597. ) -> CertificateRevocationListBuilder:
  598. """
  599. Adds an X.509 extension to the certificate revocation list.
  600. """
  601. if not isinstance(extval, ExtensionType):
  602. raise TypeError("extension must be an ExtensionType")
  603. extension = Extension(extval.oid, critical, extval)
  604. _reject_duplicate_extension(extension, self._extensions)
  605. return CertificateRevocationListBuilder(
  606. self._issuer_name,
  607. self._last_update,
  608. self._next_update,
  609. [*self._extensions, extension],
  610. self._revoked_certificates,
  611. )
  612. def add_revoked_certificate(
  613. self, revoked_certificate: RevokedCertificate
  614. ) -> CertificateRevocationListBuilder:
  615. """
  616. Adds a revoked certificate to the CRL.
  617. """
  618. if not isinstance(revoked_certificate, RevokedCertificate):
  619. raise TypeError("Must be an instance of RevokedCertificate")
  620. return CertificateRevocationListBuilder(
  621. self._issuer_name,
  622. self._last_update,
  623. self._next_update,
  624. self._extensions,
  625. [*self._revoked_certificates, revoked_certificate],
  626. )
  627. def sign(
  628. self,
  629. private_key: CertificateIssuerPrivateKeyTypes,
  630. algorithm: _AllowedHashTypes | None,
  631. backend: typing.Any = None,
  632. *,
  633. rsa_padding: padding.PSS | padding.PKCS1v15 | None = None,
  634. ecdsa_deterministic: bool | None = None,
  635. ) -> CertificateRevocationList:
  636. if self._issuer_name is None:
  637. raise ValueError("A CRL must have an issuer name")
  638. if self._last_update is None:
  639. raise ValueError("A CRL must have a last update time")
  640. if self._next_update is None:
  641. raise ValueError("A CRL must have a next update time")
  642. if rsa_padding is not None:
  643. if not isinstance(rsa_padding, (padding.PSS, padding.PKCS1v15)):
  644. raise TypeError("Padding must be PSS or PKCS1v15")
  645. if not isinstance(private_key, rsa.RSAPrivateKey):
  646. raise TypeError("Padding is only supported for RSA keys")
  647. if ecdsa_deterministic is not None:
  648. if not isinstance(private_key, ec.EllipticCurvePrivateKey):
  649. raise TypeError(
  650. "Deterministic ECDSA is only supported for EC keys"
  651. )
  652. return rust_x509.create_x509_crl(
  653. self,
  654. private_key,
  655. algorithm,
  656. rsa_padding,
  657. ecdsa_deterministic,
  658. )
  659. class RevokedCertificateBuilder:
  660. def __init__(
  661. self,
  662. serial_number: int | None = None,
  663. revocation_date: datetime.datetime | None = None,
  664. extensions: list[Extension[ExtensionType]] = [],
  665. ):
  666. self._serial_number = serial_number
  667. self._revocation_date = revocation_date
  668. self._extensions = extensions
  669. def serial_number(self, number: int) -> RevokedCertificateBuilder:
  670. if not isinstance(number, int):
  671. raise TypeError("Serial number must be of integral type.")
  672. if self._serial_number is not None:
  673. raise ValueError("The serial number may only be set once.")
  674. if number <= 0:
  675. raise ValueError("The serial number should be positive")
  676. # ASN.1 integers are always signed, so most significant bit must be
  677. # zero.
  678. if number.bit_length() >= 160: # As defined in RFC 5280
  679. raise ValueError(
  680. "The serial number should not be more than 159 bits."
  681. )
  682. return RevokedCertificateBuilder(
  683. number, self._revocation_date, self._extensions
  684. )
  685. def revocation_date(
  686. self, time: datetime.datetime
  687. ) -> RevokedCertificateBuilder:
  688. if not isinstance(time, datetime.datetime):
  689. raise TypeError("Expecting datetime object.")
  690. if self._revocation_date is not None:
  691. raise ValueError("The revocation date may only be set once.")
  692. time = _convert_to_naive_utc_time(time)
  693. if time < _EARLIEST_UTC_TIME:
  694. raise ValueError(
  695. "The revocation date must be on or after 1950 January 1."
  696. )
  697. return RevokedCertificateBuilder(
  698. self._serial_number, time, self._extensions
  699. )
  700. def add_extension(
  701. self, extval: ExtensionType, critical: bool
  702. ) -> RevokedCertificateBuilder:
  703. if not isinstance(extval, ExtensionType):
  704. raise TypeError("extension must be an ExtensionType")
  705. extension = Extension(extval.oid, critical, extval)
  706. _reject_duplicate_extension(extension, self._extensions)
  707. return RevokedCertificateBuilder(
  708. self._serial_number,
  709. self._revocation_date,
  710. [*self._extensions, extension],
  711. )
  712. def build(self, backend: typing.Any = None) -> RevokedCertificate:
  713. if self._serial_number is None:
  714. raise ValueError("A revoked certificate must have a serial number")
  715. if self._revocation_date is None:
  716. raise ValueError(
  717. "A revoked certificate must have a revocation date"
  718. )
  719. return rust_x509.create_revoked_certificate(self)
  720. def random_serial_number() -> int:
  721. return int.from_bytes(os.urandom(20), "big") >> 1