JavaScript crypto

  • Revision slug: JavaScript_crypto
  • Revision title: JavaScript crypto
  • Revision id: 54838
  • Created:
  • Creator: Nickolay
  • Is current revision? No
  • Comment wikification

Revision Content

Using the Mozilla crypto object from JavaScript

Mozilla defines a special JavaScript object used to allow web pages access certain cryptographic related services. These services are a balance between what type of functions web pages need and the need to protect the user from malicious web sites. Most of these services are available of the JavaScript window object as window.crypto. For instance, to obtain a ten byte random number using the cryptographic engine, simply call:

var myrandom = window.crypto.random(10);

Services are provided to enable smart card events, generate certificate requests, import user certs, random numbers, logging out of your tokens, and signing text.

Handling Smart Card Events

In Gecko-based browsers, such as Mozilla and Firefox, websites can make themselves more SmartCard friendly by listening for SmartCard removal and insertion events. To enable your document to recieve these events, you must first tell the crypto system you are interested. You can do this by setting window.crypto.enableSmartCardEvents to true. This tells the crypto system that you are interested in listening for these events. You can then register event handlers for these events with the document.addEventListener.

Two smart card related events are generated:

  • "smartcard-insert" when SmartCards are inserted, and
  • "smartcard-remove" when SmartCards are removed.

Websites which use SSL clientAuth loggin can use the following code to refresh the page on token insertions and removals:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head> 
....
<script language="javascript">

function onSmartCardChange() {
  window.location.reload();
}
function register() {
  window.crypto.enableSmartCardEvents=true;
  document.addEventListener("smartcard-insert",onSmartCardChange,false);
  document.addEventListener("smartcard-remove",onSmartCardChange,false);
};
function deregister() {
  document.removeEventListener("smartcard-insert",onSmartCardChange,false);
  document.removeEventListener("smartcard-remove",onSmartCardChange,false);
};

</script>
</head>
<body .... onload=register() onunload=deregister()>
 .....
</body>
</html>

With the above example, your website will automatically reload anytime a SmartCard is inserted or removed. This allows the page to automatically login and logout based on the presence of the SmartCard.

Generating Keys and issuing User Certificates

There are several methods on the crypto object used in generating keys for certificates: generateCRMFRequest(), importUserCertificates(), and popChallengeResponse().

The generateCRMFRequest() function generates a key and creates a CRMF Request object. This object can be passed to a CA using a webform.

The importUserCertificates() function loads certificates into the NSS database or SmartCard if the corresponding key is found there.

The popChallengeResponse() function returns a proof of key posession signed challenge which a CA can use to verify the client has the private key associated with it's claimed public key.

Overview of New Cert Issuing Process

  1. User fills out enrollment form
  2. User action initiates script
  3. Script calls key generation method (generateCRMFRequest)
  4. Signing and Encryption keys are generated
  5. Encryption Private Key is wrapped with public key of Key Recovery Authority (KRA) (passed in in the form of a certificate as part of the script, and checked against a pre-installed certificate copy in the local certificate database)
  6. The public keys, wrapped encryption private key, and text string from the script (possibly containing naming or enrollment info) are signed by the user
  7. Signed blob is returned to the script
  8. Script submits signed blob and any other necessary info to the CA/RA
  9. CA/RA verifies signature on signed blob
  10. CA/RA validates identity of user
  11. CA/RA sends wrapped encryption private key to KRA
  12. KRA sends escrow verification back to CA
  13. CA creates and signs certificates
  14. CA sends certificates back to the user (importUserCertificates)

Typical use

The CA's enrollment page could look something like this:

<html>
<SCRIPT LANGUAGE="JavaScript">

/* the following values could be filled in by the server CGI */
var authenticator = "server_magic";
var keyTransportCert = null;

function validate()
{
   if (keygen_request == 'false')
      return false;
    with (document.forms[0]) {
        var keyTransportCert = null;
        // generate keys for nsm.
        if (typeof(crypto.version) != "undefined") {
              crmfObject = crypto.generateCRMFRequest(
                "CN="+documents.forms[0].name,
                documents.forms[0].password, authenticator,
        	    keyTransportCert,
                "setCRMFRequest();",
                1024, null, "rsa-dual");
         }
        return false;
    }
}

function setCRMFRequest()
{
    with (document.forms[0]) {
          cert_request.value = crmfObject.request;
          submit();
    }
}
</script>
<H2> Request a cert </H2>
<form name="ReqForm" onSubmit="return validate();" method="post" action="http://your.ra.site.org'">
<input type=hidden name=cert_request value="">
Name: <input type=text name=name value=""><br>
Password: <input type=password name="password" value="" ><br>
<input type=submit Name="Send" value="Submit">
</form>
</html>

