• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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