Last active
January 18, 2019 12:46
-
-
Save joshua-d-miller/241cd83602cc33882ff9ab54ab92e425 to your computer and use it in GitHub Desktop.
When deploying an EAP-TLS profile for 802.1x Ethernet, this script will create a User Identity preference which will allow a logged in user to use any Ethernet interface that is connected to their machine.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
# pylint: disable=C0103, W0612, E1101, E0602, E0611 | |
# pylint: disable=W0101, W0110, W0141 | |
''''Fix 802.1x When Using Config Profiles and EAP-TLS''' | |
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # | |
# | |
# This script will determine the profile ID that was used when | |
# installing the 802.1x Ethernet Identity preference and make | |
# a copy of the keychain entry to be used as a user identity preference | |
# so that any Ethernet can be used when a user is logged in. As of 10.12.3 | |
# there is currently a bug with the 802.1x System profile that will only | |
# allow the first Ethernet that was active at the time of profile install | |
# to be used. | |
# | |
# | |
# Joshua D. Miller - [email protected] - The Pennsylvania State University | |
# Last Updated Friday February 23, 2016 | |
# | |
# Many Many Thanks to Michael Lynn and Mosen for taking me down | |
# the rabbit hole that is PyObjC | |
# | |
# References | |
# https://gist.github.com/pudquick/8ad859f30438f3be149fe9751391d037 | |
# https://gist.github.com/pudquick/4cf32c2b403bf0be23b268d6dd3cf803 | |
# https://github.com/mosen/pudquick-pyobjc-framework-Security/ | |
# blob/master/metadata/raw/x86_64-10.12.fwinfo | |
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # | |
# | |
# Steps Performed in this script | |
# - Determine Profile ID by reading /Library/Preferences/ | |
# SystemConfiguration | |
# /com.apple.network.eapolclient.configuration.plist | |
# - Find the keycahin entry | |
# com.apple.network.eap.system.identity.profileid.UUID | |
# - Create a copy named | |
# com.apple.network.eap.user.identity.profileid.UUID | |
# | |
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # | |
# Most of EAP 802.1x and Keychain PyObjC code from Michael Lynn | |
# Instructions on using SecIdentityCopyPreferred and SecIdentityPreferred | |
# provided by Mosen | |
from __future__ import print_function | |
from Foundation import NSBundle | |
import objc | |
def get_profile_uuid(): | |
'''Get the UUID of the Configuration Profiles 802.1x Identity | |
Preference''' | |
EAP8021X_bundle = NSBundle.bundleWithPath_( | |
'/System/Library/PrivateFrameworks/EAP8021X.framework') | |
E_functions = [ | |
('EAPOLControlCopyStateAndStatus', 'i*o^io^@'), | |
('EAPOLClientConfigurationCreate', '@^@'), | |
('EAPOLClientConfigurationCopyProfiles', '@@'), | |
('EAPOLClientProfileGetUserDefinedName', '@@'), | |
('EAPOLClientProfileGetID', '@@'), ] | |
objc.loadBundleFunctions(EAP8021X_bundle, globals(), E_functions) | |
maximum_interfaces = 20 | |
interfaces = map(lambda x: 'en%s' % x, range(maximum_interfaces)) | |
for i in interfaces: | |
result, status, eap_config = EAPOLControlCopyStateAndStatus( | |
i, None, None) | |
if result == 0: | |
cfg = EAPOLClientConfigurationCreate(None) | |
profiles = EAPOLClientConfigurationCopyProfiles(cfg) | |
for n in profiles: | |
display_name = EAPOLClientProfileGetUserDefinedName(n) | |
if display_name == 'Ethernet - CoE': | |
profile_id = EAPOLClientProfileGetID(n) | |
return profile_id | |
def create_identity_preference(): | |
'''Time to modify the keychain and create the identity preference we need | |
to fix Apple's issue - Still an issue as of 10.12.3''' | |
# from CoreFoundation import CFGetTypeID | |
Security_framework = NSBundle.bundleWithPath_( | |
'/System/Library/Frameworks/Security.framework') | |
# Objective C Functions we will use to accomplish our keychain | |
# change | |
keychain_functions = [ | |
('SecKeychainGetTypeID', 'I'), | |
('SecIdentityGetTypeID', 'I'), | |
('SecKeychainSetUserInteractionAllowed', 'IZ'), | |
('SecKeychainCopyDomainDefault', 'IIo^^{__CFArray}'), | |
('SecKeychainOpen', 'I*o^^{__SecKeychain=}'), | |
('SecKeychainGetStatus', 'I^{__SecKeychain=}o^I'), | |
('SecKeychainUnlock', 'I^{__SecKeychain=}I*I'), | |
('SecIdentityCopyPreferred', | |
'^{__SecIdentityRef=}^{__CFString}^{__CFArray}^{__CFArray}'), | |
('SecKeychainSetPreferenceDomain', 'II'), | |
('SecIdentitySetPreferred', | |
'I^{__SecIdentityRef=}^{__CFString}^{__CFArray}'), | |
('SecKeychainLock', 'I^{__SecKeychain=}'), ] | |
objc.loadBundleFunctions(Security_framework, globals(), keychain_functions) | |
# Build out our CF type signatures | |
objc.registerCFSignature( | |
'SecKeychainRef', '^{__SecKeychain=}', SecKeychainGetTypeID()) | |
objc.registerCFSignature( | |
'SecIdentityRef', '^{__SecIdentityRef=}', SecIdentityGetTypeID()) | |
kSecUnlockStateStatus = 1 | |
kSecPreferencesDomainSystem = 1 | |
system_profile_name = ('com.apple.network.eap.system' | |
'.identity.profileid.{0:}'.format(uuid)) | |
user_profile_name = ('com.apple.network.eap.user' | |
'.identity.profileid.{0:}'.format(uuid)) | |
# Turn off any prompts for a user to enter a password for keychain | |
SecKeychainSetUserInteractionAllowed(False) | |
# Let's Open the System Keychain | |
err, keychains = SecKeychainCopyDomainDefault( | |
kSecPreferencesDomainSystem, None) | |
err, keychain = SecKeychainOpen('System.keychain', None) | |
if err: | |
return err | |
# Check Status of the System Keychain (Should be locked) | |
err, status = SecKeychainGetStatus(keychain, None) | |
unlocked = status | kSecUnlockStateStatus == kSecUnlockStateStatus | |
if not unlocked: | |
# Unlock the System Keychain | |
keychain = SecKeychainUnlock(keychain, 0, None, False) | |
# Copy our Identity Preference and make the new one with | |
# the same attributes | |
keychain_item = SecIdentityCopyPreferred( | |
system_profile_name, None, None) | |
# Apply Change to the System Keychain | |
SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem) | |
err = SecIdentitySetPreferred(keychain_item, user_profile_name, None) | |
if err: | |
return err | |
# Lock the System Keychain | |
err = SecKeychainLock(keychain) | |
return None | |
if __name__ == '__main__': | |
uuid = get_profile_uuid() | |
fin_code = create_identity_preference() | |
if fin_code is not None: | |
# Build the SecCopyErrorMessageString to read the error | |
Security = NSBundle.bundleWithPath_( | |
'/System/Library/Frameworks/Security.framework') | |
functions = [ | |
('SecCopyErrorMessageString', '^{__CFString}I^v'), ] | |
objc.loadBundleFunctions(Security, globals(), functions) | |
message = SecCopyErrorMessageString(fin_code, None) | |
print("Error: {}".format(message)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment