#!/usr/bin/env python3 import cryptography.hazmat.backends import cryptography.hazmat.primitives.serialization import cryptography.x509 import math def convert_to_sexp(data): if isinstance(data, int): return convert_to_sexp(data.to_bytes( math.ceil(data.bit_length() / 8), 'big', )) elif isinstance(data, str): return convert_to_sexp(data.encode()) elif isinstance(data, bytes): return str(len(data)).encode() + b':' + data else: return b'(' + b''.join(convert_to_sexp(i) for i in data) + b')' def create_gpg_key(): backend = cryptography.hazmat.backends.default_backend() with open('smartcard-app-id.hex', 'r') as f: appid = int(f.read(), 16) with open('cert-request.pem', 'rb') as f: req = cryptography.x509.load_pem_x509_csr(f.read(), backend) assert req.is_signature_valid pubnums = req.public_key().public_numbers() key_data = ['shadowed-private-key', [ 'rsa', ['n', pubnums.n], ['e', pubnums.e], ['shadowed', 't1-v1', [appid, 'OPENPGP.1']], ]] key = convert_to_sexp(key_data) with open('gpg-key.sexp', 'wb') as f: f.write(key) def _init_argparser(): import argparse argparser = argparse.ArgumentParser( description='create a shadowed-private-key in sexp format for gnupg\'s private-keys-v1.d folder' + ' containing the public key of a PEM-encoded X.509 certificate signing request (CSR)', ) return argparser def main(argv): argparser = _init_argparser() args = argparser.parse_args(argv[1:]) create_gpg_key(**vars(args)) return 0 if __name__ == '__main__': import sys sys.exit(main(sys.argv))