def __init__(self): self.crypto = VirgilCrypto() self.api_key_base64 = "MC4CAQAwBQYDK2VwBCIEIF+gQkN4StqMMFJGWE1tKXcitkLqHqmrBz+OaQZKGZFR" self.app_id = "6af75f0dd9be50ebb77facad0f71eaf3" self.app_key_id = "3def16346c7b43bbaed5b4b9acb9ac8affa4" self.api_key = self.crypto.import_private_key(Utils.b64_decode(self.api_key_base64)) self.ttl = datetime.timedelta(hours=1).seconds self.access_token_signer = AccessTokenSigner() self.key_pair = self.crypto.generate_keys() self.server_crypto = VirgilCrypto() self.server_key_pair = self.server_crypto.generate_keys() self.server_private_key_data = self.server_crypto.export_private_key(self.server_key_pair.private_key, "test password") self.server_public_key_data = self.server_crypto.export_public_key(self.server_key_pair.public_key) self.server_private_key_str = Utils.b64encode(self.server_private_key_data) self.server_for_client_public = Utils.b64encode(self.server_public_key_data) self.server_exporter = PrivateKeyExporter(self.server_crypto) self.server_private_key_storage = PrivateKeyStorage(self.server_exporter) self.server_public_key_str = self.server_key_pair.public_key self.server_card_crypto = CardCrypto() self.server_your_backend_white_list = WhiteList() self.server_your_backend_white_list = VerifierCredentials(signer="Jonathan",public_key_base64 = self.server_public_key_str) self.verifier = VirgilCardVerifier(self.server_card_crypto, white_lists = [self.server_your_backend_white_list]) self.access_token_provider = CallbackJwtProvider(self.get_token_from_server("Alice")) self.card_manager = CardManager( self.server_card_crypto, self.access_token_provider, self.verifier )
def import_card(self, card_to_import): # type: (Union[str, dict, RawSignedModel]) -> Card """ Imports and verifies Card. Args: card_to_import: Exported data of signed model. Returns: Imported and verified card. """ if isinstance(card_to_import, str) or Utils.check_unicode(card_to_import): card_to_import = str(card_to_import) try: if isinstance(Utils.json_loads(card_to_import), dict): card = Card.from_signed_model( self._card_crypto, RawSignedModel.from_json(card_to_import)) else: raise JSONDecodeError except (JSONDecodeError, ValueError) as e: card = Card.from_signed_model( self._card_crypto, RawSignedModel.from_string(card_to_import)) elif isinstance(card_to_import, dict) or isinstance( card_to_import, bytes): card = Card.from_signed_model( self._card_crypto, RawSignedModel.from_json(card_to_import)) elif isinstance(card_to_import, RawSignedModel): card = Card.from_signed_model(self._card_crypto, card_to_import) elif card_to_import is None: raise ValueError("Missing card to import") else: raise TypeError("Unexpected type for card import") self.__validate(card) return card
def from_string(cls, jwt_string): # type: (str) -> Jwt """ Initializes a new instance of the Jwt class using its string representation. Args: jwt_string: String representation of signed jwt. It must be equal to: base64UrlEncode(JWT Header) + "." + base64UrlEncode(JWT Body) "." + base64UrlEncode(Jwt Signature). Returns: Initialized instance of Jwt. Raises: ValueError: Wrong jwt format. """ parts = jwt_string.split(".") if len(parts) is not 3: raise ValueError("Wrong JWT format.") try: jwt = cls.__new__(cls) jwt._header_content = JwtHeaderContent.from_json( Utils.json_loads(Utils.b64_decode(parts[0]))) jwt._body_content = JwtBodyContent.from_json( Utils.json_loads(Utils.b64_decode(parts[1]))) jwt._signature_data = bytearray(Utils.b64_decode(parts[2])) except Exception as e: raise ValueError("Wrong JWT format.") jwt._body_content._app_id = jwt._body_content.issuer.replace( jwt._body_content.subject_prefix, "") jwt._body_content._identity = jwt._body_content.subject.replace( jwt._body_content.identity_prefix, "") jwt._unsigned_data = bytearray(parts[0] + "." + parts[1], "utf-8") jwt._string_representation = jwt_string return jwt
def to_json(self): """RawSignature json representation.""" res = { "signer": self.signer, "signature": Utils.b64encode(bytearray(self.signature)) } if self.snapshot: res["snapshot"] = Utils.b64encode(bytearray(self.snapshot)) return res
def test_generate_pure_model_from_string(self): # STC-1 rsm = RawSignedModel.from_string( self._compatibility_data["STC-1.as_string"]) rsm_string = rsm.to_string() self.assertEqual(self._compatibility_data["STC-1.as_string"], rsm_string) self.assertEqual( Utils.json_loads( Utils.b64decode(self._compatibility_data["STC-1.as_string"])) ["signatures"], rsm.signatures)
def test_get_const_access_token(self): token_from_server = self._get_token_from_server( TokenContext(Utils.b64encode(os.urandom(20)), "some_operation")) jwt = Jwt.from_string(token_from_server) const_token_provider = ConstAccessTokenProvider(jwt) token1 = const_token_provider.get_token( TokenContext(Utils.b64encode(os.urandom(10)), Utils.b64encode(os.urandom(10)), True)) token2 = const_token_provider.get_token( TokenContext(Utils.b64encode(os.urandom(10)), Utils.b64encode(os.urandom(10)), True)) self.assertEqual(token1, token2)
def json(self): """JwtBodyContent json representation.""" raw = OrderedDict({ "iat": Utils.to_timestamp(self._issued_at), "exp": Utils.to_timestamp(self._expires_at), "ada": self._additional_data, "iss": self.issuer, "sub": self.subject }) result = OrderedDict({}) for key in raw: if raw[key]: result[key] = raw[key] return result
def test_get_invalid_card(self): class FakeCardClient(object): def __init__(self, raw_signed_model): self._raw_signed_model = raw_signed_model def publish_card(self, raw_signed_model, access_token): return self._raw_signed_model def get_card(self, card_id, access_token): return self._raw_signed_model, False def search_card(self, identity, access_token): return [self._raw_signed_model] validator = self.NegativeVerifier() jwt_generator = JwtGenerator(config.VIRGIL_APP_ID, self._app_private_key, config.VIRGIL_API_KEY_ID, datetime.timedelta(minutes=10).seconds, AccessTokenSigner()) identity = Utils.b64encode(os.urandom(20)) token = jwt_generator.generate_token(identity) access_token_provider = self.EchoTokenProvider(token) key_pair = self._crypto.generate_keys() virgil_key_pair = self._crypto.generate_keys() additional_key_pair = self._crypto.generate_keys() model = self._data_generator.generate_raw_signed_model( key_pair, True, virgil_key_pair, additional_key_pair) client = FakeCardClient(model) card_id = self._data_generator.generate_card_id() search_identity = Utils.b64encode(os.urandom(20)) manager = CardManager(CardCrypto(), access_token_provider, validator, sign_callback=self.sign_callback) manager._card_client = client self.assertRaises(CardVerificationException, manager.import_card, model.to_json()) self.assertRaises(CardVerificationException, manager.import_card, model.to_string()) self.assertRaises(CardVerificationException, manager.get_card, card_id) self.assertRaises(CardVerificationException, manager.publish_card, model) self.assertRaises(CardVerificationException, manager.search_card, search_identity) self.assertRaises(CardVerificationException, manager.import_card, model)
def generate_token(self, identity, data=None): # type: (str, Optional[dict]) -> Jwt """ Generates new JWT using specified identity and additional data. Args: identity: Identity to generate with. data: Dictionary with additional data which will be kept in jwt body. Returns: A new instance of Jwt. """ issued_at = datetime.datetime.now() expires_at = datetime.datetime.utcfromtimestamp(Utils.to_timestamp(issued_at) + self._lifetime) jwt_body = JwtBodyContent( self._app_id, identity, issued_at, expires_at, data ) jwt_header = JwtHeaderContent( self._access_token_signer.algorithm, self._api_public_key_id ) unsigned_jwt = Jwt(jwt_header, jwt_body).unsigned_data jwt_bytes = unsigned_jwt signature = self._access_token_signer.generate_token_signature(bytearray(jwt_bytes), self._api_key) return Jwt(jwt_header, jwt_body, bytearray(signature))
def getUserVirgilJWT(): try: if not g.user: print('ERROR: No user to get Virgil JWT for.') return "", constants.STATUS_BAD_REQUEST crypto = VirgilCrypto() api_id = os.environ['VIRGIL_API_ID'] api_key_id = os.environ['VIRGIL_API_KEY_ID'] api_private_key = os.environ['VIRGIL_API_PRIVATE_KEY_ID'] token_ttl = 20 # seconds imported_key = crypto.import_private_key( Utils.b64decode(api_private_key)).private_key # Instantiate token generator builder = JwtGenerator(api_id, imported_key, api_key_id, token_ttl, AccessTokenSigner()) token = builder.generate_token(str(g.user.id)).to_string() return jsonify({"token": token}), constants.STATUS_OK except Exception as err: print('Error getting the Virgil JWT: ' + str(err)) return "", constants.STATUS_SERVER_ERROR return "", constants.STATUS_SERVER_ERROR
def publish_card(self, user): self.client_crypto = VirgilCrypto() card_crypto = CardCrypto() validator = VirgilCardVerifier(card_crypto) token_provider = CallbackJwtProvider(self.get_token_from_server) print('token_provider') print(vars(token_provider)) card_manager = CardManager(card_crypto, access_token_provider=token_provider, card_verifier=validator) key_pair = self.client_crypto.generate_keys() username = user public_key_data = self.client_crypto.export_public_key( key_pair.public_key) public_key_str = Utils.b64encode(public_key_data) class DummyClass: def __init__(self, raw_key): self.raw_key = raw_key dummy = DummyClass(key_pair.public_key.raw_key) print(public_key_data) print(public_key_str) print(key_pair.public_key) card = card_manager.publish_card(identity=username, private_key=key_pair.private_key, public_key=key_pair.public_key) print(vars(card))
def authenticated_query_to_server(self, token_context, token_ttl=9999): self.crypto = VirgilCrypto() self.app_key_base64 = "MC4CAQAwBQYDK2VwBCIEIEtNPMUG9uR8YxukWw1gX3bkXjbsbOZoN54d2ZKSz09a" # self.app_key_base64 = "MC4CAQAwBQYDK2VwBCIEIJvD17QhpJ1qFfIq3q8eqrZ0oBIf9GQ0T+6obQCmspnQ" #self.app_key_base64 = "MC4CAQAwBQYDK2VwBCIEIF+gQkN4StqMMFJGWE1tKXcitkLqHqmrBz+OaQZKGZFR" #self.app_id = "6af75f0dd9be50ebb77facad0f71eaf3" self.app_id = "def16346c7b43bbaed5b4b9ac8affa4" # self.api_key_id = "3def16346c7b43bbaed5b4b9acb9ac8affa4" self.api_key_id = "309d53349835f34d5a03966d9de51877" self.app_key = self.crypto.import_private_key( Utils.b64decode(self.app_key_base64)) self.builder = JwtGenerator(self.app_id, self.app_key, self.api_key_id, token_ttl, AccessTokenSigner()) #self.identity = token_context.identity #return self.builder.generate_token(self.identity).to_string() #PLEASE MAKE TOKEN_CONTEXT AN ACTUAL JWT TOKEN #return self.builder.generate_token(token_context) try: self.identity = token_context.identity return self.builder.generate_token(self.identity).to_string() except: return self.builder.generate_token(token_context)
def to_string(self): """ Serialize to base64 encoded string. Returns: Base64 encoded string. """ return Utils.b64encode(self.to_json().encode())
def generate_raw_card(self, private_key, public_key, identity, previous_card_id="", extra_fields=None): # type: (PrivateKey, PublicKey, str, Optional[str], Optional[dict]) -> RawSignedModel """ Args: private_key: PrivateKey for generate self signature. public_key: Card Public key. identity: Unique identity value. previous_card_id: Previous card id that current card is used to override to. extra_fields: The additional data associated with the card. Returns: The instance of newly published Card. """ current_time = Utils.to_timestamp(datetime.datetime.utcnow()) raw_card = RawSignedModel.generate(public_key, identity, current_time, previous_card_id) self.model_signer.self_sign(raw_card, private_key, extra_fields=extra_fields) return raw_card
def test_imported_token_compare_with_origin(self): callback_provider = CallbackJwtProvider(self._get_token_from_server) context = TokenContext(Utils.b64encode(os.urandom(20)), "some_operation") token = callback_provider.get_token(context) imported_token = Jwt.from_string(token.to_string()) self.assertTrue(token, imported_token)
def test_verify_created_in_another_sdk(self): # STC-22 token_base64 = self._compatibility_data["STC-22.jwt"] public_key_base64 = self._compatibility_data[ "STC-22.api_public_key_base64"] key_id_base64 = self._compatibility_data["STC-22.api_key_id"] jwt = Jwt.from_string(token_base64) exported_token = jwt.to_string() signer = AccessTokenSigner() verifier = JwtVerifier( signer, self._crypto.import_public_key( Utils.strtobytes(Utils.b64decode(public_key_base64))), key_id_base64) self.assertEqual(exported_token, token_base64) self.assertTrue(verifier.verify_token(jwt))
def from_json(cls, raw_signed_model_json): # type: (Union[str, bytes, bytearray]) -> RawSignedModel """Deserialize RawSignedModel from json representation.""" loaded_json = Utils.json_loads(raw_signed_model_json) content_snapshot = loaded_json["content_snapshot"] signatures = [] for sign in loaded_json["signatures"]: if "signature_snapshot" in sign.keys(): signature = RawSignature( sign["signer"], Utils.b64decode(sign["signature"]), Utils.b64decode(sign["signature_snapshot"])) signatures.append(signature) else: signature = RawSignature(sign["signer"], Utils.b64decode(sign["signature"])) signatures.append(signature) return RawSignedModel(content_snapshot, signatures)
def to_json(self): """ Card signature json representation. Returns: Serialize signature to json. """ res = { "signer": self.signer, "signature": Utils.b64encode(self.signature), } if self.snapshot: res["snapshot"] = Utils.b64encode(self.snapshot) if self._extra_fields: res["extra_fields"] = Utils.b64encode(self.extra_fields) return res
def __init__( self, jwt_header_content=None, # type: JwtHeaderContent jwt_body_content=None, # type: JwtBodyContent signature_data=None # type: Union[bytes, bytearray] ): self._header_content = jwt_header_content self._body_content = jwt_body_content self._signature_data = signature_data self._without_signature = Utils.b64_encode(Utils.json_dumps(self._header_content.json, sort_keys=True).encode())\ + "." +\ Utils.b64_encode(Utils.json_dumps(self._body_content.json, sort_keys=True).encode()) self._unsigned_data = self._without_signature.encode() self._string_representation = self._without_signature if self._signature_data: self._string_representation += "." + Utils.b64_encode( bytes(self._signature_data))
def _app_private_key(self): if self.__app_private_key: return self.__app_private_key with open(config.VIRGIL_APP_KEY_PATH, "rb") as key_file: raw_private_key = bytearray(Utils.b64decode(key_file.read())) self.__app_private_key = self._crypto.import_private_key( key_data=raw_private_key, password=config.VIRGIL_APP_KEY_PASSWORD) return self.__app_private_key
def content_snapshot(self): """ Card content snapshot Returns: Card snapshot. """ if not self._content_snapshot: content = { "identity": self._identity, "public_key": Utils.b64encode(self._public_key.raw_key), "version": self._version, "created_at": self._created_at, } if self._previous_card_id: content.update({"previous_card_id": self._previous_card_id}) self._content_snapshot = Utils.b64encode( Utils.json_dumps(content, sort_keys=True, separators=(',', ':')).encode()) return self._content_snapshot
def to_json(self): """ RawSignedModel json representation. """ return Utils.json_dumps( { "content_snapshot": self.content_snapshot, "signatures": list(map(lambda x: x.to_json(), self.signatures)) }, separators=(',', ':'), sort_keys=True)
def __validate_signer_signature(self, card, signer_public_key, signer_type): signature = None for sign in card.signatures: if sign.signer == signer_type: signature = sign break if signature: if signature.snapshot: extended_snapshot = bytearray(Utils.b64_decode(card.content_snapshot))\ + bytearray(Utils.b64_decode(signature.snapshot)) else: extended_snapshot = bytearray( Utils.b64_decode(card.content_snapshot)) if self._crypto.verify_signature( bytearray(Utils.b64_decode(signature.signature)), extended_snapshot, signer_public_key): return True return False
def test_gets_card_with_different_id(self): class PositiveVerifier(object): def verify_card(self): return True class FakeCardClient(object): def __init__(self, raw_signed_model): self._raw_signed_model = raw_signed_model def get_card(self, card_id, access_token): return self._raw_signed_model, False validator = PositiveVerifier() key_pair = self._crypto.generate_keys() raw_card_content = RawCardContent(identity="test", public_key=key_pair.public_key, created_at=Utils.to_timestamp( datetime.datetime.now()), version="5.0") model = RawSignedModel(raw_card_content.content_snapshot) signer = ModelSigner(CardCrypto()) signer.self_sign(model, key_pair.private_key, extra_fields={"info": "some_additional_info"}) jwt_generator = JwtGenerator(config.VIRGIL_APP_ID, self._app_private_key, config.VIRGIL_API_KEY_ID, datetime.timedelta(minutes=10).seconds, AccessTokenSigner()) identity = Utils.b64encode(os.urandom(20)) token = jwt_generator.generate_token(identity) access_token_provider = self.EchoTokenProvider(token) card_id = self._data_generator.generate_app_id() manager = CardManager( card_crypto=CardCrypto(), access_token_provider=access_token_provider, card_verifier=validator, ) manager.card_client = FakeCardClient(model) self.assertRaises(CardVerificationException, manager.get_card, card_id)
def from_snapshot(cls, content_snapshot): # type: (dict) -> RawCardContent """ RawCardContent deserializer from snapshot representation. Args: content_snapshot: RawCardContent serialized snapshot. Returns: Loaded RawCardContent instance. """ card_content = cls.__new__(cls) loaded_snapshot = Utils.json_loads(Utils.b64_decode(content_snapshot)) card_content._identity = loaded_snapshot["identity"] card_content._public_key = loaded_snapshot["public_key"] card_content._version = loaded_snapshot["version"] card_content._created_at = loaded_snapshot["created_at"] if "previous_card_id" in loaded_snapshot.keys(): card_content._previous_card_id = loaded_snapshot[ "previous_card_id"] else: card_content._previous_card_id = None card_content._content_snapshot = None return card_content
def from_signed_model(cls, card_crypto, raw_singed_model, is_outdated=False): # type: (Any, RawSignedModel, bool) -> Card """ Creates card from SignedModel snapshot and signatures. Args: card_crypto: Users CardCrypto witch provides cryptographic operations. raw_singed_model: Card RawSignedModel is_outdated: State of obsolescence Returns: Card created from RawSignedModel. """ card = cls.from_snapshot(raw_singed_model.content_snapshot) card.previous_card = None card.is_outdated = is_outdated card._id = cls.__generate_card_id( card_crypto, Utils.b64_decode(raw_singed_model.content_snapshot)) card._public_key = card_crypto.import_public_key( bytearray(Utils.b64_decode(card._public_key))) signatures = list() if raw_singed_model.signatures: for sign in raw_singed_model.signatures: if isinstance(sign, dict): card_signature = CardSignature(**sign) signatures.append(card_signature) if isinstance(sign, CardSignature): card_signature = sign signatures.append(card_signature) if isinstance(sign, RawSignature): card_signature = CardSignature(sign.signer, sign.signature, sign.snapshot) signatures.append(card_signature) card.__signatures = signatures card._is_outdated = is_outdated return card
def sign(self, model, signer, signer_private_key, signature_snapshot=None, extra_fields=None): # type: (RawSignedModel, str, PrivateKey, Union[bytearray, bytes], dict) -> None """ Adds signature to the specified RawSignedModel using specified signer. Args: model: The instance of RawSignedModel to be signed. signer: signer_private_key: The instance of PrivateKey to sign with. signature_snapshot: Some additional raw bytes to be signed with model. extra_fields: Dictionary with additional data to be signed with model. """ if model.signatures: if any(list(filter(lambda x: x.signer == signer, model.signatures))): raise ValueError("The model already has this signature") if extra_fields and not signature_snapshot: signature_snapshot = bytearray( Utils.json_dumps(extra_fields).encode()) if signature_snapshot: extended_snapshot = Utils.b64encode( bytearray(Utils.b64_decode(model.content_snapshot)) + bytearray(signature_snapshot)) else: extended_snapshot = model.content_snapshot signature_bytes = self.__card_crypto.generate_signature( bytearray(Utils.b64_decode(extended_snapshot)), signer_private_key) signature = RawSignature(signer, bytearray(signature_bytes), signature_snapshot) model.add_signature(signature)
def from_signed_model(cls, card_crypto, raw_singed_model): # type: (Any, RawSignedModel) -> RawCardContent """ RawCardContent deserializer from RawSignedModel representation. Args: card_crypto: CardCrypto witch provides crypto operations. raw_singed_model: Card raw signed model. Returns: Loaded RawCardContent instance. """ card = cls.from_snapshot(raw_singed_model.content_snapshot) card._public_key = card_crypto.import_public_key( bytearray(Utils.b64_decode(card._public_key))) return card
def from_snapshot(cls, content_snapshot): # type: (str) -> Card """ Creates card from content snapshot. Args: content_snapshot: Model content snapshot. Returns: Card created from model content snapshot. """ card_content = cls.__new__(cls) loaded_snapshot = Utils.json_loads(Utils.b64_decode(content_snapshot)) card_content._identity = loaded_snapshot["identity"] card_content._public_key = loaded_snapshot["public_key"] card_content._version = loaded_snapshot["version"] card_content._created_at = loaded_snapshot["created_at"] if "previous_card_id" in loaded_snapshot.keys(): card_content._previous_card_id = loaded_snapshot[ "previous_card_id"] else: card_content._previous_card_id = None card_content._content_snapshot = None return card_content
def test_generate_full_model_from_string(self): # STC-2 rsm = RawSignedModel.from_string( self._compatibility_data["STC-2.as_string"]) rsm_string = rsm.to_string() self.assertEqual(self._compatibility_data["STC-2.as_string"], rsm_string) self.assertEqual( json.dumps(json.loads( Utils.b64decode( self._compatibility_data["STC-2.as_string"]).decode()) ["signatures"], sort_keys=True), json.dumps(list(map(lambda x: x.to_json(), rsm.signatures)), sort_keys=True))