create-gpg-shadow-key-from-x509-cert-req.py 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. #!/usr/bin/env python3
  2. import cryptography.hazmat.backends
  3. import cryptography.hazmat.primitives.serialization
  4. import cryptography.x509
  5. import math
  6. DEFAULT_SMARTCARD_APP_ID_HEX = 'D2760001240102010001234567890000'
  7. def convert_to_sexp(data):
  8. if isinstance(data, int):
  9. return convert_to_sexp(data.to_bytes(
  10. math.ceil(data.bit_length() / 8),
  11. 'big',
  12. ))
  13. elif isinstance(data, str):
  14. return convert_to_sexp(data.encode())
  15. elif isinstance(data, bytes):
  16. return str(len(data)).encode() + b':' + data
  17. else:
  18. return b'(' + b''.join(convert_to_sexp(i) for i in data) + b')'
  19. def create_gpg_key(smartcard_app_id_hex):
  20. backend = cryptography.hazmat.backends.default_backend()
  21. with open('cert-request.pem', 'rb') as f:
  22. req = cryptography.x509.load_pem_x509_csr(f.read(), backend)
  23. assert req.is_signature_valid
  24. pubnums = req.public_key().public_numbers()
  25. key_data = ['shadowed-private-key', [
  26. 'rsa',
  27. ['n', pubnums.n],
  28. ['e', pubnums.e],
  29. ['shadowed', 't1-v1', [int(smartcard_app_id_hex, 16), 'OPENPGP.1']],
  30. ]]
  31. key = convert_to_sexp(key_data)
  32. with open('gpg-key.sexp', 'wb') as f:
  33. f.write(key)
  34. def _init_argparser():
  35. import argparse
  36. argparser = argparse.ArgumentParser(
  37. description='create a shadowed-private-key in sexp format for gnupg\'s private-keys-v1.d folder'
  38. + ' containing the public key of a PEM-encoded X.509 certificate signing request (CSR)',
  39. )
  40. argparser.add_argument(
  41. '--smartcard-app-id',
  42. dest='smartcard_app_id_hex',
  43. metavar='hex-string',
  44. default=DEFAULT_SMARTCARD_APP_ID_HEX,
  45. help='default: %(default)s',
  46. )
  47. return argparser
  48. def main(argv):
  49. argparser = _init_argparser()
  50. args = argparser.parse_args(argv[1:])
  51. create_gpg_key(**vars(args))
  52. return 0
  53. if __name__ == '__main__':
  54. import sys
  55. sys.exit(main(sys.argv))