On completion of the request, the CA may submit a page that looks something like this:

<html>
<SCRIPT LANGUAGE="JavaScript">

/* the following values could be filled in by the server CGI */
var nickname= "MyCertNickname";
var cert = "Mkjflakdjfiwjflaksufklasf ...";
var forceBackup = false;

function LoadCertificate()
{
    window.crypto.importUserCertificates(nickname, cert, forceBackup)
}
  
</script>
<H2> Certificate Request Successful </H2>
Hit 'load' to load your certificate
<form name="ReqForm" onSubmit="return LoadCertificate();">
<input type=submit Name="Load" value="Submit">
</form>
</html>

Signing text

DOMString                 signText(in DOMString stringToSign,
                                   in DOMString caOption /* ... */);

Loading PKCS #11 modules

 long                      deletemodule(in DOMString moduleName);
 long                      addmodule(in DOMString moduleName,
                                     in DOMString libraryFullPath,
                                     in long cryptoMechanismFlags,
                                     in long cipherFlags);

Miscellaneous

DOMString                 random(in long numBytes);
void                      alert(in DOMString message);
void                      logout();
void                      disableRightClick();

Revision Source

<p>
</p>
<h3 name="Using_the_Mozilla_crypto_object_from_JavaScript"> Using the Mozilla <code>crypto</code> object from JavaScript </h3>
<p>Mozilla defines a special JavaScript object used to allow web pages access certain cryptographic related services. These services are a balance between what type of functions web pages need and the need to protect the user from malicious web sites. Most of these services are available of the JavaScript <a href="en/DOM/window">window</a> object as <code>window.crypto</code>. For instance, to obtain a ten byte random number using the cryptographic engine, simply call:
</p>
<pre class="eval">var myrandom = window.crypto.random(10);
</pre>
<p>Services are provided to enable smart card events, generate certificate requests, import user certs, random numbers, logging out of your tokens, and signing text.
</p>
<h4 name="Handling_Smart_Card_Events"> Handling Smart Card Events </h4>
<p>In Gecko-based browsers, such as Mozilla and Firefox, websites can make themselves more SmartCard friendly by listening for SmartCard removal and insertion events. To enable your document to recieve these events, you must first tell the crypto system you are interested. You can do this by setting <code>window.crypto.enableSmartCardEvents</code> to <code>true</code>. This tells the crypto system that you are interested in listening for these events. You can then register event handlers for these events with the <code>document.addEventListener</code>.
</p><p>Two smart card related events are generated:
</p>
<ul><li> "smartcard-insert" when SmartCards are inserted, and
</li><li> "smartcard-remove" when SmartCards are removed.
</li></ul>
<p>Websites which use SSL clientAuth loggin can use the following code to refresh the page on token insertions and removals:
</p>
<pre>&lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"&gt;
&lt;html&gt;&lt;head&gt; 
....
&lt;script language="javascript"&gt;

function onSmartCardChange() {
  window.location.reload();
}
function register() {
  window.crypto.enableSmartCardEvents=true;
  document.addEventListener("smartcard-insert",onSmartCardChange,false);
  document.addEventListener("smartcard-remove",onSmartCardChange,false);
};
function deregister() {
  document.removeEventListener("smartcard-insert",onSmartCardChange,false);
  document.removeEventListener("smartcard-remove",onSmartCardChange,false);
};

&lt;/script&gt;
&lt;/head&gt;
&lt;body .... onload=register() onunload=deregister()&gt;
 .....
