Example #1
0
def generate_ca_cert(base_year, quiet=False):
    if not quiet:
        write('Generating ca cert ... ', end='')

    public_key = load_public('ca')
    private_key = load_private('ca')

    builder = CertificateBuilder(
        {
            'country_name': 'US',
            'state_or_province_name': 'Massachusetts',
            'locality_name': 'Newbury',
            'organization_name': 'Bad TLS Limited',
            'common_name': 'Bad TLS Limited RSA CA',
        },
        public_key
    )
    builder.self_signed = True
    builder.ca = True
    builder.begin_date = datetime(base_year, 1, 1, 0, 0, 0, tzinfo=timezone.utc)
    builder.end_date = datetime(base_year + 10, 1, 1, 0, 0, 0, tzinfo=timezone.utc)
    certificate = builder.build(private_key)

    dump_cert('ca', certificate)

    if not quiet:
        write('done')
Example #2
0
def build_ca():
    if not os.path.exists(settings.CA_PATH):
        os.makedirs(settings.CA_PATH)

    root_ca_public_key, root_ca_private_key = asymmetric.generate_pair(
        'rsa', bit_size=4096)

    with open(settings.CA_KEY, 'wb') as f:
        f.write(
            asymmetric.dump_private_key(root_ca_private_key,
                                        settings.CA_KEY_PASSWD))

    builder = CertificateBuilder(
        {
            'country_name': 'CR',
            'state_or_province_name': 'San Jose',
            'locality_name': 'Costa Rica',
            'organization_name': 'DFVA Independiente',
            'common_name': 'DFVA Root CA 1',
        }, root_ca_public_key)
    now = timezone.now()
    builder.self_signed = True
    builder.ca = True
    builder.end_date = now + timedelta(settings.CA_CERT_DURATION * 10)
    root_ca_certificate = builder.build(root_ca_private_key)

    with open(settings.CA_CERT, 'wb') as f:
        f.write(pem_armor_certificate(root_ca_certificate))

    builder = CertificateListBuilder('http://crl.dfva.info',
                                     root_ca_certificate, 1000)
    crl_list = builder.build(root_ca_private_key)

    with open(settings.CA_CRL, 'wb') as f:
        f.write(crl_list.dump())
Example #3
0
def _gen_ca():
    public, private = _gen_key()
    builder = CertificateBuilder(
        {"organization_name": "Fake Certificate Authority"}, public)
    builder.self_signed = True
    builder.ca = True
    return (_dump_cert(builder.build(private)), _dump_private(private))
def generate_cert_and_key(cn, filename, keysize, keytype='rsa'):
    ca_key_name = '%s.key' % filename
    ca_cert_name = '%s.crt' % filename

    curdir = pathlib.Path(__file__).parent

    # Generate and save the key and certificate for the root CA
    root_ca_public_key, root_ca_private_key = asymmetric.generate_pair(
        keytype, bit_size=keysize)

    with open(curdir.joinpath(ca_key_name), 'wb') as f:
        f.write(asymmetric.dump_private_key(root_ca_private_key, None))

    builder = CertificateBuilder(
        {
            'country_name': 'US',
            'state_or_province_name': 'Massachusetts',
            'locality_name': 'Newbury',
            'organization_name': 'Codex Non Sufficit LC',
            'common_name': cn,
        }, root_ca_public_key)
    builder.self_signed = True
    builder.ca = True
    root_ca_certificate = builder.build(root_ca_private_key)

    with open(curdir.joinpath(ca_cert_name), 'wb') as f:
        f.write(pem_armor_certificate(root_ca_certificate))
Example #5
0
def generate_ca2_cert(base_year, quiet=False):
    if not quiet:
        write('Generating ca2 cert ... ', end='')

    public_key = load_public('ca2')
    private_key = load_private('ca2')

    builder = CertificateBuilder(
        {
            'country_name': 'US',
            'state_or_province_name': 'Massachusetts',
            'locality_name': 'Newbury',
            'organization_name': 'Good TLS Limited',
            'common_name': 'Good TLS Limited RSA CA',
        },
        public_key
    )
    builder.self_signed = True
    builder.ca = True
    builder.begin_date = datetime(base_year, 1, 1, 0, 0, 0, tzinfo=timezone.utc)
    builder.end_date = datetime(base_year + 10, 1, 1, 0, 0, 0, tzinfo=timezone.utc)
    certificate = builder.build(private_key)

    dump_cert('ca2', certificate)

    if not quiet:
        write('done')
    def test_build_ca_cert(self):
        public_key, private_key = self.ec_secp256r1

        builder = CertificateBuilder(
            {
                'country_name': 'US',
                'state_or_province_name': 'Massachusetts',
                'locality_name': 'Newbury',
                'organization_name': 'Codex Non Sufficit LC',
                'common_name': 'Will Bond',
            },
            public_key
        )
        builder.hash_algo = 'sha512'
        builder.self_signed = True
        builder.ca = True
        certificate = builder.build(private_key)
        der_bytes = certificate.dump()

        new_certificate = asn1crypto.x509.Certificate.load(der_bytes)

        self.assertEqual('sha512', new_certificate.hash_algo)
        self.assertEqual(
            {
                'country_name': 'US',
                'state_or_province_name': 'Massachusetts',
                'locality_name': 'Newbury',
                'organization_name': 'Codex Non Sufficit LC',
                'common_name': 'Will Bond',
            },
            new_certificate.issuer.native
        )
        self.assertEqual(
            {
                'country_name': 'US',
                'state_or_province_name': 'Massachusetts',
                'locality_name': 'Newbury',
                'organization_name': 'Codex Non Sufficit LC',
                'common_name': 'Will Bond',
            },
            new_certificate.subject.native
        )
        self.assertEqual('ecdsa', new_certificate.signature_algo)
        self.assertEqual(set(['key_usage', 'basic_constraints']), new_certificate.critical_extensions)
        self.assertEqual(set(['key_cert_sign', 'crl_sign']), new_certificate.key_usage_value.native)
        self.assertEqual(None, new_certificate.extended_key_usage_value)
        self.assertEqual(None, new_certificate.authority_key_identifier)
        self.assertEqual(True, new_certificate.ca)
        self.assertEqual(True, new_certificate.self_issued)
        self.assertEqual('yes', new_certificate.self_signed)
        self.assertEqual(certificate.public_key.sha1, new_certificate.key_identifier)
    def test_build_ca_cert(self):
        public_key, private_key = self.ec_secp256r1

        builder = CertificateBuilder(
            {
                'country_name': 'US',
                'state_or_province_name': 'Massachusetts',
                'locality_name': 'Newbury',
                'organization_name': 'Codex Non Sufficit LC',
                'common_name': 'Will Bond',
            },
            public_key
        )
        builder.hash_algo = 'sha512'
        builder.self_signed = True
        builder.ca = True
        certificate = builder.build(private_key)
        der_bytes = certificate.dump()

        new_certificate = asn1crypto.x509.Certificate.load(der_bytes)

        self.assertEqual('sha512', new_certificate.hash_algo)
        self.assertEqual(
            {
                'country_name': 'US',
                'state_or_province_name': 'Massachusetts',
                'locality_name': 'Newbury',
                'organization_name': 'Codex Non Sufficit LC',
                'common_name': 'Will Bond',
            },
            new_certificate.issuer.native
        )
        self.assertEqual(
            {
                'country_name': 'US',
                'state_or_province_name': 'Massachusetts',
                'locality_name': 'Newbury',
                'organization_name': 'Codex Non Sufficit LC',
                'common_name': 'Will Bond',
            },
            new_certificate.subject.native
        )
        self.assertEqual('ecdsa', new_certificate.signature_algo)
        self.assertEqual(set(['key_usage', 'basic_constraints']), new_certificate.critical_extensions)
        self.assertEqual(set(['key_cert_sign', 'crl_sign']), new_certificate.key_usage_value.native)
        self.assertEqual(None, new_certificate.extended_key_usage_value)
        self.assertEqual(None, new_certificate.authority_key_identifier)
        self.assertEqual(True, new_certificate.ca)
        self.assertEqual(True, new_certificate.self_issued)
        self.assertEqual('yes', new_certificate.self_signed)
        self.assertEqual(certificate.public_key.sha1, new_certificate.key_identifier)
Example #8
0
def create_certificate():
    root_ca_public_key, root_ca_private_key = asymmetric.generate_pair(
        'rsa', bit_size=2048)

    with open('root_ca.key', 'wb') as f:
        f.write(asymmetric.dump_private_key(root_ca_private_key, u'p'))

    with open('root_ca_public.key', 'wb') as f:
        f.write(asymmetric.dump_public_key(root_ca_public_key, 'pem'))

    builder = CertificateBuilder(
        {
            u'country_name': u'US',
            u'state_or_province_name': u'Massachusetts',
            u'locality_name': u'Amherst',
            u'organization_name': u'Name Certifying service',
            u'common_name': u'NCS Root CA',
        }, root_ca_public_key)
    builder.self_signed = True
    builder.ca = True
    root_ca_certificate = builder.build(root_ca_private_key)

    with open('root_ca.crt', 'wb') as f:
        f.write(pem_armor_certificate(root_ca_certificate))

    # Generate an end-entity key and certificate, signed by the root
    end_entity_public_key, end_entity_private_key = asymmetric.generate_pair(
        'rsa', bit_size=2048)

    with open('ramteja_tadishetti_private.key', 'wb') as f:
        f.write(asymmetric.dump_private_key(end_entity_private_key, u'p'))

    with open('ramteja_tadishetti_public.key', 'wb') as f:
        f.write(asymmetric.dump_public_key(end_entity_public_key, 'pem'))

    builder = CertificateBuilder(
        {
            u'country_name': u'US',
            u'state_or_province_name': u'Massachusetts',
            u'locality_name': u'Amherst',
            u'organization_name': u'Ramteja Tadishetti Corp',
            u'common_name': u'ramtejatadishetti',
        }, end_entity_public_key)
    builder.issuer = root_ca_certificate
    #builder.set_extension( u'1.2.840.113549.1.1.1', 'ramteja', allow_deprecated=False)
    end_entity_certificate = builder.build(root_ca_private_key)

    with open('ramteja_tadishetti.crt', 'wb') as f:
        f.write(pem_armor_certificate(end_entity_certificate))
Example #9
0
def create_certificate():
    root_ca_public_key, root_ca_private_key = asymmetric.generate_pair(
        'rsa', bit_size=2048)

    with open('root_ca.key', 'wb') as f:
        f.write(asymmetric.dump_private_key(root_ca_private_key, u'p'))

    with open('root_ca_public.key', 'wb') as f:
        f.write(asymmetric.dump_public_key(root_ca_public_key, 'pem'))

    builder = CertificateBuilder(
        {
            u'country_name': u'US',
            u'state_or_province_name': u'Massachusetts',
            u'locality_name': u'Amherst',
            u'organization_name': u'Name Certifying service',
            u'common_name': u'NCS Root CA',
        }, root_ca_public_key)
    builder.self_signed = True
    builder.ca = True
    root_ca_certificate = builder.build(root_ca_private_key)

    with open('root_ca.crt', 'wb') as f:
        f.write(pem_armor_certificate(root_ca_certificate))
Example #10
0
import json
import sys

f = open("orqIp.txt", "r")
orq_ip = f.read()
f.close()

keyId = sys.argv[1]

