blob: 56612dae31e0035d84d6fc4ae3e9db8d3892bb84 [file] [log] [blame]
Jon Wayne Parrott8713a712016-10-04 14:19:01 -07001# Copyright 2016 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
Jon Wayne Parrottfc169292016-12-13 16:02:40 -080015import json
Jon Wayne Parrott54451fb2016-12-14 12:20:24 -080016import os
Jon Wayne Parrott8713a712016-10-04 14:19:01 -070017
18import mock
19from pyasn1_modules import pem
20import pytest
21import rsa
22import six
23
24from google.auth import _helpers
25from google.auth import crypt
26
27
28DATA_DIR = os.path.join(os.path.dirname(__file__), 'data')
29
30# To generate privatekey.pem, privatekey.pub, and public_cert.pem:
31# $ openssl req -new -newkey rsa:1024 -x509 -nodes -out public_cert.pem \
32# > -keyout privatekey.pem
33# $ openssl rsa -in privatekey.pem -pubout -out privatekey.pub
34
35with open(os.path.join(DATA_DIR, 'privatekey.pem'), 'rb') as fh:
36 PRIVATE_KEY_BYTES = fh.read()
37 PKCS1_KEY_BYTES = PRIVATE_KEY_BYTES
38
39with open(os.path.join(DATA_DIR, 'privatekey.pub'), 'rb') as fh:
40 PUBLIC_KEY_BYTES = fh.read()
41
42with open(os.path.join(DATA_DIR, 'public_cert.pem'), 'rb') as fh:
43 PUBLIC_CERT_BYTES = fh.read()
44
45# To generate other_cert.pem:
46# $ openssl req -new -newkey rsa:1024 -x509 -nodes -out other_cert.pem
47
48with open(os.path.join(DATA_DIR, 'other_cert.pem'), 'rb') as fh:
49 OTHER_CERT_BYTES = fh.read()
50
51# To generate pem_from_pkcs12.pem and privatekey.p12:
52# $ openssl pkcs12 -export -out privatekey.p12 -inkey privatekey.pem \
53# > -in public_cert.pem
54# $ openssl pkcs12 -in privatekey.p12 -nocerts -nodes \
55# > -out pem_from_pkcs12.pem
56
57with open(os.path.join(DATA_DIR, 'pem_from_pkcs12.pem'), 'rb') as fh:
58 PKCS8_KEY_BYTES = fh.read()
59
60with open(os.path.join(DATA_DIR, 'privatekey.p12'), 'rb') as fh:
61 PKCS12_KEY_BYTES = fh.read()
62
Jon Wayne Parrottfc169292016-12-13 16:02:40 -080063# The service account JSON file can be generated from the Google Cloud Console.
64SERVICE_ACCOUNT_JSON_FILE = os.path.join(DATA_DIR, 'service_account.json')
65
66with open(SERVICE_ACCOUNT_JSON_FILE, 'r') as fh:
67 SERVICE_ACCOUNT_INFO = json.load(fh)
68
Jon Wayne Parrott8713a712016-10-04 14:19:01 -070069
70def test_verify_signature():
71 to_sign = b'foo'
Jon Wayne Parrott254befe2017-02-22 14:37:31 -080072 signer = crypt.RSASigner.from_string(PRIVATE_KEY_BYTES)
Jon Wayne Parrott8713a712016-10-04 14:19:01 -070073 signature = signer.sign(to_sign)
74
75 assert crypt.verify_signature(
76 to_sign, signature, PUBLIC_CERT_BYTES)
77
78 # List of certs
79 assert crypt.verify_signature(
80 to_sign, signature, [OTHER_CERT_BYTES, PUBLIC_CERT_BYTES])
81
82
83def test_verify_signature_failure():
84 to_sign = b'foo'
Jon Wayne Parrott254befe2017-02-22 14:37:31 -080085 signer = crypt.RSASigner.from_string(PRIVATE_KEY_BYTES)
Jon Wayne Parrott8713a712016-10-04 14:19:01 -070086 signature = signer.sign(to_sign)
87
88 assert not crypt.verify_signature(
89 to_sign, signature, OTHER_CERT_BYTES)
90
91
Jon Wayne Parrott254befe2017-02-22 14:37:31 -080092class TestRSAVerifier(object):
Jon Wayne Parrott8713a712016-10-04 14:19:01 -070093 def test_verify_success(self):
94 to_sign = b'foo'
Jon Wayne Parrott254befe2017-02-22 14:37:31 -080095 signer = crypt.RSASigner.from_string(PRIVATE_KEY_BYTES)
Jon Wayne Parrott8713a712016-10-04 14:19:01 -070096 actual_signature = signer.sign(to_sign)
97
Jon Wayne Parrott254befe2017-02-22 14:37:31 -080098 verifier = crypt.RSAVerifier.from_string(PUBLIC_KEY_BYTES)
Jon Wayne Parrott8713a712016-10-04 14:19:01 -070099 assert verifier.verify(to_sign, actual_signature)
100
101 def test_verify_unicode_success(self):
102 to_sign = u'foo'
Jon Wayne Parrott254befe2017-02-22 14:37:31 -0800103 signer = crypt.RSASigner.from_string(PRIVATE_KEY_BYTES)
Jon Wayne Parrott8713a712016-10-04 14:19:01 -0700104 actual_signature = signer.sign(to_sign)
105
Jon Wayne Parrott254befe2017-02-22 14:37:31 -0800106 verifier = crypt.RSAVerifier.from_string(PUBLIC_KEY_BYTES)
Jon Wayne Parrott8713a712016-10-04 14:19:01 -0700107 assert verifier.verify(to_sign, actual_signature)
108
109 def test_verify_failure(self):
Jon Wayne Parrott254befe2017-02-22 14:37:31 -0800110 verifier = crypt.RSAVerifier.from_string(PUBLIC_KEY_BYTES)
Jon Wayne Parrott8713a712016-10-04 14:19:01 -0700111 bad_signature1 = b''
112 assert not verifier.verify(b'foo', bad_signature1)
113 bad_signature2 = b'a'
114 assert not verifier.verify(b'foo', bad_signature2)
115
116 def test_from_string_pub_key(self):
Jon Wayne Parrott254befe2017-02-22 14:37:31 -0800117 verifier = crypt.RSAVerifier.from_string(PUBLIC_KEY_BYTES)
118 assert isinstance(verifier, crypt.RSAVerifier)
Jon Wayne Parrott8713a712016-10-04 14:19:01 -0700119 assert isinstance(verifier._pubkey, rsa.key.PublicKey)
120
121 def test_from_string_pub_key_unicode(self):
122 public_key = _helpers.from_bytes(PUBLIC_KEY_BYTES)
Jon Wayne Parrott254befe2017-02-22 14:37:31 -0800123 verifier = crypt.RSAVerifier.from_string(public_key)
124 assert isinstance(verifier, crypt.RSAVerifier)
Jon Wayne Parrott8713a712016-10-04 14:19:01 -0700125 assert isinstance(verifier._pubkey, rsa.key.PublicKey)
126
127 def test_from_string_pub_cert(self):
Jon Wayne Parrott254befe2017-02-22 14:37:31 -0800128 verifier = crypt.RSAVerifier.from_string(PUBLIC_CERT_BYTES)
129 assert isinstance(verifier, crypt.RSAVerifier)
Jon Wayne Parrott8713a712016-10-04 14:19:01 -0700130 assert isinstance(verifier._pubkey, rsa.key.PublicKey)
131
132 def test_from_string_pub_cert_unicode(self):
133 public_cert = _helpers.from_bytes(PUBLIC_CERT_BYTES)
Jon Wayne Parrott254befe2017-02-22 14:37:31 -0800134 verifier = crypt.RSAVerifier.from_string(public_cert)
135 assert isinstance(verifier, crypt.RSAVerifier)
Jon Wayne Parrott8713a712016-10-04 14:19:01 -0700136 assert isinstance(verifier._pubkey, rsa.key.PublicKey)
137
138 def test_from_string_pub_cert_failure(self):
139 cert_bytes = PUBLIC_CERT_BYTES
140 true_der = rsa.pem.load_pem(cert_bytes, 'CERTIFICATE')
Jon Wayne Parrott8784b232016-11-10 12:53:55 -0800141 load_pem_patch = mock.patch(
142 'rsa.pem.load_pem', return_value=true_der + b'extra',
143 autospec=True)
144
145 with load_pem_patch as load_pem:
Jon Wayne Parrott8713a712016-10-04 14:19:01 -0700146 with pytest.raises(ValueError):
Jon Wayne Parrott254befe2017-02-22 14:37:31 -0800147 crypt.RSAVerifier.from_string(cert_bytes)
Jon Wayne Parrott8713a712016-10-04 14:19:01 -0700148 load_pem.assert_called_once_with(cert_bytes, 'CERTIFICATE')
149
150
Jon Wayne Parrott254befe2017-02-22 14:37:31 -0800151class TestRSASigner(object):
Jon Wayne Parrott8713a712016-10-04 14:19:01 -0700152 def test_from_string_pkcs1(self):
Jon Wayne Parrott254befe2017-02-22 14:37:31 -0800153 signer = crypt.RSASigner.from_string(PKCS1_KEY_BYTES)
154 assert isinstance(signer, crypt.RSASigner)
Jon Wayne Parrott8713a712016-10-04 14:19:01 -0700155 assert isinstance(signer._key, rsa.key.PrivateKey)
156
157 def test_from_string_pkcs1_unicode(self):
158 key_bytes = _helpers.from_bytes(PKCS1_KEY_BYTES)
Jon Wayne Parrott254befe2017-02-22 14:37:31 -0800159 signer = crypt.RSASigner.from_string(key_bytes)
160 assert isinstance(signer, crypt.RSASigner)
Jon Wayne Parrott8713a712016-10-04 14:19:01 -0700161 assert isinstance(signer._key, rsa.key.PrivateKey)
162
163 def test_from_string_pkcs8(self):
Jon Wayne Parrott254befe2017-02-22 14:37:31 -0800164 signer = crypt.RSASigner.from_string(PKCS8_KEY_BYTES)
165 assert isinstance(signer, crypt.RSASigner)
Jon Wayne Parrott8713a712016-10-04 14:19:01 -0700166 assert isinstance(signer._key, rsa.key.PrivateKey)
167
168 def test_from_string_pkcs8_extra_bytes(self):
169 key_bytes = PKCS8_KEY_BYTES
170 _, pem_bytes = pem.readPemBlocksFromFile(
171 six.StringIO(_helpers.from_bytes(key_bytes)),
172 crypt._PKCS8_MARKER)
173
Jon Wayne Parrott8784b232016-11-10 12:53:55 -0800174 key_info, remaining = None, 'extra'
175 decode_patch = mock.patch(
176 'pyasn1.codec.der.decoder.decode',
177 return_value=(key_info, remaining),
178 autospec=True)
179
180 with decode_patch as decode:
Jon Wayne Parrott8713a712016-10-04 14:19:01 -0700181 with pytest.raises(ValueError):
Jon Wayne Parrott254befe2017-02-22 14:37:31 -0800182 crypt.RSASigner.from_string(key_bytes)
Jon Wayne Parrott8713a712016-10-04 14:19:01 -0700183 # Verify mock was called.
Jon Wayne Parrott8784b232016-11-10 12:53:55 -0800184 decode.assert_called_once_with(
Jon Wayne Parrott8713a712016-10-04 14:19:01 -0700185 pem_bytes, asn1Spec=crypt._PKCS8_SPEC)
186
187 def test_from_string_pkcs8_unicode(self):
188 key_bytes = _helpers.from_bytes(PKCS8_KEY_BYTES)
Jon Wayne Parrott254befe2017-02-22 14:37:31 -0800189 signer = crypt.RSASigner.from_string(key_bytes)
190 assert isinstance(signer, crypt.RSASigner)
Jon Wayne Parrott8713a712016-10-04 14:19:01 -0700191 assert isinstance(signer._key, rsa.key.PrivateKey)
192
193 def test_from_string_pkcs12(self):
194 with pytest.raises(ValueError):
Jon Wayne Parrott254befe2017-02-22 14:37:31 -0800195 crypt.RSASigner.from_string(PKCS12_KEY_BYTES)
Jon Wayne Parrott8713a712016-10-04 14:19:01 -0700196
197 def test_from_string_bogus_key(self):
198 key_bytes = 'bogus-key'
199 with pytest.raises(ValueError):
Jon Wayne Parrott254befe2017-02-22 14:37:31 -0800200 crypt.RSASigner.from_string(key_bytes)
Jon Wayne Parrottfc169292016-12-13 16:02:40 -0800201
Jon Wayne Parrott54451fb2016-12-14 12:20:24 -0800202 def test_from_service_account_info(self):
Jon Wayne Parrott254befe2017-02-22 14:37:31 -0800203 signer = crypt.RSASigner.from_service_account_info(
204 SERVICE_ACCOUNT_INFO)
Jon Wayne Parrott54451fb2016-12-14 12:20:24 -0800205
206 assert signer.key_id == SERVICE_ACCOUNT_INFO[
207 crypt._JSON_FILE_PRIVATE_KEY_ID]
208 assert isinstance(signer._key, rsa.key.PrivateKey)
209
210 def test_from_service_account_info_missing_key(self):
211 with pytest.raises(ValueError) as excinfo:
Jon Wayne Parrott254befe2017-02-22 14:37:31 -0800212 crypt.RSASigner.from_service_account_info({})
Jon Wayne Parrott54451fb2016-12-14 12:20:24 -0800213
214 assert excinfo.match(crypt._JSON_FILE_PRIVATE_KEY)
215
Jon Wayne Parrottfc169292016-12-13 16:02:40 -0800216 def test_from_service_account_file(self):
Jon Wayne Parrott254befe2017-02-22 14:37:31 -0800217 signer = crypt.RSASigner.from_service_account_file(
Jon Wayne Parrottfc169292016-12-13 16:02:40 -0800218 SERVICE_ACCOUNT_JSON_FILE)
219
Jon Wayne Parrott54451fb2016-12-14 12:20:24 -0800220 assert signer.key_id == SERVICE_ACCOUNT_INFO[
221 crypt._JSON_FILE_PRIVATE_KEY_ID]
Jon Wayne Parrottfc169292016-12-13 16:02:40 -0800222 assert isinstance(signer._key, rsa.key.PrivateKey)