blob: 33105e414fc090fae4df2310b66317108c21c21b [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
15import os
16
17import mock
18from pyasn1_modules import pem
19import pytest
20import rsa
21import six
22
23from google.auth import _helpers
24from google.auth import crypt
25
26
27DATA_DIR = os.path.join(os.path.dirname(__file__), 'data')
28
29# To generate privatekey.pem, privatekey.pub, and public_cert.pem:
30# $ openssl req -new -newkey rsa:1024 -x509 -nodes -out public_cert.pem \
31# > -keyout privatekey.pem
32# $ openssl rsa -in privatekey.pem -pubout -out privatekey.pub
33
34with open(os.path.join(DATA_DIR, 'privatekey.pem'), 'rb') as fh:
35 PRIVATE_KEY_BYTES = fh.read()
36 PKCS1_KEY_BYTES = PRIVATE_KEY_BYTES
37
38with open(os.path.join(DATA_DIR, 'privatekey.pub'), 'rb') as fh:
39 PUBLIC_KEY_BYTES = fh.read()
40
41with open(os.path.join(DATA_DIR, 'public_cert.pem'), 'rb') as fh:
42 PUBLIC_CERT_BYTES = fh.read()
43
44# To generate other_cert.pem:
45# $ openssl req -new -newkey rsa:1024 -x509 -nodes -out other_cert.pem
46
47with open(os.path.join(DATA_DIR, 'other_cert.pem'), 'rb') as fh:
48 OTHER_CERT_BYTES = fh.read()
49
50# To generate pem_from_pkcs12.pem and privatekey.p12:
51# $ openssl pkcs12 -export -out privatekey.p12 -inkey privatekey.pem \
52# > -in public_cert.pem
53# $ openssl pkcs12 -in privatekey.p12 -nocerts -nodes \
54# > -out pem_from_pkcs12.pem
55
56with open(os.path.join(DATA_DIR, 'pem_from_pkcs12.pem'), 'rb') as fh:
57 PKCS8_KEY_BYTES = fh.read()
58
59with open(os.path.join(DATA_DIR, 'privatekey.p12'), 'rb') as fh:
60 PKCS12_KEY_BYTES = fh.read()
61
62
63def test_verify_signature():
64 to_sign = b'foo'
65 signer = crypt.Signer.from_string(PRIVATE_KEY_BYTES)
66 signature = signer.sign(to_sign)
67
68 assert crypt.verify_signature(
69 to_sign, signature, PUBLIC_CERT_BYTES)
70
71 # List of certs
72 assert crypt.verify_signature(
73 to_sign, signature, [OTHER_CERT_BYTES, PUBLIC_CERT_BYTES])
74
75
76def test_verify_signature_failure():
77 to_sign = b'foo'
78 signer = crypt.Signer.from_string(PRIVATE_KEY_BYTES)
79 signature = signer.sign(to_sign)
80
81 assert not crypt.verify_signature(
82 to_sign, signature, OTHER_CERT_BYTES)
83
84
85class TestVerifier(object):
86 def test_verify_success(self):
87 to_sign = b'foo'
88 signer = crypt.Signer.from_string(PRIVATE_KEY_BYTES)
89 actual_signature = signer.sign(to_sign)
90
91 verifier = crypt.Verifier.from_string(PUBLIC_KEY_BYTES)
92 assert verifier.verify(to_sign, actual_signature)
93
94 def test_verify_unicode_success(self):
95 to_sign = u'foo'
96 signer = crypt.Signer.from_string(PRIVATE_KEY_BYTES)
97 actual_signature = signer.sign(to_sign)
98
99 verifier = crypt.Verifier.from_string(PUBLIC_KEY_BYTES)
100 assert verifier.verify(to_sign, actual_signature)
101
102 def test_verify_failure(self):
103 verifier = crypt.Verifier.from_string(PUBLIC_KEY_BYTES)
104 bad_signature1 = b''
105 assert not verifier.verify(b'foo', bad_signature1)
106 bad_signature2 = b'a'
107 assert not verifier.verify(b'foo', bad_signature2)
108
109 def test_from_string_pub_key(self):
110 verifier = crypt.Verifier.from_string(PUBLIC_KEY_BYTES)
111 assert isinstance(verifier, crypt.Verifier)
112 assert isinstance(verifier._pubkey, rsa.key.PublicKey)
113
114 def test_from_string_pub_key_unicode(self):
115 public_key = _helpers.from_bytes(PUBLIC_KEY_BYTES)
116 verifier = crypt.Verifier.from_string(public_key)
117 assert isinstance(verifier, crypt.Verifier)
118 assert isinstance(verifier._pubkey, rsa.key.PublicKey)
119
120 def test_from_string_pub_cert(self):
121 verifier = crypt.Verifier.from_string(PUBLIC_CERT_BYTES)
122 assert isinstance(verifier, crypt.Verifier)
123 assert isinstance(verifier._pubkey, rsa.key.PublicKey)
124
125 def test_from_string_pub_cert_unicode(self):
126 public_cert = _helpers.from_bytes(PUBLIC_CERT_BYTES)
127 verifier = crypt.Verifier.from_string(public_cert)
128 assert isinstance(verifier, crypt.Verifier)
129 assert isinstance(verifier._pubkey, rsa.key.PublicKey)
130
131 def test_from_string_pub_cert_failure(self):
132 cert_bytes = PUBLIC_CERT_BYTES
133 true_der = rsa.pem.load_pem(cert_bytes, 'CERTIFICATE')
Jon Wayne Parrott8784b232016-11-10 12:53:55 -0800134 load_pem_patch = mock.patch(
135 'rsa.pem.load_pem', return_value=true_der + b'extra',
136 autospec=True)
137
138 with load_pem_patch as load_pem:
Jon Wayne Parrott8713a712016-10-04 14:19:01 -0700139 with pytest.raises(ValueError):
140 crypt.Verifier.from_string(cert_bytes)
141 load_pem.assert_called_once_with(cert_bytes, 'CERTIFICATE')
142
143
144class TestSigner(object):
145 def test_from_string_pkcs1(self):
146 signer = crypt.Signer.from_string(PKCS1_KEY_BYTES)
147 assert isinstance(signer, crypt.Signer)
148 assert isinstance(signer._key, rsa.key.PrivateKey)
149
150 def test_from_string_pkcs1_unicode(self):
151 key_bytes = _helpers.from_bytes(PKCS1_KEY_BYTES)
152 signer = crypt.Signer.from_string(key_bytes)
153 assert isinstance(signer, crypt.Signer)
154 assert isinstance(signer._key, rsa.key.PrivateKey)
155
156 def test_from_string_pkcs8(self):
157 signer = crypt.Signer.from_string(PKCS8_KEY_BYTES)
158 assert isinstance(signer, crypt.Signer)
159 assert isinstance(signer._key, rsa.key.PrivateKey)
160
161 def test_from_string_pkcs8_extra_bytes(self):
162 key_bytes = PKCS8_KEY_BYTES
163 _, pem_bytes = pem.readPemBlocksFromFile(
164 six.StringIO(_helpers.from_bytes(key_bytes)),
165 crypt._PKCS8_MARKER)
166
Jon Wayne Parrott8784b232016-11-10 12:53:55 -0800167 key_info, remaining = None, 'extra'
168 decode_patch = mock.patch(
169 'pyasn1.codec.der.decoder.decode',
170 return_value=(key_info, remaining),
171 autospec=True)
172
173 with decode_patch as decode:
Jon Wayne Parrott8713a712016-10-04 14:19:01 -0700174 with pytest.raises(ValueError):
175 crypt.Signer.from_string(key_bytes)
176 # Verify mock was called.
Jon Wayne Parrott8784b232016-11-10 12:53:55 -0800177 decode.assert_called_once_with(
Jon Wayne Parrott8713a712016-10-04 14:19:01 -0700178 pem_bytes, asn1Spec=crypt._PKCS8_SPEC)
179
180 def test_from_string_pkcs8_unicode(self):
181 key_bytes = _helpers.from_bytes(PKCS8_KEY_BYTES)
182 signer = crypt.Signer.from_string(key_bytes)
183 assert isinstance(signer, crypt.Signer)
184 assert isinstance(signer._key, rsa.key.PrivateKey)
185
186 def test_from_string_pkcs12(self):
187 with pytest.raises(ValueError):
188 crypt.Signer.from_string(PKCS12_KEY_BYTES)
189
190 def test_from_string_bogus_key(self):
191 key_bytes = 'bogus-key'
192 with pytest.raises(ValueError):
193 crypt.Signer.from_string(key_bytes)