r = requests.get("http://" + orq_ip + ":5000/getKey/" + keyId)
response = dict(json.loads(r.text))
pub_key = response["pubKey"]
asn1PublicKey = core.Asn1Value.load(unhexlify(pub_key))
publicKey = keys.PublicKeyInfo.wrap(asn1PublicKey, u'rsa')

builder = CertificateBuilder(
    {
        u'country_name': u'SP',
        u'state_or_province_name': u'Malaga',
        u'locality_name': u'Malaga',
        u'organization_name': u'NICS Lab',
        u'common_name': u'Certificacion Raiz'
    }, publicKey)
builder.self_signed = True
builder.ca = True

root_ca_certificate = builder.build_mpc(int(keyId), orq_ip, "5000")

with open('certificado_raiz.crt', 'wb') as f:
    f.write(pem_armor_certificate(root_ca_certificate))
    def test_build_chain_of_certs(self):
        ca_public_key, ca_private_key = self.ec_secp521r1
        ee_public_key, _ = self.ec_secp256r1

        ca_builder = CertificateBuilder(
            {
                'country_name': 'US',
                'state_or_province_name': 'Massachusetts',
                'locality_name': 'Newbury',
                'organization_name': 'Codex Non Sufficit LC',
                'common_name': 'Codex Non Sufficit LC - Primary CA',
            },
            ca_public_key
        )
        ca_builder.hash_algo = 'sha512'
        ca_builder.self_signed = True
        ca_builder.ca = True
        ca_certificate = ca_builder.build(ca_private_key)

        ee_builder = CertificateBuilder(
            {
                'country_name': 'US',
                'state_or_province_name': 'Massachusetts',
                'locality_name': 'Newbury',
                'organization_name': 'Codex Non Sufficit LC',
                'common_name': 'Will Bond',
            },
            ee_public_key
        )
        ee_builder.issuer = ca_certificate
        ee_builder.serial_number = 1
        ee_certificate = ee_builder.build(ca_private_key)
        der_bytes = ee_certificate.dump()

        new_certificate = asn1crypto.x509.Certificate.load(der_bytes)

        self.assertEqual('sha256', new_certificate.hash_algo)
        self.assertEqual(
            {
                'country_name': 'US',
                'state_or_province_name': 'Massachusetts',
                'locality_name': 'Newbury',
                'organization_name': 'Codex Non Sufficit LC',
                'common_name': 'Codex Non Sufficit LC - Primary CA',
            },
            new_certificate.issuer.native
        )
        self.assertEqual(
            {
                'country_name': 'US',
                'state_or_province_name': 'Massachusetts',
                'locality_name': 'Newbury',
                'organization_name': 'Codex Non Sufficit LC',
                'common_name': 'Will Bond',
            },
            new_certificate.subject.native
        )
        self.assertEqual('ecdsa', new_certificate.signature_algo)
        self.assertEqual(set(['key_usage']), new_certificate.critical_extensions)
        self.assertEqual(set(['digital_signature', 'key_encipherment']), new_certificate.key_usage_value.native)
        self.assertEqual(['server_auth', 'client_auth'], new_certificate.extended_key_usage_value.native)
        self.assertEqual(ca_certificate.key_identifier, new_certificate.authority_key_identifier)
        self.assertEqual(False, new_certificate.ca)
        self.assertEqual(False, new_certificate.self_issued)
        self.assertEqual('no', new_certificate.self_signed)
