Пример #1
0
    def __setitem__(self, key, value):
        """

        :param key: issuer ID
        :type: String
        :param value: Cryptographic keys that should be connected to to an
         issuer ID.
        :type value: KeyJar or a JWKS (JSON document)
        """
        if not isinstance(value, KeyJar):
            kj = KeyJar()
            kj.import_jwks(value, issuer=key)
            value = kj
        else:
            _val = value.copy()
            _iss = list(_val.owners())
            if _iss == ['']:
                _val.issuer_keys[key] = _val.issuer_keys['']
                del _val.issuer_keys['']
            elif len(_iss) == 1:
                if _iss[0] != key:
                    _val.issuer_keys[key] = _val.issuer_keys[_iss[0]]
                    del _val.issuer_keys[_iss[0]]
            else:
                raise ValueError('KeyJar contains to many issuers')

            value = _val

        self.bundle[key] = value
Пример #2
0
    def test_dump_issuer_keys(self):
        kb = keybundle_from_local_file("file://%s/jwk.json" % BASE_PATH,
                                       "jwks", ["sig"])
        assert len(kb) == 1
        kj = KeyJar()
        kj.issuer_keys[""] = [kb]
        _jwks_dict = kj.export_jwks()

        _info = _jwks_dict['keys'][0]
        assert _info == {
            'use':
            'sig',
            'e':
            'AQAB',
            'kty':
            'RSA',
            'alg':
            'RS256',
            'n':
            'pKybs0WaHU_y4cHxWbm8Wzj66HtcyFn7Fh3n'
            '-99qTXu5yNa30MRYIYfSDwe9JVc1JUoGw41yq2StdGBJ40HxichjE'
            '-Yopfu3B58Q'
            'lgJvToUbWD4gmTDGgMGxQxtv1En2yedaynQ73sDpIK-12JJDY55pvf'
            '-PCiSQ9OjxZLiVGKlClDus44_uv2370b9IN2JiEOF-a7JB'
            'qaTEYLPpXaoKWDSnJNonr79tL0T7iuJmO1l705oO3Y0TQ'
            '-INLY6jnKG_RpsvyvGNnwP9pMvcP1phKsWZ10ofuuhJGRp8IxQL9Rfz'
            'T87OvF0RBSO1U73h09YP-corWDsnKIi6TbzRpN5YDw',
            'kid':
            'abc'
        }
Пример #3
0
    def verify(self, **kwargs):
        """
        Verifies that an instance of this class adhers to the given 
            restrictions.
        """
        super(MetadataStatement, self).verify(**kwargs)
        if "signing_keys" in self:
            if 'signing_keys_uri' in self:
                raise VerificationError(
                    'You can only have one of "signing_keys" and '
                    '"signing_keys_uri" in a metadata statement')
            else:
                # signing_keys MUST be a JWKS
                kj = KeyJar()
                try:
                    kj.import_jwks(self['signing_keys'], '')
                except Exception:
                    raise VerificationError('"signing_keys" not a proper JWKS')

        if "metadata_statements" in self and "metadata_statement_uris" in self:
            s = set(self['metadata_statements'].keys())
            t = set(self['metadata_statement_uris'].keys())
            if s.intersection(t):
                raise VerificationError(
                    'You should not have the same key in "metadata_statements" '
                    'and in "metadata_statement_uris"')

        return True
Пример #4
0
def test_jwt_pack_unpack_sym():
    kj = KeyJar()
    kj.add_symmetric(owner='', key='client_secret', usage=['sig'])
    kj['https://fedop.example.org'] = kj['']
    srv = JWT(kj, iss=issuer, sign_alg="HS256")
    payload = {'sub': 'sub2'}
    _jwt = srv.pack(payload=payload)
    info = srv.unpack(_jwt)
    assert info
Пример #5
0
    def test_provider(self):
        provider_info = {
            "jwks_uri": "https://connect-op.herokuapp.com/jwks.json",
        }

        ks = KeyJar()
        ks.load_keys(provider_info, "https://connect-op.heroku.com")

        assert ks["https://connect-op.heroku.com"][0].keys()
