Reland "webauthn: implement getPublicKey() and friends."

This reverts commit e2c1b358db1755a91f62f4c27a1d220bd326c742.

https://chromium-review.googlesource.com/c/chromium/src/+/2238777 updates some Java tests with non-dummy data that should avoid causing problems.

Original change's description:
> Revert "webauthn: implement getPublicKey() and friends."
>
> This reverts commit c5d236776cd30849a65ca626e51cd19e651da7c6.
>
> Reason for revert: I suspect that this CL causes Fido2CredentialRequestTest failures on android-pie-x86-rel:
> https://ci.chromium.org/p/chromium/builders/ci/android-pie-x86-rel
>
> Here is a snippet of callstack:
> java.lang.AssertionError: expected:<11> but was:<0>
> 	at org.junit.Assert.fail(Assert.java:88)
> 	at org.junit.Assert.failNotEquals(Assert.java:834)
> 	at org.junit.Assert.assertEquals(Assert.java:118)
> 	at org.junit.Assert.assertEquals(Assert.java:144)
> 	at org.chromium.chrome.browser.webauth.Fido2CredentialRequestTest.testMakeCredential_attestationIndirect(Fido2CredentialRequestTest.java:921)
>
> Here is sample failure:
> https://00e9e64bac4dbda9c3b8a07931c85e48f4420a03929ffbcaf5-apidata.googleusercontent.com/download/storage/v1/b/chromium-result-details/o/html%2Fchrome_public_test_apk_android-pie-x86-rel_990_2020_06_09_T16_33_45-UTC?qk=AD5uMEvQvMK8K2ZyV-tHIDwdTtLEnQK-X1Mw0ohWLQeOpgogj0sVgm_7y9e5CdF-FMV6ObBmwjpVxD6Jh8_7VTv4z2FpOutuS8Gd6qQH5OxikfytS8cKFb_SRCCQXIgWq45BwD7DediOcKTF-UZea_JAoFuHO0ljO0PRqnkFYSoIHcPONuqaszXChp63b5o4VAKYsofAHDhpHru_hiAf6xUyfK91I8cr-2sdHjQU6Ks4XQIIWVnq2PSAiysd6hNeq51qWPEaX7HS8hCwWIpe55Xq9hIWLOtab3MY1WLLxM3UuWMY8IDCKfcvnrTiQMcRyeD7Iii33jHhC8-rDGttfDEl39kpFnWynDC-C0TmPFoCJVkl7mHxz0uCNlQJ3I0Rt_F2DTqA96qIKrpwEltNs96-0j1VgSOJCjU3s4od6h7juoIxpH5HThyg7G-fB1-MWzv7mQfAE5ZBilodU0CKMsFrnN_5Kf4thAbDj-RJUiUNpy0A9swLOhMLjEsfxQeDRldVvy9OVUNvcakhJziml5iA7LWoDB58E3eGTyUi-dA5aOLN3KWLR7T452j4MwnCHC5vTRNxxGxCkemgQQDkl1fHJas1u6GUcY4_ncvhIuGvLsfg8uqWpzFuau4CFamGC2USpyVpNIeNhpcf2w-lYzG1rkHjHWYgUKSvhoaItY3oeRFjnkYMgZrDsy8QmneuVVGTPd4nzoWWaCZbaG9ZaF80xRu9YhYnTUXI7GqQF1rlst09Mqu8IvDXo9dgYzodInIA6p3H7azZgnvCfzYUxL4QVrvskyjTQCITmz-o2W6CPUzBqWJhWLRTpZYcVSV7z8zjj1cFwDQPBKpJzQDRrtC1sZCM0WrmQ7oSNeU-AH3uBaNWeGBF2rkY8-9gx8dlr38DGQvXoKZVWHWi61jVnQhac27ctKBLKQ&isca=1
>
> Original change's description:
> > webauthn: implement getPublicKey() and friends.
> >
> > This change implements the getPublicKey(), getPublicKeyAlgorithm(), and
> > getAuthenticatorData() functions described in the editor's draft of
> > WebAuthn level two[1].
> >
> > [1] https://w3c.github.io/webauthn/#sctn-public-key-easy
> >
> > BUG=1083301
> >
> > Change-Id: I3a03279d5239a9f8df50a78f2166f30d01d38d3e
> > Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2204087
> > Reviewed-by: Andrew Grieve <agrieve@chromium.org>
> > Reviewed-by: Ken Buchanan <kenrb@chromium.org>
> > Reviewed-by: Alex Russell <slightlyoff@chromium.org>
> > Reviewed-by: Jared Saul <jsaul@google.com>
> > Reviewed-by: Adam Langley <agl@chromium.org>
> > Reviewed-by: Nina Satragno <nsatragno@chromium.org>
> > Reviewed-by: Martin Kreichgauer <martinkr@google.com>
> > Commit-Queue: Adam Langley <agl@chromium.org>
> > Cr-Commit-Position: refs/heads/master@{#776517}
>
> TBR=kenrb@chromium.org,agl@chromium.org,slightlyoff@chromium.org,nsatragno@chromium.org,agrieve@chromium.org,jsaul@google.com,martinkr@google.com
>
> Change-Id: I7429b5b7ecd7fa38c4e1ec2905b80a15e7c64216
> No-Presubmit: true
> No-Tree-Checks: true
> No-Try: true
> Bug: 1083301
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2238749
> Reviewed-by: Pavel Yatsuk <pavely@chromium.org>
> Commit-Queue: Pavel Yatsuk <pavely@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#776637}

TBR=kenrb@chromium.org,agl@chromium.org,slightlyoff@chromium.org,pavely@chromium.org,nsatragno@chromium.org,agrieve@chromium.org,jsaul@google.com,martinkr@google.com

# Not skipping CQ checks because original CL landed > 1 day ago.

Bug: 1083301
Change-Id: I9e3c8278dde4b61b7a45b6277f48fe018b3a8188
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2241341
Reviewed-by: Adam Langley <agl@chromium.org>
Commit-Queue: Adam Langley <agl@chromium.org>
Cr-Commit-Position: refs/heads/master@{#777424}
diff --git a/webauthn/createcredential-getpublickey.https.html b/webauthn/createcredential-getpublickey.https.html
new file mode 100644
index 0000000..2155199
--- /dev/null
+++ b/webauthn/createcredential-getpublickey.https.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebAuthn getPublicKey</title>
+<meta name="timeout" content="long">
+<link rel="help" href="https://w3c.github.io/webauthn/#sctn-public-key-easy">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="helpers.js"></script>
+<script src="resources/utils.js"></script>
+<script>
+function testGetPublicKey() {
+    standardSetup(function() {
+        promise_test(async t => {
+            let cred = await createCredential();
+            const response = cred.response;
+            assert_equals(response.getPublicKeyAlgorithm(),
+                          cose_alg_ECDSA_w_SHA256);
+
+            const attestationObject =
+                new Cbor(response.attestationObject).getCBOR();
+            const claimedAuthDataHex = uint8ArrayToHex(
+                new Uint8Array(response.getAuthenticatorData()));
+            const actualAuthDataHex = uint8ArrayToHex(attestationObject.authData);
+            assert_equals(actualAuthDataHex, claimedAuthDataHex);
+
+            // Check that the x and y coordinates of the public key appear in
+            // the claimed SPKI, at least.
+            const spkiHex = uint8ArrayToHex(
+                new Uint8Array(response.getPublicKey()));
+            const authData = parseAuthenticatorData(attestationObject.authData);
+            const pubKey = authData.attestedCredentialData.credentialPublicKey;
+            const xHex = uint8ArrayToHex(pubKey.x);
+            const yHex = uint8ArrayToHex(pubKey.y);
+            assert_not_equals(-1, spkiHex.indexOf(xHex));
+            assert_not_equals(-1, spkiHex.indexOf(yHex));
+
+            t.done();
+        });
+    });
+}
+
+testGetPublicKey();
+/* JSHINT */
+/* globals standardSetup, createCredential */
+</script>
+</head>
+<body></body>
+</html>
diff --git a/webauthn/resources/utils.js b/webauthn/resources/utils.js
index f361a94..50c3960 100644
--- a/webauthn/resources/utils.js
+++ b/webauthn/resources/utils.js
@@ -17,6 +17,17 @@
   return base64urlEncode(String.fromCharCode.apply(null, array));
 }
 
+// Encodes a Uint8Array to lowercase hex.
+function uint8ArrayToHex(array) {
+  const hexTable = '0123456789abcdef';
+  let s = '';
+  for (let i = 0; i < array.length; i++) {
+    s += hexTable.charAt(array[i] >> 4);
+    s += hexTable.charAt(array[i] & 15);
+  }
+  return s;
+}
+
 // Convert a EC signature from DER to a concatenation of the r and s parameters,
 // as expected by the subtle crypto API.
 function convertDERSignatureToSubtle(der) {
@@ -158,13 +169,7 @@
     return this.slice.length == 0;
   }
   get hex() {
-    const hexTable = '0123456789abcdef';
-    let s = '';
-    for (let i = 0; i < this.data.length; i++) {
-      s += hexTable.charAt(this.data[i] >> 4);
-      s += hexTable.charAt(this.data[i] & 15);
-    }
-    return s;
+    return uint8ArrayToHex(this.data);
   }
   compare(other) {
     if (this.length < other.length) {