Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/google/auth/crypt/_python_rsa.py: 43%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

79 statements  

1# Copyright 2016 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 

15"""Pure-Python RSA cryptography implementation. 

16 

17Uses the ``rsa``, ``pyasn1`` and ``pyasn1_modules`` packages 

18to parse PEM files storing PKCS#1 or PKCS#8 keys as well as 

19certificates. There is no support for p12 files. 

20""" 

21 

22from __future__ import absolute_import 

23 

24import io 

25import warnings 

26 

27from pyasn1.codec.der import decoder # type: ignore 

28from pyasn1_modules import pem # type: ignore 

29from pyasn1_modules.rfc2459 import Certificate # type: ignore 

30from pyasn1_modules.rfc5208 import PrivateKeyInfo # type: ignore 

31import rsa # type: ignore 

32 

33from google.auth import _helpers 

34from google.auth import exceptions 

35from google.auth.crypt import base 

36 

37_POW2 = (128, 64, 32, 16, 8, 4, 2, 1) 

38_CERTIFICATE_MARKER = b"-----BEGIN CERTIFICATE-----" 

39_PKCS1_MARKER = ("-----BEGIN RSA PRIVATE KEY-----", "-----END RSA PRIVATE KEY-----") 

40_PKCS8_MARKER = ("-----BEGIN PRIVATE KEY-----", "-----END PRIVATE KEY-----") 

41_PKCS8_SPEC = PrivateKeyInfo() 

42 

43_warning_msg = ( 

44 "The 'rsa' library is deprecated and will be removed in a future release. " 

45 "Please migrate to 'cryptography'." 

46) 

47 

48 

49def _bit_list_to_bytes(bit_list): 

50 """Converts an iterable of 1s and 0s to bytes. 

51 

52 Combines the list 8 at a time, treating each group of 8 bits 

53 as a single byte. 

54 

55 Args: 

56 bit_list (Sequence): Sequence of 1s and 0s. 

57 

58 Returns: 

59 bytes: The decoded bytes. 

60 """ 

61 num_bits = len(bit_list) 

62 byte_vals = bytearray() 

63 for start in range(0, num_bits, 8): 

64 curr_bits = bit_list[start : start + 8] 

65 char_val = sum(val * digit for val, digit in zip(_POW2, curr_bits)) 

66 byte_vals.append(char_val) 

67 return bytes(byte_vals) 

68 

69 

70class RSAVerifier(base.Verifier): 

71 """Verifies RSA cryptographic signatures using public keys. 

72 

73 .. deprecated:: 

74 The `rsa` library has been archived. Please migrate to 

75 `cryptography`. 

76 

77 Args: 

78 public_key (rsa.key.PublicKey): The public key used to verify 

79 signatures. 

80 """ 

81 

82 def __init__(self, public_key): 

83 warnings.warn( 

84 _warning_msg, 

85 category=DeprecationWarning, 

86 stacklevel=2, 

87 ) 

88 self._pubkey = public_key 

89 

90 @_helpers.copy_docstring(base.Verifier) 

91 def verify(self, message, signature): 

92 message = _helpers.to_bytes(message) 

93 try: 

94 return rsa.pkcs1.verify(message, signature, self._pubkey) 

95 except (ValueError, rsa.pkcs1.VerificationError): 

96 return False 

97 

98 @classmethod 

99 def from_string(cls, public_key): 

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

101 certificate string. 

102 

103 Args: 

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

105 x509 public key certificate. 

106 

107 Returns: 

108 google.auth.crypt._python_rsa.RSAVerifier: The constructed verifier. 

109 

110 Raises: 

111 ValueError: If the public_key can't be parsed. 

112 """ 

113 public_key = _helpers.to_bytes(public_key) 

114 is_x509_cert = _CERTIFICATE_MARKER in public_key 

115 

116 # If this is a certificate, extract the public key info. 

117 if is_x509_cert: 

118 der = rsa.pem.load_pem(public_key, "CERTIFICATE") 

119 asn1_cert, remaining = decoder.decode(der, asn1Spec=Certificate()) 

120 if remaining != b"": 

121 raise exceptions.InvalidValue("Unused bytes", remaining) 

122 

123 cert_info = asn1_cert["tbsCertificate"]["subjectPublicKeyInfo"] 

124 key_bytes = _bit_list_to_bytes(cert_info["subjectPublicKey"]) 

125 pubkey = rsa.PublicKey.load_pkcs1(key_bytes, "DER") 

126 else: 

127 pubkey = rsa.PublicKey.load_pkcs1(public_key, "PEM") 

128 return cls(pubkey) 

129 

130 

131class RSASigner(base.Signer, base.FromServiceAccountMixin): 

132 """Signs messages with an RSA private key. 

133 

134 .. deprecated:: 

135 The `rsa` library has been archived. Please migrate to 

136 `cryptography`. 

137 

138 Args: 

139 private_key (rsa.key.PrivateKey): The private key to sign with. 

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

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

142 public key or certificate. 

143 """ 

144 

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

146 warnings.warn( 

147 _warning_msg, 

148 category=DeprecationWarning, 

149 stacklevel=2, 

150 ) 

151 self._key = private_key 

152 self._key_id = key_id 

153 

154 @property # type: ignore 

155 @_helpers.copy_docstring(base.Signer) 

156 def key_id(self): 

157 return self._key_id 

158 

159 @_helpers.copy_docstring(base.Signer) 

160 def sign(self, message): 

161 message = _helpers.to_bytes(message) 

162 return rsa.pkcs1.sign(message, self._key, "SHA-256") 

163 

164 @classmethod 

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

166 """Construct an Signer instance from a private key in PEM format. 

167 

168 Args: 

169 key (str): Private key in PEM format. 

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

171 

172 Returns: 

173 google.auth.crypt.Signer: The constructed signer. 

174 

175 Raises: 

176 ValueError: If the key cannot be parsed as PKCS#1 or PKCS#8 in 

177 PEM format. 

178 """ 

179 key = _helpers.from_bytes(key) # PEM expects str in Python 3 

180 marker_id, key_bytes = pem.readPemBlocksFromFile( 

181 io.StringIO(key), _PKCS1_MARKER, _PKCS8_MARKER 

182 ) 

183 

184 # Key is in pkcs1 format. 

185 if marker_id == 0: 

186 private_key = rsa.key.PrivateKey.load_pkcs1(key_bytes, format="DER") 

187 # Key is in pkcs8. 

188 elif marker_id == 1: 

189 key_info, remaining = decoder.decode(key_bytes, asn1Spec=_PKCS8_SPEC) 

190 if remaining != b"": 

191 raise exceptions.InvalidValue("Unused bytes", remaining) 

192 private_key_info = key_info.getComponentByName("privateKey") 

193 private_key = rsa.key.PrivateKey.load_pkcs1( 

194 private_key_info.asOctets(), format="DER" 

195 ) 

196 else: 

197 raise exceptions.MalformedError("No key could be detected.") 

198 

199 return cls(private_key, key_id=key_id)