HEX
Server: Apache
System: Linux sg241.singhost.net 2.6.32-896.16.1.lve1.4.51.el6.x86_64 #1 SMP Wed Jan 17 13:19:23 EST 2018 x86_64
User: honghock (909)
PHP: 8.0.30
Disabled: passthru,system,shell_exec,show_source,exec,popen,proc_open
Upload Files
File: //usr/lib/python2.7/site-packages/salt/modules/keystore.py
# -*- coding: utf-8 -*-
'''
Module to interact with keystores
'''

# Import Python libs
from __future__ import absolute_import, unicode_literals, print_function
import logging
from datetime import datetime
import os

log = logging.getLogger(__name__)

__virtualname__ = 'keystore'

# Import third party libs
from salt.exceptions import CommandExecutionError, SaltInvocationError

try:
    import jks
    import OpenSSL
    has_depends = True
except ImportError:
    has_depends = False


def __virtual__():
    '''
    Check dependencies
    '''
    if has_depends is False:
        msg = 'jks unavailable: {0} execution module cant be loaded '.format(__virtualname__)
        return False, msg
    return __virtualname__


def _parse_cert(alias, public_cert, return_cert=False):
    ASN1 = OpenSSL.crypto.FILETYPE_ASN1
    PEM = OpenSSL.crypto.FILETYPE_PEM
    cert_data = {}
    sha1 = public_cert.digest(b'sha1')

    cert_pem = OpenSSL.crypto.dump_certificate(PEM, public_cert)
    raw_until = public_cert.get_notAfter()
    date_until = datetime.strptime(raw_until, '%Y%m%d%H%M%SZ')
    string_until = date_until.strftime("%B %d %Y")

    raw_start = public_cert.get_notBefore()
    date_start = datetime.strptime(raw_start, '%Y%m%d%H%M%SZ')
    string_start = date_start.strftime("%B %d %Y")

    if return_cert:
        cert_data['pem'] = cert_pem
    cert_data['alias'] = alias
    cert_data['sha1'] = sha1
    cert_data['valid_until'] = string_until
    cert_data['valid_start'] = string_start
    cert_data['expired'] = date_until < datetime.now()

    return cert_data


def list(keystore, passphrase, alias=None, return_cert=False):
    '''
    Lists certificates in a keytool managed keystore.


    :param keystore: The path to the keystore file to query
    :param passphrase: The passphrase to use to decode the keystore
    :param alias: (Optional) If found, displays details on only this key
    :param return_certs: (Optional) Also return certificate PEM.

    .. warning::

        There are security implications for using return_cert to return decrypted certificates.

    CLI Example:

    .. code-block:: bash

        salt '*' keystore.list /usr/lib/jvm/java-8/jre/lib/security/cacerts changeit
        salt '*' keystore.list /usr/lib/jvm/java-8/jre/lib/security/cacerts changeit debian:verisign_-_g5.pem

    '''
    ASN1 = OpenSSL.crypto.FILETYPE_ASN1
    PEM = OpenSSL.crypto.FILETYPE_PEM
    decoded_certs = []
    entries = []

    keystore = jks.KeyStore.load(keystore, passphrase)

    if alias:
        # If alias is given, look it up and build expected data structure
        entry_value = keystore.entries.get(alias)
        if entry_value:
            entries = [(alias, entry_value)]
    else:
        entries = keystore.entries.items()

    if entries:
        for entry_alias, cert_enc in entries:
            entry_data = {}
            if isinstance(cert_enc, jks.PrivateKeyEntry):
                cert_result = cert_enc.cert_chain[0][1]
                entry_data['type'] = 'PrivateKeyEntry'
            elif isinstance(cert_enc, jks.TrustedCertEntry):
                cert_result = cert_enc.cert
                entry_data['type'] = 'TrustedCertEntry'
            else:
                raise CommandExecutionError('Unsupported EntryType detected in keystore')

            # Detect if ASN1 binary, otherwise assume PEM
            if '\x30' in cert_result[0]:
                public_cert = OpenSSL.crypto.load_certificate(ASN1, cert_result)
            else:
                public_cert = OpenSSL.crypto.load_certificate(PEM, cert_result)

            entry_data.update(_parse_cert(entry_alias, public_cert, return_cert))
            decoded_certs.append(entry_data)

    return decoded_certs


def add(name, keystore, passphrase, certificate, private_key=None):
    '''
    Adds certificates to an existing keystore or creates a new one if necesssary.

    :param name: alias for the certificate
    :param keystore: The path to the keystore file to query
    :param passphrase: The passphrase to use to decode the keystore
    :param certificate: The PEM public certificate to add to keystore. Can be a string for file.
    :param private_key: (Optional for TrustedCert) The PEM private key to add to the keystore

    CLI Example:

    .. code-block:: bash

        salt '*' keystore.add aliasname /tmp/test.store changeit /tmp/testcert.crt
        salt '*' keystore.add aliasname /tmp/test.store changeit certificate="-----BEGIN CERTIFICATE-----SIb...BM=-----END CERTIFICATE-----"
        salt '*' keystore.add keyname /tmp/test.store changeit /tmp/512.cert private_key=/tmp/512.key

    '''
    ASN1 = OpenSSL.crypto.FILETYPE_ASN1
    PEM = OpenSSL.crypto.FILETYPE_PEM
    certs_list = []
    if os.path.isfile(keystore):
        keystore_object = jks.KeyStore.load(keystore, passphrase)
        for alias, loaded_cert in keystore_object.entries.items():
            certs_list.append(loaded_cert)

    try:
        cert_string = __salt__['x509.get_pem_entry'](certificate)
    except SaltInvocationError:
        raise SaltInvocationError('Invalid certificate file or string: {0}'.format(certificate))

    if private_key:
        # Accept PEM input format, but convert to DES for loading into new keystore
        key_string = __salt__['x509.get_pem_entry'](private_key)
        loaded_cert = OpenSSL.crypto.load_certificate(PEM, cert_string)
        loaded_key = OpenSSL.crypto.load_privatekey(PEM, key_string)
        dumped_cert = OpenSSL.crypto.dump_certificate(ASN1, loaded_cert)
        dumped_key = OpenSSL.crypto.dump_privatekey(ASN1, loaded_key)

        new_entry = jks.PrivateKeyEntry.new(name, [dumped_cert], dumped_key, 'rsa_raw')
    else:
        new_entry = jks.TrustedCertEntry.new(name, cert_string)

    certs_list.append(new_entry)

    keystore_object = jks.KeyStore.new('jks', certs_list)
    keystore_object.save(keystore, passphrase)
    return True


def remove(name, keystore, passphrase):
    '''
    Removes a certificate from an existing keystore.
    Returns True if remove was successful, otherwise False

    :param name: alias for the certificate
    :param keystore: The path to the keystore file to query
    :param passphrase: The passphrase to use to decode the keystore

    CLI Example:

    .. code-block:: bash

        salt '*' keystore.remove aliasname /tmp/test.store changeit
    '''
    certs_list = []
    keystore_object = jks.KeyStore.load(keystore, passphrase)
    for alias, loaded_cert in keystore_object.entries.items():
        if name not in alias:
            certs_list.append(loaded_cert)

    if len(keystore_object.entries) != len(certs_list):
        # Entry has been removed, save keystore updates
        keystore_object = jks.KeyStore.new('jks', certs_list)
        keystore_object.save(keystore, passphrase)
        return True
    else:
        # No alias found, notify user
        return False