1# Copyright 2015 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"""Helper functions for commonly used utilities.""" 15 16import base64 17import json 18import six 19 20 21def _parse_pem_key(raw_key_input): 22 """Identify and extract PEM keys. 23 24 Determines whether the given key is in the format of PEM key, and extracts 25 the relevant part of the key if it is. 26 27 Args: 28 raw_key_input: The contents of a private key file (either PEM or 29 PKCS12). 30 31 Returns: 32 string, The actual key if the contents are from a PEM file, or 33 else None. 34 """ 35 offset = raw_key_input.find(b'-----BEGIN ') 36 if offset != -1: 37 return raw_key_input[offset:] 38 39 40def _json_encode(data): 41 return json.dumps(data, separators=(',', ':')) 42 43 44def _to_bytes(value, encoding='ascii'): 45 """Converts a string value to bytes, if necessary. 46 47 Unfortunately, ``six.b`` is insufficient for this task since in 48 Python2 it does not modify ``unicode`` objects. 49 50 Args: 51 value: The string/bytes value to be converted. 52 encoding: The encoding to use to convert unicode to bytes. Defaults 53 to "ascii", which will not allow any characters from ordinals 54 larger than 127. Other useful values are "latin-1", which 55 which will only allows byte ordinals (up to 255) and "utf-8", 56 which will encode any unicode that needs to be. 57 58 Returns: 59 The original value converted to bytes (if unicode) or as passed in 60 if it started out as bytes. 61 62 Raises: 63 ValueError if the value could not be converted to bytes. 64 """ 65 result = (value.encode(encoding) 66 if isinstance(value, six.text_type) else value) 67 if isinstance(result, six.binary_type): 68 return result 69 else: 70 raise ValueError('%r could not be converted to bytes' % (value,)) 71 72 73def _from_bytes(value): 74 """Converts bytes to a string value, if necessary. 75 76 Args: 77 value: The string/bytes value to be converted. 78 79 Returns: 80 The original value converted to unicode (if bytes) or as passed in 81 if it started out as unicode. 82 83 Raises: 84 ValueError if the value could not be converted to unicode. 85 """ 86 result = (value.decode('utf-8') 87 if isinstance(value, six.binary_type) else value) 88 if isinstance(result, six.text_type): 89 return result 90 else: 91 raise ValueError('%r could not be converted to unicode' % (value,)) 92 93 94def _urlsafe_b64encode(raw_bytes): 95 raw_bytes = _to_bytes(raw_bytes, encoding='utf-8') 96 return base64.urlsafe_b64encode(raw_bytes).rstrip(b'=') 97 98 99def _urlsafe_b64decode(b64string): 100 # Guard against unicode strings, which base64 can't handle. 101 b64string = _to_bytes(b64string) 102 padded = b64string + b'=' * (4 - len(b64string) % 4) 103 return base64.urlsafe_b64decode(padded) 104