gpt4 book ai didi

c# - 如何将 HSM 中存储的私钥转换为 C# 中的 SignedXml.SigningKey

转载 作者:行者123 更新时间:2023-12-01 18:52:29 28 4
gpt4 key购买 nike

我正在尝试使用存储在 HSM 中的证书来实现 XML 签名的一些演示。

我从此链接中发现了一些有趣的示例: Sign XML Document with X509Certificate2并将其修改为使用 HSM 内的证书和 key 以及 PKCS11Interop 包装器。

但任何人都可以给我一个建议或示例,以将 ObjectHandle privateKey 从 HSM 转换为 SignedXML.SigningKey

private static void SignXmlWithCertificate(XmlDocument xmlDoc, X509Certificate2 cert, Session session, String alias)
{
SignedXml signedXml = new SignedXml(xmlDoc);

List<ObjectAttribute> template = new List<ObjectAttribute>();
template.Add(new ObjectAttribute(CKA.CKA_CLASS, CKO.CKO_PRIVATE_KEY));
template.Add(new ObjectAttribute(CKA.CKA_KEY_TYPE, CKK.CKK_RSA));
template.Add(new ObjectAttribute(CKA.CKA_LABEL, alias));
List<ObjectHandle> foundObjects = session.FindAllObjects(template);
ObjectHandle privateKey = foundObjects[0];

signedXml.SigningKey = privateKey; //Here is where I stuck.

在上面外部链接的示例中。他们使用结合了私钥的证书。然后他们就可以像这样使用。

signedXml.SigningKey = cert.PrivateKey;

但是我使用的证书里面没有私钥内容。请给我一些建议。

最佳答案

您需要实现继承自 System.Security.Cryptography.Xml.SignedXml 的自定义类像这样

public class CustomSignedXml: SignedXml
{
public CustomSignedXml(XmlDocument xmlDoc):base(xmlDoc)
{
}
internal void ComputeSignature(ISignerProvider signerProvider)
{
var methodInfo = typeof (SignedXml).GetMethod("BuildDigestedReferences",
BindingFlags.Instance | BindingFlags.NonPublic);
methodInfo.Invoke(this, null);
SignedInfo.SignatureMethod = XmlDsigRSASHA1Url;
// See if there is a signature description class defined in the Config file
SignatureDescription signatureDescription =
CryptoConfig.CreateFromName(SignedInfo.SignatureMethod) as SignatureDescription;
if (signatureDescription == null)
throw new CryptographicException("Cryptography_Xml_SignatureDescriptionNotCreated");

var hashAlg = signatureDescription.CreateDigest();
if (hashAlg == null)
throw new CryptographicException("Cryptography_Xml_CreateHashAlgorithmFailed");
var methodInfo2 = typeof (SignedXml).GetMethod("GetC14NDigest", BindingFlags.Instance | BindingFlags.NonPublic);
var hashvalue = (byte[]) methodInfo2.Invoke(this, new object[] {hashAlg});

m_signature.SignatureValue = signerProvider.Sign(hashvalue);
}
}

然后你需要创建这样的界面

public interface ISignerProvider
{
byte[] Sign(byte[] data);
}

然后通过Pkcs11Interop来实现它像这样

    public class Pkcs11SignerProvider : ISignerProvider
{
private string _thumbprint;
public string DllPath { get; set; }
public string TokenSerial { get; set; }
public string TokenPin { get; set; }
public string PrivateKeyLabel { get; set; }

public Pkcs11SignerProvider(string dllPath, string tokenSerial, string tokenPin, string privateKeyLabel)
{
DllPath = dllPath;
TokenSerial = tokenSerial;
TokenPin = tokenPin;
PrivateKeyLabel = privateKeyLabel;
}

public byte[] Sign(byte[] data)
{
using (var pkcs11 = new Pkcs11(DllPath, AppType.SingleThreaded))
{

var slots = pkcs11.GetSlotList(SlotsType.WithTokenPresent);
var slot = slots.FirstOrDefault(slot1 => slot1.GetTokenInfo().SerialNumber == TokenSerial);
if (slot == null)
throw new Exception("there is no token with serial " + TokenSerial);
using (var session = slot.OpenSession(SessionType.ReadOnly))
{
session.Login(CKU.CKU_USER, TokenPin);

var searchTemplate = new List<ObjectAttribute>
{
new ObjectAttribute(CKA.CKA_CLASS, CKO.CKO_PRIVATE_KEY),
new ObjectAttribute(CKA.CKA_KEY_TYPE, CKK.CKK_RSA)
};
if (!string.IsNullOrEmpty(PrivateKeyLabel))
searchTemplate.Add(new ObjectAttribute(CKA.CKA_LABEL, PrivateKeyLabel));

var foundObjects = session.FindAllObjects(searchTemplate);
var privateKey = foundObjects.FirstOrDefault();

using (var mechanism = new Mechanism(CKM.CKM_RSA_PKCS))
{
return session.Sign(mechanism, privateKey, data);
}

}

}
}

}

然后调用该方法对xml进行签名

public static void Sign(XmlDocument xmlDoc, ISignerProvider signerProvider)
{
if (xmlDoc == null)
throw new ArgumentException("xmlDoc");
if (xmlDoc.DocumentElement == null)
throw new ArgumentException("xmlDoc.DocumentElement");
var signedXml = new CustomSignedXml(xmlDoc);
var reference = new Reference { Uri = "" };
var env = new XmlDsigEnvelopedSignatureTransform();
reference.AddTransform(env);
signedXml.AddReference(reference);
signedXml.ComputeSignature(signerProvider);
var xmlDigitalSignature = signedXml.GetXml();
xmlDoc.DocumentElement.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, true));
}

并用此代码进行验证

        public static bool Verify(XmlDocument document, X509Certificate2 certificate)
{
// Check arguments.
if (document == null)
throw new ArgumentException("Doc");
if (certificate == null)
throw new ArgumentException("Key");

// Create a new SignedXml object and pass it
// the XML document class.
var signedXml = new SignedXml(document);

// Find the "Signature" node and create a new
// XmlNodeList object.
var nodeList = document.GetElementsByTagName("Signature");

// Throw an exception if no signature was found.
if (nodeList.Count <= 0)
{
throw new CryptographicException("Verification failed: No Signature was found in the document.");
}

// This example only supports one signature for
// the entire XML document. Throw an exception
// if more than one signature was found.
if (nodeList.Count >= 2)
{
throw new CryptographicException("Verification failed: More that one signature was found for the document.");
}

// Load the first <signature> node.
signedXml.LoadXml((XmlElement)nodeList[0]);

return signedXml.CheckSignature(certificate, true);
}

关于c# - 如何将 HSM 中存储的私钥转换为 C# 中的 SignedXml.SigningKey,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46440422/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com