我正在使用 MAC 应用程序从我的应用程序创建 VPN 连接。
经过大量研究后,我发现我需要以 ROOT 身份运行应用程序以将用户密码和 sharedSecretKey 存储在SYSTEM钥匙串中。
应用程序用户不会以 ROOT 身份打开应用程序,因此我需要在没有 ROOT 访问权限的情况下在SYSTEM KEYCHAIN中添加用户密码和 sharedsecretkey。
我在网上搜索,发现 Apple 提供此代码:https ://developer.apple.com/library/mac/samplecode/SMJobBless/Introduction/Intro.html https://developer.apple.com/library/mac /samplecode/EvenBetterAuthorizationSample/Introduction/Intro.html
但不明白如何在我的应用程序中使用这 2 个代码将用户的密码和 SharedSecretKey 存储在SYSTEM KEYCHAIN 中而无需 ROOT ACCESS。
任何帮助将不胜感激。
提前致谢。
这是我在 SYSTEM KEYCHAIN 中添加密码的代码,如果我将代码作为 ROOT 运行,这将非常有用。
// Vendor dependencies
#import <Security/SecKeychain.h>
// Local dependencies
#import "VPNKeychain.h"
// These are the applications which are going to get access to new Keychain items.
// How do we know them? Just create a VPN service manualy and run the following command:
// security dump-keychain -a /Library/Keychains/System.keychain
// Among the results, you will find your VPN service and you can see the paths that have access to it
static const char * trustedAppPaths[] = {
"/System/Library/Frameworks/SystemConfiguration.framework/Versions/A/Helpers/SCHelper", "/System/Library/PreferencePanes/Network.prefPane/Contents/XPCServices/com.apple.preference.network.remoteservice.xpc",
"/System/Library/CoreServices/SystemUIServer.app",
"/usr/sbin/pppd",
"/usr/sbin/racoon",
"/usr/libexec/configd",
};
// This class contains all code we need to handle System Keychain Items
// Exit status codes: 60-79
@implementation VPNKeychain
// This will create a PPP Password Keychain Item
+ (int) createPasswordKeyChainItem:(NSString*)label forService:(NSString*)service withAccount:(NSString*)account andPassword:(NSString*)password {
return [self createItem:label withService:service account:account description:@"PPP Password" andPassword:password];
}
// This will create an IPSec Shared Secret Keychain Item
+ (int) createSharedSecretKeyChainItem:(NSString*)label forService:(NSString*)service withPassword:(NSString*)password {
service = [NSString stringWithFormat:@"%@.SS", service];
return [self createItem:label withService:service account:@"" description:@"IPSec Shared Secret" andPassword:password];
}
// A generic method to create Keychain Items holding Network service passwords
+ (int) createItem:(NSString*)label withService:(NSString*)service account:(NSString*)account description:(NSString*)description andPassword:(NSString*)password {
// This variable will hold all sorts of operation status responses
OSStatus status;
// Converting the NSStrings to char* variables which we will need later
const char *labelUTF8 = [label UTF8String];
const char *serviceUTF8 = [service UTF8String];
const char *accountUTF8 = [account UTF8String];
const char *descriptionUTF8 = [description UTF8String];
const char *passwordUTF8 = [password UTF8String];
// This variable is soon to hold the System Keychain
SecKeychainRef keychain = NULL;
status = SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem, &keychain);
if (status == errSecSuccess) {
NSLog(@"Succeeded opening System Keychain");
} else {
NSLog(@"Could not obtain System Keychain: %@", SecCopyErrorMessageString(status, NULL));
return 60;
}
NSLog(@"Unlocking System Keychain");
status = SecKeychainUnlock(keychain, 0, NULL, FALSE);
if (status == errSecSuccess) {
NSLog(@"Succeeded unlocking System Keychain");
} else {
NSLog(@"Could not unlock System Keychain: %@", SecCopyErrorMessageString(status, NULL));
return 61;
}
// This variable is going to hold our new Keychain Item
SecKeychainItemRef item = nil;
SecAccessRef access = nil;
status = SecAccessCreate(CFSTR("Some VPN Test"), (__bridge CFArrayRef)(self.trustedApps), &access);
if(status == noErr) {
NSLog(@"Created empty Keychain access object");
} else {
NSLog(@"Could not unlock System Keychain: %@", SecCopyErrorMessageString(status, NULL));
return 62;
}
// Putting together the configuration options
SecKeychainAttribute attrs[] = {
{kSecLabelItemAttr, (int)strlen(labelUTF8), (char *)labelUTF8},
{kSecAccountItemAttr, (int)strlen(accountUTF8), (char *)accountUTF8},
{kSecServiceItemAttr, (int)strlen(serviceUTF8), (char *)serviceUTF8},
{kSecDescriptionItemAttr, (int)strlen(descriptionUTF8), (char *)descriptionUTF8},
};
SecKeychainAttributeList attributes = {sizeof(attrs) / sizeof(attrs[0]), attrs};
status = SecKeychainItemCreateFromContent(kSecGenericPasswordItemClass, &attributes, (int)strlen(passwordUTF8), passwordUTF8, keychain, access, &item);
if(status == noErr) {
NSLog(@"Successfully created Keychain Item");
} else {
NSLog(@"Creating Keychain item failed: %@", SecCopyErrorMessageString(status, NULL));
return 63;
}
return 0;
}
+(NSArray*) trustedApps {
NSMutableArray *apps = [NSMutableArray array];
SecTrustedApplicationRef app;
OSStatus err;
for (int i = 0; i < (sizeof(trustedAppPaths) / sizeof(*trustedAppPaths)); i++) {
err = SecTrustedApplicationCreateFromPath(trustedAppPaths[i], &app);
if (err == errSecSuccess) {
//NSLog(@"SecTrustedApplicationCreateFromPath succeeded: %@", SecCopyErrorMessageString(err, NULL));
} else {
NSLog(@"SecTrustedApplicationCreateFromPath failed: %@", SecCopyErrorMessageString(err, NULL));
}
[apps addObject:(__bridge id)app];
}
return apps;
}