I have tried to write some program to sign PDF document with the certificate inside the HSM.
1. First, I have used this for reference: https://www.pkcs11interop.net/extensions/pdf/_pkcs11_rsa_signature_example_8cs-example.html
And It works perfectly. The signature is valid.
2. I have used this for reference of my program: https://sourceforge.net/p/itextsharp/code/HEAD/tree/tutorial/signatures/chapter4/C4_03_SignWithPKCS11SC/C4_03_SignWithPKCS11SC.cs#l11
And here is my code
namespace SignWithPKCS11
{
class CryptokiPrivateKeySignature : IExternalSignature
{
private readonly Session session;
ObjectHandle privateKey;
public CryptokiPrivateKeySignature(Session session, String alias)
{
this.session = session;
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> foundPrivateKey = session.FindAllObjects(template);
privateKey = foundPrivateKey[0];
}
public String GetHashAlgorithm()
{
return "SHA1";
}
public String GetEncryptionAlgorithm()
{
return "RSA";
}
public byte[] Sign(byte[] message)
{
using (Mechanism mechanism = new Mechanism(CKM.CKM_RSA_PKCS))
{
return session.Sign(mechanism, privateKey, message);
}
}
}
class Program
{
public const String SRC = @"D:\Hello.pdf";
public const String DEST = @"D:\Hello-signedv2.pdf";
public void Sign(String src, String dest, ICollection<X509Certificate> chain, Session session, String alias,
String digestAlgorithm, CryptoStandard subfilter, String reason, String location,
ICollection<ICrlClient> crlList, IOcspClient ocspClient, ITSAClient tsaClient, int estimatedSize)
{
PdfReader reader = null;
PdfStamper stamper = null;
FileStream os = null;
try
{
reader = new PdfReader(src);
os = new FileStream(dest, FileMode.Create);
stamper = PdfStamper.CreateSignature(reader, os, '\0');
PdfSignatureAppearance appearance = stamper.SignatureAppearance;
appearance.Reason = reason;
appearance.Location = location;
appearance.SetVisibleSignature(new Rectangle(36, 748, 144, 780), 1, "sig");
IExternalSignature pks = new CryptokiPrivateKeySignature(session, alias);
MakeSignature.SignDetached(appearance, pks, chain, crlList, ocspClient, tsaClient, estimatedSize, subfilter);
}
finally
{
if (reader != null)
reader.Close();
if (stamper != null)
stamper.Close();
if (os != null)
os.Close();
}
}
static void Main(string[] args)
{
LoggerFactory.GetInstance().SetLogger(new SysoLogger());
string libraryPath = @"C:\Program Files\SafeNet\Protect Toolkit 5\Protect Toolkit C SDK\bin\sw\cryptoki.dll";
String pin = @"1111";
Pkcs11 cryptoki = new Pkcs11(libraryPath, true);
List<Slot> slots = cryptoki.GetSlotList(true);
Slot usableSlot = slots[0];
Session session = usableSlot.OpenSession(false);
session.Login(CKU.CKU_USER, pin);
HsmSign(session, "mycert");
session.Logout();
usableSlot.CloseSession(session);
cryptoki.Dispose();
}
public static void HsmSign(Session session, String alias)
{
List<ObjectAttribute> template = new List<ObjectAttribute>();
template.Add(new ObjectAttribute(CKA.CKA_CLASS,CKO.CKO_CERTIFICATE));
template.Add(new ObjectAttribute(CKA.CKA_CERTIFICATE_TYPE, CKC.CKC_X_509));
template.Add(new ObjectAttribute(CKA.CKA_LABEL, alias));
List<ObjectHandle> foundNCert = session.FindAllObjects(template);
List<CKA> attributes = new List<CKA>();
attributes.Add(CKA.CKA_VALUE);
List<ObjectAttribute> certificateAttribute = session.GetAttributeValue(foundNCert[0], attributes);
byte[] nCert = certificateAttribute[0].GetValueAsByteArray();
X509Certificate2 cert = CertUtils.ToDotNetObject(nCert);
ICollection<X509Certificate> chain = new List<X509Certificate>();
X509Chain x509Chain = new X509Chain();
x509Chain.Build(cert);
foreach (X509ChainElement x509ChainElement in x509Chain.ChainElements)
{
chain.Add(DotNetUtilities.FromX509Certificate(x509ChainElement.Certificate));
}
IOcspClient ocspClient = new OcspClientBouncyCastle();
List<ICrlClient> crlList = new List<ICrlClient>();
crlList.Add(new CrlClientOnline(chain));
Program app = new Program();
app.Sign(SRC, String.Format(DEST, alias), chain, session, alias, DigestAlgorithms.SHA256, CryptoStandard.CMS, "Test", "Greenwich", crlList, ocspClient, null, 0);
}
}
}
This code ran perfectly. But at last, the signature is invalid.
And here are the reason from Adobe Acrobat Reader:
1) There are errors in the formatting or information contained in this signature.
2) Signer's identity has not yet been verified.
3) Signing time is from the clock on the signer's computer.
If you want more information please tell me.
Please help and thanks in advance.
Hi Everyone,
I have found the root of the problem.
In the following line:
using (Mechanism mechanism = new Mechanism(CKM.CKM_RSA_PKCS))
{
return session.Sign(mechanism, privateKey, message);
}
I think I have used the wrong mechanism and then the signature invalid at last.
When I changed to CKM.CKM_SHA1_RSA_PKCS then it works. The signature is valid.