Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/google/auth/crypt/es256.py: 3%

67 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2023-12-08 06:51 +0000

1# Copyright 2017 Google Inc. 

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 

15"""ECDSA (ES256) verifier and signer that use the ``cryptography`` library. 

16""" 

17 

18from cryptography import utils # type: ignore 

19import cryptography.exceptions 

20from cryptography.hazmat import backends 

21from cryptography.hazmat.primitives import hashes 

22from cryptography.hazmat.primitives import serialization 

23from cryptography.hazmat.primitives.asymmetric import ec 

24from cryptography.hazmat.primitives.asymmetric import padding 

25from cryptography.hazmat.primitives.asymmetric.utils import decode_dss_signature 

26from cryptography.hazmat.primitives.asymmetric.utils import encode_dss_signature 

27import cryptography.x509 

28 

29from google.auth import _helpers 

30from google.auth.crypt import base 

31 

32 

33_CERTIFICATE_MARKER = b"-----BEGIN CERTIFICATE-----" 

34_BACKEND = backends.default_backend() 

35_PADDING = padding.PKCS1v15() 

36 

37 

38class ES256Verifier(base.Verifier): 

39 """Verifies ECDSA cryptographic signatures using public keys. 

40 

41 Args: 

42 public_key ( 

43 cryptography.hazmat.primitives.asymmetric.ec.ECDSAPublicKey): 

44 The public key used to verify signatures. 

45 """ 

46 

47 def __init__(self, public_key): 

48 self._pubkey = public_key 

49 

50 @_helpers.copy_docstring(base.Verifier) 

51 def verify(self, message, signature): 

52 # First convert (r||s) raw signature to ASN1 encoded signature. 

53 sig_bytes = _helpers.to_bytes(signature) 

54 if len(sig_bytes) != 64: 

55 return False 

56 r = ( 

57 int.from_bytes(sig_bytes[:32], byteorder="big") 

58 if _helpers.is_python_3() 

59 else utils.int_from_bytes(sig_bytes[:32], byteorder="big") 

60 ) 

61 s = ( 

62 int.from_bytes(sig_bytes[32:], byteorder="big") 

63 if _helpers.is_python_3() 

64 else utils.int_from_bytes(sig_bytes[32:], byteorder="big") 

65 ) 

66 asn1_sig = encode_dss_signature(r, s) 

67 

68 message = _helpers.to_bytes(message) 

69 try: 

70 self._pubkey.verify(asn1_sig, message, ec.ECDSA(hashes.SHA256())) 

71 return True 

72 except (ValueError, cryptography.exceptions.InvalidSignature): 

73 return False 

74 

75 @classmethod 

76 def from_string(cls, public_key): 

77 """Construct an Verifier instance from a public key or public 

78 certificate string. 

79 

80 Args: 

81 public_key (Union[str, bytes]): The public key in PEM format or the 

82 x509 public key certificate. 

83 

84 Returns: 

85 Verifier: The constructed verifier. 

86 

87 Raises: 

88 ValueError: If the public key can't be parsed. 

89 """ 

90 public_key_data = _helpers.to_bytes(public_key) 

91 

92 if _CERTIFICATE_MARKER in public_key_data: 

93 cert = cryptography.x509.load_pem_x509_certificate( 

94 public_key_data, _BACKEND 

95 ) 

96 pubkey = cert.public_key() 

97 

98 else: 

99 pubkey = serialization.load_pem_public_key(public_key_data, _BACKEND) 

100 

101 return cls(pubkey) 

102 

103 

104class ES256Signer(base.Signer, base.FromServiceAccountMixin): 

105 """Signs messages with an ECDSA private key. 

106 

107 Args: 

108 private_key ( 

109 cryptography.hazmat.primitives.asymmetric.ec.ECDSAPrivateKey): 

110 The private key to sign with. 

111 key_id (str): Optional key ID used to identify this private key. This 

112 can be useful to associate the private key with its associated 

113 public key or certificate. 

114 """ 

115 

116 def __init__(self, private_key, key_id=None): 

117 self._key = private_key 

118 self._key_id = key_id 

119 

120 @property # type: ignore 

121 @_helpers.copy_docstring(base.Signer) 

122 def key_id(self): 

123 return self._key_id 

124 

125 @_helpers.copy_docstring(base.Signer) 

126 def sign(self, message): 

127 message = _helpers.to_bytes(message) 

128 asn1_signature = self._key.sign(message, ec.ECDSA(hashes.SHA256())) 

129 

130 # Convert ASN1 encoded signature to (r||s) raw signature. 

131 (r, s) = decode_dss_signature(asn1_signature) 

132 return ( 

133 (r.to_bytes(32, byteorder="big") + s.to_bytes(32, byteorder="big")) 

134 if _helpers.is_python_3() 

135 else (utils.int_to_bytes(r, 32) + utils.int_to_bytes(s, 32)) 

136 ) 

137 

138 @classmethod 

139 def from_string(cls, key, key_id=None): 

140 """Construct a RSASigner from a private key in PEM format. 

141 

142 Args: 

143 key (Union[bytes, str]): Private key in PEM format. 

144 key_id (str): An optional key id used to identify the private key. 

145 

146 Returns: 

147 google.auth.crypt._cryptography_rsa.RSASigner: The 

148 constructed signer. 

149 

150 Raises: 

151 ValueError: If ``key`` is not ``bytes`` or ``str`` (unicode). 

152 UnicodeDecodeError: If ``key`` is ``bytes`` but cannot be decoded 

153 into a UTF-8 ``str``. 

154 ValueError: If ``cryptography`` "Could not deserialize key data." 

155 """ 

156 key = _helpers.to_bytes(key) 

157 private_key = serialization.load_pem_private_key( 

158 key, password=None, backend=_BACKEND 

159 ) 

160 return cls(private_key, key_id=key_id) 

161 

162 def __getstate__(self): 

163 """Pickle helper that serializes the _key attribute.""" 

164 state = self.__dict__.copy() 

165 state["_key"] = self._key.private_bytes( 

166 encoding=serialization.Encoding.PEM, 

167 format=serialization.PrivateFormat.PKCS8, 

168 encryption_algorithm=serialization.NoEncryption(), 

169 ) 

170 return state 

171 

172 def __setstate__(self, state): 

173 """Pickle helper that deserializes the _key attribute.""" 

174 state["_key"] = serialization.load_pem_private_key(state["_key"], None) 

175 self.__dict__.update(state)