How to create a digital signing solution with only JavaScript

Look at the js-signer project on GitHub

Go to the new version of this blog post

It is sometimes required to have the user sign a text in order to certify that he is the one who has done the operation. For example, in an e-banking software, the user might have to sign a text describing the transaction (“Transfer 300 dollars to IBAN xxxxxxxxx”), or sign a request for a governmental eService. This could be achieved by a java-applet, but as JRE owners are not a majority, it is preferable to use other ways.

Of course, the preconditions are, that the user has a digital signature, issued by a CA, and has followed the CA’s manual for installing the certificate in a browser. If these steps are not completed successfully, the solution below wouldn’t work.

Also, note that this uses PKCS7 (java developers: use bouncy castle to verify it), instead of the XAdES standard. Internet Explorer has support for XAdES, but FireFox doesn’t.

Let’s see a simple HTML page that should sign a given text:


<script src="sign.js" type="text/javascript"></script>

<input id="text" type="text" />
<input onclick="signDigest(document.getElementById('text').value);" type="button" value="Sign" />

and then the JavaScript itself:


function signDigest(text)
{
if(window.event)
window.event.cancelBubble = true;

var dest = sign(text); //TODO
alert(dest);
return dest;
}

// CAPICOM constants
var CAPICOM_STORE_OPEN_READ_ONLY = 0;
var CAPICOM_CURRENT_USER_STORE = 2;
var CAPICOM_CERTIFICATE_FIND_SHA1_HASH = 0;
var CAPICOM_CERTIFICATE_FIND_EXTENDED_PROPERTY = 6;
var CAPICOM_CERTIFICATE_FIND_TIME_VALID = 9;
var CAPICOM_CERTIFICATE_FIND_KEY_USAGE = 12;
var CAPICOM_DIGITAL_SIGNATURE_KEY_USAGE = 0x00000080;
var CAPICOM_AUTHENTICATED_ATTRIBUTE_SIGNING_TIME = 0;
var CAPICOM_INFO_SUBJECT_SIMPLE_NAME = 0;
var CAPICOM_ENCODE_BASE64 = 0;
var CAPICOM_E_CANCELLED = -2138568446;
var CERT_KEY_SPEC_PROP_ID = 6;

function IsCAPICOMInstalled()
{
if(typeof(oCAPICOM) == "object")
{
if( (oCAPICOM.object != null) )
{
// We found CAPICOM!
return true;
}
}
}

function FindCertificateByHash()
{

try
{
// instantiate the CAPICOM objects
var MyStore = new ActiveXObject("CAPICOM.Store");
// open the current users personal certificate store
MyStore.Open(CAPICOM_CURRENT_USER_STORE, "My", CAPICOM_STORE_OPEN_READ_ONLY);

// find all of the certificates that have the specified hash
var FilteredCertificates = MyStore.Certificates.Find(CAPICOM_CERTIFICATE_FIND_SHA1_HASH, strUserCertigicateThumbprint);

var Signer = new ActiveXObject("CAPICOM.Signer");
Signer.Certificate = FilteredCertificates.Item(1);
return Signer;

// Clean Up
MyStore = null;
FilteredCertificates = null;
}
catch (e)
{
if (e.number != CAPICOM_E_CANCELLED)
{
return new ActiveXObject("CAPICOM.Signer");
}
}
}

function sign(src)
{
if(window.crypto &amp;&amp; window.crypto.signText)
return sign_NS(src);

return sign_IE(src);
}

function sign_NS(src)
{
var s = crypto.signText(src, "ask" );
return s;
}

function sign_IE(src)
{
try
{
// instantiate the CAPICOM objects
var SignedData = new ActiveXObject("CAPICOM.SignedData");
var TimeAttribute = new ActiveXObject("CAPICOM.Attribute");

// Set the data that we want to sign
SignedData.Content = src;
var Signer = FindCertificateByHash();

// Set the time in which we are applying the signature
var Today = new Date();
TimeAttribute.Name = CAPICOM_AUTHENTICATED_ATTRIBUTE_SIGNING_TIME;
TimeAttribute.Value = Today.getVarDate();
Today = null;
Signer.AuthenticatedAttributes.Add(TimeAttribute);

// Do the Sign operation
var szSignature = SignedData.Sign(Signer, true, CAPICOM_ENCODE_BASE64);
return szSignature;
}
catch (e)
{
if (e.number != CAPICOM_E_CANCELLED)
{
alert("An error occurred when attempting to sign the content, the errot was: " + e.description);
}
}
return "";
}

And that should do the stuff – the signed text can be sent to the server, where it can be verified (in case, of course, the server has the public part of the user’s certificate)

P.S. One important note when verifying afterward – Internet Explorer uses UnicodeLittleUnmarked (UTF-16LE) to encode the signed data, before signing it. So when verifying, use this encoding.

About these ads

