How to make a digital signature in a web application (JavaScript) using a smartcard?
Asked Answered
S

5

10

We have written a document management system and would like to digitally sign documents using the web client. Our Java client application is already able to apply and check digital signature, but we would like to make signature even with our web client. This is written in GWT and so, when run on the client side, it is a JavaScript application.

We not want to create a Java applet and download it on the client and execute it. We would like to use the browser security device or the browser API in order to sign a document. We would also like to keep the complete document server side, and move to the client only the document hash.

We feel this should be possible using NSS or npapi/npruntime, but we did not find any information about this. (By the way, is npruntime available also in IE? Should we use ActiveX for achieving the same result with IE?)

Do you have any hints?

Scuttle answered 11/5, 2012 at 14:31 Comment(1)
Use Browser Extensions for Modern Browsers. Please refer https://mcmap.net/q/671268/-sign-pdf-with-plain-javascript and stackoverflow.com/a/55692742/9659885Conurbation
S
9

After some more googling I found the answer. Mozilla export part of its NSS module via window.crypto object. A more standard way of doing such operation is probably via DOMCrypt, that is currently discusses in W3C. Google Chrome developer will wait W3C to standardize DOMCrypt, while Microsoft require the use of an ActiveX object as explained here (this works even with Firefox/Chrome/Opera on Windows).

Scuttle answered 12/5, 2012 at 5:27 Comment(4)
DOMCrypt link is not what its supposed to be.Lorusso
Thanks @Lorusso , the DOMcrypt.org DNS seems to be assigned to a different owner now. I changed the link to a different page with very similar content.Scuttle
window.crypto was not removed after Firefox 33?Astronautics
Today's best way to achieve is to use Browser Extension which can access local CertificateStore. Signer.Digital Chrome Extension is one such free extension provided by my Company.Conurbation
O
5

Currently (may 2016) it is not possible.

Chrome has dropped Java support. 'Windows edge' will not have. IE11 support is bad, and Oracle has decided to discontinue the java plugin. It would only be possible with Firefox, older versions of IE and the Java plugin.

The new WebCryptographyApi standard provides digital signature support for browsers, but it does not have pcks#11 support

Real e-goverment solution to solve this: 1) Install a local Java application on the user's PC. The application listens on a port as, for example 5678 2) In your page, javascript detects whether there is support for applets 3) If there is no support, connects to the application in the form http://127.0.01:5678/sign and sends the data to sign. 4) The application is local and has no trouble using the operating system keystore, which includes drivers PKCS # 11. Make digital signature and prepares the result 5) page javascript periodically query the result and retrieves it when ready

Orabelle answered 24/5, 2016 at 18:23 Comment(2)
Java applets can be launched via Java Web Start. This works in all desktop browsers, though some extra effort is needed.Thousand
There is a solution in Spain in e-government to solve this. I will document it in the answerOrabelle
D
0

In Win/IE you can still use CAPICOM http://en.wikipedia.org/wiki/CAPICOM without any third party ActiveX or external libraries.
This works anywhere IE is installed.
This is being retired however.

Below is what I am using to sign in IE. I call this with e.g: var signature = signDigest(stringToBeSigned);

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

var dest = sign(text); //TODO  

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);
    else

        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 error was: " + e.description);
        }
    }
    return "";
}  

I had some issues with encoding,etc, so I have included my controller (.net) as well

        byte[] decbuff = Convert.FromBase64String(signature);


    //CAPICOM USES 16 BIT ENCODING
    Encoding utf16Enc = Encoding.GetEncoding("UTF-16LE");


    byte[] utf16Data = utf16Enc.GetBytes(getContent);


    ContentInfo content = new ContentInfo(utf16Data);

    System.Security.Cryptography.Pkcs.SignedCms cms = new System.Security.Cryptography.Pkcs.SignedCms(content,true);
    cms.Decode(decbuff);

    int length = decbuff.Length;         

    X509Certificate2 cert = cms.SignerInfos[0].Certificate;


    X509Chain chain = new X509Chain();
    bool theVal = chain.Build(cert);
    cms.CheckHash();       
    cms.CheckSignature(false);
Dorladorlisa answered 1/7, 2013 at 16:26 Comment(2)
I am using also CAPICOM to sign xml with X509Certificate2 sign. When I choose a certificate from the store it doesn't ask me after that to enter username and password for that certificate. Is it the same situation and with your code above?Mewl
Only sometimes if it is 'messed up' -- I close the browser, open, and it asks for credentials. I occasionally get a point where it stops asking, but reloading the browser always seems to fix this.Dorladorlisa
D
0

One project that I have been involved with did this with Chrome and Native Messaging:

https://github.com/CACBridge/ChromeCAC

This requires the installation of the chrome plugin, but otherwise works great. Ideal for e.g. Intranet/Group environments where you know you will need to do this ahead of time.

Dorladorlisa answered 7/11, 2016 at 17:6 Comment(0)
Z
-1

Now you can do that. Web application based on PKCS#11 smart cards or tokens can be implemented by using the Silverlight version of NCryptoki. See http://www.ncryptoki.com

You have two chanches:

1) using the Silverlight version of NCryptoki and develop your own Silverlight User Control that implements your logic, a Digital Signature in your case, using PKCS#11 functions supplied by the smart card

2) using the JQuery plugin based on the above Silverlight version and implement your application in JavaScript by calling the PKCS#11 functions in JavaScript

Also, you can use the Silverlight version of NDigitSign (see again http://www.ncryptoki.com) that does all you need and can be implemented in any web browser.

Ziwot answered 19/10, 2013 at 15:17 Comment(1)
Thanks for pointing to this solution. I was not aware of ncryptoki project, but since it silverlight based, it still require do install software on client machine (as for java applet) and, more important, it would probably only work on Windows machines. Finally, that would require to write an application that directly uses PKCS#11, and I would really like to avoid such program.Scuttle

© 2022 - 2024 — McMap. All rights reserved.