4

There is a WebCrypto API in browsers. It allows clients to sign data. However, it seems to me that it does not prevent web page to access the private key.

After key has been generated, it can be marked as non-extractable and can be saved to IndexedDb API.

How to generate the key, that it is clear for the client that web page could not access the private key during the generation?

For instance, web page can generate extractable key and then import it as non extractable and send the private key to the server, which served the web page.

(Is it possible to ensure this without proprietary addons?)

  • I'm confused. Without digging into WebCrypto, I would assume the browser creates it's own public/private key combination and provides the public key to the server, not the private key. Also, in your 2nd to last sentence, you say "web site" and "server" but aren't they one in the same? – TTT Aug 16 '16 at 21:58
  • @TTT I have changed the term web site to the web page. In WebCrypto, it is decision of the web page, how it will obtain the key. (As mentioned above, the web page could also send the private key to the server.) – TN. Aug 17 '16 at 6:14
  • So the web page generates the server's private key? Why can't the server generate it's own private key? I would assume each party can create it's own private key so that no one else ever sees it. – TTT Aug 17 '16 at 13:33
  • @TTT No, the web page generates client's private key. Check the WebCrypto API. – TN. Aug 18 '16 at 8:32
  • Exactly, so then which private key is the web page sending to the server? It wouldn't make sense for the web page to send its own private key to the server, since the server wouldn't need it. – TTT Aug 18 '16 at 14:15
2

Setting the extract option to false does allow you to extract the public key but NOT the private key.

If you put the below code in JS Fiddle you will get "[object ArrayBuffer]" for the public key and "HEY:Key is not extractable" for the private key.

You can still sign with the protected private key using the reference key_priv later but never read the actual private key.

This is exactly the behavior you are looking for.

window.crypto.subtle.generateKey(
{
    name: "RSASSA-PKCS1-v1_5",
    modulusLength: 1024,
    publicExponent: new Uint8Array([1, 0, 1]),  // 24 bit representation of 65537
    hash: {name: "SHA-256"}
},
false,   // can extract it later if we want
["sign", "verify"]).
then(function(key) {
    window.crypto.subtle.exportKey("spki", key.publicKey).
        then(function(key_pub) {
    alert(key_pub);
        window.crypto.subtle.exportKey("pkcs8", key.privateKey).
        then(function(key_priv) {
                alert(key_priv);
            }).catch(function(err) {
                alert("HEY!: " + err.message);
            });
    });
});

Remember that you only need to send the server the public key that it can use to confirm the signature.

  • The issue is, that WebCrypto API does not seem to protect clients. Web server could secretly steal the client's private key during its generation. – TN. Oct 31 '16 at 13:26
  • 2
    You are referring to the old 'it's not secure because... javascript' argument? By the same token why would anyone trust a compiled application that could do the same thing? – dave.zap Oct 31 '16 at 17:41
  • 1
    No. Let's imaging different web crypto API, that allows the javascript just to use the certificate from some certstore to e.g. sign a content that will be sent to server. Then the server can claim that no one except for the client could sign the content. – TN. Nov 1 '16 at 13:04
  • @dave.zap Because compiled applications can hook into the OS's native crypto functionality so that the app never actually handles the private key. Or they can use USB crypto devices like smart cards so that the private key is never in the computer's memory at all, and thus couldn't be sent to the sever even if the app wanted to. The argument isn't "javascript sucks because it's javascript", the argument is "javascript sucks because any process on the machine can take a memory dump of the browser and extract the private key". – Mike Ounsworth Mar 30 '17 at 1:01
  • @dave.zap - The big problem with web apps for security purposes are that they are served on demand. With a compiled app you can audit it and be certain of its behavior. With a web app the server can replace the code at any point in time. – Hector Sep 26 '17 at 7:56
1

This depends on the use case.

@dave.zap has shown how to generate the keypair. Of course your server could change the generation logic at any point but assuming the keypair is rarely generated a paticularly concerned user could audit the JS at any point during key generation (or using developer tools manually add the key in the IndexedDB).

This now means the JS does not have any further access to the keypair. Only that client can sign documents - meaning that you know any document signed with that private key came from that machine.

However there is nothing to stop the server giving JavaScript which downloads a foreign document, signs it and sends it back.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.