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 _create_raw_card(self, key_pair: KeyGeneratorInterface, key_info: dict) -> str: # Prepare public key in virgil format public_key = key_pair.public_key public_key = tiny_key_to_virgil(public_key) public_key = self._crypto.import_public_key(public_key) # Calculate identity. identity = key_pair.key_type # For keys which amount is 2 there should be identities like auth_1, auth_2 if key_pair.key_type in (VSKeyTypeS.RECOVERY.value, VSKeyTypeS.AUTH.value, VSKeyTypeS.TRUSTLIST.value, VSKeyTypeS.FIRMWARE.value): if key_pair.key_type not in self._keys_counter or self._keys_counter[ key_pair.key_type] == 2: key_number = 1 else: key_number = 2 identity = "%s_%s" % (identity, key_number) self._keys_counter[key_pair.key_type] = key_number # Prepare card content snapshot created_at = int(datetime.utcnow().timestamp()) card_content = RawCardContent(identity=identity, public_key=public_key, created_at=created_at) card_content_snapshot = card_content.content_snapshot # Create raw card raw_card = RawSignedModel(card_content_snapshot) # Sign combined snapshot (with key_info) key_info_b = json.dumps(key_info).encode("utf-8") key_info_b64 = to_b64(key_info_b) combined_snapshot = to_b64( b64_to_bytes(card_content_snapshot) + b64_to_bytes(key_info_b64)) signature = key_pair.sign(combined_snapshot, long_sign=True) if not signature: err_msg = "[ERROR]: Virgil Card creation request: signing failed" self._ui.print_error(err_msg) self._logger.error(err_msg) sys.exit(1) raw_signature = RawSignature( signer="self", signature=b64_to_bytes(signature), signature_snapshot=b64_to_bytes(key_info_b64)) # Append signature to card raw_card.signatures.append(raw_signature) # Return card request as json string return raw_card.to_json()
def test_create_from_raw_card_content(self): # STC-1 raw_signed_model = RawSignedModel.from_json( self._compatibility_data["STC-1.as_json"]) raw_card_content = RawCardContent.from_signed_model( self._crypto, raw_signed_model) raw_signed_model_from_raw_card_content = RawSignedModel( raw_card_content.content_snapshot) self.assertEqual( raw_signed_model.content_snapshot, raw_signed_model_from_raw_card_content.content_snapshot) self.assertDictEqual(vars(raw_signed_model), vars(raw_signed_model_from_raw_card_content))
def export_card_to_raw_card(self, card): # type: (Card) -> RawSignedModel """ Exports the specified card as a RawSignedModel. Args: card: Card instance to be exported. Returns: Returns instance of RawSignedModel representing Card. """ raw_signed_model = RawSignedModel(card.content_snapshot) for signature in card.signatures: raw_signed_model.add_signature(signature) return raw_signed_model
def generate_raw_signed_model( self, key_pair, add_self_sign=False, virgil_key_pair=None, extra_key_pair=None, previous_card_id=None ): create_time = 1515686245 raw_card_content = RawCardContent( created_at=create_time, identity="test", public_key=key_pair.public_key, version="5.0", previous_card_id=previous_card_id ) model = RawSignedModel(raw_card_content.content_snapshot) signer = ModelSigner(CardCrypto()) if add_self_sign: signer.self_sign(model, key_pair.private_key) if virgil_key_pair: signer.sign(model, ModelSigner.VIRGIL_SIGNER, virgil_key_pair.private_key) if extra_key_pair: signer.sign(model, "extra", extra_key_pair.private_key) return model
def get_card(self, card_id, token): # type: (str, str) -> Tuple[RawSignedModel, bool] """ Gets a card from Virgil Services by specified card ID. Args: card_id: The Card ID. token: The string representation of Jwt token. Returns: An instance of RawSignedModel class and flag, which determines whether or not this raw card is superseded. Raises: ValueError: Missed argument. """ if not card_id: raise ValueError("Missing card id") if not token: raise ValueError("Missing access token") request = Request("/card/v5/{}".format(card_id), ) request.authorization(token) response, headers = self.__connection.send(request) card_raw = RawSignedModel(**response) superseded = False if headers and "X-VIRGIL-IS-SUPERSEEDED" in headers.keys(): if headers["X-VIRGIL-IS-SUPERSEEDED"]: superseded = True return card_raw, superseded
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 __parse_cards_from_response(self, response): if response: result = list() for card in response: result.append(RawSignedModel(**card)) return result else: return response
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_generate_pure_model_from_json(self): # STC-1 rsm = RawSignedModel.from_json( self._compatibility_data["STC-1.as_json"]) rsm_json = rsm.to_json() self.assertDictEqual( json.loads(self._compatibility_data["STC-1.as_json"]), json.loads(rsm_json)) self.assertEqual( json.loads( self._compatibility_data["STC-1.as_json"])["signatures"], rsm.signatures)
def test_generate_full_model_from_json(self): # STC-2 rsm = RawSignedModel.from_json( self._compatibility_data["STC-2.as_json"]) rsm_json = rsm.to_json() self.assertDictEqual( json.loads(self._compatibility_data["STC-2.as_json"]), json.loads(rsm_json)) self.assertEqual( json.dumps(json.loads( self._compatibility_data["STC-2.as_json"])["signatures"], sort_keys=True), json.dumps(list(map(lambda x: x.to_json(), rsm.signatures)), sort_keys=True))
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))
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 publish_card(self, raw_card, token): # type: (RawSignedModel, str) -> RawSignedModel """ Publishes card in Virgil Cards service. Args: raw_card: An instance of RawSignedModel class. token: The string representation of Jwt token. Returns: Published raw card. """ if not raw_card: raise ValueError("Missing raw card") if not token: raise ValueError("Missing JWT token") request = Request("/card/v5", Utils.json_loads(raw_card.to_json()), method=Request.POST) request.authorization(token) response, headers = self.__connection.send(request) return RawSignedModel(**response)
def test_create_from_signed_model_string(self): # STC-1 raw_signed_model = RawSignedModel.from_string(self._compatibility_data["STC-1.as_string"]) raw_card_content = RawCardContent.from_signed_model(self._crypto, raw_signed_model) self.assertEqual(raw_signed_model.content_snapshot, raw_card_content.content_snapshot)
def __emulate_server_app_sign_response(self, model_sting): raw_signed_model = RawSignedModel.from_string(model_sting) return raw_signed_model.to_string()
def sign_callback(self, model): response = self.__emulate_server_app_sign_response(model.to_string()) return RawSignedModel.from_string(response)