| <!DOCTYPE html><!-- webkit-test-runner [ WebAuthenticationModernEnabled=false allowTestOnlyIPC=true ] --> |
| <title>Web Authentication API: PublicKeyCredential's [[create]] success cases with a mock local authenticator.</title> |
| <script src="/resources/testharness.js"></script> |
| <script src="/resources/testharnessreport.js"></script> |
| <script src="./resources/util.js"></script> |
| <script src="./resources/cbor.js"></script> |
| <script> |
| async function checkResult(credential, credentialID, isUV = true, isUP = true) |
| { |
| // Check keychain |
| if (window.testRunner) { |
| assert_true(await testRunner.keyExistsInKeychain(testRpId, base64encode(credentialID))); |
| testRunner.cleanUpKeychain(testRpId, base64encode(credentialID)); |
| } |
| |
| // Check respond |
| assert_array_equals(Base64URL.parse(credential.id), credentialID); |
| assert_equals(credential.type, 'public-key'); |
| assert_array_equals(new Uint8Array(credential.rawId), credentialID); |
| assert_equals(bytesToASCIIString(credential.response.clientDataJSON), '{"type":"webauthn.create","challenge":"MTIzNDU2","origin":"https://localhost:9443"}'); |
| assert_not_own_property(credential.getClientExtensionResults(), "appid"); |
| |
| // Check attestation |
| const attestationObject = CBOR.decode(credential.response.attestationObject); |
| assert_equals(attestationObject.fmt, "none"); |
| // Check authData |
| const authData = decodeAuthData(attestationObject.authData); |
| assert_equals(bytesToHexString(authData.rpIdHash), "49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d9763"); |
| let expectedFlags = 64; |
| if (isUP) |
| expectedFlags |= 1; |
| if (isUV) |
| expectedFlags |= 4; |
| assert_equals(expectedFlags, authData.flags); |
| assert_equals(authData.counter, 0); |
| assert_equals("fbfc3007154e4ecc8c0b6e020557d7bd", bytesToHexString(authData.aaguid)); |
| assert_array_equals(authData.credentialID, credentialID); |
| // Check self attestation |
| assert_true(checkPublicKey(authData.publicKey)); |
| assert_object_equals(attestationObject.attStmt, { }); |
| } |
| |
| promise_test(async t => { |
| const privateKeyBase64 = await generatePrivateKeyBase64(); |
| const credentialID = await calculateCredentialID(privateKeyBase64); |
| const userhandleBase64 = generateUserhandleBase64(); |
| if (window.internals) |
| internals.setMockWebAuthenticationConfiguration({ |
| local: { |
| userVerification: "yes", |
| acceptAttestation: false, |
| privateKeyBase64: privateKeyBase64, |
| } |
| }); |
| |
| const options = { |
| publicKey: { |
| rp: { |
| name: "localhost", |
| }, |
| user: { |
| name: userhandleBase64, |
| id: Base64URL.parse(userhandleBase64), |
| displayName: "Appleseed", |
| }, |
| challenge: Base64URL.parse("MTIzNDU2"), |
| pubKeyCredParams: [{ type: "public-key", alg: -7 }], |
| } |
| }; |
| |
| return navigator.credentials.create(options).then(credential => { |
| checkResult(credential, credentialID); |
| }); |
| }, "PublicKeyCredential's [[create]] with minimum options in a mock local authenticator."); |
| |
| promise_test(async t => { |
| const privateKeyBase64 = "BKeelnM8D7ykBNa79wacy6FW8UYZ+PG0Cr2Dr4Rzo+qJHExNkPVdzQ1/hjrqg8iY3IzM/NUvJJOzmtuchS6TLqTfzmsXsVdApUn9kx4Lh/cv01hbXt7/Q8kAbubi8Mqmqw=="; |
| const userhandleBase64 = generateUserhandleBase64(); |
| if (window.internals) |
| internals.setMockWebAuthenticationConfiguration({ |
| local: { |
| userVerification: "yes", |
| acceptAttestation: false, |
| privateKeyBase64: privateKeyBase64, |
| } |
| }); |
| |
| const options = { |
| publicKey: { |
| rp: { |
| name: "localhost", |
| }, |
| user: { |
| name: userhandleBase64, |
| id: Base64URL.parse(userhandleBase64), |
| displayName: "Appleseed", |
| }, |
| challenge: Base64URL.parse("MTIzNDU2"), |
| pubKeyCredParams: [{ type: "public-key", alg: -7 }], |
| } |
| }; |
| |
| return navigator.credentials.create(options).then(credential => { |
| assert_equals(bytesToHexString(credential.response.getPublicKey()), "3059301306072a8648ce3d020106082a8648ce3d03010703420004a79e96733c0fbca404d6bbf7069ccba156f14619f8f1b40abd83af8473a3ea891c4c4d90f55dcd0d7f863aea83c898dc8cccfcd52f2493b39adb9c852e932ea4"); |
| assert_equals(credential.response.getPublicKeyAlgorithm(), -7); |
| }); |
| }, "PublicKeyCredential's [[create]] with minimum options in a mock local authenticator checking getPublicKey()"); |
| |
| promise_test(async t => { |
| const privateKeyBase64 = await generatePrivateKeyBase64(); |
| const credentialID = await calculateCredentialID(privateKeyBase64); |
| const userhandleBase64 = generateUserhandleBase64(); |
| if (window.internals) |
| internals.setMockWebAuthenticationConfiguration({ |
| local: { |
| userVerification: "yes", |
| acceptAttestation: false, |
| privateKeyBase64: privateKeyBase64, |
| } |
| }); |
| |
| const options = { |
| publicKey: { |
| rp: { |
| name: "localhost", |
| }, |
| user: { |
| name: userhandleBase64, |
| id: Base64URL.parse(userhandleBase64), |
| displayName: "Appleseed", |
| }, |
| challenge: Base64URL.parse("MTIzNDU2"), |
| pubKeyCredParams: [{ type: "public-key", alg: -7 }], |
| authenticatorSelection: { authenticatorAttachment: "platform" } |
| } |
| }; |
| |
| return navigator.credentials.create(options).then(credential => { |
| checkResult(credential, credentialID); |
| }); |
| }, "PublicKeyCredential's [[create]] with authenticatorSelection { 'platform' } in a mock local authenticator."); |
| |
| promise_test(async t => { |
| const privateKeyBase64 = await generatePrivateKeyBase64(); |
| const credentialID = await calculateCredentialID(privateKeyBase64); |
| const userhandleBase64 = generateUserhandleBase64(); |
| if (window.internals) |
| internals.setMockWebAuthenticationConfiguration({ |
| local: { |
| userVerification: "yes", |
| acceptAttestation: false, |
| privateKeyBase64: privateKeyBase64, |
| } |
| }); |
| |
| const anotherPrivateKeyBase64 = await generatePrivateKeyBase64(); |
| const anotherCredentialID = await calculateCredentialID(anotherPrivateKeyBase64); |
| const options = { |
| publicKey: { |
| rp: { |
| name: "example.com" |
| }, |
| user: { |
| name: userhandleBase64, |
| id: Base64URL.parse(userhandleBase64), |
| displayName: "John", |
| }, |
| challenge: asciiToUint8Array("123456"), |
| pubKeyCredParams: [{ type: "public-key", alg: -7 }], |
| excludeCredentials: [ |
| { type: "public-key", id: anotherCredentialID, transports: ["usb"] }, |
| { type: "public-key", id: anotherCredentialID, transports: ["nfc"] }, |
| { type: "public-key", id: anotherCredentialID, transports: ["ble"] } |
| ] |
| } |
| }; |
| if (window.testRunner) |
| testRunner.addTestKeyToKeychain(anotherPrivateKeyBase64, testRpId, testUserEntityBundleBase64); |
| |
| return navigator.credentials.create(options).then(credential => { |
| checkResult(credential, credentialID); |
| if (window.testRunner) |
| testRunner.cleanUpKeychain(testRpId, base64encode(anotherCredentialID)); |
| }); |
| }, "PublicKeyCredential's [[create]] with matched exclude credential ids but not transports in a mock local authenticator."); |
| |
| promise_test(async t => { |
| const privateKeyBase64 = await generatePrivateKeyBase64(); |
| const credentialID = await calculateCredentialID(privateKeyBase64); |
| const userhandleBase64 = generateUserhandleBase64(); |
| if (window.internals) |
| internals.setMockWebAuthenticationConfiguration({ |
| local: { |
| userVerification: "yes", |
| acceptAttestation: false, |
| privateKeyBase64: privateKeyBase64, |
| } |
| }); |
| |
| const options = { |
| publicKey: { |
| rp: { |
| name: "localhost", |
| }, |
| user: { |
| name: userhandleBase64, |
| id: Base64URL.parse(userhandleBase64), |
| displayName: "Appleseed", |
| }, |
| challenge: Base64URL.parse("MTIzNDU2"), |
| pubKeyCredParams: [{ type: "public-key", alg: -7 }], |
| attestation: "none" |
| } |
| }; |
| |
| return navigator.credentials.create(options).then(credential => { |
| checkResult(credential, credentialID); |
| }); |
| }, "PublicKeyCredential's [[create]] with none attestation in a mock local authenticator."); |
| |
| promise_test(async t => { |
| const privateKeyBase64 = await generatePrivateKeyBase64(); |
| const credentialID = await calculateCredentialID(privateKeyBase64); |
| const userhandleBase64 = generateUserhandleBase64(); |
| if (window.internals) |
| internals.setMockWebAuthenticationConfiguration({ |
| local: { |
| userVerification: "yes", |
| acceptAttestation: true, |
| privateKeyBase64: privateKeyBase64, |
| userCertificateBase64: testAttestationCertificateBase64, |
| intermediateCACertificateBase64: testAttestationIssuingCACertificateBase64 |
| } |
| }); |
| |
| const options = { |
| publicKey: { |
| rp: { |
| name: "localhost", |
| }, |
| user: { |
| name: userhandleBase64, |
| id: Base64URL.parse(userhandleBase64), |
| displayName: "Appleseed", |
| }, |
| challenge: Base64URL.parse("MTIzNDU2"), |
| pubKeyCredParams: [{ type: "public-key", alg: -7 }], |
| attestation: "indirect" |
| } |
| }; |
| |
| return navigator.credentials.create(options).then(credential => { |
| checkResult(credential, credentialID); |
| }); |
| }, "PublicKeyCredential's [[create]] with indirect attestation in a mock local authenticator."); |
| |
| promise_test(async t => { |
| const privateKeyBase64 = await generatePrivateKeyBase64(); |
| const credentialID = await calculateCredentialID(privateKeyBase64); |
| const userhandleBase64 = generateUserhandleBase64(); |
| if (window.internals) |
| internals.setMockWebAuthenticationConfiguration({ |
| local: { |
| userVerification: "yes", |
| acceptAttestation: true, |
| privateKeyBase64: privateKeyBase64, |
| userCertificateBase64: testAttestationCertificateBase64, |
| intermediateCACertificateBase64: testAttestationIssuingCACertificateBase64 |
| } |
| }); |
| |
| const options = { |
| publicKey: { |
| rp: { |
| name: "localhost", |
| }, |
| user: { |
| name: userhandleBase64, |
| id: Base64URL.parse(userhandleBase64), |
| displayName: "Appleseed", |
| }, |
| challenge: Base64URL.parse("MTIzNDU2"), |
| pubKeyCredParams: [{ type: "public-key", alg: -7 }], |
| attestation: "direct" |
| } |
| }; |
| |
| return navigator.credentials.create(options).then(credential => { |
| checkResult(credential, credentialID, true); |
| }); |
| }, "PublicKeyCredential's [[create]] with direct attestation in a mock local authenticator."); |
| |
| promise_test(async t => { |
| const privateKeyBase64 = await generatePrivateKeyBase64(); |
| const credentialID = await calculateCredentialID(privateKeyBase64); |
| const userhandleBase64 = generateUserhandleBase64(); |
| if (window.internals) |
| internals.setMockWebAuthenticationConfiguration({ |
| local: { |
| userVerification: "yes", |
| acceptAttestation: false, |
| privateKeyBase64: privateKeyBase64, |
| } |
| }); |
| |
| const options = { |
| publicKey: { |
| rp: { |
| name: "localhost", |
| }, |
| user: { |
| name: userhandleBase64, |
| id: Base64URL.parse(userhandleBase64), |
| displayName: "Appleseed", |
| }, |
| challenge: Base64URL.parse("MTIzNDU2"), |
| pubKeyCredParams: [{ type: "public-key", alg: -7 }], |
| } |
| }; |
| |
| const anotherPrivateKeyBase64 = await generatePrivateKeyBase64(); |
| const anotherCredentialID = await calculateCredentialID(anotherPrivateKeyBase64); |
| if (window.internals) |
| testRunner.addTestKeyToKeychain(anotherPrivateKeyBase64, testRpId, base64encode(CBOR.encode({ "id": Base64URL.parse(userhandleBase64), "name": userhandleBase64 }))); |
| |
| return navigator.credentials.create(options).then(async (credential) => { |
| checkResult(credential, credentialID, true); |
| assert_false(await testRunner.keyExistsInKeychain(testRpId, base64encode(anotherCredentialID))); |
| }); |
| }, "PublicKeyCredential's [[create]] with duplicate credential in a mock local authenticator."); |
| |
| promise_test(async t => { |
| const privateKeyBase64 = await generatePrivateKeyBase64(); |
| const credentialID = await calculateCredentialID(privateKeyBase64); |
| const userhandleBase64 = generateUserhandleBase64(); |
| if (window.internals) |
| internals.setMockWebAuthenticationConfiguration({ |
| local: { |
| userVerification: "yes", |
| acceptAttestation: true, |
| privateKeyBase64: privateKeyBase64, |
| userCertificateBase64: testAttestationCertificateBase64, |
| intermediateCACertificateBase64: testAttestationIssuingCACertificateBase64 |
| } |
| }); |
| |
| const options = { |
| publicKey: { |
| rp: { |
| name: "localhost", |
| }, |
| user: { |
| name: userhandleBase64, |
| id: Base64URL.parse(userhandleBase64), |
| displayName: "Appleseed", |
| }, |
| challenge: Base64URL.parse("MTIzNDU2"), |
| pubKeyCredParams: [{ type: "public-key", alg: -7 }], |
| attestation: "direct" |
| } |
| }; |
| |
| const anotherPrivateKeyBase64 = await generatePrivateKeyBase64(); |
| const anotherCredentialID = await calculateCredentialID(anotherPrivateKeyBase64); |
| if (window.internals) |
| testRunner.addTestKeyToKeychain(anotherPrivateKeyBase64, testRpId, base64encode(CBOR.encode({ "id": Base64URL.parse(userhandleBase64), "name": userhandleBase64 }))); |
| |
| return navigator.credentials.create(options).then(async (credential) => { |
| checkResult(credential, credentialID, true); |
| assert_false(await testRunner.keyExistsInKeychain(testRpId, base64encode(anotherCredentialID))); |
| }); |
| }, "PublicKeyCredential's [[create]] with duplicate credential in a mock local authenticator. 2"); |
| |
| promise_test(async t => { |
| const privateKeyBase64 = await generatePrivateKeyBase64(); |
| const credentialID = await calculateCredentialID(privateKeyBase64); |
| const userhandleBase64 = generateUserhandleBase64(); |
| if (window.internals) |
| internals.setMockWebAuthenticationConfiguration({ |
| local: { |
| userVerification: "presence", |
| acceptAttestation: false, |
| privateKeyBase64: privateKeyBase64, |
| } |
| }); |
| |
| const options = { |
| publicKey: { |
| rp: { |
| name: "localhost", |
| }, |
| user: { |
| name: userhandleBase64, |
| id: Base64URL.parse(userhandleBase64), |
| displayName: "Appleseed", |
| }, |
| challenge: Base64URL.parse("MTIzNDU2"), |
| pubKeyCredParams: [{ type: "public-key", alg: -7 }], |
| } |
| }; |
| |
| return navigator.credentials.create(options).then(credential => { |
| checkResult(credential, credentialID, false); |
| }); |
| }, "PublicKeyCredential's [[create]] with user presence in a mock local authenticator."); |
| |
| promise_test(async t => { |
| const privateKeyBase64 = await generatePrivateKeyBase64(); |
| const credentialID = await calculateCredentialID(privateKeyBase64); |
| const userhandleBase64 = generateUserhandleBase64(); |
| if (window.internals) |
| internals.setMockWebAuthenticationConfiguration({ |
| local: { |
| userVerification: "presence", |
| acceptAttestation: false, |
| privateKeyBase64: privateKeyBase64, |
| } |
| }); |
| |
| const options = { |
| publicKey: { |
| rp: { |
| name: "localhost", |
| }, |
| user: { |
| name: userhandleBase64, |
| id: Base64URL.parse(userhandleBase64), |
| displayName: "Appleseed", |
| }, |
| challenge: Base64URL.parse("MTIzNDU2"), |
| pubKeyCredParams: [{ type: "public-key", alg: -7 }], |
| }, |
| mediation: "conditional", |
| }; |
| |
| return navigator.credentials.create(options).then(credential => { |
| checkResult(credential, credentialID, false, false); |
| }); |
| }, "PublicKeyCredential's [[create]] with conditional mediation mock local authenticator."); |
| </script> |