| OLD | NEW |
| (Empty) | |
| 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 """OpenSSL Crypto-related routines for oauth2client.""" |
| 15 |
| 16 import base64 |
| 17 import six |
| 18 |
| 19 from oauth2client._helpers import _parse_pem_key |
| 20 |
| 21 |
| 22 class OpenSSLVerifier(object): |
| 23 """Verifies the signature on a message.""" |
| 24 |
| 25 def __init__(self, pubkey): |
| 26 """Constructor. |
| 27 |
| 28 Args: |
| 29 pubkey, OpenSSL.crypto.PKey, The public key to verify with. |
| 30 """ |
| 31 self._pubkey = pubkey |
| 32 |
| 33 def verify(self, message, signature): |
| 34 """Verifies a message against a signature. |
| 35 |
| 36 Args: |
| 37 message: string or bytes, The message to verify. If string, will be |
| 38 encoded to bytes as utf-8. |
| 39 signature: string or bytes, The signature on the message. If string, |
| 40 will be encoded to bytes as utf-8. |
| 41 |
| 42 Returns: |
| 43 True if message was signed by the private key associated with the public |
| 44 key that this object was constructed with. |
| 45 """ |
| 46 from OpenSSL import crypto # Delay import due to 0.5s import time. |
| 47 if isinstance(message, six.text_type): |
| 48 message = message.encode('utf-8') |
| 49 if isinstance(signature, six.text_type): |
| 50 signature = signature.encode('utf-8') |
| 51 try: |
| 52 crypto.verify(self._pubkey, signature, message, 'sha256') |
| 53 return True |
| 54 except crypto.Error: |
| 55 return False |
| 56 |
| 57 @staticmethod |
| 58 def from_string(key_pem, is_x509_cert): |
| 59 """Construct a Verified instance from a string. |
| 60 |
| 61 Args: |
| 62 key_pem: string, public key in PEM format. |
| 63 is_x509_cert: bool, True if key_pem is an X509 cert, otherwise it is |
| 64 expected to be an RSA key in PEM format. |
| 65 |
| 66 Returns: |
| 67 Verifier instance. |
| 68 |
| 69 Raises: |
| 70 OpenSSL.crypto.Error if the key_pem can't be parsed. |
| 71 """ |
| 72 from OpenSSL import crypto # Delay import due to 0.5s import time. |
| 73 if is_x509_cert: |
| 74 pubkey = crypto.load_certificate(crypto.FILETYPE_PEM, key_pem) |
| 75 else: |
| 76 pubkey = crypto.load_privatekey(crypto.FILETYPE_PEM, key_pem) |
| 77 return OpenSSLVerifier(pubkey) |
| 78 |
| 79 |
| 80 class OpenSSLSigner(object): |
| 81 """Signs messages with a private key.""" |
| 82 |
| 83 def __init__(self, pkey): |
| 84 """Constructor. |
| 85 |
| 86 Args: |
| 87 pkey, OpenSSL.crypto.PKey (or equiv), The private key to sign with. |
| 88 """ |
| 89 self._key = pkey |
| 90 |
| 91 def sign(self, message): |
| 92 """Signs a message. |
| 93 |
| 94 Args: |
| 95 message: bytes, Message to be signed. |
| 96 |
| 97 Returns: |
| 98 string, The signature of the message for the given key. |
| 99 """ |
| 100 from OpenSSL import crypto # Delay import due to 0.5s import time. |
| 101 if isinstance(message, six.text_type): |
| 102 message = message.encode('utf-8') |
| 103 return crypto.sign(self._key, message, 'sha256') |
| 104 |
| 105 @staticmethod |
| 106 def from_string(key, password=b'notasecret'): |
| 107 """Construct a Signer instance from a string. |
| 108 |
| 109 Args: |
| 110 key: string, private key in PKCS12 or PEM format. |
| 111 password: string, password for the private key file. |
| 112 |
| 113 Returns: |
| 114 Signer instance. |
| 115 |
| 116 Raises: |
| 117 OpenSSL.crypto.Error if the key can't be parsed. |
| 118 """ |
| 119 from OpenSSL import crypto # Delay import due to 0.5s import time. |
| 120 parsed_pem_key = _parse_pem_key(key) |
| 121 if parsed_pem_key: |
| 122 pkey = crypto.load_privatekey(crypto.FILETYPE_PEM, parsed_pem_key) |
| 123 else: |
| 124 if isinstance(password, six.text_type): |
| 125 password = password.encode('utf-8') |
| 126 pkey = crypto.load_pkcs12(key, password).get_privatekey() |
| 127 return OpenSSLSigner(pkey) |
| 128 |
| 129 |
| 130 def pkcs12_key_as_pem(private_key_text, private_key_password): |
| 131 """Convert the contents of a PKCS12 key to PEM using OpenSSL. |
| 132 |
| 133 Args: |
| 134 private_key_text: String. Private key. |
| 135 private_key_password: String. Password for PKCS12. |
| 136 |
| 137 Returns: |
| 138 String. PEM contents of ``private_key_text``. |
| 139 """ |
| 140 from OpenSSL import crypto # Delay import due to 0.5s import time. |
| 141 decoded_body = base64.b64decode(private_key_text) |
| 142 if isinstance(private_key_password, six.text_type): |
| 143 private_key_password = private_key_password.encode('ascii') |
| 144 |
| 145 pkcs12 = crypto.load_pkcs12(decoded_body, private_key_password) |
| 146 return crypto.dump_privatekey(crypto.FILETYPE_PEM, |
| 147 pkcs12.get_privatekey()) |
| OLD | NEW |