Funktionierender Prototyp des Serious Games zur Vermittlung von Wissen zu Software-Engineering-Arbeitsmodellen.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

base.py 35KB

1 year ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173
  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 abc
  6. import datetime
  7. import os
  8. import typing
  9. from cryptography import utils
  10. from cryptography.hazmat.bindings._rust import x509 as rust_x509
  11. from cryptography.hazmat.primitives import hashes, serialization
  12. from cryptography.hazmat.primitives.asymmetric import (
  13. dsa,
  14. ec,
  15. ed448,
  16. ed25519,
  17. padding,
  18. rsa,
  19. x448,
  20. x25519,
  21. )
  22. from cryptography.hazmat.primitives.asymmetric.types import (
  23. CertificateIssuerPrivateKeyTypes,
  24. CertificateIssuerPublicKeyTypes,
  25. CertificatePublicKeyTypes,
  26. )
  27. from cryptography.x509.extensions import (
  28. Extension,
  29. Extensions,
  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: typing.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: typing.List[
  63. typing.Tuple[ObjectIdentifier, bytes, typing.Optional[int]]
  64. ],
  65. ) -> None:
  66. # This is quadratic in the number of attributes
  67. for attr_oid, _, _ in attributes:
  68. if attr_oid == oid:
  69. raise ValueError("This attribute has already been set.")
  70. def _convert_to_naive_utc_time(time: datetime.datetime) -> datetime.datetime:
  71. """Normalizes a datetime to a naive datetime in UTC.
  72. time -- datetime to normalize. Assumed to be in UTC if not timezone
  73. aware.
  74. """
  75. if time.tzinfo is not None:
  76. offset = time.utcoffset()
  77. offset = offset if offset else datetime.timedelta()
  78. return time.replace(tzinfo=None) - offset
  79. else:
  80. return time
  81. class Attribute:
  82. def __init__(
  83. self,
  84. oid: ObjectIdentifier,
  85. value: bytes,
  86. _type: int = _ASN1Type.UTF8String.value,
  87. ) -> None:
  88. self._oid = oid
  89. self._value = value
  90. self._type = _type
  91. @property
  92. def oid(self) -> ObjectIdentifier:
  93. return self._oid
  94. @property
  95. def value(self) -> bytes:
  96. return self._value
  97. def __repr__(self) -> str:
  98. return f"<Attribute(oid={self.oid}, value={self.value!r})>"
  99. def __eq__(self, other: object) -> bool:
  100. if not isinstance(other, Attribute):
  101. return NotImplemented
  102. return (
  103. self.oid == other.oid
  104. and self.value == other.value
  105. and self._type == other._type
  106. )
  107. def __hash__(self) -> int:
  108. return hash((self.oid, self.value, self._type))
  109. class Attributes:
  110. def __init__(
  111. self,
  112. attributes: typing.Iterable[Attribute],
  113. ) -> None:
  114. self._attributes = list(attributes)
  115. __len__, __iter__, __getitem__ = _make_sequence_methods("_attributes")
  116. def __repr__(self) -> str:
  117. return f"<Attributes({self._attributes})>"
  118. def get_attribute_for_oid(self, oid: ObjectIdentifier) -> Attribute:
  119. for attr in self:
  120. if attr.oid == oid:
  121. return attr
  122. raise AttributeNotFound(f"No {oid} attribute was found", oid)
  123. class Version(utils.Enum):
  124. v1 = 0
  125. v3 = 2
  126. class InvalidVersion(Exception):
  127. def __init__(self, msg: str, parsed_version: int) -> None:
  128. super().__init__(msg)
  129. self.parsed_version = parsed_version
  130. class Certificate(metaclass=abc.ABCMeta):
  131. @abc.abstractmethod
  132. def fingerprint(self, algorithm: hashes.HashAlgorithm) -> bytes:
  133. """
  134. Returns bytes using digest passed.
  135. """
  136. @property
  137. @abc.abstractmethod
  138. def serial_number(self) -> int:
  139. """
  140. Returns certificate serial number
  141. """
  142. @property
  143. @abc.abstractmethod
  144. def version(self) -> Version:
  145. """
  146. Returns the certificate version
  147. """
  148. @abc.abstractmethod
  149. def public_key(self) -> CertificatePublicKeyTypes:
  150. """
  151. Returns the public key
  152. """
  153. @property
  154. @abc.abstractmethod
  155. def not_valid_before(self) -> datetime.datetime:
  156. """
  157. Not before time (represented as UTC datetime)
  158. """
  159. @property
  160. @abc.abstractmethod
  161. def not_valid_after(self) -> datetime.datetime:
  162. """
  163. Not after time (represented as UTC datetime)
  164. """
  165. @property
  166. @abc.abstractmethod
  167. def issuer(self) -> Name:
  168. """
  169. Returns the issuer name object.
  170. """
  171. @property
  172. @abc.abstractmethod
  173. def subject(self) -> Name:
  174. """
  175. Returns the subject name object.
  176. """
  177. @property
  178. @abc.abstractmethod
  179. def signature_hash_algorithm(
  180. self,
  181. ) -> typing.Optional[hashes.HashAlgorithm]:
  182. """
  183. Returns a HashAlgorithm corresponding to the type of the digest signed
  184. in the certificate.
  185. """
  186. @property
  187. @abc.abstractmethod
  188. def signature_algorithm_oid(self) -> ObjectIdentifier:
  189. """
  190. Returns the ObjectIdentifier of the signature algorithm.
  191. """
  192. @property
  193. @abc.abstractmethod
  194. def signature_algorithm_parameters(
  195. self,
  196. ) -> typing.Union[None, padding.PSS, padding.PKCS1v15, ec.ECDSA]:
  197. """
  198. Returns the signature algorithm parameters.
  199. """
  200. @property
  201. @abc.abstractmethod
  202. def extensions(self) -> Extensions:
  203. """
  204. Returns an Extensions object.
  205. """
  206. @property
  207. @abc.abstractmethod
  208. def signature(self) -> bytes:
  209. """
  210. Returns the signature bytes.
  211. """
  212. @property
  213. @abc.abstractmethod
  214. def tbs_certificate_bytes(self) -> bytes:
  215. """
  216. Returns the tbsCertificate payload bytes as defined in RFC 5280.
  217. """
  218. @property
  219. @abc.abstractmethod
  220. def tbs_precertificate_bytes(self) -> bytes:
  221. """
  222. Returns the tbsCertificate payload bytes with the SCT list extension
  223. stripped.
  224. """
  225. @abc.abstractmethod
  226. def __eq__(self, other: object) -> bool:
  227. """
  228. Checks equality.
  229. """
  230. @abc.abstractmethod
  231. def __hash__(self) -> int:
  232. """
  233. Computes a hash.
  234. """
  235. @abc.abstractmethod
  236. def public_bytes(self, encoding: serialization.Encoding) -> bytes:
  237. """
  238. Serializes the certificate to PEM or DER format.
  239. """
  240. @abc.abstractmethod
  241. def verify_directly_issued_by(self, issuer: Certificate) -> None:
  242. """
  243. This method verifies that certificate issuer name matches the
  244. issuer subject name and that the certificate is signed by the
  245. issuer's private key. No other validation is performed.
  246. """
  247. # Runtime isinstance checks need this since the rust class is not a subclass.
  248. Certificate.register(rust_x509.Certificate)
  249. class RevokedCertificate(metaclass=abc.ABCMeta):
  250. @property
  251. @abc.abstractmethod
  252. def serial_number(self) -> int:
  253. """
  254. Returns the serial number of the revoked certificate.
  255. """
  256. @property
  257. @abc.abstractmethod
  258. def revocation_date(self) -> datetime.datetime:
  259. """
  260. Returns the date of when this certificate was revoked.
  261. """
  262. @property
  263. @abc.abstractmethod
  264. def extensions(self) -> Extensions:
  265. """
  266. Returns an Extensions object containing a list of Revoked extensions.
  267. """
  268. # Runtime isinstance checks need this since the rust class is not a subclass.
  269. RevokedCertificate.register(rust_x509.RevokedCertificate)
  270. class _RawRevokedCertificate(RevokedCertificate):
  271. def __init__(
  272. self,
  273. serial_number: int,
  274. revocation_date: datetime.datetime,
  275. extensions: Extensions,
  276. ):
  277. self._serial_number = serial_number
  278. self._revocation_date = revocation_date
  279. self._extensions = extensions
  280. @property
  281. def serial_number(self) -> int:
  282. return self._serial_number
  283. @property
  284. def revocation_date(self) -> datetime.datetime:
  285. return self._revocation_date
  286. @property
  287. def extensions(self) -> Extensions:
  288. return self._extensions
  289. class CertificateRevocationList(metaclass=abc.ABCMeta):
  290. @abc.abstractmethod
  291. def public_bytes(self, encoding: serialization.Encoding) -> bytes:
  292. """
  293. Serializes the CRL to PEM or DER format.
  294. """
  295. @abc.abstractmethod
  296. def fingerprint(self, algorithm: hashes.HashAlgorithm) -> bytes:
  297. """
  298. Returns bytes using digest passed.
  299. """
  300. @abc.abstractmethod
  301. def get_revoked_certificate_by_serial_number(
  302. self, serial_number: int
  303. ) -> typing.Optional[RevokedCertificate]:
  304. """
  305. Returns an instance of RevokedCertificate or None if the serial_number
  306. is not in the CRL.
  307. """
  308. @property
  309. @abc.abstractmethod
  310. def signature_hash_algorithm(
  311. self,
  312. ) -> typing.Optional[hashes.HashAlgorithm]:
  313. """
  314. Returns a HashAlgorithm corresponding to the type of the digest signed
  315. in the certificate.
  316. """
  317. @property
  318. @abc.abstractmethod
  319. def signature_algorithm_oid(self) -> ObjectIdentifier:
  320. """
  321. Returns the ObjectIdentifier of the signature algorithm.
  322. """
  323. @property
  324. @abc.abstractmethod
  325. def issuer(self) -> Name:
  326. """
  327. Returns the X509Name with the issuer of this CRL.
  328. """
  329. @property
  330. @abc.abstractmethod
  331. def next_update(self) -> typing.Optional[datetime.datetime]:
  332. """
  333. Returns the date of next update for this CRL.
  334. """
  335. @property
  336. @abc.abstractmethod
  337. def last_update(self) -> datetime.datetime:
  338. """
  339. Returns the date of last update for this CRL.
  340. """
  341. @property
  342. @abc.abstractmethod
  343. def extensions(self) -> Extensions:
  344. """
  345. Returns an Extensions object containing a list of CRL extensions.
  346. """
  347. @property
  348. @abc.abstractmethod
  349. def signature(self) -> bytes:
  350. """
  351. Returns the signature bytes.
  352. """
  353. @property
  354. @abc.abstractmethod
  355. def tbs_certlist_bytes(self) -> bytes:
  356. """
  357. Returns the tbsCertList payload bytes as defined in RFC 5280.
  358. """
  359. @abc.abstractmethod
  360. def __eq__(self, other: object) -> bool:
  361. """
  362. Checks equality.
  363. """
  364. @abc.abstractmethod
  365. def __len__(self) -> int:
  366. """
  367. Number of revoked certificates in the CRL.
  368. """
  369. @typing.overload
  370. def __getitem__(self, idx: int) -> RevokedCertificate:
  371. ...
  372. @typing.overload
  373. def __getitem__(self, idx: slice) -> typing.List[RevokedCertificate]:
  374. ...
  375. @abc.abstractmethod
  376. def __getitem__(
  377. self, idx: typing.Union[int, slice]
  378. ) -> typing.Union[RevokedCertificate, typing.List[RevokedCertificate]]:
  379. """
  380. Returns a revoked certificate (or slice of revoked certificates).
  381. """
  382. @abc.abstractmethod
  383. def __iter__(self) -> typing.Iterator[RevokedCertificate]:
  384. """
  385. Iterator over the revoked certificates
  386. """
  387. @abc.abstractmethod
  388. def is_signature_valid(
  389. self, public_key: CertificateIssuerPublicKeyTypes
  390. ) -> bool:
  391. """
  392. Verifies signature of revocation list against given public key.
  393. """
  394. CertificateRevocationList.register(rust_x509.CertificateRevocationList)
  395. class CertificateSigningRequest(metaclass=abc.ABCMeta):
  396. @abc.abstractmethod
  397. def __eq__(self, other: object) -> bool:
  398. """
  399. Checks equality.
  400. """
  401. @abc.abstractmethod
  402. def __hash__(self) -> int:
  403. """
  404. Computes a hash.
  405. """
  406. @abc.abstractmethod
  407. def public_key(self) -> CertificatePublicKeyTypes:
  408. """
  409. Returns the public key
  410. """
  411. @property
  412. @abc.abstractmethod
  413. def subject(self) -> Name:
  414. """
  415. Returns the subject name object.
  416. """
  417. @property
  418. @abc.abstractmethod
  419. def signature_hash_algorithm(
  420. self,
  421. ) -> typing.Optional[hashes.HashAlgorithm]:
  422. """
  423. Returns a HashAlgorithm corresponding to the type of the digest signed
  424. in the certificate.
  425. """
  426. @property
  427. @abc.abstractmethod
  428. def signature_algorithm_oid(self) -> ObjectIdentifier:
  429. """
  430. Returns the ObjectIdentifier of the signature algorithm.
  431. """
  432. @property
  433. @abc.abstractmethod
  434. def extensions(self) -> Extensions:
  435. """
  436. Returns the extensions in the signing request.
  437. """
  438. @property
  439. @abc.abstractmethod
  440. def attributes(self) -> Attributes:
  441. """
  442. Returns an Attributes object.
  443. """
  444. @abc.abstractmethod
  445. def public_bytes(self, encoding: serialization.Encoding) -> bytes:
  446. """
  447. Encodes the request to PEM or DER format.
  448. """
  449. @property
  450. @abc.abstractmethod
  451. def signature(self) -> bytes:
  452. """
  453. Returns the signature bytes.
  454. """
  455. @property
  456. @abc.abstractmethod
  457. def tbs_certrequest_bytes(self) -> bytes:
  458. """
  459. Returns the PKCS#10 CertificationRequestInfo bytes as defined in RFC
  460. 2986.
  461. """
  462. @property
  463. @abc.abstractmethod
  464. def is_signature_valid(self) -> bool:
  465. """
  466. Verifies signature of signing request.
  467. """
  468. @abc.abstractmethod
  469. def get_attribute_for_oid(self, oid: ObjectIdentifier) -> bytes:
  470. """
  471. Get the attribute value for a given OID.
  472. """
  473. # Runtime isinstance checks need this since the rust class is not a subclass.
  474. CertificateSigningRequest.register(rust_x509.CertificateSigningRequest)
  475. # Backend argument preserved for API compatibility, but ignored.
  476. def load_pem_x509_certificate(
  477. data: bytes, backend: typing.Any = None
  478. ) -> Certificate:
  479. return rust_x509.load_pem_x509_certificate(data)
  480. def load_pem_x509_certificates(data: bytes) -> typing.List[Certificate]:
  481. return rust_x509.load_pem_x509_certificates(data)
  482. # Backend argument preserved for API compatibility, but ignored.
  483. def load_der_x509_certificate(
  484. data: bytes, backend: typing.Any = None
  485. ) -> Certificate:
  486. return rust_x509.load_der_x509_certificate(data)
  487. # Backend argument preserved for API compatibility, but ignored.
  488. def load_pem_x509_csr(
  489. data: bytes, backend: typing.Any = None
  490. ) -> CertificateSigningRequest:
  491. return rust_x509.load_pem_x509_csr(data)
  492. # Backend argument preserved for API compatibility, but ignored.
  493. def load_der_x509_csr(
  494. data: bytes, backend: typing.Any = None
  495. ) -> CertificateSigningRequest:
  496. return rust_x509.load_der_x509_csr(data)
  497. # Backend argument preserved for API compatibility, but ignored.
  498. def load_pem_x509_crl(
  499. data: bytes, backend: typing.Any = None
  500. ) -> CertificateRevocationList:
  501. return rust_x509.load_pem_x509_crl(data)
  502. # Backend argument preserved for API compatibility, but ignored.
  503. def load_der_x509_crl(
  504. data: bytes, backend: typing.Any = None
  505. ) -> CertificateRevocationList:
  506. return rust_x509.load_der_x509_crl(data)
  507. class CertificateSigningRequestBuilder:
  508. def __init__(
  509. self,
  510. subject_name: typing.Optional[Name] = None,
  511. extensions: typing.List[Extension[ExtensionType]] = [],
  512. attributes: typing.List[
  513. typing.Tuple[ObjectIdentifier, bytes, typing.Optional[int]]
  514. ] = [],
  515. ):
  516. """
  517. Creates an empty X.509 certificate request (v1).
  518. """
  519. self._subject_name = subject_name
  520. self._extensions = extensions
  521. self._attributes = attributes
  522. def subject_name(self, name: Name) -> CertificateSigningRequestBuilder:
  523. """
  524. Sets the certificate requestor's distinguished name.
  525. """
  526. if not isinstance(name, Name):
  527. raise TypeError("Expecting x509.Name object.")
  528. if self._subject_name is not None:
  529. raise ValueError("The subject name may only be set once.")
  530. return CertificateSigningRequestBuilder(
  531. name, self._extensions, self._attributes
  532. )
  533. def add_extension(
  534. self, extval: ExtensionType, critical: bool
  535. ) -> CertificateSigningRequestBuilder:
  536. """
  537. Adds an X.509 extension to the certificate request.
  538. """
  539. if not isinstance(extval, ExtensionType):
  540. raise TypeError("extension must be an ExtensionType")
  541. extension = Extension(extval.oid, critical, extval)
  542. _reject_duplicate_extension(extension, self._extensions)
  543. return CertificateSigningRequestBuilder(
  544. self._subject_name,
  545. self._extensions + [extension],
  546. self._attributes,
  547. )
  548. def add_attribute(
  549. self,
  550. oid: ObjectIdentifier,
  551. value: bytes,
  552. *,
  553. _tag: typing.Optional[_ASN1Type] = None,
  554. ) -> CertificateSigningRequestBuilder:
  555. """
  556. Adds an X.509 attribute with an OID and associated value.
  557. """
  558. if not isinstance(oid, ObjectIdentifier):
  559. raise TypeError("oid must be an ObjectIdentifier")
  560. if not isinstance(value, bytes):
  561. raise TypeError("value must be bytes")
  562. if _tag is not None and not isinstance(_tag, _ASN1Type):
  563. raise TypeError("tag must be _ASN1Type")
  564. _reject_duplicate_attribute(oid, self._attributes)
  565. if _tag is not None:
  566. tag = _tag.value
  567. else:
  568. tag = None
  569. return CertificateSigningRequestBuilder(
  570. self._subject_name,
  571. self._extensions,
  572. self._attributes + [(oid, value, tag)],
  573. )
  574. def sign(
  575. self,
  576. private_key: CertificateIssuerPrivateKeyTypes,
  577. algorithm: typing.Optional[_AllowedHashTypes],
  578. backend: typing.Any = None,
  579. ) -> CertificateSigningRequest:
  580. """
  581. Signs the request using the requestor's private key.
  582. """
  583. if self._subject_name is None:
  584. raise ValueError("A CertificateSigningRequest must have a subject")
  585. return rust_x509.create_x509_csr(self, private_key, algorithm)
  586. class CertificateBuilder:
  587. _extensions: typing.List[Extension[ExtensionType]]
  588. def __init__(
  589. self,
  590. issuer_name: typing.Optional[Name] = None,
  591. subject_name: typing.Optional[Name] = None,
  592. public_key: typing.Optional[CertificatePublicKeyTypes] = None,
  593. serial_number: typing.Optional[int] = None,
  594. not_valid_before: typing.Optional[datetime.datetime] = None,
  595. not_valid_after: typing.Optional[datetime.datetime] = None,
  596. extensions: typing.List[Extension[ExtensionType]] = [],
  597. ) -> None:
  598. self._version = Version.v3
  599. self._issuer_name = issuer_name
  600. self._subject_name = subject_name
  601. self._public_key = public_key
  602. self._serial_number = serial_number
  603. self._not_valid_before = not_valid_before
  604. self._not_valid_after = not_valid_after
  605. self._extensions = extensions
  606. def issuer_name(self, name: Name) -> CertificateBuilder:
  607. """
  608. Sets the CA's distinguished name.
  609. """
  610. if not isinstance(name, Name):
  611. raise TypeError("Expecting x509.Name object.")
  612. if self._issuer_name is not None:
  613. raise ValueError("The issuer name may only be set once.")
  614. return CertificateBuilder(
  615. name,
  616. self._subject_name,
  617. self._public_key,
  618. self._serial_number,
  619. self._not_valid_before,
  620. self._not_valid_after,
  621. self._extensions,
  622. )
  623. def subject_name(self, name: Name) -> CertificateBuilder:
  624. """
  625. Sets the requestor's distinguished name.
  626. """
  627. if not isinstance(name, Name):
  628. raise TypeError("Expecting x509.Name object.")
  629. if self._subject_name is not None:
  630. raise ValueError("The subject name may only be set once.")
  631. return CertificateBuilder(
  632. self._issuer_name,
  633. name,
  634. self._public_key,
  635. self._serial_number,
  636. self._not_valid_before,
  637. self._not_valid_after,
  638. self._extensions,
  639. )
  640. def public_key(
  641. self,
  642. key: CertificatePublicKeyTypes,
  643. ) -> CertificateBuilder:
  644. """
  645. Sets the requestor's public key (as found in the signing request).
  646. """
  647. if not isinstance(
  648. key,
  649. (
  650. dsa.DSAPublicKey,
  651. rsa.RSAPublicKey,
  652. ec.EllipticCurvePublicKey,
  653. ed25519.Ed25519PublicKey,
  654. ed448.Ed448PublicKey,
  655. x25519.X25519PublicKey,
  656. x448.X448PublicKey,
  657. ),
  658. ):
  659. raise TypeError(
  660. "Expecting one of DSAPublicKey, RSAPublicKey,"
  661. " EllipticCurvePublicKey, Ed25519PublicKey,"
  662. " Ed448PublicKey, X25519PublicKey, or "
  663. "X448PublicKey."
  664. )
  665. if self._public_key is not None:
  666. raise ValueError("The public key may only be set once.")
  667. return CertificateBuilder(
  668. self._issuer_name,
  669. self._subject_name,
  670. key,
  671. self._serial_number,
  672. self._not_valid_before,
  673. self._not_valid_after,
  674. self._extensions,
  675. )
  676. def serial_number(self, number: int) -> CertificateBuilder:
  677. """
  678. Sets the certificate serial number.
  679. """
  680. if not isinstance(number, int):
  681. raise TypeError("Serial number must be of integral type.")
  682. if self._serial_number is not None:
  683. raise ValueError("The serial number may only be set once.")
  684. if number <= 0:
  685. raise ValueError("The serial number should be positive.")
  686. # ASN.1 integers are always signed, so most significant bit must be
  687. # zero.
  688. if number.bit_length() >= 160: # As defined in RFC 5280
  689. raise ValueError(
  690. "The serial number should not be more than 159 " "bits."
  691. )
  692. return CertificateBuilder(
  693. self._issuer_name,
  694. self._subject_name,
  695. self._public_key,
  696. number,
  697. self._not_valid_before,
  698. self._not_valid_after,
  699. self._extensions,
  700. )
  701. def not_valid_before(self, time: datetime.datetime) -> CertificateBuilder:
  702. """
  703. Sets the certificate activation time.
  704. """
  705. if not isinstance(time, datetime.datetime):
  706. raise TypeError("Expecting datetime object.")
  707. if self._not_valid_before is not None:
  708. raise ValueError("The not valid before may only be set once.")
  709. time = _convert_to_naive_utc_time(time)
  710. if time < _EARLIEST_UTC_TIME:
  711. raise ValueError(
  712. "The not valid before date must be on or after"
  713. " 1950 January 1)."
  714. )
  715. if self._not_valid_after is not None and time > self._not_valid_after:
  716. raise ValueError(
  717. "The not valid before date must be before the not valid after "
  718. "date."
  719. )
  720. return CertificateBuilder(
  721. self._issuer_name,
  722. self._subject_name,
  723. self._public_key,
  724. self._serial_number,
  725. time,
  726. self._not_valid_after,
  727. self._extensions,
  728. )
  729. def not_valid_after(self, time: datetime.datetime) -> CertificateBuilder:
  730. """
  731. Sets the certificate expiration time.
  732. """
  733. if not isinstance(time, datetime.datetime):
  734. raise TypeError("Expecting datetime object.")
  735. if self._not_valid_after is not None:
  736. raise ValueError("The not valid after may only be set once.")
  737. time = _convert_to_naive_utc_time(time)
  738. if time < _EARLIEST_UTC_TIME:
  739. raise ValueError(
  740. "The not valid after date must be on or after"
  741. " 1950 January 1."
  742. )
  743. if (
  744. self._not_valid_before is not None
  745. and time < self._not_valid_before
  746. ):
  747. raise ValueError(
  748. "The not valid after date must be after the not valid before "
  749. "date."
  750. )
  751. return CertificateBuilder(
  752. self._issuer_name,
  753. self._subject_name,
  754. self._public_key,
  755. self._serial_number,
  756. self._not_valid_before,
  757. time,
  758. self._extensions,
  759. )
  760. def add_extension(
  761. self, extval: ExtensionType, critical: bool
  762. ) -> CertificateBuilder:
  763. """
  764. Adds an X.509 extension to the certificate.
  765. """
  766. if not isinstance(extval, ExtensionType):
  767. raise TypeError("extension must be an ExtensionType")
  768. extension = Extension(extval.oid, critical, extval)
  769. _reject_duplicate_extension(extension, self._extensions)
  770. return CertificateBuilder(
  771. self._issuer_name,
  772. self._subject_name,
  773. self._public_key,
  774. self._serial_number,
  775. self._not_valid_before,
  776. self._not_valid_after,
  777. self._extensions + [extension],
  778. )
  779. def sign(
  780. self,
  781. private_key: CertificateIssuerPrivateKeyTypes,
  782. algorithm: typing.Optional[_AllowedHashTypes],
  783. backend: typing.Any = None,
  784. *,
  785. rsa_padding: typing.Optional[
  786. typing.Union[padding.PSS, padding.PKCS1v15]
  787. ] = None,
  788. ) -> Certificate:
  789. """
  790. Signs the certificate using the CA's private key.
  791. """
  792. if self._subject_name is None:
  793. raise ValueError("A certificate must have a subject name")
  794. if self._issuer_name is None:
  795. raise ValueError("A certificate must have an issuer name")
  796. if self._serial_number is None:
  797. raise ValueError("A certificate must have a serial number")
  798. if self._not_valid_before is None:
  799. raise ValueError("A certificate must have a not valid before time")
  800. if self._not_valid_after is None:
  801. raise ValueError("A certificate must have a not valid after time")
  802. if self._public_key is None:
  803. raise ValueError("A certificate must have a public key")
  804. if rsa_padding is not None:
  805. if not isinstance(rsa_padding, (padding.PSS, padding.PKCS1v15)):
  806. raise TypeError("Padding must be PSS or PKCS1v15")
  807. if not isinstance(private_key, rsa.RSAPrivateKey):
  808. raise TypeError("Padding is only supported for RSA keys")
  809. return rust_x509.create_x509_certificate(
  810. self, private_key, algorithm, rsa_padding
  811. )
  812. class CertificateRevocationListBuilder:
  813. _extensions: typing.List[Extension[ExtensionType]]
  814. _revoked_certificates: typing.List[RevokedCertificate]
  815. def __init__(
  816. self,
  817. issuer_name: typing.Optional[Name] = None,
  818. last_update: typing.Optional[datetime.datetime] = None,
  819. next_update: typing.Optional[datetime.datetime] = None,
  820. extensions: typing.List[Extension[ExtensionType]] = [],
  821. revoked_certificates: typing.List[RevokedCertificate] = [],
  822. ):
  823. self._issuer_name = issuer_name
  824. self._last_update = last_update
  825. self._next_update = next_update
  826. self._extensions = extensions
  827. self._revoked_certificates = revoked_certificates
  828. def issuer_name(
  829. self, issuer_name: Name
  830. ) -> CertificateRevocationListBuilder:
  831. if not isinstance(issuer_name, Name):
  832. raise TypeError("Expecting x509.Name object.")
  833. if self._issuer_name is not None:
  834. raise ValueError("The issuer name may only be set once.")
  835. return CertificateRevocationListBuilder(
  836. issuer_name,
  837. self._last_update,
  838. self._next_update,
  839. self._extensions,
  840. self._revoked_certificates,
  841. )
  842. def last_update(
  843. self, last_update: datetime.datetime
  844. ) -> CertificateRevocationListBuilder:
  845. if not isinstance(last_update, datetime.datetime):
  846. raise TypeError("Expecting datetime object.")
  847. if self._last_update is not None:
  848. raise ValueError("Last update may only be set once.")
  849. last_update = _convert_to_naive_utc_time(last_update)
  850. if last_update < _EARLIEST_UTC_TIME:
  851. raise ValueError(
  852. "The last update date must be on or after" " 1950 January 1."
  853. )
  854. if self._next_update is not None and last_update > self._next_update:
  855. raise ValueError(
  856. "The last update date must be before the next update date."
  857. )
  858. return CertificateRevocationListBuilder(
  859. self._issuer_name,
  860. last_update,
  861. self._next_update,
  862. self._extensions,
  863. self._revoked_certificates,
  864. )
  865. def next_update(
  866. self, next_update: datetime.datetime
  867. ) -> CertificateRevocationListBuilder:
  868. if not isinstance(next_update, datetime.datetime):
  869. raise TypeError("Expecting datetime object.")
  870. if self._next_update is not None:
  871. raise ValueError("Last update may only be set once.")
  872. next_update = _convert_to_naive_utc_time(next_update)
  873. if next_update < _EARLIEST_UTC_TIME:
  874. raise ValueError(
  875. "The last update date must be on or after" " 1950 January 1."
  876. )
  877. if self._last_update is not None and next_update < self._last_update:
  878. raise ValueError(
  879. "The next update date must be after the last update date."
  880. )
  881. return CertificateRevocationListBuilder(
  882. self._issuer_name,
  883. self._last_update,
  884. next_update,
  885. self._extensions,
  886. self._revoked_certificates,
  887. )
  888. def add_extension(
  889. self, extval: ExtensionType, critical: bool
  890. ) -> CertificateRevocationListBuilder:
  891. """
  892. Adds an X.509 extension to the certificate revocation list.
  893. """
  894. if not isinstance(extval, ExtensionType):
  895. raise TypeError("extension must be an ExtensionType")
  896. extension = Extension(extval.oid, critical, extval)
  897. _reject_duplicate_extension(extension, self._extensions)
  898. return CertificateRevocationListBuilder(
  899. self._issuer_name,
  900. self._last_update,
  901. self._next_update,
  902. self._extensions + [extension],
  903. self._revoked_certificates,
  904. )
  905. def add_revoked_certificate(
  906. self, revoked_certificate: RevokedCertificate
  907. ) -> CertificateRevocationListBuilder:
  908. """
  909. Adds a revoked certificate to the CRL.
  910. """
  911. if not isinstance(revoked_certificate, RevokedCertificate):
  912. raise TypeError("Must be an instance of RevokedCertificate")
  913. return CertificateRevocationListBuilder(
  914. self._issuer_name,
  915. self._last_update,
  916. self._next_update,
  917. self._extensions,
  918. self._revoked_certificates + [revoked_certificate],
  919. )
  920. def sign(
  921. self,
  922. private_key: CertificateIssuerPrivateKeyTypes,
  923. algorithm: typing.Optional[_AllowedHashTypes],
  924. backend: typing.Any = None,
  925. ) -> CertificateRevocationList:
  926. if self._issuer_name is None:
  927. raise ValueError("A CRL must have an issuer name")
  928. if self._last_update is None:
  929. raise ValueError("A CRL must have a last update time")
  930. if self._next_update is None:
  931. raise ValueError("A CRL must have a next update time")
  932. return rust_x509.create_x509_crl(self, private_key, algorithm)
  933. class RevokedCertificateBuilder:
  934. def __init__(
  935. self,
  936. serial_number: typing.Optional[int] = None,
  937. revocation_date: typing.Optional[datetime.datetime] = None,
  938. extensions: typing.List[Extension[ExtensionType]] = [],
  939. ):
  940. self._serial_number = serial_number
  941. self._revocation_date = revocation_date
  942. self._extensions = extensions
  943. def serial_number(self, number: int) -> RevokedCertificateBuilder:
  944. if not isinstance(number, int):
  945. raise TypeError("Serial number must be of integral type.")
  946. if self._serial_number is not None:
  947. raise ValueError("The serial number may only be set once.")
  948. if number <= 0:
  949. raise ValueError("The serial number should be positive")
  950. # ASN.1 integers are always signed, so most significant bit must be
  951. # zero.
  952. if number.bit_length() >= 160: # As defined in RFC 5280
  953. raise ValueError(
  954. "The serial number should not be more than 159 " "bits."
  955. )
  956. return RevokedCertificateBuilder(
  957. number, self._revocation_date, self._extensions
  958. )
  959. def revocation_date(
  960. self, time: datetime.datetime
  961. ) -> RevokedCertificateBuilder:
  962. if not isinstance(time, datetime.datetime):
  963. raise TypeError("Expecting datetime object.")
  964. if self._revocation_date is not None:
  965. raise ValueError("The revocation date may only be set once.")
  966. time = _convert_to_naive_utc_time(time)
  967. if time < _EARLIEST_UTC_TIME:
  968. raise ValueError(
  969. "The revocation date must be on or after" " 1950 January 1."
  970. )
  971. return RevokedCertificateBuilder(
  972. self._serial_number, time, self._extensions
  973. )
  974. def add_extension(
  975. self, extval: ExtensionType, critical: bool
  976. ) -> RevokedCertificateBuilder:
  977. if not isinstance(extval, ExtensionType):
  978. raise TypeError("extension must be an ExtensionType")
  979. extension = Extension(extval.oid, critical, extval)
  980. _reject_duplicate_extension(extension, self._extensions)
  981. return RevokedCertificateBuilder(
  982. self._serial_number,
  983. self._revocation_date,
  984. self._extensions + [extension],
  985. )
  986. def build(self, backend: typing.Any = None) -> RevokedCertificate:
  987. if self._serial_number is None:
  988. raise ValueError("A revoked certificate must have a serial number")
  989. if self._revocation_date is None:
  990. raise ValueError(
  991. "A revoked certificate must have a revocation date"
  992. )
  993. return _RawRevokedCertificate(
  994. self._serial_number,
  995. self._revocation_date,
  996. Extensions(self._extensions),
  997. )
  998. def random_serial_number() -> int:
  999. return int.from_bytes(os.urandom(20), "big") >> 1