¡@

Home 

OpenStack Study: crypto.py

OpenStack Index

**** CubicPower OpenStack Study ****

def ca_folder(project_id=None):

    if CONF.use_project_ca and project_id:

        return os.path.join(CONF.ca_path, 'projects', project_id)

    return CONF.ca_path

**** CubicPower OpenStack Study ****

def ca_path(project_id=None):

    return os.path.join(ca_folder(project_id), CONF.ca_file)

**** CubicPower OpenStack Study ****

def key_path(project_id=None):

    return os.path.join(ca_folder(project_id), CONF.key_file)

**** CubicPower OpenStack Study ****

def crl_path(project_id=None):

    return os.path.join(ca_folder(project_id), CONF.crl_file)

**** CubicPower OpenStack Study ****

def fetch_ca(project_id=None):

    if not CONF.use_project_ca:

        project_id = None

    ca_file_path = ca_path(project_id)

    if not os.path.exists(ca_file_path):

        raise exception.CryptoCAFileNotFound(project=project_id)

    with open(ca_file_path, 'r') as cafile:

        return cafile.read()

**** CubicPower OpenStack Study ****

def ensure_ca_filesystem():

    """Ensure the CA filesystem exists."""

    ca_dir = ca_folder()

    if not os.path.exists(ca_path()):

        genrootca_sh_path = os.path.abspath(

                os.path.join(os.path.dirname(__file__), 'CA', 'genrootca.sh'))

        start = os.getcwd()

        fileutils.ensure_tree(ca_dir)

        os.chdir(ca_dir)

        utils.execute("sh", genrootca_sh_path)

        os.chdir(start)

**** CubicPower OpenStack Study ****

def _generate_fingerprint(public_key_file):

    (out, err) = utils.execute('ssh-keygen', '-q', '-l', '-f', public_key_file)

    fingerprint = out.split(' ')[1]

    return fingerprint

**** CubicPower OpenStack Study ****

def generate_fingerprint(public_key):

    with utils.tempdir() as tmpdir:

        try:

            pubfile = os.path.join(tmpdir, 'temp.pub')

            with open(pubfile, 'w') as f:

                f.write(public_key)

            return _generate_fingerprint(pubfile)

        except processutils.ProcessExecutionError:

            raise exception.InvalidKeypair(

                reason=_('failed to generate fingerprint'))

**** CubicPower OpenStack Study ****

def generate_key_pair(bits=None):

    with utils.tempdir() as tmpdir:

        keyfile = os.path.join(tmpdir, 'temp')

        args = ['ssh-keygen', '-q', '-N', '', '-t', 'rsa',

                '-f', keyfile, '-C', 'Generated by Nova']

        if bits is not None:

            args.extend(['-b', bits])

        utils.execute(*args)

        fingerprint = _generate_fingerprint('%s.pub' % (keyfile))

        if not os.path.exists(keyfile):

            raise exception.FileNotFound(keyfile)

        private_key = open(keyfile).read()

        public_key_path = keyfile + '.pub'

        if not os.path.exists(public_key_path):

            raise exception.FileNotFound(public_key_path)

        public_key = open(public_key_path).read()

    return (private_key, public_key, fingerprint)

**** CubicPower OpenStack Study ****

def fetch_crl(project_id):

    """Get crl file for project."""

    if not CONF.use_project_ca:

        project_id = None

    crl_file_path = crl_path(project_id)

    if not os.path.exists(crl_file_path):

        raise exception.CryptoCRLFileNotFound(project=project_id)

    with open(crl_file_path, 'r') as crlfile:

        return crlfile.read()

**** CubicPower OpenStack Study ****

def decrypt_text(project_id, text):

    private_key = key_path(project_id)

    if not os.path.exists(private_key):

        raise exception.ProjectNotFound(project_id=project_id)

    try:

        dec, _err = utils.execute('openssl',

                                  'rsautl',

                                  '-decrypt',

                                  '-inkey', '%s' % private_key,

                                  process_input=text)

        return dec

    except processutils.ProcessExecutionError as exc:

        raise exception.DecryptionFailure(reason=exc.stderr)

_RSA_OID = univ.ObjectIdentifier('1.2.840.113549.1.1.1')

**** CubicPower OpenStack Study ****

def _to_sequence(*vals):

    seq = univ.Sequence()

    for i in range(len(vals)):

        seq.setComponentByPosition(i, vals[i])

    return seq

**** CubicPower OpenStack Study ****

