Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/dom/webauthn/tests/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 13 kB image not shown  

Quelle  u2futil.js   Sprache: JAVA

 
// Used by local_addTest() / local_completeTest()
var _countCompletions = 0;
var _expectedCompletions = 0;

const flag_TUP = 0x01;
const flag_UV = 0x04;
const flag_AT = 0x40;

const cose_kty = 1;
const cose_kty_ec2 = 2;
const cose_alg = 3;
const cose_alg_ECDSA_w_SHA256 = -7;
const cose_alg_ECDSA_w_SHA512 = -36;
const cose_crv = -1;
const cose_crv_P256 = 1;
const cose_crv_x = -2;
const cose_crv_y = -3;

var { AppConstants } = SpecialPowers.ChromeUtils.importESModule(
  "resource://gre/modules/AppConstants.sys.mjs"
);

async function addVirtualAuthenticator(
  protocol = "ctap2_1",
  transport = "internal",
  hasResidentKey = true,
  hasUserVerification = true,
  isUserConsenting = true,
  isUserVerified = true
) {
  let id = await SpecialPowers.spawnChrome(
    [
      protocol,
      transport,
      hasResidentKey,
      hasUserVerification,
      isUserConsenting,
      isUserVerified,
    ],
    (
      protocol,
      transport,
      hasResidentKey,
      hasUserVerification,
      isUserConsenting,
      isUserVerified
    ) => {
      let webauthnService = Cc["@mozilla.org/webauthn/service;1"].getService(
        Ci.nsIWebAuthnService
      );
      let id = webauthnService.addVirtualAuthenticator(
        protocol,
        transport,
        hasResidentKey,
        hasUserVerification,
        isUserConsenting,
        isUserVerified
      );
      return id;
    }
  );

  SimpleTest.registerCleanupFunction(async () => {
    await SpecialPowers.spawnChrome([id], id => {
      let webauthnService = Cc["@mozilla.org/webauthn/service;1"].getService(
        Ci.nsIWebAuthnService
      );
      webauthnService.removeVirtualAuthenticator(id);
    });
  });

  return id;
}

function handleEventMessage(event) {
  if ("test" in event.data) {
    let summary = event.data.test + ": " + event.data.msg;
    log(event.data.status + ": " + summary);
    ok(event.data.status, summary);
  } else if ("done" in event.data) {
    SimpleTest.finish();
  } else {
    ok(false"Unexpected message in the test harness: " + event.data);
  }
}

function log(msg) {
  console.log(msg);
  let logBox = document.getElementById("log");
  if (logBox) {
    logBox.textContent += "\n" + msg;
  }
}

function local_is(value, expected, message) {
  if (value === expected) {
    local_ok(true, message);
  } else {
    local_ok(false, message + " unexpectedly: " + value + " !== " + expected);
  }
}

function local_isnot(value, expected, message) {
  if (value !== expected) {
    local_ok(true, message);
  } else {
    local_ok(false, message + " unexpectedly: " + value + " === " + expected);
  }
}

function local_ok(expression, message) {
  let body = { test: this.location.pathname, status: expression, msg: message };
  parent.postMessage(body, "http://mochi.test:8888");
}

function local_doesThrow(fn, name) {
  let gotException = false;
  try {
    fn();
  } catch (ex) {
    gotException = true;
  }
  local_ok(gotException, name);
}

function local_expectThisManyTests(count) {
  if (_expectedCompletions > 0) {
    local_ok(
      false,
      "Error: local_expectThisManyTests should only be called once."
    );
  }
  _expectedCompletions = count;
}

function local_completeTest() {
  _countCompletions += 1;
  if (_countCompletions == _expectedCompletions) {
    log("All tests completed.");
    local_finished();
  }
  if (_countCompletions > _expectedCompletions) {
    local_ok(
      false,
      "Error: local_completeTest called more than local_addTest."
    );
  }
}

function local_finished() {
  parent.postMessage({ done: true }, "http://mochi.test:8888");
}

function string2buffer(str) {
  return new Uint8Array(str.length).map((x, i) => str.charCodeAt(i));
}

