Beispiel #1
0
    def verify(self, data, signature, ca_name, detached=True):
        """Verify detached SMIME signature.

        Requires CA cert.

        Returns tuple (data, signer_details_dict).
        """

        sm = self.get_verify_ctx(ca_name)

        # init data
        bsign = BIO.MemoryBuffer(signature)
        if RAW_MESSAGES:
            pk = load_pkcs7_bio_der(bsign)
        else:
            pk = SMIME.load_pkcs7_bio(bsign)

        # check signature
        if detached:
            bdata = BIO.MemoryBuffer(data)
            data2 = sm.verify(pk, bdata, flags = SMIME.PKCS7_BINARY | SMIME.PKCS7_DETACHED)
            assert data2 == data
        elif data:
            raise Exception('Have data when detached=False')
        else:
            data2 = sm.verify(pk, flags = SMIME.PKCS7_BINARY)

        return data2, self.get_signature_info(sm, pk)
Beispiel #2
0
def verify_payload(msg, raw_sig, cert, ca_cert, verify_cert):
    # Load the public certificate of the signer
    signer = SMIME.SMIME()
    signer_key = X509.X509_Stack()
    signer_key.push(X509.load_cert(cert))
    signer.set_x509_stack(signer_key)
    signer_store = X509.X509_Store()
    signer_store.load_info(ca_cert)
    signer.set_x509_store(signer_store)

    # Extract the pkcs7 signature and the data
    if raw_sig:
        raw_sig.strip()
        sig = "-----BEGIN PKCS7-----\n%s\n-----END PKCS7-----\n" % raw_sig.replace('\r\n', '\n')
        p7 = SMIME.load_pkcs7_bio(BIO.MemoryBuffer(sig))
        data_bio = BIO.MemoryBuffer(msg)
    else:
        p7, data_bio = SMIME.smime_load_pkcs7_bio(BIO.MemoryBuffer(msg))

    # Verify the signature against the message
    if verify_cert:
        signer.verify(p7, data_bio)
    else:
        # Don't verify the signer certificate if this flag is set
        signer.verify(p7, data_bio, SMIME.PKCS7_NOVERIFY)
Beispiel #3
0
    def test_load_bad(self):
        s = SMIME.SMIME()
        with self.assertRaises(EVP.EVPError):
            s.load_key('tests/signer.pem', 'tests/signer.pem')

        with self.assertRaises(BIO.BIOError):
            SMIME.load_pkcs7('nosuchfile-dfg456')
        with self.assertRaises(SMIME.PKCS7_Error):
            SMIME.load_pkcs7('tests/signer.pem')
        with self.assertRaises(SMIME.PKCS7_Error):
            SMIME.load_pkcs7_bio(BIO.MemoryBuffer(b'no pkcs7'))

        with self.assertRaises(SMIME.SMIME_Error):
            SMIME.smime_load_pkcs7('tests/signer.pem')
        with self.assertRaises(SMIME.SMIME_Error):
            SMIME.smime_load_pkcs7_bio(BIO.MemoryBuffer(b'no pkcs7'))
Beispiel #4
0
def plist_from_pkcs7(pkcs7):
    """Extract a plist from PKCS7 encoded data."""
    # DEP request

    # base64 encode the DER data, and wrap in a PEM-ish format for SMIME.load_pkcs7_bio()
    req_data = base64_to_pem('PKCS7', pkcs7)

    p7_bio = BIO.MemoryBuffer(str(req_data))
    pkcs7 = SMIME.load_pkcs7_bio(p7_bio)

    p7_signers = pkcs7.get0_signers(X509.X509_Stack())

    signer = SMIME.SMIME()
    signer.set_x509_store(X509.X509_Store())
    signer.set_x509_stack(p7_signers)

    # TODO/XXX: not verifying ANY certificates!
    #
    # spec says we should verify against the "Apple Root CA" and that this
    # CMS message contains all intermediates to do that verification.
    # M2Crypto has no way to get at all the intermediate certificates to
    # do this manually we'd need to extract all of the certificates and
    # verify the chain aginst it. Note as of 2016-03-14 on a brand new
    # iPad Apple was including an expired certificate in this chain. Note
    # also that at least one of the intermediate certificates had a
    # certificate purpose apparently not appropraite for CMS/SMIME
    # verification. For now just verify with no CA and skip any
    # verification.
    plist_text = signer.verify(pkcs7, None, flags=SMIME.PKCS7_NOVERIFY)

    plist = plistlib.readPlistFromString(plist_text)

    return plist
Beispiel #5
0
def verify_pkcs7(pkcs7_sig, document):
    try:
        # raw_sig = pkcs7_sig
        raw_sig = str(pkcs7_sig).encode('ascii')
        msg = document

        sm_obj = SMIME.SMIME()
        x509 = X509.load_cert(os.path.join(config.APP_STATIC, 'AWSpubkey'))  # public key cert used by the remote
        # client when signing the message
        sk = X509.X509_Stack()
        sk.push(x509)
        sm_obj.set_x509_stack(sk)

        st = X509.X509_Store()
        st.load_info(os.path.join(config.APP_STATIC, 'AWSpubkey'))  # Public cert for the CA which signed
        # the above certificate
        sm_obj.set_x509_store(st)

        # re-wrap signature so that it fits base64 standards
        cooked_sig = '\n'.join(raw_sig[pos:pos + 76] for pos in xrange(0, len(raw_sig), 76))
        # cooked_sig = raw_sig
        # now, wrap the signature in a PKCS7 block
        sig = ("-----BEGIN PKCS7-----\n" + cooked_sig + "\n-----END PKCS7-----").encode('ascii')

        # and load it into an SMIME p7 object through the BIO I/O buffer:
        buf = BIO.MemoryBuffer(sig)
        p7 = SMIME.load_pkcs7_bio(buf)

        # finally, try to verify it:
        if dict(json.loads(sm_obj.verify(p7))) == dict(json.loads(msg)):
            return True
        else:
            return False
    except Exception as e:
        raise Exception("INVALID CLIENT MESSAGE SIGNATURE")
Beispiel #6
0
def verify_mdm_signature(mdm_sig, req_data):
    '''Verify the client's supplied MDM signature and return the client certificate included in the signature.'''
    pkcs7_pem_sig = base64_to_pem('PKCS7', mdm_sig)

    p7_bio = BIO.MemoryBuffer(str(pkcs7_pem_sig))
    p7 = SMIME.load_pkcs7_bio(p7_bio)

    p7_signers = p7.get0_signers(X509.X509_Stack())

    mdm_ca = get_ca()

    # can probably directly use m2 certificate here
    ca_x509_bio = BIO.MemoryBuffer(mdm_ca.get_cacert().get_pem())
    ca_x509 = X509.load_cert_bio(ca_x509_bio)

    cert_store = X509.X509_Store()
    cert_store.add_x509(ca_x509)

    signer = SMIME.SMIME()
    signer.set_x509_store(cert_store)
    signer.set_x509_stack(p7_signers)

    # NOTE: may need to do something special if we can't cleanly convert
    # to string from Unicode. must be byte-accurate as the signature won't
    # match otherwise
    data_bio = BIO.MemoryBuffer(req_data)

    # will raise an exception if verification fails
    # if no CA certificate we get an:
    #   PKCS7_Error: certificate verify error
    signer.verify(p7, data_bio)

    return p7_signers[0].as_pem()
Beispiel #7
0
def verify_mdm_signature(mdm_sig, req_data):
    '''Verify the client's supplied MDM signature and return the client certificate included in the signature.'''

    p7_bio = BIO.MemoryBuffer(str(mdm_sig))
    p7 = SMIME.load_pkcs7_bio(p7_bio)

    p7_signers = p7.get0_signers(X509.X509_Stack())

    mdm_ca = get_ca()

    # can probably directly use m2 certificate here
    ca_x509_bio = BIO.MemoryBuffer(mdm_ca.get_cacert().to_pem())
    ca_x509 = X509.load_cert_bio(ca_x509_bio)

    cert_store = X509.X509_Store()
    cert_store.add_x509(ca_x509)

    signer = SMIME.SMIME()
    signer.set_x509_store(cert_store)
    signer.set_x509_stack(p7_signers)

    # NOTE: may need to do something special if we can't cleanly convert
    # to string from Unicode. must be byte-accurate as the signature won't
    # match otherwise
    data_bio = BIO.MemoryBuffer(req_data)

    # will raise an exception if verification fails
    # if no CA certificate we get an:
    #   PKCS7_Error: certificate verify error
    signer.verify(p7, data_bio)

    return p7_signers[0].as_pem()
Beispiel #8
0
    def test_load_bad(self):
        s = SMIME.SMIME()
        with self.assertRaises(EVP.EVPError):
            s.load_key('tests/signer.pem',
                       'tests/signer.pem')

        with self.assertRaises(BIO.BIOError):
            SMIME.load_pkcs7('nosuchfile-dfg456')
        with self.assertRaises(SMIME.PKCS7_Error):
            SMIME.load_pkcs7('tests/signer.pem')
        with self.assertRaises(SMIME.PKCS7_Error):
            SMIME.load_pkcs7_bio(BIO.MemoryBuffer('no pkcs7'))

        with self.assertRaises(SMIME.SMIME_Error):
            SMIME.smime_load_pkcs7('tests/signer.pem')
        with self.assertRaises(SMIME.SMIME_Error):
            SMIME.smime_load_pkcs7_bio(BIO.MemoryBuffer('no pkcs7'))
Beispiel #9
0
def verify_sig_cert(sig, sender, local_domain):
    import certvld

    p7 = SMIME.load_pkcs7_bio(BIO.MemoryBuffer(sig))
    certs = p7.get0_signers(X509.X509_Stack())
    if len(certs) == 0:
        return False
    for cert in certs:
        if certvld.verify_cert(cert, local_domain, sender) and certvld.verify_binding(cert, sender, sender.partition('@')[2], True):
            return True
    return False
Beispiel #10
0
    def unlock(self, passphrase):
        s = SMIME.SMIME()
        try:
            s.load_key(settings.RSA_KEYPAIR, settings.RSA_CERTIFICATE,
                       lambda *args: passphrase)
        except:
            raise Lockable.InvalidPassphrase(
                'The supplied passhrase was incorrect.')

        p7 = SMIME.load_pkcs7_bio(BIO.MemoryBuffer(self.ciphertext))
        plaintext = s.decrypt(p7)

        self.plaindict = loads(plaintext)
Beispiel #11
0
def calculate_difference(FILENAME):

    signature_date = None
    certificate_date = None
    certificate_subject = None

    try:
        # open an apk or jar as a ZipFile
        Z = zipfile.ZipFile(open(FILENAME, 'rb'))
    except:
        print 'WARNING: Not a ZipFile', FILENAME
        return signature_date, certificate_date, certificate_subject

    for name in Z.namelist():
        # certificate file
        if (name.endswith("DSA") or (name.endswith("RSA"))):
            try:
                with Z.open(name) as f:
                    fileBytes = f.read()
            except:
                print 'WARNING: Bad ZipFile', name
                return signature_date, certificate_date, certificate_subject
            # encode binary data to base64 and wrap it in a PKCS7 envelop
            sig = '-----BEGIN PKCS7-----\n' + fileBytes.encode(
                'base64') + '-----END PKCS7-----\n'

            # load certificate into a p7 object through BIO I/O buffer:
            buf = BIO.MemoryBuffer(sig)
            p7 = SMIME.load_pkcs7_bio(buf)
            sk = X509.X509_Stack()
            signers = p7.get0_signers(sk)
            # get X509 certificate
            certificate = signers[0]

            dateString = certificate.get_not_before()
            certificate_date = datetime.datetime.strptime(
                str(dateString), '%b %d %H:%M:%S %Y %Z')
            certificate_subject = certificate.get_subject()

        # signature file
        if (name.endswith("SF")):
            try:
                signature_date = datetime.datetime(
                    *Z.getinfo(name).date_time[0:6])
            except ValueError:
                signature_date = datetime.datetime(
                    Z.getinfo(name).date_time[0], 1, 1)

    Z.close()
    return signature_date, certificate_date, certificate_subject
Beispiel #12
0
    def _run(self, scanObject, result, depth, args):
        moduleResult = []

        flags = []

        buffer = scanObject.buffer
        cert = None

        try:
            #scanObject.addMetadata(self.module_name, key, value)

            input_bio = BIO.MemoryBuffer(buffer)

            #Check for PEM or DER
            if buffer[:1] == "0":
                #DER
                p7 = SMIME.PKCS7(m2.pkcs7_read_bio_der(input_bio._ptr()), 1)
            else:
                #PEM
                p7 = SMIME.load_pkcs7_bio(input_bio)

            certs = p7.get0_signers(X509.X509_Stack())

            #some pkcs7's should have more than one certificate in them. openssl can extract them handily.
            #openssl pkcs7 -inform der -print_certs -in MYKEY.DSA
            i = 0
            for cert in certs:
                cert_filename = "%x.der" % (cert.get_serial_number())
                moduleResult.append(
                    ModuleObject(
                        buffer=cert.as_der(),
                        externalVars=ExternalVars(filename=cert_filename)))
                i = i + 1

        except (QuitScanException, GlobalScanTimeoutError,
                GlobalModuleTimeoutError):
            raise
        except:
            exc_type, exc_value, exc_traceback = sys.exc_info()
            logging.exception("Error parsing cert in " +
                              str(get_scanObjectUID(getRootObject(result))))

            ugly_error_string = str(exc_value)
            #nicer_error_string = string.split(string.split(ugly_error_string,":")[4])[0]
            nicer_error_string = ugly_error_string.split(":")[4].split()[0]

            scanObject.addFlag("pkcs7:err:" + nicer_error_string)

        return moduleResult
Beispiel #13
0
    def _run(self, scanObject, result, depth, args):
        moduleResult = [] 

        flags = []
        

        buffer = scanObject.buffer
        cert = None
        
        try:
            #scanObject.addMetadata(self.module_name, key, value)    

            input_bio = BIO.MemoryBuffer(buffer)

            #Check for PEM or DER
            if buffer[:1] == "0":
                #DER
                p7 = SMIME.PKCS7(m2.pkcs7_read_bio_der(input_bio._ptr()), 1)
            else:
                #PEM
                p7 = SMIME.load_pkcs7_bio(input_bio)    
            
            
            certs = p7.get0_signers(X509.X509_Stack())
            
            
            #some pkcs7's should have more than one certificate in them. openssl can extract them handily.
            #openssl pkcs7 -inform der -print_certs -in MYKEY.DSA
            i=0
            for cert in certs:
                cert_filename = "%x.der" % (cert.get_serial_number())
                moduleResult.append(ModuleObject(buffer=cert.as_der(),externalVars=ExternalVars(filename=cert_filename)))
                i = i + 1
            
        except (QuitScanException, GlobalScanTimeoutError, GlobalModuleTimeoutError):
            raise
        except:
            exc_type, exc_value, exc_traceback = sys.exc_info()
            logging.exception("Error parsing cert in "+str(get_scanObjectUID(getRootObject(result))))
            
            ugly_error_string = str(exc_value)
            #nicer_error_string = string.split(string.split(ugly_error_string,":")[4])[0]
            nicer_error_string = ugly_error_string.split(":")[4].split()[0]
                        
            scanObject.addFlag("pkcs7:err:"+nicer_error_string)
            
            
       
        return moduleResult
Beispiel #14
0
    def decrypt(self, ciphtext, receiver_name):
        """Decrypt message.

        Requires private key and it's cert.

        Returns decrypted message.
        """

        sm = self.get_decrypt_ctx(receiver_name)

        # decrypt
        bdata = BIO.MemoryBuffer(ciphtext)
        if RAW_MESSAGES:
            pk = load_pkcs7_bio_der(bdata)
        else:
            pk = SMIME.load_pkcs7_bio(bdata)
        return sm.decrypt(pk, SMIME.PKCS7_BINARY)
Beispiel #15
0
def verify_payload(msg, raw_sig, cert, ca_cert, verify_cert):
    signer = SMIME.SMIME()
    signerKey = X509.X509_Stack()
    signerKey.push(X509.load_cert(cert))
    signer.set_x509_stack(signerKey)
    signerStore = X509.X509_Store()
    signerStore.load_info(ca_cert)
    signer.set_x509_store(signerStore)
    if raw_sig:
        raw_sig.strip()
        sig = "-----BEGIN PKCS7-----\n%s\n-----END PKCS7-----\n"%raw_sig.replace('\r\n','\n')
        p7 = SMIME.load_pkcs7_bio(BIO.MemoryBuffer(sig))
        data_bio = BIO.MemoryBuffer(msg)
        if verify_cert:
            signer.verify(p7, data_bio)
        else:
            signer.verify(p7, data_bio,SMIME.PKCS7_NOVERIFY)
    else:
        p7, data_bio = SMIME.smime_load_pkcs7_bio(BIO.MemoryBuffer(msg))
        signer.verify(p7, data_bio)
Beispiel #16
0
def verify_pkcs7(pkcs7_sig, document):
    try:
        # raw_sig = pkcs7_sig
        raw_sig = str(pkcs7_sig).encode('ascii')
        msg = document

        sm_obj = SMIME.SMIME()
        x509 = X509.load_cert(
            os.path.join(config.APP_STATIC,
                         'AWSpubkey'))  # public key cert used by the remote
        # client when signing the message
        sk = X509.X509_Stack()
        sk.push(x509)
        sm_obj.set_x509_stack(sk)

        st = X509.X509_Store()
        st.load_info(
            os.path.join(config.APP_STATIC,
                         'AWSpubkey'))  # Public cert for the CA which signed
        # the above certificate
        sm_obj.set_x509_store(st)

        # re-wrap signature so that it fits base64 standards
        cooked_sig = '\n'.join(raw_sig[pos:pos + 76]
                               for pos in xrange(0, len(raw_sig), 76))
        # cooked_sig = raw_sig
        # now, wrap the signature in a PKCS7 block
        sig = ("-----BEGIN PKCS7-----\n" + cooked_sig +
               "\n-----END PKCS7-----").encode('ascii')

        # and load it into an SMIME p7 object through the BIO I/O buffer:
        buf = BIO.MemoryBuffer(sig)
        p7 = SMIME.load_pkcs7_bio(buf)

        # finally, try to verify it:
        if dict(json.loads(sm_obj.verify(p7))) == dict(json.loads(msg)):
            return True
        else:
            return False
    except Exception as e:
        raise Exception("INVALID CLIENT MESSAGE SIGNATURE")
def verifySignature(signaturePkcs7, hash, chainOfTrust):
    # see also in AM: src/crypto-lib/signature.cpp / Signature::verify()

    s = SMIME.SMIME()

    bioSignature = BIO.MemoryBuffer(data=base64.decodestring(signaturePkcs7))
    signature = SMIME.load_pkcs7_bio(bioSignature)
    bioHash = BIO.MemoryBuffer(data=hash)
    certChain = X509.X509_Store()

    for trustedCert in chainOfTrust:
        bioCert = BIO.MemoryBuffer(data=trustedCert)

        while len(bioCert):
            cert = X509.load_cert_bio(bioCert, X509.FORMAT_PEM)
            certChain.add_x509(cert)

    s.set_x509_store(certChain)
    s.set_x509_stack(X509.X509_Stack())

    s.verify(signature, bioHash, SMIME.PKCS7_NOCHAIN)
def verifySignature(signaturePkcs7, hash, chainOfTrust):
    # see also in AM: src/crypto-lib/signature.cpp / Signature::verify()

    s = SMIME.SMIME()

    bioSignature = BIO.MemoryBuffer(data = base64.decodestring(signaturePkcs7))
    signature = SMIME.load_pkcs7_bio(bioSignature)
    bioHash = BIO.MemoryBuffer(data = hash)
    certChain = X509.X509_Store()

    for trustedCert in chainOfTrust:
        bioCert = BIO.MemoryBuffer(data = trustedCert)

        while len(bioCert):
            cert = X509.load_cert_bio(bioCert, X509.FORMAT_PEM)
            certChain.add_x509(cert)

    s.set_x509_store(certChain)
    s.set_x509_stack(X509.X509_Stack())

    s.verify(signature, bioHash, SMIME.PKCS7_NOCHAIN)
 def validate_smime(self, msg_part, ):
     '''
     Validates SMIME certs
     :param  msg_part: email.message
     :return signer_certs: valid signer certs
     '''
     _dashes = '-----'
     if self._smime is None:
         self.__setup_smimesetup()
     if msg_part.get_content_type() in self.SMIME_CONTENT_TYPES:
         with TemporaryFile('r+b') as fh:
             fh.write('%sBEGIN PKCS7%s\n%s\n%sEND PKCS7%s' % (
                         _dashes, _dashes,
                         msg_part.get_payload(),
                         _dashes, _dashes
                     ))
             fh.seek(0)
             pfh = BIO.File(fh)
             p7 = SMIME.load_pkcs7_bio(pf)
             sk3 = p7.get0_signers(X509.X509_Stack())
             if len(sk3) == 0:
                 raise []
             signer_certs = []
             for cert in sk3:
                 signer_certs.append(
                     "%sBEGIN CERTIFICATE%s\n%s\n%sEND CERTIFICATE%s" % (
                         _dashes, _dashes,
                         base64.encodestring(cert.as_der()),
                         _dashes, _dashes
                     ))
             self._smime.set_x509_stack(sk3)
             try:
                 v = self._smime.verify(p7)
             except SMIME.SMIME_Error, e:
                 return []
             if data_bio is not None and data != v:
                 raise []
             return signer_certs
Beispiel #20
0
from M2Crypto import BIO, SMIME

pf = BIO.openfile('pkcs7-thawte.pem')
p7 = SMIME.load_pkcs7_bio(pf)
print p7.type(1)

Beispiel #21
0
    def PUT(self):
        global current_command, last_result
        HIGH=''
        LOW=''
        NORMAL=''

        i = web.data()
        pl = readPlistFromString(i)

        if 'HTTP_MDM_SIGNATURE' in web.ctx.environ:
            raw_sig = web.ctx.environ['HTTP_MDM_SIGNATURE']
            cooked_sig = '\n'.join(raw_sig[pos:pos+76] for pos in xrange(0, len(raw_sig), 76))
    
            signature = """
-----BEGIN PKCS7-----
%s
-----END PKCS7-----
""" % cooked_sig


            #print i
            #print signature

            buf = BIO.MemoryBuffer(signature)
            p7 = SMIME.load_pkcs7_bio(buf)
            data_bio = BIO.MemoryBuffer(i)
            try:
                v = sm_obj.verify(p7, data_bio)
                if v:
                    print "Client signature verified."
            except:
                print "*** INVALID CLIENT MESSAGE SIGNATURE ***"

        print "%sReceived %4d bytes: %s" % (HIGH, len(web.data()), NORMAL),

        if pl.get('Status') == 'Idle':
            print HIGH + "Idle Status" + NORMAL
            rd = current_command
            print "%sSent: %s%s" % (HIGH, rd['Command']['RequestType'], NORMAL)
#            print HIGH, rd, NORMAL

        elif pl.get('MessageType') == 'TokenUpdate':
            print HIGH+"Token Update"+NORMAL
            rd = do_TokenUpdate(pl)
            print HIGH+"Device Enrolled!"+NORMAL

        elif pl.get('Status') == 'Acknowledged':
            print HIGH+"Acknowledged"+NORMAL
            rd = dict()

        else:
            rd = dict()
            if pl.get('MessageType') == 'Authenticate':
                print HIGH+"Authenticate"+NORMAL
            elif pl.get('MessageType') == 'CheckOut':
                print HIGH+"Device leaving MDM"+ NORMAL
            else:
                print HIGH+"(other)"+NORMAL
                print HIGH, pl, NORMAL
        log_data(pl)
        log_data(rd)

        out = writePlistToString(rd)
#        print LOW, out, NORMAL

        q = pl.get('QueryResponses')
        last_result = pprint.pformat(pl)
        return out
Beispiel #22
0
    raw_sig = sign_part.get_payload().replace("\n", "")
    # re-wrap signature so that it fits base64 standards
    cooked_sig = '\n'.join(raw_sig[pos:pos + 76]
                           for pos in xrange(0, len(raw_sig), 76))

    if sign_type == 'smime':
        # now, wrap the signature in a PKCS7 block
        sig = """
-----BEGIN PKCS7-----
%s
-----END PKCS7-----
		""" % cooked_sig

        # and load it into an SMIME p7 object through the BIO I/O buffer:
        buf = BIO.MemoryBuffer(sig)
        p7 = SMIME.load_pkcs7_bio(buf)

        sk = X509.X509_Stack()
        signers = p7.get0_signers(sk)
        signing_cert = signers[0]

        signing_cert.save(os.path.join(CERT_PATH, from_addr))

    elif sign_type == 'pgp':
        # send POST to localost on port 11371 which points to our HTTP registration page
        sig = cooked_sig
        payload = {'email': from_addr, 'key': sig}
        r = requests.post("http://127.0.0.1:11371", data=payload)

    # format in user-specific data
    success_msg = file(cfg['smime']['mail_templates'] +
Beispiel #23
0
    def PUT(self):
        global sm_obj, device_list
        HIGH=''
        LOW=''
        NORMAL=''

        i = web.data()
        pl = readPlistFromString(i)

	print pl
	print web.ctx.environ

        if 'HTTP_MDM_SIGNATURE' in web.ctx.environ:
            raw_sig = web.ctx.environ['HTTP_MDM_SIGNATURE']
            cooked_sig = '\n'.join(raw_sig[pos:pos+76] for pos in xrange(0, len(raw_sig), 76))

            signature = '\n-----BEGIN PKCS7-----\n%s\n-----END PKCS7-----\n' % cooked_sig

            # Verify client signature - necessary?
            buf = BIO.MemoryBuffer(signature)
            p7 = SMIME.load_pkcs7_bio(buf)
            data_bio = BIO.MemoryBuffer(i)
            try:
                v = sm_obj.verify(p7, data_bio)
                if v:
                    print "Client signature verified."
            except:
                print "*** INVALID CLIENT MESSAGE SIGNATURE ***"

        print "%sReceived %4d bytes: %s" % (HIGH, len(web.data()), NORMAL),

        if pl.get('Status') == 'Idle':
            print HIGH + "Idle Status" + NORMAL

            print "*FETCHING CMD TO BE SENT FROM DEVICE:", pl['UDID']
            rd = device_list[pl['UDID']].sendCommand()

            # If no commands in queue, return empty string to avoid infinite idle loop
            if(not rd):
                return ''

            print "%sSent: %s%s" % (HIGH, rd['Command']['RequestType'], NORMAL)

        elif pl.get('MessageType') == 'TokenUpdate':
            print HIGH+"Token Update"+NORMAL
            rd = do_TokenUpdate(pl)
            print HIGH+"Device Enrolled!"+NORMAL

        elif pl.get('Status') == 'Acknowledged':
            global devicesAwaitingConfiguration
            print HIGH+"Acknowledged"+NORMAL
            rd = dict()
            # A command has returned a response
            # Add the response to the given device
            print "*CALLING ADD RESPONSE TO CMD:", pl['CommandUUID']
            device_list[pl['UDID']].addResponse(pl['CommandUUID'], pl)

            # If we grab device information, we should also update the device info
            if pl.get('QueryResponses'):
                print "DeviceInformation should update here..."
                p = pl['QueryResponses']
                device_list[pl['UDID']].updateInfo(p['DeviceName'], p['ModelName'], p['OSVersion'])

            if pl.get('RequestType') and 'SetupConfiguration' in pl.get('RequestType'):
                print HIGH+"Device completed SetupConfiguration command!"+NORMAL
                print HIGH+"Sending DeviceConfigured command now."+NORMAL

                queue('DeviceConfigured', pl['UDID'])

                print HIGH+"Removing device from devicesAwaitingConfiguration list..."+NORMAL
                devicesAwaitingConfiguration[pl['UDID']]['status'] = 'DeviceConfigured'
                devicesAwaitingConfiguration[pl['UDID']]['mtime'] = int(datetime.now().strftime('%s'))
                print HIGH+"Removed device from devicesAwaitingConfiguration list"+NORMAL

            if pl.get('RequestType') and 'DeviceConfigured' in pl.get('RequestType'):
                devicesAwaitingConfiguration[pl['UDID']] = { 'status': 'InstallApplication',
                                                             'mtime': int(datetime.now().strftime('%s'))}
                print HIGH+"Sending InstallManagementTools command now."+NORMAL
                sleep(5)
                queue('InstallManagementTools', pl['UDID'])
                sleep(5)

            if pl.get('RequestType') and 'InstallApplication' in pl.get('RequestType'):
                devicesAwaitingConfiguration[pl['UDID']] = { 'status': 'AllDone',
                                                             'mtime': int(datetime.now().strftime('%s'))}
                sleep(5)

            # Update pickle file with new response
            store_devices()
        else:
            rd = dict()
            if pl.get('MessageType') == 'Authenticate':
                print HIGH+"Authenticate"+NORMAL
            elif pl.get('MessageType') == 'CheckOut':
                print HIGH+"Device leaving MDM"+ NORMAL
            elif pl.get('Status') == 'Error':
                print "*CALLING ADD RESPONSE WITH ERROR TO CMD:", pl['CommandUUID']
                device_list[pl['UDID']].addResponse(pl['CommandUUID'], pl)
            elif pl.get('Status') == 'NotNow':
                print "*CALLING ADD RESPONSE WITH NotNow TO CMD:", pl['CommandUUID']
                device_list[pl['UDID']].addResponse(pl['CommandUUID'], pl)

                now = int(datetime.now().strftime('%s'))
                mtime = devicesAwaitingConfiguration[pl['UDID']]['mtime']

                queue('DeviceInformation', pl['UDID'])

                if now - mtime > 5:
                    if 'InstallApplication' in devicesAwaitingConfiguration[udid]['status']:
                        print "*Sending command %s again to device %s" % (pl['RequestType'], pl['UDID'])
                        devicesAwaitingConfiguration[pl['UDID']]['mtime'] = now
                        queue('InstallApplication', pl['UDID'])
            else:
                print HIGH+"(other)"+NORMAL
                print HIGH, pl, NORMAL
        log_data(pl)
        log_data(rd)

        out = writePlistToString(rd)
        #print LOW, out, NORMAL

        return out
    def PUT(self):
        global sm_obj, device_list
        HIGH=''
        LOW=''
        NORMAL=''

        i = web.data()
        pl = readPlistFromString(i)

        if 'HTTP_MDM_SIGNATURE' in web.ctx.environ:
            raw_sig = web.ctx.environ['HTTP_MDM_SIGNATURE']
            cooked_sig = '\n'.join(raw_sig[pos:pos+76] for pos in xrange(0, len(raw_sig), 76))

            signature = '\n-----BEGIN PKCS7-----\n%s\n-----END PKCS7-----\n' % cooked_sig

            # Verify client signature - necessary?
            buf = BIO.MemoryBuffer(signature)
            p7 = SMIME.load_pkcs7_bio(buf)
            data_bio = BIO.MemoryBuffer(i)
            try:
                v = sm_obj.verify(p7, data_bio)
                if v:
                    print "Client signature verified."
            except:
                print "*** INVALID CLIENT MESSAGE SIGNATURE ***"

        print "%sReceived %4d bytes: %s" % (HIGH, len(web.data()), NORMAL),

        if pl.get('Status') == 'Idle':
            print HIGH + "Idle Status" + NORMAL
            
            print "*FETCHING CMD TO BE SENT FROM DEVICE:", pl['UDID']
            rd = device_list[pl['UDID']].sendCommand()

            # If no commands in queue, return empty string to avoid infinite idle loop
            if(not rd):
                return ''

            print "%sSent: %s%s" % (HIGH, rd['Command']['RequestType'], NORMAL)

        elif pl.get('MessageType') == 'TokenUpdate':
            print HIGH+"Token Update"+NORMAL
            rd = do_TokenUpdate(pl)
            print HIGH+"Device Enrolled!"+NORMAL

        elif pl.get('Status') == 'Acknowledged':
            print HIGH+"Acknowledged"+NORMAL
            rd = dict()
            # A command has returned a response
            # Add the response to the given device
            print "*CALLING ADD RESPONSE TO CMD:", pl['CommandUUID']
            device_list[pl['UDID']].addResponse(pl['CommandUUID'], pl)

            # If we grab device information, we should also update the device info
            if pl.get('QueryResponses'):
                print "DeviceInformation should update here..."
                p = pl['QueryResponses']
                device_list[pl['UDID']].updateInfo(p['DeviceName'], p['ModelName'], p['OSVersion'])

            # Update pickle file with new response
            store_devices()
        else:
            rd = dict()
            if pl.get('MessageType') == 'Authenticate':
                print HIGH+"Authenticate"+NORMAL
            elif pl.get('MessageType') == 'CheckOut':
                print HIGH+"Device leaving MDM"+ NORMAL
            elif pl.get('Status') == 'Error':
                print "*CALLING ADD RESPONSE WITH ERROR TO CMD:", pl['CommandUUID']
                device_list[pl['UDID']].addResponse(pl['CommandUUID'], pl)
            else:
                print HIGH+"(other)"+NORMAL
                print HIGH, pl, NORMAL
        log_data(pl)
        log_data(rd)

        out = writePlistToString(rd)
        #print LOW, out, NORMAL

        return out
Beispiel #25
0
def main():
    """ The script takes as argument the content of PATH_INFO, that is to say
    the string after the script name in the query URL.
    The format is: http://<server>/<path_to_the_script>/<file_id>~<key_id>
    (note the "~" in between), where:
    file_id: file to get
    key_id: identifier of the key to encrypt the file
    """

    # SETTINGS for the key exchange server connection
    KEY_SERVER_URL = "http://localhost/cgi-bin/"
    KEY_SCRIPTNAME = "main.py/"

    # SETTINGS for the server authentication
    PRIVATE_KEY_FILENAME = "luventur_privkey.pem" # TODO (jblomer): generate a certificate for the server
    CERT_FILENAME = "luventurx509.cer"

    
    # Get the arguments
    query = os.environ["PATH_INFO"][1:] # remove the first "/" from PATH_INFO
    argv = query.split("~")
    file_id = argv[0]
    key_id = argv[1]

    # Get the key
    command = "get/"+key_id
    pkcs7 = urllib.urlopen(KEY_SERVER_URL + KEY_SCRIPTNAME + command).read()
    # Decript the key
    s = SMIME.SMIME() # Prepare an SMIME object
    def passphrase_fun(self):
        return "pass"
    s.load_key(PRIVATE_KEY_FILENAME, CERT_FILENAME, passphrase_fun)
    p7 = SMIME.load_pkcs7_bio(BIO.MemoryBuffer(pkcs7))
    key = s.decrypt(p7)
    
    # CHECK IF THIS IS NEEDED
    # The key and the iv are currently exchanged in ascii format.
    # Potentially, we could use binary data, but there are compatibility issues between Python and C++.

    # key = binascii.unhexlify(key)

    # END CHECK

    # Get the IV from the file id
    iv = file_id[-33:-1] # Take 32 chars (128 bits) from the id, excluding the last (could be NaN)

    # iv = binascii.unhexlify(iv) # Translate to binary (see above)

    # Get the file
    # N.B.: the files are stored in the subtree "data/xy",
    # where xy are the first two hex digits of file_id
    path = "data/" + file_id[0:2] + "/" + file_id[2:]
    clear_text = open(path).read() # TODO: open the real file from cvmfs

    # Encrypt
    cipher = Cipher('aes_256_cbc', key, iv, op=ENC) # TODO: ask the type of the key ('aes_256_cbc') to the server
    v = cipher.update(clear_text)
    v = v + cipher.final()
    v = b64encode(v)

    # print "HTTP/1.1 200 OK"
    print "Content-Type: text/plain"
    print "Content-Length: " + str(len(v))
    print # blank line: end of headers
    print v

    return
 def test_load_pkcs7_bio(self):
     f = open(self.filename, 'rb')
     buf = BIO.MemoryBuffer(f.read())
     f.close()
     
     assert SMIME.load_pkcs7_bio(buf).type() == SMIME.PKCS7_SIGNED
Beispiel #27
0
def enroll():
    if request.method == 'POST' and \
            request.headers.get('Content-type', '').lower() == \
                'application/pkcs7-signature':
        # DEP request

        # base64 encode the DER data, and wrap in a PEM-ish format for SMIME.load_pkcs7_bio()
        req_data = base64_to_pem('PKCS7', base64.b64encode(request.data))

        p7_bio = BIO.MemoryBuffer(str(req_data))
        p7 = SMIME.load_pkcs7_bio(p7_bio)

        p7_signers = p7.get0_signers(X509.X509_Stack())

        signer = SMIME.SMIME()
        signer.set_x509_store(X509.X509_Store())
        signer.set_x509_stack(p7_signers)

        # TODO/XXX: not verifying ANY certificates!
        #
        # spec says we should verify against the "Apple Root CA" and that this
        # CMS message contains all intermediates to do that verification.
        # M2Crypto has no way to get at all the intermediate certificates to
        # do this manually we'd need to extract all of the certificates and
        # verify the chain aginst it. Note as of 2016-03-14 on a brand new
        # iPad Apple was including an expired certificate in this chain. Note
        # also that at least one of the intermediate certificates had a
        # certificate purpose apparently not appropraite for CMS/SMIME
        # verification. For now just verify with no CA and skip any
        # verification.
        plist_text = signer.verify(p7, None, flags=SMIME.PKCS7_NOVERIFY)

        plist = plistlib.readPlistFromString(plist_text)

        try:
            device = db_session.query(Device).filter(or_(Device.serial_number == plist['SERIAL'], Device.udid == plist['UDID'])).one()
            # assign in case absent (UDID present only - not likely due to spec)
            device.serial_number = plist['SERIAL']
            # assign in case different (e.g. changing serial UDIDs i.e. VM testing)
            device.udid = plist['UDID']
        except NoResultFound:
            # should never get here, we could take benefit of the doubt and
            # allow the enrollment anyway, though..?
            current_app.logger.warn('DEP enrollment attempt but no serial number nor UDID found!')

            device = Device()
            device.serial_number = plist['SERIAL']
            device.udid = plist['UDID']
            # TODO: do we care about PRODUCT, VERSION, or LANGUAGE here?

            db_session.add(device)
            db_session.commit()
        # TODO: except too many results (e.g. perhaps both a UDID and a SERIAL found?)
    else:
        device = None

    mdm_ca = get_ca()

    config = db_session.query(MDMConfig).first()

    if not config:
        abort(500, 'No MDM configuration present; cannot generate enrollment profile')

    profile = Profile(config.prefix, PayloadDisplayName=config.mdm_name)

    ca_cert_payload = PEMCertificatePayload(config.prefix + '.mdm-ca', mdm_ca.get_cacert().get_pem(), PayloadDisplayName='MDM CA Certificate')

    profile.append_payload(ca_cert_payload)

    # find and include all mdm.webcrt's
    q = db_session.query(DBCertificate).filter(DBCertificate.cert_type == 'mdm.webcrt')
    for i, cert in enumerate(q):
        new_webcrt_profile = PEMCertificatePayload(config.prefix + '.webcrt.%d' % i, str(cert.pem_certificate), PayloadDisplayName='Web Server Certificate')
        profile.append_payload(new_webcrt_profile)

    db_push_cert = config.push_cert

    push_cert = PushCertificate.load(str(db_push_cert.pem_certificate))

    topic = push_cert.get_topic()

    # make new device privkey, certificate then CA sign and persist certificate finally return new Identity object

    # NOTE: any device requesting enrollment will be generating new CA-signed
    # certificates. may want to gate the enrollment page by password or other
    # authentication

    # NOTE2: at a high-level there are two choices for how to get client
    # identity certificates onto the device: 1. embeddeding an PKCS12
    # identitiy (what we're doing) and 2. using SCEP to hand off certificates.
    # Apple recommends the latter method but not everyone will have a SCEP
    # infrastructure and due to complexities we're using this methodology at
    # the moment
    new_dev_ident, db_dev_cert = mdm_ca.gen_new_device_identity()

    if device:
        # pre-assign for DEP enrollment
        # TODO: delete previously assigned certificate before assignment?
        device.certificate = db_dev_cert

    # random password for PKCS12 payload
    p12pw = urandom(20).encode('hex')

    # generate PCKS12 profile payload
    new_dev_ident_payload = PKCS12CertificatePayload(config.prefix + '.id-cert', new_dev_ident.gen_pkcs12(p12pw), p12pw, PayloadDisplayName='Device Identity Certificate')

    profile.append_payload(new_dev_ident_payload)

    new_mdm_payload = MDMPayload(
        config.prefix + '.mdm',
        new_dev_ident_payload.get_uuid(),
        topic, # APNs push topic
        config.mdm_url,
        config.access_rights,
        CheckInURL=config.checkin_url,
        # we can validate MDM device client certs provided via SSL/TLS.
        # however this requires an SSL framework that is able to do that.
        # alternatively we may optionally have the client digitally sign the
        # MDM messages in an HTTP header. this method is most portable across
        # web servers so we'll default to using that method. note it comes
        # with the disadvantage of adding something like 2KB to every MDM
        # request
        SignMessage=True,
        CheckOutWhenRemoved=True,
        ServerCapabilities=['com.apple.mdm.per-user-connections'], # per-network user & mobile account authentication (OS X extensions)
        PayloadDisplayName='Device Configuration and Management')

    profile.append_payload(new_mdm_payload)

    resp = make_response(profile.generate_plist())
    resp.headers['Content-Type'] = PROFILE_CONTENT_TYPE
    return resp
Beispiel #28
0
# Make a MemoryBuffer of the message.
# buf = BIO.MemoryBuffer('a sign of our times')


buf = BIO.File(open("inputfile.txt"))

# Seed the PRNG.
#Rand.load_file('/dev/random', 1024)

# Instantiate an SMIME object; set it up; sign the buffer.
s = SMIME.SMIME()
s.load_key_bio(BIO.File(open('signer.key.pem')), BIO.File(open('signer.pem')))
p7 = s.sign(buf, SMIME.PKCS7_DETACHED)

out = BIO.MemoryBuffer()
p7.write(out)

x509 = X509.load_cert('signer.pem')
sk = X509.X509_Stack()
sk.push(x509)
s.set_x509_stack(sk)
    
st = X509.X509_Store()
st.load_info('signer.pem')
s.set_x509_store(st)

p7 = SMIME.load_pkcs7_bio(out)

v = s.verify(p7, BIO.File(open("inputfile.txt")))
print "VERIFY", v
Beispiel #29
0
    def PUT(self):
        global current_command, last_result
        HIGH = ''
        LOW = ''
        NORMAL = ''

        i = web.data()
        pl = readPlistFromString(i)

        if 'HTTP_MDM_SIGNATURE' in web.ctx.environ:
            raw_sig = web.ctx.environ['HTTP_MDM_SIGNATURE']
            cooked_sig = '\n'.join(raw_sig[pos:pos + 76]
                                   for pos in xrange(0, len(raw_sig), 76))

            signature = """
-----BEGIN PKCS7-----
%s
-----END PKCS7-----
""" % cooked_sig

            #print i
            #print signature

            buf = BIO.MemoryBuffer(signature)
            p7 = SMIME.load_pkcs7_bio(buf)
            data_bio = BIO.MemoryBuffer(i)
            try:
                v = sm_obj.verify(p7, data_bio)
                if v:
                    print "Client signature verified."
            except:
                print "*** INVALID CLIENT MESSAGE SIGNATURE ***"

        print "%sReceived %4d bytes: %s" % (HIGH, len(web.data()), NORMAL),

        if pl.get('Status') == 'Idle':
            print HIGH + "Idle Status" + NORMAL
            rd = current_command
            print "%sSent: %s%s" % (HIGH, rd['Command']['RequestType'], NORMAL)


#            print HIGH, rd, NORMAL

        elif pl.get('MessageType') == 'TokenUpdate':
            print HIGH + "Token Update" + NORMAL
            rd = do_TokenUpdate(pl)
            print HIGH + "Device Enrolled!" + NORMAL

        elif pl.get('Status') == 'Acknowledged':
            print HIGH + "Acknowledged" + NORMAL
            rd = dict()

        else:
            rd = dict()
            if pl.get('MessageType') == 'Authenticate':
                print HIGH + "Authenticate" + NORMAL
            elif pl.get('MessageType') == 'CheckOut':
                print HIGH + "Device leaving MDM" + NORMAL
            else:
                print HIGH + "(other)" + NORMAL
                print HIGH, pl, NORMAL
        log_data(pl)
        log_data(rd)

        out = writePlistToString(rd)
        #        print LOW, out, NORMAL

        q = pl.get('QueryResponses')
        if q:
            redact_list = ('UDID', 'BluetoothMAC', 'SerialNumber', 'WiFiMAC',
                           'IMEI', 'ICCID', 'SerialNumber')
            for resp in redact_list:
                if q.get(resp):
                    pl['QueryResponses'][resp] = '--redacted--'
        for top in ('UDID', 'Token', 'PushMagic', 'UnlockToken'):
            if pl.get(top):
                pl[top] = '--redacted--'

        last_result = pprint.pformat(pl)
        return out
Beispiel #30
0
    def PUT(self):
        global sm_obj, device_list
        HIGH = ''
        LOW = ''
        NORMAL = ''

        i = web.data()
        pl = readPlistFromString(i)

        if 'HTTP_MDM_SIGNATURE' in web.ctx.environ:
            raw_sig = web.ctx.environ['HTTP_MDM_SIGNATURE']
            cooked_sig = '\n'.join(raw_sig[pos:pos + 76]
                                   for pos in xrange(0, len(raw_sig), 76))

            signature = '\n-----BEGIN PKCS7-----\n%s\n-----END PKCS7-----\n' % cooked_sig

            # Verify client signature - necessary?
            buf = BIO.MemoryBuffer(signature)
            p7 = SMIME.load_pkcs7_bio(buf)
            data_bio = BIO.MemoryBuffer(i)
            try:
                v = sm_obj.verify(p7, data_bio)
                if v:
                    print "Client signature verified."
            except:
                print "*** INVALID CLIENT MESSAGE SIGNATURE ***"

        print "%sReceived %4d bytes: %s" % (HIGH, len(web.data()), NORMAL),

        if pl.get('Status') == 'Idle':
            print HIGH + "Idle Status" + NORMAL

            print "*FETCHING CMD TO BE SENT FROM DEVICE:", pl['UDID']
            rd = device_list[pl['UDID']].sendCommand()

            # If no commands in queue, return empty string to avoid infinite idle loop
            if (not rd):
                return ''

            print "%sSent: %s%s" % (HIGH, rd['Command']['RequestType'], NORMAL)

        elif pl.get('MessageType') == 'TokenUpdate':
            print HIGH + "Token Update" + NORMAL
            rd = do_TokenUpdate(pl)
            print HIGH + "Device Enrolled!" + NORMAL

        elif pl.get('Status') == 'Acknowledged':
            print HIGH + "Acknowledged" + NORMAL
            rd = dict()
            # A command has returned a response
            # Add the response to the given device
            print "*CALLING ADD RESPONSE TO CMD:", pl['CommandUUID']
            device_list[pl['UDID']].addResponse(pl['CommandUUID'], pl)

            # If we grab device information, we should also update the device info
            if pl.get('QueryResponses'):
                print "DeviceInformation should update here..."
                p = pl['QueryResponses']
                device_list[pl['UDID']].updateInfo(p['DeviceName'],
                                                   p['ModelName'],
                                                   p['OSVersion'])

            # Update pickle file with new response
            store_devices()
        else:
            rd = dict()
            if pl.get('MessageType') == 'Authenticate':
                print HIGH + "Authenticate" + NORMAL
            elif pl.get('MessageType') == 'CheckOut':
                print HIGH + "Device leaving MDM" + NORMAL
            elif pl.get('Status') == 'Error':
                print "*CALLING ADD RESPONSE WITH ERROR TO CMD:", pl[
                    'CommandUUID']
                device_list[pl['UDID']].addResponse(pl['CommandUUID'], pl)
            else:
                print HIGH + "(other)" + NORMAL
                print HIGH, pl, NORMAL
        log_data(pl)
        log_data(rd)

        out = writePlistToString(rd)
        #print LOW, out, NORMAL

        return out
Beispiel #31
0
    def PUT(self):
        print "**** do-mdm -> PUT ****"
        global current_command, last_result, sm_obj
        HIGH = ''
        LOW = ''
        NORMAL = ''

        i = web.data()
        pl = readPlistFromString(i)

        if 'HTTP_MDM_SIGNATURE' in web.ctx.environ:
            raw_sig = web.ctx.environ['HTTP_MDM_SIGNATURE']
            cooked_sig = '\n'.join(raw_sig[pos:pos + 76]
                                   for pos in xrange(0, len(raw_sig), 76))

            signature = '\n-----BEGIN PKCS7-----\n%s\n-----END PKCS7-----\n' % cooked_sig

            #print i
            #print signature

            buf = BIO.MemoryBuffer(signature)
            p7 = SMIME.load_pkcs7_bio(buf)
            data_bio = BIO.MemoryBuffer(i)
            try:
                v = sm_obj.verify(p7, data_bio)
                if v:
                    print "Client signature verified."
            except:
                print "*** INVALID CLIENT MESSAGE SIGNATURE ***"

        print "%sReceived %4d bytes: %s" % (HIGH, len(web.data()), NORMAL),

        if pl.get('Status') == 'Idle':
            print HIGH + "Idle Status" + NORMAL

            # Hack to fix iOS7 infinite /server calls
            if (current_command == {}):
                return ''

            rd = current_command
            print "%sSent: %s%s" % (HIGH, rd['Command']['RequestType'], NORMAL)
            current_command = {}

        elif pl.get('MessageType') == 'TokenUpdate':
            print HIGH + "Token Update" + NORMAL
            rd = do_TokenUpdate(pl)
            print HIGH + "Device Enrolled!" + NORMAL

        elif pl.get('Status') == 'Acknowledged':
            print HIGH + "Acknowledged" + NORMAL
            rd = dict()

        else:
            rd = dict()
            if pl.get('MessageType') == 'Authenticate':
                print HIGH + "Authenticate" + NORMAL
            elif pl.get('MessageType') == 'CheckOut':
                print HIGH + "Device leaving MDM" + NORMAL
            else:
                print HIGH + "(other)" + NORMAL
                print HIGH, pl, NORMAL
        log_data(pl)
        log_data(rd)

        out = writePlistToString(rd)
        #print LOW, out, NORMAL
        print "**** END OF do_mdm ****"
        q = pl.get('QueryResponses')
        last_result = pprint.pformat(pl)
        return out
		
		if sign_type == 'smime':
			raw_sig = sign_part.get_payload().replace("\n","")
			# re-wrap signature so that it fits base64 standards
			cooked_sig = '\n'.join(raw_sig[pos:pos+76] for pos in xrange(0, len(raw_sig), 76))
			
			# now, wrap the signature in a PKCS7 block
			sig = """
-----BEGIN PKCS7-----
%s
-----END PKCS7-----
		""" % cooked_sig

			# and load it into an SMIME p7 object through the BIO I/O buffer:
			buf = BIO.MemoryBuffer(sig)
			p7 = SMIME.load_pkcs7_bio(buf)

			sk = X509.X509_Stack()
			signers = p7.get0_signers(sk)
			signing_cert = signers[0]

			#Save certificate compatible to RFC 2821
			splitted_from_addr = from_addr.split('@')
			processed_from_addr = splitted_from_addr[0] + '@' + splitted_from_addr[1].lower()

			signing_cert.save(os.path.join(CERT_PATH, processed_from_addr))
					
			# format in user-specific data
			# sending success mail only for S/MIME as GPGMW handles this on its own
			success_msg = file(cfg['mailregister']['mail_templates']+"/registrationSuccess.md").read()
			success_msg = success_msg.replace("[:FROMADDRESS:]",from_addr)
Beispiel #33
0
def enroll():
    if request.method == 'POST' and \
            request.headers.get('Content-type', '').lower() == \
                'application/pkcs7-signature':
        # DEP request

        # base64 encode the DER data, and wrap in a PEM-ish format for SMIME.load_pkcs7_bio()
        req_data = base64_to_pem('PKCS7', base64.b64encode(request.data))

        p7_bio = BIO.MemoryBuffer(str(req_data))
        p7 = SMIME.load_pkcs7_bio(p7_bio)

        p7_signers = p7.get0_signers(X509.X509_Stack())

        signer = SMIME.SMIME()
        signer.set_x509_store(X509.X509_Store())
        signer.set_x509_stack(p7_signers)

        # TODO/XXX: not verifying ANY certificates!
        #
        # spec says we should verify against the "Apple Root CA" and that this
        # CMS message contains all intermediates to do that verification.
        # M2Crypto has no way to get at all the intermediate certificates to
        # do this manually we'd need to extract all of the certificates and
        # verify the chain aginst it. Note as of 2016-03-14 on a brand new
        # iPad Apple was including an expired certificate in this chain. Note
        # also that at least one of the intermediate certificates had a
        # certificate purpose apparently not appropraite for CMS/SMIME
        # verification. For now just verify with no CA and skip any
        # verification.
        plist_text = signer.verify(p7, None, flags=SMIME.PKCS7_NOVERIFY)

        plist = plistlib.readPlistFromString(plist_text)

        try:
            device = db_session.query(Device).filter(
                or_(Device.serial_number == plist['SERIAL'],
                    Device.udid == plist['UDID'])).one()
            # assign in case absent (UDID present only - not likely due to spec)
            device.serial_number = plist['SERIAL']
            # assign in case different (e.g. changing serial UDIDs i.e. VM testing)
            device.udid = plist['UDID']
        except NoResultFound:
            # should never get here, we could take benefit of the doubt and
            # allow the enrollment anyway, though..?
            current_app.logger.warn(
                'DEP enrollment attempt but no serial number nor UDID found!')

            device = Device()
            device.serial_number = plist['SERIAL']
            device.udid = plist['UDID']
            # TODO: do we care about PRODUCT, VERSION, or LANGUAGE here?

            db_session.add(device)
            db_session.commit()
        # TODO: except too many results (e.g. perhaps both a UDID and a SERIAL found?)
    else:
        device = None

    mdm_ca = get_ca()

    config = db_session.query(MDMConfig).first()

    if not config:
        abort(
            500,
            'No MDM configuration present; cannot generate enrollment profile')

    if not config.prefix or not config.prefix.strip():
        abort(500, 'MDM configuration has no profile prefix')

    profile = Profile(config.prefix + '.enroll',
                      PayloadDisplayName=config.mdm_name)

    print mdm_ca.get_cacert().to_pem()
    ca_cert_payload = PEMCertificatePayload(
        config.prefix + '.mdm-ca',
        str(mdm_ca.get_cacert().to_pem()).strip(),
        PayloadDisplayName='MDM CA Certificate')

    profile.append_payload(ca_cert_payload)

    # find and include all mdm.webcrt's
    q = db_session.query(DBCertificate).filter(
        DBCertificate.cert_type == 'mdm.webcrt')
    for i, cert in enumerate(q):
        print cert.pem_certificate
        new_webcrt_profile = PEMCertificatePayload(
            config.prefix + '.webcrt.%d' % i,
            str(cert.pem_certificate).strip(),
            PayloadDisplayName='Web Server Certificate')
        profile.append_payload(new_webcrt_profile)

    push_cert = config.push_cert.to_x509(cert_type=PushCertificate)
    topic = push_cert.get_topic()

    # NOTE: any device requesting non-SCEP enrollment will be generating new
    # CA-signed certificates. may want to gate the enrollment page by password
    # or other authentication
    if config.device_identity_method == 'provide':
        # make new device privkey, certificate then CA sign and persist
        # certificate finally return new Identity object

        new_dev_ident, db_dev_cert = mdm_ca.gen_new_device_identity()

        # random password for PKCS12 payload
        p12pw = urandom(20).encode('hex')

        # generate PCKS12 profile payload
        new_dev_ident_payload = PKCS12CertificatePayload(
            config.prefix + '.id-cert',
            new_dev_ident.to_pkcs12(p12pw),
            p12pw,
            PayloadDisplayName='Device Identity Certificate')

        profile.append_payload(new_dev_ident_payload)
        cert_uuid = new_dev_ident_payload.get_uuid()
    elif config.device_identity_method == 'ourscep':
        # SCEP is preferred
        scep_config = db_session.query(SCEPConfig).one()

        scep_payload = SCEPPayload(
            config.prefix + '.mdm-scep',
            config.scep_url,
            PayloadContent=dict(
                Keysize=2048,
                Challenge=scep_config.challenge,
                # CAFingerprint=plistlib.Data(mdm_ca.get_cacert().get_m2_cert().get_fingerprint('sha1').decode('hex')),
                # Subject=[
                #     [ ['CN', 'MDM Enrollment'] ],
                # ],
            ),
            PayloadDisplayName='MDM SCEP')
        profile.append_payload(scep_payload)
        cert_uuid = scep_payload.get_uuid()
    else:
        abort(500, 'Invalid device identity method')

    new_mdm_payload = MDMPayload(
        config.prefix + '.mdm',
        cert_uuid,
        topic,  # APNs push topic
        config.mdm_url,
        config.access_rights,
        CheckInURL=config.checkin_url,
        # we can validate MDM device client certs provided via SSL/TLS.
        # however this requires an SSL framework that is able to do that.
        # alternatively we may optionally have the client digitally sign the
        # MDM messages in an HTTP header. this method is most portable across
        # web servers so we'll default to using that method. note it comes
        # with the disadvantage of adding something like 2KB to every MDM
        # request
        SignMessage=True,
        CheckOutWhenRemoved=True,
        ServerCapabilities=[
            'com.apple.mdm.per-user-connections'
        ],  # per-network user & mobile account authentication (OS X extensions)
        PayloadDisplayName='Device Configuration and Management')

    profile.append_payload(new_mdm_payload)

    resp = make_response(profile.generate_plist())
    resp.headers['Content-Type'] = PROFILE_CONTENT_TYPE
    return resp
    def verify_cms(self, data):
        """Verify a pkcs7 SMIME message"""    
        from M2Crypto import SMIME, X509, BIO
        import base64, TLV_utils,  os

        data3 = "-----BEGIN PKCS7-----\n"
        data3 += base64.encodestring(data)
        data3 += "-----END PKCS7-----"    
        #print data3
        
        p7_bio = BIO.MemoryBuffer(data3)

        # Instantiate an SMIME object.
        s = SMIME.SMIME()
        
        # TODO: ugly hack for M2Crypto
        body = TLV_utils.tlv_find_tag(TLV_utils.unpack(data), 0xA0,  1)[0][2]
        thecert = TLV_utils.tlv_find_tag(body, 0xA0,  2)[1][2]

        cert_bio = BIO.MemoryBuffer(TLV_utils.pack(thecert))
        
        # Load the signer's cert.
        x509 = X509.load_cert_bio(cert_bio,  format=0)
        sk = X509.X509_Stack()
        sk.push(x509)
        s.set_x509_stack(sk)
        country = str(x509.get_issuer()).split('/')[1][2:]
        #print country
        
        cacert = country + "-cacert.der"
        #print cacert
        
        msgErr =  "couldn't parse certificate to determine URL for CACert, search the intertubes,"
        msg =  "download CACert (convert to DER if necessary) and save it as \n\"%s\"" % cacert
        
        if not os.path.isfile(cacert):
            try:
                v = x509.get_ext("certificatePolicies").get_value()
                start = v.find("CPS: ")
                if start != -1:
                    url = v[start + 5:-1]
                    print "visit %s" % url,  msg
                else:
                    print msgErr,  msg
            except Exception:
                print msgErr,  msg
            return ""
            
        # Load the signer's CA cert. 
        st = X509.X509_Store()
        #st.load_info('main')
        x509CA = X509.load_cert(cacert,  format=0)
        st.add_x509(x509CA)
        s.set_x509_store(st)

        # Load the data, verify it.
        #p7, data = SMIME.smime_load_pkcs7_bio(p7_bio)
        p7 = SMIME.load_pkcs7_bio(p7_bio)
        
        v = s.verify(p7)
        return v
Beispiel #35
0
    def verify_cms(self, data):
        """Verify a pkcs7 SMIME message"""
        from M2Crypto import SMIME, X509, BIO
        import base64, TLV_utils, os

        data3 = "-----BEGIN PKCS7-----\n"
        data3 += base64.encodestring(data)
        data3 += "-----END PKCS7-----"
        #print data3

        p7_bio = BIO.MemoryBuffer(data3)

        # Instantiate an SMIME object.
        s = SMIME.SMIME()

        # TODO: ugly hack for M2Crypto
        body = TLV_utils.tlv_find_tag(TLV_utils.unpack(data), 0xA0, 1)[0][2]
        thecert = TLV_utils.tlv_find_tag(body, 0xA0, 2)[1][2]

        cert_bio = BIO.MemoryBuffer(TLV_utils.pack(thecert))

        # Load the signer's cert.
        x509 = X509.load_cert_bio(cert_bio, format=0)
        sk = X509.X509_Stack()
        sk.push(x509)
        s.set_x509_stack(sk)
        country = str(x509.get_issuer()).split('/')[1][2:]
        #print country

        cacert = country + "-cacert.der"
        #print cacert

        msgErr = "couldn't parse certificate to determine URL for CACert, search the intertubes,"
        msg = "download CACert (convert to DER if necessary) and save it as \n\"%s\"" % cacert

        if not os.path.isfile(cacert):
            try:
                v = x509.get_ext("certificatePolicies").get_value()
                start = v.find("CPS: ")
                if start != -1:
                    url = v[start + 5:-1]
                    print "visit %s" % url, msg
                else:
                    print msgErr, msg
            except Exception:
                print msgErr, msg
            return ""

        # Load the signer's CA cert.
        st = X509.X509_Store()
        #st.load_info('main')
        x509CA = X509.load_cert(cacert, format=0)
        st.add_x509(x509CA)
        s.set_x509_store(st)

        # Load the data, verify it.
        #p7, data = SMIME.smime_load_pkcs7_bio(p7_bio)
        p7 = SMIME.load_pkcs7_bio(p7_bio)

        v = s.verify(p7)
        return v
Beispiel #36
0
    def test_load_pkcs7_bio(self):
        with open(self.filename, 'rb') as f:
            buf = BIO.MemoryBuffer(f.read())

        self.assertEqual(SMIME.load_pkcs7_bio(buf).type(), SMIME.PKCS7_SIGNED)
Beispiel #37
0
    def test_load_pkcs7_bio(self):
        with open(self.filename, 'rb') as f:
            buf = BIO.MemoryBuffer(f.read())

        self.assertEqual(SMIME.load_pkcs7_bio(buf).type(), SMIME.PKCS7_SIGNED)