Browse Source

register with simple-lib browser (works until jwt signature validation)

pull/116/head
Trent Larson 6 months ago
parent
commit
c5598d5b4c
  1. 85
      src/libs/didPeer.ts
  2. 5
      src/views/TestView.vue

85
src/libs/didPeer.ts

@ -4,9 +4,13 @@ import { decode as cborDecode } from "cbor-x";
import { createJWS, JWTPayload, verifyJWT } from "did-jwt"; import { createJWS, JWTPayload, verifyJWT } from "did-jwt";
import { DIDResolutionResult, Resolver } from "did-resolver"; import { DIDResolutionResult, Resolver } from "did-resolver";
import { bytesToMultibase } from "@veramo/utils"; import { bytesToMultibase } from "@veramo/utils";
import { startAuthentication } from "@simplewebauthn/browser"; import {
startAuthentication,
startRegistration,
} from "@simplewebauthn/browser";
import { import {
generateAuthenticationOptions, generateAuthenticationOptions,
generateRegistrationOptions,
verifyAuthenticationResponse, verifyAuthenticationResponse,
verifyRegistrationResponse, verifyRegistrationResponse,
VerifyRegistrationResponseOpts, VerifyRegistrationResponseOpts,
@ -14,6 +18,7 @@ import {
import { VerifyAuthenticationResponseOpts } from "@simplewebauthn/server/esm/authentication/verifyAuthenticationResponse"; import { VerifyAuthenticationResponseOpts } from "@simplewebauthn/server/esm/authentication/verifyAuthenticationResponse";
import { import {
Base64URLString, Base64URLString,
PublicKeyCredentialCreationOptionsJSON,
PublicKeyCredentialRequestOptionsJSON, PublicKeyCredentialRequestOptionsJSON,
} from "@simplewebauthn/types"; } from "@simplewebauthn/types";
@ -36,7 +41,51 @@ function toBase64Url(anything: Uint8Array) {
.replace(/=+$/, ""); .replace(/=+$/, "");
} }
export async function registerCredential( export async function registerCredential() {
const options: PublicKeyCredentialCreationOptionsJSON =
await generateRegistrationOptions({
rpName: "Time Safari",
rpID: window.location.hostname,
userName: "Current-User",
// Don't prompt users for additional information about the authenticator
// (Recommended for smoother UX)
attestationType: "none",
// Prevent users from re-registering existing authenticators
// excludeCredentials: userPasskeys.map(passkey => ({
// id: passkey.id,
// // Optional
// transports: passkey.transports,
// })),
// // See "Guiding use of authenticators via authenticatorSelection" below
authenticatorSelection: {
// Defaults
residentKey: "preferred",
userVerification: "preferred",
// Optional
authenticatorAttachment: "platform",
},
});
const attResp = await startRegistration(options);
console.log("attResp", attResp);
const verification = await verifyRegistrationResponse({
response: attResp,
expectedChallenge: options.challenge,
expectedOrigin: window.location.origin,
expectedRPID: window.location.hostname,
});
console.log("verification", verification);
return {
authData: verification.registrationInfo?.attestationObject,
credId: verification.registrationInfo?.credentialID as string,
rawId: new Uint8Array(new Buffer(attResp.rawId, "base64")),
publicKeyJwk: undefined,
publicKeyBytes: verification.registrationInfo
?.credentialPublicKey as Uint8Array,
};
}
export async function registerCredential2(
userId: Uint8Array, userId: Uint8Array,
challenge: Uint8Array, challenge: Uint8Array,
) { ) {
@ -68,6 +117,7 @@ export async function registerCredential(
const credential = await navigator.credentials.create({ const credential = await navigator.credentials.create({
publicKey: publicKeyOptions, publicKey: publicKeyOptions,
}); });
console.log("credential", credential); console.log("credential", credential);
console.log(credential?.id, " is the new ID base64-url-encoded"); console.log(credential?.id, " is the new ID base64-url-encoded");
console.log(toBase64Url(credential?.rawId), " is the base64 rawId"); console.log(toBase64Url(credential?.rawId), " is the base64 rawId");
@ -288,45 +338,44 @@ export async function verifyJwt(
console.log("clientAuth", clientAuth); console.log("clientAuth", clientAuth);
const verfOpts: VerifyAuthenticationResponseOpts = { const verfOpts: VerifyAuthenticationResponseOpts = {
response: clientAuth,
authenticator: { authenticator: {
credentialID: credId, credentialID: credId,
credentialPublicKey: publicKey, credentialPublicKey: publicKey,
counter: 0, counter: 0,
}, },
expectedChallenge: () => true, // options.challenge doesn't work expectedChallenge: options.challenge,
expectedOrigin: window.location.origin, expectedOrigin: window.location.origin,
expectedRPID: window.location.hostname, expectedRPID: window.location.hostname,
response: clientAuth,
}; };
console.log("verfOpts", verfOpts); console.log("verfOpts", verfOpts);
const verificationFromClient = await verifyAuthenticationResponse(verfOpts); const verificationFromClient = await verifyAuthenticationResponse(verfOpts);
console.log("client auth verification", verificationFromClient); console.log("client auth verification", verificationFromClient);
const authData = toBase64Url(Buffer.from(authenticatorData)); const authData = toBase64Url(Buffer.from(authenticatorData));
const bufferizedJson = toBase64Url(
new TextEncoder().encode(JSON.stringify(clientDataJSON)),
);
const authOpts: VerifyAuthenticationResponseOpts = { const authOpts: VerifyAuthenticationResponseOpts = {
authenticator: {
credentialID: credId,
credentialPublicKey: publicKey,
counter: 0,
},
expectedChallenge: options.challenge,
expectedOrigin: window.location.origin,
expectedRPID: window.location.hostname,
response: { response: {
authenticatorAttachment: "platform",
clientExtensionResults: {},
id: credId, id: credId,
rawId: toBase64Url(rawId), rawId: toBase64Url(rawId),
response: { response: {
authenticatorData: authData, authenticatorData: authData,
clientDataJSON: bufferizedJson, clientDataJSON: clientAuth.response.clientDataJSON,
signature: signature, signature: clientAuth.response.signature,
}, },
clientExtensionResults: {},
type: "public-key", type: "public-key",
}, },
expectedChallenge: () => true, // options.challenge doesn't work
expectedOrigin: window.location.origin,
expectedRPID: window.location.hostname,
authenticator: {
credentialID: credId,
credentialPublicKey: publicKey,
counter: 0,
},
}; };
console.log("auth opts", authOpts);
const verification = await verifyAuthenticationResponse(authOpts); const verification = await verifyAuthenticationResponse(authOpts);
console.log("auth verification", verification); console.log("auth verification", verification);

5
src/views/TestView.vue

@ -209,6 +209,7 @@ import {
registerCredential, registerCredential,
verifyJwt, verifyJwt,
} from "@/libs/didPeer"; } from "@/libs/didPeer";
import { Buffer } from "buffer";
const inputFileNameRef = ref<Blob>(); const inputFileNameRef = ref<Blob>();
@ -260,7 +261,7 @@ export default class Help extends Vue {
public async register() { public async register() {
this.userId = generateRandomBytes(16).buffer; this.userId = generateRandomBytes(16).buffer;
const encodedUserId = new TextDecoder("utf-8").decode(this.userId); const encodedUserId = Buffer.from(this.userId).toString("base64");
console.log("encodedUserId", encodedUserId); console.log("encodedUserId", encodedUserId);
const challenge = generateRandomBytes(32); const challenge = generateRandomBytes(32);
@ -297,7 +298,7 @@ export default class Help extends Vue {
} }
const signature = this.jwt.split(".")[2]; const signature = this.jwt.split(".")[2];
const decoded = await verifyJwt( const decoded = await verifyJwt(
this.jwt || "", this.jwt,
this.credId as Base64URLString, this.credId as Base64URLString,
this.rawId as Uint8Array, this.rawId as Uint8Array,
this.peerSetup.authenticatorData as ArrayBuffer, this.peerSetup.authenticatorData as ArrayBuffer,

Loading…
Cancel
Save