示例#1
0
def main(argv):
    p = optparse.OptionParser()
    p.set_usage("""Usage: %prog [options] userdata.plist [password]""")
    p.add_option("-v", "--verbose", action="store_true",
                 help="Verbose output.")
    options, argv = p.parse_args(argv)
    if len(argv) not in (2, 3):
        print >>sys.stderr, p.get_usage()
        return 1
    
    # Read the userdata.plist.
    plist = argv[1]
    
    plist_data = NSData.dataWithContentsOfFile_(plist)
    if not plist_data:
        print >>sys.stderr, "Couldn't read %s" % plist
        return 1
    
    user_plist, plist_format, error = \
     NSPropertyListSerialization.propertyListFromData_mutabilityOption_format_errorDescription_(
                    plist_data, NSPropertyListMutableContainers, None, None)
    
    if error:
        print >>sys.stderr, "Can't read %s: %s" % (plist, error)
        return 1
    
    # Use password on commandline, or ask if one isn't provided.
    try:
        password = argv[2]
    except IndexError:
        while True:
            password = getpass.getpass()
            verify_password = getpass.getpass("Password again: ")
            if password == verify_password:
                break
            else:
                print "Passwords don't match!"
    
    # Hash password with all available methods.
    hashed_passwords = dict()
    for k, m in hash_methods.items():
        hashed_pwd = m(password)
        pwd_data = NSData.alloc().initWithBytes_length_(hashed_pwd, len(hashed_pwd))
        hashed_passwords[k] = pwd_data
    
    # Serialize hashed passwords to a binary plist.
    serialized_passwords = serialize_hash_dict(hashed_passwords)
    if not serialized_passwords:
        return 2
    
    # Write back userdata.plist with ShadowHashData.
    user_plist["ShadowHashData"] = list()
    user_plist["ShadowHashData"].append(serialized_passwords)
    
    plist_data, error = \
     NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_(
                            user_plist, plist_format, None)
    plist_data.writeToFile_atomically_(argv[1], True)
    
    return 0
示例#2
0
def writePlistToString(rootObject):
    '''Return 'rootObject' as a plist-formatted string.'''
    plistData, error = \
     NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_(
                            rootObject, NSPropertyListXMLFormat_v1_0, None)
    if error:
        raise NSPropertyListSerializationException(error)
    else:
        return str(plistData)
示例#3
0
def serialize_hash_dict(hash_dict):
    plist_data, error = \
     NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_(
                            hash_dict, NSPropertyListBinaryFormat_v1_0, None)
    if error:
        # FIXME: Raise an exception instead.
        print >>sys.stderr, error
        return None
    
    return plist_data
示例#4
0
def writePlistToString(rootObject):
    """Return 'rootObject' as a plist-formatted string."""
    plistData, error = NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_(
        rootObject, NSPropertyListXMLFormat_v1_0, None
    )
    if error:
        error = error.encode("ascii", "ignore")
        raise NSPropertyListSerializationException(error)
    else:
        return str(plistData)
示例#5
0
def _generate_plist_string(rootObject, format=NSPropertyListXMLFormat_v1_0):
    '''Return 'rootObject' as a plist-formatted string.'''
    plistData, error = \
        NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_(
            rootObject, format, None)
    if error:
        error = error.encode('ascii', 'ignore')
        raise salt.exceptions.SaltInvocationError(
            'Error encoding Property List: {}'.format(error)
        )
    else:
        return str(plistData)
示例#6
0
def _writePlistToString(rootObject):
    '''Return 'rootObject' as a plist-formatted string.'''
    plistData, error = \
        NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_(
            rootObject, NSPropertyListXMLFormat_v1_0, None)
    if error:
        error = error.encode('ascii', 'ignore')
        log.debug('Error encoding to plist')
        log.debug(error)
        raise NSPropertyListSerializationException(error)
    else:
        return str(plistData)
def writePlist(dataObject, filepath):
    """
    Write 'rootObject' as a plist to filepath.
    """
    plistData, error = NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_(
        dataObject, NSPropertyListXMLFormat_v1_0, None
    )
    if error:
        raise NSPropertyListSerializationException(error)
    else:
        if plistData.writeToFile_atomically_(filepath, True):
            return
        else:
            raise Exception("Failed to write plist data to %s" % filepath)
 def write_bundle_info(self, info, path):
     """Write Contents/Info.plist inside a bundle."""
     
     plistpath = os.path.join(path, "Contents", "Info.plist")
     plist_data, error = \
         NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_(
             info,
             NSPropertyListXMLFormat_v1_0,
             None
         )
     if error:
         raise ProcessorError("Can't serialize %s: %s" % (plistpath, error))
     
     if not plist_data.writeToFile_atomically_(plistpath, True):
         raise ProcessorError("Can't write %s" % (plistpath))
def _plistToData(plistObject):
    """low-level function that creates NSData from a plist object"""
    darwin_vers = int(os.uname()[2].split(".")[0])
    if darwin_vers > 10:
        (data, error) = NSPropertyListSerialization.dataWithPropertyList_format_options_error_(
            plistObject, NSPropertyListXMLFormat_v1_0, 0, None
        )
    else:
        # use the older NSPropertyListSerialization function on 10.6 and 10.5
        (data, error) = NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_(
            plistObject, NSPropertyListXMLFormat_v1_0, None
        )
    if error:
        raise NSPropertyListSerializationException(error)
    return data
示例#10
0
def writePlist(dataObject, filepath):
    '''
    Write 'rootObject' as a plist to filepath.
    '''
    plistData, error = \
     NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_(
                            dataObject, NSPropertyListXMLFormat_v1_0, None)
    if error:
        error = error.encode('ascii', 'ignore')
        raise NSPropertyListSerializationException(error)
    else:
        if plistData.writeToFile_atomically_(filepath, True):
            return
        else:
            raise NSPropertyListWriteException(
                "Failed to write plist data to %s" % filepath)
示例#11
0
def writePlist(dataObject, filepath):
    '''
    Write 'rootObject' as a plist to filepath.
    '''
    plistData, error = \
     NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_(
                            dataObject, NSPropertyListXMLFormat_v1_0, None)
    if error:
        error = error.encode('ascii', 'ignore')
        raise NSPropertyListSerializationException(error)
    else:
        if plistData.writeToFile_atomically_(filepath, True):
            return
        else:
            raise NSPropertyListWriteException(
                                "Failed to write plist data to %s" % filepath)
示例#12
0
def _plistToData(plistObject):
    '''low-level function that creates NSData from a plist object'''
    darwin_vers = int(os.uname()[2].split('.')[0])
    if darwin_vers > 10:
        (data, error) = (
            NSPropertyListSerialization.dataWithPropertyList_format_options_error_(
                plistObject, NSPropertyListXMLFormat_v1_0, 0, None))
    else:
        # use the older NSPropertyListSerialization function on 10.6 and 10.5
        (data, error) = (
            NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_(
                plistObject, NSPropertyListXMLFormat_v1_0, None))
    if data is None:
        if error is None:
            error = "Property list invalid for format."
        raise NSPropertyListSerializationException(error)
    return data
示例#13
0
def _plistToData(plistObject):
    '''low-level function that creates NSData from a plist object'''
    darwin_vers = int(os.uname()[2].split('.')[0])
    if darwin_vers > 10:
        (data, error) = (
            NSPropertyListSerialization.dataWithPropertyList_format_options_error_(
                plistObject, NSPropertyListXMLFormat_v1_0, 0, None))
    else:
        # use the older NSPropertyListSerialization function on 10.6 and 10.5
        (data, error) = (
            NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_(
                plistObject, NSPropertyListXMLFormat_v1_0, None))
    if data is None:
        if error is None:
            error = "Property list invalid for format."
        raise NSPropertyListSerializationException(error)
    return data
示例#14
0
def _write_plist(dataObject, filepath, format=NSPropertyListXMLFormat_v1_0):
    '''
    Write 'rootObject' as a plist to filepath.
    '''
    plistData, error = \
        NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_(
            dataObject, format, None)
    if error:
        error = error.encode('ascii', 'ignore')
        raise salt.exceptions.SaltInvocationError(
            'Error encoding Property List: {}'.format(error))
    else:
        if plistData.writeToFile_atomically_(filepath, True):
            return
        else:
            raise salt.exceptions.SaltInvocationError(
                'Failed to write Property List at path: {}'.format(filepath))
示例#15
0
def _write_plist(dataObject, filepath, format=NSPropertyListXMLFormat_v1_0):
    '''
    Write 'rootObject' as a plist to filepath.
    '''
    plistData, error = \
        NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_(
            dataObject, format, None)
    if error:
        error = error.encode('ascii', 'ignore')
        raise salt.exceptions.SaltInvocationError(
            'Error encoding Property List: {}'.format(error)
        )
    else:
        if plistData.writeToFile_atomically_(filepath, True):
            return
        else:
            raise salt.exceptions.SaltInvocationError(
                'Failed to write Property List at path: {}'.format(filepath)
            )
def writePlist(dataObject, filepath):
    """Write 'rootObject' as a plist to filepath."""
    (
        plistData,
        error,
    ) = NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_(
        dataObject, NSPropertyListXMLFormat_v1_0, None)
    if plistData is None:
        if error:
            error = error.encode("ascii", "ignore")
        else:
            error = "Unknown error"
        raise NSPropertyListSerializationException(error)
    else:
        if plistData.writeToFile_atomically_(filepath, True):
            return
        else:
            raise NSPropertyListWriteException(
                "Failed to write plist data to %s" % filepath)
示例#17
0
def gen_string(data, format='xml'):
    '''
    Take a python struct (normally a dict) and generate a string representing a property list.

    data
        Python data structure (dict)

    format (default 'xml')
        Generate format, 'xml' or 'binary'
    '''
    serialization = NSPropertyListXMLFormat_v1_0 if format == 'xml' else NSPropertyListBinaryFormat_v1_0
    plistData, error = \
        NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_(
            data, serialization, None)
    if error:
        error = error.encode('ascii', 'ignore')
        log.debug('Error writing plist')
        log.debug(error)
        raise NSPropertyListSerializationException(error)
    else:
        return plistData
示例#18
0
def gen_string(data, format='xml'):
    '''
    Take a python struct (normally a dict) and generate a string representing a property list.

    data
        Python data structure (dict)

    format (default 'xml')
        Generate format, 'xml' or 'binary'
    '''
    serialization = NSPropertyListXMLFormat_v1_0 if format == 'xml' else NSPropertyListBinaryFormat_v1_0
    plistData, error = \
        NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_(
            data, serialization, None)
    if error:
        error = error.encode('ascii', 'ignore')
        log.debug('Error writing plist')
        log.debug(error)
        raise NSPropertyListSerializationException(error)
    else:
        return plistData
示例#19
0
def _writePlist(dataObject, filepath):
    '''
    Write 'rootObject' as a plist to filepath.
    '''
    plistData, error = \
        NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_(
            dataObject, NSPropertyListXMLFormat_v1_0, None)
    if error:
        error = error.encode('ascii', 'ignore')
        log.debug('Error writing plist')
        log.debug(error)
        raise NSPropertyListSerializationException(error)
    else:
        if plistData.writeToFile_atomically_(filepath, True):
            return
        else:
            errmsg = "Failed to write plist data to %s" % filepath

            import traceback

            log.debug(errmsg)
            log.debug(traceback.format_exc())
            raise NSPropertyListWriteException(errmsg)
示例#20
0
def _writePlist(dataObject, filepath):
    '''
    Write 'rootObject' as a plist to filepath.
    '''
    plistData, error = \
        NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_(
            dataObject, NSPropertyListXMLFormat_v1_0, None)
    if error:
        error = error.encode('ascii', 'ignore')
        log.debug('Error writing plist')
        log.debug(error)
        raise NSPropertyListSerializationException(error)
    else:
        if plistData.writeToFile_atomically_(filepath, True):
            return
        else:
            errmsg = "Failed to write plist data to %s" % filepath

            import traceback

            log.debug(errmsg)
            log.debug(traceback.format_exc())
            raise NSPropertyListWriteException(errmsg)
示例#21
0
def main():
    parser = argparse.ArgumentParser(description='Sign or encrypt mobileconfig profiles, using either a cert + key file, or a keychain certificate.')
    parser.add_argument('sign', choices=('sign', 'encrypt', 'both'), help='Choose to sign, encrypt, or do both on a profile.')
    key_group = parser.add_argument_group('Keychain arguments', description='Use these if you wish to sign with a Keychain certificate.')
    key_group.add_argument('-k', '--keychain', help='Name of keychain to search for cert. Defaults to login.keychain',
                        default='login.keychain')
    key_group.add_argument('-n', '--name', help='Common name of certificate to use from keychain.', required=True)
    parser.add_argument('infile', help='Path to input .mobileconfig file')
    parser.add_argument('outfile', help='Path to output .mobileconfig file. Defaults to outputting into the same directory.')
    args = parser.parse_args()
    print "f**k yeah"
    
    if args.sign == 'encrypt' or args.sign == 'both':
        # encrypt the profile only, do not sign
        # Encrypting a profile:
        # 1. Extract payload content into its own file
        # 2. Serial that file as its own plist
        # 3. CMS-envelope that content (using openssl for now)
        # 4. Remove "PayloadContent" key and replace with "EncryptedPayloadContent" key
        # 5. Replace the PayloadContent <array> with <data> tags instead

        # Step 1: Extract payload content into its own file
        myProfile = plistlib.readPlist(args.infile)
        payloadContent = myProfile['PayloadContent']

        # Step 2: Serialize that file into its own plist
        (pContentFile, pContentPath) = tempfile.mkstemp()
        plistlib.writePlist(payloadContent, pContentPath)
        
        # Step 3: Use openssl to encrypt that content
        # First, we need to extract the certificate we want to use from the keychain
        security_cmd = ['/usr/bin/security', 'find-certificate', '-c', args.name, '-p' ]
        if args.keychain:
            security_cmd += [args.keychain]
        print security_cmd
        proc = subprocess.Popen(security_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        (sout, serr) = proc.communicate()
        if serr:
            print >> sys.stderr, "Error: %s" % serr
            sys.exit(1)
        # Now write the certificate to a temp file
        (certfile, certpath) = tempfile.mkstemp('.pem')
        try:
            with open(certpath, 'wb') as f:
                f.write(sout)
        except IOError:
            print >> sys.stderr, "Could not write to file!"
            sys.exit(1)      
        # Now use openssl to encrypt the payload content using that certificate
        (encPContentfile, encPContentPath) = tempfile.mkstemp('.plist')
        enc_cmd = ['/usr/bin/openssl', 'smime', '-encrypt', '-aes256', '-outform', 'pem', 
                '-in', pContentPath, '-out', encPContentPath]
        enc_cmd += [certpath] 
        proc = subprocess.Popen(enc_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        (encout, encerr) = proc.communicate()
        if encerr:
            print >> sys.stderr, "Error: %s" % encerr
            sys.exit(1)
        # openssl smime -encrypt produces no output if successful
        
        # Step 4: Add the new encrypted payload content back into the plist
        with open(encPContentPath, 'rb') as f:
            content = f.readlines()
            content = content[1:-1] #this is to skip the ---BEGIN PKCS7--- and ----END PKCS7---- lines
        encPayload = ""
        for line in content:
            encPayload += ''.join(line.rstrip()) # to get rid of Python's \n everywhere
        del myProfile['PayloadContent']

        binaryEncPayload = base64.b64decode(encPayload)
        wrapped_data = NSData.dataWithBytes_length_(binaryEncPayload, len(binaryEncPayload))
        myProfile['EncryptedPayloadContent'] = wrapped_data
        plistData, error = NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_(myProfile, NSPropertyListXMLFormat_v1_0, None)
        plistData.writeToFile_atomically_(args.outfile, True)

        # Step 5: Use plistlib.Data to properly encode the content
        # myProfile['EncryptedPayloadContent'] = plistlib.Data(encPayload)
        # now save the profile
        # plistlib.writePlist(myProfile, args.outfile)

        # Now clean up after ourselves
    
    if args.sign == 'sign' or args.sign == 'both':
        # sign the profile only
        # Keychain check:
        if not args.name:
            print >> sys.stderr, 'Error: A certificate common name is required to sign profiles with the Keychain.'
            sys.exit(22)
        cmd = ['/usr/bin/security', 'cms', '-S', '-N', args.name, '-i', args.infile, '-o', args.outfile ]
        proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        (sout, serr) = proc.communicate()
        if serr:
            print >> sys.stderr, 'Error: %s' % serr
            sys.exit(1)
示例#22
0
def serializePlist(data):
    plistData, error = NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_(
        data, NSPropertyListXMLFormat_v1_0, None)
    if error:
        raise NSPropertyListSerializationException(error)
    return plistData
示例#23
0
def serializePlist(data):
    plistData, error = NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_(
        data, NSPropertyListXMLFormat_v1_0, None)
    if error:
        raise NSPropertyListSerializationException(error)
    return plistData
示例#24
0
def main(argv):
    p = optparse.OptionParser()
    p.set_usage("""Usage: %prog [options] userdata.plist [password]""")
    p.add_option("-v",
                 "--verbose",
                 action="store_true",
                 help="Verbose output.")
    options, argv = p.parse_args(argv)
    if len(argv) not in (2, 3):
        print >> sys.stderr, p.get_usage()
        return 1

    # Read the userdata.plist.
    plist = argv[1]

    plist_data = NSData.dataWithContentsOfFile_(plist)
    if not plist_data:
        print >> sys.stderr, "Couldn't read %s" % plist
        return 1

    user_plist, plist_format, error = \
     NSPropertyListSerialization.propertyListFromData_mutabilityOption_format_errorDescription_(
                    plist_data, NSPropertyListMutableContainers, None, None)

    if error:
        print >> sys.stderr, "Can't read %s: %s" % (plist, error)
        return 1

    # Use password on commandline, or ask if one isn't provided.
    try:
        password = argv[2]
    except IndexError:
        while True:
            password = getpass.getpass()
            verify_password = getpass.getpass("Password again: ")
            if password == verify_password:
                break
            else:
                print "Passwords don't match!"

    # Hash password with all available methods.
    hashed_passwords = dict()
    for k, m in hash_methods.items():
        hashed_pwd = m(password)
        pwd_data = NSData.alloc().initWithBytes_length_(
            hashed_pwd, len(hashed_pwd))
        hashed_passwords[k] = pwd_data

    # Serialize hashed passwords to a binary plist.
    serialized_passwords = serialize_hash_dict(hashed_passwords)
    if not serialized_passwords:
        return 2

    # Write back userdata.plist with ShadowHashData.
    user_plist["ShadowHashData"] = list()
    user_plist["ShadowHashData"].append(serialized_passwords)

    plist_data, error = \
     NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_(
                            user_plist, plist_format, None)
    plist_data.writeToFile_atomically_(argv[1], True)

    return 0
示例#25
0
def main():
    parser = argparse.ArgumentParser(
        description=
        'Sign or encrypt mobileconfig profiles, using either a cert + key file, or a keychain certificate.'
    )
    parser.add_argument(
        'sign',
        choices=('sign', 'encrypt', 'both'),
        help='Choose to sign, encrypt, or do both on a profile.')
    key_group = parser.add_argument_group(
        'Keychain arguments',
        description='Use these if you wish to sign with a Keychain certificate.'
    )
    key_group.add_argument(
        '-k',
        '--keychain',
        help='Name of keychain to search for cert. Defaults to login.keychain',
        default='login.keychain')
    key_group.add_argument(
        '-n',
        '--name',
        help='Common name of certificate to use from keychain.',
        required=True)
    parser.add_argument('infile', help='Path to input .mobileconfig file')
    parser.add_argument(
        'outfile',
        help=
        'Path to output .mobileconfig file. Defaults to outputting into the same directory.'
    )
    args = parser.parse_args()
    print "f**k yeah"

    if args.sign == 'encrypt' or args.sign == 'both':
        # encrypt the profile only, do not sign
        # Encrypting a profile:
        # 1. Extract payload content into its own file
        # 2. Serial that file as its own plist
        # 3. CMS-envelope that content (using openssl for now)
        # 4. Remove "PayloadContent" key and replace with "EncryptedPayloadContent" key
        # 5. Replace the PayloadContent <array> with <data> tags instead

        # Step 1: Extract payload content into its own file
        myProfile = plistlib.readPlist(args.infile)
        payloadContent = myProfile['PayloadContent']

        # Step 2: Serialize that file into its own plist
        (pContentFile, pContentPath) = tempfile.mkstemp()
        plistlib.writePlist(payloadContent, pContentPath)

        # Step 3: Use openssl to encrypt that content
        # First, we need to extract the certificate we want to use from the keychain
        security_cmd = [
            '/usr/bin/security', 'find-certificate', '-c', args.name, '-p'
        ]
        if args.keychain:
            security_cmd += [args.keychain]
        print security_cmd
        proc = subprocess.Popen(security_cmd,
                                stdout=subprocess.PIPE,
                                stderr=subprocess.PIPE)
        (sout, serr) = proc.communicate()
        if serr:
            print >> sys.stderr, "Error: %s" % serr
            sys.exit(1)
        # Now write the certificate to a temp file
        (certfile, certpath) = tempfile.mkstemp('.pem')
        try:
            with open(certpath, 'wb') as f:
                f.write(sout)
        except IOError:
            print >> sys.stderr, "Could not write to file!"
            sys.exit(1)
        # Now use openssl to encrypt the payload content using that certificate
        (encPContentfile, encPContentPath) = tempfile.mkstemp('.plist')
        enc_cmd = [
            '/usr/bin/openssl', 'smime', '-encrypt', '-aes256', '-outform',
            'pem', '-in', pContentPath, '-out', encPContentPath
        ]
        enc_cmd += [certpath]
        proc = subprocess.Popen(enc_cmd,
                                stdout=subprocess.PIPE,
                                stderr=subprocess.PIPE)
        (encout, encerr) = proc.communicate()
        if encerr:
            print >> sys.stderr, "Error: %s" % encerr
            sys.exit(1)
        # openssl smime -encrypt produces no output if successful

        # Step 4: Add the new encrypted payload content back into the plist
        with open(encPContentPath, 'rb') as f:
            content = f.readlines()
            content = content[
                1:
                -1]  #this is to skip the ---BEGIN PKCS7--- and ----END PKCS7---- lines
        encPayload = ""
        for line in content:
            encPayload += ''.join(
                line.rstrip())  # to get rid of Python's \n everywhere
        del myProfile['PayloadContent']

        binaryEncPayload = base64.b64decode(encPayload)
        wrapped_data = NSData.dataWithBytes_length_(binaryEncPayload,
                                                    len(binaryEncPayload))
        myProfile['EncryptedPayloadContent'] = wrapped_data
        plistData, error = NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_(
            myProfile, NSPropertyListXMLFormat_v1_0, None)
        plistData.writeToFile_atomically_(args.outfile, True)

        # Step 5: Use plistlib.Data to properly encode the content
        # myProfile['EncryptedPayloadContent'] = plistlib.Data(encPayload)
        # now save the profile
        # plistlib.writePlist(myProfile, args.outfile)

        # Now clean up after ourselves

    if args.sign == 'sign' or args.sign == 'both':
        # sign the profile only
        # Keychain check:
        if not args.name:
            print >> sys.stderr, 'Error: A certificate common name is required to sign profiles with the Keychain.'
            sys.exit(22)
        cmd = [
            '/usr/bin/security', 'cms', '-S', '-N', args.name, '-i',
            args.infile, '-o', args.outfile
        ]
        proc = subprocess.Popen(cmd,
                                stdout=subprocess.PIPE,
                                stderr=subprocess.PIPE)
        (sout, serr) = proc.communicate()
        if serr:
            print >> sys.stderr, 'Error: %s' % serr
            sys.exit(1)
示例#26
0
def main():
    parser = argparse.ArgumentParser(description='Sign or encrypt mobileconfig profiles, using either a cert + key file, or a keychain certificate.')
    parser.add_argument('sign', choices=('sign', 'encrypt', 'both'), help='Choose to sign, encrypt, or do both on a profile.')
    key_group = parser.add_argument_group('Keychain arguments', description='Use these if you wish to sign with a Keychain certificate.')
    key_group.add_argument('-k', '--keychain', help='Name of keychain to search for cert. Defaults to login.keychain',
                        default='login.keychain')
    key_group.add_argument('-n', '--name', help='Common name of certificate to use from keychain.', required=True)
    parser.add_argument('infile', help='Path to input .mobileconfig file')
    parser.add_argument('outfile', help='Path to output .mobileconfig file. Defaults to outputting into the same directory.')
    args = parser.parse_args()
    
    if args.sign == 'encrypt' or args.sign == 'both':
        if args.sign == 'both':
            outputFile = args.outfile + '_unsigned'
        else:
            outputFile = args.outfile
        # encrypt the profile only, do not sign
        # Encrypting a profile:
        # 1. Extract payload content into its own file
        # 2. Serial that file as its own plist
        # 3. CMS-envelope that content (using openssl for now)
        # 4. Remove "PayloadContent" key and replace with "EncryptedPayloadContent" key
        # 5. Replace the PayloadContent <array> with <data> tags instead

        # Step 1: Extract payload content into its own file
        myProfile = readPlist(args.infile)
        payloadContent = myProfile['PayloadContent']

        # Step 2: Serialize that file into its own plist
        (pContentFile, pContentPath) = tempfile.mkstemp()
        #print "pContentPath: %s" % pContentPath
        writePlist(payloadContent, pContentPath)
        
        # Step 3: Use openssl to encrypt that content
        # First, we need to extract the certificate we want to use from the keychain
        security_cmd = ['/usr/bin/security', 'find-certificate', '-c', args.name, '-p' ]
        if args.keychain:
            security_cmd += [args.keychain]
        proc = subprocess.Popen(security_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        (sout, serr) = proc.communicate()
        if serr:
            print >> sys.stderr, "Error: %s" % serr
            sys.exit(1)
        # Now write the certificate to a temp file
        (certfile, certpath) = tempfile.mkstemp('.der')
        #print "Certpath: %s" % certpath
        try:
            with open(certpath, 'wb') as f:
                f.write(sout)
        except IOError:
            print >> sys.stderr, "Could not write to file!"
            sys.exit(1)      
        # Now use openssl to encrypt the payload content using that certificate
        (encPContentfile, encPContentPath) = tempfile.mkstemp('.plist')
        #print "encPContentPath: %s" % encPContentPath
        enc_cmd = ['/usr/bin/openssl', 'smime', '-encrypt', '-aes256', '-outform', 'der', 
                '-in', pContentPath, '-out', encPContentPath]
        enc_cmd += [certpath]
        proc = subprocess.Popen(enc_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        (encout, encerr) = proc.communicate()
        if encerr:
            print >> sys.stderr, "Error: %s" % encerr
            sys.exit(1)
        # openssl smime -encrypt produces no output if successful
        
        # Step 4: Add the new encrypted payload content back into the plist
        with open(encPContentPath, 'rb') as f:
            binaryEncPayload = f.read()
        del myProfile['PayloadContent']
        wrapped_data = NSData.dataWithBytes_length_(binaryEncPayload, len(binaryEncPayload))
        myProfile['EncryptedPayloadContent'] = wrapped_data

        # Step 5: Replace the plist with the new content
        plistData, error = NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_(myProfile, NSPropertyListXMLFormat_v1_0, None)
        plistData.writeToFile_atomically_(outputFile, True)

        # Now clean up after ourselves
        os.remove(pContentPath)
        os.remove(certpath)
        os.remove(encPContentPath)
    
    if args.sign == 'sign' or args.sign == 'both':
        # Keychain check:
        if not args.name:
            print >> sys.stderr, 'Error: A certificate common name is required to sign profiles with the Keychain.'
            sys.exit(22)
        if args.sign == 'both':
            # If we already encrypted it, then the correct file is already in outputFile
            inputFile = outputFile
        else:
            inputFile = args.infile
        cmd = ['/usr/bin/security', 'cms', '-S', '-N', args.name, '-i', inputFile, '-o', args.outfile ]
        proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        (sout, serr) = proc.communicate()
        if serr:
            print >> sys.stderr, 'Error: %s' % serr
            sys.exit(1)
        if args.sign == 'both':
            os.remove(outputFile)
示例#27
0
def main():
    parser = argparse.ArgumentParser(description='Sign or encrypt mobileconfig profiles, using either a cert + key file, or a keychain certificate.')
    parser.add_argument('sign', choices=('sign', 'encrypt', 'both'), help='Choose to sign, encrypt, or do both on a profile.')
    key_group = parser.add_argument_group('Keychain arguments', description='Use these if you wish to sign with a Keychain certificate.')
    key_group.add_argument('-k', '--keychain', help='Name of keychain to search for cert. Defaults to login.keychain',
                        default='login.keychain')
    key_group.add_argument('-n', '--name', help='Common name of certificate to use from keychain.', required=True)
    parser.add_argument('infile', help='Path to input .mobileconfig file')
    parser.add_argument('outfile', help='Path to output .mobileconfig file. Defaults to outputting into the same directory.')
    args = parser.parse_args()
    
    if args.sign == 'encrypt' or args.sign == 'both':
        if args.sign == 'both':
            outputFile = args.outfile + '_unsigned'
        else:
            outputFile = args.outfile
        # encrypt the profile only, do not sign
        # Encrypting a profile:
        # 1. Extract payload content into its own file
        # 2. Serial that file as its own plist
        # 3. CMS-envelope that content (using openssl for now)
        # 4. Remove "PayloadContent" key and replace with "EncryptedPayloadContent" key
        # 5. Replace the PayloadContent <array> with <data> tags instead

        # Step 1: Extract payload content into its own file
        myProfile = readPlist(args.infile)
        payloadContent = myProfile['PayloadContent']

        # Step 2: Serialize that file into its own plist
        (pContentFile, pContentPath) = tempfile.mkstemp()
        #print "pContentPath: %s" % pContentPath
        writePlist(payloadContent, pContentPath)
        
        # Step 3: Use openssl to encrypt that content
        # First, we need to extract the certificate we want to use from the keychain
        security_cmd = ['/usr/bin/security', 'find-certificate', '-c', args.name, '-p' ]
        if args.keychain:
            security_cmd += [args.keychain]
        proc = subprocess.Popen(security_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        (sout, serr) = proc.communicate()
        if serr:
            print >> sys.stderr, "Error: %s" % serr
            sys.exit(1)
        # Now write the certificate to a temp file
        (certfile, certpath) = tempfile.mkstemp('.der')
        #print "Certpath: %s" % certpath
        try:
            with open(certpath, 'wb') as f:
                f.write(sout)
        except IOError:
            print >> sys.stderr, "Could not write to file!"
            sys.exit(1)      
        # Now use openssl to encrypt the payload content using that certificate
        (encPContentfile, encPContentPath) = tempfile.mkstemp('.plist')
        #print "encPContentPath: %s" % encPContentPath
        enc_cmd = ['/usr/bin/openssl', 'smime', '-encrypt', '-aes256', '-outform', 'der', 
                '-in', pContentPath, '-out', encPContentPath]
        enc_cmd += [certpath]
        proc = subprocess.Popen(enc_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        (encout, encerr) = proc.communicate()
        if encerr:
            print >> sys.stderr, "Error: %s" % encerr
            sys.exit(1)
        # openssl smime -encrypt produces no output if successful
        
        # Step 4: Add the new encrypted payload content back into the plist
        with open(encPContentPath, 'rb') as f:
            binaryEncPayload = f.read()
        del myProfile['PayloadContent']
        wrapped_data = NSData.dataWithBytes_length_(binaryEncPayload, len(binaryEncPayload))
        myProfile['EncryptedPayloadContent'] = wrapped_data

        # Step 5: Replace the plist with the new content
        plistData, error = NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_(myProfile, NSPropertyListXMLFormat_v1_0, None)
        plistData.writeToFile_atomically_(outputFile, True)

        # Now clean up after ourselves
        os.remove(pContentPath)
        os.remove(certpath)
        os.remove(encPContentPath)
    
    if args.sign == 'sign' or args.sign == 'both':
        # Keychain check:
        if not args.name:
            print >> sys.stderr, 'Error: A certificate common name is required to sign profiles with the Keychain.'
            sys.exit(22)
        if args.sign == 'both':
            # If we already encrypted it, then the correct file is already in outputFile
            inputFile = outputFile
        else:
            inputFile = args.infile
        cmd = ['/usr/bin/security', 'cms', '-S', '-N', args.name, '-i', inputFile, '-o', args.outfile ]
        proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        (sout, serr) = proc.communicate()
        if serr:
            print >> sys.stderr, 'Error: %s' % serr
            sys.exit(1)
        if args.sign == 'both':
            os.remove(outputFile)