Example #12
0
def _sign(csr,
          buf,
          profile,
          skip_notify=False,
          skip_push=False,
          overwrite=False,
          signer=None):
    # TODO: CRLDistributionPoints, OCSP URL, Certificate URL
    assert buf.startswith(b"-----BEGIN ")
    assert isinstance(csr, CertificationRequest)
    csr_pubkey = asymmetric.load_public_key(
        csr["certification_request_info"]["subject_pk_info"])
    common_name = csr["certification_request_info"]["subject"].native[
        "common_name"]
    cert_path = os.path.join(config.SIGNED_DIR, "%s.pem" % common_name)
    renew = False

    attachments = [
        (buf, "application/x-pem-file", common_name + ".csr"),
    ]

    revoked_path = None
    overwritten = False

    # Move existing certificate if necessary
    if os.path.exists(cert_path):
        with open(cert_path, "rb") as fh:
            prev_buf = fh.read()
            header, _, der_bytes = pem.unarmor(prev_buf)
            prev = x509.Certificate.load(der_bytes)

            # TODO: assert validity here again?
            renew = \
                asymmetric.load_public_key(prev["tbs_certificate"]["subject_public_key_info"]) == \
                csr_pubkey
            # BUGBUG: is this enough?

        if overwrite:
            # TODO: is this the best approach?
            # TODO: why didn't unittest detect bugs here?
            prev_serial_hex = "%x" % prev.serial_number
            revoked_path = os.path.join(config.REVOKED_DIR,
                                        "%040x.pem" % prev.serial_number)
            os.rename(cert_path, revoked_path)
            attachments += [(prev_buf, "application/x-pem-file",
                             "deprecated.crt" if renew else "overwritten.crt")]
            overwritten = True
        else:
            raise FileExistsError("Will not overwrite existing certificate")

    builder = CertificateBuilder(
        cn_to_dn(common_name,
                 const.FQDN,
                 o=certificate["tbs_certificate"]["subject"].native.get(
                     "organization_name"),
                 ou=profile.ou), csr_pubkey)
    builder.serial_number = generate_serial()

    now = datetime.utcnow()
    builder.begin_date = now - const.CLOCK_SKEW_TOLERANCE
    builder.end_date = now + timedelta(days=profile.lifetime)
    builder.issuer = certificate
    builder.ca = profile.ca
    builder.key_usage = profile.key_usage
    builder.extended_key_usage = profile.extended_key_usage
    builder.subject_alt_domains = [common_name]
    builder.ocsp_url = profile.responder_url
    builder.crl_url = profile.revoked_url

    end_entity_cert = builder.build(private_key)
    end_entity_cert_buf = asymmetric.dump_certificate(end_entity_cert)
    with open(cert_path + ".part", "wb") as fh:
        fh.write(end_entity_cert_buf)

    os.rename(cert_path + ".part", cert_path)
    attachments.append(
        (end_entity_cert_buf, "application/x-pem-file", common_name + ".crt"))
    cert_serial_hex = "%x" % end_entity_cert.serial_number

    # Create symlink
    link_name = os.path.join(config.SIGNED_BY_SERIAL_DIR,
                             "%040x.pem" % end_entity_cert.serial_number)
    assert not os.path.exists(
        link_name
    ), "Certificate with same serial number already exists: %s" % link_name
    os.symlink("../%s.pem" % common_name, link_name)

    # Copy filesystem attributes to newly signed certificate
    if revoked_path:
        for key in listxattr(revoked_path):
            if not key.startswith(b"user."):
                continue
            setxattr(cert_path, key, getxattr(revoked_path, key))

    # Attach signer username
    if signer:
        setxattr(cert_path, "user.signature.username", signer)

    if not skip_notify:
        # Send mail
        if renew:  # Same keypair
            mailer.send("certificate-renewed.md", **locals())
        else:  # New keypair
            mailer.send("certificate-signed.md", **locals())

    if not skip_push:
        url = config.LONG_POLL_PUBLISH % hashlib.sha256(buf).hexdigest()
        click.echo("Publishing certificate at %s ..." % url)
        requests.post(url,
                      data=end_entity_cert_buf,
                      headers={
                          "User-Agent": "Certidude API",
                          "Content-Type": "application/x-x509-user-cert"
                      })
        if renew:
            # TODO: certificate-renewed event
            push.publish("certificate-revoked", common_name)
            push.publish("request-signed", common_name)
        else:
            push.publish("request-signed", common_name)
    return end_entity_cert, end_entity_cert_buf
    def test_build_chain_of_certs(self):
        ca_public_key, ca_private_key = self.ec_secp521r1
        ee_public_key, _ = self.ec_secp256r1

        ca_builder = CertificateBuilder(
            {
                'country_name': 'US',
                'state_or_province_name': 'Massachusetts',
                'locality_name': 'Newbury',
                'organization_name': 'Codex Non Sufficit LC',
                'common_name': 'Codex Non Sufficit LC - Primary CA',
            }, ca_public_key)
        ca_builder.hash_algo = 'sha512'
        ca_builder.self_signed = True
        ca_builder.ca = True
        ca_certificate = ca_builder.build(ca_private_key)

        ee_builder = CertificateBuilder(
            {
                'country_name': 'US',
                'state_or_province_name': 'Massachusetts',
                'locality_name': 'Newbury',
                'organization_name': 'Codex Non Sufficit LC',
                'common_name': 'Will Bond',
            }, ee_public_key)
        ee_builder.issuer = ca_certificate
        ee_builder.serial_number = 1
        ee_certificate = ee_builder.build(ca_private_key)
        der_bytes = ee_certificate.dump()

        new_certificate = asn1crypto.x509.Certificate.load(der_bytes)

        self.assertEqual('sha256', new_certificate.hash_algo)
        self.assertEqual(
            {
                'country_name': 'US',
                'state_or_province_name': 'Massachusetts',
                'locality_name': 'Newbury',
                'organization_name': 'Codex Non Sufficit LC',
                'common_name': 'Codex Non Sufficit LC - Primary CA',
            }, new_certificate.issuer.native)
        self.assertEqual(
            {
                'country_name': 'US',
                'state_or_province_name': 'Massachusetts',
                'locality_name': 'Newbury',
                'organization_name': 'Codex Non Sufficit LC',
                'common_name': 'Will Bond',
            }, new_certificate.subject.native)
        self.assertEqual('ecdsa', new_certificate.signature_algo)
        self.assertEqual(set(['key_usage']),
                         new_certificate.critical_extensions)
        self.assertEqual(set(['digital_signature', 'key_encipherment']),
                         new_certificate.key_usage_value.native)
        self.assertEqual(['server_auth', 'client_auth'],
                         new_certificate.extended_key_usage_value.native)
        self.assertEqual(ca_certificate.key_identifier,
                         new_certificate.authority_key_identifier)
        self.assertEqual(False, new_certificate.ca)
        self.assertEqual(False, new_certificate.self_issued)
        self.assertEqual('no', new_certificate.self_signed)
