def test_signer_protected_headers(): payload = "Please take a moment to register today" eck = ec.generate_private_key(ec.SECP256R1(), default_backend()) _key = ECKey().load_key(eck) keys = [_key] _jws = JWS(payload, alg="ES256") protected = dict(header1=u"header1 is protected", header2="header2 is protected too", a=1) _jwt = _jws.sign_compact(keys, protected=protected) exp_protected = protected.copy() exp_protected["alg"] = "ES256" enc_header, enc_payload, sig = _jwt.split(".") assert json.loads(b64d( enc_header.encode("utf-8")).decode("utf-8")) == exp_protected assert b64d(enc_payload.encode("utf-8")).decode("utf-8") == payload _pub_key = ECKey().load_key(eck.public_key()) _rj = JWS(alg="ES256") info = _rj.verify_compact(_jwt, [_pub_key]) assert info == payload # Protected by default protected["alg"] = "ES256" assert _rj.protected_headers() == protected
def test_get_token(self): """Get BoB auth token (good)""" response = self.env.get_auth_response(api='authentication') now = int(time.time()) self.assertEqual(response.status_code, 200) data = response.json() (header, payload, signature) = data['jwtCompact'].split('.') header_dict = json.loads(b64d(header.encode())) payload_dict = json.loads(b64d(payload.encode())) signature_dict = b64d(signature.encode()) # check for supported algorithms self.assertIn(header_dict['alg'], TOKEN_ALGS) # ensure some headers are not missing self.assertIsNotNone(header_dict.get('kid')) self.assertIsNotNone(payload_dict.get('iss')) self.assertIsNotNone(payload_dict.get('sub')) self.assertIsNotNone(payload_dict.get('bobAuthZ')) self.assertIsNotNone(payload_dict.get('exp')) # ensure iat/nbf/exp are reasonable (if provided) if 'iat' in payload_dict: self.assertTrue(now + TIMESKEW >= payload_dict['iat']) if 'nbf' in payload_dict: self.assertTrue(now + TIMESKEW >= payload_dict['nbf']) if 'exp' in payload_dict: self.assertTrue(now - TIMESKEW < payload_dict['exp'])
def modify_header(token, **kwargs): part = token.split('.') _txt = utils.b64d(as_bytes(part[0])) header = json.loads(as_unicode(_txt)) header.update(kwargs) part[0] = utils.b64e(as_bytes(json.dumps(header))) return b'.'.join([as_bytes(p) for p in part])
def command_sign(args: argparse.Namespace): """Create signed EHC""" private_key = read_cosekey(args.key, private=True) if args.kid: private_key.kid = b64d(args.kid.encode()) with open(args.input, "rt") as input_file: input_data = input_file.read() logger.info("Input JSON data: %d bytes", len(input_data)) eu_dgc_v1 = json.loads(input_data) cwt_bytes = sign( private_key=private_key, payload=eu_dgc_v1, issuer=args.issuer, ttl=args.ttl, sign1=args.sign1, ) logger.info("Raw signed CWT: %d bytes", len(cwt_bytes)) if args.output: with open(args.output, "wb") as output_file: output_file.write(cwt_bytes) else: logger.info("Output: %s", binascii.hexlify(cwt_bytes).decode()) if args.qrcode: save_qrcode(cwt_bytes, args.qrcode)
def command_verify(args: argparse.Namespace): """Verify signed EHC""" public_keys = [] if args.jwks: with open(args.jwks) as jwks_file: jwks = json.load(jwks_file) for jwk_dict in jwks.get("keys", []): key = cosekey_from_jwk_dict(jwk_dict, private=False) key.issuer = jwk_dict.get("issuer") public_keys.append(key) elif args.key: public_keys = [read_cosekey(args.key, private=False)] if args.kid: public_key.kid = b64d(args.kid.encode()) with open(args.input, "rb") as input_file: signed_data = input_file.read() res = verify(signed_data=signed_data, public_keys=public_keys) logger.info("Signatured issued by: %s", res.iss) logger.info( "Signature verified by: %s (%s)", b64e(res.kid).decode(), res.key.issuer if hasattr(res.key, "issuer") else None, ) logger.info("Signatured issued at: %s", res.iat) if res.expired: logger.warning("Signatured expired at: %s", res.exp) else: logger.info("Signatured expires at: %s", res.exp) if res.eu_dgc_v1 is None: logger.warning("No EU DCC version 1 found in payload") if args.output: with open(args.output, "wt") as output_file: json.dump(res.eu_dgc_v1, output_file, indent=4) else: logger.info("Verified payload: %s", json.dumps(res.eu_dgc_v1, indent=4))
def modify_json_message(token): part = [as_bytes(p) for p in token.split('.')] _txt = utils.b64d(part[1]) msg = json.loads(as_unicode(_txt)) for k, v in msg.items(): msg_copy = msg.copy() del msg_copy[k] for _k in modify_str(k): msg_copy[_k] = v part[1] = utils.b64e(as_bytes(json.dumps(msg_copy))) yield b'.'.join([as_bytes(p) for p in part]) if isinstance(v, str): for _v in modify_str(v): msg_copy[k] = _v part[1] = utils.b64e(as_bytes(json.dumps(msg_copy))) yield b'.'.join([as_bytes(p) for p in part]) elif isinstance(v, int): _v = v + 1 msg_copy[k] = _v part[1] = utils.b64e(as_bytes(json.dumps(msg_copy))) yield b'.'.join([as_bytes(p) for p in part])
async def process_csv(filename: str, server: str, speed: float = 1.0): """Process CSV realtime data""" mqtt = MQTTClient() ret = await mqtt.connect(server) logging.debug("MQTT connect to %s -> %s", server, ret) testdata_file = open(filename) header = testdata_file.readline() last_timestamp = None for line in testdata_file: (timestamp, topic, qos, message) = line.rstrip().split(",") topic = topic.strip() message = message.strip() payload = b64d(message) if last_timestamp is not None and speed != 0: delay = (float(timestamp) - float(last_timestamp)) / speed if delay > 0: logging.info("Sleeping for %f seconds", delay) time.sleep(delay) logging.info("Topic %s, Payload %s", topic, message) asyncio.get_event_loop().run_until_complete( send_realtime(server, [(topic, payload)])) last_timestamp = timestamp testdata_file.close()
def get_channel_contents(config: dict, name: str, contents: dict): """Publish channel contents on MQTT""" if name in config: channel_topic = config[name]["topic"] channel_format = config[name]["format"] if channel_format == "json": new_contents = {} for key, value in contents.items(): if key.startswith(FILE_PREFIX): key = key[len(FILE_PREFIX):] with open(value, "rb") as input_file: value = input_file.read() if key.startswith(BASE64_PREFIX): key = key[len(BASE64_PREFIX):] value = b64e(value) value = value.decode() new_contents[key] = value payload = json.dumps(new_contents).encode() elif channel_format == "nmea": payload = contents_to_nmea(contents).encode() elif channel_format == "bytes": if "base64" in contents: payload = b64d(contents["base64"]) elif "file" in contents: filename = contents["file"] with open(filename, "rb") as input_file: payload = input_file.read() elif "string" in contents: payload = contents["string"].encode() else: raise Exception("No binary contents found") else: raise Exception("Undefined format: {}".format(channel_format)) return (channel_topic, payload) else: raise Exception("Undefined channel: {}".format(name))
def modify_signature(token): part = [as_bytes(p) for p in token.split('.')] signature = utils.b64d(part[2]) for sig in modify_bytes(signature): part[2] = utils.b64e(sig) yield b'.'.join([as_bytes(p) for p in part])
def setup_auth(self, request, redirect_uri, cinfo, cookie, acr=None, **kwargs): """ :param request: The authorization/authentication request :param redirect_uri: :param cinfo: client info :param cookie: :param acr: Default ACR, if nothing else is specified :param kwargs: :return: """ res = self.pick_authn_method(request, redirect_uri, acr, **kwargs) authn = res["method"] authn_class_ref = res["acr"] try: _auth_info = kwargs.get("authn", "") if "upm_answer" in request and request["upm_answer"] == "true": _max_age = 0 else: _max_age = max_age(request) identity, _ts = authn.authenticated_as(cookie, authorization=_auth_info, max_age=_max_age) except (NoSuchAuthentication, TamperAllert): identity = None _ts = 0 except ToOld: logger.info("Too old authentication") identity = None _ts = 0 else: if identity: try: # If identity['uid'] is in fact a base64 encoded JSON string _id = b64d(as_bytes(identity["uid"])) except BadSyntax: pass else: identity = json.loads(as_unicode(_id)) session = self.endpoint_context.sdb[identity.get("sid")] if not session or "revoked" in session: identity = None authn_args = authn_args_gather(request, authn_class_ref, cinfo, **kwargs) # To authenticate or Not if identity is None: # No! logger.info("No active authentication") logger.debug("Known clients: {}".format( list(self.endpoint_context.cdb.keys()))) if "prompt" in request and "none" in request["prompt"]: # Need to authenticate but not allowed return { "error": "login_required", "return_uri": redirect_uri, "return_type": request["response_type"], } else: return {"function": authn, "args": authn_args} else: logger.info("Active authentication") if re_authenticate(request, authn): # demand re-authentication return {"function": authn, "args": authn_args} else: # I get back a dictionary user = identity["uid"] if "req_user" in kwargs: sids = self.endpoint_context.sdb.get_sids_by_sub( kwargs["req_user"]) if (sids and user != self.endpoint_context.sdb.get_authentication_event( sids[-1]).uid): logger.debug("Wanted to be someone else!") if "prompt" in request and "none" in request["prompt"]: # Need to authenticate but not allowed return { "error": "login_required", "return_uri": redirect_uri, } else: return {"function": authn, "args": authn_args} authn_event = create_authn_event( identity["uid"], identity.get("salt", ""), authn_info=authn_class_ref, time_stamp=_ts, ) if "valid_until" in authn_event: vu = time.time() + authn.kwargs.get("expires_in", 0.0) authn_event["valid_until"] = vu return {"authn_event": authn_event, "identity": identity, "user": user}
def main(): """Main function""" parser = argparse.ArgumentParser(description="JWS verifier") parser.add_argument( "--trusted", dest="trusted", metavar="filename", help="Trusted keys (JWKS)", required=False, ) parser.add_argument( "--input", dest="jws_input", metavar="filename", help="JWS file input", required=True, ) parser.add_argument( "--output", dest="output", metavar="filename", help="Output", required=False, ) parser.add_argument( "--headers", dest="headers_output", metavar="filename", help="Headers output", required=False, ) parser.add_argument("--debug", dest="debug", action="store_true", help="Enable debugging") args = parser.parse_args() if args.debug: logging.basicConfig(level=logging.DEBUG) else: logging.basicConfig(level=logging.INFO) trusted_keys = [] if args.trusted: with open(args.trusted) as input_file: trusted_payload = json.load(input_file) if isinstance(trusted_payload, dict): trusted_keys.append(key_from_jwk_dict(trusted_payload)) elif isinstance(trusted_payload, dict): for jwk_dict in trusted_payload["keys"]: trusted_keys.append( key_from_jwk_dict(jwk_dict, private=False)) else: raise ValueError("Unknown trusted list format") with open(args.jws_input, "rt") as input_file: jws_file = input_file.read() protected_headers = [] jws_dict = json.loads(jws_file) if args.trusted: jws = JWS() message = jws.verify_json(jws_file, keys=trusted_keys) else: message = json.loads(b64d(jws_dict["payload"].encode()).decode()) for signatures in jws_dict["signatures"]: if "protected" in signatures: protected_headers.append(extract_headers(signatures["protected"])) if args.headers_output: with open(args.headers_output, "wt") as output_file: print(json.dumps(protected_headers, indent=4), file=output_file) else: if args.trusted: print("# JWS PROTECTED HEADERS (VERIFIED)") else: print("# JWS PROTECTED HEADERS (NOT VERIFIED)") print(json.dumps(protected_headers, indent=4, sort_keys=True)) if args.output: with open(args.output, "wt") as output_file: print(json.dumps(message, indent=4), file=output_file) else: if args.trusted: print("# JWS CONTENTS (VERIFIED)") else: print("# JWS CONTENTS (NOT VERIFIED)") print(json.dumps(message, indent=4, sort_keys=True))
def extract_headers(data: str) -> dict: """Extract JSON-encoded headers""" return json.loads(b64d(data.encode()).decode())
def cosekey_from_jwk_dict(jwk_dict: Dict, private: bool = True) -> CoseKey: """Read key and return CoseKey""" if jwk_dict["kty"] == "EC": if jwk_dict["crv"] != "P-256": raise ValueError("Only P-256 supported") if private: key = EC2Key( crv=cose.keys.curves.P256, x=b64d(jwk_dict["x"].encode()), y=b64d(jwk_dict["y"].encode()), d=b64d(jwk_dict["d"].encode()), ) else: key = EC2Key( crv=cose.keys.curves.P256, x=b64d(jwk_dict["x"].encode()), y=b64d(jwk_dict["y"].encode()), ) elif jwk_dict["kty"] == "RSA": if private: key = RSAKey( e=b64d(jwk_dict["e"].encode()), n=b64d(jwk_dict["n"].encode()), p=b64d(jwk_dict["p"].encode()), q=b64d(jwk_dict["q"].encode()), d=b64d(jwk_dict["d"].encode()), ) else: key = RSAKey( e=b64d(jwk_dict["e"].encode()), n=b64d(jwk_dict["n"].encode()), ) else: raise ValueError("Unsupport key type: " + jwk_dict["kty"]) if private: key.key_ops = [cose.keys.keyops.SignOp, cose.keys.keyops.VerifyOp] else: key.key_ops = [cose.keys.keyops.VerifyOp] if "kid" in jwk_dict: kid = jwk_dict["kid"] try: key.kid = b64d(kid.encode()) except cryptojwt.exception.BadSyntax: key.kid = b64decode(kid.encode()) return key