#!/usr/bin/env python
# Copyright 2016 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Cryptography helpers for verifying and signing messages.

The simplest way to verify signatures is using :func:`verify_signature`::

    cert = open('certs.pem').read()
    valid = crypt.verify_signature(message, signature, cert)

If you're going to verify many messages with the same certificate, you can use
:class:`RSAVerifier`::

    cert = open('certs.pem').read()
    verifier = crypt.RSAVerifier.from_string(cert)
    valid = verifier.verify(message, signature)

To sign messages use :class:`RSASigner` with a private key::

    private_key = open('private_key.pem').read()
    signer = crypt.RSASigner.from_string(private_key)
    signature = signer.sign(message)

The code above also works for :class:`ES256Signer` and :class:`ES256Verifier`.
Note that these two classes are only available if your `cryptography` dependency
version is at least 1.4.0.
"""

import six

from google.auth.crypt import base
from google.auth.crypt import rsa

try:
    from google.auth.crypt import es256
except ImportError:  # pragma: NO COVER
    es256 = None  # type: ignore

if es256 is not None:  # pragma: NO COVER
    __all__ = [
        "ES256Signer",
        "ES256Verifier",
        "RSASigner",
        "RSAVerifier",
        "Signer",
        "Verifier",
    ]
else:  # pragma: NO COVER
    __all__ = ["RSASigner", "RSAVerifier", "Signer", "Verifier"]


# Aliases to maintain the v1.0.0 interface, as the crypt module was split
# into submodules.
Signer = base.Signer
Verifier = base.Verifier
RSASigner = rsa.RSASigner
RSAVerifier = rsa.RSAVerifier

if es256 is not None:  # pragma: NO COVER
    ES256Signer = es256.ES256Signer
    ES256Verifier = es256.ES256Verifier


def verify_signature(message, signature, certs, verifier_cls=rsa.RSAVerifier):
    """Verify an RSA or ECDSA cryptographic signature.

    Checks that the provided ``signature`` was generated from ``bytes`` using
    the private key associated with the ``cert``.

    Args:
        message (Union[str, bytes]): The plaintext message.
        signature (Union[str, bytes]): The cryptographic signature to check.
        certs (Union[Sequence, str, bytes]): The certificate or certificates
            to use to check the signature.
        verifier_cls (Optional[~google.auth.crypt.base.Signer]): Which verifier
            class to use for verification. This can be used to select different
            algorithms, such as RSA or ECDSA. Default value is :class:`RSAVerifier`.

    Returns:
        bool: True if the signature is valid, otherwise False.
    """
    if isinstance(certs, (six.text_type, six.binary_type)):
        certs = [certs]

    for cert in certs:
        verifier = verifier_cls.from_string(cert)
        if verifier.verify(message, signature):
            return True
    return False