Example #14
0
def _sign(csr, buf, overwrite=False):
    # TODO: CRLDistributionPoints, OCSP URL, Certificate URL

    assert buf.startswith("-----BEGIN CERTIFICATE REQUEST-----\n")
    assert isinstance(csr, CertificationRequest)
    csr_pubkey = asymmetric.load_public_key(
        csr["certification_request_info"]["subject_pk_info"])
    common_name = csr["certification_request_info"]["subject"].native[
        "common_name"]
    cert_path = os.path.join(config.SIGNED_DIR, "%s.pem" % common_name)
    renew = False

    attachments = [
        (buf, "application/x-pem-file", common_name + ".csr"),
    ]

    revoked_path = None
    overwritten = False

    # Move existing certificate if necessary
    if os.path.exists(cert_path):
        with open(cert_path) as fh:
            prev_buf = fh.read()
            header, _, der_bytes = pem.unarmor(prev_buf)
            prev = x509.Certificate.load(der_bytes)

            # TODO: assert validity here again?
            renew = \
                asymmetric.load_public_key(prev["tbs_certificate"]["subject_public_key_info"]) == \
                csr_pubkey
            # BUGBUG: is this enough?

        if overwrite:
            # TODO: is this the best approach?
            prev_serial_hex = "%x" % prev.serial_number
            revoked_path = os.path.join(config.REVOKED_DIR,
                                        "%s.pem" % prev_serial_hex)
            os.rename(cert_path, revoked_path)
            attachments += [(prev_buf, "application/x-pem-file",
                             "deprecated.crt" if renew else "overwritten.crt")]
            overwritten = True
        else:
            raise EnvironmentError("Will not overwrite existing certificate")

    # Sign via signer process
    builder = CertificateBuilder({u'common_name': common_name}, csr_pubkey)
    builder.serial_number = random.randint(
        0x1000000000000000000000000000000000000000,
        0xffffffffffffffffffffffffffffffffffffffff)

    now = datetime.utcnow()
    builder.begin_date = now - timedelta(minutes=5)
    builder.end_date = now + timedelta(
        days=config.SERVER_CERTIFICATE_LIFETIME
        if server_flags(common_name) else config.CLIENT_CERTIFICATE_LIFETIME)
    builder.issuer = certificate
    builder.ca = False
    builder.key_usage = set([u"digital_signature", u"key_encipherment"])

    # OpenVPN uses CN while StrongSwan uses SAN
    if server_flags(common_name):
        builder.subject_alt_domains = [common_name]
        builder.extended_key_usage = set(
            [u"server_auth", u"1.3.6.1.5.5.8.2.2", u"client_auth"])
    else:
        builder.extended_key_usage = set([u"client_auth"])

    end_entity_cert = builder.build(private_key)
    end_entity_cert_buf = asymmetric.dump_certificate(end_entity_cert)
    with open(cert_path + ".part", "wb") as fh:
        fh.write(end_entity_cert_buf)

    os.rename(cert_path + ".part", cert_path)
    attachments.append(
        (end_entity_cert_buf, "application/x-pem-file", common_name + ".crt"))
    cert_serial_hex = "%x" % end_entity_cert.serial_number

    # Create symlink
    link_name = os.path.join(config.SIGNED_BY_SERIAL_DIR,
                             "%x.pem" % end_entity_cert.serial_number)
    assert not os.path.exists(
        link_name
    ), "Certificate with same serial number already exists: %s" % link_name
    os.symlink("../%s.pem" % common_name, link_name)

    # Copy filesystem attributes to newly signed certificate
    if revoked_path:
        for key in listxattr(revoked_path):
            if not key.startswith("user."):
                continue
            setxattr(cert_path, key, getxattr(revoked_path, key))

    # Send mail
    if renew:  # Same keypair
        mailer.send("certificate-renewed.md", **locals())
    else:  # New keypair
        mailer.send("certificate-signed.md", **locals())

    url = config.LONG_POLL_PUBLISH % hashlib.sha256(buf).hexdigest()
    click.echo("Publishing certificate at %s ..." % url)
    requests.post(url,
                  data=end_entity_cert_buf,
                  headers={
                      "User-Agent": "Certidude API",
                      "Content-Type": "application/x-x509-user-cert"
                  })

    push.publish("request-signed", common_name)
    return end_entity_cert, end_entity_cert_buf
Example #15
0
def _sign(csr,
          buf,
          skip_notify=False,
          skip_push=False,
          overwrite=False,
          profile="default",
          signer=None):
    # TODO: CRLDistributionPoints, OCSP URL, Certificate URL
    if profile not in config.PROFILES:
        raise ValueError("Invalid profile supplied '%s'" % profile)

    assert buf.startswith(b"-----BEGIN ")
    assert isinstance(csr, CertificationRequest)
    csr_pubkey = asymmetric.load_public_key(
        csr["certification_request_info"]["subject_pk_info"])
    common_name = csr["certification_request_info"]["subject"].native[
        "common_name"]
    cert_path = os.path.join(config.SIGNED_DIR, "%s.pem" % common_name)
    renew = False

    attachments = [
        (buf, "application/x-pem-file", common_name + ".csr"),
    ]

    revoked_path = None
    overwritten = False

    # Move existing certificate if necessary
    if os.path.exists(cert_path):
        with open(cert_path, "rb") as fh:
            prev_buf = fh.read()
            header, _, der_bytes = pem.unarmor(prev_buf)
            prev = x509.Certificate.load(der_bytes)

            # TODO: assert validity here again?
            renew = \
                asymmetric.load_public_key(prev["tbs_certificate"]["subject_public_key_info"]) == \
                csr_pubkey
            # BUGBUG: is this enough?

        if overwrite:
            # TODO: is this the best approach?
            prev_serial_hex = "%x" % prev.serial_number
            revoked_path = os.path.join(config.REVOKED_DIR,
                                        "%s.pem" % prev_serial_hex)
            os.rename(cert_path, revoked_path)
            attachments += [(prev_buf, "application/x-pem-file",
                             "deprecated.crt" if renew else "overwritten.crt")]
            overwritten = True
        else:
            raise FileExistsError("Will not overwrite existing certificate")

    # Sign via signer process
    dn = {u'common_name': common_name}
    profile_server_flags, lifetime, dn[
        "organizational_unit_name"], _ = config.PROFILES[profile]
    lifetime = int(lifetime)

    builder = CertificateBuilder(dn, csr_pubkey)
    builder.serial_number = random.randint(
        0x1000000000000000000000000000000000000000,
        0x7fffffffffffffffffffffffffffffffffffffff)

    now = datetime.utcnow()
    builder.begin_date = now - timedelta(minutes=5)
    builder.end_date = now + timedelta(days=lifetime)
    builder.issuer = certificate
    builder.ca = False
    builder.key_usage = set(["digital_signature", "key_encipherment"])

    # If we have FQDN and profile suggests server flags, enable them
    if server_flags(common_name) and profile_server_flags:
        builder.subject_alt_domains = [
            common_name
        ]  # OpenVPN uses CN while StrongSwan uses SAN to match hostname of the server
        builder.extended_key_usage = set(
            ["server_auth", "1.3.6.1.5.5.8.2.2", "client_auth"])
    else:
        builder.subject_alt_domains = [common_name
                                       ]  # iOS demands SAN also for clients
        builder.extended_key_usage = set(["client_auth"])

    end_entity_cert = builder.build(private_key)
    end_entity_cert_buf = asymmetric.dump_certificate(end_entity_cert)
    with open(cert_path + ".part", "wb") as fh:
        fh.write(end_entity_cert_buf)

    os.rename(cert_path + ".part", cert_path)
    attachments.append(
        (end_entity_cert_buf, "application/x-pem-file", common_name + ".crt"))
    cert_serial_hex = "%x" % end_entity_cert.serial_number

    # Create symlink
    link_name = os.path.join(config.SIGNED_BY_SERIAL_DIR,
                             "%x.pem" % end_entity_cert.serial_number)
    assert not os.path.exists(
        link_name
    ), "Certificate with same serial number already exists: %s" % link_name
    os.symlink("../%s.pem" % common_name, link_name)

    # Copy filesystem attributes to newly signed certificate
    if revoked_path:
        for key in listxattr(revoked_path):
            if not key.startswith(b"user."):
                continue
            setxattr(cert_path, key, getxattr(revoked_path, key))

    # Attach signer username
    if signer:
        setxattr(cert_path, "user.signature.username", signer)

    if not skip_notify:
        # Send mail
        if renew:  # Same keypair
            mailer.send("certificate-renewed.md", **locals())
        else:  # New keypair
            mailer.send("certificate-signed.md", **locals())

    if not skip_push:
        url = config.LONG_POLL_PUBLISH % hashlib.sha256(buf).hexdigest()
        click.echo("Publishing certificate at %s ..." % url)
        requests.post(url,
                      data=end_entity_cert_buf,
                      headers={
                          "User-Agent": "Certidude API",
                          "Content-Type": "application/x-x509-user-cert"
                      })

        push.publish("request-signed", common_name)
    return end_entity_cert, end_entity_cert_buf