blob: 90692166dcaf67b17f2b300006d6f14333774f3f [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')
134 with mock.patch('rsa.pem.load_pem',
135 return_value=true_der + b'extra') as load_pem:
136 with pytest.raises(ValueError):
137 crypt.Verifier.from_string(cert_bytes)
138 load_pem.assert_called_once_with(cert_bytes, 'CERTIFICATE')
139
140
141class TestSigner(object):
142 def test_from_string_pkcs1(self):
143 signer = crypt.Signer.from_string(PKCS1_KEY_BYTES)
144 assert isinstance(signer, crypt.Signer)
145 assert isinstance(signer._key, rsa.key.PrivateKey)
146
147 def test_from_string_pkcs1_unicode(self):
148 key_bytes = _helpers.from_bytes(PKCS1_KEY_BYTES)
149 signer = crypt.Signer.from_string(key_bytes)
150 assert isinstance(signer, crypt.Signer)
151 assert isinstance(signer._key, rsa.key.PrivateKey)
152
153 def test_from_string_pkcs8(self):
154 signer = crypt.Signer.from_string(PKCS8_KEY_BYTES)
155 assert isinstance(signer, crypt.Signer)
156 assert isinstance(signer._key, rsa.key.PrivateKey)
157
158 def test_from_string_pkcs8_extra_bytes(self):
159 key_bytes = PKCS8_KEY_BYTES
160 _, pem_bytes = pem.readPemBlocksFromFile(
161 six.StringIO(_helpers.from_bytes(key_bytes)),
162 crypt._PKCS8_MARKER)
163
164 with mock.patch('pyasn1.codec.der.decoder.decode') as mock_decode:
165 key_info, remaining = None, 'extra'
166 mock_decode.return_value = (key_info, remaining)
167 with pytest.raises(ValueError):
168 crypt.Signer.from_string(key_bytes)
169 # Verify mock was called.
170 mock_decode.assert_called_once_with(
171 pem_bytes, asn1Spec=crypt._PKCS8_SPEC)
172
173 def test_from_string_pkcs8_unicode(self):
174 key_bytes = _helpers.from_bytes(PKCS8_KEY_BYTES)
175 signer = crypt.Signer.from_string(key_bytes)
176 assert isinstance(signer, crypt.Signer)
177 assert isinstance(signer._key, rsa.key.PrivateKey)
178
179 def test_from_string_pkcs12(self):
180 with pytest.raises(ValueError):
181 crypt.Signer.from_string(PKCS12_KEY_BYTES)
182
183 def test_from_string_bogus_key(self):
184 key_bytes = 'bogus-key'
185 with pytest.raises(ValueError):
186 crypt.Signer.from_string(key_bytes)