def test_calls_service_for_operations_unsupported_locally():
    """When an operation can't be performed locally, the client should request Key Vault perform it"""

    mock_client = mock.Mock()
    key = mock.Mock(spec=KeyVaultKey, id="https://localhost/fake/key/version")
    client = CryptographyClient(key, mock.Mock())
    client._client = mock_client

    supports_nothing = mock.Mock(supports=mock.Mock(return_value=False))
    with mock.patch(
            CryptographyClient.__module__ + ".get_local_cryptography_provider",
            lambda *_: supports_nothing):
        client.decrypt(EncryptionAlgorithm.rsa_oaep, b"...")
    assert mock_client.decrypt.call_count == 1
    assert supports_nothing.decrypt.call_count == 0

    client.encrypt(EncryptionAlgorithm.rsa_oaep, b"...")
    assert mock_client.encrypt.call_count == 1
    assert supports_nothing.encrypt.call_count == 0

    client.sign(SignatureAlgorithm.rs256, b"...")
    assert mock_client.sign.call_count == 1
    assert supports_nothing.sign.call_count == 0

    client.verify(SignatureAlgorithm.rs256, b"...", b"...")
    assert mock_client.verify.call_count == 1
    assert supports_nothing.verify.call_count == 0

    client.unwrap_key(KeyWrapAlgorithm.rsa_oaep, b"...")
    assert mock_client.unwrap_key.call_count == 1
    assert supports_nothing.unwrap_key.call_count == 0

    client.wrap_key(KeyWrapAlgorithm.rsa_oaep, b"...")
    assert mock_client.wrap_key.call_count == 1
    assert supports_nothing.wrap_key.call_count == 0
class SignTest(PerfStressTest):

    def __init__(self, arguments):
        super().__init__(arguments)

        from dotenv import load_dotenv
        load_dotenv()

        # Auth configuration
        self.credential = DefaultAzureCredential()
        self.async_credential = AsyncDefaultAzureCredential()

        # Create clients
        vault_url = self.get_from_env("AZURE_KEYVAULT_URL")
        self.client = KeyClient(vault_url, self.credential, **self._client_kwargs)
        self.async_client = AsyncKeyClient(vault_url, self.async_credential, **self._client_kwargs)
        self.key_name = "livekvtestsignperfkey"

    async def global_setup(self):
        """The global setup is run only once."""
        await super().global_setup()
        rsa_key = await self.async_client.create_rsa_key(self.key_name)
        self.crypto_client = CryptographyClient(rsa_key.id, self.credential, permissions=NO_GET, **self._client_kwargs)
        self.async_crypto_client = AsyncCryptographyClient(
            rsa_key.id, self.async_credential, permissions=NO_GET, **self._client_kwargs
        )

        self.test_algorithm = SignatureAlgorithm.rs256
        plaintext = os.urandom(2048)
        hasher = hashlib.sha256()
        hasher.update(plaintext)
        self.digest = hasher.digest()

    async def global_cleanup(self):
        """The global cleanup is run only once."""
        await self.async_client.delete_key(self.key_name)
        await self.async_client.purge_deleted_key(self.key_name)
        await super().global_cleanup()

    async def close(self):
        """This is run after cleanup."""
        await self.async_client.close()
        await self.async_crypto_client.close()
        await self.async_credential.close()
        await super().close()

    def run_sync(self):
        """The synchronous perf test."""
        self.crypto_client.sign(self.test_algorithm, self.digest)

    async def run_async(self):
        """The asynchronous perf test."""
        await self.async_crypto_client.sign(self.test_algorithm, self.digest)
Exemple #3
0
    def test_sign_verify(self, key_client, credential, **kwargs):
        key_name = self.get_resource_name("crypto-test-wrapping-key")
        key = key_client.create_rsa_key(key_name)
        client = CryptographyClient(key, credential)

        # [START sign]

        import hashlib
        from azure.keyvault.keys.crypto import SignatureAlgorithm

        digest = hashlib.sha256(b"plaintext").digest()

        # sign returns a tuple with the signature and the metadata required to verify it
        result = client.sign(SignatureAlgorithm.rs256, digest)

        # the result contains the signature and identifies the key and algorithm used
        print(result.key_id)
        print(result.algorithm)
        signature = result.signature

        # [END sign]

        # [START verify]

        from azure.keyvault.keys.crypto import SignatureAlgorithm

        verified = client.verify(SignatureAlgorithm.rs256, digest, signature)
        assert verified.is_valid