function buffer2string(buf) {
  let str = "";
  if (!(buf.constructor === Uint8Array)) {
    buf = new Uint8Array(buf);
  }
  buf.map(function (x) {
    return (str += String.fromCharCode(x));
  });
  return str;
}

function bytesToBase64(u8a) {
  let CHUNK_SZ = 0x8000;
  let c = [];
  let array = new Uint8Array(u8a);
  for (let i = 0; i < array.length; i += CHUNK_SZ) {
    c.push(String.fromCharCode.apply(null, array.subarray(i, i + CHUNK_SZ)));
  }
  return window.btoa(c.join(""));
}

function base64ToBytes(b64encoded) {
  return new Uint8Array(
    window
      .atob(b64encoded)
      .split("")
      .map(function (c) {
        return c.charCodeAt(0);
      })
  );
}

function bytesToBase64UrlSafe(buf) {
  return bytesToBase64(buf)
    .replace(/\+/g, "-")
    .replace(/\//g, "_")
    .replace(/=/g, "");
}

function base64ToBytesUrlSafe(str) {
  if (str.length % 4 == 1) {
    throw "Improper b64 string";
  }

  var b64 = str.replace(/\-/g, "+").replace(/\_/g, "/");
  while (b64.length % 4 != 0) {
    b64 += "=";
  }
  return base64ToBytes(b64);
}

function hexEncode(buf) {
  return Array.from(buf)
    .map(x => ("0" + x.toString(16)).substr(-2))
    .join("");
}

function hexDecode(str) {
  return new Uint8Array(str.match(/../g).map(x => parseInt(x, 16)));
}

function hasOnlyKeys(obj, ...keys) {
  let okeys = new Set(Object.keys(obj));
  return keys.length == okeys.size && keys.every(k => okeys.has(k));
}

function webAuthnDecodeCBORAttestation(aCborAttBuf) {
  let attObj = CBOR.decode(aCborAttBuf);
  console.log(":: Attestation CBOR Object ::");
  if (!hasOnlyKeys(attObj, "authData""fmt""attStmt")) {
    return Promise.reject("Invalid CBOR Attestation Object");
  }
  if (attObj.fmt == "fido-u2f" && !hasOnlyKeys(attObj.attStmt, "sig""x5c")) {
    return Promise.reject("Invalid CBOR Attestation Statement");
  }
  if (
    attObj.fmt == "packed" &&
    !(
      hasOnlyKeys(attObj.attStmt, "alg""sig") ||
      hasOnlyKeys(attObj.attStmt, "alg""sig""x5c")
    )
  ) {
    return Promise.reject("Invalid CBOR Attestation Statement");
  }
  if (attObj.fmt == "none" && Object.keys(attObj.attStmt).length) {
    return Promise.reject("Invalid CBOR Attestation Statement");
  }

  return webAuthnDecodeAuthDataArray(new Uint8Array(attObj.authData)).then(
    function (aAuthDataObj) {
      attObj.authDataObj = aAuthDataObj;
      return Promise.resolve(attObj);
    }
  );
}

function webAuthnDecodeAuthDataArray(aAuthData) {
  let rpIdHash = aAuthData.slice(0, 32);
  let flags = aAuthData.slice(32, 33);
  let counter = aAuthData.slice(33, 37);

  console.log(":: Authenticator Data ::");
  console.log("RP ID Hash: " + hexEncode(rpIdHash));
  console.log("Counter: " + hexEncode(counter) + " Flags: " + flags);

  if ((flags & flag_AT) == 0x00) {
    // No Attestation Data, so we're done.
    return Promise.resolve({
      rpIdHash,
      flags,
      counter,
    });
  }

  if (aAuthData.length < 38) {
    return Promise.reject(
      "Authenticator Data flag was set, but not enough data passed in!"
    );
  }

  let attData = {};
  attData.aaguid = aAuthData.slice(37, 53);
  attData.credIdLen = (aAuthData[53] << 8) + aAuthData[54];
  attData.credId = aAuthData.slice(55, 55 + attData.credIdLen);

  console.log(":: Authenticator Data ::");
  console.log("AAGUID: " + hexEncode(attData.aaguid));

  let cborPubKey = aAuthData.slice(55 + attData.credIdLen);
  var pubkeyObj = CBOR.decode(cborPubKey.buffer);
  if (
    !(
      cose_kty in pubkeyObj &&
      cose_alg in pubkeyObj &&
      cose_crv in pubkeyObj &&
      cose_crv_x in pubkeyObj &&
      cose_crv_y in pubkeyObj
    )
  ) {
    throw "Invalid CBOR Public Key Object";
  }
  if (pubkeyObj[cose_kty] != cose_kty_ec2) {
    throw "Unexpected key type";
  }
  if (pubkeyObj[cose_alg] != cose_alg_ECDSA_w_SHA256) {
    throw "Unexpected public key algorithm";
  }
  if (pubkeyObj[cose_crv] != cose_crv_P256) {
    throw "Unexpected curve";
  }

  let pubKeyBytes = assemblePublicKeyBytesData(
    pubkeyObj[cose_crv_x],
    pubkeyObj[cose_crv_y]
  );
  console.log(":: CBOR Public Key Object Data ::");
  console.log("kty: " + pubkeyObj[cose_kty] + " (EC2)");
  console.log("alg: " + pubkeyObj[cose_alg] + " (ES256)");
  console.log("crv: " + pubkeyObj[cose_crv] + " (P256)");
  console.log("X: " + pubkeyObj[cose_crv_x]);
  console.log("Y: " + pubkeyObj[cose_crv_y]);
  console.log("Uncompressed (hex): " + hexEncode(pubKeyBytes));

  return importPublicKey(pubKeyBytes).then(function (aKeyHandle) {
    return Promise.resolve({
      rpIdHash,
      flags,
      counter,
      attestationAuthData: attData,
      publicKeyBytes: pubKeyBytes,
      publicKeyHandle: aKeyHandle,
    });
  });
}

function importPublicKey(keyBytes) {
  if (keyBytes[0] != 0x04 || keyBytes.byteLength != 65) {
    throw "Bad public key octet string";
  }
  var jwk = {
    kty: "EC",
    crv: "P-256",
    x: bytesToBase64UrlSafe(keyBytes.slice(1, 33)),
    y: bytesToBase64UrlSafe(keyBytes.slice(33)),
  };
  return crypto.subtle.importKey(
    "jwk",
    jwk,
    { name: "ECDSA", namedCurve: "P-256" },
    true,
    ["verify"]
  );
}

function deriveAppAndChallengeParam(appId, clientData, attestation) {
  var appIdBuf = string2buffer(appId);
  return Promise.all([
    crypto.subtle.digest("SHA-256", appIdBuf),
    crypto.subtle.digest("SHA-256", clientData),
  ]).then(function (digests) {
    return {
      appParam: new Uint8Array(digests[0]),
      challengeParam: new Uint8Array(digests[1]),
      attestation,
    };
  });
}

function assemblePublicKeyBytesData(xCoord, yCoord) {
  // Produce an uncompressed EC key point. These start with 0x04, and then
  // two 32-byte numbers denoting X and Y.
  if (xCoord.length != 32 || yCoord.length != 32) {
    throw "Coordinates must be 32 bytes long";
  }
  let keyBytes = new Uint8Array(65);
  keyBytes[0] = 0x04;
  xCoord.map((x, i) => (keyBytes[1 + i] = x));
  yCoord.map((x, i) => (keyBytes[33 + i] = x));
  return keyBytes;
}

function assembleSignedData(appParam, flags, counter, challengeParam) {
  let signedData = new Uint8Array(32 + 1 + 4 + 32);
  new Uint8Array(appParam).map((x, i) => (signedData[0 + i] = x));
  signedData[32] = new Uint8Array(flags)[0];
  new Uint8Array(counter).map((x, i) => (signedData[33 + i] = x));
  new Uint8Array(challengeParam).map((x, i) => (signedData[37 + i] = x));
  return signedData;
}

function assembleRegistrationSignedData(
  appParam,
  challengeParam,
  keyHandle,
  pubKey
) {
  let signedData = new Uint8Array(1 + 32 + 32 + keyHandle.length + 65);
  signedData[0] = 0x00;
  new Uint8Array(appParam).map((x, i) => (signedData[1 + i] = x));
  new Uint8Array(challengeParam).map((x, i) => (signedData[33 + i] = x));
  new Uint8Array(keyHandle).map((x, i) => (signedData[65 + i] = x));
  new Uint8Array(pubKey).map(
    (x, i) => (signedData[65 + keyHandle.length + i] = x)
  );
  return signedData;
}

function sanitizeSigArray(arr) {
  // ECDSA signature fields into WebCrypto must be exactly 32 bytes long, so
  // this method strips leading padding bytes, if added, and also appends
  // padding zeros, if needed.
  if (arr.length > 32) {
    arr = arr.slice(arr.length - 32);
  }
  let ret = new Uint8Array(32);
  ret.set(arr, ret.length - arr.length);
  return ret;
}

function verifySignature(key, data, derSig) {
  if (derSig.byteLength < 68) {
    return Promise.reject(
      "Invalid signature (length=" +
        derSig.byteLength +
        "): " +
        hexEncode(new Uint8Array(derSig))
    );
  }

  // Copy signature data into the current context.
  let derSigCopy = new ArrayBuffer(derSig.byteLength);
  new Uint8Array(derSigCopy).set(new Uint8Array(derSig));

  let sigAsn1 = org.pkijs.fromBER(derSigCopy);

  // pkijs.asn1 seems to erroneously set an error code when calling some
  // internal function. The test suite doesn't like dangling globals.
  delete window.error;

  let sigR = new Uint8Array(
    sigAsn1.result.value_block.value[0].value_block.value_hex
  );
  let sigS = new Uint8Array(
    sigAsn1.result.value_block.value[1].value_block.value_hex
  );

  // The resulting R and S values from the ASN.1 Sequence must be fit into 32
  // bytes. Sometimes they have leading zeros, sometimes they're too short, it
  // all depends on what lib generated the signature.
  let R = sanitizeSigArray(sigR);
  let S = sanitizeSigArray(sigS);

  console.log("Verifying these bytes: " + bytesToBase64UrlSafe(data));

  let sigData = new Uint8Array(R.length + S.length);
  sigData.set(R);
  sigData.set(S, R.length);

  let alg = { name: "ECDSA", hash: "SHA-256" };
  return crypto.subtle.verify(alg, key, sigData, data);
}

async function addCredential(authenticatorId, rpId) {
  let keyPair = await crypto.subtle.generateKey(
    {
      name: "ECDSA",
      namedCurve: "P-256",
    },
    true,
    ["sign"]
  );

  let credId = new Uint8Array(32);
  crypto.getRandomValues(credId);
  credId = bytesToBase64UrlSafe(credId);

  let privateKey = await crypto.subtle
    .exportKey("pkcs8", keyPair.privateKey)
    .then(privateKey => bytesToBase64UrlSafe(privateKey));

  await SpecialPowers.spawnChrome(
    [authenticatorId, credId, rpId, privateKey],
    (authenticatorId, credId, rpId, privateKey) => {
      let webauthnService = Cc["@mozilla.org/webauthn/service;1"].getService(
        Ci.nsIWebAuthnService
      );

      webauthnService.addCredential(
        authenticatorId,
        credId,
        true// resident key
        rpId,
        privateKey,
        "VGVzdCBVc2Vy"// "Test User"
        0 // sign count
      );
    }
  );

  return credId;
}

async function removeCredential(authenticatorId, credId) {
  await SpecialPowers.spawnChrome(
    [authenticatorId, credId],
    (authenticatorId, credId) => {
      let webauthnService = Cc["@mozilla.org/webauthn/service;1"].getService(
        Ci.nsIWebAuthnService
      );

      webauthnService.removeCredential(authenticatorId, credId);
    }
  );
}

Messung V0.5
C=89 H=98 G=93

¤ Dauer der Verarbeitung: 0.6 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.