| <!DOCTYPE html> |
| <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> |
| // Default mock configuration. Tests need to override if they need different configuration. |
| if (window.testRunner) |
| testRunner.setWebAuthenticationMockConfiguration({ |
| local: { |
| acceptAuthentication: true, |
| acceptAttestation: true, |
| privateKeyBase64: testES256PrivateKeyBase64, |
| userCertificateBase64: testAttestationCertificateBase64, |
| intermediateCACertificateBase64: testAttestationIssuingCACertificateBase64 |
| } |
| }); |
| |
| function checkResult(credential) |
| { |
| // Check keychain |
| if (window.testRunner) { |
| assert_true(testRunner.keyExistsInKeychain(testRpId, testUserhandleBase64)); |
| testRunner.cleanUpKeychain(testRpId); |
| } |
| |
| // Check respond |
| assert_array_equals(Base64URL.parse(credential.id), Base64URL.parse(testCredentialIdBase64)); |
| assert_equals(credential.type, 'public-key'); |
| assert_array_equals(new Uint8Array(credential.rawId), Base64URL.parse(testCredentialIdBase64)); |
| assert_equals(bytesToASCIIString(credential.response.clientDataJSON), '{"type":"webauthn.create","challenge":"MTIzNDU2","origin":"https://localhost:9443"}'); |
| assert_not_exists(credential.getClientExtensionResults(), "appid"); |
| |
| // Check attestation |
| const attestationObject = CBOR.decode(credential.response.attestationObject); |
| assert_equals(attestationObject.fmt, "Apple"); |
| // Check authData |
| const authData = decodeAuthData(attestationObject.authData); |
| assert_equals(bytesToHexString(authData.rpIdHash), "49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d9763"); |
| assert_equals(authData.flags, 69); |
| assert_equals(authData.counter, 0); |
| assert_equals(bytesToHexString(authData.aaguid), "00000000000000000000000000000000"); |
| assert_array_equals(authData.credentialID, Base64URL.parse(testCredentialIdBase64)); |
| // Check self attestation |
| assert_equals(attestationObject.attStmt.alg, -7); |
| assert_true(checkPublicKey(authData.publicKey)); |
| assert_equals(attestationObject.attStmt.x5c.length, 2); |
| assert_array_equals(attestationObject.attStmt.x5c[0], Base64URL.parse(testAttestationCertificateBase64)); |
| assert_array_equals(attestationObject.attStmt.x5c[1], Base64URL.parse(testAttestationIssuingCACertificateBase64)); |
| |
| // Check signature |
| let publicKeyData = new Uint8Array(65); |
| publicKeyData[0] = 0x04; |
| publicKeyData.set(authData.publicKey['-2'], 1); |
| publicKeyData.set(authData.publicKey['-3'], 33); |
| return crypto.subtle.importKey("raw", publicKeyData, { name: "ECDSA", namedCurve: "P-256" }, false, ['verify']).then( publicKey => { |
| return crypto.subtle.verify({name: "ECDSA", hash: "SHA-256"}, publicKey, extractRawSignature(attestationObject.attStmt.sig), attestationObject.authData).then( verified => { |
| assert_true(verified); |
| }); |
| }); |
| } |
| |
| promise_test(t => { |
| const options = { |
| publicKey: { |
| rp: { |
| name: "localhost", |
| }, |
| user: { |
| name: "John Appleseed", |
| id: Base64URL.parse(testUserhandleBase64), |
| displayName: "Appleseed", |
| }, |
| challenge: Base64URL.parse("MTIzNDU2"), |
| pubKeyCredParams: [{ type: "public-key", alg: -7 }], |
| } |
| }; |
| |
| return navigator.credentials.create(options).then(credential => { |
| checkResult(credential); |
| }); |
| }, "PublicKeyCredential's [[create]] with minimum options in a mock local authenticator."); |
| |
| promise_test(t => { |
| const options = { |
| publicKey: { |
| rp: { |
| name: "localhost", |
| }, |
| user: { |
| name: "John Appleseed", |
| id: Base64URL.parse(testUserhandleBase64), |
| displayName: "Appleseed", |
| }, |
| challenge: Base64URL.parse("MTIzNDU2"), |
| pubKeyCredParams: [{ type: "public-key", alg: -7 }], |
| authenticatorSelection: { authenticatorAttachment: "platform" } |
| } |
| }; |
| |
| return navigator.credentials.create(options).then(credential => { |
| checkResult(credential); |
| }); |
| }, "PublicKeyCredential's [[create]] with authenticatorSelection { 'platform' } in a mock local authenticator."); |
| |
| promise_test(t => { |
| const options = { |
| publicKey: { |
| rp: { |
| name: "example.com" |
| }, |
| user: { |
| name: "John Appleseed", |
| id: Base64URL.parse(testUserhandleBase64), |
| displayName: "John", |
| }, |
| challenge: asciiToUint8Array("123456"), |
| pubKeyCredParams: [{ type: "public-key", alg: -7 }], |
| excludeCredentials: [ |
| { type: "public-key", id: Base64URL.parse(testCredentialIdBase64), transports: ["usb"] }, |
| { type: "public-key", id: Base64URL.parse(testCredentialIdBase64), transports: ["nfc"] }, |
| { type: "public-key", id: Base64URL.parse(testCredentialIdBase64), transports: ["ble"] } |
| ] |
| } |
| }; |
| if (window.testRunner) |
| testRunner.addTestKeyToKeychain(testES256PrivateKeyBase64, testRpId, testUserhandleBase64); |
| |
| return navigator.credentials.create(options).then(credential => { |
| checkResult(credential); |
| }); |
| }, "PublicKeyCredential's [[create]] with matched exclude credential ids but not transports in a mock local authenticator."); |
| </script> |