0

I am new in cryptographic programming. I want to create only digital signature in C# with CAdES format using Pkcs11Interop library without having data or document or message to sign, I want the signature string only to use it on any json or xml file generated from my application. I used Pkcs11Interop library because I have a smart token "Cryptoki" with unmanaged PKCS#11 dll library which I have to use to make the signature. Here is my sample code based on Pkcs11Interop open source samples.

using System;
using System.Collections.Generic;
using Net.Pkcs11Interop.Common;
using Net.Pkcs11Interop.HighLevelAPI;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            Pkcs11InteropFactories factories = new Pkcs11InteropFactories();

            using (IPkcs11Library pkcs11Library = factories.Pkcs11LibraryFactory.LoadPkcs11Library(factories, @"C:\eps2003csp11.dll", AppType.MultiThreaded))
            {
                ILibraryInfo libraryInfo = pkcs11Library.GetInfo();

                foreach (ISlot slot in pkcs11Library.GetSlotList(SlotsType.WithOrWithoutTokenPresent))
                {
                    ISlotInfo slotInfo = slot.GetSlotInfo();

                    if (slotInfo.SlotFlags.TokenPresent)
                    {
                        using (ISession session = slot.OpenSession(SessionType.ReadWrite))
                        {
                            session.Login(CKU.CKU_USER, @"000000");

                            IObjectHandle publicKey = null;
                            IObjectHandle privateKey = null;
                            GenerateKeyPair(session, out publicKey, out privateKey);

                            IMechanism mechanism = session.Factories.MechanismFactory.Create(CKM.CKM_CMS_SIG);

                            byte[] sourceData = ConvertUtils.Utf8StringToBytes(null);

                            byte[] signature = session.Sign(mechanism, privateKey, sourceData);

                            string vStringSignature = ConvertUtils.BytesToBase64String(signature);
                            Console.WriteLine("Signature:  " + vStringSignature);
                                                        
                            session.DestroyObject(privateKey);
                            session.DestroyObject(publicKey);
                            session.Logout();
                        }
                    }
                }
            }
            
        }
        static void GenerateKeyPair(ISession session, out IObjectHandle publicKeyHandle, out IObjectHandle privateKeyHandle)
        {
            // The CKA_ID attribute is intended as a means of distinguishing multiple key pairs held by the same subject
            byte[] ckaId = session.GenerateRandom(20);

            // Prepare attribute template of new public key
            List<IObjectAttribute> publicKeyAttributes = new List<IObjectAttribute>();
            publicKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_TOKEN, true));
            publicKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_PRIVATE, false));
            publicKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_LABEL, "Digital Business ERP"));
            publicKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_ID, ckaId));
            publicKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_ENCRYPT, true));
            publicKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_VERIFY, true));
            publicKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_VERIFY_RECOVER, true));
            publicKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_WRAP, true));
            publicKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_MODULUS_BITS, 1024));
            publicKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_PUBLIC_EXPONENT, new byte[] { 0x01, 0x00, 0x01 }));

            // Prepare attribute template of new private key
            List<IObjectAttribute> privateKeyAttributes = new List<IObjectAttribute>();
            privateKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_TOKEN, true));
            privateKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_PRIVATE, true));
            privateKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_LABEL, "Digital Business ERP"));
            privateKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_ID, ckaId));
            privateKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_SENSITIVE, true));
            privateKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_DECRYPT, true));
            privateKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_SIGN, true));
            privateKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_SIGN_RECOVER, true));
            privateKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_UNWRAP, true));

            // Specify key generation mechanism
            IMechanism mechanism = session.Factories.MechanismFactory.Create(CKM.CKM_RSA_PKCS_KEY_PAIR_GEN);

            // Generate key pair
            session.GenerateKeyPair(mechanism, publicKeyAttributes, privateKeyAttributes, out publicKeyHandle, out privateKeyHandle);
        }
    }
}

If I put "null" or empty double quotes in the following sourceData variable

byte[] sourceData = ConvertUtils.Utf8StringToBytes(null);

or

byte[] sourceData = ConvertUtils.Utf8StringToBytes("");

I get error in creating signature like this

byte[] signature = session.Sign(mechanism, privateKey, sourceData);

or

byte[] signature = session.Sign(mechanism, privateKey, null);

Only when I put sample data like "Hello World" the signature string is generated successfully but it containes data string which is "Hello World" in this sample.

I want to generate signature string without any data contained, Also in my code I don't know how to set signature format to CAdES.

  • I sound like you want to create a template without the actual signature. The certificate is Xml so you want to add a xml tag and not put anything in the innertext. So you do not need to run the sign method. Just add the tag to the xml document. – jdweng Nov 04 '20 at 15:09
  • Yes you got it right, I want a signature template by my HSM token to add to xml tag or json element later when needed. – Tarek Helmy Nov 04 '20 at 15:30
  • Where is your Xml Document or string you want the tag added? I've done this lots of times. See my answer at following posting : https://stackoverflow.com/questions/46722997/saml-assertion-in-a-xml-using-c-sharp/46724392 – jdweng Nov 04 '20 at 15:39
  • Your answer in that link is for Xml documents only, what about json document. That is why I want signature template as string to add it to any file i want. – Tarek Helmy Nov 04 '20 at 15:52
  • Certificates are XML format and signing is XML. Never seen JSON signatures. – jdweng Nov 04 '20 at 18:52
  • In my case I have to use XML and JSON files to integrate and exchange data between my application and online APIs where signature must be attached as string in a tag inside files. – Tarek Helmy Nov 04 '20 at 20:26
  • If you look at SOAP (my link) an Xml format it is part of a http request. JSON is a scripting language that produces http. The json can be in a file or part of your application. In your case to are sending a certificate (xml) inside a http request/response. – jdweng Nov 04 '20 at 21:06
  • FYI, we have added Digital Signature as per Egypt ITIDA CAdES-BES standard to [Signer.Digital](https://signer.digital) offerings – Bharat Vasant Jul 08 '22 at 10:24

1 Answers1

-1

Tarek

I'm also struggling with the same issue, trying to produce a cades-bes signature on a json document and attach it to the original json document as a property.

This is as part of Egyptian tax authority rules for submitting signed invoices using their Api.

I tried the CMS classes of. Net core, and managed to produce the signature of the document, but the Api refuses my document, and I get a response of 400 "Bad request".

If you managed in your eduvor, please add the solution here.

  • This does not really answer the question. If you have a different question, you can ask it by clicking [Ask Question](https://stackoverflow.com/questions/ask). To get notified when this question gets new answers, you can [follow this question](https://meta.stackexchange.com/q/345661). Once you have enough [reputation](https://stackoverflow.com/help/whats-reputation), you can also [add a bounty](https://stackoverflow.com/help/privileges/set-bounties) to draw more attention to this question. - [From Review](/review/late-answers/29790891) – Paulo Sep 10 '21 at 12:33
  • FYI, we have added Digital Signature as per Egypt ITIDA CAdES-BES standard to [Signer.Digital](https://signer.digital/) offerings – Bharat Vasant Jul 08 '22 at 10:26