I am trying to perform 3 types of digital signature (SHA256) at once, XML, PDF and Text using smart card device. All signatures are working perfectly, but problem is, it is asking for PIN when each signing takes place, but I need it to be asked only once. Can anybody suggest a better way for achieving the result?
What I am trying to implement is,
Ask pin -> Sign XML -> Sign PDF -> Sign TEXT
What was happening is,
Ask pin -> Sign XML -> Ask pin -> Sign PDF -> Ask pin -> Sign TEXT
Then I created a common cmssiger
object for PDF and TEXT signing.
Now what happening is,
Ask pin -> Sign XML -> Ask pin -> Sign PDF -> Sign TEXT
I hope everyone understood what I am saying.
Code for each signing process is as follows, XML
XAdESSignedXml signer = new XAdESSignedXml(toSign);
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa = cert.PrivateKey as RSACryptoServiceProvider;
signer.SigningKey = rsa;
/*.......Elements attached......*/
signer.ComputeSignature();
private byte[] SignMsg(Byte[] msg, bool detached)
{
ContentInfo contentInfo = new ContentInfo(msg);
SignedCms signedCms = new SignedCms(contentInfo, detached);
_cmsSigner.IncludeOption = X509IncludeOption.EndCertOnly;//common cmssigner object
_cmsSigner.DigestAlgorithm.FriendlyName = "SHA256";
signedCms.ComputeSignature(_cmsSigner, false);
byte[] bb = signedCms.Encode();
CmsSignedData sd = new CmsSignedData(bb);
SignerInformationStore signers = sd.GetSignerInfos();
byte[] signature = null;
SignerInformation signer = null;
foreach (SignerInformation signer_ in signers.GetSigners())
{
signer = signer_;
break;
}
signature = signer.GetSignature();
signer = SignerInformation.ReplaceUnsignedAttributes(signer, null);
IList signerInfos = new ArrayList();
signerInfos.Add(signer);
sd = CmsSignedData.ReplaceSigners(sd, new SignerInformationStore(signerInfos));
bb = sd.GetEncoded();
return bb;
}
TEXT
public static string Sign(string msg, CmsSigner cmsSigner) //common cmssigner object
{
SHA256Managed crypt = new SHA256Managed();
string hash = String.Empty;
byte[] crypto = crypt.ComputeHash(Encoding.UTF8.GetBytes(msg), 0, Encoding.UTF8.GetByteCount(msg));
foreach (byte theByte in crypto)
{
hash += theByte.ToString("x2");
}
ContentInfo contentInfo = new ContentInfo(Encoding.UTF8.GetBytes(hash));
SignedCms cms = new SignedCms(contentInfo);
cmsSigner.IncludeOption = X509IncludeOption.EndCertOnly;
cmsSigner.DigestAlgorithm.FriendlyName = "SHA256";
cms.ComputeSignature(cmsSigner, false);
return Convert.ToBase64String(cms.Encode());
}
Thanks in advance.
Pin prompt behavior is a provider specific implementation detail. In other words, one cryptographic service provider / key storage provider will behave one way while another will behave another.
To reduce chances of pin prompting you will want to use one session for all operations, it sounds like you are doing that though so were back to the provider-specific behavior.
In the case of RSACryptoServiceProvider a key can be generated and stored in such a way it enforces an on-use pin prompt policy. This is really the only pin prompt behavior it exposes, as such your stuck with the observed behavior with such keys.