Пример #6
0
def test_self_signed_jwks():
    kj = KeyJar()
    kj.issuer_keys['abc'] = KEYJAR.issuer_keys['']
    ssj = self_sign_jwks(kj, 'abc', kid='', lifetime=3600)
    assert ssj

    res = verify_self_signed_jwks(ssj)
    _kj = jwks_to_keyjar(res['jwks'], res['iss'])
    assert list(_kj.owners()) == ['abc']
    assert len(_kj.get_signing_key('RSA',owner='abc')) == 2
    assert len(_kj.get_signing_key('EC',owner='abc')) == 1
Пример #7
0
def read_jwks_file(jwks_file):
    """
    Reads a file containing a JWKS and populates a oic.utils.keyio.KeyJar from
    it.

    :param jwks_file: file name of the JWKS file 
    :return: A oic.utils.keyio.KeyJar instance
    """
    _jwks = open(jwks_file, 'r').read()
    _kj = KeyJar()
    _kj.import_jwks(json.loads(_jwks), '')
    return _kj
Пример #8
0
def test_request_signed_by_signing_keys():
    kj = KeyJar()
    kj.issuer_keys['abc'] = KEYJAR.issuer_keys['']
    msreq = MetadataStatement(signing_keys=json.dumps(JWKS))
    smsreq = request_signed_by_signing_keys(kj, msreq, 'abc', 3600)

    assert smsreq

    res = verify_request_signed_by_signing_keys(smsreq)

    assert set(res.keys()) == {'ms', 'iss'}
    assert res['iss'] == 'abc'
Пример #9
0
 def as_keyjar(self):
     """
     Convert a key bundle into a KeyJar instance.
     
     :return: An :py:class:`oic.utils.keyio.KeyJar` instance 
     """
     kj = KeyJar()
     for iss, k in self.bundle.items():
         try:
             kj.issuer_keys[iss] = k.issuer_keys[iss]
         except KeyError:
             kj.issuer_keys[iss] = k.issuer_keys['']
     return kj
Пример #10
0
def keyjar_from_metadata_statements(iss, msl):
    """
    Builds a keyJar instance based on the information in the 'signing_keys'
    claims in a list of metadata statements.
    
    :param iss: Owner of the signing keys 
    :param msl: List of :py:class:`MetadataStatement` instances.
    :return: A oic.utils.keyio.KeyJar instance
    """
    keyjar = KeyJar()
    for ms in msl:
        keyjar.import_jwks(ms['signing_keys'], iss)
    return keyjar
Пример #11
0
def test_create_verify():
    sign_keyjar = build_keyjar(KEYDEFS)[1]
    jb = make_jwks_bundle('https://example.com', ['fo0', 'fo1', 'fo2', 'fo3'],
                          sign_keyjar, KEYDEFS)

    _jws = jb.create_signed_bundle()
    _jwks = sign_keyjar.export_jwks()

    kj = KeyJar()
    kj.import_jwks(_jwks, 'https://example.com')
    bundle = verify_signed_bundle(_jws, kj)

    assert bundle
Пример #12
0
 def __init__(self, keys=None, source="", cache_time=300, verify_ssl=True,
         fileformat="jwk", keytype="RSA", keyusage=None,
         verify_keys=None):
     super(KeyBundle, self).__init__(keys=keys, source=source,
                                     cache_time=cache_time,
                                     verify_ssl=verify_ssl,
                                     fileformat=fileformat,
                                     keytype=keytype, keyusage=keyusage)
     if verify_keys is not None:
         if isinstance(verify_keys, KeyJar):
             self.verify_keys = verify_keys
         else:
             self.verify_keys = KeyJar()
             self.verify_keys.import_jwks(verify_keys, '')
Пример #13
0
def test_keyjar_eq():
    kj1 = KeyJar()
    kj1.import_jwks(JWKS_SPO, '')

    kj2 = KeyJar()
    kj2.import_jwks(JWKS_SPO, '')

    assert kj1 == kj2