&lt;/body&gt;
&lt;/html&gt;
</pre>
<p>With the above example, your website will automatically reload anytime a SmartCard is inserted or removed. This allows the page to automatically login and logout based on the presence of the SmartCard.
</p>
<h4 name="Generating_Keys_and_issuing_User_Certificates"> Generating Keys and issuing User Certificates </h4>
<p>There are several methods on the crypto object used in generating keys for certificates:
<a href="en/GenerateCRMFRequest">generateCRMFRequest</a>(), <a href="en/ImportUserCertificates">importUserCertificates</a>(), and <a href="en/PopChallengeResponse">popChallengeResponse</a>().
</p><p>The <a href="en/GenerateCRMFRequest">generateCRMFRequest</a>() function generates a key and creates a <a href="en/CRMF_Request_object">CRMF Request object</a>. This object can be passed to a CA using a webform.
</p><p>The <a href="en/ImportUserCertificates">importUserCertificates</a>() function loads certificates into the NSS database or SmartCard if the corresponding key is found there.
</p><p>The <a href="en/PopChallengeResponse">popChallengeResponse</a>() function returns a proof of key posession signed challenge which a CA can use to verify the client has the private key associated with it's claimed public key.
</p>
<h3 name="Overview_of_New_Cert_Issuing_Process"> Overview of New Cert Issuing Process </h3>
<ol><li> User fills out enrollment form
</li><li> User action initiates script
</li><li> Script calls key generation method (<a href="en/GenerateCRMFRequest">generateCRMFRequest</a>)
</li><li> Signing and Encryption keys are generated
</li><li> Encryption Private Key is wrapped with public key of Key Recovery Authority (KRA) (passed in in the form of a certificate as part of the script, and checked against a pre-installed certificate copy in the local certificate database)
</li><li> The public keys, wrapped encryption private key, and text string from the script (possibly containing naming or enrollment info) are signed by the user
</li><li> Signed blob is returned to the script
</li><li> Script submits signed blob and any other necessary info to the CA/RA
</li><li> CA/RA verifies signature on signed blob
</li><li> CA/RA validates identity of user
</li><li> CA/RA sends wrapped encryption private key to KRA
</li><li> KRA sends escrow verification back to CA
</li><li> CA creates and signs certificates
</li><li> CA sends certificates back to the user (<a href="en/ImportUserCertificates">importUserCertificates</a>)
</li></ol>
<h3 name="Typical_use"> Typical use </h3>
<p>The CA's enrollment page could look something like this:
</p>
<pre>&lt;html&gt;
&lt;SCRIPT LANGUAGE="JavaScript"&gt;

/* the following values could be filled in by the server CGI */
var authenticator = "server_magic";
var keyTransportCert = null;

function validate()
{
   if (keygen_request == 'false')
      return false;
    with (document.forms[0]) {
        var keyTransportCert = null;
        // generate keys for nsm.
        if (typeof(crypto.version) != "undefined") {
              crmfObject = crypto.generateCRMFRequest(
                "CN="+documents.forms[0].name,
                documents.forms[0].password, authenticator,
        	    keyTransportCert,
                "setCRMFRequest();",
                1024, null, "rsa-dual");
         }
        return false;
    }
}

function setCRMFRequest()
{
    with (document.forms[0]) {
          cert_request.value = crmfObject.request;
          submit();
    }
}
&lt;/script&gt;
&lt;H2&gt; Request a cert &lt;/H2&gt;
&lt;form name="ReqForm" onSubmit="return validate();" method="post" action="http://your.ra.site.org'"&gt;
&lt;input type=hidden name=cert_request value=""&gt;
Name: &lt;input type=text name=name value=""&gt;&lt;br&gt;
Password: &lt;input type=password name="password" value="" &gt;&lt;br&gt;
&lt;input type=submit Name="Send" value="Submit"&gt;
&lt;/form&gt;
&lt;/html&gt;
</pre>
<p>On completion of the request, the CA may submit a page that looks something like this:
</p>
<pre>&lt;html&gt;
&lt;SCRIPT LANGUAGE="JavaScript"&gt;

/* the following values could be filled in by the server CGI */
var nickname= "MyCertNickname";
var cert = "Mkjflakdjfiwjflaksufklasf ...";
var forceBackup = false;

function LoadCertificate()
{
    window.crypto.importUserCertificates(nickname, cert, forceBackup)
}
  
&lt;/script&gt;
&lt;H2&gt; Certificate Request Successful &lt;/H2&gt;
Hit 'load' to load your certificate
&lt;form name="ReqForm" onSubmit="return LoadCertificate();"&gt;
&lt;input type=submit Name="Load" value="Submit"&gt;
&lt;/form&gt;
&lt;/html&gt;
</pre>
<h4 name="Signing_text"> Signing text </h4>
<pre class="eval">DOMString                 signText(in DOMString stringToSign,
                                   in DOMString caOption /* ... */);
</pre>
<h4 name="Loading_PKCS_.2311_modules"> Loading PKCS #11 modules </h4>
<pre class="eval"> long                      deletemodule(in DOMString moduleName);
 long                      addmodule(in DOMString moduleName,
                                     in DOMString libraryFullPath,
                                     in long cryptoMechanismFlags,
                                     in long cipherFlags);
</pre>
<h4 name="Miscellaneous"> Miscellaneous </h4>
<pre class="eval">DOMString                 random(in long numBytes);
void                      alert(in DOMString message);
void                      logout();
void                      disableRightClick();
</pre>
Revert to this revision