blob: 9b74c8c89082c2c5623352078019e47c04021a17 [file] [edit]
<!DOCTYPE html><!-- webkit-test-runner [ WebAuthenticationModernEnabled=true allowTestOnlyIPC=true ] -->
<title>Web Authentication API: PublicKeyCredential's [[create]] success cases with a mock hid 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.internals)
internals.setMockWebAuthenticationConfiguration({ hid: { stage: "request", subStage: "msg", error: "success", payloadBase64: [testCreationMessageBase64], pinProtocols: [1] } });
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: { residentKey: "required" },
timeout: 1000
}
};
const expected = {
"authenticatorAttachment" : "cross-platform",
"clientExtensionResults" : { "credProps" : { "rk" : false } },
"id" : "KAitzuj-Tslzelf3_vZwIGtDQNgoKeFd5oEieYzhyzA65saf0tK2w_mooa7tQtGgDdwZIjOhjcuZ0pQ1ajoE4A",
"rawId" : "KAitzuj-Tslzelf3_vZwIGtDQNgoKeFd5oEieYzhyzA65saf0tK2w_mooa7tQtGgDdwZIjOhjcuZ0pQ1ajoE4A",
"response" : {
"attestationObject" : "o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVjERsx_uWedVbLbkJLhyNnl4dArdYDwtIEsdwli4eSPWthBAAAATgAAAAAAAAAAAAAAAAAAAAAAQCgIrc7o_k7Jc3pX9_72cCBrQ0DYKCnhXeaBInmM4cswOubGn9LStsP5qKGu7ULRoA3cGSIzoY3LmdKUNWo6BOClAQIDJiABIVggQVuF7dGQ253qyDKtoEaOWHWnNOUJl6FCUv9vXwdnpYYiWCAmB9R396f2nkAioxBtSeKcR5d0UuS9bT_NXkGkSOM3EA",
"authenticatorData" : "Rsx_uWedVbLbkJLhyNnl4dArdYDwtIEsdwli4eSPWthBAAAATgAAAAAAAAAAAAAAAAAAAAAAQCgIrc7o_k7Jc3pX9_72cCBrQ0DYKCnhXeaBInmM4cswOubGn9LStsP5qKGu7ULRoA3cGSIzoY3LmdKUNWo6BOClAQIDJiABIVggQVuF7dGQ253qyDKtoEaOWHWnNOUJl6FCUv9vXwdnpYYiWCAmB9R396f2nkAioxBtSeKcR5d0UuS9bT_NXkGkSOM3EA",
"clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoiTVRJek5EVTIiLCJvcmlnaW4iOiJodHRwczovL2xvY2FsaG9zdDo5NDQzIn0",
"publicKey": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEQVuF7dGQ253qyDKtoEaOWHWnNOUJl6FCUv9vXwdnpYYmB9R396f2nkAioxBtSeKcR5d0UuS9bT_NXkGkSOM3EA",
"publicKeyAlgorithm" : -7,
"transports" : [ "usb" ]
},
"type" : "public-key"
};
return navigator.credentials.create(options).then(credential => {
assert_equals(JSON.stringify(expected), JSON.stringify(credential.toJSON()));
checkCtapMakeCredentialResult(credential);
});
}, "PublicKeyCredential's [[create]] calling toJSON on the result.");
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 }],
timeout: 1000
}
};
return navigator.credentials.create(options).then(credential => {
checkCtapMakeCredentialResult(credential, true, ["usb"]);
});
}, "PublicKeyCredential's [[create]] with minimum options in a mock hid authenticator.");
promise_test(t => {
const options = {
publicKey: {
rp: {
name: "localhost",
},
user: {
name: "John Appleseed",
id: asciiToUint8Array("1"),
displayName: "Appleseed",
},
challenge: Base64URL.parse("MTIzNDU2"),
pubKeyCredParams: [{ type: "public-key", alg: -7 }],
timeout: 1000
}
};
return navigator.credentials.create(options).then(credential => {
checkCtapMakeCredentialResult(credential, true, ["usb"]);
});
}, "PublicKeyCredential's [[create]] with user handle of length=1 in a mock hid authenticator.");
promise_test(t => {
const options = {
publicKey: {
rp: {
name: "localhost",
},
user: {
name: "John Appleseed",
id: asciiToUint8Array("1234567812345678123456781234567812345678123456781234567812345678"),
displayName: "Appleseed",
},
challenge: Base64URL.parse("MTIzNDU2"),
pubKeyCredParams: [{ type: "public-key", alg: -7 }],
timeout: 1000
}
};
return navigator.credentials.create(options).then(credential => {
checkCtapMakeCredentialResult(credential, true, ["usb"]);
});
}, "PublicKeyCredential's [[create]] with user handle of length=64 in a mock hid 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: [],
timeout: 1000
}
};
return navigator.credentials.create(options).then(credential => {
checkCtapMakeCredentialResult(credential);
});
}, "PublicKeyCredential's [[create]] with empty pubKeyCredParams in a mock hid 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: "cross-platform" },
timeout: 1000
}
};
return navigator.credentials.create(options).then(credential => {
checkCtapMakeCredentialResult(credential);
});
}, "PublicKeyCredential's [[create]] with authenticatorSelection { 'cross-platform' } in a mock hid 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: { requireResidentKey: false },
timeout: 1000
}
};
return navigator.credentials.create(options).then(credential => {
checkCtapMakeCredentialResult(credential);
});
}, "PublicKeyCredential's [[create]] with requireResidentKey { false } in a mock hid 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: { residentKey: "discouraged" },
timeout: 1000
}
};
return navigator.credentials.create(options).then(credential => {
checkCtapMakeCredentialResult(credential);
});
}, "PublicKeyCredential's [[create]] with residentKey { Discouraged } in a mock hid 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: { residentKey: "preferred" },
timeout: 1000
}
};
return navigator.credentials.create(options).then(credential => {
checkCtapMakeCredentialResult(credential);
});
}, "PublicKeyCredential's [[create]] with residentKey { Preferred } in a mock hid 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: { residentKey: "required" },
timeout: 1000
}
};
return navigator.credentials.create(options).then(credential => {
checkCtapMakeCredentialResult(credential);
});
}, "PublicKeyCredential's [[create]] with residentKey { Required } in a mock hid 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: { userVerification: "preferred" },
timeout: 1000
}
};
return navigator.credentials.create(options).then(credential => {
checkCtapMakeCredentialResult(credential);
});
}, "PublicKeyCredential's [[create]] with userVerification { 'preferred' } in a mock hid 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: { userVerification: "discouraged" },
timeout: 1000
}
};
return navigator.credentials.create(options).then(credential => {
checkCtapMakeCredentialResult(credential);
});
}, "PublicKeyCredential's [[create]] with userVerification { 'discouraged' } in a mock hid 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: "cross-platform", requireResidentKey: false, userVerification: "preferred" },
timeout: 1000
}
};
return navigator.credentials.create(options).then(credential => {
checkCtapMakeCredentialResult(credential);
});
}, "PublicKeyCredential's [[create]] with mixed options in a mock hid 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 }],
timeout: 1000
}
};
// Stall the first request to wait for cancellation.
if (window.internals)
internals.setMockWebAuthenticationConfiguration({ hid: { stage: "request", subStage: "msg", error: "success", payloadBase64: [testCreationMessageBase64], expectCancel: true } });
promiseRejects(t, "NotAllowedError", navigator.credentials.create(options), "This request has been cancelled by a new request.");
if (window.internals)
internals.setMockWebAuthenticationConfiguration({ hid: { stage: "request", subStage: "msg", error: "success", payloadBase64: [testCreationMessageBase64] } });
return navigator.credentials.create(options).then(credential => {
checkCtapMakeCredentialResult(credential);
});
}, "PublicKeyCredential's [[create]] with two consecutive requests.");
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 }],
attestation: "none",
timeout: 1000
}
};
return navigator.credentials.create(options).then(credential => {
checkCtapMakeCredentialResult(credential);
});
}, "PublicKeyCredential's [[create]] with none attestation in a mock hid 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 }],
attestation: "direct",
timeout: 1000
}
};
return navigator.credentials.create(options).then(credential => {
checkCtapMakeCredentialResult(credential, false);
});
}, "PublicKeyCredential's [[create]] with direct attestation in a mock hid 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 }],
attestation: "indirect",
timeout: 1000
}
};
return navigator.credentials.create(options).then(credential => {
checkCtapMakeCredentialResult(credential, false);
});
}, "PublicKeyCredential's [[create]] with indirect attestation in a mock hid authenticator.");
// When RP ID is not google.com, googleLegacyAppidSupport should not have any effects.
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 }],
extensions: { googleLegacyAppidSupport: true },
timeout: 1000
}
};
return navigator.credentials.create(options).then(credential => {
checkCtapMakeCredentialResult(credential);
});
}, "PublicKeyCredential's [[create]] with googleLegacyAppidSupport extension in a mock hid 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 }],
extensions: { googleLegacyAppidSupport: true, appid: "" },
timeout: 1000
}
};
return navigator.credentials.create(options).then(credential => {
checkCtapMakeCredentialResult(credential);
});
}, "PublicKeyCredential's [[create]] with googleLegacyAppidSupport and appid extensions in a mock hid 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: "cross-platform", residentKey: "preferred" },
extensions: { credProps: true }
}
};
if (window.internals)
internals.setMockWebAuthenticationConfiguration({ hid: { stage: "request", subStage: "msg", error: "success", payloadBase64: [testCreateMessageFullKeyStoreBase64, testCreationMessageBase64] } });
return navigator.credentials.create(options).then(credential => {
checkCtapMakeCredentialResult(credential);
});
}, "PublicKeyCredential's [[create]] with authenticatorSelection { 'cross-platform', 'preferred' } in a mock hid authenticator with a full key store.");
promise_test(t => {
let config = { hid: { stage: "request", subStage: "msg", error: "success", payloadBase64: [testCreationMessageBase64] } };
let 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 }],
timeout: 1000,
excludeCredentials: []
}
};
const numCredentials = 20;
for (let i = 0; i < numCredentials; i++) {
options.publicKey.excludeCredentials.push({ type: "public-key", id: generateID(i) });
config.hid.payloadBase64.unshift("Lg==");
}
if (window.internals)
internals.setMockWebAuthenticationConfiguration(config);
return navigator.credentials.create(options).then(credential => {
checkCtapMakeCredentialResult(credential, true, ["usb"]);
});
}, "PublicKeyCredential's [[create]] with many excludedCredentials necessitating batching in a mock hid authenticator.");
promise_test(t => {
let config = { hid: { maxCredentialCountInList: 5, stage: "request", subStage: "msg", error: "success", payloadBase64: [testCreationMessageBase64] } };
let 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 }],
timeout: 1000,
excludeCredentials: []
}
};
const numCredentials = 20;
for (let i = 0; i < numCredentials; i++)
options.publicKey.excludeCredentials.push({ type: "public-key", id: generateID(i) });
for (let i = 0; i < Math.ceil(numCredentials/config.hid.maxCredentialCountInList); i++)
config.hid.payloadBase64.unshift("Lg==");
if (window.internals)
internals.setMockWebAuthenticationConfiguration(config);
return navigator.credentials.create(options).then(credential => {
checkCtapMakeCredentialResult(credential, true, ["usb"]);
});
}, "PublicKeyCredential's [[create]] with many excludedCredentials necessitating batching in a mock hid authenticator. 2");
promise_test(t => {
// Test bidirectional HID validation with exclude list preflight
// This test validates that WebKit sends the expected sequence of HID messages:
// 1. Two silent authenticatorGetAssertion requests (exclude list preflight)
// 2. One authenticatorMakeCredential request (actual credential creation)
const excludeCredential1 = Base64URL.parse("dGVzdGNyZWRlbnRpYWwx"); // "testcredential1"
const excludeCredential2 = Base64URL.parse("dGVzdGNyZWRlbnRpYWwy"); // "testcredential2"
let config = {
hid: {
stage: "request",
subStage: "msg",
error: "success",
payloadBase64: [
"Lg==", // Response to first exclude list preflight (credential not found)
"Lg==", // Response to second exclude list preflight (credential not found)
testCreationMessageBase64 // Response to actual makeCredential
],
validateExpectedCommands: true,
expectedCommandsBase64: [
"AqQBaWxvY2FsaG9zdAJYIBraShsL58mV/5Ewkij+Q37ohfCSmOvvqFo/YdrkFzG1A4GiYmlkT3Rlc3RjcmVkZW50aWFsMWR0eXBlanB1YmxpYy1rZXkFoWJ1cPQ=",
"AqQBaWxvY2FsaG9zdAJYIBraShsL58mV/5Ewkij+Q37ohfCSmOvvqFo/YdrkFzG1A4GiYmlkT3Rlc3RjcmVkZW50aWFsMmR0eXBlanB1YmxpYy1rZXkFoWJ1cPQ=",
"AaQBWCAa2kobC+fJlf+RMJIo/kN+6IXwkpjr76haP2Ha5BcxtQKiYmlkaWxvY2FsaG9zdGRuYW1laWxvY2FsaG9zdAOjYmlkSgABAgMEBQYHCAlkbmFtZW5Kb2huIEFwcGxlc2VlZGtkaXNwbGF5TmFtZWlBcHBsZXNlZWQEgaJjYWxnJmR0eXBlanB1YmxpYy1rZXk="
]
}
};
let 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 }],
timeout: 1000,
excludeCredentials: [
{ type: "public-key", id: excludeCredential1 },
{ type: "public-key", id: excludeCredential2 }
]
}
};
if (window.internals)
internals.setMockWebAuthenticationConfiguration(config);
return navigator.credentials.create(options).then(credential => {
checkCtapMakeCredentialResult(credential, true, ["usb"]);
});
}, "PublicKeyCredential's [[create]] with excludeCredentials - verify preflighted credentials not sent in main request.");
promise_test(t => {
let config = {
hid: {
stage: "request",
subStage: "msg",
error: "success",
pinProtocols: [1, 2],
payloadBase64: [testCreationMessageBase64],
validateExpectedCommands: true,
expectedCommandsBase64: [
"AaQBWCAa2kobC+fJlf+RMJIo/kN+6IXwkpjr76haP2Ha5BcxtQKiYmlkaWxvY2FsaG9zdGRuYW1laWxvY2FsaG9zdAOjYmlkSgABAgMEBQYHCAlkbmFtZW5Kb2huIEFwcGxlc2VlZGtkaXNwbGF5TmFtZWlBcHBsZXNlZWQEgaJjYWxnJmR0eXBlanB1YmxpYy1rZXk="
]
}
};
let 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 }],
timeout: 1000
}
};
if (window.internals)
internals.setMockWebAuthenticationConfiguration(config);
return navigator.credentials.create(options).then(credential => {
checkCtapMakeCredentialResult(credential, true, ["usb"]);
});
}, "PublicKeyCredential's [[create]] with PIN Protocol 2 support in a mock hid authenticator.");
promise_test(t => {
let config = {
hid: {
stage: "request",
subStage: "msg",
error: "success",
payloadBase64: [testCreationMessageBase64],
validateExpectedCommands: true,
expectedCommandsBase64: [
"AaQBWCAa2kobC+fJlf+RMJIo/kN+6IXwkpjr76haP2Ha5BcxtQKiYmlkaWxvY2FsaG9zdGRuYW1laWxvY2FsaG9zdAOjYmlkSgABAgMEBQYHCAlkbmFtZW5Kb2huIEFwcGxlc2VlZGtkaXNwbGF5TmFtZWlBcHBsZXNlZWQEgaJjYWxnJmR0eXBlanB1YmxpYy1rZXk="
]
}
};
let 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 }],
timeout: 1000
}
};
if (window.internals)
internals.setMockWebAuthenticationConfiguration(config);
return navigator.credentials.create(options).then(credential => {
checkCtapMakeCredentialResult(credential, true, ["usb"]);
});
}, "PublicKeyCredential's [[create]] with PIN Protocol 1 fallback in a mock hid 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 }],
extensions: { prf: {} },
timeout: 1000
}
};
if (window.internals)
internals.setMockWebAuthenticationConfiguration({ hid: { stage: "request", subStage: "msg", error: "success", payloadBase64: [testHmacSecretMakeCredentialMessageBase64] } });
return navigator.credentials.create(options).then(credential => {
// Verify prf extension output
const extensions = credential.getClientExtensionResults();
assert_true(extensions.prf !== undefined, "prf should be present");
assert_true(extensions.prf.enabled, "prf.enabled should be true");
});
}, "PublicKeyCredential's [[create]] with prf extension in a mock hid authenticator.");
</script>