digital-signatureecdsacloudflare-workerswebcrypto-apiwebcrypto

Unable to verify EDSCSA SHA-256 signature


I am trying to verify a ECDSA, SHA-256 key. But i am unable to do so with the web crypto API. My code looks like this-

export async function verifySignature(
    requestData: string,
    receivedSignature: string,
    publicKey: string
): Promise<boolean> {
    try {
        const textEncoder = new TextEncoder();

        const digest = await crypto.subtle.digest('SHA-256', textEncoder.encode(requestData));
        // using digest

        // Import the public key
        if (importedKey == null) {
            importedKey = await crypto.subtle.importKey(
                'spki',
                stringToArrayBuffer(atob(publicKey)),
                { name: 'ECDSA', namedCurve: 'P-256' },
                true,
                ['verify']
            );
        }

        // Verify the signature
        const isValid = await crypto.subtle.verify(
            { name: 'ECDSA', hash: 'SHA-256' },
            importedKey,
            stringToArrayBuffer(atob(receivedSignature)),
            digest
        );
        
        return isValid;
    } catch (error) {
        console.error('Error verifying signature:', error);
        return false;
    }
}

I am able to verify the signature with the openssl command. openssl dgst -sha256 -verify public.pem -signature signature.der data.txt

Here is the code sandbox link with required information - https://codesandbox.io/p/sandbox/beautiful-maria-2qkzxq

Any help is really appreciated.. I've spent a day on this already.. :( Thanks in advance.


Solution

  • There are two bugs:

    If both are taken into account, the signature can then be successfully verified with your code and the matching key (using my own function b642ab(), since stringToArrayBuffer() was not posted):

    (async () => {
    
    var requestData = 'The quick brown fox jumps over the lazy dog';
    var publicKey = 'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEMpHT+HNKM7zjhx0jZDHyzQlkbLV0xk0H/TFo6gfT23ish58blPNhYrFI51Q/czvkAwCtLZz/6s1n/M8aA9L1Vg==';
    var receivedSignature = 'kmsKlUBUKbvuYz9+M3dTL5v5Mx3mcFPJR5OywhzrAWJHOIHWmtmQfNh7BHCWwEjtOH8S3HnSAOjoDGdPRArf1Q=='; // Fix 1: apply signature in P1363 format
    
    function b642ab(base64_string){  
        return Uint8Array.from(window.atob(base64_string), c => c.charCodeAt(0));
    }
    
    // UTF8 encode message
    const textEncoder = new TextEncoder();
    const message = textEncoder.encode(requestData);
    
    // Import the public key
    var importedKey = null;
    if (importedKey == null) {
        importedKey = await crypto.subtle.importKey(
            'spki',
            b642ab(publicKey),
            { name: 'ECDSA', namedCurve: 'P-256' },
            true,
            ['verify']
        );
    }
    
    // Verify the signature
    const isValid = await crypto.subtle.verify(
        { name: 'ECDSA', hash: 'SHA-256' },
        importedKey,
        b642ab(receivedSignature),
        message // Fix 2: apply message instead of message hash
    );
    
    console.log("Verified: ", isValid);
        
    })();