| # Copyright 2015 The Chromium Authors. All rights reserved. | 
 | # Use of this source code is governed by a BSD-style license that can be | 
 | # found in the LICENSE file. | 
 |  | 
 | """Utility library to add SSL support to the RPC server.""" | 
 |  | 
 | import logging | 
 | import ssl | 
 | import subprocess | 
 | import tempfile | 
 |  | 
 | from legion.lib import common_lib | 
 | from legion.lib.rpc import jsonrpclib | 
 | from legion.lib.rpc import SimpleJSONRPCServer | 
 |  | 
 |  | 
 | class Error(Exception): | 
 |   pass | 
 |  | 
 |  | 
 | def CreateKeyFile(): | 
 |   """Creates an SSL keyfile and returns the path.""" | 
 |   keyfile = tempfile.mkstemp()[1] | 
 |   cmd = [ | 
 |     'openssl', | 
 |     'genrsa', | 
 |     '-out', keyfile, | 
 |     '2048' | 
 |     ] | 
 |   _RunCommand(cmd) | 
 |   return keyfile | 
 |  | 
 |  | 
 | def CreateCsrFile(keyfile): | 
 |   """Creates an SSL CSR file and returns the path.""" | 
 |   csrfile = tempfile.mkstemp()[1] | 
 |   cmd = [ | 
 |       'openssl', | 
 |       'req', | 
 |       '-new', | 
 |       '-key', keyfile, | 
 |       '-out', csrfile, | 
 |       '-subj', '/C=NA/ST=NA/L=NA/O=Chromium/OU=Test/CN=chromium.org' | 
 |       ] | 
 |   _RunCommand(cmd) | 
 |   return csrfile | 
 |  | 
 |  | 
 | def CreateCrtFile(keyfile, csrfile): | 
 |   """Creates an SSL CRT file and returns the path.""" | 
 |   crtfile = tempfile.mkstemp()[1] | 
 |   cmd = [ | 
 |       'openssl', | 
 |       'x509', | 
 |       '-req', | 
 |       '-days', '1', | 
 |       '-in', csrfile, | 
 |       '-signkey', keyfile, | 
 |       '-out', crtfile | 
 |       ] | 
 |   _RunCommand(cmd) | 
 |   return crtfile | 
 |  | 
 |  | 
 | def CreatePemFile(): | 
 |   """Creates an SSL PEM file and returns the path.""" | 
 |   keyfile = CreateKeyFile() | 
 |   csrfile = CreateCsrFile(keyfile) | 
 |   crtfile = CreateCrtFile(keyfile, csrfile) | 
 |   pemfile = tempfile.mkstemp()[1] | 
 |   with open(keyfile) as k: | 
 |     with open(crtfile) as c: | 
 |       with open(pemfile, 'wb') as p: | 
 |         p.write('%s\n%s' % (k.read(), c.read())) | 
 |   return pemfile | 
 |  | 
 |  | 
 | def _RunCommand(cmd): | 
 |   try: | 
 |     p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | 
 |   except OSError as e: | 
 |     raise Error('Failed to run %s: %s' % (' '.join(cmd), e)) | 
 |   out, err = p.communicate() | 
 |   if p.returncode != 0: | 
 |     raise Error(err) | 
 |   return out | 
 |  | 
 |  | 
 | class SslRpcServer(SimpleJSONRPCServer.SimpleJSONRPCServer): | 
 |   """Class to add SSL support to the RPC server.""" | 
 |  | 
 |   def __init__(self, *args, **kwargs): | 
 |     SimpleJSONRPCServer.SimpleJSONRPCServer.__init__(self, *args, **kwargs) | 
 |     self.socket = ssl.wrap_socket(self.socket, certfile=CreatePemFile(), | 
 |                                   server_side=True) | 
 |  | 
 |   @staticmethod | 
 |   def Connect(server, port=common_lib.SERVER_PORT): | 
 |     """Creates and returns a connection to an SSL RPC server.""" | 
 |     addr = 'https://%s:%d' % (server, port) | 
 |     logging.debug('Connecting to RPC server at %s', addr) | 
 |     return jsonrpclib.ServerProxy(addr, allow_none=True) |