_cryptography_rsa.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. # Copyright 2017 Google LLC
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. """RSA verifier and signer that use the ``cryptography`` library.
  15. This is a much faster implementation than the default (in
  16. ``google.auth.crypt._python_rsa``), which depends on the pure-Python
  17. ``rsa`` library.
  18. """
  19. import cryptography.exceptions
  20. from cryptography.hazmat import backends
  21. from cryptography.hazmat.primitives import hashes
  22. from cryptography.hazmat.primitives import serialization
  23. from cryptography.hazmat.primitives.asymmetric import padding
  24. import cryptography.x509
  25. from google.auth import _helpers
  26. from google.auth.crypt import base
  27. _CERTIFICATE_MARKER = b"-----BEGIN CERTIFICATE-----"
  28. _BACKEND = backends.default_backend()
  29. _PADDING = padding.PKCS1v15()
  30. _SHA256 = hashes.SHA256()
  31. class RSAVerifier(base.Verifier):
  32. """Verifies RSA cryptographic signatures using public keys.
  33. Args:
  34. public_key (
  35. cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey):
  36. The public key used to verify signatures.
  37. """
  38. def __init__(self, public_key):
  39. self._pubkey = public_key
  40. @_helpers.copy_docstring(base.Verifier)
  41. def verify(self, message, signature):
  42. message = _helpers.to_bytes(message)
  43. try:
  44. self._pubkey.verify(signature, message, _PADDING, _SHA256)
  45. return True
  46. except (ValueError, cryptography.exceptions.InvalidSignature):
  47. return False
  48. @classmethod
  49. def from_string(cls, public_key):
  50. """Construct an Verifier instance from a public key or public
  51. certificate string.
  52. Args:
  53. public_key (Union[str, bytes]): The public key in PEM format or the
  54. x509 public key certificate.
  55. Returns:
  56. Verifier: The constructed verifier.
  57. Raises:
  58. ValueError: If the public key can't be parsed.
  59. """
  60. public_key_data = _helpers.to_bytes(public_key)
  61. if _CERTIFICATE_MARKER in public_key_data:
  62. cert = cryptography.x509.load_pem_x509_certificate(
  63. public_key_data, _BACKEND
  64. )
  65. pubkey = cert.public_key()
  66. else:
  67. pubkey = serialization.load_pem_public_key(public_key_data, _BACKEND)
  68. return cls(pubkey)
  69. class RSASigner(base.Signer, base.FromServiceAccountMixin):
  70. """Signs messages with an RSA private key.
  71. Args:
  72. private_key (
  73. cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey):
  74. The private key to sign with.
  75. key_id (str): Optional key ID used to identify this private key. This
  76. can be useful to associate the private key with its associated
  77. public key or certificate.
  78. """
  79. def __init__(self, private_key, key_id=None):
  80. self._key = private_key
  81. self._key_id = key_id
  82. @property # type: ignore
  83. @_helpers.copy_docstring(base.Signer)
  84. def key_id(self):
  85. return self._key_id
  86. @_helpers.copy_docstring(base.Signer)
  87. def sign(self, message):
  88. message = _helpers.to_bytes(message)
  89. return self._key.sign(message, _PADDING, _SHA256)
  90. @classmethod
  91. def from_string(cls, key, key_id=None):
  92. """Construct a RSASigner from a private key in PEM format.
  93. Args:
  94. key (Union[bytes, str]): Private key in PEM format.
  95. key_id (str): An optional key id used to identify the private key.
  96. Returns:
  97. google.auth.crypt._cryptography_rsa.RSASigner: The
  98. constructed signer.
  99. Raises:
  100. ValueError: If ``key`` is not ``bytes`` or ``str`` (unicode).
  101. UnicodeDecodeError: If ``key`` is ``bytes`` but cannot be decoded
  102. into a UTF-8 ``str``.
  103. ValueError: If ``cryptography`` "Could not deserialize key data."
  104. """
  105. key = _helpers.to_bytes(key)
  106. private_key = serialization.load_pem_private_key(
  107. key, password=None, backend=_BACKEND
  108. )
  109. return cls(private_key, key_id=key_id)
  110. def __getstate__(self):
  111. """Pickle helper that serializes the _key attribute."""
  112. state = self.__dict__.copy()
  113. state["_key"] = self._key.private_bytes(
  114. encoding=serialization.Encoding.PEM,
  115. format=serialization.PrivateFormat.PKCS8,
  116. encryption_algorithm=serialization.NoEncryption(),
  117. )
  118. return state
  119. def __setstate__(self, state):
  120. """Pickle helper that deserializes the _key attribute."""
  121. state["_key"] = serialization.load_pem_private_key(state["_key"], None)
  122. self.__dict__.update(state)