Created
July 2, 2017 09:31
-
-
Save magnuswatn/6ce0017c1f8ef18ed04115583b4f79f8 to your computer and use it in GitHub Desktop.
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
""" | |
A script to re-sign a certificate signing request | |
Can be useful if it has been tampered with, | |
e.g. by using the excellent DER ASCII tool | |
(https://github.com/google/der-ascii) | |
Magnus Watn <[email protected]> | |
""" | |
import base64 | |
import binascii | |
import argparse | |
from pyasn1_modules import rfc2314 | |
from pyasn1.codec.der import encoder, decoder | |
from cryptography import x509 | |
from cryptography.hazmat.backends import default_backend | |
from cryptography.hazmat.primitives import hashes | |
from cryptography.hazmat.primitives import serialization | |
from cryptography.hazmat.primitives.asymmetric import ec | |
from cryptography.hazmat.primitives.asymmetric import rsa | |
from cryptography.hazmat.primitives.asymmetric import padding | |
class UnsupportedKeyTypeError(Exception): | |
"""Signifies that the key was of an unsupported type""" | |
pass | |
def _update_signature(csr, private_key): | |
"""Updates the signature on the csr""" | |
raw_signature, signature_algorithm = _sign(private_key, csr.tbs_certrequest_bytes) | |
signature = rfc2314.univ.BitString(hexValue=binascii.hexlify(raw_signature).decode('ascii')) | |
certification_request_info, _ = decoder.decode(csr.tbs_certrequest_bytes, | |
asn1Spec=rfc2314.CertificationRequestInfo()) | |
certification_request = rfc2314.CertificationRequest() | |
certification_request.setComponentByName('certificationRequestInfo', certification_request_info) | |
certification_request.setComponentByName('signatureAlgorithm', signature_algorithm) | |
certification_request.setComponentByName('signature', signature) | |
return encoder.encode(certification_request) | |
def _pem_encode_csr(csr): | |
"""Encodes the CSR in PEM format""" | |
b64_csr = base64.b64encode(csr).decode('ascii') | |
b64rn_csr = '\r\n'.join(b64_csr[pos:pos+64] for pos in range(0, len(b64_csr), 64)) | |
pem_csr = '-----BEGIN NEW CERTIFICATE REQUEST-----\r\n' | |
pem_csr += b64rn_csr | |
pem_csr += '\r\n-----END NEW CERTIFICATE REQUEST-----' | |
return pem_csr | |
def _sign(key, payload): | |
"""Signs the payload with the specified key""" | |
signature_algorithm = rfc2314.AlgorithmIdentifier() | |
if isinstance(key, rsa.RSAPrivateKey): | |
# sha256WithRSAEncryption. MUST have ASN.1 NULL in the parameters field | |
signature_algorithm.setComponentByName('algorithm', (1, 2, 840, 113549, 1, 1, 11)) | |
signature_algorithm.setComponentByName('parameters', '\x05\x00') | |
signature = key.sign( | |
payload, | |
padding.PKCS1v15(), | |
hashes.SHA256() | |
) | |
elif isinstance(key, ec.EllipticCurvePrivateKey): | |
# ecdsaWithSHA256. MUST omit the parameters field | |
signature_algorithm.setComponentByName('algorithm', (1, 2, 840, 10045, 4, 3, 2)) | |
signature = key.sign( | |
payload, | |
ec.ECDSA(hashes.SHA256()) | |
) | |
else: | |
raise UnsupportedKeyTypeError | |
return signature, signature_algorithm | |
def main(): | |
parser = argparse.ArgumentParser( | |
description='Re-signs a CSR to make the signature valid again after tampering. '\ | |
'Prints the finished CSR to standard out') | |
parser.add_argument('csr', help="The CSR to be re-signed") | |
parser.add_argument('key', help="The private key beloging to the CSR (in PEM format)") | |
args = parser.parse_args() | |
with open(args.key, 'rb') as open_file: | |
key = serialization.load_pem_private_key( | |
open_file.read(), | |
password=None, | |
backend=default_backend() | |
) | |
with open(args.csr, 'rb') as open_file: | |
csr_bytes = open_file.read() | |
try: | |
original_csr = x509.load_pem_x509_csr(csr_bytes, default_backend()) | |
except ValueError: | |
original_csr = x509.load_der_x509_csr(csr_bytes, default_backend()) | |
new_csr = _update_signature(original_csr, key) | |
print(_pem_encode_csr(new_csr)) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment