Exemple #1
0
    def __init__(self, plaintext=None, protected=None, unprotected=None,
                 aad=None, algs=None):
        """Creates a JWE token.

        :param plaintext(bytes): An arbitrary plaintext to be encrypted.
        :param protected: A JSON string with the protected header.
        :param unprotected: A JSON string with the shared unprotected header.
        :param aad(bytes): Arbitrary additional authenticated data
        :param algs: An optional list of allowed algorithms
        """
        self._allowed_algs = None
        self.objects = dict()
        self.plaintext = None
        if plaintext is not None:
            if isinstance(plaintext, bytes):
                self.plaintext = plaintext
            else:
                self.plaintext = plaintext.encode('utf-8')
        self.cek = None
        self.decryptlog = None
        if aad:
            self.objects['aad'] = aad
        if protected:
            _ = json_decode(protected)  # check header encoding
            self.objects['protected'] = protected
        if unprotected:
            _ = json_decode(unprotected)  # check header encoding
            self.objects['unprotected'] = unprotected
        if algs:
            self.allowed_algs = algs
Exemple #2
0
 def server_keys(self):
     if self._server_keys is None:
         if "server_keys" not in self.config:
             raise UnknownPublicKey("Server Keys not defined")
         skey = self.find_key(self.config["server_keys"], KEY_USAGE_SIG)
         ekey = self.find_key(self.config["server_keys"], KEY_USAGE_ENC)
         self._server_keys = [JWK(**(json_decode(skey))), JWK(**(json_decode(ekey)))]
     return self._server_keys
Exemple #3
0
    def serialize(self, compact=False):
        """Serializes the object into a JWE token.

        :param compact(boolean): if True generates the compact
         representation, otherwise generates a standard JSON format.

        :raises InvalidJWEOperation: if the object cannot serialized
         with the compact representation and `compat` is True.
        :raises InvalidJWEOperation: if no recipients have been added
         to the object.
        """

        if 'ciphertext' not in self.objects:
            raise InvalidJWEOperation("No available ciphertext")

        if compact:
            for invalid in 'aad', 'unprotected':
                if invalid in self.objects:
                    raise InvalidJWEOperation("Can't use compact encoding")
            if 'recipients' in self.objects:
                if len(self.objects['recipients']) != 1:
                    raise InvalidJWEOperation("Invalid number of recipients")
                rec = self.objects['recipients'][0]
            else:
                rec = self.objects
            return '.'.join([base64url_encode(self.objects['protected']),
                             base64url_encode(rec.get('encrypted_key', '')),
                             base64url_encode(self.objects['iv']),
                             base64url_encode(self.objects['ciphertext']),
                             base64url_encode(self.objects['tag'])])
        else:
            obj = self.objects
            enc = {'ciphertext': base64url_encode(obj['ciphertext']),
                   'iv': base64url_encode(obj['iv']),
                   'tag': base64url_encode(self.objects['tag'])}
            if 'protected' in obj:
                enc['protected'] = base64url_encode(obj['protected'])
            if 'unprotected' in obj:
                enc['unprotected'] = json_decode(obj['unprotected'])
            if 'aad' in obj:
                enc['aad'] = base64url_encode(obj['aad'])
            if 'recipients' in obj:
                enc['recipients'] = list()
                for rec in obj['recipients']:
                    e = dict()
                    if 'encrypted_key' in rec:
                        e['encrypted_key'] = \
                            base64url_encode(rec['encrypted_key'])
                    if 'header' in rec:
                        e['header'] = json_decode(rec['header'])
                    enc['recipients'].append(e)
            else:
                if 'encrypted_key' in obj:
                    enc['encrypted_key'] = \
                        base64url_encode(obj['encrypted_key'])
                if 'header' in obj:
                    enc['header'] = json_decode(obj['header'])
            return json_encode(enc)
Exemple #4
0
def verify(sjws, pub_pem):
    sjws = json_decode(sjws)
    pub_pem = json_decode(pub_pem.replace('\n', '\\n'))
    if pub_pem.startswith("-----BEGIN"):
        pub_key = JWK.from_pem(to_bytes_2and3(pub_pem))
    else:
        pub_key = JWK(kty='oct', k=base64url_encode(pub_pem))
    sig = JWS()
    sig.deserialize(sjws, pub_key)
    sys.stdout.write(base64url_decode(json_decode(sig.serialize())['payload']))
Exemple #5
0
 def _get_jose_header(self, header=None):
     jh = dict()
     if 'protected' in self.objects:
         ph = json_decode(self.objects['protected'])
         jh = self._merge_headers(jh, ph)
     if 'unprotected' in self.objects:
         uh = json_decode(self.objects['unprotected'])
         jh = self._merge_headers(jh, uh)
     if header:
         rh = json_decode(header)
         jh = self._merge_headers(jh, rh)
     return jh
Exemple #6
0
 def test_1_Parse_GET(self):
     cli_skey = JWK(**self.client_keys[0])
     jtok = make_sig_kem("mykey", None, cli_skey, "RS256")
     kem = KEMHandler({'KEMKeysStore': self.kk})
     kem.parse(jtok, "mykey")
     out = kem.reply('output')
     jtok = JWT(jwt=json_decode(out)['value'])
     cli_ekey = JWK(**self.client_keys[1])
     jtok.token.decrypt(cli_ekey)
     nested = jtok.token.payload
     jtok = JWT(jwt=nested.decode('utf-8'))
     jtok.token.verify(JWK(**test_keys[0]))
     payload = json_decode(jtok.token.payload)['value']
     self.assertEqual(payload, 'output')
Exemple #7
0
    def wrap(self, key, keylen, cek, headers):
        self._check_key(key)
        if self.keydatalen is None:
            if cek is not None:
                raise InvalidJWEOperation('ECDH-ES cannot use an existing CEK')
            keydatalen = keylen * 8
            alg = headers['enc']
        else:
            keydatalen = self.keydatalen
            alg = headers['alg']

        epk = JWK.generate(kty=key.key_type, crv=key.key_curve)
        dk = self._derive(epk.get_op_key('unwrapKey'),
                          key.get_op_key('wrapKey'),
                          alg, keydatalen, headers)

        if self.keydatalen is None:
            ret = {'cek': dk}
        else:
            aeskw = _AesKw(keydatalen)
            kek = JWK(kty="oct", use="enc", k=base64url_encode(dk))
            ret = aeskw.wrap(kek, keydatalen // 8, cek, headers)

        ret['header'] = {'epk': json_decode(epk.export_public())}
        return ret
 def topic(self):
     """ Generate token """
     token = jwt.generate_jwt(payload, None, 'none', timedelta(seconds=60))
     header, claims, _ = token.split('.')
     parsed_header = json_decode(base64url_decode(header))
     del parsed_header['alg']
     return u"%s.%s." % (base64url_encode(json_encode(parsed_header)), claims)
Exemple #9
0
    def _format_public_key(self, key):
        if isinstance(key, str):
            jwkey = json_decode(key)
            if 'kty' not in jwkey:
                raise ValueError('Invalid key, missing "kty" attribute')
            if jwkey['kty'] == 'RSA':
                pubnum = rsa.RSAPublicNumbers(jwkey['e'], jwkey['n'])
                pubkey = pubnum.public_key(default_backend())
            elif jwkey['kty'] == 'EC':
                if jwkey['crv'] == 'P-256':
                    curve = ec.SECP256R1
                elif jwkey['crv'] == 'P-384':
                    curve = ec.SECP384R1
                elif jwkey['crv'] == 'P-521':
                    curve = ec.SECP521R1
                else:
                    raise TypeError('Unsupported Elliptic Curve')
                pubnum = ec.EllipticCurvePublicNumbers(
                    jwkey['x'], jwkey['y'], curve)
                pubkey = pubnum.public_key(default_backend())
            else:
                raise ValueError('Unknown key type: %s' % jwkey['kty'])
        elif isinstance(key, rsa.RSAPublicKey):
            pubkey = key
        elif isinstance(key, ec.EllipticCurvePublicKey):
            pubkey = key
        else:
            raise TypeError('Unknown key type: %s' % type(key))

        return pubkey.public_bytes(
            encoding=serialization.Encoding.DER,
            format=serialization.PublicFormat.SubjectPublicKeyInfo)
Exemple #10
0
    def _verify(self, alg, key, payload, signature, protected, header=None):
        # verify it is a valid JSON object and keep a decode copy
        if protected is not None:
            p = json_decode(protected)
        else:
            p = dict()
        if not isinstance(p, dict):
            raise InvalidJWSSignature('Invalid Protected header')
        # merge heders, and verify there are no duplicates
        if header:
            if not isinstance(header, dict):
                raise InvalidJWSSignature('Invalid Unprotected header')
            p = self._merge_headers(p, header)
        # verify critical headers
        # TODO: allow caller to specify list of headers it understands
        if 'crit' in p:
            self._check_crit(p['crit'])
        # check 'alg' is present
        if alg is None and 'alg' not in p:
            raise InvalidJWSSignature('No "alg" in headers')
        if alg:
            if 'alg' in p and alg != p['alg']:
                raise InvalidJWSSignature('"alg" mismatch, requested '
                                          '"%s", found "%s"' % (alg,
                                                                p['alg']))
            a = alg
        else:
            a = p['alg']

        # the following will verify the "alg" is supported and the signature
        # verifies
        S = JWSCore(a, key, protected, payload, self._allowed_algs)
        S.verify(signature)
Exemple #11
0
def process_jwt(jwt):
    """
    Process a JSON Web Token without verifying it.

    Call this before :func:`verify_jwt` if you need access to the header or claims in the token before verifying it. For example, the claims might identify the issuer such that you can retrieve the appropriate public key.

    :param jwt: The JSON Web Token to verify.
    :type jwt: str or unicode

    :rtype: tuple
    :returns: ``(header, claims)``
    """
    header, claims, _ = jwt.split('.')
    parsed_header = json_decode(base64url_decode(header))
    parsed_claims = json_decode(base64url_decode(claims))
    return parsed_header, parsed_claims
Exemple #12
0
    def import_key(self, value):
        v = json_decode(value)
        data = b64decode(v['pkcs12 data'])
        password = v['export password']
        try:
            _fd, tmpdata = tempfile.mkstemp(dir=paths.TMP)
            with open(tmpdata, 'w') as f:
                f.write(data)

            # get the certificate from the file
            ipautil.run([paths.OPENSSL,
                         "pkcs12",
                         "-in", tmpdata,
                         "-clcerts", "-nokeys",
                         "-out", self.certfile,
                         "-passin", "pass:{pwd}".format(pwd=password)],
                        nolog=(password, ))

            if self.keyfile is not None:
                # get the private key from the file
                ipautil.run([paths.OPENSSL,
                             "pkcs12",
                             "-in", tmpdata,
                             "-nocerts", "-nodes",
                             "-out", self.keyfile,
                             "-passin", "pass:{pwd}".format(pwd=password)],
                            nolog=(password, ))
        finally:
            os.remove(tmpdata)
Exemple #13
0
    def deserialize(self, raw_jws, key=None, alg=None):
        """Deserialize a JWS token.

        NOTE: Destroys any current status and tries to import the raw
        JWS provided.

        :param raw_jws: a 'raw' JWS token (JSON Encoded or Compact
         notation) string.
        :param key: A (:class:`jwcrypto.jwk.JWK`) verification key (optional).
         If a key is provided a verification step will be attempted after
         the object is successfully deserialized.
        :param alg: The signing algorithm (optional). usually the algorithm
         is known as it is provided with the JOSE Headers of the token.

        :raises InvalidJWSObject: if the raw object is an invaid JWS token.
        :raises InvalidJWSSignature: if the verification fails.
        """
        self.objects = dict()
        o = dict()
        try:
            try:
                djws = json_decode(raw_jws)
                o['payload'] = base64url_decode(str(djws['payload']))
                if 'signatures' in djws:
                    o['signatures'] = list()
                    for s in djws['signatures']:
                        os = dict()
                        os['signature'] = base64url_decode(str(s['signature']))
                        if 'protected' in s:
                            p = base64url_decode(str(s['protected']))
                            os['protected'] = p.decode('utf-8')
                        if 'header' in s:
                            os['header'] = s['header']
                        o['signatures'].append(os)
                else:
                    o['signature'] = base64url_decode(str(djws['signature']))
                    if 'protected' in djws:
                        p = base64url_decode(str(djws['protected']))
                        o['protected'] = p.decode('utf-8')
                    if 'header' in djws:
                        o['header'] = djws['header']

            except ValueError:
                c = raw_jws.split('.')
                if len(c) != 3:
                    raise InvalidJWSObject('Unrecognized representation')
                p = base64url_decode(str(c[0]))
                if len(p) > 0:
                    o['protected'] = p.decode('utf-8')
                o['payload'] = base64url_decode(str(c[1]))
                o['signature'] = base64url_decode(str(c[2]))

            self.objects = o

        except Exception as e:  # pylint: disable=broad-except
            raise InvalidJWSObject('Invalid format', repr(e))

        if key:
            self.verify(key, alg)
Exemple #14
0
    def _get_key(self, header, usage):
        if 'kid' not in header:
            raise InvalidMessage("Missing key identifier")

        key = self.kkstore.find_key(header['kid'], usage)
        if key is None:
            raise UnknownPublicKey('Key found [kid:%s]' % header['kid'])
        return json_decode(key)
Exemple #15
0
 def server_keys(self):
     if self._server_keys is None:
         with open(self.config['server_keys']) as f:
             jsonkeys = f.read()
         dictkeys = json_decode(jsonkeys)
         self._server_keys = (JWK(**dictkeys[KEY_USAGE_SIG]),
                              JWK(**dictkeys[KEY_USAGE_ENC]))
     return self._server_keys
Exemple #16
0
    def _check_provided_claims(self):
        # check_claims can be set to False to skip any check
        if self._check_claims is False:
            return

        try:
            claims = json_decode(self.claims)
            if not isinstance(claims, dict):
                raise ValueError()
        except ValueError:
            if self._check_claims is not None:
                raise JWTInvalidClaimFormat(
                    "Claims check requested but claims is not a json dict")
            return

        self._check_default_claims(claims)

        if self._check_claims is None:
            return

        for name, value in self._check_claims.items():
            if name not in claims:
                raise JWTMissingClaim("Claim %s is missing" % (name, ))

            if name in ['iss', 'sub', 'jti']:
                if value is not None and value != claims[name]:
                    raise JWTInvalidClaimValue(
                        "Invalid '%s' value. Expected '%s' got '%s'" % (
                            name, value, claims[name]))

            elif name == 'aud':
                if value is not None:
                    if value == claims[name]:
                        continue
                    if isinstance(claims[name], list):
                        if value in claims[name]:
                            continue
                    raise JWTInvalidClaimValue(
                        "Invalid '%s' value. Expected '%s' in '%s'" % (
                            name, value, claims[name]))

            elif name == 'exp':
                if value is not None:
                    self._check_exp(claims[name], value, 0)
                else:
                    self._check_exp(claims[name], time.time(), self._leeway)

            elif name == 'nbf':
                if value is not None:
                    self._check_nbf(claims[name], value, 0)
                else:
                    self._check_nbf(claims[name], time.time(), self._leeway)

            else:
                if value is not None and value != claims[name]:
                    raise JWTInvalidClaimValue(
                        "Invalid '%s' value. Expected '%d' got '%d'" % (
                            name, value, claims[name]))
Exemple #17
0
def generate(header, payload, priv_pem):
    priv_pem = json_decode(priv_pem.replace('\n', '\\n'))
    if priv_pem.startswith("-----BEGIN"):
        priv_key = JWK.from_pem(to_bytes_2and3(priv_pem))
    else:
        priv_key = JWK(kty='oct', k=base64url_encode(priv_pem))
    sig = JWS(payload)
    sig.add_signature(priv_key, protected=header)
    sys.stdout.write(sig.serialize(compact=True))
Exemple #18
0
    def test_A2(self):
        sigkey = jwk.JWK(**A2_example['key'])
        touter = jwt.JWT(jwt=A2_token, key=E_A2_ex['key'])
        tinner = jwt.JWT(jwt=touter.claims, key=sigkey, check_claims=False)
        self.assertEqual(A1_claims, json_decode(tinner.claims))

        with self.assertRaises(jwe.InvalidJWEData):
            jwt.JWT(jwt=A2_token, key=E_A2_ex['key'],
                    algs=['RSA_1_5', 'AES256GCM'])
Exemple #19
0
    def __get_keys(self, ca_host, cacerts_file, cacerts_pwd, data):
        # Fecth all needed certs one by one, then combine them in a single
        # p12 file

        prefix = data['prefix']
        certlist = data['list']

        cli = self.__CustodiaClient(server=ca_host)

        # Temporary nssdb
        tmpnssdir = tempfile.mkdtemp(dir=paths.TMP)
        try:
            # Temporary nssdb password
            nsspwfile = os.path.join(tmpnssdir, 'nsspwfile')
            with open(nsspwfile, 'w+') as f:
                f.write(b64encode(os.urandom(16)))
                f.flush()

            # Cert file password
            crtpwfile = os.path.join(tmpnssdir, 'crtpwfile')
            with open(crtpwfile, 'w+') as f:
                f.write(cacerts_pwd)
                f.flush()

            for nickname in certlist:
                value = cli.fetch_key(os.path.join(prefix, nickname), False)
                v = json_decode(value)
                pk12pwfile = os.path.join(tmpnssdir, 'pk12pwfile')
                with open(pk12pwfile, 'w+') as f:
                    f.write(v['export password'])
                pk12file = os.path.join(tmpnssdir, 'pk12file')
                with open(pk12file, 'w+') as f:
                    f.write(b64decode(v['pkcs12 data']))
                ipautil.run([paths.PK12UTIL,
                             '-d', tmpnssdir,
                             '-k', nsspwfile,
                             '-n', nickname,
                             '-i', pk12file,
                             '-w', pk12pwfile])

            # Add CA certificates
            tmpdb = CertDB(self.realm, nssdir=tmpnssdir)
            self.suffix = ipautil.realm_to_suffix(self.realm)
            if self.admin_conn is not None:
                self.ldap_disconnect()
            self.import_ca_certs(tmpdb, True)

            # Now that we gathered all certs, re-export
            ipautil.run([paths.PKCS12EXPORT,
                         '-d', tmpnssdir,
                         '-p', nsspwfile,
                         '-w', crtpwfile,
                         '-o', cacerts_file])

        finally:
            shutil.rmtree(tmpnssdir)
Exemple #20
0
 def test_3_KEMClient(self):
     server_keys = [JWK(**test_keys[KEY_USAGE_SIG]), JWK(**test_keys[KEY_USAGE_ENC])]
     client_keys = [JWK(**self.client_keys[KEY_USAGE_SIG]), JWK(**self.client_keys[KEY_USAGE_ENC])]
     cli = KEMClient(server_keys, client_keys)
     kem = KEMHandler({"KEMKeysStore": self.kk})
     req = cli.make_request("key name", encalg=("RSA1_5", "A256CBC-HS512"))
     kem.parse(req, "key name")
     msg = json_decode(kem.reply("key value"))
     rep = cli.parse_reply("key name", msg["value"])
     self.assertEqual(rep, "key value")
 def f(sjwt, iat_skew=timedelta()):
     """ verify token using node-jsjws """
     r = spawn(
         "fixtures.verify({now}, {sjwt}, {iat_skew}, {key}, {alg})".format(
             now=timegm(datetime.utcnow().utctimetuple()),
             sjwt=json_encode(sjwt),
             iat_skew=iat_skew.total_seconds(),
             key=json_encode(base64url_decode(json_decode(key.export())['k']) if key.is_symmetric else key.export_to_pem()),
             alg=json_encode(alg)),
         True)
     return tuple(r)
Exemple #22
0
 def test_2_KEMClient(self):
     server_keys = [JWK(**test_keys[KEY_USAGE_SIG]), None]
     client_keys = [JWK(**self.client_keys[KEY_USAGE_SIG]),
                    JWK(**self.client_keys[KEY_USAGE_ENC])]
     cli = KEMClient(server_keys, client_keys)
     kem = KEMHandler({'KEMKeysStore': self.kk})
     req = cli.make_request("key name")
     kem.parse(req, "key name")
     msg = json_decode(kem.reply('key value'))
     rep = cli.parse_reply("key name", msg['value'])
     self.assertEqual(rep, 'key value')
Exemple #23
0
 def setUpClass(cls):
     config = {"server_keys": test_keys[0]["kid"]}
     with open("examples/client_enc.key") as f:
         data = f.read()
         cls.client_keys = json_decode(data)
     cls.kk = KEMKeysStore(config)
     cls.kk.store = SqliteStore({"dburi": "kemtests.db"})
     _store_keys(cls.kk.store, KEY_USAGE_SIG, test_keys)
     _store_keys(cls.kk.store, KEY_USAGE_ENC, test_keys)
     _store_keys(cls.kk.store, KEY_USAGE_SIG, cls.client_keys)
     _store_keys(cls.kk.store, KEY_USAGE_ENC, cls.client_keys)
Exemple #24
0
    def test_create_symKeys(self):
        keylist = SymmetricKeys['keys']
        for key in keylist:
            jwkey = jwk.JWK(**key)
            jwkey.get_op_key('sign')
            jwkey.get_op_key('verify')
            e = jwkey.export()
            self.assertEqual(json_decode(e), key)

        jwk.JWK(**Useofx5c)
        jwk.JWK(**RSAPrivateKey)
Exemple #25
0
 def setUpClass(cls):
     config = {'server_keys': test_keys[0]['kid']}
     with open('examples/client_enc.key') as f:
         data = f.read()
         cls.client_keys = json_decode(data)
     cls.kk = KEMKeysStore(config)
     cls.kk.store = SqliteStore({'dburi': 'kemtests.db'})
     _store_keys(cls.kk.store, KEY_USAGE_SIG, test_keys)
     _store_keys(cls.kk.store, KEY_USAGE_ENC, test_keys)
     _store_keys(cls.kk.store, KEY_USAGE_SIG, cls.client_keys)
     _store_keys(cls.kk.store, KEY_USAGE_ENC, cls.client_keys)
Exemple #26
0
 def _decode_key(self, key):
     if key is None:
         return None
     elif isinstance(key, JWK):
         return key
     elif isinstance(key, dict):
         return JWK(**key)
     elif isinstance(key, str):
         return JWK(**(json_decode(key)))
     else:
         raise TypeError("Invalid key type")
Exemple #27
0
    def add_recipient(self, key, header=None):
        """Encrypt the plaintext with the given key.

        :param key: A JWK key or password of appropriate type for the 'alg'
         provided in the JOSE Headers.
        :param header: A JSON string representing the per-recipient header.

        :raises ValueError: if the plaintext is missing or not of type bytes.
        :raises ValueError: if the compression type is unknown.
        :raises InvalidJWAAlgorithm: if the 'alg' provided in the JOSE
         headers is missing or unknown, or otherwise not implemented.
        """
        if self.plaintext is None:
            raise ValueError('Missing plaintext')
        if not isinstance(self.plaintext, bytes):
            raise ValueError("Plaintext must be 'bytes'")

        jh = self._get_jose_header(header)
        alg, enc = self._get_alg_enc_from_headers(jh)

        rec = dict()
        if header:
            rec['header'] = header

        wrapped = alg.wrap(key, enc.key_size, self.cek, jh)
        self.cek = wrapped['cek']

        if 'ek' in wrapped:
            rec['encrypted_key'] = wrapped['ek']

        if 'header' in wrapped:
            h = json_decode(rec.get('header', '{}'))
            nh = self._merge_headers(h, wrapped['header'])
            rec['header'] = json_encode(nh)

        if 'ciphertext' not in self.objects:
            self._encrypt(alg, enc, jh)

        if 'recipients' in self.objects:
            self.objects['recipients'].append(rec)
        elif 'encrypted_key' in self.objects or 'header' in self.objects:
            self.objects['recipients'] = list()
            n = dict()
            if 'encrypted_key' in self.objects:
                n['encrypted_key'] = self.objects['encrypted_key']
                del self.objects['encrypted_key']
            if 'header' in self.objects:
                n['header'] = self.objects['header']
                del self.objects['header']
            self.objects['recipients'].append(n)
            self.objects['recipients'].append(rec)
        else:
            self.objects.update(rec)
Exemple #28
0
 def test_4_7_signing(self):
     plaintext = base64url_decode(Payload_plaintext_b64_4)
     header = json_encode(JWS_Unprotected_Header_4_7_2)
     key = jwk.JWK(**Symmetric_Key_MAC_3_5)
     S = jws.JWS(payload=plaintext)
     S.add_signature(key, None, None, header)
     sig = S.serialize()
     S.deserialize(sig, key)
     self.assertEqual(json_decode(sig), JWS_flattened_4_7_3)
     # Just deserialize each example form
     S.deserialize(json_encode(JWS_general_4_7_3), key)
     S.deserialize(json_encode(JWS_flattened_4_7_3), key)
Exemple #29
0
 def jose_header(self):
     obj = self.objects
     if 'signature' in obj:
         jh = dict()
         if 'protected' in obj:
             p = json_decode(obj['protected'])
             jh = self._merge_headers(jh, p)
         jh = self._merge_headers(jh, obj.get('header', dict()))
         return jh
     elif 'signatures' in self.objects:
         jhl = list()
         for o in obj['signatures']:
             jh = dict()
             if 'protected' in obj:
                 p = json_decode(o['protected'])
                 jh = self._merge_headers(jh, p)
             jh = self._merge_headers(jh, o.get('header', dict()))
             jhl.append(jh)
         return jhl
     else:
         raise InvalidJWSOperation("JOSE Header(s) not available")
 def f(claims, alg, lifetime=None, expires=None, not_before=None):
     """ generate token using node-jsjws """
     now = datetime.utcnow()
     return spawn(
         "fixtures.generate({now}, {header}, {claims}, {expires}, {not_before}, {key})".format(
             now=timegm(now.utctimetuple()),
             header=json_encode({'alg': alg}),
             claims=json_encode(claims),
             expires=timegm(((now + lifetime) if lifetime else expires).utctimetuple()),
             not_before=timegm((not_before or now).utctimetuple()),
             key=json_encode(base64url_decode(json_decode(key.export())['k']) if key.is_symmetric else key.export_to_pem(True, None))),
         False)
    def __get_keys(self, ca_host, cacerts_file, cacerts_pwd, data):
        # Fecth all needed certs one by one, then combine them in a single
        # p12 file

        prefix = data['prefix']
        certlist = data['list']

        cli = self.__CustodiaClient(server=ca_host)

        # Temporary nssdb
        tmpnssdir = tempfile.mkdtemp(dir=paths.TMP)
        try:
            # Temporary nssdb password
            nsspwfile = os.path.join(tmpnssdir, 'nsspwfile')
            with open(nsspwfile, 'w+') as f:
                f.write(b64encode(os.urandom(16)))
                f.flush()

            # Cert file password
            crtpwfile = os.path.join(tmpnssdir, 'crtpwfile')
            with open(crtpwfile, 'w+') as f:
                f.write(cacerts_pwd)
                f.flush()

            for nickname in certlist:
                value = cli.fetch_key(os.path.join(prefix, nickname), False)
                v = json_decode(value)
                pk12pwfile = os.path.join(tmpnssdir, 'pk12pwfile')
                with open(pk12pwfile, 'w+') as f:
                    f.write(v['export password'])
                pk12file = os.path.join(tmpnssdir, 'pk12file')
                with open(pk12file, 'w+') as f:
                    f.write(b64decode(v['pkcs12 data']))
                ipautil.run([
                    paths.PK12UTIL, '-d', tmpnssdir, '-k', nsspwfile, '-n',
                    nickname, '-i', pk12file, '-w', pk12pwfile
                ])

            # Add CA certificates
            tmpdb = CertDB(self.realm, nssdir=tmpnssdir)
            self.suffix = ipautil.realm_to_suffix(self.realm)
            self.import_ca_certs(tmpdb, True)

            # Now that we gathered all certs, re-export
            ipautil.run([
                paths.PKCS12EXPORT, '-d', tmpnssdir, '-p', nsspwfile, '-w',
                crtpwfile, '-o', cacerts_file
            ])

        finally:
            shutil.rmtree(tmpnssdir)
Exemple #32
0
 def test_2_KEMClient(self):
     server_keys = [JWK(**test_keys[kem.KEY_USAGE_SIG]), None]
     client_keys = [
         JWK(**self.client_keys[kem.KEY_USAGE_SIG]),
         JWK(**self.client_keys[kem.KEY_USAGE_ENC])
     ]
     cli = kem.KEMClient(server_keys, client_keys)
     kh = kem.KEMHandler({'KEMKeysStore': self.kk})
     req = cli.make_request("key name")
     kh.parse(req, "key name")
     msg = kh.reply('key value')
     self.assertEqual(msg, json_decode(json_encode(msg)))
     rep = cli.parse_reply("key name", msg['value'])
     self.assertEqual(rep, 'key value')
Exemple #33
0
def spawn(cmd, parse_json):
    """ run node command """
    #pylint: disable=E1101
    with lock:
        p = Popen(["node", "-e", "fixtures=require('./test/fixtures');" + cmd],
                  stdout=PIPE,
                  stderr=PIPE)
        (stdout, stderr) = p.communicate()
    stdout = stdout.decode('utf-8')
    stderr = stderr.decode('utf-8')
    if p.returncode == 0:
        return json_decode(stdout) if parse_json else stdout
    raise Exception(stderr if stderr else (
        'exited with {}'.format(p.returncode)))
Exemple #34
0
def sign(client_id, payload, compact=True):
    key = jwk.JWK.from_json(open(os.environ["KEY_FILE"], 'rb').read())
    public_key = jwk.JWK()
    public_key.import_key(**json_decode(key.export_public()))
    jwstoken = jws.JWS(payload)
    jwstoken.add_signature(
        key, None,
        json_encode({
            "alg": "RS512",
            "cid": client_id,
            "kid": public_key.thumbprint()
        }), None)
    signed_payload = jwstoken.serialize(compact)
    return signed_payload
 def test_4_6_signing(self):
     plaintext = base64url_decode(Payload_plaintext_b64_4)
     protected = \
         base64url_decode(JWS_Protected_Header_4_6_2).decode('utf-8')
     header = json_encode(JWS_Unprotected_Header_4_6_2)
     key = jwk.JWK(**Symmetric_Key_MAC_3_5)
     S = jws.JWS(payload=plaintext)
     S.add_signature(key, None, protected, header)
     sig = S.serialize()
     S.deserialize(sig, key)
     self.assertEqual(json_decode(sig), JWS_flattened_4_6_3)
     # Just deserialize each example form
     S.deserialize(json_encode(JWS_general_4_6_3), key)
     S.deserialize(json_encode(JWS_flattened_4_6_3), key)
Exemple #36
0
    def __get_keys(self, ca_host, cacerts_file, cacerts_pwd, data):
        # Fecth all needed certs one by one, then combine them in a single
        # p12 file

        prefix = data['prefix']
        certlist = data['list']

        # Before we attempt to fetch keys from this host, make sure our public
        # keys have been replicated there.
        self.__wait_keys(ca_host)

        cli = self.__CustodiaClient(server=ca_host)

        # Temporary nssdb
        tmpnssdir = tempfile.mkdtemp(dir=paths.TMP)
        tmpdb = NSSDatabase(tmpnssdir)
        tmpdb.create_db()
        try:
            # Cert file password
            crtpwfile = os.path.join(tmpnssdir, 'crtpwfile')
            with open(crtpwfile, 'w+') as f:
                f.write(cacerts_pwd)
                f.flush()

            for nickname in certlist:
                value = cli.fetch_key(os.path.join(prefix, nickname), False)
                v = json_decode(value)
                pk12pwfile = os.path.join(tmpnssdir, 'pk12pwfile')
                with open(pk12pwfile, 'w+') as f:
                    f.write(v['export password'])
                pk12file = os.path.join(tmpnssdir, 'pk12file')
                with open(pk12file, 'w+') as f:
                    f.write(b64decode(v['pkcs12 data']))
                ipautil.run([
                    paths.PK12UTIL, '-d', tmpdb.secdir, '-k', tmpdb.pwd_file,
                    '-n', nickname, '-i', pk12file, '-w', pk12pwfile
                ])

            # Add CA certificates
            self.suffix = ipautil.realm_to_suffix(self.realm)
            self.import_ca_certs(tmpdb, True)

            # Now that we gathered all certs, re-export
            ipautil.run([
                paths.PKCS12EXPORT, '-d', tmpdb.secdir, '-p', tmpdb.pwd_file,
                '-w', crtpwfile, '-o', cacerts_file
            ])

        finally:
            shutil.rmtree(tmpnssdir)
Exemple #37
0
    def parse(self, msg, name):
        """Parses the message.

        We check that the message is properly formatted.

        :param msg: a json-encoded value containing a JWS or JWE+JWS token

        :raises InvalidMessage: if the message cannot be parsed or validated

        :returns: A verified payload
        """

        try:
            jtok = JWT(jwt=msg)
        except Exception as e:
            raise InvalidMessage('Failed to parse message: %s' % str(e))

        try:
            token = jtok.token
            if isinstance(token, JWE):
                token.decrypt(self.kkstore.server_keys[KEY_USAGE_ENC])
                # If an encrypted payload is received then there must be
                # a nested signed payload to verify the provenance.
                payload = token.payload.decode('utf-8')
                token = JWS()
                token.deserialize(payload)
            elif isinstance(token, JWS):
                pass
            else:
                raise TypeError("Invalid Token type: %s" % type(jtok))

            # Retrieve client keys for later use
            self.client_keys = [
                JWK(**self._get_key(token.jose_header, KEY_USAGE_SIG)),
                JWK(**self._get_key(token.jose_header, KEY_USAGE_ENC))]

            # verify token and get payload
            token.verify(self.client_keys[KEY_USAGE_SIG])
            claims = json_decode(token.payload)
        except Exception as e:
            raise InvalidMessage('Failed to validate message: %s' % str(e))

        check_kem_claims(claims, name)
        self.name = name
        self.payload = claims.get('value')

        return {'type': 'kem',
                'value': {'kid': self.client_keys[KEY_USAGE_ENC].key_id,
                          'claims': claims}}
Exemple #38
0
    def export(self, private_keys=True):
        """Exports a RFC 7517 keyset using the standard JSON format

        :param private_key(bool): Whether to export private keys.
                                  Defaults to True.
        """
        exp_dict = dict()
        for k, v in iteritems(self):
            if k == 'keys':
                keys = list()
                for jwk in v:
                    keys.append(json_decode(jwk.export(private_keys)))
                v = keys
            exp_dict[k] = v
        return json_encode(exp_dict)
def unwrap_response(body_data, arguments):
    """Unwrap the response payload

    DCS signed, encrypted, and then signed the plaintext response.

    See https://dcs-pilot-docs.cloudapps.digital/message-structure for the documentation.
    """
    server_signing_certificate = load_pem(
        arguments["--server-signing-certificate"])
    client_encryption_key = load_pem(arguments["--client-encryption-key"])

    encrypted = unwrap_signature(body_data, server_signing_certificate)
    inner_signed = decrypt(encrypted, client_encryption_key)
    return json_decode(
        unwrap_signature(inner_signed, server_signing_certificate))
Exemple #40
0
 def f(claims, alg, lifetime=None, expires=None, not_before=None):
     """ generate token using jose """
     now = datetime.utcnow()
     return spawn(
         "fixtures.generate({now}, {header}, {claims}, {expires}, {not_before}, {key})"
         .format(
             now=timegm(now.utctimetuple()),
             header=json_encode({'alg': alg}),
             claims=json_encode(claims),
             expires=timegm(
                 ((now +
                   lifetime) if lifetime else expires).utctimetuple()),
             not_before=timegm((not_before or now).utctimetuple()),
             key=json_encode(
                 base64url_decode(json_decode(key.export())['k']) if key.
                 is_symmetric else key.export_to_pem(True, None))), False)
Exemple #41
0
 def _deserialize_b64(self, o, protected):
     if protected is None:
         b64n = None
     else:
         p = json_decode(protected)
         b64n = p.get('b64')
         if b64n is not None:
             if not isinstance(b64n, bool):
                 raise InvalidJWSObject('b64 header must be boolean')
     b64 = o.get('b64')
     if b64 == b64n:
         return
     elif b64 is None:
         o['b64'] = b64n
     else:
         raise InvalidJWSObject('conflicting b64 values')
Exemple #42
0
    def __init__(self, config):

        super(EncryptedStore, self).__init__(config)

        if 'master_key' not in config:
            raise ValueError('Missing "master_key" for Encrypted Store')

        with open(config['master_key']) as f:
            data = f.read()
            key = json_decode(data)
            self.mkey = jwk.JWK(**key)

        if 'master_enctype' in config:
            self.enc = config['master_enctype']
        else:
            self.enc = 'A256CBC_HS512'
Exemple #43
0
 def test_3_KEMClient(self):
     server_keys = [
         JWK(**test_keys[KEY_USAGE_SIG]),
         JWK(**test_keys[KEY_USAGE_ENC])
     ]
     client_keys = [
         JWK(**self.client_keys[KEY_USAGE_SIG]),
         JWK(**self.client_keys[KEY_USAGE_ENC])
     ]
     cli = KEMClient(server_keys, client_keys)
     kem = KEMHandler({'KEMKeysStore': self.kk})
     req = cli.make_request("key name", encalg=('RSA1_5', 'A256CBC-HS512'))
     kem.parse(req, "key name")
     msg = json_decode(kem.reply('key value'))
     rep = cli.parse_reply("key name", msg['value'])
     self.assertEqual(rep, 'key value')
Exemple #44
0
    def __init__(self, config, section):
        super(EncryptedOverlay, self).__init__(config, section)
        self.store_name = self.backing_store
        self.store = None

        if (not os.path.isfile(self.master_key) and self.autogen_master_key):
            # XXX https://github.com/latchset/jwcrypto/issues/50
            size = self.key_sizes.get(self.master_enctype, 512)
            key = JWK(generate='oct', size=size)
            with open(self.master_key, 'w') as f:
                os.fchmod(f.fileno(), 0o600)
                f.write(key.export())

        with open(self.master_key) as f:
            data = f.read()
            key = json_decode(data)
            self.mkey = JWK(**key)
Exemple #45
0
    def __init__(self, config):
        super(EncryptedOverlay, self).__init__(config)

        if 'backing_store' not in config:
            raise ValueError('Missing "backing_store" for Encrypted Store')
        self.store_name = config['backing_store']
        self.store = None

        if 'master_key' not in config:
            raise ValueError('Missing "master_key" for Encrypted Store')

        with open(config['master_key']) as f:
            data = f.read()
            key = json_decode(data)
            self.mkey = JWK(**key)

        self.enc = config.get('master_enctype', 'A256CBC_HS512')
Exemple #46
0
	def getAuthTokenFromJWT(JWEtoken):
		# Get the key
		key = Config.JWT_KEY

		# Decrypt token
		encryptedSignedToken = jwt.JWT(jwt=JWEtoken).token
		encryptedSignedToken.decrypt(key)
		raw_payload = encryptedSignedToken.payload
		JWStoken = raw_payload.decode("utf-8")

		# extract payload from signed token
		signedToken = jwt.JWT(jwt=JWStoken).token
		signedToken.verify(key)
		payload = json_decode(signedToken.payload)
		authToken = payload['authToken']

		return authToken
Exemple #47
0
    def setUpClass(cls):
        cls.parser = configparser.ConfigParser(
            interpolation=configparser.ExtendedInterpolation())
        cls.parser.read_string(CONFIG)

        config = {'server_keys': test_keys[0]['kid']}
        with open('examples/client_enc.key') as f:
            data = f.read()
            cls.client_keys = json_decode(data)

        cls.kk = kem.KEMKeysStore(config)
        cls.kk.store = SqliteStore(cls.parser, 'store:sqlite')

        _store_keys(cls.kk.store, kem.KEY_USAGE_SIG, test_keys)
        _store_keys(cls.kk.store, kem.KEY_USAGE_ENC, test_keys)
        _store_keys(cls.kk.store, kem.KEY_USAGE_SIG, cls.client_keys)
        _store_keys(cls.kk.store, kem.KEY_USAGE_ENC, cls.client_keys)
Exemple #48
0
    def _get_keys(self, ca_host, cacerts_file, cacerts_pwd, data):
        # Fetch all needed certs one by one, then combine them in a single
        # PKCS12 file
        prefix = data['prefix']
        certlist = data['list']
        cli = self._get_custodia_client(server=ca_host)

        with NSSDatabase(None) as tmpdb:
            tmpdb.create_db()
            # Cert file password
            crtpwfile = os.path.join(tmpdb.secdir, 'crtpwfile')
            with open(crtpwfile, 'w+') as f:
                f.write(cacerts_pwd)

            for nickname in certlist:
                value = cli.fetch_key(os.path.join(prefix, nickname), False)
                v = json_decode(value)
                pk12pwfile = os.path.join(tmpdb.secdir, 'pk12pwfile')
                with open(pk12pwfile, 'w+') as f:
                    f.write(v['export password'])
                pk12file = os.path.join(tmpdb.secdir, 'pk12file')
                with open(pk12file, 'wb') as f:
                    f.write(b64decode(v['pkcs12 data']))
                tmpdb.run_pk12util([
                    '-k', tmpdb.pwd_file, '-n', nickname, '-i', pk12file, '-w',
                    pk12pwfile
                ])

            # Add CA certificates, but don't import the main CA cert. It's
            # already present as 'caSigningCert cert-pki-ca'. With SQL db
            # format, a second import would rename the certificate. See
            # https://pagure.io/freeipa/issue/7498 for more details.
            conn = api.Backend.ldap2
            suffix = ipautil.realm_to_suffix(self.realm)
            ca_certs = get_ca_certs_nss(conn, suffix, self.realm, True)
            for cert, nickname, trust_flags in ca_certs:
                if nickname == get_ca_nickname(self.realm):
                    continue
                tmpdb.add_cert(cert, nickname, trust_flags)

            # Now that we gathered all certs, re-export
            ipautil.run([
                paths.PKCS12EXPORT, '-d', tmpdb.secdir, '-p', tmpdb.pwd_file,
                '-w', crtpwfile, '-o', cacerts_file
            ])
Exemple #49
0
 def import_key(self, value):
     v = json_decode(value)
     tdir = tempfile.mkdtemp(dir=paths.TMP)
     try:
         nsspwfile = os.path.join(tdir, 'nsspwfile')
         with open(nsspwfile, 'w+') as f:
             f.write(self.nssdb_password)
         pk12pwfile = os.path.join(tdir, 'pk12pwfile')
         with open(pk12pwfile, 'w+') as f:
             f.write(v['export password'])
         pk12file = os.path.join(tdir, 'pk12file')
         with open(pk12file, 'w+') as f:
             f.write(b64decode(v['pkcs12 data']))
         ipautil.run([
             paths.PK12UTIL, "-d", self.nssdb_path, "-i", pk12file, "-n",
             self.nickname, "-k", nsspwfile, "-w", pk12pwfile
         ])
     finally:
         shutil.rmtree(tdir)
Exemple #50
0
def decrypt():
    public_file = (open(str(settings.ROOT) + "/public.pub", "r"))
    private_file = (open(str(settings.ROOT) + "/private.pem", "r"))
    public_key = jwk.JWK.from_pem(public_file.read().encode())
    private_key = jwk.JWK.from_pem(private_file.read().encode())
    enc = request.args.get("k")

    e = jwt.JWT(key=private_key, jwt=enc)
    s = jwt.JWT()
    s.leeway = 999999
    s.deserialize(jwt=e.claims, key=public_key)

    # it can be validated from keyset
    #ks = jwk.JWKSet()
    #ks.import_keyset(json_encode(index()))
    #s.deserialize(jwt=e.claims, key=ks.get_key(json_decode(e.header)["kid"]))


    return json_decode(s.claims)
Exemple #51
0
    def import_keyset(self, keyset):
        """Imports a RFC 7517 key set using the standard JSON format.

        :param keyset: The RFC 7517 representation of a JOSE key set.
        """
        try:
            jwkset = json_decode(keyset)
        except Exception:  # pylint: disable=broad-except
            raise InvalidJWKValue()

        if 'keys' not in jwkset:
            raise InvalidJWKValue()

        for k, v in iteritems(jwkset):
            if k == 'keys':
                for jwk in v:
                    self['keys'].add(JWK(**jwk))
            else:
                self[k] = v
Exemple #52
0
    def wrap(self, key, bitsize, cek, headers):
        dk_size = self.keysize
        if self.keysize is None:
            if cek is not None:
                raise jwe.InvalidJWEOperation('ECDH-ES cannot use an existing CEK')
            alg = headers['enc']
            dk_size = bitsize
        else:
            alg = headers['alg']

        dk = self._derive(key, key, alg, dk_size, headers)
        if self.keysize is None:
            ret = {'cek': dk}
        else:
            aeskw = self.aeskwmap[self.keysize]()
            kek = jwk.JWK(kty="oct", use="enc", k=base64url_encode(dk))
            ret = aeskw.wrap(kek, bitsize, cek, headers)

        ret['header'] = {'epk': json_decode(key.export_public())}
        return ret
    def _get_keys(self, cacerts_file, cacerts_pwd, data):
        # Fetch all needed certs one by one, then combine them in a single
        # PKCS12 file
        prefix = data['prefix']
        certlist = data['list']
        cli = self._get_custodia_client()

        with NSSDatabase(None) as tmpdb:
            tmpdb.create_db()
            # Cert file password
            crtpwfile = os.path.join(tmpdb.secdir, 'crtpwfile')
            with open(crtpwfile, 'w+') as f:
                f.write(cacerts_pwd)

            for nickname in certlist:
                value = cli.fetch_key(os.path.join(prefix, nickname), False)
                v = json_decode(value)
                pk12pwfile = os.path.join(tmpdb.secdir, 'pk12pwfile')
                with open(pk12pwfile, 'w+') as f:
                    f.write(v['export password'])
                pk12file = os.path.join(tmpdb.secdir, 'pk12file')
                with open(pk12file, 'wb') as f:
                    f.write(b64decode(v['pkcs12 data']))
                tmpdb.run_pk12util([
                    '-k', tmpdb.pwd_file,
                    '-n', nickname,
                    '-i', pk12file,
                    '-w', pk12pwfile
                ])

            # Add CA certificates
            self.export_ca_certs_nssdb(tmpdb, True)

            # Now that we gathered all certs, re-export
            ipautil.run([
                paths.PKCS12EXPORT,
                '-d', tmpdb.secdir,
                '-p', tmpdb.pwd_file,
                '-w', crtpwfile,
                '-o', cacerts_file
            ])
Exemple #54
0
 def import_key(self, value):
     v = json_decode(value)
     tdir = tempfile.mkdtemp(dir=paths.TMP)
     try:
         pk12pwfile = os.path.join(tdir, 'pk12pwfile')
         with open(pk12pwfile, 'w') as f:
             f.write(v['export password'])
         pk12file = os.path.join(tdir, 'pk12file')
         with open(pk12file, 'wb') as f:
             f.write(b64decode(v['pkcs12 data']))
         nssdb = NSSDatabase(self.nssdb_path)
         nssdb.run_pk12util([
             "-i",
             pk12file,
             "-n",
             self.nickname,
             "-k",
             self.nssdb_pwdfile,
             "-w",
             pk12pwfile,
         ])
     finally:
         shutil.rmtree(tdir)
Exemple #55
0
    def wrap(self, key, bitsize, cek, headers):
        self._check_key(key)
        if self.keysize is None:
            if cek is not None:
                raise InvalidJWEOperation('ECDH-ES cannot use an existing CEK')
            alg = headers['enc']
        else:
            bitsize = self.keysize
            alg = headers['alg']

        epk = JWK.generate(kty=key.key_type, crv=key.key_curve)
        dk = self._derive(epk.get_op_key('unwrapKey'),
                          key.get_op_key('wrapKey'), alg, bitsize, headers)

        if self.keysize is None:
            ret = {'cek': dk}
        else:
            aeskw = self.aeskwmap[bitsize]()
            kek = JWK(kty="oct", use="enc", k=base64url_encode(dk))
            ret = aeskw.wrap(kek, bitsize, cek, headers)

        ret['header'] = {'epk': json_decode(epk.export_public())}
        return ret
Exemple #56
0
    def _derive(self, key, _, alg, bitsize, headers):
        otherinfo = struct.pack('>I', len(alg))
        otherinfo += bytes(alg.encode('utf8'))
        apu = base64url_decode(headers['apu']) if 'apu' in headers else b''
        otherinfo += struct.pack('>I', len(apu))
        otherinfo += apu
        apv = base64url_decode(headers['apv']) if 'apv' in headers else b''
        otherinfo += struct.pack('>I', len(apv))
        otherinfo += apv
        otherinfo += struct.pack('>I', bitsize)
        key = json_decode(key.export(True))
        assert key['kty'] == 'EC'
        assert key['crv'] == 'P-256'
        ggx = int.from_bytes(base64url_decode(key['x']), 'big')
        ggy = int.from_bytes(base64url_decode(key['y']), 'big')
        d = int.from_bytes(base64url_decode(key['d']), 'big')
        shared_key = (d * AffinePoint(secp256r1, ggx, ggy)).x.to_bytes(32, 'big')

        ckdf = jwa.ConcatKDFHash(algorithm=jwa.hashes.SHA256(),
                                 length=jwa._inbytes(bitsize),
                                 otherinfo=otherinfo,
                                 backend=self.backend)
        return ckdf.derive(shared_key)
Exemple #57
0
    def deserialize(self, raw_jwe, key=None):
        """Deserialize a JWE token.

        NOTE: Destroys any current status and tries to import the raw
        JWE provided.

        :param raw_jwe: a 'raw' JWE token (JSON Encoded or Compact
         notation) string.
        :param key: A (:class:`jwcrypto.jwk.JWK`) decryption key (optional).
         If a key is provided a idecryption step will be attempted after
         the object is successfully deserialized.

        :raises InvalidJWEData: if the raw object is an invaid JWE token.
        :raises InvalidJWEOperation: if the decryption fails.
        """

        self.objects = dict()
        self.plaintext = None
        self.cek = None

        o = dict()
        try:
            try:
                djwe = json_decode(raw_jwe)
                o['iv'] = base64url_decode(str(djwe['iv']))
                o['ciphertext'] = base64url_decode(str(djwe['ciphertext']))
                o['tag'] = base64url_decode(str(djwe['tag']))
                if 'protected' in djwe:
                    p = base64url_decode(str(djwe['protected']))
                    o['protected'] = p.decode('utf-8')
                if 'unprotected' in djwe:
                    o['unprotected'] = json_encode(djwe['unprotected'])
                if 'aad' in djwe:
                    o['aad'] = base64url_decode(str(djwe['aad']))
                if 'recipients' in djwe:
                    o['recipients'] = list()
                    for rec in djwe['recipients']:
                        e = dict()
                        if 'encrypted_key' in rec:
                            e['encrypted_key'] = \
                                base64url_decode(str(rec['encrypted_key']))
                        if 'header' in rec:
                            e['header'] = json_encode(rec['header'])
                        o['recipients'].append(e)
                else:
                    if 'encrypted_key' in djwe:
                        o['encrypted_key'] = \
                            base64url_decode(str(djwe['encrypted_key']))
                    if 'header' in djwe:
                        o['header'] = json_encode(djwe['header'])

            except ValueError:
                c = raw_jwe.split('.')
                if len(c) != 5:
                    raise InvalidJWEData()
                p = base64url_decode(str(c[0]))
                o['protected'] = p.decode('utf-8')
                ekey = base64url_decode(str(c[1]))
                if ekey != '':
                    o['encrypted_key'] = base64url_decode(str(c[1]))
                o['iv'] = base64url_decode(str(c[2]))
                o['ciphertext'] = base64url_decode(str(c[3]))
                o['tag'] = base64url_decode(str(c[4]))

            self.objects = o

        except Exception as e:  # pylint: disable=broad-except
            raise InvalidJWEData('Invalid format', repr(e))

        if key:
            self.decrypt(key)
Exemple #58
0
def generate_jwt(claims,
                 priv_key=None,
                 algorithm='PS512',
                 lifetime=None,
                 expires=None,
                 not_before=None,
                 jti_size=16,
                 other_headers=None):
    """
    Generate a JSON Web Token.

    :param claims: The claims you want included in the signature.
    :type claims: dict

    :param priv_key: The private key to be used to sign the token. Note: if you pass ``None`` then the token will be returned with an empty cryptographic signature and :obj:`algorithm` will be forced to the value ``none``.
    :type priv_key: `jwcrypto.jwk.JWK <https://jwcrypto.readthedocs.io/en/latest/jwk.html>`_

    :param algorithm: The algorithm to use for generating the signature. ``RS256``, ``RS384``, ``RS512``, ``PS256``, ``PS384``, ``PS512``, ``ES256``, ``ES384``, ``ES512``, ``HS256``, ``HS384``, ``HS512`` and ``none`` are supported.
    :type algorithm: str

    :param lifetime: How long the token is valid for.
    :type lifetime: datetime.timedelta

    :param expires: When the token expires (if :obj:`lifetime` isn't specified)
    :type expires: datetime.datetime

    :param not_before: When the token is valid from. Defaults to current time (if ``None`` is passed).
    :type not_before: datetime.datetime

    :param jti_size: Size in bytes of the unique token ID to put into the token (can be used to detect replay attacks). Defaults to 16 (128 bits). Specify 0 or ``None`` to omit the JTI from the token.
    :type jti_size: int

    :param other_headers: Any headers other than "typ" and "alg" may be specified, they will be included in the header.
    :type other_headers: dict

    :rtype: unicode
    :returns: The JSON Web Token. Note this includes a header, the claims and a cryptographic signature. The following extra claims are added, per the `JWT spec <http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html>`_:

    - **exp** (*IntDate*) -- The UTC expiry date and time of the token, in number of seconds from 1970-01-01T0:0:0Z UTC.
    - **iat** (*IntDate*) -- The UTC date and time at which the token was generated.
    - **nbf** (*IntDate*) -- The UTC valid-from date and time of the token.
    - **jti** (*str*) -- A unique identifier for the token.

    :raises:
        ValueError: If other_headers contains either the "typ" or "alg" header
    """
    header = {'typ': 'JWT', 'alg': algorithm if priv_key else 'none'}

    if other_headers is not None:
        redefined_keys = set(header.keys()) & set(other_headers.keys())
        if redefined_keys:
            raise ValueError(
                'other_headers re-specified the headers: {}'.format(
                    ', '.join(redefined_keys)))
        header.update(other_headers)

    claims = dict(claims)

    now = datetime.utcnow()

    if jti_size:
        claims['jti'] = base64url_encode(urandom(jti_size))

    claims['nbf'] = timegm((not_before or now).utctimetuple())
    claims['iat'] = timegm(now.utctimetuple())

    if lifetime:
        claims['exp'] = timegm((now + lifetime).utctimetuple())
    elif expires:
        claims['exp'] = timegm(expires.utctimetuple())

    if header['alg'] == 'none':
        signature = ''
    else:
        token = JWS(json_encode(claims))
        token.allowed_algs = [header['alg']]
        token.add_signature(priv_key, protected=header)
        signature = json_decode(token.serialize())['signature']

    return u'%s.%s.%s' % (base64url_encode(
        json_encode(header)), base64url_encode(json_encode(claims)), signature)
Exemple #59
0
    def serialize(self, compact=False):
        """Serializes the object into a JWE token.

        :param compact(boolean): if True generates the compact
         representation, otherwise generates a standard JSON format.

        :raises InvalidJWEOperation: if the object cannot serialized
         with the compact representation and `compact` is True.
        :raises InvalidJWEOperation: if no recipients have been added
         to the object.
        """

        if 'ciphertext' not in self.objects:
            raise InvalidJWEOperation("No available ciphertext")

        if compact:
            for invalid in 'aad', 'unprotected':
                if invalid in self.objects:
                    raise InvalidJWEOperation(
                        "Can't use compact encoding when the '%s' parameter"
                        "is set" % invalid)
            if 'protected' not in self.objects:
                raise InvalidJWEOperation(
                    "Can't use compat encoding without protected headers")
            else:
                ph = json_decode(self.objects['protected'])
                for required in 'alg', 'enc':
                    if required not in ph:
                        raise InvalidJWEOperation(
                            "Can't use compat encoding, '%s' must be in the "
                            "protected header" % required)
            if 'recipients' in self.objects:
                if len(self.objects['recipients']) != 1:
                    raise InvalidJWEOperation("Invalid number of recipients")
                rec = self.objects['recipients'][0]
            else:
                rec = self.objects
            if 'header' in rec:
                # The AESGCMKW algorithm generates data (iv, tag) we put in the
                # per-recipient unpotected header by default. Move it to the
                # protected header and re-encrypt the payload, as the protected
                # header is used as additional authenticated data.
                h = json_decode(rec['header'])
                ph = json_decode(self.objects['protected'])
                nph = self._merge_headers(h, ph)
                self.objects['protected'] = json_encode(nph)
                jh = self._get_jose_header()
                alg, enc = self._get_alg_enc_from_headers(jh)
                self._encrypt(alg, enc, jh)
                del rec['header']

            return '.'.join([base64url_encode(self.objects['protected']),
                             base64url_encode(rec.get('encrypted_key', '')),
                             base64url_encode(self.objects['iv']),
                             base64url_encode(self.objects['ciphertext']),
                             base64url_encode(self.objects['tag'])])
        else:
            obj = self.objects
            enc = {'ciphertext': base64url_encode(obj['ciphertext']),
                   'iv': base64url_encode(obj['iv']),
                   'tag': base64url_encode(self.objects['tag'])}
            if 'protected' in obj:
                enc['protected'] = base64url_encode(obj['protected'])
            if 'unprotected' in obj:
                enc['unprotected'] = json_decode(obj['unprotected'])
            if 'aad' in obj:
                enc['aad'] = base64url_encode(obj['aad'])
            if 'recipients' in obj:
                enc['recipients'] = list()
                for rec in obj['recipients']:
                    e = dict()
                    if 'encrypted_key' in rec:
                        e['encrypted_key'] = \
                            base64url_encode(rec['encrypted_key'])
                    if 'header' in rec:
                        e['header'] = json_decode(rec['header'])
                    enc['recipients'].append(e)
            else:
                if 'encrypted_key' in obj:
                    enc['encrypted_key'] = \
                        base64url_encode(obj['encrypted_key'])
                if 'header' in obj:
                    enc['header'] = json_decode(obj['header'])
            return json_encode(enc)
Exemple #60
0
def verify_cert_token(cert_token:str) -> dict:

    # In order to verify the signature of the JWT, we need first to get the public key that was used
    # The JWT is now in serialized format, so we need:
    # 1. Deserialize the JWT without verifying it (we do not yet have the public key)
    # 2. Get the 'kid' property from the header (the JOSE header of the JWT)
    # 3. The 'kid' has the format did#id where 'did' is the DID of the issuer and 'id' is the 
    #     identifier of the key in the DIDDocument associated to the DID
    # 4. Perform resolution of the DID of the issuer
    # 5. Get the public key specified inside the DIDDocument
    # 6. Verify the JWT using the public key associated to the DID
    # 7. Verify that the DID in the 'iss' field of the JWT payload is the same as the one that
    #     signed the JWT

    # 1. Deserialize the JWT without verifying it (we do not yet have the public key)
    cert_obj = jwt.JWT()
    cert_obj.deserialize(jwt=cert_token)
 
    # Get the protected header of the JWT
    header = cert_obj.token.jose_header

    # 2. Get the 'kid' property from the header (the JOSE header of the JWT)
    key_id = str(header["kid"])

    # 3. The 'kid' has the format did#id where 'did' is the DID of the issuer and 'id' is the 
    #     identifier of the key in the DIDDocument associated to the DID
    key_components = key_id.split("#")
    if len(key_components) != 2:
        print(f"KeyID in JOSE header invalid: {header}")
        return None

    # Get the DID component
    DID = key_components[0]

    # 4. Perform resolution of the DID of the issuer, and get the public key
    _DID, name, didDoc, active = tf.resolver.resolveDID(DID)
    if didDoc is None:
        print(f"No DIDDoc found for DID: {DID}")
        return None

    # 5. Get the public key specified inside the DIDDocument
    keys = didDoc["publicKey"]
    publicKeyJwk = None
    for key in keys:
        if key["id"] == key_id:
            publicKeyJwk = key["publicKeyJwk"]

    if publicKeyJwk is None:
        print(f"Key ID not found in DIDDoc: {key_id}")
        return None

    jwk_key = jwk.JWK(**publicKeyJwk)

    # 6. Verify the JWT using the public key associated to the DID
    cert_obj = jwt.JWT(
        jwt=cert_token,
        key=jwk_key,
        algs=["ES256K"]
    )

    # 7. Verify that the DID in the 'iss' field of the JWT payload is the same as the one that
    #     signed the JWT
    claims = json_decode(cert_obj.claims)
    if claims["iss"] != DID:
        print(f"Token issuer is not the same as specified in the header")
        return None

    return claims