Exemple #4
0
    def test_sign_verify(self, key_client, **kwargs):
        credential = self.get_credential(CryptographyClient)
        key_name = self.get_resource_name("crypto-test-wrapping-key")
        key = key_client.create_rsa_key(key_name)
        client = CryptographyClient(key,
                                    credential,
                                    api_version=key_client.api_version)

        # [START sign]
        import hashlib
        from azure.keyvault.keys.crypto import SignatureAlgorithm

        digest = hashlib.sha256(b"plaintext").digest()

        # sign returns the signature and the metadata required to verify it
        result = client.sign(SignatureAlgorithm.rs256, digest)
        print(result.key_id)
        print(result.algorithm)
        signature = result.signature
        # [END sign]

        # [START verify]
        from azure.keyvault.keys.crypto import SignatureAlgorithm

        result = client.verify(SignatureAlgorithm.rs256, digest, signature)
        assert result.is_valid
class KeyVaultRSAKey(rsa.RSAPublicKey, rsa.RSAPrivateKey):
    """Azure KeyVault provider for public and private account key"""
    def __init__(self, credentials, vault_url: str, key_name: str):
        self.vault_url = vault_url
        self.key_name = key_name

        self.key_client = KeyClient(vault_url=vault_url,
                                    credential=credentials)

        try:
            self.kv_key = self.key_client.get_key(key_name)
            logger.info('Using existing user key from KeyVault')
        except ResourceNotFoundError:
            logger.info('Creating new user key in KeyVault')
            self.kv_key = self.key_client.create_rsa_key(key_name,
                                                         size=self.key_size)

        self.crypto_client = CryptographyClient(self.kv_key,
                                                credential=credentials)

    @property
    def key_size(self):
        return 2048

    def encrypt(self, plaintext, padding):
        result = self.crypto_client.encrypt(EncryptionAlgorithm.rsa_oaep,
                                            plaintext)
        return result

    def public_numbers(self):
        e = int.from_bytes(self.kv_key.key.e, byteorder='big')
        n = int.from_bytes(self.kv_key.key.n, byteorder='big')
        return rsa.RSAPublicNumbers(e, n)

    def public_bytes(self):
        pass

    def verifier(self, signature, padding, algorithm):
        pass

    def verify(self, signature, data, padding, algorithm):
        pass

    def public_key(self):
        return self

    def signer(self, padding, algorithm):
        pass

    def decrypt(self, ciphertext, padding):
        pass

    def sign(self, data, padding, algorithm):
        value = hashlib.sha256(data).digest()
        res = self.crypto_client.sign(SignatureAlgorithm.rs256, digest=value)
        return res.signature
def test_prefers_local_provider():
    """The client should complete operations locally whenever possible"""

    mock_client = mock.Mock()
    key = mock.Mock(
        spec=KeyVaultKey,
        id="https://localhost/fake/key/version",
        properties=mock.Mock(not_before=datetime(2000, 1, 1, tzinfo=_UTC),
                             expires_on=datetime(3000, 1, 1, tzinfo=_UTC)),
    )
    client = CryptographyClient(key, mock.Mock())
    client._client = mock_client

    supports_everything = mock.Mock(supports=mock.Mock(return_value=True))
    with mock.patch(
            CryptographyClient.__module__ + ".get_local_cryptography_provider",
            lambda *_: supports_everything):
        client.decrypt(EncryptionAlgorithm.rsa_oaep, b"...")
    assert mock_client.decrypt.call_count == 0
    assert supports_everything.decrypt.call_count == 1

    client.encrypt(EncryptionAlgorithm.rsa_oaep, b"...")
    assert mock_client.encrypt.call_count == 0
    assert supports_everything.encrypt.call_count == 1

    client.sign(SignatureAlgorithm.rs256, b"...")
    assert mock_client.sign.call_count == 0
    assert supports_everything.sign.call_count == 1

    client.verify(SignatureAlgorithm.rs256, b"...", b"...")
    assert mock_client.verify.call_count == 0
    assert supports_everything.verify.call_count == 1

    client.unwrap_key(KeyWrapAlgorithm.rsa_oaep, b"...")
    assert mock_client.unwrap_key.call_count == 0
    assert supports_everything.unwrap_key.call_count == 1

    client.wrap_key(KeyWrapAlgorithm.rsa_oaep, b"...")
    assert mock_client.wrap_key.call_count == 0
    assert supports_everything.wrap_key.call_count == 1
