Last active
December 27, 2023 23:22
-
-
Save vectorsigma/f0aa64e9794198a2fd5a8d0aa7f29353 to your computer and use it in GitHub Desktop.
convert a PEM formatted private key to a JWKS formatted private key
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env python3 | |
| # | |
| # import a PEM formatted private key made by some legacy build of certbot a few months earlier in 2023 | |
| # and output a JWKS version of the same key since that format changed on disk and I didn't know it. | |
| # Also, I used chat-gpt-4 to help me write this, because finding out which crypto libraries | |
| # were the right ones to use was a nightmare. It worked, well, and fast, and that should scare the | |
| # shit out of anyone trying to get into the world of programming at this moment in time. | |
| from cryptography.hazmat.primitives import serialization # Deal with X509/PEM formatted ecdsa keys | |
| from jwcrypto import jwk # work with JWK's, `sudo dnf -y install python3-jwcrypto` | |
| import json # format JSON for writing | |
| import sys | |
| from os import path | |
| import argparse | |
| import getpass | |
| # Make sure command line arguments are correct. First two params are mandatory (File paths) | |
| # last param is optional (private key password) | |
| parser = argparse.ArgumentParser(prog='pem-to-jwks.py', description='Convert a PEM Formatted key to a JWKS formatted key.') | |
| parser.add_argument('-p', '--pem', metavar='FILEPATH', action='store', dest='pem_infile') | |
| parser.add_argument('-j', '--json', metavar='FILEPATH', action='store', dest='jwks_outfile') | |
| parser.add_argument('-w', '--password', action='store_true', dest='pem_pp', default=False) | |
| args = parser.parse_args() | |
| pem_infile = path.expanduser(args.pem_infile) | |
| jwks_outfile = path.expanduser(args.jwks_outfile) | |
| if args.pem_pp is True: | |
| pw = getpass.getpass('Passphrase for private key file, {}: '.format(pem_infile)) | |
| else: | |
| pw = None | |
| # Chat-GPT-4 assisted code here (the code contained no error handling, so all that was me, what a waste.) | |
| with open(pem_infile, mode='rb') as pem_key: | |
| try: | |
| private_key = serialization.load_pem_private_key(pem_key.read(), password=pw) # I wouldn't have figured this part out for a while. | |
| except FileNotFoundError: | |
| print ('Unable to locate PEM private key file: {}'.format(pem_infile)) | |
| sys.exit(3) | |
| except PermissionError: | |
| print ('Unable to open PEM private key file: {}'.format(pem_infile)) | |
| sys.exit(4) | |
| # probably could've gotten this from the module docs, but knowing _which_ module would've been difficult, | |
| # since my only code experience with JWK was the josepy module, which, uh, I didn't really understand. | |
| jwk_key = jwk.JWK.from_pem(private_key.private_bytes(encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.PKCS8, encryption_algorithm=serialization.NoEncryption())) | |
| with open(jwks_outfile, mode='wb') as jwkwrite: | |
| try: | |
| jwkwrite.write(json.dumps({"keys": [json.loads(jwk_key.export())]}).encode('utf-8')) | |
| except PermissionError: | |
| print ('Unable to create JWK private key file: {}, check directory permissions or your own EUID.'.format(pem_infile)) | |
| sys.exit(5) | |
| print('Finished writing JWK key to: {}'.format(jwks_outfile)) | |
| sys.exit(0) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment