| Index: appengine/chromium_build_logs/third_party/oauth2client/crypt.py | 
| diff --git a/appengine/chromium_build_logs/third_party/oauth2client/crypt.py b/appengine/chromium_build_logs/third_party/oauth2client/crypt.py | 
| index 3df861d29b98368239727c75b7f1d3e2a9f9b456..cc7a6cd3a46b85d6df62eb0db27c03814bb89282 100644 | 
| --- a/appengine/chromium_build_logs/third_party/oauth2client/crypt.py | 
| +++ b/appengine/chromium_build_logs/third_party/oauth2client/crypt.py | 
| @@ -1,7 +1,6 @@ | 
| -#!/usr/bin/python2.4 | 
| # -*- coding: utf-8 -*- | 
| # | 
| -# Copyright (C) 2011 Google Inc. | 
| +# Copyright 2014 Google Inc. All rights reserved. | 
| # | 
| # Licensed under the Apache License, Version 2.0 (the "License"); | 
| # you may not use this file except in compliance with the License. | 
| @@ -14,14 +13,17 @@ | 
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
| # See the License for the specific language governing permissions and | 
| # limitations under the License. | 
| +"""Crypto-related routines for oauth2client.""" | 
|  | 
| -import base64 | 
| -import hashlib | 
| +import imp | 
| +import json | 
| import logging | 
| +import os | 
| import time | 
|  | 
| -from OpenSSL import crypto | 
| -from anyjson import simplejson | 
| +from oauth2client._helpers import _json_encode | 
| +from oauth2client._helpers import _urlsafe_b64decode | 
| +from oauth2client._helpers import _urlsafe_b64encode | 
|  | 
|  | 
| CLOCK_SKEW_SECS = 300  # 5 minutes in seconds | 
| @@ -29,113 +31,71 @@ AUTH_TOKEN_LIFETIME_SECS = 300  # 5 minutes in seconds | 
| MAX_TOKEN_LIFETIME_SECS = 86400  # 1 day in seconds | 
|  | 
|  | 
| -class AppIdentityError(Exception): | 
| -  pass | 
| - | 
| - | 
| -class Verifier(object): | 
| -  """Verifies the signature on a message.""" | 
| - | 
| -  def __init__(self, pubkey): | 
| -    """Constructor. | 
| - | 
| -    Args: | 
| -      pubkey, OpenSSL.crypto.PKey, The public key to verify with. | 
| -    """ | 
| -    self._pubkey = pubkey | 
| - | 
| -  def verify(self, message, signature): | 
| -    """Verifies a message against a signature. | 
| - | 
| -    Args: | 
| -      message: string, The message to verify. | 
| -      signature: string, The signature on the message. | 
| - | 
| -    Returns: | 
| -      True if message was singed by the private key associated with the public | 
| -      key that this object was constructed with. | 
| -    """ | 
| -    try: | 
| -      crypto.verify(self._pubkey, signature, message, 'sha256') | 
| -      return True | 
| -    except: | 
| -      return False | 
| - | 
| -  @staticmethod | 
| -  def from_string(key_pem, is_x509_cert): | 
| -    """Construct a Verified instance from a string. | 
| - | 
| -    Args: | 
| -      key_pem: string, public key in PEM format. | 
| -      is_x509_cert: bool, True if key_pem is an X509 cert, otherwise it is | 
| -        expected to be an RSA key in PEM format. | 
| - | 
| -    Returns: | 
| -      Verifier instance. | 
| - | 
| -    Raises: | 
| -      OpenSSL.crypto.Error if the key_pem can't be parsed. | 
| -    """ | 
| -    if is_x509_cert: | 
| -      pubkey = crypto.load_certificate(crypto.FILETYPE_PEM, key_pem) | 
| -    else: | 
| -      pubkey = crypto.load_privatekey(crypto.FILETYPE_PEM, key_pem) | 
| -    return Verifier(pubkey) | 
| - | 
| - | 
| -class Signer(object): | 
| -  """Signs messages with a private key.""" | 
| +logger = logging.getLogger(__name__) | 
|  | 
| -  def __init__(self, pkey): | 
| -    """Constructor. | 
| - | 
| -    Args: | 
| -      pkey, OpenSSL.crypto.PKey, The private key to sign with. | 
| -    """ | 
| -    self._key = pkey | 
| - | 
| -  def sign(self, message): | 
| -    """Signs a message. | 
| - | 
| -    Args: | 
| -      message: string, Message to be signed. | 
| - | 
| -    Returns: | 
| -      string, The signature of the message for the given key. | 
| -    """ | 
| -    return crypto.sign(self._key, message, 'sha256') | 
| - | 
| -  @staticmethod | 
| -  def from_string(key, password='notasecret'): | 
| -    """Construct a Signer instance from a string. | 
| - | 
| -    Args: | 
| -      key: string, private key in P12 format. | 
| -      password: string, password for the private key file. | 
| - | 
| -    Returns: | 
| -      Signer instance. | 
| - | 
| -    Raises: | 
| -      OpenSSL.crypto.Error if the key can't be parsed. | 
| -    """ | 
| -    pkey = crypto.load_pkcs12(key, password).get_privatekey() | 
| -    return Signer(pkey) | 
|  | 
| +class AppIdentityError(Exception): | 
| +  pass | 
|  | 
| -def _urlsafe_b64encode(raw_bytes): | 
| -  return base64.urlsafe_b64encode(raw_bytes).rstrip('=') | 
|  | 
| +def _TryOpenSslImport(): | 
| +  """Import OpenSSL, avoiding the explicit import where possible. | 
|  | 
| -def _urlsafe_b64decode(b64string): | 
| -  # Guard against unicode strings, which base64 can't handle. | 
| -  b64string = b64string.encode('ascii') | 
| -  padded = b64string + '=' * (4 - len(b64string) % 4) | 
| -  return base64.urlsafe_b64decode(padded) | 
| +  Importing OpenSSL 0.14 can take up to 0.5s, which is a large price | 
| +  to pay at module import time. However, it's also possible for | 
| +  ``imp.find_module`` to fail to find the module, even when it's | 
| +  installed. (This is the case in various exotic environments, | 
| +  including some relevant for Google.) So we first try a fast-path, | 
| +  and fall back to the slow import as needed. | 
|  | 
| +  Args: | 
| +    None | 
| +  Returns: | 
| +    None | 
| +  Raises: | 
| +    ImportError if OpenSSL is unavailable. | 
|  | 
| -def _json_encode(data): | 
| -  return simplejson.dumps(data, separators = (',', ':')) | 
| +  """ | 
| +  try: | 
| +    _, _package_dir, _ = imp.find_module('OpenSSL') | 
| +    if not (os.path.isfile(os.path.join(_package_dir, 'crypto.py')) or | 
| +            os.path.isfile(os.path.join(_package_dir, 'crypto.so')) or | 
| +            os.path.isdir(os.path.join(_package_dir, 'crypto'))): | 
| +      raise ImportError('No module named OpenSSL.crypto') | 
| +    return | 
| +  except ImportError: | 
| +    import OpenSSL.crypto | 
| + | 
| + | 
| +try: | 
| +  _TryOpenSslImport() | 
| +  from oauth2client._openssl_crypt import OpenSSLVerifier | 
| +  from oauth2client._openssl_crypt import OpenSSLSigner | 
| +  from oauth2client._openssl_crypt import pkcs12_key_as_pem | 
| +except ImportError: | 
| +  OpenSSLVerifier = None | 
| +  OpenSSLSigner = None | 
| +  def pkcs12_key_as_pem(*args, **kwargs): | 
| +    raise NotImplementedError('pkcs12_key_as_pem requires OpenSSL.') | 
| + | 
| + | 
| +try: | 
| +  from oauth2client._pycrypto_crypt import PyCryptoVerifier | 
| +  from oauth2client._pycrypto_crypt import PyCryptoSigner | 
| +except ImportError: | 
| +  PyCryptoVerifier = None | 
| +  PyCryptoSigner = None | 
| + | 
| + | 
| +if OpenSSLSigner: | 
| +  Signer = OpenSSLSigner | 
| +  Verifier = OpenSSLVerifier | 
| +elif PyCryptoSigner: | 
| +  Signer = PyCryptoSigner | 
| +  Verifier = PyCryptoVerifier | 
| +else: | 
| +  raise ImportError('No encryption library found. Please install either ' | 
| +                    'PyOpenSSL, or PyCrypto 2.6 or later') | 
|  | 
|  | 
| def make_signed_jwt(signer, payload): | 
| @@ -153,15 +113,15 @@ def make_signed_jwt(signer, payload): | 
| header = {'typ': 'JWT', 'alg': 'RS256'} | 
|  | 
| segments = [ | 
| -          _urlsafe_b64encode(_json_encode(header)), | 
| -          _urlsafe_b64encode(_json_encode(payload)), | 
| +      _urlsafe_b64encode(_json_encode(header)), | 
| +      _urlsafe_b64encode(_json_encode(payload)), | 
| ] | 
| signing_input = '.'.join(segments) | 
|  | 
| signature = signer.sign(signing_input) | 
| segments.append(_urlsafe_b64encode(signature)) | 
|  | 
| -  logging.debug(str(segments)) | 
| +  logger.debug(str(segments)) | 
|  | 
| return '.'.join(segments) | 
|  | 
| @@ -185,9 +145,8 @@ def verify_signed_jwt_with_certs(jwt, certs, audience): | 
| """ | 
| segments = jwt.split('.') | 
|  | 
| -  if (len(segments) != 3): | 
| -    raise AppIdentityError( | 
| -      'Wrong number of segments in token: %s' % jwt) | 
| +  if len(segments) != 3: | 
| +    raise AppIdentityError('Wrong number of segments in token: %s' % jwt) | 
| signed = '%s.%s' % (segments[0], segments[1]) | 
|  | 
| signature = _urlsafe_b64decode(segments[2]) | 
| @@ -195,15 +154,15 @@ def verify_signed_jwt_with_certs(jwt, certs, audience): | 
| # Parse token. | 
| json_body = _urlsafe_b64decode(segments[1]) | 
| try: | 
| -    parsed = simplejson.loads(json_body) | 
| +    parsed = json.loads(json_body.decode('utf-8')) | 
| except: | 
| raise AppIdentityError('Can\'t parse token: %s' % json_body) | 
|  | 
| # Check signature. | 
| verified = False | 
| -  for (keyname, pem) in certs.items(): | 
| +  for pem in certs.values(): | 
| verifier = Verifier.from_string(pem, True) | 
| -    if (verifier.verify(signed, signature)): | 
| +    if verifier.verify(signed, signature): | 
| verified = True | 
| break | 
| if not verified: | 
| @@ -216,21 +175,20 @@ def verify_signed_jwt_with_certs(jwt, certs, audience): | 
| earliest = iat - CLOCK_SKEW_SECS | 
|  | 
| # Check expiration timestamp. | 
| -  now = long(time.time()) | 
| +  now = int(time.time()) | 
| exp = parsed.get('exp') | 
| if exp is None: | 
| raise AppIdentityError('No exp field in token: %s' % json_body) | 
| if exp >= now + MAX_TOKEN_LIFETIME_SECS: | 
| -    raise AppIdentityError( | 
| -      'exp field too far in future: %s' % json_body) | 
| +    raise AppIdentityError('exp field too far in future: %s' % json_body) | 
| latest = exp + CLOCK_SKEW_SECS | 
|  | 
| if now < earliest: | 
| raise AppIdentityError('Token used too early, %d < %d: %s' % | 
| -      (now, earliest, json_body)) | 
| +                           (now, earliest, json_body)) | 
| if now > latest: | 
| raise AppIdentityError('Token used too late, %d > %d: %s' % | 
| -      (now, latest, json_body)) | 
| +                           (now, latest, json_body)) | 
|  | 
| # Check audience. | 
| if audience is not None: | 
| @@ -239,6 +197,6 @@ def verify_signed_jwt_with_certs(jwt, certs, audience): | 
| raise AppIdentityError('No aud field in token: %s' % json_body) | 
| if aud != audience: | 
| raise AppIdentityError('Wrong recipient, %s != %s: %s' % | 
| -          (aud, audience, json_body)) | 
| +                             (aud, audience, json_body)) | 
|  | 
| return parsed | 
|  |