Beispiel #1
0
def pkcs11_jws_verify(token: str) -> Optional[str]:
    """
    Perform JWS Sign with a key stored in an PKCS#11 token.

    This requires temporarily switching the key class for the algorithm in the token.
    See the documentation for pkcs11_jws_sign for more details.

    :return: The signed payload from the token, or None if verify is not supported
    """
    headers = jws.get_unverified_headers(token)
    _alg = headers['alg']

    # First, check if verify for this algorithm is supported by the token (current YubiKey can
    # sign with ECDSA, but not verify).
    # We have to do it in this hackish manner since the JOSE library will ignore any exceptions
    # from the verify method and just turn everything into an
    # JWSError('Signature verification failed.') exception.
    _p11key = P11Key('', _alg, P11Key_params)
    with _p11key.token.open(user_pin=_p11key.p11.pin) as session:
        _p11key._load_key(session)
        info = _p11key.token.slot.get_mechanism_info(_p11key._mechanism)
    logger.debug('Token mechanism info:\n{}'.format(info))
    if pkcs11.MechanismFlag.VERIFY not in info.flags:
        logger.info(
            'Verify is not a supported operation for algorithm {} using the PKCS#11 token'
            .format(_p11key._algorithm))
        return None

    orig_key = jwk.get_key(_alg)
    try:
        # First check if verify is a supported operation using this al
        jwk.register_key(_alg, P11Key)
        res = jws.verify(
            token, '', algorithms=[jwk.ALGORITHMS.ES256, jwk.ALGORITHMS.RS256])
    except:
        raise
    finally:
        jwk.register_key(_alg, orig_key)
    return res
Beispiel #2
0
def pkcs11_jws_sign(data, key=None, headers=None) -> str:
    """
    Perform JWS Sign with a key stored in an PKCS#11 token.

    This requires some trickery - temporary switch out the key class for the algorithm
    to P11Key before calling jws.sign. It is not possible to just register a new algorithm,
    say ECP11, because the algorithm is included in the JWT and the consumer of the JWT
    would expect ES256 (or similar) and not know how to handle ECP11.

    :return: A signed JWT
    """
    global P11Key_params
    _p11key = P11Key('', '', P11Key_params)
    _alg = _p11key.get_jwk_alg()

    orig_key = jwk.get_key(_alg)
    try:
        jwk.register_key(_alg, P11Key)
        res = jws.sign(data, key, algorithm=_alg, headers=headers)
    except:
        raise
    finally:
        jwk.register_key(_alg, orig_key)
    return res
Beispiel #3
0
    def test_register_key(self):
        assert jwk.register_key("ALG", jwk.Key)
        assert jwk.get_key("ALG") == jwk.Key

        with pytest.raises(TypeError):
            assert jwk.register_key("ALG", object)
Beispiel #4
0
    def test_register_key(self):
        assert jwk.register_key("ALG", jwk.Key)
        assert jwk.get_key("ALG") == jwk.Key

        with pytest.raises(TypeError):
            assert jwk.register_key("ALG", object)