Beispiel #1
0
def upload_push_certificate_private():
    """Upload a push certificate pubkey to the MDM.
    
    The type of certificate encoding will be guessed from the Content-Type header in the request.
    
    TODO: The reason for invalid certificate should be part of a json response

    :reqheader Accept: application/json
    :reqheader Content-Type: application/pkcs8
    :statuscode 204: no error
    :statuscode 400: invalid certificate supplied
    """
    if request.headers['Content-Type'] not in [
            'application/x-pem-file', 'application/pkcs8'
    ]:
        abort(400, 'Invalid Content-Type supplied for private key')

    if request.headers['Content-Type'] == 'application/x-pem-file':
        pk = RSAPrivateKey(pem_key=request.data)
    else:
        crypto_key = serialization.rsa_from_der(request.data)
        pk = RSAPrivateKey(pem_key=serialization.rsa_to_pem(crypto_key))

    db.session.add(pk)
    db.session.commit()

    return None, 204, None
Beispiel #2
0
def generate_push_certificate_csr():
    """Generate a signed push certificate for upload to the Apple Push Certificate Portal.

    :resheader Content-Type: application/x-pem-file
    :resheader Content-Type: application/x-x509-user-cert
    :resheader Content-Type: application/x-x509-ca-cert
    """
    private_key, csr = ssl.generate_signing_request('commandment')
    private_key_model = RSAPrivateKey.from_crypto(private_key)
    db.session.add(private_key_model)
    csr_model = CertificateSigningRequest.from_crypto(csr)
    db.session.add(csr_model)

    encrypt_with = db.session.query(CACertificate).filter_by(
        x509_cn='COMMANDMENT-CA').one()

    base64_csr = b64encode(csr_model.pem_data)
    base64_recipient = b64encode(encrypt_with.pem_data)

    mdmcert_dict = {
        'csr': base64_csr.decode('utf8'),
        'email': '*****@*****.**',
        'key': MDMCERT_API_KEY,
        'encrypt': base64_recipient.decode('utf8'),
    }
Beispiel #3
0
    def test_rsa_privatekey_from_crypto(self, private_key: rsa.RSAPrivateKeyWithSerialization, session):
        m = RSAPrivateKey.from_crypto(private_key)
        session.add(m)
        session.commit()

        assert m.id is not None
        assert m.pem_data is not None
Beispiel #4
0
    def create(cls, common_name: str = 'COMMANDMENT-CA', key_size=2048):
        ca = cls()
        ca.common_name = common_name
        name = x509.Name([
            x509.NameAttribute(NameOID.COMMON_NAME, common_name),
            x509.NameAttribute(NameOID.ORGANIZATION_NAME, 'commandment')
        ])

        private_key = rsa.generate_private_key(
            public_exponent=65537,
            key_size=key_size,
            backend=default_backend(),
        )
        ca.rsa_private_key = RSAPrivateKey.from_crypto(private_key)

        certificate = x509.CertificateBuilder().subject_name(name).issuer_name(
            name).public_key(private_key.public_key()).serial_number(
                x509.random_serial_number()).not_valid_before(
                    datetime.datetime.utcnow()).not_valid_after(
                        datetime.datetime.utcnow() +
                        datetime.timedelta(days=365)).add_extension(
                            x509.BasicConstraints(ca=True, path_length=None),
                            True).sign(private_key, hashes.SHA256(),
                                       default_backend())

        ca_certificate_model = CACertificate.from_crypto(certificate)
        ca.certificate = ca_certificate_model

        db.session.add(ca)
        db.session.commit()

        return ca
Beispiel #5
0
def mdmcert_request(email: str):
    """Ask the mdmcert.download service to generate a new Certificate Signing Request for the given e-mail address.

    If an encryption certificate does not exist on the system, one will be generated to process the resulting encrypted
    and signed CSR.

    :reqheader Accept: application/json
    :resheader Content-Type: application/json
    """
    try:
        apns_csr_model = db.session.query(CertificateSigningRequest).\
            filter(CertificateSigningRequest.x509_cn == "commandment-apns").one()
    except NoResultFound:
        private_key, csr = cmdssl.generate_signing_request('commandment-apns')
        private_key_model = RSAPrivateKey.from_crypto(private_key)
        db.session.add(private_key_model)
        apns_csr_model = CertificateSigningRequest.from_crypto(csr)
        apns_csr_model.rsa_private_key = private_key_model
        db.session.add(apns_csr_model)
        db.session.commit()

    try:
        encrypt_cert_model = db.session.query(EncryptionCertificate).\
            filter(EncryptionCertificate.x509_cn == 'MDMCERT-DECRYPT').one()
    except NoResultFound:
        encrypt_key, encrypt_with_cert = cmdssl.generate_self_signed_certificate(
            'MDMCERT-DECRYPT')
        encrypt_key_model = RSAPrivateKey.from_crypto(encrypt_key)
        db.session.add(encrypt_key_model)
        encrypt_cert_model = EncryptionCertificate.from_crypto(
            encrypt_with_cert)
        encrypt_cert_model.rsa_private_key = encrypt_key_model
        db.session.add(encrypt_cert_model)
        db.session.commit()

    mdmcert_result = submit_mdmcert_request(
        email=email,
        csr_pem=apns_csr_model.pem_data,
        encrypt_with_pem=encrypt_cert_model.pem_data,
    )

    return jsonify(mdmcert_result)
Beispiel #6
0
def generate_ca(app: Flask):
    """Generate internal CA certificate for sandbox setups."""
    with app.app_context():
        try:
            ca_certificate = db.session.query(CACertificate).filter_by(x509_cn='COMMANDMENT-CA').one()
            logger.debug("COMMANDMENT-CA already generated")

        except sqlalchemy.orm.exc.MultipleResultsFound:
            logger.error("Multiple COMMANDMENT-CA Certificates were found, this should never happen.")

        except sqlalchemy.orm.exc.NoResultFound:
            logger.debug("Generating Private Key for COMMANDMENT-CA")
            # Create CA Certificate if not Available to bootstrap internal CA
            # Issue a Certificate to receive encrypted replies from mdmcert.download
            key = rsa.generate_private_key(
                public_exponent=65537,
                key_size=2048,
                backend=default_backend()
            )
            key_model = RSAPrivateKey.from_crypto(key)
            db.session.add(key_model)

            subject = issuer = x509.Name([
                x509.NameAttribute(NameOID.COMMON_NAME, "COMMANDMENT-CA"),
                x509.NameAttribute(NameOID.ORGANIZATION_NAME, "Commandment")
            ])

            logger.debug("Generating CA Certificate for COMMANDMENT-CA")
            cert = x509.CertificateBuilder().subject_name(
                subject
            ).issuer_name(
                issuer
            ).public_key(
                key.public_key()
            ).serial_number(
                x509.random_serial_number()
            ).not_valid_before(
                datetime.datetime.utcnow()
            ).not_valid_after(
                datetime.datetime.utcnow() + datetime.timedelta(days=900)
            ).add_extension(
                x509.BasicConstraints(ca=True, path_length=None), critical=True
            ).sign(key, hashes.SHA256(), default_backend())

            cert_model = CACertificate.from_crypto(cert)
            db.session.add(cert_model)

            db.session.commit()
Beispiel #7
0
def certificate_download():
    """Create a new key/certificate to upload to the DEP/ASM/ABM portal.

    The private key generated for this certificate will be the key recipient of the DEP S/MIME payload.
    """

    try:
        certificate_model = db.session.query(
            DEPServerTokenCertificate).filter_by(
                x509_cn='COMMANDMENT-DEP').one()
    except sqlalchemy.orm.exc.NoResultFound:
        ca = get_ca()
        private_key = rsa.generate_private_key(
            public_exponent=65537,
            key_size=2048,
            backend=default_backend(),
        )
        private_key_model = RSAPrivateKey.from_crypto(private_key)
        db.session.add(private_key_model)

        name = x509.Name([
            x509.NameAttribute(NameOID.COMMON_NAME, 'COMMANDMENT-DEP'),
            x509.NameAttribute(NameOID.ORGANIZATION_NAME, 'commandment')
        ])

        builder = x509.CertificateSigningRequestBuilder()
        builder = builder.subject_name(name)
        builder = builder.add_extension(x509.BasicConstraints(
            ca=False, path_length=None),
                                        critical=True)

        request = builder.sign(private_key, hashes.SHA256(), default_backend())
        request_model = CertificateSigningRequest.from_crypto(request)
        db.session.add(request_model)

        certificate = ca.sign(request)
        certificate_model = DEPServerTokenCertificate.from_crypto(certificate)
        db.session.add(certificate_model)

        db.session.commit()

    return certificate_model.pem_data, 200, {
        'Content-Type': 'application/x-x509-ca-cert',
        'Content-Disposition': 'attachment; filename="commandment-dep.cer"'
    }
Beispiel #8
0
    def create_device_csr(self, common_name: str) -> (rsa.RSAPrivateKeyWithSerialization, x509.CertificateSigningRequest):
        """
        Create a Certificate Signing Request with the specified Common Name.

        The private key model is automatically committed to the database.
        This is also true for the certificate signing request.

        Args:
            common_name (str): The certificate Common Name attribute

        Returns:
            Tuple[rsa.RSAPrivateKeyWithSerialization, x509.CertificateSigningRequest] - A tuple containing the RSA
            Private key that was generated, along with the CSR.
        """
        private_key = rsa.generate_private_key(
            public_exponent=65537,
            key_size=2048,
            backend=default_backend(),
        )

        private_key_model = RSAPrivateKey.from_crypto(private_key)
        db.session.add(private_key_model)
        db.session.commit()

        name = x509.Name([
            x509.NameAttribute(NameOID.COMMON_NAME, common_name),
            x509.NameAttribute(NameOID.ORGANIZATION_NAME, 'commandment')
        ])

        builder = x509.CertificateSigningRequestBuilder()
        builder = builder.subject_name(name)
        builder = builder.add_extension(x509.BasicConstraints(ca=False, path_length=None), critical=True)

        request = builder.sign(
            private_key,
            hashes.SHA256(),
            default_backend()
        )

        csr_model = CertificateSigningRequest().from_crypto(request)
        db.session.add(csr_model)
        db.session.commit()

        return private_key, request