def handle(self, country, state, city, org, ou, cn, **options):
        if os.path.exists(settings.CA_KEY):
            raise CommandError("%s: private key already exists." % settings.CA_KEY)
        if os.path.exists(settings.CA_CRT):
            raise CommandError("%s: public key already exists." % settings.CA_CRT)

        now = datetime.utcnow()
        expires = now + timedelta(days=options['expires'])

        key = crypto.PKey()
        key.generate_key(settings.CA_KEY_TYPE, settings.CA_BITSIZE)

        cert = crypto.X509()
        cert.get_subject().C = country
        cert.get_subject().ST = state
        cert.get_subject().L = city
        cert.get_subject().O = org
        cert.get_subject().OU = ou
        cert.get_subject().CN = cn
        cert.set_serial_number(uuid.uuid4().int)
        cert.set_notBefore(format_date(now - timedelta(minutes=5)))
        cert.set_notAfter(format_date(expires))
        cert.set_issuer(cert.get_subject())
        cert.set_pubkey(key)
        cert.sign(key, settings.DIGEST_ALGORITHM)

        cert.add_extensions([
            crypto.X509Extension(str('basicConstraints'), True, str('CA:TRUE, pathlen:0')),
            crypto.X509Extension(str('keyUsage'), 0, str('keyCertSign,cRLSign')),
            crypto.X509Extension(str('subjectKeyIdentifier'), False, str('hash'), subject=cert),
            crypto.X509Extension(str('subjectAltName'), 0, str('DNS:%s' % cn))
        ])
        cert.add_extensions([
            crypto.X509Extension(str('authorityKeyIdentifier'), False, str('keyid:always'), issuer=cert),
        ])

        if options['password'] is None:
            args = []
        elif options['password'] == '':
            args = [str('des3'), getpass()]
        else:
            args = [str('des3'), options['password']]

        oldmask = os.umask(247)
        with open(settings.CA_KEY, 'w') as key_file:
            # TODO: optionally add 'des3', 'passphrase' as args
            key_file.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, key, *args))
        with open(settings.CA_CRT, 'w') as cert_file:
            cert_file.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
        os.umask(oldmask)
    def from_csr(self, csr, subjectAltNames=None, key_usage=None, ext_key_usage=None, days=730,
                 algorithm=None, watchers=None):
        # get algorithm used to sign certificate
        if algorithm is None:
            algorithm = settings.DIGEST_ALGORITHM
        if key_usage is None:
            key_usage = settings.CA_KEY_USAGE
        if ext_key_usage is None:
            ext_key_usage = settings.CA_EXT_KEY_USAGE

        # get certificate information
        req = crypto.load_certificate_request(crypto.FILETYPE_PEM, csr)
        subject = req.get_subject()
        cn = dict(subject.get_components()).get('CN')
        if cn is None:
            raise Exception('CSR has no CommonName!')

        # load CA key and cert
        with open(settings.CA_KEY) as ca_key:
            issuerKey = crypto.load_privatekey(crypto.FILETYPE_PEM, ca_key.read())
        with open(settings.CA_CRT) as ca_crt:
            issuerPub = crypto.load_certificate(crypto.FILETYPE_PEM, ca_crt.read())

        # compute notAfter info
        expires = datetime.today() + timedelta(days=days + 1)
        expires = expires.replace(hour=0, minute=0, second=0, microsecond=0)

        # create signed certificate
        cert = crypto.X509()
        cert.set_serial_number(uuid.uuid4().int)
        cert.set_notBefore(format_date(datetime.utcnow() - timedelta(minutes=5)))
        cert.set_notAfter(format_date(expires))
        cert.set_issuer(issuerPub.get_subject())
        cert.set_subject(req.get_subject())
        cert.set_pubkey(req.get_pubkey())

        # collect any extension
        extensions = []

        # add subjectAltName if given:
        if subjectAltNames:
            subjData = str(','.join(['DNS:%s' % n for n in subjectAltNames]))
            ext = crypto.X509Extension(str('subjectAltName'), 0, subjData)
            extensions.append(ext)

        # set CRL distribution points:
        if settings.CA_CRL_DISTRIBUTION_POINTS:
            value = ','.join(['URI:%s' % uri for uri in settings.CA_CRL_DISTRIBUTION_POINTS])
            extensions.append(crypto.X509Extension(str('crlDistributionPoints'), 0, str(value)))

        # Add issuerAltName
        if settings.CA_ISSUER_ALT_NAME:
            issuerAltName = str('URI:%s' % settings.CA_ISSUER_ALT_NAME)
        else:
            issuerAltName = str('issuer:copy')
        extensions.append(crypto.X509Extension(str('issuerAltName'), 0, issuerAltName,
                                               issuer=issuerPub))

        # Add authorityInfoAccess
        auth_info_access = []
        if settings.CA_OCSP:
            auth_info_access.append('OCSP;URI:%s' % settings.CA_OCSP)
        if settings.CA_ISSUER:
            auth_info_access.append('caIssuers;URI:%s' % settings.CA_ISSUER)
        if auth_info_access:
            auth_info_access = str(','.join(auth_info_access))
            extensions.append(crypto.X509Extension(str('authorityInfoAccess'), 0, auth_info_access))

        # add basicConstraints, keyUsage and extendedKeyUsage
        extensions.append(crypto.X509Extension(str('basicConstraints'), 0, str('CA:FALSE')))
        extensions.append(crypto.X509Extension(str('keyUsage'), 0, str(','.join(key_usage))))
        extensions.append(crypto.X509Extension(str('extendedKeyUsage'), 0,
                                               str(','.join(ext_key_usage))))
        extensions.append(crypto.X509Extension(str('subjectKeyIdentifier'), 0, str('hash'),
                                               subject=cert))
        extensions.append(crypto.X509Extension(str('authorityKeyIdentifier'), 0,
                                               str('keyid,issuer'), issuer=issuerPub))


        cert.add_extensions(extensions)

        # finally sign the certificate:
        cert.sign(issuerKey, algorithm)

        # create database object
        crt = crypto.dump_certificate(crypto.FILETYPE_PEM, cert)
        obj = self.create(csr=csr, pub=crt, cn=cn, expires=expires)

        # add watchers:
        if watchers:
            obj.watchers.add(*watchers)

        return obj