无法在 Xamarin 中使用 SecKeyChain 将证书存储到 KeyChain
Cannot store Certificate to KeyChain using SecKeyChain in Xamarin
在花了几个小时阅读网上可用的内容来解决这个问题后,我决定 post 在这里回答我的问题。
我的目标很简单:使用 Xamarin for iOS 将 X509Certficate 存储到 KeyChain。这是我使用 BouncyCastle 库生成的自签名证书。
我正在成功导入它,但是当使用 SecKeyChain.Add
保存到 KeyChain 时,结果总是 SecStatusCode.Param
,文档解释说缺少或无效参数。这是我使用的方法
public static bool StoreCertInKeyChain(X509Certificate2 certificate, string password)
{
var data = certificate.Export(X509ContentType.Pkcs12, password);
var options = NSMutableDictionary.FromObjectAndKey(FromObject(password), SecImportExport.Passphrase);
var statusCode = SecImportExport.ImportPkcs12(data, options, out NSDictionary[] result);
if (statusCode != SecStatusCode.Success) return false;
var certChain = result[0][SecImportExport.CertChain];
var record = new SecRecord(SecKind.Certificate)
{
Label = "MyKey",
Account = "Certificate",
ApplicationTag = "MyTag"
};
record.SetValueRef(certChain);
// Using the below code instead, produces the same result
// var cert = new SecCertificate(certChain.Handle);
// record.SetValueRef(cert);
var resultAdd = SecKeyChain.Add(record);
return resultAdd == SecStatusCode.Success;
}
有人 运行 遇到过这个问题吗?我不知道还有什么可以尝试的。我遵循了 Xamarin 文档站点上给出的示例,但没有成功。谢谢
在这里回答我的解决方案,以防其他人遇到同样的问题。问题是 SecRecord
中提供的证书不是 SecCertificate
的实例,因此使用 SecImportExport.ImportPkcs12
是错误的方法。我最终改用了 SecIdentity.Import
,它提供了对证书及其中的私钥的引用。证书和私钥需要使用身份分别添加到密钥链中。这是完成此操作的代码。
var identity = SecIdentity.Import(certificate.Export(X509ContentType.Pkcs12, password), password);
var storedCertificate = SecKeyChain.QueryAsConcreteType(new SecRecord(SecKind.Certificate) { Label = "My Cert" }, out SecStatusCode statusCode);
if (statusCode != SecStatusCode.Success)
{
var record = new SecRecord(SecKind.Certificate);
record.Label = "My Cert";
record.SetValueRef(identity.Certificate);
var result = SecKeyChain.Add(record);
SecKeyChain.AddIdentity(identity);
storedCertificate = SecKeyChain.QueryAsConcreteType(new SecRecord(SecKind.Certificate) { Label = "My Cert" }, out statusCode);
}
var storedIdentity = SecKeyChain.FindIdentity(storedCertificate as SecCertificate);
可以使用标签检索证书,但要获取私钥,必须使用证书作为参数在SecKeyChain.FindIdentity
中查询身份。从此时起,可以从身份实例访问私钥的签名和解密。
在花了几个小时阅读网上可用的内容来解决这个问题后,我决定 post 在这里回答我的问题。
我的目标很简单:使用 Xamarin for iOS 将 X509Certficate 存储到 KeyChain。这是我使用 BouncyCastle 库生成的自签名证书。
我正在成功导入它,但是当使用 SecKeyChain.Add
保存到 KeyChain 时,结果总是 SecStatusCode.Param
,文档解释说缺少或无效参数。这是我使用的方法
public static bool StoreCertInKeyChain(X509Certificate2 certificate, string password)
{
var data = certificate.Export(X509ContentType.Pkcs12, password);
var options = NSMutableDictionary.FromObjectAndKey(FromObject(password), SecImportExport.Passphrase);
var statusCode = SecImportExport.ImportPkcs12(data, options, out NSDictionary[] result);
if (statusCode != SecStatusCode.Success) return false;
var certChain = result[0][SecImportExport.CertChain];
var record = new SecRecord(SecKind.Certificate)
{
Label = "MyKey",
Account = "Certificate",
ApplicationTag = "MyTag"
};
record.SetValueRef(certChain);
// Using the below code instead, produces the same result
// var cert = new SecCertificate(certChain.Handle);
// record.SetValueRef(cert);
var resultAdd = SecKeyChain.Add(record);
return resultAdd == SecStatusCode.Success;
}
有人 运行 遇到过这个问题吗?我不知道还有什么可以尝试的。我遵循了 Xamarin 文档站点上给出的示例,但没有成功。谢谢
在这里回答我的解决方案,以防其他人遇到同样的问题。问题是 SecRecord
中提供的证书不是 SecCertificate
的实例,因此使用 SecImportExport.ImportPkcs12
是错误的方法。我最终改用了 SecIdentity.Import
,它提供了对证书及其中的私钥的引用。证书和私钥需要使用身份分别添加到密钥链中。这是完成此操作的代码。
var identity = SecIdentity.Import(certificate.Export(X509ContentType.Pkcs12, password), password);
var storedCertificate = SecKeyChain.QueryAsConcreteType(new SecRecord(SecKind.Certificate) { Label = "My Cert" }, out SecStatusCode statusCode);
if (statusCode != SecStatusCode.Success)
{
var record = new SecRecord(SecKind.Certificate);
record.Label = "My Cert";
record.SetValueRef(identity.Certificate);
var result = SecKeyChain.Add(record);
SecKeyChain.AddIdentity(identity);
storedCertificate = SecKeyChain.QueryAsConcreteType(new SecRecord(SecKind.Certificate) { Label = "My Cert" }, out statusCode);
}
var storedIdentity = SecKeyChain.FindIdentity(storedCertificate as SecCertificate);
可以使用标签检索证书,但要获取私钥,必须使用证书作为参数在SecKeyChain.FindIdentity
中查询身份。从此时起,可以从身份实例访问私钥的签名和解密。