Пример #14
0
    def oauth_post_parse_response(self, resp, cli_info, **kwargs):
        """
        Deal with Provider Config Response
        :param resp: The provider info response
        :param cli_info: Information about the client/server session
        """
        issuer = cli_info.issuer

        if "issuer" in resp:
            _pcr_issuer = resp["issuer"]
            if resp["issuer"].endswith("/"):
                if issuer.endswith("/"):
                    _issuer = issuer
                else:
                    _issuer = issuer + "/"
            else:
                if issuer.endswith("/"):
                    _issuer = issuer[:-1]
                else:
                    _issuer = issuer

            try:
                cli_info.allow['issuer_mismatch']
            except KeyError:
                if _issuer != _pcr_issuer:
                    raise OicCliError(
                        "provider info issuer mismatch '%s' != '%s'" %
                        (_issuer, _pcr_issuer))

        else:  # No prior knowledge
            _pcr_issuer = issuer

        cli_info.issuer = _pcr_issuer
        cli_info.provider_info = resp

        for key, val in resp.items():
            if key.endswith("_endpoint"):
                for _srv in cli_info.service.values():
                    if _srv.endpoint_name == key:
                        _srv.endpoint = val

        try:
            kj = cli_info.keyjar
        except KeyError:
            kj = KeyJar()

        kj.load_keys(resp, _pcr_issuer)
        cli_info.keyjar = kj
Пример #15
0
def jwks_to_keyjar(jwks, iss=''):
    """
    Convert a JWKS to a KeyJar instance.

    :param jwks: String representation of a JWKS
    :return: A :py:class:`oic.utils.keyio.KeyJar` instance
    """
    if not isinstance(jwks, dict):
        try:
            jwks = json.loads(jwks)
        except json.JSONDecodeError:
            raise ValueError('No proper JSON')

    kj = KeyJar()
    kj.import_jwks(jwks, issuer=iss)
    return kj
Пример #16
0
    def __init__(self, ca_certs=None, client_authn_method=None,
                 keyjar=None, verify_ssl=True, config=None, client_cert=None,
                 httplib=None, services=None, service_factory=None):
        """

        :param ca_certs: Certificates used to verify HTTPS certificates
        :param client_authn_method: Methods that this client can use to
            authenticate itself. It's a dictionary with method names as
            keys and method classes as values.
        :param verify_ssl: Whether the SSL certificate should be verified.
        :return: Client instance
        """

        self.http = httplib or HTTPLib(ca_certs=ca_certs,
                                       verify_ssl=verify_ssl,
                                       client_cert=client_cert,
                                       keyjar=keyjar)

        if not keyjar:
            keyjar = KeyJar()

        self.events = None
        self.client_info = ClientInfo(keyjar, config=config)
        if self.client_info.client_id:
            self.client_id = self.client_info.client_id
        _cam = client_authn_method or CLIENT_AUTHN_METHOD
        self.service_factory = service_factory or service.factory
        _srvs = services or DEFAULT_SERVICES

        self.service = build_services(_srvs, self.service_factory, self.http,
                                      keyjar, _cam)

        self.client_info.service = self.service

        self.verify_ssl = verify_ssl
Пример #17
0
class KeyBundle(key_bundle.KeyBundle):
    def __init__(self, keys=None, source="", cache_time=300, verify_ssl=True,
            fileformat="jwk", keytype="RSA", keyusage=None,
            verify_keys=None):
        super(KeyBundle, self).__init__(keys=keys, source=source,
                                        cache_time=cache_time,
                                        verify_ssl=verify_ssl,
                                        fileformat=fileformat,
                                        keytype=keytype, keyusage=keyusage)
        if verify_keys is not None:
            if isinstance(verify_keys, KeyJar):
                self.verify_keys = verify_keys
            else:
                self.verify_keys = KeyJar()
                self.verify_keys.import_jwks(verify_keys, '')

    def _parse_remote_response(self, response):
        """
        Parse simple JWKS or signed JWKS from the HTTP response.

        :param response: HTTP response from the 'jwks_uri' or 'signed_jwks_uri'
            endpoint
        :return: response parsed as JSON
        """
        # Check if the content type is the right one.
        try:
            if response.headers["Content-Type"] == 'application/json':
                logger.debug(
                    "Loaded JWKS: %s from %s" % (response.text, self.source))
                try:
                    return json.loads(response.text)
                except ValueError:
                    return None
            elif response.headers["Content-Type"] == 'application/jose':
                logger.debug(
                    "Signed JWKS: %s from %s" % (response.text, self.source))
                _jws = factory(response.text)
                _resp = _jws.verify_compact(
                    response.text, keys=self.verify_keys.get_signing_key())
                return _resp
            else:
                logger.error('Wrong content type: {}'.format(
                    response.headers['Content-Type']))
                return None
        except KeyError:
            pass
Пример #18
0
def public_jwks_bundle(jwks_bundle):
    jb_copy = JWKSBundle('')
    for fo, kj in jwks_bundle.bundle.items():
        kj_copy = KeyJar()
        for owner in kj.owners():
            public_keys_keyjar(kj, owner, kj_copy, owner)
        jb_copy.bundle[fo] = kj_copy
    return jb_copy
Пример #19
0
def test_copy():
    kj = KeyJar()
    kj['A'] = [KeyBundle(JWK0['keys'])]
    kj['B'] = [KeyBundle(JWK1['keys'])]
    kj['C'] = [KeyBundle(JWK2['keys'])]

    kjc = kj.copy()

    assert set(kjc.owners()) == {'A', 'B', 'C'}

    assert len(kjc.get('sig', 'oct', 'A')) == 0
    assert len(kjc.get('sig', 'rsa', 'A')) == 1

    assert len(kjc.get('sig', 'oct', 'B')) == 1
    assert len(kjc.get('sig', 'rsa', 'B')) == 1

    assert len(kjc.get('sig', 'oct', 'C')) == 0
    assert len(kjc.get('sig', 'rsa', 'C')) == 4
Пример #20
0
def test_get_signing_key_use_undefined():
    kj = KeyJar()
    kj.import_jwks(JWK1, '')
    keys = kj.get_signing_key(kid='rsa1')
    assert len(keys) == 1

    keys = kj.get_signing_key(key_type='rsa')
    assert len(keys) == 1

    keys = kj.get_signing_key(key_type='rsa', kid='rsa1')
    assert len(keys) == 1
Пример #21
0
    def setup(self):
        mkey = [
            {
                "type": "RSA",
                "use": ["sig"]
            },
            {
                "type": "RSA",
                "use": ["sig"]
            },
            {
                "type": "RSA",
                "use": ["sig"]
            },
        ]

        skey = [
            {
                "type": "RSA",
                "use": ["sig"]
            },
        ]

        kj1 = build_keyjar(mkey)[1]
        kj2 = build_keyjar(skey)[1]
        self.keyjar = KeyJar()
        self.keyjar['A'] = kj1['']
        self.keyjar['B'] = kj2['']

        _jws = JWS('{"aud": "A"}', alg='RS256')
        sig_key = self.keyjar.get_signing_key('rsa', owner='A')[0]
        self.sjwt_a = _jws.sign_compact([sig_key])

        _jws = JWS('{"aud": "B"}', alg='RS256')
        sig_key = self.keyjar.get_signing_key('rsa', owner='B')[0]
        self.sjwt_b = _jws.sign_compact([sig_key])
Пример #22
0
    def test_items(self):
        ks = KeyJar()
        ks[""] = KeyBundle([{
            "kty": "oct",
            "key": "a1b2c3d4",
            "use": "sig"
        }, {
            "kty": "oct",
            "key": "a1b2c3d4",
            "use": "ver"
        }])
        ks["http://www.example.org"] = KeyBundle([{
            "kty": "oct",
            "key": "e5f6g7h8",
            "use": "sig"
        }, {
            "kty": "oct",
            "key": "e5f6g7h8",
            "use": "ver"
        }])
        ks["http://www.example.org"].append(
            keybundle_from_local_file(RSAKEY, "der", ["ver", "sig"]))

        assert len(ks.items()) == 2
Пример #23
0
    def test_issuer_missing_slash(self):
        ks = KeyJar()
        ks[""] = KeyBundle([{
            "kty": "oct",
            "key": "a1b2c3d4",
            "use": "sig"
        }, {
            "kty": "oct",
            "key": "a1b2c3d4",
            "use": "ver"
        }])
        ks["http://www.example.org/"] = KeyBundle([{
            "kty": "oct",
            "key": "e5f6g7h8",
            "use": "sig"
        }, {
            "kty": "oct",
            "key": "e5f6g7h8",
            "use": "ver"
        }])
        ks["http://www.example.org/"].append(
            keybundle_from_local_file(RSAKEY, "der", ["ver", "sig"]))

        assert ks.get('sig', 'RSA', 'http://www.example.org')
Пример #24
0
    def test_get_enc_not_mine(self):
        ks = KeyJar()
        ks[""] = KeyBundle([{
            "kty": "oct",
            "key": "a1b2c3d4",
            "use": "sig"
        }, {
            "kty": "oct",
            "key": "a1b2c3d4",
            "use": "enc"
        }])
        ks["http://www.example.org/"] = KeyBundle([{
            "kty": "oct",
            "key": "e5f6g7h8",
            "use": "sig"
        }, {
            "kty": "oct",
            "key": "e5f6g7h8",
            "use": "ver"
        }])
        ks["http://www.example.org/"].append(
            keybundle_from_local_file(RSAKEY, "der", ["ver", "sig"]))

        assert ks.get('enc', 'oct', 'http://www.example.org/')
Пример #25
0
    def __init__(self, ca_certs=None, verify_ssl=True, keyjar=None,
                 client_cert=None):
        """
        A base class for OAuth2 clients and servers

        :param ca_certs: the path to a CA_BUNDLE file or directory with
            certificates of trusted CAs
        :param verify_ssl: If True then the server SSL certificate is not
            verfied
        :param keyjar: A place to keep keys for signing/encrypting messages
        :param client_cert: local cert to use as client side certificate, as a
            single file (containing the private key and the certificate) or as
            a tuple of both file's path
        """

        self.keyjar = keyjar or KeyJar(verify_ssl=verify_ssl)

        self.request_args = {"allow_redirects": False}

        self.cookiejar = FileCookieJar()
        self.ca_certs = ca_certs

        if ca_certs:
            if verify_ssl is False:
                raise ValueError(
                    'conflict: ca_certs defined, but verify_ssl is False')

            # Instruct requests to verify certificate against the CA cert
            # bundle located at the path given by `ca_certs`.
            self.request_args["verify"] = ca_certs

        elif verify_ssl:
            # Instruct requests to verify server certificates against the
            # default CA bundle provided by 'certifi'. See
            # http://docs.python-requests.org/en/master/user/advanced/#ca
            # -certificates
            self.request_args["verify"] = True

        else:
            # Instruct requests to not perform server cert verification.
            self.request_args["verify"] = False

        self.events = None
        self.req_callback = None
        if client_cert:
            self.request_args['cert'] = client_cert
Пример #26
0
def own_sign_keys(sigkey_name, issuer, sig_def_keys):
    try:
        jwks = json.loads(open(sigkey_name, 'r').read())
        sign_kj = KeyJar()
        sign_kj.import_jwks(jwks, issuer)
    except FileNotFoundError:
        jwks, sign_kj, _ = build_keyjar(sig_def_keys)
        sign_kj.issuer_keys[issuer] = sign_kj.issuer_keys['']
        fp = open(sigkey_name, 'w')
        fp.write(json.dumps(sign_kj.export_jwks(private=True, issuer=issuer)))
        fp.close()

    return sign_kj
Пример #27
0
def test_key_export():
    kj = KeyJar()
    url = key_export("http://example.com/keys/",
                     "outbound",
                     "secret",
                     keyjar=kj,
                     sig={
                         "alg": "rsa",
                         "format": ["x509", "jwks"]
                     })

    assert url == "http://example.com/keys/outbound/jwks"

    # Now a jwks should reside in './keys/outbound/jwks'

    kb = KeyBundle(source='file://./keys/outbound/jwks')

    # One key
    assert len(kb) == 1
    # more specifically one RSA key
    assert len(kb.get('RSA')) == 1
    k = kb.get('RSA')[0]
    # For signing
    assert k.use == 'sig'
Пример #28
0
    def loads(self, jstr):
        """
        Upload a bundle from an unsigned JSON document

        :param jstr: A bundle as a dictionary or a JSON document
        """
        if isinstance(jstr, dict):
            _info = jstr
        else:
            _info = json.loads(jstr)

        for iss, jwks in _info.items():
            kj = KeyJar()
            if isinstance(jwks, dict):
                kj.import_jwks(jwks, issuer=iss)
            else:
                kj.import_jwks_as_json(jwks, issuer=iss)
            self.bundle[iss] = kj
        return self