def main():
    try:

        # Enable logging
        enable_logging()

        # Setup some sample data
        sample_data = {
            "value1": "some value 1",
            "value2": "some value 2",
            "value3": "some value 3",
            "value4": "some value 4"
        }

        # Convert the dict to string, encode to bytes, and hash the data
        sample_data_hash = hashlib.sha512(
            json.dumps(sample_data).encode('UTF-8')).digest()

        # Obtain a credential from the system-assigned managed identity
        msi_credential = DefaultAzureCredential()

        # Get the key from Key Vault and setup a cryptography client
        key_client = KeyClient(KEY_VAULT_URL, msi_credential)
        key = key_client.get_key(CERTIFICATE_NAME)
        crypto_client = CryptographyClient(key, credential=msi_credential)

        # Use Key Vault to calculate a signature using RSASSA-PKCS1-v1_5 using SHA-512
        data_signature = (crypto_client.sign(SignatureAlgorithm.rs512,
                                             sample_data_hash)).signature

        # Retrieve the certificate from Key Vault
        cert_client = CertificateClient(KEY_VAULT_URL, msi_credential)
        result = (cert_client.get_certificate(CERTIFICATE_NAME)).cer

        # Load the DER certificate returned into an x509 object and get the public key
        cert = load_der_x509_certificate(result, backend=default_backend())
        public_key = cert.public_key()

        # Verify the signature
        try:
            public_key.verify(signature=data_signature,
                              data=(json.dumps(sample_data)).encode('UTF-8'),
                              padding=padding.PKCS1v15(),
                              algorithm=hashes.SHA512())
            logging.info('Payload verified successfully')
            print('Payload verified successfully!')

        except InvalidSignature:
            print('Payload and/or signature files failed verification')

    except Exception:
        logging.error('Execution error: ', exc_info=True)
Exemple #8
0
def get_github_auth_token():
    # credentials for AKV come from environment settings
    credential = azid.DefaultAzureCredential()

    akvURL = '{0}keys/{1}/{2}'.format(os.environ['key_vault_uri'], os.environ['key_name'], os.environ['key_version'])

    # built JWT token
    header = {
        'alg': 'RS256',
        'kid': akvURL,
        'typ': 'JWT',
    }

    payload = {
        'iss': os.environ['github_appID'],
        'iat': int(datetime.now(timezone.utc).timestamp()),
        'exp': int((datetime.now(timezone.utc) + timedelta(minutes=1)).timestamp()),
    }

    p = []

    p.append(base64.urlsafe_b64encode(json.dumps(header).encode('utf-8')))
    p.append(base64.urlsafe_b64encode(json.dumps(payload).encode('utf-8')))

    digest = hashlib.sha256(b".".join(p)).digest()
    cryptoClient = CryptographyClient(akvURL, credential)
    result = cryptoClient.sign(azkeys.crypto.SignatureAlgorithm.rs256, digest)

    p.append(base64.urlsafe_b64encode(result.signature).replace(b"=", b""))

    token = b".".join(p).decode()

    headers = {
        "Authorization": "Bearer " + token,
        "Accept": "application/vnd.github.machine-man-preview+json",
    }

    r = requests.get('https://api.github.com/integration/installations', headers=headers)

    logging.debug(r.json())

    access_token_url = r.json()[0]['access_tokens_url']

    r = requests.post(access_token_url, headers=headers)

    logging.debug(r.json())

    return r.json()['token']
Exemple #9
0
    def test_sign_and_verify(self, key_client, credential, **kwargs):
        key_name = self.get_resource_name("keysign")

        md = hashlib.sha256()
        md.update(self.plaintext)
        digest = md.digest()

        imported_key = self._import_test_key(key_client, key_name)
        crypto_client = CryptographyClient(imported_key.id, credential)

        result = crypto_client.sign(SignatureAlgorithm.rs256, digest)
        self.assertEqual(result.key_id, imported_key.id)

        verified = crypto_client.verify(result.algorithm, digest,
                                        result.signature)
        self.assertEqual(result.key_id, imported_key.id)
        self.assertEqual(result.algorithm, SignatureAlgorithm.rs256)
        self.assertTrue(verified.is_valid)
