如何使用 node-forge 创建与 iOS 的多点连接兼容的 PKCS12?
How to create a PKCS12 compatible with iOS's Multipeer Connectivity with node-forge?
我正在尝试通过使用 X509 证书 的客户端身份验证实现 多点连接 通信安全。
为此,我使用 node-forge 在我的服务器中生成客户端证书。首先,创建 X509 然后将其转换为返回给客户端的 PKCS12 base64 字符串 。
这基本上就是我使用的代码:
var username = "client1"
// Create key pair
var pki = forge.pki;
var keys = pki.rsa.generateKeyPair(2048);
var cert = pki.createCertificate();
// Creating the certificate
cert.publicKey = keys.publicKey;
cert.serialNumber = '01'; // TODO : generate random number and have a little custom algo to verify it !!
cert.validity.notBefore = new Date();
cert.validity.notAfter = new Date();
cert.validity.notAfter.setTime(cert.validity.notBefore.getTime() + msWeek);
var subject = [{
name : "commonName",
value : username
}, {
name : "organizationName",
value : "My Company"
}, {
name : "organizationalUnitName",
value : "MU"
}, {
name : "stateOrProvinceName",
value : "Ile-de-France"
}, {
name : "countryName",
value : "FR"
}, {
name : "localityName",
value : "Paris"
}, {
name : "emailAddress",
value : "hello@world.com"
} ];
var issuer = [{
name : "commonName",
value : "MPC App"
}, {
name : "organizationName",
value : "My Company"
}, {
name : "organizationalUnitName",
value : "MU"
}, {
name : "stateOrProvinceName",
value : "Ile-de-France"
}, {
name : "countryName",
value : "FR"
}, {
name : "localityName",
value : "Paris"
}, {
name : "emailAddress",
value : "hello@world.com"
} ];
cert.setSubject(subject);
cert.setIssuer(issuer);
// Extensions
cert.setExtensions([{
name: 'basicConstraints',
cA : true
} , {
name : 'keyUsage',
digitalSignature : true,
keyCertSign : true,
nonRepudiation : true,
keyEncipherment : true,
dataEncipherment : true
}, {
name : 'extKeyUsage',
clientAuth : true,
serverAuth : false,
codeSigning : true,
emailProtection : false,
timeStamping : true
}, {
name : 'nsCertType',
client : true,
server : false,
email : false,
objsign : true,
sslCA : false,
emailCA : false,
objCA : false
}]);
cert.sign(keys.privateKey);
var asn1Cert = pki.certificateToAsn1(cert);
// Create PKCS#12 from the certificate and encode to base64 string
var p12Asn1 = forge.pkcs12.toPkcs12Asn1(keys.privateKey , cert, "iPhone");
var p12Der = forge.asn1.toDer(p12Asn1).getBytes();
return forge.util.encode64(p12Der);
但是,当我将它导入我的 iOS 应用程序时,运行时不断崩溃,告诉我它未能通过返回 errSecDecode。
我不知道我的代码的哪一部分导致了这个错误,尽管我怀疑 extensions 是这些问题的根源,顺便说一句,我不知道我真的不知道什么最适合我的用例(两个客户端相互验证自己以便与 MultiPeer Connectivity 通信)。
我还想知道我在将 PKCS#12 编码为 base64 字符串 时是否做错了什么?
如果有帮助,这是我用来在 iOS 中导入 PKCS#12 的代码从服务器恢复 base64 字符串后的一侧。
private func generateIdentity (base64p12 : String, password : String?) {
print("gen id")
let p12KeyFileContent = NSData(base64EncodedString: base64p12, options: NSDataBase64DecodingOptions.IgnoreUnknownCharacters)
if (p12KeyFileContent == nil) {
NSLog("Cannot read PKCS12 data")
return
}
let options = [String(kSecImportExportPassphrase):password ?? ""]
var citems: CFArray? = nil
let resultPKCS12Import = withUnsafeMutablePointer(&citems) { citemsPtr in
SecPKCS12Import(p12KeyFileContent!, options, citemsPtr)
}
if (resultPKCS12Import != errSecSuccess) {
print("resultPKCS12Import :", resultPKCS12Import)
return
}
let items = citems! as NSArray
let myIdentityAndTrust = items.objectAtIndex(0) as! NSDictionary
let identityKey = String(kSecImportItemIdentity)
identity = myIdentityAndTrust[identityKey] as! SecIdentityRef
hasCertificate = true
print("cert cre", identity)
}
提前致谢
编辑:
通过使用 node-forge 解码 base64 字符串,我可以看到我在创建证书时输入的信息,而且它们打印得很好,没有呈现不好的字符。
现在我问自己 iOS 是否故意抛出此错误以阻止我使用不是使用其特定工具(Apple Keychain 如果我没记错的话)创建的证书。
显然,iOS 的安全框架要求 PKCS#12 使用 TripleDES 加密算法。
因此,替换行:
var p12Asn1 = forge.pkcs12.toPkcs12Asn1(keys.privateKey , cert, "iPhone");
与:
var p12Asn1 = forge.pkcs12.toPkcs12Asn1(keys.privateKey , cert, "iPhone", {algorithm : '3des'});
很有魅力。
在这一点上,我仍然不明白为什么 Apple 的文档在这个主题上如此详尽无遗:/。
我正在尝试通过使用 X509 证书 的客户端身份验证实现 多点连接 通信安全。
为此,我使用 node-forge 在我的服务器中生成客户端证书。首先,创建 X509 然后将其转换为返回给客户端的 PKCS12 base64 字符串 。
这基本上就是我使用的代码:
var username = "client1"
// Create key pair
var pki = forge.pki;
var keys = pki.rsa.generateKeyPair(2048);
var cert = pki.createCertificate();
// Creating the certificate
cert.publicKey = keys.publicKey;
cert.serialNumber = '01'; // TODO : generate random number and have a little custom algo to verify it !!
cert.validity.notBefore = new Date();
cert.validity.notAfter = new Date();
cert.validity.notAfter.setTime(cert.validity.notBefore.getTime() + msWeek);
var subject = [{
name : "commonName",
value : username
}, {
name : "organizationName",
value : "My Company"
}, {
name : "organizationalUnitName",
value : "MU"
}, {
name : "stateOrProvinceName",
value : "Ile-de-France"
}, {
name : "countryName",
value : "FR"
}, {
name : "localityName",
value : "Paris"
}, {
name : "emailAddress",
value : "hello@world.com"
} ];
var issuer = [{
name : "commonName",
value : "MPC App"
}, {
name : "organizationName",
value : "My Company"
}, {
name : "organizationalUnitName",
value : "MU"
}, {
name : "stateOrProvinceName",
value : "Ile-de-France"
}, {
name : "countryName",
value : "FR"
}, {
name : "localityName",
value : "Paris"
}, {
name : "emailAddress",
value : "hello@world.com"
} ];
cert.setSubject(subject);
cert.setIssuer(issuer);
// Extensions
cert.setExtensions([{
name: 'basicConstraints',
cA : true
} , {
name : 'keyUsage',
digitalSignature : true,
keyCertSign : true,
nonRepudiation : true,
keyEncipherment : true,
dataEncipherment : true
}, {
name : 'extKeyUsage',
clientAuth : true,
serverAuth : false,
codeSigning : true,
emailProtection : false,
timeStamping : true
}, {
name : 'nsCertType',
client : true,
server : false,
email : false,
objsign : true,
sslCA : false,
emailCA : false,
objCA : false
}]);
cert.sign(keys.privateKey);
var asn1Cert = pki.certificateToAsn1(cert);
// Create PKCS#12 from the certificate and encode to base64 string
var p12Asn1 = forge.pkcs12.toPkcs12Asn1(keys.privateKey , cert, "iPhone");
var p12Der = forge.asn1.toDer(p12Asn1).getBytes();
return forge.util.encode64(p12Der);
但是,当我将它导入我的 iOS 应用程序时,运行时不断崩溃,告诉我它未能通过返回 errSecDecode。
我不知道我的代码的哪一部分导致了这个错误,尽管我怀疑 extensions 是这些问题的根源,顺便说一句,我不知道我真的不知道什么最适合我的用例(两个客户端相互验证自己以便与 MultiPeer Connectivity 通信)。
我还想知道我在将 PKCS#12 编码为 base64 字符串 时是否做错了什么?
如果有帮助,这是我用来在 iOS 中导入 PKCS#12 的代码从服务器恢复 base64 字符串后的一侧。
private func generateIdentity (base64p12 : String, password : String?) {
print("gen id")
let p12KeyFileContent = NSData(base64EncodedString: base64p12, options: NSDataBase64DecodingOptions.IgnoreUnknownCharacters)
if (p12KeyFileContent == nil) {
NSLog("Cannot read PKCS12 data")
return
}
let options = [String(kSecImportExportPassphrase):password ?? ""]
var citems: CFArray? = nil
let resultPKCS12Import = withUnsafeMutablePointer(&citems) { citemsPtr in
SecPKCS12Import(p12KeyFileContent!, options, citemsPtr)
}
if (resultPKCS12Import != errSecSuccess) {
print("resultPKCS12Import :", resultPKCS12Import)
return
}
let items = citems! as NSArray
let myIdentityAndTrust = items.objectAtIndex(0) as! NSDictionary
let identityKey = String(kSecImportItemIdentity)
identity = myIdentityAndTrust[identityKey] as! SecIdentityRef
hasCertificate = true
print("cert cre", identity)
}
提前致谢
编辑: 通过使用 node-forge 解码 base64 字符串,我可以看到我在创建证书时输入的信息,而且它们打印得很好,没有呈现不好的字符。
现在我问自己 iOS 是否故意抛出此错误以阻止我使用不是使用其特定工具(Apple Keychain 如果我没记错的话)创建的证书。
显然,iOS 的安全框架要求 PKCS#12 使用 TripleDES 加密算法。
因此,替换行:
var p12Asn1 = forge.pkcs12.toPkcs12Asn1(keys.privateKey , cert, "iPhone");
与:
var p12Asn1 = forge.pkcs12.toPkcs12Asn1(keys.privateKey , cert, "iPhone", {algorithm : '3des'});
很有魅力。
在这一点上,我仍然不明白为什么 Apple 的文档在这个主题上如此详尽无遗:/。