Skip to content

Instantly share code, notes, and snippets.

@vectorsigma
Last active December 27, 2023 23:22
Show Gist options
  • Select an option

  • Save vectorsigma/f0aa64e9794198a2fd5a8d0aa7f29353 to your computer and use it in GitHub Desktop.

Select an option

Save vectorsigma/f0aa64e9794198a2fd5a8d0aa7f29353 to your computer and use it in GitHub Desktop.
convert a PEM formatted private key to a JWKS formatted private key
#!/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