def convert_from_sshrsa_to_pkcs8(pubkey):

    """Convert a ssh public key to openssl format

       Equivalent to the ssh-keygen's -m option

    """

    # get the second field from the public key file.

    try:

        keydata = base64.b64decode(pubkey.split(None)[1])

    except IndexError:

        msg = _("Unable to find the key")

        raise exception.EncryptionFailure(reason=msg)

    # decode the parts of the key

    parts = []

    while keydata:

        dlen = struct.unpack('>I', keydata[:4])[0]

        data = keydata[4:dlen + 4]

        keydata = keydata[4 + dlen:]

        parts.append(data)

    # Use asn to build the openssl key structure

    #

    #  SEQUENCE(2 elem)

    #    +- SEQUENCE(2 elem)

    #    |    +- OBJECT IDENTIFIER (1.2.840.113549.1.1.1)

    #    |    +- NULL

    #    +- BIT STRING(1 elem)

    #         +- SEQUENCE(2 elem)

    #              +- INTEGER(2048 bit)

    #              +- INTEGER 65537

    # Build the sequence for the bit string

    n_val = int(

        ''.join(['%02X' % struct.unpack('B', x)[0] for x in parts[2]]), 16)

    e_val = int(

        ''.join(['%02X' % struct.unpack('B', x)[0] for x in parts[1]]), 16)

    pkinfo = _to_sequence(univ.Integer(n_val), univ.Integer(e_val))

    # Convert the sequence into a bit string

    pklong = long(der_encoder.encode(pkinfo).encode('hex'), 16)

    pkbitstring = univ.BitString("'00%s'B" % bin(pklong)[2:])

    # Build the key data structure

    oid = _to_sequence(_RSA_OID, univ.Null())

    pkcs1_seq = _to_sequence(oid, pkbitstring)

    pkcs8 = base64.encodestring(der_encoder.encode(pkcs1_seq))

    # Remove the embedded new line and format the key, each line

    # should be 64 characters long

    return ('-----BEGIN PUBLIC KEY-----\n%s\n-----END PUBLIC KEY-----\n' %

            re.sub("(.{64})", "\\1\n", pkcs8.replace('\n', ''), re.DOTALL))

**** CubicPower OpenStack Study ****

def ssh_encrypt_text(ssh_public_key, text):

    """Encrypt text with an ssh public key.

    """

    with utils.tempdir() as tmpdir:

        sslkey = os.path.abspath(os.path.join(tmpdir, 'ssl.key'))

        try:

            out = convert_from_sshrsa_to_pkcs8(ssh_public_key)

            with open(sslkey, 'w') as f:

                f.write(out)

            enc, _err = utils.execute('openssl',

                                      'rsautl',

                                      '-encrypt',

                                      '-pubin',

                                      '-inkey', sslkey,

                                      '-keyform', 'PEM',

                                      process_input=text)

            return enc

        except processutils.ProcessExecutionError as exc:

            raise exception.EncryptionFailure(reason=exc.stderr)

**** CubicPower OpenStack Study ****

def revoke_cert(project_id, file_name):

    """Revoke a cert by file name."""

    start = os.getcwd()

    os.chdir(ca_folder(project_id))

    # NOTE(vish): potential race condition here

    utils.execute('openssl', 'ca', '-config', './openssl.cnf', '-revoke',

                  file_name)

    utils.execute('openssl', 'ca', '-gencrl', '-config', './openssl.cnf',

                  '-out', CONF.crl_file)

    os.chdir(start)

**** CubicPower OpenStack Study ****

def revoke_certs_by_user(user_id):

    """Revoke all user certs."""

    admin = context.get_admin_context()

    for cert in db.certificate_get_all_by_user(admin, user_id):

        revoke_cert(cert['project_id'], cert['file_name'])

**** CubicPower OpenStack Study ****

def revoke_certs_by_project(project_id):

    """Revoke all project certs."""

    # NOTE(vish): This is somewhat useless because we can just shut down

    #             the vpn.

    admin = context.get_admin_context()

    for cert in db.certificate_get_all_by_project(admin, project_id):

        revoke_cert(cert['project_id'], cert['file_name'])

**** CubicPower OpenStack Study ****

def revoke_certs_by_user_and_project(user_id, project_id):

    """Revoke certs for user in project."""

    admin = context.get_admin_context()

    for cert in db.certificate_get_all_by_user_and_project(admin,

                                            user_id, project_id):

        revoke_cert(cert['project_id'], cert['file_name'])

**** CubicPower OpenStack Study ****

def _project_cert_subject(project_id):

    """Helper to generate user cert subject."""

    return CONF.project_cert_subject % (project_id, timeutils.isotime())

**** CubicPower OpenStack Study ****

def _user_cert_subject(user_id, project_id):

    """Helper to generate user cert subject."""

    return CONF.user_cert_subject % (project_id, user_id, timeutils.isotime())

**** CubicPower OpenStack Study ****

