webauthn-open-source / fido2-lib Goto Github PK
View Code? Open in Web Editor NEWA node.js library for performing FIDO 2.0 / WebAuthn server functionality
Home Page: https://webauthn.io
License: MIT License
A node.js library for performing FIDO 2.0 / WebAuthn server functionality
Home Page: https://webauthn.io
License: MIT License
Do you know if there's a soft token library available that would be suitable to use for testing?
At the moment I use webdriverio and Firefox, which is fine but requires me to have a hard token plugged in and press the button multiple times on each test.
For one of my projects I saved the responses and then replayed them (ignoring replay errors).
However it would by nice to have a library/program which would act like a hard token.
@apowers313 what do you use for testing?
Hello,
Both in the Assertion and Attestation validation the WebAuthn guideline specify these controls:
The library get the flags to be verified from the expectations that are parsed by this function:
function factorToFlags(expectedFactor, flags) {
// var flags = ["AT"];
flags = flags || [];
switch (expectedFactor) {
case "first":
flags.push("UV");
break;
case "second":
flags.push("UP");
break;
case "either":
flags.push("UP-or-UV");
break;
default:
throw new TypeError("expectedFactor should be 'first', 'second' or 'either'");
}
return flags;
}
The flags in the authnrData are parsed by these lines in "parseAuthenticatorData(authnrDataArrayBuffer)":
if (flags & 0x01) flagsSet.add("UP");
if (flags & 0x02) flagsSet.add("RFU1");
if (flags & 0x04) flagsSet.add("UV");
if (flags & 0x08) flagsSet.add("RFU3");
if (flags & 0x10) flagsSet.add("RFU4");
if (flags & 0x20) flagsSet.add("RFU5");
if (flags & 0x40) flagsSet.add("AT");
if (flags & 0x80) flagsSet.add("ED");
Finally the following function validates the flags:
async function validateFlags() {
var expectedFlags = this.expectations.get("flags");
var flags = this.authnrData.get("flags");
for (let expFlag of expectedFlags) {
if (expFlag === "UP-or-UV") {
if (flags.has("UP") || flags.has("UV")) {
continue;
} else {
throw new Error("expected User Presence (UP) or User Verification (UV) flag to be set and neither was");
}
}
if (!flags.has(expFlag)) {
throw new Error(`expected flag was not set: ${expFlag}`);
}
}
this.audit.journal.add("flags");
return true;
}
These controls allow UP flag to be not set while it's mandatory, as specified in the WebAuthn docs reported above.
In my opinion the "factorToFlags()" should be changed in order to always put UP flag in the array. Additionlly the factor "either" and "second" are not necessary. The function factorToFlags() could be rewritten in this way:
function factorToFlags(expectedFactor, flags) {
// var flags = ["AT"];
flags = flags || [];
switch (expectedFactor) {
case "first":
flags.push("UP");
flags.push("UV");
break;
case "second":
flags.push("UP");
break;
case "either":
flags.push("UP-or-UV");
break;
default:
throw new TypeError("expectedFactor should be 'first', 'second' or 'either'");
}
return flags;
}
and also the validateFlags() should be changed like following:
async function validateFlags() {
var expectedFlags = this.expectations.get("flags");
var flags = this.authnrData.get("flags");
for (let expFlag of expectedFlags) {
if (expFlag === "UP-or-UV") {
if (flags.has("UV")) {
if (flags.has("UP")) {
continue;
} else {
throw new Error("expected User Presence (UP) flag to be set if User Verification (UV) is set");
}
} else if (flags.has("UP")) {
continue;
} else {
throw new Error("expected User Presence (UP) or User Verification (UV) flag to be set and neither was");
}
}
if (expFlag === "UV") {
if (flags.has("UV")) {
if (flags.has("UP")) {
continue;
} else {
throw new Error("expected User Presence (UP) flag to be set if User Verification (UV) is set");
}
} else {
throw new Error(`expected flag was not set: ${expFlag}`);
}
}
if (!flags.has(expFlag)) {
throw new Error(`expected flag was not set: ${expFlag}`);
}
}
this.audit.journal.add("flags");
return true;
}
Do you agree with me? If so I can do a pull request to fix this.
Enrico Fabris.
I recently stared using this repo, however it seems the be stale, there are many open PR's solving various issues, @apowers313 is there any chance some of these can be merged, or could someone be appointed to manage this repo?
Hi, MDS2 is going to be deprecated this month, may I know if FIDO Metadata Service 3 is supported? If no, is there any roadmap to support MDS3?
Because of PeculiarVentures/node-webcrypto-ossl#121
david@david-Latitude-E6440:/tmp$ npm install node-webcrypto-ossl
> [email protected] install /tmp/node_modules/node-webcrypto-ossl
> node-gyp rebuild
make: Entering directory '/tmp/node_modules/node-webcrypto-ossl/build'
CXX(target) Release/obj.target/nodessl/src/main.o
CXX(target) Release/obj.target/nodessl/src/core/bn.o
../src/core/bn.cpp: In function โlong unsigned int read_word_padded(const BIGNUM*, size_t)โ:
../src/core/bn.cpp:33:17: error: invalid use of incomplete type โconst BIGNUM {aka const struct bignum_st}โ
BN_ULONG l = in->d[constant_time_select_ulong(
^~
In file included from /home/david/.node-gyp/10.0.0/include/node/openssl/bn.h:32:0,
from ../src/core/bn.h:5,
from ../src/core/bn.cpp:1:
/home/david/.node-gyp/10.0.0/include/node/openssl/ossl_typ.h:80:16: note: forward declaration of โBIGNUM {aka struct bignum_st}โ
typedef struct bignum_st BIGNUM;
^~~~~~~~~
../src/core/bn.cpp:34:29: error: invalid use of incomplete type โconst BIGNUM {aka const struct bignum_st}โ
constant_time_le_size_t(in->dmax, i), in->dmax - 1, i)];
^~
In file included from /home/david/.node-gyp/10.0.0/include/node/openssl/bn.h:32:0,
from ../src/core/bn.h:5,
from ../src/core/bn.cpp:1:
/home/david/.node-gyp/10.0.0/include/node/openssl/ossl_typ.h:80:16: note: forward declaration of โBIGNUM {aka struct bignum_st}โ
typedef struct bignum_st BIGNUM;
^~~~~~~~~
../src/core/bn.cpp:34:43: error: invalid use of incomplete type โconst BIGNUM {aka const struct bignum_st}โ
constant_time_le_size_t(in->dmax, i), in->dmax - 1, i)];
^~
In file included from /home/david/.node-gyp/10.0.0/include/node/openssl/bn.h:32:0,
from ../src/core/bn.h:5,
from ../src/core/bn.cpp:1:
/home/david/.node-gyp/10.0.0/include/node/openssl/ossl_typ.h:80:16: note: forward declaration of โBIGNUM {aka struct bignum_st}โ
typedef struct bignum_st BIGNUM;
^~~~~~~~~
../src/core/bn.cpp:36:62: error: invalid use of incomplete type โconst BIGNUM {aka const struct bignum_st}โ
return constant_time_select_ulong(constant_time_le_size_t(in->top, i), 0, l);
^~
In file included from /home/david/.node-gyp/10.0.0/include/node/openssl/bn.h:32:0,
from ../src/core/bn.h:5,
from ../src/core/bn.cpp:1:
/home/david/.node-gyp/10.0.0/include/node/openssl/ossl_typ.h:80:16: note: forward declaration of โBIGNUM {aka struct bignum_st}โ
typedef struct bignum_st BIGNUM;
^~~~~~~~~
../src/core/bn.cpp: In function โint BN_bn2bin_padded(uint8_t*, size_t, const BIGNUM*)โ:
../src/core/bn.cpp:49:16: error: invalid use of incomplete type โconst BIGNUM {aka const struct bignum_st}โ
if ((size_t)in->top > (len + (BN_BYTES - 1)) / BN_BYTES) {
^~
In file included from /home/david/.node-gyp/10.0.0/include/node/openssl/bn.h:32:0,
from ../src/core/bn.h:5,
from ../src/core/bn.cpp:1:
/home/david/.node-gyp/10.0.0/include/node/openssl/ossl_typ.h:80:16: note: forward declaration of โBIGNUM {aka struct bignum_st}โ
typedef struct bignum_st BIGNUM;
^~~~~~~~~
../src/core/bn.cpp: At global scope:
../src/core/bn.cpp:22:12: warning: โint constant_time_le_size_t(size_t, size_t)โ defined but not used [-Wunused-function]
static int constant_time_le_size_t(size_t x, size_t y) {
^~~~~~~~~~~~~~~~~~~~~~~
../src/core/bn.cpp:14:17: warning: โlong unsigned int constant_time_select_ulong(int, long unsigned int, long unsigned int)โ defined but not used [-Wunused-function]
static BN_ULONG constant_time_select_ulong(int v, BN_ULONG x, BN_ULONG y) {
^~~~~~~~~~~~~~~~~~~~~~~~~~
nodessl.target.mk:134: recipe for target 'Release/obj.target/nodessl/src/core/bn.o' failed
make: *** [Release/obj.target/nodessl/src/core/bn.o] Error 1
make: Leaving directory '/tmp/node_modules/node-webcrypto-ossl/build'
gyp ERR! build error
gyp ERR! stack Error: `make` failed with exit code: 2
gyp ERR! stack at ChildProcess.onExit (/home/david/.nvm/versions/node/v10.0.0/lib/node_modules/npm/node_modules/node-gyp/lib/build.js:258:23)
gyp ERR! stack at ChildProcess.emit (events.js:182:13)
gyp ERR! stack at Process.ChildProcess._handle.onexit (internal/child_process.js:225:12)
gyp ERR! System Linux 4.15.0-20-generic
gyp ERR! command "/home/david/.nvm/versions/node/v10.0.0/bin/node" "/home/david/.nvm/versions/node/v10.0.0/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js" "rebuild"
gyp ERR! cwd /tmp/node_modules/node-webcrypto-ossl
gyp ERR! node -v v10.0.0
gyp ERR! node-gyp -v v3.6.2
gyp ERR! not ok
npm WARN enoent ENOENT: no such file or directory, open '/tmp/package.json'
npm WARN tmp No description
npm WARN tmp No repository field.
npm WARN tmp No README data
npm WARN tmp No license field.
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] install: `node-gyp rebuild`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] install script.
This line:
https://github.com/apowers313/fido2-lib/blob/master/lib/parser.js#L102
var clientDataJson = String.fromCharCode.apply(null, new Uint8Array(clientDataJSON));
Won't this bust the stack if clientDataJSON
is long? Since this is client-supplied data, perhaps its length should be sanity checked?
I believe the webauthn spec allows rpId to be a registrable suffix of the origin domain, but https://github.com/apowers313/fido2-lib/blob/master/lib/validator.js#L365 only allows it to be exactly equal to the client origin domain.
Maybe Fido2Lib options.rpId should be used here, and rsl
might need to be checked to verify that options.rpId is a registrable suffix of clientDataJSON.origin.
The docs say this takes response.authenticatorData
. Should it be response.attestationObject
?
API for registering new extensions (e.g. - AppID, geo, etc.)
Support functions for loading and validating MDS data, and using MDS data for validating cert chains.
According to yubico docs in case of u2f migrated credentials the assertion challenge should include also appid
extension. In that case the credential manager in browser uses appid as rpId, and this is failing in validation of checkRpId or validateRpIdHash because it requires rp id to be a full domain aand not url, however credential manager uses full url of appid in such cases as rpId.
Cannot figure this one out...
All is ok with [email protected] - Error with [email protected]
verifyCertChain ...
rejects on empty arguments ... ok (13ms)
works for MDS2 ... FAILED (93ms)
Error: No revocation values found for one of certificates: No valid CRLs found
throw new Error(res.resultMessage);
^
at Function.verifyCertChain (/fido2-lib/lib/certUtils.js:587:10)
Failing test:
fido2-lib/test/certUtils.test.js
Line 531 in e60117e
Related certs available here:
fido2-lib/test/helpers/fido2-helpers.js
Line 4598 in e60117e
Failing line:
Line 587 in e60117e
Could it be related to this change in CertificateChainValidationEngine.js? Or something else?
After updating the library to 2.8.3 from 3.1.0.
We observer the following error:
error parsing ASN.1
We have not changed any parts of our code.
We use yubikeys 5 with this library.
Hi all,
Is it possible to mainline the Apple attestation format into this to create a sort of "commercial omnibus" canonical node library?
This might help/promote adoption?!
If you are open to external contribution and contributors -- I will definitely submit a PR for this!
Thanks,
David
Would be really nice if this lib supported Deno and moved away from CommonJS!
I'm experimenting on porting fido2-lib to a dual mode Node/Deno-lib on my own, and migrating everything to ES6 while at it. But I guess the changes are too big to "pull back" into this lib (?).
What need to be done/What I'm experimenting on:
Check out https://github.com/Hexagon/webauthn for ideas and inspiration, and please drop an issue of you find anything that doesn't look ok :)
Update 2022-04-25
https://github.com/Hexagon/webauthn is pretty much in sync with fido2-lib now.
dist/webauthn.js
). The bundle work in both Deno and Node, and it should technically work in browser too.I've also submitted a pull request with a Node-first/Dual platform version of fido2-lib at PR #80
Two alternatives, both support both Deno and Node :)
I'm having discussions with a FIDO2 authenticator manufacturer to get their public attestation key.
If they allow me can I PR the addition of the key in u2fRootCerts.js?
Would that make https://webauthn.org/ able to validate the attestation?
Right now it's giving me the boring:
warning: {
attesation-not-validated: "could not validate attestation because the root attestation certification could not be found",
},
clientDataJson
in Chrome Canary Version 68.0.3438.3 now has a hashAlgorithm
property. Should use this field if it is present.
{
"rawClientDataJson":"{\"challenge\":\"ICFGoPRC4FMPIKSX5cexUVwBzEX5H9KWnRYQZVCiGpesn59PzizxgLYQS_QRIy-TBYsRg1_zJ4hLpTNLeLUFiA\",\"clientExtensions\":{},\"hashAlgorithm\":\"SHA-256\",\"origin\":\"https://localhost:8443\",\"type\":\"webauthn.create\"}",
}
Make attestation formats into modules that can be registered -- enables loading of new attestation formats. Existing attestation formats should use this interface, but should probably be included by default. Also include a function to deregister attestation formats (so that default formats can be unloaded).
Like I have already registered key then try to register again then show me that the key already registered
please help me
Hi Adam,
I am trying to receive TPM attestation statement and that's why setting attestation:"direct" in create() but still fmt in response comes as "none". How we can instruct Authenticator (Windows Hello) to use TPM as cryptographic engine.
Does none means TPM is not used for cryptographic operation?
AAGUID coming as {08987058-cadc-4b81-b6e1-30de50dcbe96} which indicates hardware authenticator.
Regards,
Pooja
ECDSA signatures in ASN.1/DER format with an R or S that is not 32 bytes (this happens when the R/S have some number of leading zeros), are not verified properly.
This test can be used to reproduce this behavior:
// Testing lib
import * as chai from "chai";
import * as chaiAsPromised from "chai-as-promised";
import crypto from "crypto";
import { Fido2Lib } from "../lib/main.js";
chai.use(chaiAsPromised.default);
const assert = chai.assert;
const sha256 = (data) => {
return crypto.createHash("sha256").update(data).digest("hex");
};
const base64url = (buf) => {
return Buffer.from(buf).toString("base64url");
};
const base64urlToBuffer = (str) => {
return Buffer.from(str, "base64url");
};
const base64urlToArrayBuffer = (str) => {
const buf = base64urlToBuffer(str);
return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
};
const generateSignature = (authenticatorData, clientData, privateKey) => {
const dataHash = sha256(clientData);
const authenticatorDataHex = base64urlToBuffer(authenticatorData).toString("hex");
let signature;
do {
signature = new Uint8Array(
crypto.sign(
null,
Buffer.from(authenticatorDataHex + dataHash, "hex"),
privateKey
)
);
} while(signature[3] >= 32);
return base64url(signature);
};
const generateAuthenticatorData = () => {
const flags = 5;
const counter = 15;
const rpidHash = sha256("localhost", "hex");
const authData = Buffer.from(
rpidHash + flags.toString(16).padStart(2, "0") + counter.toString(16).padStart(8, "0"),
"hex"
);
return base64url(authData);
};
const generateInput = (privateKey) => {
const challenge = sha256("SomeRandomChallenge");
const clientData = JSON.stringify({
type: "webauthn.get",
challenge: base64url(challenge),
origin: "http://localhost:3000",
crossOrigin: false,
});
const authenticatorData = generateAuthenticatorData();
return {
credId: base64url("RandomCredId"),
clientData: base64url(clientData),
authenticatorData: authenticatorData,
signature: generateSignature(authenticatorData, clientData, privateKey),
userHandle: base64url("RandomUserId"),
};
};
describe("assertion", function() {
it("can verify a ECDSA signature with non-standard r / s", async function() {
const key = crypto.generateKeyPairSync("ec", { namedCurve: "P-256" });
const privateKey = key.privateKey.export({ type: "pkcs8", format:"pem" });
const publicKey = key.publicKey.export({ type: "spki", format:"pem" });
const input = generateInput(privateKey);
const fido2 = new Fido2Lib({
timeout: 42,
rpId: "localhost",
rpName: "localhost",
challengeSize: 128,
attestation: "direct",
cryptoParams: [-7, -257],
authenticatorRequireResidentKey: true,
authenticatorUserVerification: "required",
});
const challenge = sha256("SomeRandomChallenge");
const result = await fido2.assertionResult(
{
rawId: base64urlToArrayBuffer(input.credId),
response: {
clientDataJSON: input.clientData,
authenticatorData: base64urlToArrayBuffer(input.authenticatorData),
signature: input.signature,
userHandle: input.userHandle,
},
},
{
rpId: "localhost",
challenge: base64url(challenge),
origin: "http://localhost:3000",
factor: "first",
publicKey: publicKey,
prevCounter: 1,
userHandle: input.userHandle,
}
);
assert.strictEqual(result.audit.validRequest, true);
assert.strictEqual(result.audit.validExpectations, true);
});
});
The following error occurred when using MacBook TouchID as a authenticator.
Error: Server responed with error. The message is: packed attestation: self attestation not implemented, please open a GitHub issue.
Looks like fido2-lib doesn't support self-attestation.So we can not use TouchID as a authenticator.
Add AppID extension
Error: expected transports of allowCredentials[0] to be string with value 'usb', 'nfc', 'ble', 'internal' or null
at Fido2AssertionResult.validateExpectations (https://cdn.jsdelivr.net/npm/[email protected]/dist/main.js:53854:31)?
When using Chrome on computer, with a remote Android device as security key (over ble)- getTransports()
return cable
, which is not allowed by fido2-lib
Add an interface for removing default attestation formats (such as none
and fido-u2f
).
Library works great with chrome+ android phone as mfa, but when trying to register with windows hello I get: Error: packed attestation: unknown algorithm: -257
node_modules/fido2-lib/lib/attestations/packed.js:45:9
Is there any special configuration to setup for windows hello to work?
Found this project as the most full FIDO2 implementation but can't make it work for Android mobile app case.
The attestationResult
function throws the origin was malformatted
error because the origin is not a valid web-URL and not started with https
The clientDataJSON
is following for attestation and the same, but with "type": "webauthn.get"
for the assert:
{
"androidPackageName": "com.example.app",
"challenge": "CvPFgfKYZCkviLwzieQZBArgORy6ayCZ8ModjHYrl24FG_uzdSZkXEFBHpGPJ9agV9XksMeVyUkDKCg_-ZhCmOO1_JT-BAK52bjY60gSsx291Piqc30haY-Cf93levthvoQQG3YJ8yOALVS6I1VNEo23Z7vOpIXoloXauAMGN98",
"origin": "android:apk-key-hash:-sYXRdwJA3hvue3mKpYrOZ9zSPC7b4mbgzJmdZEDO5w",
"type": "webauthn.create",
}
Can some one advise, please, if it possible to configure this library or the short way to extend it to make it work?
Seems you at least incorrectly named this function. And in order to get serialNumber
would could use this code:
import { bufferToHexCodes } from "pvutils";
const serialNumber = bufferToHexCodes(certificate.serialNumber.valueBlock.valueHex);
or this one:
const serialNumber = certificate.serialNumber.valueBlock.toString(); // for decimal representation, even for huge serial numbers
I was wondering if we could use native webcrypto (available since Node 15).
This is because the node-webcrypto-ossl package has really old dependencies (using node-gyp 3.8.0 which uses python2)
Anyway since the browsers have to support fido on the client side also, I think it is worthwhile to also let the backend require a higher node version.
I tested on production the android-safetynet
attestation. However, it is not working as currently it is not doing any of the checks required by WebAuthn (https://www.w3.org/TR/webauthn/#android-safetynet-attestation) nor the androidSafetyNetValidateFn()
is returning true
.
I also detected this function also needs to include the changes in the journal for it work.
I'm making a PR with this tested changes here and in @JamesCullum fork. The changes woul be, namely:
nonce
and payload checksExpires On Sunday, 16 June 2019 at 14:45:01
I see package.json
is at 2.2.0 but npm is at 2.1.1.
Just wondered if you forgot to publish.
No worries if it's work in progress, feel free to close immediately.
Hi there,
I was interested in using the standard to implement both passwordless login as well as usernameless login, so I created a demo for it which allowed both forms: https://github.com/MxBlu/fido-poc
Unfortunately I've found that when requiring a resident key, the response cannot be parsed by the server using attestationResult()
:
Error: couldn't parse authenticator.authData.attestationData CBOR: Error: Data read, but end of buffer not reached
at PublicKey.fromCose (\x\fido-poc\backend\node_modules\fido2-lib\dist\main.cjs:1010:10)
at parseAuthenticatorData (\x\fido-poc\backend\node_modules\fido2-lib\dist\main.cjs:2898:19)
at parseAuthnrAttestationResponse (\x\fido-poc\backend\node_modules\fido2-lib\dist\main.cjs:2845:12)
at Fido2AttestationResult.parse (\x\fido-poc\backend\node_modules\fido2-lib\dist\main.cjs:3035:27)
at async Fido2AttestationResult.create (\x\fido-poc\backend\node_modules\fido2-lib\dist\main.cjs:3004:3)
at async Function.create (\x\fido-poc\backend\node_modules\fido2-lib\dist\main.cjs:3050:10)
at async Fido2Lib.attestationResult (\x\fido-poc\backend\node_modules\fido2-lib\dist\main.cjs:5465:10)
I can debug JS code, but decoding the CBOR response is out of my expertise sadly. Any insight would be much appreciated!
The issue can be reproduced with my demo by setting FIDO2_REQUIRE_RESIDENT_KEY = true
in backend/src/constants.ts
.
Options object passed to nagivator.credentials.create()
:
{
"publicKey": {
"rp": {
"name": "MxBlue Server",
"id": "fido.mxblue.net.au"
},
"user": {
"id": {},
"displayName": "mxblue",
"name": "mxblue-150822-3"
},
"challenge": {},
"pubKeyCredParams": [
{
"type": "public-key",
"alg": -7
},
{
"type": "public-key",
"alg": -257
}
],
"timeout": 120000,
"attestation": "none",
"authenticatorSelection": {
"requireResidentKey": true
}
}
}
Environment details:
Add fido-u2f attestation support
Create new error types for parsing, validation errors, so that server can return right HTTP status code depending on the type of failure.
Input strings should have a reasonable maximum length.
See also #11.
I am having trouble in understanding how exactly one would authenticate a user that wants to use multiple devices to log in.. Lets say a user has a mac laptop with touchId and a windows pc with a security key. I register on my laptop using my touch id. That generates a public key which is then saved, and I can log in just fine on my laptop. Now I switch to my PC and want to register. I understand that there is a allowCredentials
field, but I am not sure what is its use exactly. If I try to register on my PC, and save just the credential ID of that pc, but I try to log in using the public key generated from the laptop, I am guessing that will just fail, right? Would I need to also save an array of public keys, and try to authenticate with each one of them? Or maybe save which credential ID matches to which public key? This is just theory crafting as I unfortunately don't have multiple webauth capable devices around me to test right now, so sorry if this may be a dumb question
For some reason the library uses default console warn facility to print a message "Native crypto is enabled" without any explanation why this warning exists or if we expect users to do anything about this.
console.warn("[FIDO2-LIB] Native crypto is enabled");
can be found in at least 2 places in the codebase:
Line 27 in c38c2cc
Line 33 in c38c2cc
If this is needed information to the users we should improve the message to be more actionable OR we should remove the message.
Fixed in pull request: #32
authenticatorSelectionCriteria
The field authenticatorSelection is of type authenticatorSelectionCriteria but the name should be authenticatorSelection according to the w3c: authenticatorselection Changing the property name will make the userVerification working. Set the property to "required" and it enforces a PIN setup during attestation and asks for a pin during assertion. According to specs :-)
authenticatorAttachment
Changed property "attachment" into "authenticatorAttachment", is now also working for "platform" and "cross-platform" also tested and working now with both Solo & Yubi... well both devices are rejected when in platform mode and that is according to specs :-)
Unit tests updated
Add routes / message formats for conformance testing. Add a feature for enabling / disabling those routes.
When installing fido2-lib, if the python command is version 3, the following error will occur.
$ git clone https://github.com/apowers313/fido2-lib.git
$ cd fido2-lib/
$ npm install
npm WARN deprecated [email protected]: Jade has been renamed to pug, please install the latest version of pug instead of jade
npm WARN deprecated [email protected]: This package is unmaintained. Use @sinonjs/formatio instead
npm WARN deprecated [email protected]: to-iso-string has been deprecated, use @segment/to-iso-string instead.
npm WARN deprecated [email protected]: This package has been deprecated in favour of @sinonjs/samsam
npm WARN deprecated [email protected]: This package has been deprecated in favour of @sinonjs/samsam
npm WARN deprecated [email protected]: Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue
npm WARN deprecated [email protected]: This module moved to @hapi/hawk. Please make sure to switch over as this distribution is no longer supported and may contain bugs and critical security issues.
npm WARN deprecated [email protected]: This version has been deprecated in accordance with the hapi support policy (hapi.im/support). Please upgrade to the latest version to get the best features, bug fixes, and security patches. If you are unable to upgrade at this time, paid support is available for older versions (hapi.im/commercial).
npm WARN deprecated [email protected]: This version has been deprecated in accordance with the hapi support policy (hapi.im/support). Please upgrade to the latest version to get the best features, bug fixes, and security patches. If you are unable to upgrade at this time, paid support is available for older versions (hapi.im/commercial).
npm WARN deprecated [email protected]: This version has been deprecated in accordance with the hapi support policy (hapi.im/support). Please upgrade to the latest version to get the best features, bug fixes, and security patches. If you are unable to upgrade at this time, paid support is available for older versions (hapi.im/commercial).
npm WARN deprecated [email protected]: This module moved to @hapi/sntp. Please make sure to switch over as this distribution is no longer supported and may contain bugs and critical security issues.
> [email protected] install /private/tmp/fido2-lib/node_modules/node-webcrypto-ossl
> node-gyp rebuild
gyp ERR! configure error
gyp ERR! stack Error: Command failed: /Users/kg0r0/venv/bin/python -c import sys; print "%s.%s.%s" % sys.version_info[:3];
gyp ERR! stack File "<string>", line 1
gyp ERR! stack import sys; print "%s.%s.%s" % sys.version_info[:3];
gyp ERR! stack ^
gyp ERR! stack SyntaxError: invalid syntax
gyp ERR! stack
gyp ERR! stack at ChildProcess.exithandler (child_process.js:294:12)
gyp ERR! stack at ChildProcess.emit (events.js:189:13)
gyp ERR! stack at maybeClose (internal/child_process.js:970:16)
gyp ERR! stack at Socket.stream.socket.on (internal/child_process.js:389:11)
gyp ERR! stack at Socket.emit (events.js:189:13)
gyp ERR! stack at Pipe._handle.close (net.js:597:12)
gyp ERR! System Darwin 18.5.0
gyp ERR! command "/usr/local/bin/node" "/usr/local/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js" "rebuild"
gyp ERR! cwd /private/tmp/fido2-lib/node_modules/node-webcrypto-ossl
gyp ERR! node -v v10.15.3
gyp ERR! node-gyp -v v3.8.0
gyp ERR! not ok
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] install: `node-gyp rebuild`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] install script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
npm ERR! A complete log of this run can be found in:
npm ERR! /Users/kg0r0/.npm/_logs/2019-08-13T14_38_15_118Z-debug.log
Hi,
During npm install, it looks very "scary" with found 10 vulnerabilities (1 low, 6 moderate, 2 high, 1 critical), however its only good old obsolete istanbul generating all these depreciation errors. I'm lacking any knowledge of the auto build street what the impact is if I replace this with nyc.
Is there anybody who could just upgrade this to nyc 14.x so we get rid of these depreciation warnings... please?
JWR
> yarn add fido2-lib
yarn add v1.22.10
[1/4] ๐ Resolving packages...
warning fido2-lib > node-jose > [email protected]: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.
[2/4] ๐ Fetching packages...
[3/4] ๐ Linking dependencies...
warning " > [email protected]" has incorrect peer dependency "react@^17.0.2".
warning " > [email protected]" has incorrect peer dependency "react-dom@^17.0.2".
warning "@types/next > next > @next/[email protected]" has incorrect peer dependency "react@^17.0.2".
warning "@types/next > next > @next/[email protected]" has incorrect peer dependency "react-dom@^17.0.2".
warning "@types/next > next > [email protected]" has incorrect peer dependency "[email protected] || 16.x.x || 17.x.x".
warning "@types/next > next > [email protected]" has incorrect peer dependency "react@^16.8.0 || ^17.0.0".
warning " > [email protected]" has incorrect peer dependency "react@>=16.x <=17.x".
warning " > [email protected]" has incorrect peer dependency "react-dom@>=16.x <=17.x".
warning "next-mdx-remote > @mdx-js/[email protected]" has incorrect peer dependency "react@^16.13.1 || ^17.0.0".
warning " > [email protected]" has incorrect peer dependency "next@^8.1.1-canary.54 || ^9.0.0 || ^10.0.0".
warning " > [email protected]" has incorrect peer dependency "react@^16.0.0 || ^17.0.0".
warning " > [email protected]" has incorrect peer dependency "react-dom@^16.0.0 || ^17.0.0".
warning "eslint-config-next > @typescript-eslint/parser > @typescript-eslint/typescript-estree > [email protected]" has unmet peer dependency "typescript@>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta".
[4/4] ๐จ Building fresh packages...
[-/3] โ waiting...
[-/3] โ waiting...
error /Users/himself65/Code/Github/himself65.github.io/node_modules/node-webcrypto-ossl: Command failed.
Exit code: 1
Command: node-gyp rebuild
Arguments:
Directory: /Users/himself65/Code/Github/himself65.github.io/node_modules/node-webcrypto-ossl
Output:
gyp info it worked if it ends with ok
gyp info using [email protected]
gyp info using [email protected] | darwin | x64
gyp info find Python using Python version 3.9.5 found at "/usr/local/opt/[email protected]/bin/python3.9"
(node:12667) [DEP0150] DeprecationWarning: Setting process.config is deprecated. In the future the property will be read-only.
(Use `node --trace-deprecation ...` to show where the warning was created)
gyp info spawn /usr/local/opt/[email protected]/bin/python3.9
gyp info spawn args [
gyp info spawn args '/Users/himself65/.nvm/versions/node/v16.4.0/lib/node_modules/npm/node_modules/node-gyp/gyp/gyp_main.py',
gyp info spawn args 'binding.gyp',
gyp info spawn args '-f',
gyp info spawn args 'make',
gyp info spawn args '-I',
gyp info spawn args '/Users/himself65/Code/Github/himself65.github.io/node_modules/node-webcrypto-ossl/build/config.gypi',
gyp info spawn args '-I',
gyp info spawn args '/Users/himself65/.nvm/versions/node/v16.4.0/lib/node_modules/npm/node_modules/node-gyp/addon.gypi',
gyp info spawn args '-I',
gyp info spawn args '/Users/himself65/Library/Caches/node-gyp/16.4.0/include/node/common.gypi',
gyp info spawn args '-Dlibrary=shared_library',
gyp info spawn args '-Dvisibility=default',
gyp info spawn args '-Dnode_root_dir=/Users/himself65/Library/Caches/node-gyp/16.4.0',
gyp info spawn args '-Dnode_gyp_dir=/Users/himself65/.nvm/versions/node/v16.4.0/lib/node_modules/npm/node_modules/node-gyp',
gyp info spawn args '-Dnode_lib_file=/Users/himself65/Library/Caches/node-gyp/16.4.0/<(target_arch)/node.lib',
gyp info spawn args '-Dmodule_root_dir=/Users/himself65/Code/Github/himself65.github.io/node_modules/node-webcrypto-ossl',
gyp info spawn args '-Dnode_engine=v8',
gyp info spawn args '--depth=.',
gyp info spawn args '--no-parallel',
gyp info spawn args '--generator-output',
gyp info spawn args 'build',
gyp info spawn args '-Goutput_dir=.'
gyp info spawn args ]
gyp info spawn make
gyp info spawn args [ 'BUILDTYPE=Release', '-C', 'build' ]
CXX(target) Release/obj.target/nodessl/src/main.o
Apple clang version 13.0.0 (clang-1300.0.18.6)
Target: x86_64-apple-darwin21.0.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang" -cc1 -triple x86_64-apple-macosx10.7.0 -Wundef-prefix=TARGET_OS_ -Wdeprecated-objc-isa-usage -Werror=deprecated-objc-isa-usage -Werror=implicit-function-declaration -emit-obj --mrelax-relocations -disable-free -disable-llvm-verifier -discard-value-names -main-file-name main.cpp -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fno-strict-return -fno-rounding-math -munwind-tables -faligned-alloc-unavailable -target-sdk-version=12.0 -fvisibility-inlines-hidden-static-local-var -target-cpu core2 -tune-cpu generic -debug-info-kind=standalone -dwarf-version=2 -debugger-tuning=lldb -target-linker-version 705 -v -resource-dir /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/13.0.0 -dependency-file ./Release/.deps/Release/obj.target/nodessl/src/main.o.d.raw -skip-unused-modulemap-deps -MT Release/obj.target/nodessl/src/main.o -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk -D NODE_GYP_MODULE_NAME=nodessl -D USING_UV_SHARED=1 -D USING_V8_SHARED=1 -D V8_DEPRECATION_WARNINGS=1 -D V8_DEPRECATION_WARNINGS -D V8_IMMINENT_DEPRECATION_WARNINGS -D _GLIBCXX_USE_CXX11_ABI=1 -D _DARWIN_USE_64_BIT_INODE=1 -D _LARGEFILE_SOURCE -D _FILE_OFFSET_BITS=64 -D OPENSSL_NO_PINSHARED -D OPENSSL_THREADS -D BUILDING_NODE_EXTENSION -I /Users/himself65/Library/Caches/node-gyp/16.4.0/include/node -I /Users/himself65/Library/Caches/node-gyp/16.4.0/src -I /Users/himself65/Library/Caches/node-gyp/16.4.0/deps/openssl/config -I /Users/himself65/Library/Caches/node-gyp/16.4.0/deps/openssl/openssl/include -I /Users/himself65/Library/Caches/node-gyp/16.4.0/deps/uv/include -I /Users/himself65/Library/Caches/node-gyp/16.4.0/deps/zlib -I /Users/himself65/Library/Caches/node-gyp/16.4.0/deps/v8/include -I ../../nan -I/usr/local/include -stdlib=libc++ -stdlib=libc++ -internal-isystem /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/v1 -internal-isystem /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/local/include -internal-isystem /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/13.0.0/include -internal-externc-isystem /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include -internal-externc-isystem /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include -O3 -Wall -Wendif-labels -W -Wno-unused-parameter -Wno-reorder-init-list -Wno-implicit-int-float-conversion -Wno-c99-designator -Wno-final-dtor-non-final-class -Wno-extra-semi-stmt -Wno-misleading-indentation -Wno-quoted-include-in-framework-header -Wno-implicit-fallthrough -Wno-enum-enum-conversion -Wno-enum-float-conversion -Wno-elaborated-enum-base -std=c++11 -fdeprecated-macro -fdebug-compilation-dir /Users/himself65/Code/Github/himself65.github.io/node_modules/node-webcrypto-ossl/build -ferror-limit 19 -stack-protector 1 -mdarwin-stkchk-strong-link -fblocks -fencode-extended-block-signature -fno-rtti -fregister-global-dtors-with-atexit -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -fmax-type-align=16 -fcommon -vectorize-loops -vectorize-slp -clang-vendor-feature=+nullptrToBoolConversion -clang-vendor-feature=+messageToSelfInClassMethodIdReturnType -clang-vendor-feature=+disableInferNewAvailabilityFromInit -clang-vendor-feature=+disableNeonImmediateRangeCheck -clang-vendor-feature=+disableNonDependentMemberExprInCurrentInstantiation -fno-odr-hash-protocols -clang-vendor-feature=+revert09abecef7bbf -mllvm -disable-aligned-alloc-awareness=1 -mllvm -enable-dse-memoryssa=0 -o Release/obj.target/nodessl/src/main.o -x c++ ../src/main.cpp
clang -cc1 version 13.0.0 (clang-1300.0.18.6) default target x86_64-apple-darwin21.0.0
ignoring nonexistent directory "/Users/himself65/Library/Caches/node-gyp/16.4.0/src"
ignoring nonexistent directory "/Users/himself65/Library/Caches/node-gyp/16.4.0/deps/openssl/config"
ignoring nonexistent directory "/Users/himself65/Library/Caches/node-gyp/16.4.0/deps/openssl/openssl/include"
ignoring nonexistent directory "/Users/himself65/Library/Caches/node-gyp/16.4.0/deps/uv/include"
ignoring nonexistent directory "/Users/himself65/Library/Caches/node-gyp/16.4.0/deps/zlib"
ignoring nonexistent directory "/Users/himself65/Library/Caches/node-gyp/16.4.0/deps/v8/include"
ignoring nonexistent directory "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/local/include"
ignoring nonexistent directory "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/Library/Frameworks"
#include "..." search starts here:
#include <...> search starts here:
/Users/himself65/Library/Caches/node-gyp/16.4.0/include/node
../../nan
/usr/local/include
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/v1
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/13.0.0/include
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks (framework directory)
End of search list.
In file included from ../src/main.cpp:1:
In file included from ../src/node/common.h:4:
In file included from ../src/node/../core/common.h:8:
In file included from ../../nan/nan.h:56:
In file included from /Users/himself65/Library/Caches/node-gyp/16.4.0/include/node/node.h:63:
In file included from /Users/himself65/Library/Caches/node-gyp/16.4.0/include/node/v8.h:30:
/Users/himself65/Library/Caches/node-gyp/16.4.0/include/node/v8-internal.h:454:38: error: no template named 'remove_cv_t' in namespace 'std'; did you mean 'remove_cv'?
!std::is_same<Data, std::remove_cv_t<T>>::value>::Perform(data);
~~~~~^~~~~~~~~~~
remove_cv
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/v1/type_traits:776:50: note: 'remove_cv' declared here
template <class _Tp> struct _LIBCPP_TEMPLATE_VIS remove_cv
^
1 error generated.
make: *** [Release/obj.target/nodessl/src/main.o] Error 1
gyp ERR! build error
gyp ERR! stack Error: `make` failed with exit code: 2
gyp ERR! stack at ChildProcess.onExit (/Users/himself65/.nvm/versions/node/v16.4.0/lib/node_modules/npm/node_modules/node-gyp/lib/build.js:194:23)
gyp ERR! stack at ChildProcess.emit (node:events:394:28)
gyp ERR! stack at Process.ChildProcess._handle.onexit (node:internal/child_process:290:12)
gyp ERR! System Darwin 21.0.0
gyp ERR! command "/Users/himself65/.nvm/versions/node/v16.4.0/bin/node" "/Users/himself65/.nvm/versions/node/v16.4.0/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js" "rebuild"
gyp ERR! cwd /Users/himself65/Code/Github/himself65.github.io/node_modules/node-webcrypto-ossl
gyp ERR! node -v v16.4.0
gyp ERR! node-gyp -v v7.1.2
Hi @JamesCullum,
Currently the parseAuthenticatorData function throws and error if the "ED" flag is present in the authenticator data.
This behaviour blocks the parsing of the authenticatorData and the library fails.
I would like to propose a different approach: it's possible to parse the extension data as reported in this link and delegate the effective validation to a function in the validation process, as reported here. The reported validateExtensionData is very simple and in the future could be extended letting the user to provide their own function to validate extension data or could be improved to validate the most frequent extensions.
These changes allow to accept also authenticator data with extension.
What do you think? If you agree with me I'll complete the tests and then I'll create a PR.
Enrico.
In the case of localhost, there should be no problem even if it is not https.
Please note: both create() and get() require a Secure Context (e.g. - the server is connected by https or is the localhost), and will not be available for use if the browser is not operating in a secure context.
https://developer.mozilla.org/en-US/docs/Web/API/Web_Authentication_API
I think in the case of localhost should be excluded this error.
https://github.com/apowers313/fido2-lib/blob/7341fc49479bd736b1f1b57860bcec480d1ea744/lib/utils.js#L157-L159
I was implementing MDS according to the documentation which gives this example:
var mc = Fido2Lib.createMdsCollection()
// download TOC from https://mds.fidoalliance.org ...
var tocObj = await mc.addToc(tocBase64);
tocObj.entries.forEach((entry) => {
// download entry.url ...
mc.addEntry(entryBase64);
});
Fido2Lib.setMdsCollection(mc); // performs validation
var entry = Fido2Lib.findEntry("4e4e#4005");
After downloading the TOC from the provided url, I discovered that the default certificate was not valid, so I added the one provided. From there, I ran into more issues. The structure seems to be completely different than what is coded. I decoded the JWT so I could take a look for myself what the returned structure is. The library expects a hash in all of the entries, but there is no hash entry to be found. All of the data is also in a "metadataStatement" property, which I made sure to account for in my modified code. However, authenticationAlgorithm and publicKeyAlgAndEncoding are arrays and are plural in the returned data as well. They are also already strings in the arrays, which is not checked in the string conversion, making them "invalid" when they are just of an unexpected type. Then, when I tried to use findEntry it did not work with the AAGUID, which I had to convert to a hex to get. This was because the AAGUIDs in the map contained dashes, but the library tried to convert the security key's AAGUID to a base64 which matched none of the values in the map.
I am using a YubiKey 5 with NFC to test. Am I doing something completely wrong or is there an issue with the library?
My code:
const cert = "CERT HERE"
axios.get("https://mds.fidoalliance.org").then(async (response) => {
const tocObj = await mdsCollection.addToc(response.data, cert);
tocObj.entries.forEach((entry) => {
entry = entry.metadataStatement
entry.authenticationAlgorithm = entry.authenticationAlgorithms[0]
entry.publicKeyAlgAndEncoding = `ALG_KEY_${entry.publicKeyAlgAndEncodings[0].toUpperCase()}`
mdsCollection.addEntry(base64url.encode(JSON.stringify(entry)));
});
Fido2Lib.addMdsCollection(mdsCollection);
})
To get it to work, I had to edit the library to check if the algorithms and attestationTypes were a string before attempting to convert them. I also had to create a hash for the TOC entries rather than attempting to rely on a non-existent one. Last, I had to convert all the AAGUIDs to not contain dashes so the security key's AAGUID (hex value) would match.
I'm getting an error, authnrData rawAuthnrData should be ArrayBuffer
, when calling assertionResult
. I passed everything required in the docs to the function.
Hi, I'm creating an issue here documenting the mismatch in specs and then making a quick PR.
I get the error when running assertionResult(response)
:
TypeError: expected 'response.userHandle' to be base64 String, ArrayBuffer, or undefined
response.userHandle
is set to null
I modified the validateAssertionResponse
function to validate the type internally
throw new TypeError(`expected 'response.userHandle' to be base64 String, ArrayBuffer, or undefined got ${req.response.userHandle}`);
which returns:
... got null
So I'm wondering if we should allow null? Any foreseen consequences?
According to the level 3 and level 2 docs, userHandle
nullable, and should be accepted?
https://w3c.github.io/webauthn/#dom-authenticatorassertionresponse-userhandle
https://www.w3.org/TR/webauthn-2/#dom-authenticatorassertionresponse-userhandle
I'm using import { get } from '@github/webauthn-json/browser-ponyfill'
to sign the decoded PublicKeyCredentialRequestOptions
from the server. This PublicKeyCredentialRequestOptions contains a list of allowCredentials (~3), some of which do not correspond to resident keys.
The userHandle is only set if I sign using a residentKey, if not, I get the TypeError on the server side.
It may be good to allow null, if we agree this is applicable to spec.
Thanks!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.