Skip to content

Commit 4d02099

Browse files
committed
Moving private_key_as_pem->pkcs12_key_as_pem.
Also only defining if OpenSSL is installed and conditionally defining a method which raises NotImplementedError if not defined.
1 parent bb2e770 commit 4d02099

File tree

3 files changed

+94
-78
lines changed

3 files changed

+94
-78
lines changed

oauth2client/crypt.py

Lines changed: 21 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -137,9 +137,30 @@ def from_string(key, password=b'notasecret'):
137137
password = password.encode('utf-8')
138138
pkey = crypto.load_pkcs12(key, password).get_privatekey()
139139
return OpenSSLSigner(pkey)
140+
141+
142+
def pkcs12_key_as_pem(private_key_text, private_key_password):
143+
"""Convert the contents of a PKCS12 key to PEM using OpenSSL.
144+
145+
Args:
146+
private_key_text: String. Private key.
147+
private_key_password: String. Password for PKCS12.
148+
149+
Returns:
150+
String. PEM contents of ``private_key_text``.
151+
"""
152+
decoded_body = base64.b64decode(private_key_text)
153+
if isinstance(private_key_password, six.string_types):
154+
private_key_password = private_key_password.encode('ascii')
155+
156+
pkcs12 = crypto.load_pkcs12(decoded_body, private_key_password)
157+
return crypto.dump_privatekey(crypto.FILETYPE_PEM,
158+
pkcs12.get_privatekey())
140159
except ImportError:
141160
OpenSSLVerifier = None
142161
OpenSSLSigner = None
162+
def pkcs12_key_as_pem(*args, **kwargs):
163+
raise NotImplementedError('pkcs12_key_as_pem requires OpenSSL.')
143164

144165

145166
try:
@@ -286,39 +307,6 @@ def _parse_pem_key(raw_key_input):
286307
return raw_key_input[offset:]
287308

288309

289-
def private_key_as_pem(private_key_text, private_key_password=None):
290-
"""Convert the contents of a key to PEM.
291-
292-
First tries to determine if the current key is PEM, then tries to
293-
use OpenSSL to convert from PKCS12 to PEM.
294-
295-
Args:
296-
private_key_text: String. Private key.
297-
private_key_password: Optional string. Password for PKCS12.
298-
299-
Returns:
300-
String. PEM contents of ``private_key_text``.
301-
302-
Raises:
303-
ImportError: If key is PKCS12 and OpenSSL is not installed.
304-
"""
305-
decoded_body = base64.b64decode(private_key_text)
306-
pem_contents = _parse_pem_key(decoded_body)
307-
if pem_contents is None:
308-
if OpenSSLVerifier is None or OpenSSLSigner is None:
309-
raise ImportError('OpenSSL not installed. Required to convert '
310-
'PKCS12 key to PEM.')
311-
312-
if isinstance(private_key_password, six.string_types):
313-
private_key_password = private_key_password.encode('ascii')
314-
315-
pkcs12 = crypto.load_pkcs12(decoded_body, private_key_password)
316-
pem_contents = crypto.dump_privatekey(crypto.FILETYPE_PEM,
317-
pkcs12.get_privatekey())
318-
319-
return pem_contents
320-
321-
322310
def _urlsafe_b64encode(raw_bytes):
323311
if isinstance(raw_bytes, six.text_type):
324312
raw_bytes = raw_bytes.encode('utf-8')

tests/test_crypt.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# Copyright 2014 Google Inc. All rights reserved.
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+
import mock
16+
import os
17+
import sys
18+
import unittest
19+
20+
try:
21+
reload
22+
except NameError:
23+
# For Python3 (though importlib should be used, silly 3.3).
24+
from imp import reload
25+
26+
from oauth2client.client import HAS_OPENSSL
27+
from oauth2client.client import SignedJwtAssertionCredentials
28+
from oauth2client import crypt
29+
30+
31+
def datafile(filename):
32+
f = open(os.path.join(os.path.dirname(__file__), 'data', filename), 'rb')
33+
data = f.read()
34+
f.close()
35+
return data
36+
37+
38+
class Test_pkcs12_key_as_pem(unittest.TestCase):
39+
40+
def _make_signed_jwt_creds(self, private_key_file='privatekey.p12',
41+
private_key=None):
42+
private_key = private_key or datafile(private_key_file)
43+
return SignedJwtAssertionCredentials(
44+
45+
private_key,
46+
scope='read+write',
47+
48+
49+
def test_succeeds(self):
50+
self.assertEqual(True, HAS_OPENSSL)
51+
52+
credentials = self._make_signed_jwt_creds()
53+
pem_contents = crypt.pkcs12_key_as_pem(credentials.private_key,
54+
credentials.private_key_password)
55+
pkcs12_key_as_pem = datafile('pem_from_pkcs12.pem')
56+
pkcs12_key_as_pem = crypt._parse_pem_key(pkcs12_key_as_pem)
57+
self.assertEqual(pem_contents, pkcs12_key_as_pem)
58+
59+
def test_without_openssl(self):
60+
openssl_mod = sys.modules['OpenSSL']
61+
try:
62+
sys.modules['OpenSSL'] = None
63+
reload(crypt)
64+
self.assertRaises(NotImplementedError, crypt.pkcs12_key_as_pem,
65+
'FOO', 'BAR')
66+
finally:
67+
sys.modules['OpenSSL'] = openssl_mod
68+
reload(crypt)
69+
70+
def test_with_nonsense_key(self):
71+
credentials = self._make_signed_jwt_creds(private_key=b'NOT_A_KEY')
72+
self.assertRaises(crypt.crypto.Error, crypt.pkcs12_key_as_pem,
73+
credentials.private_key, credentials.private_key_password)

tests/test_jwt.py

Lines changed: 0 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -188,51 +188,6 @@ def test_verify_id_token_bad_tokens(self):
188188
self._check_jwt_failure(jwt, 'Wrong recipient')
189189

190190

191-
class Test_crypt_private_key_as_pem(unittest.TestCase):
192-
193-
def _make_signed_jwt_creds(self, private_key_file='privatekey.p12',
194-
private_key=None):
195-
private_key = private_key or datafile(private_key_file)
196-
return SignedJwtAssertionCredentials(
197-
198-
private_key,
199-
scope='read+write',
200-
201-
202-
def test_succeeds(self):
203-
self.assertEqual(True, HAS_OPENSSL)
204-
205-
credentials = self._make_signed_jwt_creds()
206-
pem_contents = crypt.private_key_as_pem(
207-
credentials.private_key,
208-
private_key_password=credentials.private_key_password)
209-
210-
private_key_as_pem = datafile('pem_from_pkcs12.pem')
211-
private_key_as_pem = crypt._parse_pem_key(private_key_as_pem)
212-
self.assertEqual(pem_contents, private_key_as_pem)
213-
214-
def test_without_openssl(self):
215-
credentials = self._make_signed_jwt_creds()
216-
with mock.patch('oauth2client.crypt.OpenSSLSigner', None):
217-
self.assertRaises(ImportError, crypt.private_key_as_pem,
218-
credentials.private_key,
219-
private_key_password=credentials.private_key_password)
220-
221-
def test_with_pem_key(self):
222-
credentials = self._make_signed_jwt_creds(private_key_file='privatekey.pem')
223-
pem_contents = crypt.private_key_as_pem(
224-
credentials.private_key,
225-
private_key_password=credentials.private_key_password)
226-
expected_pem_key = datafile('privatekey.pem')
227-
self.assertEqual(pem_contents, expected_pem_key)
228-
229-
def test_with_nonsense_key(self):
230-
credentials = self._make_signed_jwt_creds(private_key=b'NOT_A_KEY')
231-
self.assertRaises(crypt.crypto.Error, crypt.private_key_as_pem,
232-
credentials.private_key,
233-
private_key_password=credentials.private_key_password)
234-
235-
236191
class PEMCryptTestsPyCrypto(CryptTests):
237192
def setUp(self):
238193
self.format = 'pem'

0 commit comments

Comments
 (0)