def generate_x509_cert(user_id, project_id, bits=1024):

    """Generate and sign a cert for user in project."""

    subject = _user_cert_subject(user_id, project_id)

    with utils.tempdir() as tmpdir:

        keyfile = os.path.abspath(os.path.join(tmpdir, 'temp.key'))

        csrfile = os.path.abspath(os.path.join(tmpdir, 'temp.csr'))

        utils.execute('openssl', 'genrsa', '-out', keyfile, str(bits))

        utils.execute('openssl', 'req', '-new', '-key', keyfile, '-out',

                      csrfile, '-batch', '-subj', subject)

        private_key = open(keyfile).read()

        csr = open(csrfile).read()

    (serial, signed_csr) = sign_csr(csr, project_id)

    fname = os.path.join(ca_folder(project_id), 'newcerts/%s.pem' % serial)

    cert = {'user_id': user_id,

            'project_id': project_id,

            'file_name': fname}

    db.certificate_create(context.get_admin_context(), cert)

    return (private_key, signed_csr)

**** CubicPower OpenStack Study ****

def _ensure_project_folder(project_id):

    if not os.path.exists(ca_path(project_id)):

        geninter_sh_path = os.path.abspath(

                os.path.join(os.path.dirname(__file__), 'CA', 'geninter.sh'))

        start = os.getcwd()

        os.chdir(ca_folder())

        utils.execute('sh', geninter_sh_path, project_id,

                      _project_cert_subject(project_id))

        os.chdir(start)

**** CubicPower OpenStack Study ****

def generate_vpn_files(project_id):

    project_folder = ca_folder(project_id)

    key_fn = os.path.join(project_folder, 'server.key')

    crt_fn = os.path.join(project_folder, 'server.crt')

    if os.path.exists(crt_fn):

        return

    # NOTE(vish): The 2048 is to maintain compatibility with the old script.

    #             We are using "project-vpn" as the user_id for the cert

    #             even though that user may not really exist. Ultimately

    #             this will be changed to be launched by a real user.  At

    #             that point we will can delete this helper method.

    key, csr = generate_x509_cert('project-vpn', project_id, 2048)

    with open(key_fn, 'w') as keyfile:

        keyfile.write(key)

    with open(crt_fn, 'w') as crtfile:

        crtfile.write(csr)

**** CubicPower OpenStack Study ****

def sign_csr(csr_text, project_id=None):

    if not CONF.use_project_ca:

        project_id = None

    if not project_id:

        return _sign_csr(csr_text, ca_folder())

    _ensure_project_folder(project_id)

    project_folder = ca_folder(project_id)

    return _sign_csr(csr_text, ca_folder(project_id))

**** CubicPower OpenStack Study ****

def _sign_csr(csr_text, ca_folder):

    with utils.tempdir() as tmpdir:

        inbound = os.path.join(tmpdir, 'inbound.csr')

        outbound = os.path.join(tmpdir, 'outbound.csr')

        try:

            with open(inbound, 'w') as csrfile:

                csrfile.write(csr_text)

        except IOError:

            with excutils.save_and_reraise_exception():

                LOG.exception(_('Failed to write inbound.csr'))

        LOG.debug(_('Flags path: %s'), ca_folder)

        start = os.getcwd()

        # Change working dir to CA

        fileutils.ensure_tree(ca_folder)

        os.chdir(ca_folder)

        utils.execute('openssl', 'ca', '-batch', '-out', outbound, '-config',

                      './openssl.cnf', '-infiles', inbound)

        out, _err = utils.execute('openssl', 'x509', '-in', outbound,

                                  '-serial', '-noout')

        serial = string.strip(out.rpartition('=')[2])

        os.chdir(start)

        with open(outbound, 'r') as crtfile:

            return (serial, crtfile.read())

# Copyright (c) 2006-2009 Mitch Garnaat http://garnaat.org/

#

# Permission is hereby granted, free of charge, to any person obtaining a

# copy of this software and associated documentation files (the

# "Software"), to deal in the Software without restriction, including

# without limitation the rights to use, copy, modify, merge, publish, dis-

# tribute, sublicense, and/or sell copies of the Software, and to permit

# persons to whom the Software is furnished to do so, subject to the fol-

# lowing conditions:

#

# The above copyright notice and this permission notice shall be included

# in all copies or substantial portions of the Software.

#

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS

# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-

# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT

# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,

# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS

# IN THE SOFTWARE.

# http://code.google.com/p/boto

**** CubicPower OpenStack Study ****

def compute_md5(fp):

    """Compute an md5 hash.

    :type fp: file

    :param fp: File pointer to the file to MD5 hash.  The file pointer will be

               reset to the beginning of the file before the method returns.

    :rtype: tuple

    :returns: the hex digest version of the MD5 hash

    """

    m = hashlib.md5()

    fp.seek(0)

    s = fp.read(8192)

    while s:

        m.update(s)

        s = fp.read(8192)

    hex_md5 = m.hexdigest()

    # size = fp.tell()

    fp.seek(0)

    return hex_md5