52 Responses to “How to create a digital signing solution with only JavaScript”

  1. EllisGL Says:

    Can we see a demo of this?

  2. bozhobg Says:

    Well, it’s pretty much all in the code above – just copy-paste it in an .html file and you have the demo. But have in mind that you must have a real signature, otherwise browsers give errors.

  3. Kristof Says:

    IE gives this error: “An error occurred when attempting to sign the content, the error was: Automation server can’t create object”

    Ever seen such? :)

  4. Bozho Says:

    Yes. In order to sign successfully (with both IE and Firefox) you need a installed smart card with the digital signature. Self-signed certificates can’t be used with the browsers to sign content. (don’t ask me why :) )

  5. B J Says:

    Hi, this jscript is encrypting some given text “Hello” using CAPICOM sertificate?? Ok, so if this is true i would like to get public Key from sertificate, and later use this public key to verify authetntication of used sertificate for encryption(i will encrypt the same text “Hello” but this time with public key and compare both encriptions). Is there any chance for that???

    Thanks

  6. Bozho Says:

    I didn’t quite get your idea, but getting the public key from the encrypted message will be a server-side action, about which I will blog tomorrow (stay tuned). Then you can use it in whatever way you need.

  7. How to obtain signer’s details from a JavaScript signed data « Bozho’s Weblog Says:

    [...] to obtain signer’s details from a JavaScript signed data By bozhobg In a previous post I described how to sign data with only javascript. Now, this data should be used on the server side [...]

  8. bozhobg Says:

    Check this out – http://bozhobg.wordpress.com/2009/07/02/how-to-obtain-signers-details-from-a-javascript-signed-data/

  9. B J Says:

    Hi,

    Thanks for your quick replay. My question was how to get public key from CAPICOM certificate.Later use that key to decrypt signed(encrypted) text, and make comparison between original and decrypted text, wich should have some function like verification.

    P.S is there any chance to convert your Java code from your newest blog to C#?

    Thanks

  10. bozhobg Says:

    Well, I don’t have enough experience with C# to be able to do so – furthermore, I’m not even sure bouncy castle have C# libraries, so you have to ‘translate’ it yourself, and find the appropriate libraries :)

  11. B J Says:

    hi me again :)

    I can’t understand why on some PCs i am able to get Certificate and sign text and on the other PCs i am get error (Error in reading DLL)????

    when i was Debuging I found that this error occurs in the next two lines.

    var SignedData = new ActiveXObject(“CAPICOM.SignedData”);
    var TimeAttribute = new ActiveXObject(“CAPICOM.Attribute”);

    Thanks for your time and previous responses.

  12. B J Says:

    I forget to say that all PCs in my network have certificate by same Issuer.

  13. Bozho Says:

    Hm, that would probably be due to unsuccessfully installed smart-card software (Charismatics, for instance). Check the installation procedure from the signature vendor.

  14. B J Says:

    Thanks i instaled CAPICOM on all PC’s where i was not able to get theirs certificate, and that solves my problem, now it’s working exelent.
    Thanks again for your help.

  15. Sushil Says:

    This is good but i need only Secure email signature from etoken can u tell me the javascript code for that

  16. Bozho Says:

    Whether it is SmartCard, eToken or self-signed certificate , it doesn’t matter, as long as the browser is set-up to locate them.

  17. Ramba Says:

    Hi.

    Thanks for this valuable article.I wanted to know the signed output length of your code.I am getting morethen 3000 char ,even for a 15 char input.

    Thanks and regards..

    Ramba

  18. Bozho Says:

    Yes, this is normal. The whole certificate data is encoded in base64, so it’s fine.

    • Nitin Nanivadekar Says:

      Hi,
      Can we extract certificate data from the base-64 so that we get the signature only ?
      I believe the signature is 172 characters (base-64).
      Please relate this post to my earlier reply.
      How can we locally verify the signature?

  19. Ramba Says:

    Thank you for your response.I wanted to convert this output into pdf417 barcode ,2D. Pdf417 is supproting upto 1800 ascii character only.

    Is there any way to compress the output to reduce the number of characters?.Or please suggest alternate for capicom ,to sign at client side.

    Thanks and Regards.
    Ramba.

  20. Bozho Says:

    What information should the barcode contain?
    You can extract whichever part of the PKCS7 you wish – check this post: http://bozhobg.wordpress.com/2009/07/02/how-to-obtain-signers-details-from-a-javascript-signed-data/

  21. Ramba Says:

    Thank you for your reply.

    The barcode should contain the signature.ie SignedData.Sign methods output.I am implementing in asp.net application.The content of the barcode should be used for signature verification in future.

    Regards

    Ramba

  22. Bozho Says:

    Well, then extract the publicKey and put it in the barcode. Should suffice.
    But the PKCS7 contains much more information, hence the big size.

  23. Ramba Says:

    Thank you,

    I will do in that way.

    Regards,

    Ramba

  24. Ramba Says:

    Thank You,

    I will do based on your suggession..

    Regards,

    Ramba

  25. Sushil Agrawal Says:

    Thanks you for Reply
    I created code for reading etoken code is working fine on local host but when i access page from IIS this is not working What i have to do for that.

  26. mirza Says:

    “Whether it is SmartCard, eToken or self-signed certificate , it doesn’t matter, as long as the browser is set-up to locate them.”
    How to set upi IE to locate SmartCard so that user can enter pin and then use cert in this js

  27. bozhobg Says:

    It depends on the smart card software. It should include detailed manual on how to enable it on each browser.

  28. 使用CAPICOM实现证书管理 | 出家如初,成佛有余 Says:

    [...] How to create a digital signing solution with only JavaScript [...]

  29. How to obtain signer’s details from a JavaScript signed data « Bozho's tech blog Says:

    [...] a previous post I described how to sign data with only javascript. Now, this data should be used on the server side [...]

    • Dhirendra Says:

      Hi,

      I am using this code and this is running perfectly.

      This is the small piece of code from yr post.

      var Signer = new ActiveXObject(“CAPICOM.Signer”);

      Signer.Certificate = FilteredCertificates.Item(1);

      return Signer;

      While the execution of Signer.Certificate = FilteredCertificates.Item(1); code i am getting exception ,so instead of taking certificate at location 1 this opens the certificate store to choose the certificate which is not my requirement.
      Plz help i have to filter certificate without giving the selection of the same to user.

  30. Nitin Nanivadekar Says:

    bozhobg,
    Hi.
    I tried this code and works perfectly. I was searching for the same results and the code looks great.
    The problem is the signer.sign result. The signature happens to be @ 2292 bytes. I think it is too long. We are used to hash the data with SHA1 (40 bytes) and sign with RSA 1024 key. The resulting signature is 128 bytes (172 after BASE64).
    Can you please tell me how to resolve this issue so that the sign is 172 bytes long (BASE-64). This is the only thing that is holding us to use the code.
    Thank you for this awesome post.

  31. Dhirendra Says:

    // find all of the certificates that have the specified hash

    048 var FilteredCertificates = MyStore.Certificates.Find(CAPICOM_CERTIFICATE_FIND_SHA1_HASH, strUserCertigicateThumbprint);

    Hi,

    I am using this code and this is running perfectly.

    This is the small piece of code from yr post.

    var Signer = new ActiveXObject(“CAPICOM.Signer”);

    Signer.Certificate = FilteredCertificates.Item(1);

    return Signer;

    While the execution of Signer.Certificate = FilteredCertificates.Item(1); code i am getting exception ,so instead of taking certificate at location 1 this opens the certificate store to choose the certificate which is not my requirement.
    Plz help i have to filter certificate without giving the selection of the same to user.

  32. 使用CAPICOM实现证书管理 « 出家如初,成佛有余 Says:

    [...] How to create a digital signing solution with only JavaScript [...]

  33. Romani Says:

    Is crypto.signText returns the actual data and certificate?
    i.e.
    1) text passed for digital signing
    2) certificate

    if yes, then can you tell me how to get the actual data from encoded string?

  34. bozhobg Says:

    @Romani, sorry but I completely forgot, it was quite some time ago, and now I don’t even have that project in my workspace :) Try checking some documentation, or simply experiment and let us know the result. If you do so, do it on http://techblog.bozho.net – it’s where the blog now resides. thanks.

  35. George Hernando Says:

    This looks great, but will it only work in FireFox and IE?
    I don’t see anything in Chrome for example to support crypto.signText

    Thanks

  36. sushil Says:

    How i use it for FireFox

  37. Olivenöl Says:

    Weekly Post…

    [...]when you would like to read a little way more then I advise the following[...]…

  38. sena reddy Says:

    could you please tell me how to get thumbprint value from certificate in java script.

    thank you …….

  39. Odpryski na temat podpisywania PDF « Wiadomości o technologiach IT Says:

    [...] dokumentu w przeglądarce po stronie klienta – http://bozhobg.wordpress.com/2009/04/16/how-to-create-a-digital-signing-solution-with-only-javascrip… Share this:ShareFacebookTwitterRedditStumbleUponDiggDodaj do ulubionych:LubięBądź pierwszą [...]

  40. gamekeys Says:

    gamekeys…

    [...]How to create a digital signing solution with only JavaScript « Bozho’s Weblog[...]…

  41. Fernando Says:

    hello , i am getting this error in IE9 “The Signer object has not been properly initialized” , i just copy and paste the code , whay i could be ? Thank you!

  42. src belgesi Says:

    Öncelikle yazınız için teşekkür.ederiz. Böyle yazıların bilgilendirici nitelikte olduğunu düşünüyoruz. Tekrar teşekkürler.

  43. Geri Valentine Says:

    Need to learn how to set all my functions to us my phone properly.Thanksfor the help.

  44. swili Says:

    In IE11 get:

    “Internet Explorer Has stopped working – Windows is checking for a solution to the problem.”

    Please help!

    thanx

  45. Parvez Says:

    Hello Dear,

    I want to attached digital certificate with my web page.
    but don’t find anything. I need to decrypt that certificate from token USB device and have to attached with my webpage.

    I had also saw one application which is in ASP.NET where One popup window that come from click on one button called “Select Certificate” but doesnt able to make it in php

    Your Above explain concept I have read properly but it doesnt work when I copy and paste in html.

    Want to ask that CAPICOM library will be a file or it will automatically get its function.

    Please help me here. I had make full R N D in that but didnt find any thing.

  46. Rahul Says:

    Good Work..it is working great for 32 bit .. now i follow process for 64 bit …it gives error i.e automated server can’t create object… please Resolve my Problem

  47. how-to-create-a-digital-signing-solution-with-only-javascript/ | epodsetnik Says:

    […] http://bozhobg.wordpress.com/2009/04/16/how-to-create-a-digital-signing-solution-with-only-javascrip&#8230; […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


Follow

Get every new post delivered to your Inbox.

%d bloggers like this: