<commit_before>"""
.. module: lemur.certificates.models
    :platform: Unix
    :copyright: (c) 2015 by Netflix Inc., see AUTHORS for more
    :license: Apache, see LICENSE for more details.
.. moduleauthor:: <NAME> <<EMAIL>>
"""
import os
import datetime
from cryptography import x509
from cryptography.hazmat.backends import default_backend

from flask import current_app

from sqlalchemy.orm import relationship
from sqlalchemy import Integer, ForeignKey, String, DateTime, PassiveDefault, func, Column, Text, Boolean

from sqlalchemy_utils import EncryptedType

from lemur.database import db

from lemur.domains.models import Domain
from lemur.users import service as user_service

from lemur.constants import SAN_NAMING_TEMPLATE, DEFAULT_NAMING_TEMPLATE, NONSTANDARD_NAMING_TEMPLATE
from lemur.models import certificate_associations, certificate_account_associations


def cert_get_cn(cert):
    """
    Attempts to get a sane common name from a given certificate.

    :param cert:
    :return: Common name or None
    """
    try:
        return cert.subject.get_attributes_for_oid(
            x509.OID_COMMON_NAME
        )[0].value.strip()
    except Exception as e:
        current_app.logger.error("Unable to get CN! {0}".format(e))


def cert_get_domains(cert):
    """
    Attempts to get an domains listed in a certificate.
    If 'subjectAltName' extension is not available we simply
    return the common name.

    :param cert:
    :return: List of domains
    """
    domains = []
    try:
        ext = cert.extensions.get_extension_for_oid(x509.OID_SUBJECT_ALTERNATIVE_NAME)
        entries = ext.get_values_for(x509.DNSName)
        for entry in entries:
            domains.append(entry.split(":")[1].strip(", "))
    except Exception as e:
        current_app.logger.warning("Failed to get SubjectAltName: {0}".format(e))
        domains.append(cert_get_cn(cert))
    return domains


def cert_get_serial(cert):
    """
    Fetch the serial number from the certificate.

    :param cert:
    :return: serial number
    """
    return cert.serial


def cert_is_san(cert):
    """
    Determines if a given certificate is a SAN certificate.
    SAN certificates are simply certificates that cover multiple domains.

    :param cert:
    :return: Bool
    """
    domains = cert_get_domains(cert)
    if len(domains) > 1:
        return True
    return False


def cert_is_wildcard(cert):
    """
    Determines if certificate is a wildcard certificate.

    :param cert:
    :return: Bool
    """
    domains = cert_get_domains(cert)
    if len(domains) == 1 and domains[0][0:1] == "*":
        return True
    return False


def cert_get_bitstrength(cert):
    """
    Calculates a certificates public key bit length.

    :param cert:
    :return: Integer
    """
    return cert.public_key().key_size * 8


def cert_get_issuer(cert):
    """
    Gets a sane issuer from a given certificate.

    :param cert:
    :return: Issuer
    """
    try:
        return cert.subject.get_attributes_for_oid(x509.OID_ORGANIZATION_NAME)[0].value
    except Exception as e:
        current_app.logger.error("Unable to get issuer! {0}".format(e))


def cert_is_internal(cert):
    """
    Uses an internal resource in order to determine if
    a given certificate was issued by an 'internal' certificate
    authority.

    :param cert:
    :return: Bool
    """
    if cert_get_issuer(cert) in current_app.config.get('INTERNAL_CA', []):
        return True
    return False


def cert_get_not_before(cert):
    """
    Gets the naive datetime of the certificates 'not_before' field.<commit_msg>Fixes an issue where the issuer has special chars in the name. AWS dislikes special chars in certificate names so we strip them out here. In general we want to have the name tracked by Lemur be the same as what is uploaded to various destinations.<commit_after>"""
.. module: lemur.certificates.models
    :platform: Unix
    :copyright: (c) 2015 by Netflix Inc., see AUTHORS for more
    :license: Apache, see LICENSE for more details.