Exemple #10
0
    def test_rsa_verify_local(self, key_client, credential, **kwargs):
        """Sign with Key Vault, verify locally"""

        for size in (2048, 3072, 4096):
            key = key_client.create_rsa_key("rsa-verify-{}".format(size),
                                            size=size)
            crypto_client = CryptographyClient(key, credential)
            for signature_algorithm, hash_function in (
                (SignatureAlgorithm.ps256, hashlib.sha256),
                (SignatureAlgorithm.ps384, hashlib.sha384),
                (SignatureAlgorithm.ps512, hashlib.sha512),
                (SignatureAlgorithm.rs256, hashlib.sha256),
                (SignatureAlgorithm.rs384, hashlib.sha384),
                (SignatureAlgorithm.rs512, hashlib.sha512),
            ):
                digest = hash_function(self.plaintext).digest()

                result = crypto_client.sign(signature_algorithm, digest)
                self.assertEqual(result.key_id, key.id)

                result = crypto_client.verify(result.algorithm, digest,
                                              result.signature)
                self.assertTrue(result.is_valid)
    def test_ec_verify_local(self, key_client, credential, **kwargs):
        """Sign with Key Vault, verify locally"""

        matrix = {
            KeyCurveName.p_256: (SignatureAlgorithm.es256, hashlib.sha256),
            KeyCurveName.p_256_k: (SignatureAlgorithm.es256_k, hashlib.sha256),
            KeyCurveName.p_384: (SignatureAlgorithm.es384, hashlib.sha384),
            KeyCurveName.p_521: (SignatureAlgorithm.es512, hashlib.sha512),
        }

        for curve, (signature_algorithm, hash_function) in matrix.items():
            key = key_client.create_ec_key("ec-verify-{}".format(curve.value),
                                           curve=curve)
            crypto_client = CryptographyClient(key, credential)

            digest = hash_function(self.plaintext).digest()

            result = crypto_client.sign(signature_algorithm, digest)
            self.assertEqual(result.key_id, key.id)

            result = crypto_client.verify(result.algorithm, digest,
                                          result.signature)
            self.assertTrue(result.is_valid)
Exemple #12
0
def obtain_access_token(key_vault_url, msi_credential, certificate_name,
                        tenant_id, client_id, resource):

    # Get certificate from Key Vault, load the DER certificate it returns, and calculate the thumbprint
    cert_client = CertificateClient(key_vault_url, msi_credential)
    result = (cert_client.get_certificate(certificate_name)).cer
    cert = load_der_x509_certificate(result, backend=default_backend())
    thumbprint = base64.urlsafe_b64encode(cert.fingerprint(
        hashes.SHA1())).decode('UTF-8')

    # Create the headers for the JWT
    headers = {"alg": "RS256", "typ": "JWT", "x5t": thumbprint}
    encoded_header = (base64.urlsafe_b64encode(
        bytes(json.dumps(headers), 'UTF-8'))).decode('UTF-8')

    # Generate a nonce
    nonce = uuid4().hex

    # Create the JWT payload
    claims = {
        "aud": f"https://login.microsoftonline.com/{tenant_id}/oauth2/token",
        "iss": client_id,
        "sub": client_id,
        "jti": nonce,
        "nbf": int(time.time()),
        "exp": int(time.time() + (7 * 86400))
    }
    encoded_claims = (base64.urlsafe_b64encode(
        bytes(json.dumps(claims), 'UTF-8'))).decode('UTF-8').rstrip('=')

    # Issue the request to Key Vault to sign the data
    key_client = KeyClient(key_vault_url, msi_credential)
    key = key_client.get_key(certificate_name)
    crypto_client = CryptographyClient(key, credential=msi_credential)
    data_hash = hashlib.sha256(
        bytes((encoded_header + '.' + encoded_claims), 'UTF-8')).digest()

    # Use Key Vault to calculate a signature using RSASSA-PKCS1-v1_5 using SHA-256
    jws_signature = (crypto_client.sign(SignatureAlgorithm.rs256,
                                        data_hash)).signature
    encoded_jws_signature = (
        base64.urlsafe_b64encode(jws_signature)).decode('UTF-8').rstrip('=')
    assertion = encoded_header + '.' + encoded_claims + '.' + encoded_jws_signature
    payload = {
        "grant_type": "client_credentials",
        "client_id": client_id,
        "client_assertion_type":
        "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
        "client_assertion": assertion,
        "resource": resource
    }

    # Post the request for the access token
    result = requests.post(
        url=f"https://login.microsoftonline.com/{tenant_id}/oauth2/token",
        data=payload)

    # Validate that access token was returned
    if result.status_code == 200:
        logging.info('Access token successfully obtained')
        return ((json.loads(result.text))['access_token'])
    else:
        error = json.loads(result.text)
        logging.error('Unable to obtain access token')
        logging.error(f"Error was: {error['error']}")
        logging.error(f"Error description was: {error['error_description']}")
        logging.error(f"Error correlation_id was: {error['correlation_id']}")
        raise Exception('Failed to obtain access token')