Example #1
0
 def __init__(self, json):
     super().__init__(json)
     decoded_n = bytes_to_int(urlsafe_b64decode(self.n))
     decoded_e = bytes_to_int(urlsafe_b64decode(self.e))
     rsa_public_key = RSAPublicNumbers(decoded_e, decoded_n).public_key(
         default_backend())
     self.public_key = rsa_public_key.public_bytes(
         Encoding.PEM, PublicFormat.SubjectPublicKeyInfo).decode()
Example #2
0
 def __init__(self, json):
     self._json = json
     self.expires = datetime.now() + timedelta(minutes=JWK_EXPIRES_MIN)
     decoded_n = bytes_to_int(urlsafe_b64decode(self.n))
     decoded_e = bytes_to_int(urlsafe_b64decode(self.e))
     rsa_public_key = RSAPublicNumbers(decoded_e, decoded_n).public_key(
         default_backend())
     self.public_key = rsa_public_key.public_bytes(
         Encoding.PEM, PublicFormat.SubjectPublicKeyInfo).decode()
Example #3
0
def get_rsa_public_key(n, e):
    """
    Retrieve an RSA public key based on a module and exponent as provided by the JWKS format.
    :param n:
    :param e:
    :return: a RSA Public Key in PEM format
    """
    n = int(binascii.hexlify(jwt.utils.base64url_decode(bytes(n))), 16)
    e = int(binascii.hexlify(jwt.utils.base64url_decode(bytes(e))), 16)
    pub = RSAPublicNumbers(e, n).public_key(default_backend())
    return pub.public_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PublicFormat.SubjectPublicKeyInfo)
Example #4
0
def get_rsa_public_key(n, e):
    """
    Retrieve an RSA public key based on a module and exponent as provided by the JWKS format.
    :param n:
    :param e:
    :return: a RSA Public Key in PEM format
    """
    n = int(binascii.hexlify(jwt.utils.base64url_decode(bytes(n))), 16)
    e = int(binascii.hexlify(jwt.utils.base64url_decode(bytes(e))), 16)
    pub = RSAPublicNumbers(e, n).public_key(default_backend())
    return pub.public_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PublicFormat.SubjectPublicKeyInfo
    )
Example #5
0
def jwt_token_verify(id_token, client_id, issuer, autoconfig=None, jwk=None):
    """
    Verify a JWT token using public key.
    If jwk is not provided the issuer must support auto-discovery.
    This will also slow down the login process since multiple remote calls
    are required to fetch jwk.
    :param id_token: The openid id_token returned by the authorisation call
    :param client_id: The client_id, required for JWT verification
    :param issuer: The issuer, required for JWT verification and for
                   auto-configuration if necessary
    :param autoconfig: Dictionary of auto-configuration properties, if empty
                       will be fetched if required
    :param jwk: The JSON web key, if empty will be fetched using autoconfig
    :return dict: The decoded verified token
    :raises Exception: If verification failed
    """
    # https://pyjwt.readthedocs.io/en/latest/usage.html
    # https://openid.net/specs/openid-connect-core-1_0.html#IDToken

    if not jwk:
        header = jwt.get_unverified_header(id_token)
        if not autoconfig:
            autoconfig = openid_connect_discover(issuer)
        jwks = _cache_get(autoconfig['jwks_uri'])
        for jwk in jwks['keys']:
            if jwk['kid'] == header['kid']:
                break
    if not jwk:
        raise Exception('Failed to get public key for {}'.format(issuer))

    e = int(codecs.encode(base64url_decode(jwk['e']), 'hex'), 16)
    n = int(codecs.encode(base64url_decode(jwk['n']), 'hex'), 16)
    public_key = RSAPublicNumbers(e, n).public_key(backend=default_backend())
    pem = public_key.public_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PublicFormat.SubjectPublicKeyInfo)
    d = jwt.decode(id_token, key=pem, algorithms=jwk['alg'],
                   audience=client_id, issuer=issuer)
    return d
Example #6
0
def main():
    parser = ArgumentParser(
        description='Swiss Army Knife for keys and certificates')
    parser.add_argument('--import', dest='do_import', action='store_true')
    parser.add_argument('--export', dest='do_export', action='store_true')
    parser.add_argument('--search', dest='do_search', action='store_true')
    parser.add_argument('--list', dest='do_list', action='store_true')
    parser.add_argument('--format', dest='format')
    parser.add_argument('--comment', dest='comment')
    args = parser.parse_args()
    db = sqlite3.connect(path.expanduser('~/.config/ktool.sqlite3'))
    db.execute(
        'CREATE TABLE IF NOT EXISTS rsa_keys (e, n, comment, PRIMARY KEY (e, n))'
    )
    if args.format:
        args.format = args.format.lower()
    if args.format == 'rb64':
        e = '\x01\x00\x01'  # XXX
        n = stdin.read().decode('base64')
    elif args.format == 'rhex':
        e = '\x01\x00\x01'  # XXX
        n = re.sub('[^0-9a-f]+', '', stdin.read(), flags=re.I).decode('hex')
    elif args.format in ('der', 'pem'):
        from Crypto.PublicKey import RSA
        k = RSA.importKey(stdin.read())
        n = number_to_str(k.n)
        e = number_to_str(k.e)
    else:
        n = ''
    n = n.lstrip('\0')
    if args.do_import:
        try:
            db.execute('INSERT INTO rsa_keys (e, n, comment) VALUES (?, ?, ?)',
                       (sqlite3.Binary(e), sqlite3.Binary(n), args.comment))
            db.commit()
        except sqlite3.IntegrityError:
            row = db.execute('SELECT comment FROM rsa_keys WHERE n = ?',
                             (sqlite3.Binary(n), )).fetchone()
            if row:
                print('Key already in database with comment: ' + row[0],
                      file=stderr)
                raise SystemExit(1)
            else:
                raise
    elif args.do_export:
        row = db.execute('SELECT e, n FROM rsa_keys WHERE comment = ?',
                         (args.comment, )).fetchone()
        if row:
            from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicNumbers
            from cryptography.hazmat.primitives import serialization
            from cryptography.hazmat.backends import default_backend
            e, n = (str_to_number(p) for p in row)
            pk = RSAPublicNumbers(e, n).public_key(default_backend())
            print(
                pk.public_bytes(
                    encoding=serialization.Encoding.PEM,
                    format=serialization.PublicFormat.SubjectPublicKeyInfo))
        else:
            print('No key with matching comment found', file=stderr)
            raise SystemExit(1)
    elif args.do_search:
        row = db.execute('SELECT comment FROM rsa_keys WHERE n = ?',
                         (sqlite3.Binary(n), )).fetchone()
        if row:
            print('Comment: ' + row[0])
        else:
            print('No modulus matches in database', file=stderr)
            raise SystemExit(1)

    elif args.do_list:
        c = db.execute('SELECT e, n, comment FROM rsa_keys ORDER BY e, n')
        print('{0:>8} {1:32} {2:>5} {3}'.format(
            'e', 'n (first 16 octets from MSB)', 'nbits', 'comment'))
        print('=' * 80)
        for e, n, comment in c:
            print('{0:>8} {1:32} {2:>5} {3}'.format(e[:4].encode('hex'),
                                                    n[:16].encode('hex'),
                                                    len(n) * 8, comment))