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 && 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.
May 3, 2009 at 3:34 am |
Can we see a demo of this?
May 3, 2009 at 6:53 am |
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.
June 26, 2009 at 2:10 pm |
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?
June 27, 2009 at 6:56 am |
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
)
June 30, 2009 at 7:35 am |
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
July 1, 2009 at 8:17 pm |
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.
July 2, 2009 at 9:23 am |
[...] 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 [...]
July 2, 2009 at 9:25 am |
Check this out – http://bozhobg.wordpress.com/2009/07/02/how-to-obtain-signers-details-from-a-javascript-signed-data/
July 3, 2009 at 10:37 am |
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
July 3, 2009 at 12:35 pm |
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
July 10, 2009 at 12:15 pm |
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.
July 10, 2009 at 12:20 pm |
I forget to say that all PCs in my network have certificate by same Issuer.
July 10, 2009 at 4:28 pm |
Hm, that would probably be due to unsuccessfully installed smart-card software (Charismatics, for instance). Check the installation procedure from the signature vendor.
July 14, 2009 at 8:10 am |
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.
November 4, 2009 at 7:51 am |
This is good but i need only Secure email signature from etoken can u tell me the javascript code for that
November 4, 2009 at 2:51 pm |
Whether it is SmartCard, eToken or self-signed certificate , it doesn’t matter, as long as the browser is set-up to locate them.
November 11, 2009 at 10:45 am |
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
November 11, 2009 at 11:40 am |
Yes, this is normal. The whole certificate data is encoded in base64, so it’s fine.
May 14, 2010 at 6:57 am |
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?
November 12, 2009 at 4:48 am |
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.
November 12, 2009 at 9:22 am |
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/
November 13, 2009 at 4:57 am |
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
November 13, 2009 at 6:31 am |
Well, then extract the publicKey and put it in the barcode. Should suffice.
But the PKCS7 contains much more information, hence the big size.
November 16, 2009 at 11:55 am |
Thank you,
I will do in that way.
Regards,
Ramba
November 16, 2009 at 11:57 am |
Thank You,
I will do based on your suggession..
Regards,
Ramba
November 20, 2009 at 9:27 am |
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.
May 4, 2011 at 6:16 am |
this code is not working in firefox
January 21, 2010 at 10:55 am |
“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
January 21, 2010 at 4:58 pm |
It depends on the smart card software. It should include detailed manual on how to enable it on each browser.
February 15, 2010 at 4:54 pm |
[...] How to create a digital signing solution with only JavaScript [...]
March 29, 2010 at 6:10 pm |
[...] a previous post I described how to sign data with only javascript. Now, this data should be used on the server side [...]
June 2, 2010 at 10:27 am |
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.
May 14, 2010 at 6:46 am |
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.
May 14, 2010 at 6:53 am |
Could you copy-paste your question at http://techblog.bozho.net – I’m not sure how this old version of the blog will continue to live, so it’d be better if I answer you on the other one.
June 2, 2010 at 5:45 am |
// 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.
October 6, 2010 at 12:04 pm |
[...] How to create a digital signing solution with only JavaScript [...]
October 20, 2010 at 12:28 pm |
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?
October 20, 2010 at 12:55 pm |
@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.
October 22, 2010 at 2:57 am |
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
November 9, 2010 at 11:08 am |
hmmm.
I also not found any support for chrome.
May 9, 2011 at 9:04 am |
How i use it for FireFox
September 3, 2011 at 4:25 am |
Weekly Post…
[...]when you would like to read a little way more then I advise the following[...]…
December 15, 2011 at 2:36 pm |
could you please tell me how to get thumbprint value from certificate in java script.
thank you …….
February 20, 2012 at 12:15 pm |
[...] 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ą [...]
April 15, 2012 at 11:39 am |
gamekeys…
[...]How to create a digital signing solution with only JavaScript « Bozho’s Weblog[...]…
May 2, 2012 at 2:47 am |
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!
December 6, 2012 at 11:01 pm |
Ö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.
January 10, 2013 at 4:04 am |
Need to learn how to set all my functions to us my phone properly.Thanksfor the help.