.. moduleauthor:: <NAME> <<EMAIL>>
"""
import os
import datetime
from cryptography import x509
from cryptography.hazmat.backends import default_backend

from flask import current_app

from sqlalchemy.orm import relationship
from sqlalchemy import Integer, ForeignKey, String, DateTime, PassiveDefault, func, Column, Text, Boolean

from sqlalchemy_utils import EncryptedType

from lemur.database import db

from lemur.domains.models import Domain
from lemur.users import service as user_service

from lemur.constants import SAN_NAMING_TEMPLATE, DEFAULT_NAMING_TEMPLATE, NONSTANDARD_NAMING_TEMPLATE
from lemur.models import certificate_associations, certificate_account_associations


def cert_get_cn(cert):
    """
    Attempts to get a sane common name from a given certificate.

    :param cert:
    :return: Common name or None
    """
    try:
        return cert.subject.get_attributes_for_oid(
            x509.OID_COMMON_NAME
        )[0].value.strip()
    except Exception as e:
        current_app.logger.error("Unable to get CN! {0}".format(e))


def cert_get_domains(cert):
    """
    Attempts to get an domains listed in a certificate.
    If 'subjectAltName' extension is not available we simply
    return the common name.

    :param cert:
    :return: List of domains
    """
    domains = []
    try:
        ext = cert.extensions.get_extension_for_oid(x509.OID_SUBJECT_ALTERNATIVE_NAME)
        entries = ext.get_values_for(x509.DNSName)
        for entry in entries:
            domains.append(entry.split(":")[1].strip(", "))
    except Exception as e:
        current_app.logger.warning("Failed to get SubjectAltName: {0}".format(e))
        domains.append(cert_get_cn(cert))
    return domains


def cert_get_serial(cert):
    """
    Fetch the serial number from the certificate.

    :param cert:
    :return: serial number
    """
    return cert.serial


def cert_is_san(cert):
    """
    Determines if a given certificate is a SAN certificate.
    SAN certificates are simply certificates that cover multiple domains.

    :param cert:
    :return: Bool
    """
    domains = cert_get_domains(cert)
    if len(domains) > 1:
        return True
    return False


def cert_is_wildcard(cert):
    """
    Determines if certificate is a wildcard certificate.

    :param cert:
    :return: Bool
    """
    domains = cert_get_domains(cert)
    if len(domains) == 1 and domains[0][0:1] == "*":
        return True
    return False


def cert_get_bitstrength(cert):
    """
    Calculates a certificates public key bit length.

    :param cert:
    :return: Integer
    """
    return cert.public_key().key_size * 8


def cert_get_issuer(cert):
    """
    Gets a sane issuer from a given certificate.

    :param cert:
    :return: Issuer
    """
    delchars = ''.join(c for c in map(chr, range(256)) if not c.isalnum())
    try:
        issuer = str(cert.subject.get_attributes_for_oid(x509.OID_ORGANIZATION_NAME)[0].value)
        return issuer.translate(None, delchars)
    except Exception as e:
        current_app.logger.error("Unable to get issuer! {0}".format(e))


def cert_is_internal(cert):
    """
    Uses an internal resource in order to determine if
    a given certificate was issued by an 'internal' certificate
    authority.

    :param cert:
    :return: Bool
    """
    if cert_get_issuer(cert) in current_app.config.get('INTERNAL_CA', []):
        return True
    return False


def cert_get_not_before(cert):
    """
    Gets the naive datetime of the certificates 'not_before' field.
{'fraction_non_alphanumeric': 0.08870116156282999, 'fraction_numerical': 0.008579725448785639, 'mean_word_length': 3.2353269983230857, 'pattern_counts': {'":': 4, '<': 9, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7459255', 'n_tokens_mistral': 2392, 'n_tokens_neox': 2230, 'n_words': 719}