Marian
Marian

Reputation: 7472

Import elliptic curve private key from PEM in Firefox

I am trying to import an elliptic curve private key from PEM encoding. The following code works fine on Chrome but does not work with Firefox. It says:

ERR Operation is not supported

Browsing around I've got impression it is a know problem, however I did not find a solution. Is there any workaround to import ECDSA private key from PEM on Firefox? In preference I want a solution working with reasonably older versions of Firefoxes.

<html>
    <body>
        <script>
         function stringToArrayBuffer(str) {
             var buf = new ArrayBuffer(str.length);
             var bufView = new Uint8Array(buf);
             var len = str.length;
             for (var i=0; i<len; i++) {
                 bufView[i] = str.charCodeAt(i);
             }
             return buf;
         };
         function importPrivateKey(pem) {
             // console.log("PP", pem);
             var crypto = window.crypto || window.msCrypto;
             // fetch the part of the PEM string between header and footer
             const pemHeader = "-----BEGIN PRIVATE KEY-----";
             const pemFooter = "-----END PRIVATE KEY-----";
             const pemContents = pem.substring(pemHeader.length+1, pem.length - pemFooter.length - 2);
             // base64 decode the string to get the binary data
             const binaryDerString = window.atob(pemContents);
             // convert from a binary string to an ArrayBuffer
             const binaryDer = stringToArrayBuffer(binaryDerString);
             var res = crypto.subtle.importKey("pkcs8", binaryDer, {name: "ECDSA", namedCurve: "P-384"}, true, ["sign"]);
             return(res);
         }
         var promise_key = importPrivateKey("-----BEGIN PRIVATE KEY-----\nMIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDBmb0Yu9UxnUhKN0Cwf\nq/OWVzNTdPKBsUHsVXJAKVUYczDQ7+PYnFxyoVaz8PtoGuihZANiAAQc7WOnfjtL\njDV0+anLxnG2d0p2d7PkdwQBLTu5nONzwOLG0fqeEzbrPRQ125PHQxz7Qr2S4/xz\nC4OVDzebpD/ABnN+QRuiUXf2SMtz90xs80sMLS3glv7OMLCTQLz3P/o=\n-----END PRIVATE KEY-----\n");
         promise_key.then(
             function(key){
                 console.log("OK");
             },
             function(e){
                 console.log("ERR", e.message);
             }      
         );
        </script>
    </body>
</html>

Upvotes: 0

Views: 414

Answers (2)

Michael Fehr
Michael Fehr

Reputation: 6414

Unfortunately, it is a long-lasting and still open bug in the WebCrypto engine of Firefox (see bugzilla.mozilla.org/show_bug.cgi?id=1133698).

Up to now there are three solutions:

  • First: don't use Firefox but e.g. Chrome or Opera.
  • Second: Use keys in the RAW or JWK encoding.
  • Third: write an PEM to JWK converter.

Yes, I know, all three options don't make me happy either.

Maybe you could use JSRSASIGN (npmjs.com/package/jsrsasign) - it supports ECDSA as well ?

Upvotes: 1

Marian
Marian

Reputation: 7472

I am answering my own question for case someone find it useful. As suggested by Michael a possible workaround is to use "jsrsasign" library and KEYUTIL functions. After having installed jsrsasign, the following code imports ECDSA private key on both Chrome and Firefox.

<html>
    <head>
    </head>
    <body>
        <script type='text/javascript' src='jsrsasign-master/jsrsasign-all-min.js'></script>
        <script>
         function importPrivateKey(pem) {
             var jsrasignkey = KEYUTIL.getKeyFromPlainPrivatePKCS8PEM(pem);
             var jwkkey = KEYUTIL.getJWKFromKey(jsrasignkey);
             var res = crypto.subtle.importKey("jwk", jwkkey, {name: "ECDSA", namedCurve: "P-384"}, true, ["sign"]);
             return(res);
         }
         var promise_key = importPrivateKey("-----BEGIN PRIVATE KEY-----\nMIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDBmb0Yu9UxnUhKN0Cwf\nq/OWVzNTdPKBsUHsVXJAKVUYczDQ7+PYnFxyoVaz8PtoGuihZANiAAQc7WOnfjtL\njDV0+anLxnG2d0p2d7PkdwQBLTu5nONzwOLG0fqeEzbrPRQ125PHQxz7Qr2S4/xz\nC4OVDzebpD/ABnN+QRuiUXf2SMtz90xs80sMLS3glv7OMLCTQLz3P/o=\n-----END PRIVATE KEY-----\n");
         promise_key.then(
             function(key){
                 console.log("OK");
             },
             function(e){
                 console.log("ERR", e.message);
             }      
         );
        </script>
    </body>
</html>

Upvotes: 1

Related Questions