Create a Self-Signed Certificate (CERT)

    tls_dir
        location appended to the ca.cert_base_path, default is 'tls'
    bits
        number of RSA key bits, default is 2048
    CN
        common name in the request, default is "localhost"
    C
        country, default is "US"
    ST
        state, default is "Utah"
    L
        locality, default is "Centerville", the city where SaltStack originated
    O
        organization, default is "SaltStack"
        NOTE: Must the same as CA certificate or an error will be raised
    OU
        organizational unit, default is None
    emailAddress
        email address for the request, default is None
    cacert_path
        absolute path to ca certificates root directory
    digest
        The message digest algorithm. Must be a string describing a digest
        algorithm supported by OpenSSL (by EVP_get_digestbyname, specifically).
        For example, "md5" or "sha1". Default: 'sha256'
    replace
        Replace this certificate even if it exists

        .. versionadded:: 2015.5.1

    Writes out a Self-Signed Certificate (CERT). If the file already
    exists, the function just returns.

    If the following values were set::

        ca.cert_base_path='/etc/pki'
        tls_dir='koji'
        CN='test.egavas.org'

    the resulting CERT, and corresponding key, would be written in the
    following location::

        /etc/pki/koji/certs/test.egavas.org.crt
        /etc/pki/koji/certs/test.egavas.org.key

    CLI Example:

    .. code-block:: bash

        salt '*' tls.create_self_signed_cert

    Passing options from the command line:

    .. code-block:: bash

        salt 'minion' tls.create_self_signed_cert CN='test.mysite.org'

def create_self_signed_cert(tls_dir='tls',
                            bits=2048,
                            days=365,
                            CN='localhost',
                            C='US',
                            ST='Utah',
                            L='Salt Lake City',
                            O='SaltStack',
                            OU=None,
                            emailAddress=None,
                            cacert_path=None,
                            cert_filename=None,
                            digest='sha256',
                            replace=False):
    '''
    Create a Self-Signed Certificate (CERT)

    tls_dir
        location appended to the ca.cert_base_path, default is 'tls'
    bits
        number of RSA key bits, default is 2048
    CN
        common name in the request, default is "localhost"
    C
        country, default is "US"
    ST
        state, default is "Utah"
    L
        locality, default is "Centerville", the city where SaltStack originated
    O
        organization, default is "SaltStack"
        NOTE: Must the same as CA certificate or an error will be raised
    OU
        organizational unit, default is None
    emailAddress
        email address for the request, default is None
    cacert_path
        absolute path to ca certificates root directory
    digest
        The message digest algorithm. Must be a string describing a digest
        algorithm supported by OpenSSL (by EVP_get_digestbyname, specifically).
        For example, "md5" or "sha1". Default: 'sha256'
    replace
        Replace this certificate even if it exists

        .. versionadded:: 2015.5.1

    Writes out a Self-Signed Certificate (CERT). If the file already
    exists, the function just returns.

    If the following values were set::

        ca.cert_base_path='/etc/pki'
        tls_dir='koji'
        CN='test.egavas.org'

    the resulting CERT, and corresponding key, would be written in the
    following location::

        /etc/pki/koji/certs/test.egavas.org.crt
        /etc/pki/koji/certs/test.egavas.org.key

    CLI Example:

    .. code-block:: bash

        salt '*' tls.create_self_signed_cert

    Passing options from the command line:

    .. code-block:: bash

        salt 'minion' tls.create_self_signed_cert CN='test.mysite.org'
    '''
    set_ca_path(cacert_path)

    if not os.path.exists('{0}/{1}/certs/'.format(cert_base_path(), tls_dir)):
        os.makedirs("{0}/{1}/certs/".format(cert_base_path(),
                                            tls_dir))

    if not cert_filename:
        cert_filename = CN

    if not replace and os.path.exists(
            '{0}/{1}/certs/{2}.crt'.format(cert_base_path(),
                                           tls_dir, cert_filename)
    ):
        return 'Certificate "{0}" already exists'.format(cert_filename)

    key = OpenSSL.crypto.PKey()
    key.generate_key(OpenSSL.crypto.TYPE_RSA, bits)

    # create certificate
    cert = OpenSSL.crypto.X509()
    cert.set_version(2)

    cert.gmtime_adj_notBefore(0)
    cert.gmtime_adj_notAfter(int(days) * 24 * 60 * 60)

    cert.get_subject().C = C
    cert.get_subject().ST = ST
    cert.get_subject().L = L
    cert.get_subject().O = O
    if OU:
        cert.get_subject().OU = OU
    cert.get_subject().CN = CN
    if emailAddress:
        cert.get_subject().emailAddress = emailAddress

    cert.set_serial_number(_new_serial(tls_dir))
    cert.set_issuer(cert.get_subject())
    cert.set_pubkey(key)
    cert.sign(key, salt.utils.stringutils.to_str(digest))

    # Write private key and cert
    priv_key_path = '{0}/{1}/certs/{2}.key'.format(cert_base_path(),
                                                   tls_dir,
                                                   cert_filename)
    with salt.utils.files.fopen(priv_key_path, 'wb+') as priv_key:
        priv_key.write(
            salt.utils.stringutils.to_bytes(
                OpenSSL.crypto.dump_privatekey(OpenSSL.crypto.FILETYPE_PEM,
                                               key)
            )
        )

    crt_path = '{0}/{1}/certs/{2}.crt'.format(cert_base_path(),
                                              tls_dir,
                                              cert_filename)
    with salt.utils.files.fopen(crt_path, 'wb+') as crt:
        crt.write(
            salt.utils.stringutils.to_bytes(
                OpenSSL.crypto.dump_certificate(
                    OpenSSL.crypto.FILETYPE_PEM,
                    cert
                )
            )
        )

    _write_cert_to_database(tls_dir, cert)

    ret = 'Created Private Key: "{0}/{1}/certs/{2}.key." '.format(
        cert_base_path(),
        tls_dir,
        cert_filename
    )
    ret += 'Created Certificate: "{0}/{1}/certs/{2}.crt."'.format(
        cert_base_path(),
        tls_dir,
        cert_filename
    )

    return ret