passwordless-id / webauthn

Webauthn / passkeys helper library to make your life easier. Client side, server side and demo included.
https://webauthn.passwordless.id
MIT License
436 stars 51 forks source link

verifyAuthentication ERR_OSSL_EVP_DECODE_ERROR #44

Closed conanliuhuan closed 5 months ago

conanliuhuan commented 5 months ago

Code:

        var challenge = passkey_challenge_store[timestamp];
        var credentialKey = {
        id: passkey.id,
        publicKey: passkey.publicKey,
        algorithm: passkey.algorithm,
    }

    var expected = {
        challenge,
        origin: get_option('nv_home_url'),
        userVerified: true,
    }

    console.log(authentication)
    console.log(credentialId)
    console.log(credentialKey)
    console.log(expected)

    return webAuthnServer.verifyAuthentication(authentication, credentialKey, expected);

Console:

{
  credentialId: 'pADVavwUiRWK_Rf_9ZZEOuZBaogKqJB-pgTIO24Pnxs',
  authenticatorData: 'SZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2MFAAAACQ==',
  clientData: 'eyJjaGFsbGVuZ2UiOiJjMjkxZDJjNS0xMmYxLTQxZTEtODlmMC0zZWQ3MWU3ZWM1ZjUiLCJvcmlnaW4iOiJodHRwOi8vbG9jYWxob3N0OjMwMDAiLCJ0eXBlIjoid2ViYXV0aG4uZ2V0In0=',
  signature: 'tRy_rJqHMfiow8nL90BRn8R4aZKXuWmh-xgllLkKiCR2HM8w9-975_tP552zJf-3ygRlbnu3H321vELGDosiSF6MiaDbp5jRGFlUXAW5PcikksdbJCYjao7O5e1zD7dZEQyrxW_Tu8blggwXZ0WvV2jDebEyDiF_Q6QC5cp-qCVLwskGS-_Qlyd4guLWNuEXsJFSvlBAfBC7390Fn5QaJS85EqQ7pO7191QIkoLZGCvPekdKVezzpXjotM7srSn4RGUJQBX6N8B3DAvq0FRa_-pze9k6UF7V13nyJIQPcW-60YbdmPMFpbagjsnTHBRI1RwAsYvKmEu3EMdoZPZ6UQ==',
  userHandle: 'lOXeWfRRCm1598JCasYucIj5F1aL24FwpCtyP5eO83o='
}
pADVavwUiRWK_Rf_9ZZEOuZBaogKqJB-pgTIO24Pnxs
{
  id: 'pADVavwUiRWK_Rf_9ZZEOuZBaogKqJB-pgTIO24Pnxs',
  publicKey: 'MIIBIjANBgkqhkiG9w0BAQsFAAOCAQ8AMIIBCgKCAQEA2JrQ5S5fV3rOc0AmKg7ljFMMcmnA62tjxGl-UVQVo77hsMwPfQjAM6fM3zpdLMWVGT7DN3AyErA2xIIDTcgcLFV0jp0RKwlnNm1uBYXkMlu9qI8XEioeyrwErYbkTKNOvjg4iXL3UU2bDxwUxCFt9ReihjaInfyo3aBjzC22P_fzQf0CUnw6Vo0SeuFdRTX5f1ZQY-56sMnPMyNqB4CBN-ejo9POG8k5nDh0IvaT2x7yfDz_YsB1Smhpj67Cb-Dl-NbqvFjikeYTzeOITBOGCaElJfExupww1DzUY-N9XN2yhph_XP9LvUH6qxc7N_BcoOtfpsDDYrDJ_hyvG6aaOQIDAQAB',
  algorithm: 'RS256'
}
{
  challenge: 'c291d2c5-12f1-41e1-89f0-3ed71e7ec5f5',
  origin: 'http://localhost:3000',
  userVerified: true
}
DOMException [DataError]: Invalid keyData
    at new DOMException (node:internal/per_context/domexception:53:5)
    at __node_internal_ (node:internal/util:695:10)
    at Object.rsaImportKey (node:internal/crypto/rsa:219:15)
    at SubtleCrypto.importKey (node:internal/crypto/webcrypto:615:10)
    ... 5 lines matching cause stack trace ...
    at new Promise (<anonymous>) {
  [cause]: Error: error:03000072:digital envelope routines::decode error
      at createPublicKey (node:internal/crypto/keys:619:12)
      at Object.rsaImportKey (node:internal/crypto/rsa:213:21)
      at SubtleCrypto.importKey (node:internal/crypto/webcrypto:615:10)
      at parseCryptoKey (file:///D:/SynologyDrive/Design/Html/nvPress/node_modules/@passwordless-id/webauthn/dist/esm/server.js:92:26)
      at verifySignature (file:///D:/SynologyDrive/Design/Html/nvPress/node_modules/@passwordless-id/webauthn/dist/esm/server.js:107:27)
      at Module.verifyAuthentication (file:///D:/SynologyDrive/Design/Html/nvPress/node_modules/@passwordless-id/webauthn/dist/esm/server.js:31:36)
      at global.async_verify_passkey_login (D:\SynologyDrive\Design\Html\nvPress\nv-includes\method-users.js:306:24)
      at D:\SynologyDrive\Design\Html\nvPress\nv-includes\init_default_users_api.js:163:4
      at new Promise (<anonymous>)
      at callback (D:\SynologyDrive\Design\Html\nvPress\nv-includes\init_default_users_api.js:162:10) {
    library: 'digital envelope routines',
    reason: 'decode error',
    code: 'ERR_OSSL_EVP_DECODE_ERROR'
  }
}
dagnelies commented 5 months ago

Without context, it's hard to determine the problem. Is it only for a specific authenticator? Does it work in the playground ? Where exactly does your passkey object come from? Is it related to your dev environment? ...

But basically, yeah, something look wrong with the key itself.

conanliuhuan commented 5 months ago

Without context, it's hard to determine the problem. Is it only for a specific authenticator? Does it work in the playground ? Where exactly does your passkey object come from? Is it related to your dev environment? ...

But basically, yeah, something look wrong with the key itself.

I create a smallest app only register and login, it still get error

Frontend:

<!DOCTYPE html>
<html>
<head>
    <title></title>
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
</head>
<body>
<button onclick="register()">register</button>
<button onclick="login()">login</button>
<script type="module">
import { client } from 'https://cdn.jsdelivr.net/npm/@passwordless-id/webauthn@1.5.0/dist/webauthn.min.js'

var challenge = "a7c61ef9-dc23-4806-b486-2428938a547e";

window.register = ()=>{
    client.register('sample_user_name', challenge, {
        authenticatorType: "auto",
        userVerification: "required",
        timeout: 60000,
        attestation: true,
        debug: false,
    })
    .then(registration=>{
        console.log(registration)
        axios({
            method: 'post',
            url: '/register',
            responseType: 'json',
            data: {
                registration,
            }
        })
        .then(({data})=>{
            console.log(data)
            alert("request succeed")
        })
        .catch((err)=>{
            console.log(err)
            alert("request failed")
        })
    })
    .catch((err)=>{
        console.log(err)
        alert("user/platform declined")
    })
}

window.login = ()=>{
    client.authenticate([], challenge, {
        authenticatorType: "auto",
        userVerification: "required",
        timeout: 60000,
    })
    .then(authentication=>{
        axios({
            method: 'post',
            url: '/login',
            responseType: 'json',
            data: {
                authentication,
            }
        })
        .then(({data})=>{
            console.log(data)
            alert("request succeed")
        })
        .catch((err)=>{
            console.log(err)
            alert("request failed")
        })
    })
    .catch((err)=>{
        console.log(err)
        alert("user/platform declined")
    })
}

</script>
</body>
</html>

Backend:

import fs from "fs"
import path from "path"
import express from "express"
import {server as webAuthnServer} from '@passwordless-id/webauthn';

var app = express();
app.use(express.json({limit: '5mb' }));

app.get('/', (req,res)=>{
    res.type("text/html");
    res.send( fs.readFileSync( path.join(process.cwd(),"./web.html") ,{encoding: 'utf-8'}) );
    return;
})

var saved_credential = null;

var challenge = "a7c61ef9-dc23-4806-b486-2428938a547e";

app.post('/register',(req,res)=>{
    var expected = {
        challenge,
        origin: "http://localhost:9999"
    }

    webAuthnServer.verifyRegistration(req.body.registration, expected)
    .then(data=>{
        // save key
        saved_credential = data.credential;

        res.json({
            success: 1
        });
    })
    .catch(()=>{
        res.json({
            success: 0
        });
    })

})

app.post('/login',(req,res)=>{
    var credentialKey = saved_credential;
    var expected = {
        challenge,
        origin: "http://localhost:9999",
        userVerified: true,
    }

    webAuthnServer.verifyAuthentication(req.body.authentication, credentialKey, expected)
    .then(data=>{
        res.json({
            success: 1
        });
    })
    .catch(err=>{
        console.log(err)
        res.json({
            success: 0
        });
    })
})

app.listen(9999,()=>{
    console.log('http://localhost:9999')
})

Try this file: webauthn-test.zip

  1. npm install
  2. node test
  3. browser open http://localhost:9999
  4. click register
  5. click login
  6. error will display on the console
conanliuhuan commented 5 months ago

Node.js version: 20.11.1

conanliuhuan commented 5 months ago

Maybe there's something wrong with my Windows11, I tested it on MacOS 13.6, it works well

dagnelies commented 5 months ago

Strange... It looks like the following key cannot be interpreted as RS256 key, dunno why.

{
  id: 'pADVavwUiRWK_Rf_9ZZEOuZBaogKqJB-pgTIO24Pnxs',
  publicKey: 'MIIBIjANBgkqhkiG9w0BAQsFAAOCAQ8AMIIBCgKCAQEA2JrQ5S5fV3rOc0AmKg7ljFMMcmnA62tjxGl-UVQVo77hsMwPfQjAM6fM3zpdLMWVGT7DN3AyErA2xIIDTcgcLFV0jp0RKwlnNm1uBYXkMlu9qI8XEioeyrwErYbkTKNOvjg4iXL3UU2bDxwUxCFt9ReihjaInfyo3aBjzC22P_fzQf0CUnw6Vo0SeuFdRTX5f1ZQY-56sMnPMyNqB4CBN-ejo9POG8k5nDh0IvaT2x7yfDz_YsB1Smhpj67Cb-Dl-NbqvFjikeYTzeOITBOGCaElJfExupww1DzUY-N9XN2yhph_XP9LvUH6qxc7N_BcoOtfpsDDYrDJ_hyvG6aaOQIDAQAB',
  algorithm: 'RS256'
}

I would be interested as well to know what went wrong with this "key".

conanliuhuan commented 5 months ago

My PC do not has TPM hardware. I replaced some system files when I was installing Windows 11. Maybe that caused the problem.