Пример #29
0
def get_signing_keys(eid, keydef, key_file):
    """
    If the *key_file* file exists then read the keys from there, otherwise
    create the keys and store them a file with the name *key_file*.

    :param eid: The ID of the entity that the keys belongs to
    :param keydef: What keys to create
    :param key_file: A file name
    :return: A :py:class:`oic.utils.keyio.KeyJar` instance
    """
    if os.path.isfile(key_file):
        kj = KeyJar()
        kj.import_jwks(json.loads(open(key_file, 'r').read()), eid)
    else:
        kj = build_keyjar(keydef)[1]
        # make it know under both names
        fp = open(key_file, 'w')
        fp.write(json.dumps(kj.export_jwks()))
        fp.close()
        kj.issuer_keys[eid] = kj.issuer_keys['']

    return kj
Пример #30
0
class TestVerifyJWTKeys(object):
    @pytest.fixture(autouse=True)
    def setup(self):
        mkey = [
            {
                "type": "RSA",
                "use": ["sig"]
            },
            {
                "type": "RSA",
                "use": ["sig"]
            },
            {
                "type": "RSA",
                "use": ["sig"]
            },
        ]

        skey = [
            {
                "type": "RSA",
                "use": ["sig"]
            },
        ]

        kj1 = build_keyjar(mkey)[1]
        kj2 = build_keyjar(skey)[1]
        self.keyjar = KeyJar()
        self.keyjar['A'] = kj1['']
        self.keyjar['B'] = kj2['']

        _jws = JWS('{"aud": "A"}', alg='RS256')
        sig_key = self.keyjar.get_signing_key('rsa', owner='A')[0]
        self.sjwt_a = _jws.sign_compact([sig_key])

        _jws = JWS('{"aud": "B"}', alg='RS256')
        sig_key = self.keyjar.get_signing_key('rsa', owner='B')[0]
        self.sjwt_b = _jws.sign_compact([sig_key])

    def test_no_kid_multiple_keys(self):
        """ This is extremely strict """
        _jwt = factory(self.sjwt_a)
        # remove kid reference
        _jwt.jwt.headers['kid'] = ''
        keys = self.keyjar.get_jwt_verify_keys(_jwt.jwt)
        assert len(keys) == 0

    def test_no_kid_single_key(self):
        _jwt = factory(self.sjwt_b)
        _jwt.jwt.headers['kid'] = ''
        keys = self.keyjar.get_jwt_verify_keys(_jwt.jwt)
        assert len(keys) == 1

    def test_no_kid_multiple_keys_no_kid_issuer(self):
        a_kids = [
            k.kid
            for k in self.keyjar.get_verify_key(owner='A', key_type='RSA')
        ]
        no_kid_issuer = {'A': a_kids}
        _jwt = factory(self.sjwt_a)
        _jwt.jwt.headers['kid'] = ''
        keys = self.keyjar.get_jwt_verify_keys(_jwt.jwt,
                                               no_kid_issuer=no_kid_issuer)
        assert len(keys) == 3
        assert set([k.kid for k in keys]) == set(a_kids)

    def test_no_kid_multiple_keys_no_kid_issuer_lim(self):
        a_kids = [
            k.kid
            for k in self.keyjar.get_verify_key(owner='A', key_type='RSA')
        ]
        no_kid_issuer = {'A': []}
        _jwt = factory(self.sjwt_a)
        _jwt.jwt.headers['kid'] = ''
        keys = self.keyjar.get_jwt_verify_keys(_jwt.jwt,
                                               no_kid_issuer=no_kid_issuer)
        assert len(keys) == 3
        assert set([k.kid for k in keys]) == set(a_kids)

    def test_matching_kid(self):
        _jwt = factory(self.sjwt_b)
        keys = self.keyjar.get_jwt_verify_keys(_jwt.jwt)
        assert len(keys) == 1

    def test_no_matching_kid(self):
        _jwt = factory(self.sjwt_b)
        _jwt.jwt.headers['kid'] = 'abcdef'
        keys = self.keyjar.get_jwt_verify_keys(_jwt.jwt)
        assert keys == []

    def test_aud(self):
        self.keyjar.import_jwks(JWK1, issuer='D')

        _jws = JWS('{"iss": "D", "aud": "A"}', alg='HS256')
        sig_key = self.keyjar.get_signing_key('oct', owner='D')[0]
        _sjwt = _jws.sign_compact([sig_key])

        no_kid_issuer = {'D': []}

        _jwt = factory(_sjwt)

        keys = self.keyjar.get_jwt_verify_keys(_jwt.jwt,
                                               no_kid_issuer=no_kid_issuer)
        assert len(keys) == 1