Last active
April 10, 2020 17:11
-
-
Save gimiki/377a58fa0400d21986163505daf293b5 to your computer and use it in GitHub Desktop.
Example - Get a public key given the modulus and public exponent from an Identity Provider metadata service
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
import sys | |
import base64 | |
from typing import Tuple, Dict, List | |
import json | |
import urllib.error | |
from urllib.request import urlopen | |
import ssl | |
import logging | |
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') | |
# pip install cryptodome | |
from Crypto.PublicKey import RSA | |
# Funzione che decodifica una stringa codificata in base64url | |
def base64urlDecode(encStr): | |
# Effettua il padding della stringa affinche' possa essere divisa in bytes e decodifcata | |
padding_factor = (4 - len(encStr) % 4) % 4 | |
encStr += "=" * padding_factor | |
return base64.urlsafe_b64decode(encStr) | |
# Funzione per estrarre il modulo e l'esponente. La codifica e' Base64Url. | |
# I byte ottenuto vanno convertiti con notazione intero big endian senza segno | |
def keyComponentsExtractor(vDict: Dict, keyType='*') -> List: | |
retList = [] | |
if 'keys' in vDict.keys(): | |
logging.debug("Chiave keys trovata!") | |
for k in vDict['keys']: | |
logging.debug("Chiave: " + str(k)) | |
if keyType == '*' or 'use' in k and k['use'] == keyType: | |
nInt = int.from_bytes(base64urlDecode(k['n']), byteorder='big', signed=False) | |
eInt = int.from_bytes(base64urlDecode(k['e']), byteorder='big', signed=False) | |
logging.debug("Modulo: " + str(nInt) + " Esponente: " + str(eInt)) | |
retList.append((nInt, eInt)) | |
return retList | |
# Creo il contesto ignorando eventuali certificati self-signed | |
sslContex = ssl.create_default_context() | |
sslContex.check_hostname = False | |
sslContex.verify_mode = ssl.CERT_NONE | |
# Chiamo il servizio ed estraggo il json | |
try: | |
response = urlopen("https://www.googleapis.com/oauth2/v3/certs", context=sslContex) | |
jsonResponse = json.load(response) | |
logging.debug("Risposta JSON: " + str(jsonResponse)) | |
except urllib.error.URLError as e: | |
logging.error("" + str(e.reason)) | |
sys.exit() | |
# Estraggo le componenti modulo e esponente dalle chiavi contenuti nella risposta JSON | |
# Se non viene specificato il tipo di chiave vengono restituite tutte le chiavi | |
# sig = signature key, enc = encryption key -> ref Oauth spec | |
componentsList = keyComponentsExtractor(jsonResponse, "sig") | |
if not componentsList: | |
logging.error("Lista delle componenti vuota!") | |
sys.exit() | |
logging.debug("Lista componenti chiavi estratti: " + str(componentsList)) | |
# Creo i certificati pubblici e scrivo la chiave pubblica in un file | |
keyfile = open("publicKey.txt", "w") | |
for (n,e) in componentsList: | |
pKey = RSA.construct((n, e)) | |
print(pKey.export_key().decode(), file=keyfile) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment