cert-utils 0.2.0__tar.gz → 1.0.0__tar.gz

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.
Files changed (196) hide show
  1. {cert_utils-0.2.0 → cert_utils-1.0.0}/CHANGES.txt +17 -0
  2. cert_utils-1.0.0/PKG-INFO +208 -0
  3. {cert_utils-0.2.0 → cert_utils-1.0.0}/setup.py +3 -2
  4. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/__init__.py +2 -1
  5. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/compat/cryptography.py +11 -5
  6. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/compat/openssl.py +179 -23
  7. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/compat/pyopenssl.py +1 -0
  8. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/conditionals.py +21 -9
  9. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/core.py +440 -201
  10. cert_utils-1.0.0/src/cert_utils/model.py +139 -0
  11. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/scripts/cert_info.py +1 -0
  12. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/utils.py +13 -136
  13. cert_utils-1.0.0/src/cert_utils.egg-info/PKG-INFO +208 -0
  14. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils.egg-info/SOURCES.txt +2 -0
  15. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/_utils.py +18 -10
  16. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/draft-acme-ari/edge_case_generate.py +2 -1
  17. cert_utils-1.0.0/tests/test_data/unit_tests/account_002/private_key.pem +51 -0
  18. cert_utils-1.0.0/tests/test_data/unit_tests/account_003/private_key.pem +6 -0
  19. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_unit.py +116 -32
  20. cert_utils-0.2.0/PKG-INFO +0 -211
  21. cert_utils-0.2.0/src/cert_utils/model.py +0 -103
  22. cert_utils-0.2.0/src/cert_utils.egg-info/PKG-INFO +0 -211
  23. {cert_utils-0.2.0 → cert_utils-1.0.0}/LICENSE.txt +0 -0
  24. {cert_utils-0.2.0 → cert_utils-1.0.0}/MANIFEST.in +0 -0
  25. {cert_utils-0.2.0 → cert_utils-1.0.0}/README.md +0 -0
  26. {cert_utils-0.2.0 → cert_utils-1.0.0}/pyproject.toml +0 -0
  27. {cert_utils-0.2.0 → cert_utils-1.0.0}/setup.cfg +0 -0
  28. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/compat/deprecated.py +0 -0
  29. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/convert.py +0 -0
  30. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/errors.py +0 -0
  31. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/letsencrypt-certs/e5-cross.pem +0 -0
  32. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/letsencrypt-certs/e5.pem +0 -0
  33. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/letsencrypt-certs/e6-cross.pem +0 -0
  34. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/letsencrypt-certs/e6.pem +0 -0
  35. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/letsencrypt-certs/e7-cross.pem +0 -0
  36. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/letsencrypt-certs/e7.pem +0 -0
  37. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/letsencrypt-certs/e8-cross.pem +0 -0
  38. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/letsencrypt-certs/e8.pem +0 -0
  39. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/letsencrypt-certs/e9-cross.pem +0 -0
  40. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/letsencrypt-certs/e9.pem +0 -0
  41. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/letsencrypt-certs/fakeleintermediatex1.pem +0 -0
  42. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/letsencrypt-certs/fakelerootx1.pem +0 -0
  43. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/letsencrypt-certs/isrg-root-ocsp-x1.pem +0 -0
  44. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/letsencrypt-certs/isrg-root-x1-cross-signed.pem +0 -0
  45. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/letsencrypt-certs/isrg-root-x2-cross-signed.pem +0 -0
  46. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/letsencrypt-certs/isrg-root-x2.pem +0 -0
  47. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/letsencrypt-certs/isrgrootx1.pem +0 -0
  48. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/letsencrypt-certs/isrgrootx1.pkix +0 -0
  49. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/letsencrypt-certs/lets-encrypt-e1.pem +0 -0
  50. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/letsencrypt-certs/lets-encrypt-e2.pem +0 -0
  51. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/letsencrypt-certs/lets-encrypt-r3-cross-signed.pem +0 -0
  52. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/letsencrypt-certs/lets-encrypt-r3.pem +0 -0
  53. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/letsencrypt-certs/lets-encrypt-r4-cross-signed.pem +0 -0
  54. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/letsencrypt-certs/lets-encrypt-r4.pem +0 -0
  55. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/letsencrypt-certs/lets-encrypt-x1-cross-signed.pem +0 -0
  56. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/letsencrypt-certs/lets-encrypt-x2-cross-signed.pem +0 -0
  57. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/letsencrypt-certs/lets-encrypt-x3-cross-signed.pem +0 -0
  58. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/letsencrypt-certs/lets-encrypt-x4-cross-signed.pem +0 -0
  59. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/letsencrypt-certs/letsencryptauthorityx1.pem +0 -0
  60. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/letsencrypt-certs/letsencryptauthorityx2.pem +0 -0
  61. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/letsencrypt-certs/letsencryptauthorityx3.pem +0 -0
  62. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/letsencrypt-certs/letsencryptauthorityx4.pem +0 -0
  63. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/letsencrypt-certs/r10.pem +0 -0
  64. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/letsencrypt-certs/r11.pem +0 -0
  65. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/letsencrypt-certs/r12.pem +0 -0
  66. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/letsencrypt-certs/r13.pem +0 -0
  67. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/letsencrypt-certs/r14.pem +0 -0
  68. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/letsencrypt-certs/trustid-x3-root.p7c +0 -0
  69. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/letsencrypt-certs/trustid-x3-root.pem +0 -0
  70. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/letsencrypt_info.py +0 -0
  71. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils/py.typed +0 -0
  72. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils.egg-info/dependency_links.txt +0 -0
  73. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils.egg-info/entry_points.txt +0 -0
  74. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils.egg-info/not-zip-safe +0 -0
  75. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils.egg-info/requires.txt +0 -0
  76. {cert_utils-0.2.0 → cert_utils-1.0.0}/src/cert_utils.egg-info/top_level.txt +0 -0
  77. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/__init__.py +0 -0
  78. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/__README__.txt +0 -0
  79. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/alternate_chains/1/__README__.txt +0 -0
  80. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/alternate_chains/1/alternate_chains/1/chain.pem +0 -0
  81. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/alternate_chains/1/alternate_chains/1/fullchain.pem +0 -0
  82. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/alternate_chains/1/alternate_chains/2/chain.pem +0 -0
  83. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/alternate_chains/1/alternate_chains/2/fullchain.pem +0 -0
  84. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/alternate_chains/1/cert.pem +0 -0
  85. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/alternate_chains/1/chain.pem +0 -0
  86. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/alternate_chains/1/fullchain.pem +0 -0
  87. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/alternate_chains/1/privkey.pem +0 -0
  88. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/draft-acme-ari/appendix_a-cert.pem +0 -0
  89. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/draft-acme-ari/cert--all.pem +0 -0
  90. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/draft-acme-ari/cert--issuer+serial.pem +0 -0
  91. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/draft-acme-ari/cert--key_id.pem +0 -0
  92. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/key_technology-ec/ec384-1-key.pem +0 -0
  93. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/key_technology-ec/ec384-1.csr +0 -0
  94. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/key_technology-ec/ec384-2-key.pem +0 -0
  95. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/key_technology-rsa/AcmeAccountKey-1.pem +0 -0
  96. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/key_technology-rsa/AcmeAccountKey-2.pem +0 -0
  97. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/key_technology-rsa/AcmeAccountKey-3.pem +0 -0
  98. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/key_technology-rsa/AcmeAccountKey-4.pem +0 -0
  99. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/key_technology-rsa/AcmeAccountKey-5.pem +0 -0
  100. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/key_technology-rsa/AcmeAccountKey-cycle-account_daily.pem +0 -0
  101. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/key_technology-rsa/AcmeAccountKey-cycle-account_weekly.pem +0 -0
  102. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/key_technology-rsa/AcmeAccountKey-cycle-global_daily.pem +0 -0
  103. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/key_technology-rsa/AcmeAccountKey-cycle-global_weekly.pem +0 -0
  104. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/key_technology-rsa/AcmeAccountKey-cycle-single_certificate.pem +0 -0
  105. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/key_technology-rsa/acme_account_1.key +0 -0
  106. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/key_technology-rsa/acme_account_2.key +0 -0
  107. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/key_technology-rsa/acme_account_3.key +0 -0
  108. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/key_technology-rsa/acme_account_4.key +0 -0
  109. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/key_technology-rsa/acme_account_5.key +0 -0
  110. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/key_technology-rsa/private_1.key +0 -0
  111. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/key_technology-rsa/private_2.key +0 -0
  112. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/key_technology-rsa/private_3.key +0 -0
  113. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/key_technology-rsa/private_4.key +0 -0
  114. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/key_technology-rsa/private_5.key +0 -0
  115. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/key_technology-rsa/selfsigned_1-server.crt +0 -0
  116. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/key_technology-rsa/selfsigned_1-server.csr +0 -0
  117. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/key_technology-rsa/selfsigned_1-server.key +0 -0
  118. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/key_technology-rsa/selfsigned_2-server.crt +0 -0
  119. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/key_technology-rsa/selfsigned_2-server.csr +0 -0
  120. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/key_technology-rsa/selfsigned_2-server.key +0 -0
  121. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/key_technology-rsa/selfsigned_3-server.crt +0 -0
  122. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/key_technology-rsa/selfsigned_3-server.csr +0 -0
  123. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/key_technology-rsa/selfsigned_3-server.key +0 -0
  124. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/key_technology-rsa/selfsigned_4-server.crt +0 -0
  125. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/key_technology-rsa/selfsigned_4-server.csr +0 -0
  126. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/key_technology-rsa/selfsigned_4-server.key +0 -0
  127. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/key_technology-rsa/selfsigned_5-server.crt +0 -0
  128. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/key_technology-rsa/selfsigned_5-server.csr +0 -0
  129. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/key_technology-rsa/selfsigned_5-server.key +0 -0
  130. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/long_chains/TestA/__README__.txt +0 -0
  131. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/long_chains/TestA/_data.json +0 -0
  132. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/long_chains/TestA/_demo.py +0 -0
  133. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/long_chains/TestA/cert.pem +0 -0
  134. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/long_chains/TestA/chain_0.pem +0 -0
  135. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/long_chains/TestA/chain_0_bad.pem +0 -0
  136. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/long_chains/TestA/chain_1.pem +0 -0
  137. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/long_chains/TestA/chain_2.pem +0 -0
  138. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/long_chains/TestA/root_0.pem +0 -0
  139. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/long_chains/TestA/root_1.pem +0 -0
  140. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/long_chains/TestA/root_2.pem +0 -0
  141. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/long_chains/__README__.txt +0 -0
  142. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/pebble-certs/cert1.pem +0 -0
  143. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/pebble-certs/cert2.pem +0 -0
  144. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/pebble-certs/cert3.pem +0 -0
  145. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/pebble-certs/cert4.pem +0 -0
  146. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/pebble-certs/cert5.pem +0 -0
  147. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/pebble-certs/cert6.pem +0 -0
  148. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/pebble-certs/chain1.pem +0 -0
  149. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/pebble-certs/chain2.pem +0 -0
  150. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/pebble-certs/chain3.pem +0 -0
  151. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/pebble-certs/chain4.pem +0 -0
  152. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/pebble-certs/chain5.pem +0 -0
  153. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/pebble-certs/chain6.pem +0 -0
  154. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/pebble-certs/fullchain1.pem +0 -0
  155. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/pebble-certs/fullchain2.pem +0 -0
  156. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/pebble-certs/fullchain3.pem +0 -0
  157. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/pebble-certs/fullchain4.pem +0 -0
  158. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/pebble-certs/fullchain5.pem +0 -0
  159. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/pebble-certs/fullchain6.pem +0 -0
  160. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/pebble-certs/privkey1.pem +0 -0
  161. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/pebble-certs/privkey2.pem +0 -0
  162. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/pebble-certs/privkey3.pem +0 -0
  163. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/pebble-certs/privkey4.pem +0 -0
  164. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/pebble-certs/privkey5.pem +0 -0
  165. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/pebble-certs/privkey6.pem +0 -0
  166. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/unit_tests/_support/account.key +0 -0
  167. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/unit_tests/_support/info.txt +0 -0
  168. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/unit_tests/account_001/info.txt +0 -0
  169. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/unit_tests/account_001/meta.json +0 -0
  170. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/unit_tests/account_001/private_key.json +0 -0
  171. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/unit_tests/account_001/private_key.pem +0 -0
  172. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/unit_tests/account_001/regr.json +0 -0
  173. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/unit_tests/cert_001/cert.pem +0 -0
  174. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/unit_tests/cert_001/chain.pem +0 -0
  175. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/unit_tests/cert_001/csr.pem +0 -0
  176. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/unit_tests/cert_001/fullchain.pem +0 -0
  177. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/unit_tests/cert_001/info.txt +0 -0
  178. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/unit_tests/cert_001/privkey.pem +0 -0
  179. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/unit_tests/cert_001/test.py +0 -0
  180. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/unit_tests/cert_002/csr.pem +0 -0
  181. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/unit_tests/cert_002/info.txt +0 -0
  182. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/unit_tests/cert_002/privkey.pem +0 -0
  183. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/unit_tests/cert_003/cert.pem +0 -0
  184. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/unit_tests/cert_003/csr.pem +0 -0
  185. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/unit_tests/cert_003/fullchain.pem +0 -0
  186. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/unit_tests/cert_003/info.txt +0 -0
  187. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/unit_tests/cert_003/privkey.pem +0 -0
  188. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/unit_tests/cert_004/cert.pem +0 -0
  189. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/unit_tests/cert_004/csr.pem +0 -0
  190. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/unit_tests/cert_004/fullchain.pem +0 -0
  191. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/unit_tests/cert_004/info.txt +0 -0
  192. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/unit_tests/cert_004/privkey.pem +0 -0
  193. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/unit_tests/cert_005/csr.pem +0 -0
  194. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/unit_tests/cert_005/info.txt +0 -0
  195. {cert_utils-0.2.0 → cert_utils-1.0.0}/tests/test_data/unit_tests/cert_005/privkey.pem +0 -0
  196. {cert_utils-0.2.0 → cert_utils-1.0.0}/tox.ini +0 -0
@@ -1,3 +1,20 @@
1
+ 1.0.0
2
+ * new_account_key supports LetsEncrypt updates to EC
3
+ * ALLOWED_CURVES_ECDSA is now a list of strings
4
+ * new_ec_key named argument is now curve(str)
5
+ * functions now require KeyTechnologyEnum, not KeyTechnology for key_technology_id
6
+ * added account_key__verify
7
+ * extended account_key__sign to accept `standardize_signature`; default True
8
+ for converting the EC signature to the encoding ACME requires
9
+ * corrected use of `secp256k1` to `secp256r1`
10
+ * `key_technology` concept of "RSA" and "EC" has been renamed to `key_technology_basic`
11
+ * `key_technology` concept is now a tuple of `(key_technology_basic, (data, ))`
12
+ For a RSA, the payload is:
13
+ ("rsa", (rsa_bits,))
14
+ For an EC, the payload is:
15
+ ("ec", (nist_curve_name,))
16
+ * validate_domains now accepts a wildcard
17
+
1
18
  0.2.0
2
19
  * replaced pyopenssl with cryptography.
3
20
  pyopenssl was originally used because certbot required it and this package
@@ -0,0 +1,208 @@
1
+ Metadata-Version: 2.1
2
+ Name: cert_utils
3
+ Version: 1.0.0
4
+ Summary: TLS/SSL Certiicate Utilities
5
+ Home-page: https://github.com/aptise/cert_utils
6
+ Author: Jonathan Vanasco
7
+ Author-email: jonathan@findmeon.com
8
+ License: MIT
9
+ Description: ![Python package](https://github.com/jvanasco/cert_utils/workflows/Python%20package/badge.svg)
10
+
11
+ cert_utils
12
+ ==========
13
+
14
+ **cert_utils** offers support for common operations when dealing with SSL
15
+ Certificates, specifically within the LetsEncrypt ecosystem.
16
+
17
+ This library was originally developed as a toolkit for bugfixing and
18
+ troubleshooting large ACME installations.
19
+
20
+ **cert_utils** will attempt to process operations with Python via the modern
21
+ [Cryptography](https://cryptography.io/en/latest/) package when possible.
22
+ If the required Python libraries are not installed, it will fallback to using
23
+ OpenSSL commandline via subprocesses. **cert_utils** does a bit of work to
24
+ standardize certificate operations across versions of Python and OpenSSL that
25
+ do not share the same inputs, outputs or invocations.
26
+
27
+ **cert_utils** was formerly part of the
28
+ **[peter_sslers](https://github.com/aptise/peter_sslers)** ACME Client and
29
+ Certificate Management System, and has been descoped into it's own library.
30
+
31
+ This library *does not* process Certificates and Certificate Data itself.
32
+ Instead, it offers a simplified API to invoke other libraries and extract data
33
+ from Certificates. It was designed for developers and system administrators to
34
+ more easily use the various libraries to accomplish specific tasks on the
35
+ commandline or as part of other projects.
36
+
37
+ This library now includes a utility, `cert_info`:
38
+
39
+ Examples CLI:
40
+ -------------
41
+
42
+ The CLI tool `cert_info` can parse a cert and pull the active ARI info.
43
+
44
+ The tool accepts a filepath to a local file OR a https URL to be inspected live:
45
+
46
+ > cert_info https://letsencrypt.org
47
+
48
+ This will gnerate the output:
49
+
50
+ ********************************************************************************
51
+ ********************************************************************************
52
+ Process URL:
53
+ url: https://letsencrypt.org
54
+ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
55
+ Connection Data:
56
+ {'cert_dict': {'OCSP': ('http://e6.o.lencr.org',),
57
+ 'caIssuers': ('http://e6.i.lencr.org/',),
58
+ 'issuer': ((('countryName', 'US'),),
59
+ (('organizationName', "Let's Encrypt"),),
60
+ (('commonName', 'E6'),)),
61
+ 'notAfter': 'Mar 7 14:44:04 2025 GMT',
62
+ 'notBefore': 'Dec 7 14:44:05 2024 GMT',
63
+ 'serialNumber': '04C7A73A361AC02B67BDBD6AF210285B1CC7',
64
+ 'subject': ((('commonName', 'letsencrypt.org'),),),
65
+ 'subjectAltName': (('DNS', 'lencr.org'),
66
+ ('DNS', 'letsencrypt.com'),
67
+ ('DNS', 'letsencrypt.org'),
68
+ ('DNS', 'www.lencr.org'),
69
+ ('DNS', 'www.letsencrypt.com'),
70
+ ('DNS', 'www.letsencrypt.org')),
71
+ 'version': 3},
72
+ 'cert_pem': '-----BEGIN CERTIFICATE-----\n'
73
+ 'MIID1DCCA1qgAwIBAgISBMenOjYawCtnvb1q8hAoWxzHMAoGCCqGSM49BAMDMDIx\n'
74
+ 'CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQDEwJF\n'
75
+ 'NjAeFw0yNDEyMDcxNDQ0MDVaFw0yNTAzMDcxNDQ0MDRaMBoxGDAWBgNVBAMTD2xl\n'
76
+ 'dHNlbmNyeXB0Lm9yZzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABDgHHaIeMwYz\n'
77
+ 'APO9ZgfeGansUeFRN0sW4K23nrVppRXfjHvN+83vtH170hshCrIAZRJCL+CPcA2N\n'
78
+ 'UqmLiSdM/M+jggJmMIICYjAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0lBBYwFAYIKwYB\n'
79
+ 'BQUHAwEGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFD2MLtcnwBWM\n'
80
+ 'FukcX4wMfYCQUCMAMB8GA1UdIwQYMBaAFJMnRpgDqVFojpjWxEJI2yO/WJTSMFUG\n'
81
+ 'CCsGAQUFBwEBBEkwRzAhBggrBgEFBQcwAYYVaHR0cDovL2U2Lm8ubGVuY3Iub3Jn\n'
82
+ 'MCIGCCsGAQUFBzAChhZodHRwOi8vZTYuaS5sZW5jci5vcmcvMG8GA1UdEQRoMGaC\n'
83
+ 'CWxlbmNyLm9yZ4IPbGV0c2VuY3J5cHQuY29tgg9sZXRzZW5jcnlwdC5vcmeCDXd3\n'
84
+ 'dy5sZW5jci5vcmeCE3d3dy5sZXRzZW5jcnlwdC5jb22CE3d3dy5sZXRzZW5jcnlw\n'
85
+ 'dC5vcmcwEwYDVR0gBAwwCjAIBgZngQwBAgEwggEEBgorBgEEAdZ5AgQCBIH1BIHy\n'
86
+ 'APAAdgB9WR4S4XgqexxhZ3xe/fjQh1wUoE6VnrkDL9kOjC55uAAAAZOhyXh9AAAE\n'
87
+ 'AwBHMEUCIAXoVc0BRK6ELL0Q1lHv+QbrobnBiPthcr2E7g0IulkHAiEAlVkiVkF9\n'
88
+ '7KeR/At3XdJNRYbJda0iKaKtqKy0KH7igZgAdgATSt8atZhCCXgMb+9MepGkFrcj\n'
89
+ 'Sc5YV2rfrtqnwqvgIgAAAZOhyXk0AAAEAwBHMEUCIQD+yhm/6lwMMWyxBaB15Mkh\n'
90
+ 'g3tsQCtr0DOD4uvAzc63FAIgHgjXduGCbB/3VTtRCGWfmkWSS9z+CjfO1O6hkzGW\n'
91
+ 'XBowCgYIKoZIzj0EAwMDaAAwZQIxAKVLzxW03Kk8qJMBtWQCw5dgSHNWOGG9Oq03\n'
92
+ 'XOGr8092sx9Ezz3XsXWeq8JvokFjhAIwCZOX/UjxdHfgV/O6gkiNARQ1FokDyfS0\n'
93
+ 'ClynPk9psMTPVl5QWgYJzjVrJagAjtJm\n'
94
+ '-----END CERTIFICATE-----\n',
95
+ 'peername': ('100.28.201.155', 443)}
96
+ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
97
+ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
98
+ Cert Data:
99
+ ARI ID: kydGmAOpUWiOmNbEQkjbI79YlNI.BMenOjYawCtnvb1q8hAoWxzH
100
+ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
101
+ Requesting ARI
102
+ ari_url: https://acme-v02.api.letsencrypt.org/draft-ietf-acme-ari-03/renewalInfo/kydGmAOpUWiOmNbEQkjbI79YlNI.BMenOjYawCtnvb1q8hAoWxzH
103
+ {'Server': 'nginx', 'Date': 'Tue, 10 Dec 2024 18:29:04 GMT', 'Content-Type': 'application/json', 'Content-Length': '101', 'Connection': 'keep-alive', 'Cache-Control': 'public, max-age=0, no-cache', 'Link': '<https://acme-v02.api.letsencrypt.org/directory>;rel="index"', 'Retry-After': '21600', 'X-Frame-Options': 'DENY', 'Strict-Transport-Security': 'max-age=604800'}
104
+ - - - - - - - - - -
105
+ {'suggestedWindow': {'end': '2025-02-06T15:03:34Z',
106
+ 'start': '2025-02-04T15:03:34Z'}}
107
+
108
+
109
+ Examples API:
110
+ -------------
111
+
112
+ For example, `cert_utils.parse_cert` returns a Python dict of key fields in a
113
+ certificate. This can make writing a script to analyze large directories of
114
+ certificates fairly simple.
115
+
116
+
117
+ ### Parse a Leaf/End-Entity
118
+
119
+ Example Script:
120
+
121
+ ```!python
122
+ import cert_utils
123
+ import pprint
124
+
125
+ cert_path = "./tests/test_data/unit_tests/cert_001/cert.pem"
126
+ cert_pem = open(cert_path, 'r').read()
127
+ data = cert_utils.parse_cert(cert_pem)
128
+ pprint.pprint(data)
129
+ ```
130
+
131
+ Result:
132
+
133
+ {'SubjectAlternativeName': ['a.example.com',
134
+ 'b.example.com',
135
+ 'c.example.com',
136
+ 'd.example.com'],
137
+ 'authority_key_identifier': 'D159010094B0A62ADBABE54B2321CA1B6EBA93E7',
138
+ 'enddate': datetime.datetime(2025, 6, 16, 20, 19, 30),
139
+ 'fingerprint_sha1': 'F63C5C66B52551EEDADF7CE44301D646680B8F5D',
140
+ 'issuer': 'CN=Pebble Intermediate CA 601ea1',
141
+ 'issuer_uri': None,
142
+ 'key_technology': 'RSA',
143
+ 'spki_sha256': '34E67CC615761CBADAF430B2E02E0EC39C99EEFC73CCE469B18AE54A37EF6942',
144
+ 'startdate': datetime.datetime(2020, 6, 16, 20, 19, 30),
145
+ 'subject': 'CN=a.example.com'}
146
+
147
+ The payload contains `SubjectAlternativeName` listing all the domains, along
148
+ with `enddate` and `startdate` in Python datetime objects for easy comparison.
149
+
150
+ ### Parse a Trusted Root
151
+
152
+ Example Script:
153
+
154
+ ```!python
155
+ import cert_utils
156
+ import pprint
157
+
158
+ cert_path = "./src/cert_utils/letsencrypt-certs/isrgrootx1.pem"
159
+ cert_pem = open(cert_path, 'r').read()
160
+ data = cert_utils.parse_cert(cert_pem)
161
+ pprint.pprint(data)
162
+ ```
163
+
164
+ Result:
165
+
166
+ {'SubjectAlternativeName': None,
167
+ 'authority_key_identifier': None,
168
+ 'enddate': datetime.datetime(2035, 6, 4, 11, 4, 38),
169
+ 'fingerprint_sha1': 'CABD2A79A1076A31F21D253635CB039D4329A5E8',
170
+ 'issuer': 'C=US\nO=Internet Security Research Group\nCN=ISRG Root X1',
171
+ 'issuer_uri': None,
172
+ 'key_technology': 'RSA',
173
+ 'spki_sha256': '0B9FA5A59EED715C26C1020C711B4F6EC42D58B0015E14337A39DAD301C5AFC3',
174
+ 'startdate': datetime.datetime(2015, 6, 4, 11, 4, 38),
175
+ 'subject': 'C=US\nO=Internet Security Research Group\nCN=ISRG Root X1'}
176
+
177
+ The payload on Trusted Roots is identical.
178
+
179
+
180
+ Why does this exist?
181
+ --------------------
182
+
183
+ The [peter_sslers](https://github.com/aptise/peter_sslers) project was designed
184
+ to deploy on a wide variety of production servers that did not share common
185
+ Python and OpenSSL installations. Earlier versions of the library
186
+ (within peter_sslers) supported both Python2.7 and Python3, as it was common to
187
+ encounter a machine that did not have Python3 installed. Although it is still
188
+ common to find these machines, Python2.7 was dropped to take advantage of
189
+ typing. Depending on the version of OpenSSL installed on a system,
190
+ **cert_utils** will invoke the binary or regex the output to bridge support
191
+ through a unified interface.
192
+
193
+ Keywords: web
194
+ Platform: UNKNOWN
195
+ Classifier: Intended Audience :: Developers
196
+ Classifier: Programming Language :: Python
197
+ Classifier: Programming Language :: Python :: 3
198
+ Classifier: Programming Language :: Python :: 3.7
199
+ Classifier: Programming Language :: Python :: 3.8
200
+ Classifier: Programming Language :: Python :: 3.9
201
+ Classifier: Programming Language :: Python :: 3.10
202
+ Classifier: Programming Language :: Python :: 3.11
203
+ Classifier: Programming Language :: Python :: 3.12
204
+ Classifier: Programming Language :: Python :: 3.13
205
+ Classifier: License :: OSI Approved :: MIT License
206
+ Requires-Python: >=3.7
207
+ Description-Content-Type: text/markdown
208
+ Provides-Extra: testing
@@ -1,5 +1,6 @@
1
1
  """metadata_utils installation script.
2
2
  """
3
+
3
4
  import os
4
5
  import re
5
6
 
@@ -21,7 +22,7 @@ requires = [
21
22
  "python-dateutil",
22
23
  "psutil>=4.4.0", # for Python2/3 compat
23
24
  "requests",
24
- "typing_extensions",
25
+ "typing_extensions", # Literal, Required, TypeDict
25
26
  ]
26
27
  tests_require = [
27
28
  "certbot",
@@ -46,7 +47,7 @@ setup(
46
47
  author="Jonathan Vanasco",
47
48
  author_email="jonathan@findmeon.com",
48
49
  zip_safe=False,
49
- python_requires=">=3.6",
50
+ python_requires=">=3.7",
50
51
  keywords="web",
51
52
  install_requires=requires,
52
53
  tests_require=tests_require,
@@ -1,7 +1,8 @@
1
1
  from .convert import * # noqa: F401, F403
2
2
  from .core import * # noqa: F401, F403
3
+ from .model import * # noqa: F401, F403
3
4
  from .utils import * # noqa: F401, F403
4
5
 
5
6
  # ==============================================================================
6
7
 
7
- __VERSION__ = "0.2.0"
8
+ __VERSION__ = "1.0.0"
@@ -11,6 +11,8 @@ from typing import Union
11
11
  # locals
12
12
  from .. import conditionals
13
13
  from ..utils import CERT_PEM_REGEX
14
+ from ..utils import curve_to_nist
15
+ from ..utils import TECHNOLOGY_RETURN_VALUES
14
16
 
15
17
  if TYPE_CHECKING:
16
18
  from cryptography.x509 import Certificate
@@ -52,20 +54,24 @@ def _format_cryptography_components(
52
54
 
53
55
  def _cryptography__public_key_technology(
54
56
  publickey: "_TYPES_CRYPTOGRAPHY_PUBLICKEY",
55
- ) -> Optional[str]:
57
+ ) -> Optional[TECHNOLOGY_RETURN_VALUES]:
56
58
  """
57
59
  :param key: key object
58
60
  :type key: instance of
59
- :returns: type of key: RSA, EC, DSA
60
- :rtype: str
61
+ :returns: If the key is valid, it will return a Tuple wherein
62
+ - The first element is the Key's technology (EC, RSA)
63
+ - The second element is a Tuple with the key's type.
64
+ (RSA, (bits, ))
65
+ (EC, (curve_name, ))
61
66
  """
62
67
  if TYPE_CHECKING:
63
68
  assert conditionals.crypto_rsa is not None
64
69
  assert conditionals.crypto_ec is not None
65
70
  if isinstance(publickey, conditionals.crypto_rsa.RSAPublicKey):
66
- return "RSA"
71
+ return ("RSA", (publickey.key_size,))
67
72
  elif isinstance(publickey, conditionals.crypto_ec.EllipticCurvePublicKey):
68
- return "EC"
73
+ curve_name = curve_to_nist(publickey.curve.name)
74
+ return ("EC", (curve_name,))
69
75
  return None
70
76
 
71
77
 
@@ -1,5 +1,6 @@
1
1
  # stdlib
2
2
  import binascii
3
+ import re
3
4
  import subprocess
4
5
  from typing import List
5
6
  from typing import Optional
@@ -18,10 +19,59 @@ from ..errors import OpenSslError_InvalidCSR
18
19
  from ..errors import OpenSslError_InvalidKey
19
20
  from ..errors import OpenSslError_VersionTooLow
20
21
  from ..utils import new_pem_tempfile
22
+ from ..utils import TECHNOLOGY_RETURN_VALUES
21
23
 
22
24
  # ==============================================================================
23
25
 
24
26
 
27
+ # note the conditional whitespace before/after `CN`
28
+ # this is because of differing openssl versions
29
+ RE_openssl_x509_subject = re.compile(r"Subject:.*? CN ?= ?([^\s,;/]+)")
30
+ RE_openssl_x509_san = re.compile(
31
+ r"X509v3 Subject Alternative Name: ?\n +([^\n]+)\n?", re.MULTILINE | re.DOTALL
32
+ )
33
+
34
+
35
+ # openssl 3 does not have "keyid:" as a prefix
36
+ # a keyid prefix is okay!
37
+ # we do not want the alternates, which are uri+serial; but take that out in results
38
+ RE_openssl_x509_authority_key_identifier = re.compile(
39
+ r"X509v3 Authority Key Identifier: ?\n +(?:keyid:)?([^\n]+)\n?",
40
+ re.MULTILINE | re.DOTALL,
41
+ )
42
+ # we have a potential line in there for the OSCP or something else.
43
+ RE_openssl_x509_issuer_uri = re.compile(
44
+ r"Authority Information Access: ?\n(?:[^\n]*^\n)? +CA Issuers - URI:([^\n]+)\n?",
45
+ re.MULTILINE | re.DOTALL,
46
+ )
47
+
48
+ RE_openssl_x509_serial = re.compile(r"Serial Number: ?(\d+)")
49
+
50
+
51
+ # depending on openssl version, the "Public key: " text might list the bits
52
+ # it may or may not also have a dash in the phrase "Public Key"
53
+ # it may or may not be prefaced with the PublicKey type
54
+ RE_openssl_x509_keytype_rsa = re.compile(
55
+ r"Subject Public Key Info:\n"
56
+ r"\s+Public Key Algorithm: rsaEncryption\n"
57
+ r"\s+(?:RSA )?Public[\-\ ]?Key: \((\d+) bits?\)",
58
+ re.MULTILINE,
59
+ )
60
+ RE_openssl_x509_keytype_ec = re.compile(
61
+ r"Subject Public Key Info:\n"
62
+ r"\s+Public Key Algorithm: id-ecPublicKey\n"
63
+ r"\s+(?:EC )?Public[\-\ ]?Key: \((\d+) bits?\)\n"
64
+ r"\s+pub:\n"
65
+ r"[\s\d\w\:]+"
66
+ r"(?:"
67
+ r"(?:\s+ASN1 OID: ([\w]+)\n)"
68
+ r"|"
69
+ r"(?:\s+NIST CURVE: ([\-\w]+)\n)"
70
+ r")",
71
+ re.MULTILINE,
72
+ )
73
+
74
+
25
75
  def _cleanup_openssl_modulus(data: str) -> str:
26
76
  data = data.strip()
27
77
  if data[:8] == "Modulus=":
@@ -144,13 +194,13 @@ def _openssl_cert__normalize_pem(cert_pem: str) -> str:
144
194
 
145
195
 
146
196
  def _openssl_spki_hash_cert(
147
- key_technology: str = "",
197
+ key_technology_basic: str = "",
148
198
  cert_pem_filepath: str = "",
149
199
  as_b64: Optional[bool] = None,
150
200
  ) -> str:
151
201
  """
152
- :param key_technology: Is the key an "EC" or "RSA" key?
153
- :type key_technology: str
202
+ :param key_technology_basic: Is the key an "EC" or "RSA" key?
203
+ :type key_technology_basic: str
154
204
  :param cert_pem_filepath: REQUIRED filepath to PEM Certificate.
155
205
  Used for commandline OpenSSL fallback operations.
156
206
  :type cert_pem_filepath: str
@@ -162,13 +212,13 @@ def _openssl_spki_hash_cert(
162
212
  The OpenSSL Equivalent / Fallback is::
163
213
 
164
214
  openssl x509 -pubkey -noout -in {CERT_FILEPATH} | \
165
- openssl {key_technology} -pubout -outform DER -pubin | \
215
+ openssl {key_technology_basic} -pubout -outform DER -pubin | \
166
216
  openssl dgst -sha256 -binary | \
167
217
  openssl enc -base64
168
218
  """
169
- if key_technology not in ("EC", "RSA"):
170
- raise ValueError("must submit `key_technology`")
171
- key_technology = key_technology.lower()
219
+ if key_technology_basic not in ("EC", "RSA"):
220
+ raise ValueError("must submit `key_technology_basic`")
221
+ key_technology_basic = key_technology_basic.lower()
172
222
  if not cert_pem_filepath:
173
223
  raise FallbackError_FilepathRequired("Must submit `cert_pem_filepath`.")
174
224
  if core.openssl_version is None:
@@ -195,7 +245,7 @@ def _openssl_spki_hash_cert(
195
245
  p2 = psutil.Popen(
196
246
  [
197
247
  core.openssl_path,
198
- key_technology,
248
+ key_technology_basic,
199
249
  "-pubin",
200
250
  "-pubout",
201
251
  "-outform",
@@ -261,13 +311,13 @@ def _openssl_spki_hash_cert(
261
311
 
262
312
 
263
313
  def _openssl_spki_hash_csr(
264
- key_technology: str = "",
314
+ key_technology_basic: str = "",
265
315
  csr_pem_filepath: str = "",
266
316
  as_b64: Optional[bool] = None,
267
317
  ) -> str:
268
318
  """
269
- :param key_technology: Is the key an "EC" or "RSA" key?
270
- :type key_technology: str
319
+ :param key_technology_basic: Is the key an "EC" or "RSA" key?
320
+ :type key_technology_basic: str
271
321
  :param csr_pem_filepath: REQUIRED filepath to PEM CSR.
272
322
  Used for commandline OpenSSL fallback operations.
273
323
  :type csr_pem_filepath: str
@@ -279,13 +329,13 @@ def _openssl_spki_hash_csr(
279
329
  The OpenSSL Equivalent / Fallback is::
280
330
 
281
331
  openssl REQ -pubkey -noout -in {CSR_FILEPATH} | \
282
- openssl {key_technology} -pubout -outform DER -pubin | \
332
+ openssl {key_technology_basic} -pubout -outform DER -pubin | \
283
333
  openssl dgst -sha256 -binary | \
284
334
  openssl enc -base64
285
335
  """
286
- if key_technology not in ("EC", "RSA"):
287
- raise ValueError("must submit `key_technology`")
288
- key_technology = key_technology.lower()
336
+ if key_technology_basic not in ("EC", "RSA"):
337
+ raise ValueError("must submit `key_technology_basic`")
338
+ key_technology_basic = key_technology_basic.lower()
289
339
  if not csr_pem_filepath:
290
340
  raise FallbackError_FilepathRequired("Must submit `csr_pem_filepath`.")
291
341
  if core.openssl_version is None:
@@ -312,7 +362,7 @@ def _openssl_spki_hash_csr(
312
362
  p2 = psutil.Popen(
313
363
  [
314
364
  core.openssl_path,
315
- key_technology,
365
+ key_technology_basic,
316
366
  "-pubin",
317
367
  "-pubout",
318
368
  "-outform",
@@ -377,13 +427,13 @@ def _openssl_spki_hash_csr(
377
427
 
378
428
 
379
429
  def _openssl_spki_hash_pkey(
380
- key_technology: str = "",
430
+ key_technology_basic: str = "",
381
431
  key_pem_filepath: str = "",
382
432
  as_b64: Optional[bool] = None,
383
433
  ) -> str:
384
434
  """
385
- :param key_technology: Is the key an "EC" or "RSA" key?
386
- :type key_technology: str
435
+ :param key_technology_basic: Is the key an "EC" or "RSA" key?
436
+ :type key_technology_basic: str
387
437
  :param key_pem_filepath: REQUIRED filepath to PEM encoded PrivateKey.
388
438
  Used for commandline OpenSSL fallback operations.
389
439
  :type key_pem_filepath: str
@@ -398,9 +448,9 @@ def _openssl_spki_hash_pkey(
398
448
  openssl dgst -sha256 -binary | \
399
449
  openssl enc -base64
400
450
  """
401
- if key_technology not in ("EC", "RSA"):
402
- raise ValueError("must submit `key_technology`")
403
- key_technology = key_technology.lower()
451
+ if key_technology_basic not in ("EC", "RSA"):
452
+ raise ValueError("must submit `key_technology_basic`")
453
+ key_technology_basic = key_technology_basic.lower()
404
454
  if not key_pem_filepath:
405
455
  raise FallbackError_FilepathRequired("Must submit `key_pem_filepath`.")
406
456
  if core.openssl_version is None:
@@ -414,7 +464,7 @@ def _openssl_spki_hash_pkey(
414
464
  p1 = psutil.Popen(
415
465
  [
416
466
  core.openssl_path,
417
- key_technology,
467
+ key_technology_basic,
418
468
  "-pubout",
419
469
  "-outform",
420
470
  "DER",
@@ -699,3 +749,109 @@ def key_single_op__pem_filepath(
699
749
  data_str = data_bytes.decode("utf8")
700
750
  data_str = data_str.strip()
701
751
  return data_str
752
+
753
+
754
+ def san_domains_from_text(text: str) -> List[str]:
755
+ """
756
+ Helper function to extract SAN domains from a chunk of text in a x509 object
757
+
758
+ :param text: string extracted from a x509 document
759
+ :type text: str
760
+ :returns: list of domains
761
+ :rtype: list
762
+ """
763
+ san_domains = set([])
764
+ _subject_alt_names = RE_openssl_x509_san.search(text)
765
+ if _subject_alt_names is not None:
766
+ for _san in _subject_alt_names.group(1).split(", "):
767
+ if _san.startswith("DNS:"):
768
+ san_domains.add(_san[4:].lower())
769
+ return sorted(list(san_domains))
770
+
771
+
772
+ def authority_key_identifier_from_text(text: str) -> Optional[str]:
773
+ """
774
+ :param text: string extracted from a x509 document
775
+ :type text: str
776
+ :returns: authority_key_identifier
777
+ :rtype: str
778
+
779
+ openssl will print a uppercase hex pairs, separated by a colon
780
+ we should remove the colons
781
+ """
782
+ results = RE_openssl_x509_authority_key_identifier.findall(text)
783
+ if results:
784
+ authority_key_identifier = results[0]
785
+ # ensure we have a key_id and not "URI:" or other convention
786
+ if authority_key_identifier[2] == ":":
787
+ return authority_key_identifier.replace(":", "")
788
+ return None
789
+
790
+
791
+ def serial_from_text(text: str) -> Optional[int]:
792
+ """
793
+ :param text: string extracted from a x509 document
794
+ :type text: str
795
+ :returns: serial
796
+ :rtype: int
797
+ """
798
+ results = RE_openssl_x509_serial.findall(text)
799
+ if results:
800
+ serial = results[0]
801
+ return int(serial)
802
+ return None
803
+
804
+
805
+ def issuer_uri_from_text(text: str) -> Optional[str]:
806
+ """
807
+ :param text: string extracted from a x509 document
808
+ :type text: str
809
+ :returns: issuer_uri
810
+ :rtype: str
811
+ """
812
+ results = RE_openssl_x509_issuer_uri.findall(text)
813
+ if results:
814
+ return results[0]
815
+ return None
816
+
817
+
818
+ def _x509_pubkey_technology__text(cert_text: str) -> Optional[TECHNOLOGY_RETURN_VALUES]:
819
+ m = RE_openssl_x509_keytype_rsa.search(cert_text)
820
+ if m:
821
+ v = m.groups()
822
+ return ("RSA", (int(v[0]),))
823
+ m = RE_openssl_x509_keytype_ec.search(cert_text)
824
+ if m:
825
+ v = m.groups()
826
+ c = None
827
+ if v[2]:
828
+ c = v[2]
829
+ elif v[0]:
830
+ c = "P-%s" % v[0]
831
+ else:
832
+ # TODO? better parsing
833
+ return None
834
+ return ("EC", (c,))
835
+ return None
836
+
837
+
838
+ def _cert_pubkey_technology__text(cert_text: str) -> Optional[TECHNOLOGY_RETURN_VALUES]:
839
+ """
840
+ :param cert_text: string extracted from a x509 document
841
+ :type cert_text: str
842
+ :returns: Pubkey type: "RSA" or "EC"
843
+ :rtype: strfRE_openssl_x509_keytype_rsa
844
+ """
845
+ # `cert_text` is the output of of `openssl x509 -noout -text -in MYCERT `
846
+ return _x509_pubkey_technology__text(cert_text)
847
+
848
+
849
+ def _csr_pubkey_technology__text(csr_text: str) -> Optional[TECHNOLOGY_RETURN_VALUES]:
850
+ """
851
+ :param csr_text: string extracted from a CSR document
852
+ :type csr_text: str
853
+ :returns: Pubkey type: "RSA" or "EC"
854
+ :rtype: str
855
+ """
856
+ # `csr_text` is the output of of `openssl req -noout -text -in MYCERT`
857
+ return _x509_pubkey_technology__text(csr_text)
@@ -8,6 +8,7 @@ more esoteric and not well documented elsewhere.
8
8
 
9
9
  Please use the other interfaces.
10
10
  """
11
+
11
12
  import logging
12
13
  from types import ModuleType
13
14
  from typing import List
@@ -1,5 +1,6 @@
1
1
  # stdlib
2
2
  from types import ModuleType
3
+ from typing import Any
3
4
  from typing import Optional
4
5
 
5
6
  # ------------------------------------------------------------------------------
@@ -31,18 +32,22 @@ GOOD:
31
32
 
32
33
  """
33
34
  cryptography: Optional[ModuleType]
35
+ crypto_x509: Optional[ModuleType]
36
+ crypto_hashes: Optional[ModuleType]
37
+ crypto_padding: Optional[ModuleType]
38
+ crypto_serialization: Optional[ModuleType]
34
39
  crypto_dsa: Optional[ModuleType]
35
40
  crypto_ec: Optional[ModuleType]
36
41
  crypto_ed25519: Optional[ModuleType]
37
42
  crypto_ed448: Optional[ModuleType]
38
- crypto_hashes: Optional[ModuleType]
39
- crypto_padding: Optional[ModuleType]
40
- crypto_pkcs7: Optional[ModuleType]
41
43
  crypto_rsa: Optional[ModuleType]
42
- crypto_serialization: Optional[ModuleType]
43
- crypto_x509: Optional[ModuleType]
44
+ crypto_utils: Optional[ModuleType]
45
+ EllipticCurvePublicKey: Optional[Any]
46
+ RSAPublicKey: Optional[Any]
47
+ crypto_pkcs7: Optional[ModuleType]
44
48
  josepy: Optional[ModuleType]
45
49
 
50
+ # first cryptography
46
51
  try:
47
52
  import cryptography
48
53
  import cryptography.x509 as crypto_x509
@@ -54,20 +59,27 @@ try:
54
59
  from cryptography.hazmat.primitives.asymmetric import ed25519 as crypto_ed25519
55
60
  from cryptography.hazmat.primitives.asymmetric import ed448 as crypto_ed448
56
61
  from cryptography.hazmat.primitives.asymmetric import rsa as crypto_rsa
62
+ from cryptography.hazmat.primitives.asymmetric import utils as crypto_utils
63
+ from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePublicKey
64
+ from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey
57
65
  from cryptography.hazmat.primitives.serialization import pkcs7 as crypto_pkcs7
58
66
  except ImportError:
59
67
  cryptography = None
60
68
  crypto_x509 = None
69
+ crypto_hashes = None
70
+ crypto_padding = None
71
+ crypto_serialization = None
61
72
  crypto_dsa = None
62
73
  crypto_ec = None
63
74
  crypto_ed25519 = None
64
75
  crypto_ed448 = None
65
- crypto_hashes = None
66
- crypto_padding = None
67
- crypto_pkcs7 = None
68
76
  crypto_rsa = None
69
- crypto_serialization = None
77
+ crypto_utils = None
78
+ EllipticCurvePublicKey = None
79
+ RSAPublicKey = None
80
+ crypto_pkcs7 = None
70
81
 
82
+ # then josepy
71
83
  try:
72
84
  import josepy
73
85
  except ImportError: