以编程方式连接到VPN不断询问系统密钥链凭据
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了以编程方式连接到VPN不断询问系统密钥链凭据相关的知识,希望对你有一定的参考价值。
我的代码使用NEVPNManager
和证书(在MacOS上)连接到VPN,代码工作正常,但每当我尝试连接(targetManager.connection.startVPNTunnel()
)系统提示输入系统密钥链时。
第一次批准后是否会使此警报消失?
码:
func initVPNTunnelProviderManager(vpnConfig: Vpn, _ connect: Bool = false) {
let url = URL(string: vpnConfig.certUrl!)
do {
let certData = try Data(contentsOf: url!)
let targetManager: NEVPNManager = NEVPNManager.shared()
targetManager.loadFromPreferences(completionHandler: { (error:Error?) in
if let error = error {
print(error)
}
switch targetManager.connection.status {
case NEVPNStatus.connected:
targetManager.connection.stopVPNTunnel()
break
case NEVPNStatus.disconnected:
let ip = vpnConfig.serverUrl
let providerProtocol = NEVPNProtocolIKEv2()
providerProtocol.authenticationMethod = .certificate
providerProtocol.serverAddress = ip
providerProtocol.remoteIdentifier = ip
providerProtocol.localIdentifier = "myIdentifier"
providerProtocol.useExtendedAuthentication = false
providerProtocol.ikeSecurityAssociationParameters.encryptionAlgorithm = .algorithmAES128GCM
providerProtocol.ikeSecurityAssociationParameters.diffieHellmanGroup = .group19
providerProtocol.ikeSecurityAssociationParameters.integrityAlgorithm = .SHA512
providerProtocol.ikeSecurityAssociationParameters.lifetimeMinutes = 20
providerProtocol.childSecurityAssociationParameters.encryptionAlgorithm = .algorithmAES128GCM
providerProtocol.childSecurityAssociationParameters.diffieHellmanGroup = .group19
providerProtocol.childSecurityAssociationParameters.integrityAlgorithm = .SHA512
providerProtocol.childSecurityAssociationParameters.lifetimeMinutes = 20
providerProtocol.deadPeerDetectionRate = .medium
providerProtocol.disableRedirect = true
providerProtocol.disableMOBIKE = false
providerProtocol.enableRevocationCheck = false
providerProtocol.enablePFS = true
providerProtocol.useConfigurationAttributeInternalIPSubnet = false
providerProtocol.serverCertificateCommonName = ip
providerProtocol.serverCertificateIssuerCommonName = ip
providerProtocol.disconnectOnSleep = true
providerProtocol.identityDataPassword = vpnConfig.certPassword
providerProtocol.certificateType = .ECDSA256
providerProtocol.identityData = certData
targetManager.protocolConfiguration = providerProtocol
targetManager.localizedDescription = vpnConfig.name
targetManager.isEnabled = true
targetManager.isOnDemandEnabled = false
targetManager.saveToPreferences(completionHandler: { (error:Error?) in
if let error = error {
print(error)
} else {
print("Save successfully")
if connect {
do {
try targetManager.connection.startVPNTunnel()
} catch {
print("Failed to connect")
}
}
}
})
break
default:
print("connection status not handled: (targetManager.connection.status.rawValue)")
}
})
} catch {
print(error.localizedDescription)
}
}
}
答案
解决方法是不使用identityData
和identityDataPassword
,而是自己将身份导入用户的钥匙串(使用SecItemImport
),然后通过NEVPNManager
属性将持久性引用传递给identityReference
。
这是一个工作样本:
private func identityReference(for pkcs12Data: Data, password: String) -> Data {
var importResult: CFArray? = nil
let err = SecPKCS12Import(pkcs12Data as NSData, [
kSecImportExportPassphrase: password
] as NSDictionary, &importResult)
guard err == errSecSuccess else { fatalError() }
let importArray = importResult! as! [[String:Any]]
let identity = importArray[0][kSecImportItemIdentity as String]! as! SecIdentity
var copyResult: CFTypeRef? = nil
let err2 = SecItemCopyMatching([
kSecValueRef: identity,
kSecReturnPersistentRef: true
] as NSDictionary, ©Result)
guard err2 == errSecSuccess else { fatalError() }
return copyResult! as! Data
}
func initVPNTunnelProviderManager(vpnConfig: Vpn, _ connect: Bool = false) {
let url = URL(string: vpnConfig.certUrl!)
do {
let certData = try Data(contentsOf: url!)
let targetManager: NEVPNManager = NEVPNManager.shared()
targetManager.loadFromPreferences(completionHandler: { (error:Error?) in
if let error = error {
print(error)
}
switch targetManager.connection.status {
case NEVPNStatus.connected:
targetManager.connection.stopVPNTunnel()
break
case NEVPNStatus.disconnected:
let ip = vpnConfig.serverUrl
let providerProtocol = NEVPNProtocolIKEv2()
providerProtocol.authenticationMethod = .certificate
providerProtocol.serverAddress = ip
providerProtocol.remoteIdentifier = ip
providerProtocol.localIdentifier = "myIdentifier"
providerProtocol.useExtendedAuthentication = false
providerProtocol.ikeSecurityAssociationParameters.encryptionAlgorithm = .algorithmAES128GCM
providerProtocol.ikeSecurityAssociationParameters.diffieHellmanGroup = .group19
providerProtocol.ikeSecurityAssociationParameters.integrityAlgorithm = .SHA512
providerProtocol.ikeSecurityAssociationParameters.lifetimeMinutes = 20
providerProtocol.childSecurityAssociationParameters.encryptionAlgorithm = .algorithmAES128GCM
providerProtocol.childSecurityAssociationParameters.diffieHellmanGroup = .group19
providerProtocol.childSecurityAssociationParameters.integrityAlgorithm = .SHA512
providerProtocol.childSecurityAssociationParameters.lifetimeMinutes = 20
providerProtocol.deadPeerDetectionRate = .medium
providerProtocol.disableRedirect = true
providerProtocol.disableMOBIKE = false
providerProtocol.enableRevocationCheck = false
providerProtocol.enablePFS = true
providerProtocol.useConfigurationAttributeInternalIPSubnet = false
providerProtocol.serverCertificateCommonName = ip
providerProtocol.serverCertificateIssuerCommonName = ip
providerProtocol.disconnectOnSleep = true
providerProtocol.identityReference = self.identityReference(for: certData, password: vpnConfig.certPassword!)
providerProtocol.certificateType = .ECDSA256
targetManager.protocolConfiguration = providerProtocol
targetManager.localizedDescription = vpnConfig.name
targetManager.isEnabled = true
targetManager.isOnDemandEnabled = false
targetManager.saveToPreferences(completionHandler: { (error:Error?) in
if let error = error {
print(error)
} else {
print("Save successfully")
if connect {
do {
try targetManager.connection.startVPNTunnel()
} catch {
print("Failed to connect")
}
}
}
})
break
default:
print("connection status not handled: (targetManager.connection.status.rawValue)")
}
})
} catch {
print(error.localizedDescription)
}
}
以上是关于以编程方式连接到VPN不断询问系统密钥链凭据的主要内容,如果未能解决你的问题,请参考以下文章
华为防火墙网关间通过IKE方式协商IPSec VPN隧道(共享密钥认证)