Cannot store CryptoKey in IndexedDB object store in Firefox

381 Views Asked by At

I need to store an ECDH P-384 keypair in an IndexedDB database. This is the code that generates the keypair:

async function generateKeys() {
    // generate client's ECDH asymmetric keypair (privateKey, publicKey)
    return await window.crypto.subtle.generateKey(
        {
            name: "ECDH",
            namedCurve: "P-384",
        },
        true,
        ["deriveKey", "deriveBits"]
    );
}

This is the code that opens the database, creates the 'asymmetric' object store if it doesn't exist and then generates and stores the keypair:


var request = window.indexedDB.open("main", 3);
request.onerror = function (event) {
    console.error("Database error: " + event.target.errorCode);
};
request.onupgradeneeded = function (event) {
    db = event.target.result;
    if (!db.objectStoreNames.contains('asymmetric')) {
        console.log('creating OS');
        var objectStore = db.createObjectStore("asymmetric", { keyPath: "owner" });
        objectStore.transaction.oncomplete = function (event) {
            intialKeySetup = true;
        };
    }

};
request.onsuccess = function (event) {
    db = event.target.result;
    if (intialKeySetup) { // first time running
        setupNewKeys();
    } else {
        console.log('loading keys...');
        loadKeys();
    }
};

function setupNewKeys() {
    // Generates ECDH keypair, then saves them to the 'asymmetric' object store with key '#this#'
    return generateKeys().then((kp) => {
        clientKeys = kp;
        var asymOS = db.transaction("asymmetric", "readwrite").objectStore("asymmetric");

        // Error occurs here:
        asymOS.add({ owner: '#this#', keys: kp }); // kp = { publicKey: CryptoKey object, privateKey: CryptoKey object }
        console.log('Done. Wrote keys to DB: ');
        console.log(kp);
        startComm();
    });
}


function loadKeys() {
    // Loads the client's keypair into memory from the 'asymmetric' object store at key '#this#'
    console.log('Attempting to access client keys...');
    var transaction = db.transaction(["asymmetric"]);
    var objectStore = transaction.objectStore("asymmetric");
    var request = objectStore.get("#this#");
    request.onerror = function (event) {
        console.error(event.target.errorCode);
    };
    request.onsuccess = function (event) {
        if (!request.result) {
            setupNewKeys();
        } else {
            console.log(request.result);
            clientKeys = request.result.keys;
            console.log('Retrieved Keys');
            console.log('Starting Comm...');
            startComm(); // connect to WebSocket server
        }
    };
}

This code works perfectly fine on Chrome, Chromium Edge, macOS Safari, iOS Safari and Chrome on Android, however it does not work on Firefox. It doesn't let it store the two CryptoKey objects in the object store, and generates the error:
Uncaught (in promise) DOMException: The object could not be cloned.
When I instead try to store a string instead of the CryptoKey objects, the error disappears, and I can see the string stored in the "Storage" tab of the developer tools. Why is it not letting me store the CryptoKey in the object store in Firefox? And are there any workarounds other than exporting the key?

0

There are 0 best solutions below