Last active
June 12, 2020 20:11
-
-
Save ryanchapman/69adee6379d215099af90b023005e311 to your computer and use it in GitHub Desktop.
Print certificate signatures that can be used with certificate pinning on iOS and Android
This file contains 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 python | |
# | |
# Print certificate signatures that can be used with certificate pinning on iOS and Android | |
# | |
# usage: cat cert_bundle.pem | ./print_cert_signatures.py | |
# usage: openssl s_client -connect fqdn:443 -showcerts </dev/null 2>/dev/null | ~/bin/print_cert_signatures.py | |
# | |
# example: | |
# $ openssl s_client -connect www.google.com:443 -showcerts </dev/null 2>/dev/null | ~/bin/print_cert_signatures.py | |
# Certificate 1 of 2: | |
# Key Type: RSA-2048 | |
# Subject: C=US, ST=California, L=Mountain View, O=Google LLC, CN=www.google.com | |
# Issuer: C=US, O=Google Trust Services, CN=GTS CA 1O1 | |
# Pubkey Signature: mcc0YcAK2ejMs6RabSa5fpKGi2zQFUyVcisQEktcjqs= | |
# Certificate 2 of 2: | |
# Key Type: RSA-2048 | |
# Subject: C=US, O=Google Trust Services, CN=GTS CA 1O1 | |
# Issuer: OU=GlobalSign Root CA - R2, O=GlobalSign, CN=GlobalSign | |
# Pubkey Signature: YZPgTZ+woNCCCIW3LH2CxQeLzB/1m42QcCTBSdgayjs= | |
import base64 | |
import datetime | |
import hashlib | |
import sys | |
from OpenSSL.crypto import load_certificate, dump_certificate, dump_publickey, TYPE_DSA, TYPE_EC, TYPE_RSA, FILETYPE_PEM, FILETYPE_ASN1 | |
def pem_header_string(): | |
return '-----BEGIN CERTIFICATE-----' | |
def pem_footer_string(): | |
return '-----END CERTIFICATE-----' | |
def seek_to_cert_beginning(): | |
found = False | |
for line in sys.stdin: | |
if pem_header_string() in line: | |
found = True | |
break | |
else: | |
continue | |
return found | |
def read_pem_certs_from_stdin(): | |
certs = [] | |
while seek_to_cert_beginning() != False: | |
# can't rewind stdin, so manually copy the header, and later, the footer | |
cert = pem_header_string() + '\n' | |
for line in sys.stdin: | |
if pem_footer_string() in line: | |
break | |
else: | |
cert += line | |
cert += pem_footer_string() | |
certs.append(cert) | |
return certs | |
def get_keytype(x509cert): | |
kt = x509cert.get_pubkey().type() | |
keytypes = { | |
TYPE_RSA: 'RSA', | |
TYPE_DSA: 'DSA', | |
TYPE_EC: 'EC' | |
} | |
return keytypes.get(kt, 'Unknown keytype {}'.format(kt)) | |
def component_list_to_string(components): | |
str = '' | |
continued = False | |
for c in components: | |
if continued: | |
str += ', ' | |
str += '{}={}'.format(c[0], c[1]) | |
continued = True | |
return str | |
def get_issuer(x509cert): | |
issuer = component_list_to_string(x509cert.get_issuer().get_components()) | |
return issuer | |
def get_issuer_expiration(x509cert): | |
not_after = x509cert.get_notAfter() | |
return not_after | |
def get_subject(x509cert): | |
subject = component_list_to_string(x509cert.get_subject().get_components()) | |
return subject | |
def get_subject_expiration(x509cert): | |
not_after = x509cert.get_notAfter() | |
return not_after | |
def get_pubkey_signature_base64(x509cert): | |
pubkey = x509cert.get_pubkey() | |
pubkey_der = dump_publickey(FILETYPE_ASN1, pubkey) | |
return base64.b64encode(hashlib.sha256(pubkey_der).digest()) | |
def get_cert_signature_base64(x509cert): | |
cert_der = dump_certificate(FILETYPE_ASN1, x509cert) | |
return base64.b64encode(hashlib.sha256(cert_der).digest()) | |
def print_certs(): | |
certs = read_pem_certs_from_stdin() | |
num_certs = len(certs) | |
i = 1 | |
for certpem in certs: | |
x509cert = load_certificate(FILETYPE_PEM, certpem) | |
keytype = get_keytype(x509cert) | |
issuer = get_issuer(x509cert) | |
issuer_expiration = datetime.datetime.strptime(get_issuer_expiration(x509cert).decode('ascii'), r'%Y%m%d%H%M%SZ') | |
subject = get_subject(x509cert) | |
subject_expiration = datetime.datetime.strptime(get_subject_expiration(x509cert).decode('ascii'), r'%Y%m%d%H%M%SZ') | |
cert_sig_b64 = get_cert_signature_base64(x509cert) | |
pubkey_sig_b64 = get_pubkey_signature_base64(x509cert) | |
print 'Certificate {} of {}:'.format(i, num_certs) | |
print ' Key Type: {}-{}'.format(keytype, x509cert.get_pubkey().bits()) | |
print ' Subject: {}'.format(subject) | |
print ' Subject Expiration: {}'.format(subject_expiration) | |
print ' Issuer: {}'.format(issuer) | |
print ' Issuer Expiration: {}'.format(issuer_expiration) | |
print ' Cert Signature: {}'.format(cert_sig_b64) | |
print ' Pubkey Signature: {}'.format(pubkey_sig_b64) | |
i += 1 | |
def main(): | |
print_certs() | |
if __name__=='__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment