无法使用Xamarin中的SecKeyChain将证书存储到KeyChain

时间:2017-12-05 15:21:37

标签: ios xamarin xamarin.ios certificate keychain

花了几个小时阅读通过网上可用的内容解决这个问题,我决定在这里发布我的问题。 我的目标很简单:使用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文档站点上给出的示例,没有成功。谢谢

1 个答案:

答案 0 :(得分:2)

在这里回答我的解决方案,以防其他人遇到同样的问题。问题是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中的证书作为参数查询身份。从现在开始,可以从身份实例访问对私钥的签名和解密。