如何使用C#从安全令牌中获取信息。

11
我需要让我的应用程序用户使用个人USB安全令牌签署他们的批准文件。
我已经成功签署了数据,但是我无法获取使用哪个令牌进行签署的信息。
以下是我目前的代码:
CspParameters csp = new CspParameters(1, "SafeNet RSA CSP");
csp.Flags = CspProviderFlags.UseDefaultKeyContainer;            
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(csp);
// Create some data to sign. 
byte[] data = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 };
Console.WriteLine("Data         : " + BitConverter.ToString(data));
// Sign the data using the Smart Card CryptoGraphic Provider.            
byte[] sig = rsa.SignData(data, "SHA1");            
Console.WriteLine("Signature    : " + BitConverter.ToString(sig));

在令牌的信息中有一个称为“令牌名称”的字段。我如何访问该字段以验证使用了哪个令牌来签署批准?

enter image description here

附加信息和更新:

  • "Token name" 始终与所有者的姓名匹配(拥有 USB 令牌的用户)
  • 看起来无法完成,可能需要调用网络服务或其他方式直接从证书授权机构获取信息。

这可能更适合在 security.stackexchange.com 上提问? - MiMo
看起来你需要提取一个模数作为证书指纹,然后与所有可用证书的指纹数据库进行比较。可能是类似于byte[] modulus = rsa.ExportParameters(false).Modulus;这样的东西。 - oleksii
@oleksii 我没有模数数据库。我需要获取“令牌名称”并将其与当前的AD用户名进行比较。感谢您的评论。 - daniloquio
1
Token Name是硬件独有的还是标准的一部分?很可能它以一种无法通过标准库获取的方式存储。 - Bobson
@daniloquio - “标准”与“一个标准”是不同的。它可能是SafeNet独有的(但以标准方式设置),在这种情况下,.NET无法知道它。或者它可能是RSA标准的一部分,在这种情况下应该有某种方法可以访问它。我猜是前者。 - Bobson
显示剩余3条评论
1个回答

8
当我最初提出问题时,我对数字证书的理解非常基础,所以问题没有得到恰当的提问。现在我明白我需要从智能卡设备中访问证书,查询其属性并测试用户是否能够输入正确的PIN码。
以下是我使用的代码:
//Prompt the user with the list of certificates on the local store.
//The user have to select the certificate he wants to use for signing.
//Note: All certificates form the USB device are automatically copied to the local store as soon the device is plugged in.
X509Store store = new X509Store(StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
X509CertificateCollection certificates = X509Certificate2UI.SelectFromCollection(store.Certificates,
                                                                                "Certificados conocidos",
                                                                                "Por favor seleccione el certificado con el cual desea firmar",
                                                                                X509SelectionFlag.SingleSelection
                                                                                );
store.Close();
X509Certificate2 certificate = null;
if (certificates.Count != 0)
{
    //The selected certificate
    certificate = (X509Certificate2)certificates[0];
}
else
{
    //The user didn't select a certificate
    return "El usuario canceló la selección de un certificado";
}
//Check certificate's atributes to identify the type of certificate (censored)
if (certificate.Issuer != "CN=............................., OU=................., O=..., C=US")
{
    //The selected certificate is not of the needed type
    return "El certificado seleccionado no corresponde a un token ...";
}
//Check if the certificate is issued to the current user
if (!certificate.Subject.ToUpper().Contains(("E=" + pUserADLogin + "@censoreddomain.com").ToUpper()))
{
    return "El certificado seleccionado no corresponde al usuario actual";
}
//Check if the token is currently plugged in
XmlDocument xmlDoc = new XmlDocument();
XmlElement element = xmlDoc.CreateElement("Content", SignedXml.XmlDsigNamespaceUrl.ToString());
element.InnerText = "comodin";
xmlDoc.AppendChild(element);
SignedXml signedXml = new SignedXml();
try
{
    signedXml.SigningKey = certificate.PrivateKey;
}
catch
{
    //USB Token is not plugged in
    return "El token no se encuentra conectado al equipo";
}
DataObject dataObject = new DataObject();
dataObject.Data = xmlDoc.ChildNodes;
dataObject.Id = "CONTENT";
signedXml.AddObject(dataObject);
Reference reference = new Reference();
reference.Uri = "#CONTENT";
signedXml.AddReference(reference);
//Attempt to sign the data. The user will be prompted to enter his PIN
try
{
    signedXml.ComputeSignature();
}
catch
{
    //User didn't enter the correct PIN
    return "Hubo un error confirmando la identidad del usuario";
}
//The user has signed with the correct token
return String.Format("El usuario {0} ha firmado exitosamente usando el token con serial {1}", pUserADLogin, certificate.SerialNumber);

来源:

http://stormimon.developpez.com/dotnet/signature-electronique/(法语) https://www.simple-talk.com/content/print.aspx?article=1713(英语)

(说明:此文涉及IT技术,介绍了电子签名的相关内容。)

有一种替代方法可以获取令牌名称。您将需要使用PKCS#11或CryptoAPI接口来检测已插入哪个令牌。这与您基于证书主题名称检测令牌名称的方法不同。 - Raj

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接