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
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
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)