Browse Source

refactor, and make separate testing buttons for different approaches

pull/116/head
Trent Larson 5 months ago
parent
commit
141a7fd563
  1. 502
      src/libs/didPeer.ts
  2. 173
      src/views/TestView.vue

502
src/libs/didPeer.ts

@ -1,20 +1,19 @@
import asn1 from "asn1-ber";
import { Buffer } from "buffer/";
import { decode as cborDecode } from "cbor-x";
import { createJWS, JWTPayload } from "did-jwt";
import { JWTPayload } from "did-jwt";
import { DIDResolutionResult } from "did-resolver";
import { sha256 } from "ethereum-cryptography/sha256.js";
import { bytesToMultibase } from "@veramo/utils";
import {
startAuthentication,
startRegistration, WebAuthnAbortService,
startRegistration,
} from "@simplewebauthn/browser";
import {
generateAuthenticationOptions,
generateRegistrationOptions,
verifyAuthenticationResponse,
verifyRegistrationResponse,
VerifyRegistrationResponseOpts,
} from "@simplewebauthn/server";
import { VerifyAuthenticationResponseOpts } from "@simplewebauthn/server/esm/authentication/verifyAuthenticationResponse";
import {
@ -23,7 +22,6 @@ import {
PublicKeyCredentialRequestOptionsJSON,
} from "@simplewebauthn/types";
import { generateRandomBytes } from "@/libs/crypto";
import { getWebCrypto, unwrapEC2Signature } from "@/libs/crypto/passkeyHelpers";
export interface JWK {
@ -54,13 +52,6 @@ export async function registerCredential(userId: Uint8Array) {
// 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",
@ -69,24 +60,21 @@ export async function registerCredential(userId: Uint8Array) {
authenticatorAttachment: "platform",
},
});
// someday, instead of simplwebauthn, we'll go direct: navigator.credentials.create with PublicKeyCredentialCreationOptions
// with pubKeyCredParams: { type: "public-key", alg: -7 }
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);
const jwkObj = cborDecode(
verification.registrationInfo?.credentialPublicKey as Uint8Array,
);
console.log("jwkObj from verification", jwkObj);
console.log(
"[1]==2 => kty EC",
"[3]==-7 => alg ES256",
"[-1]==1 => crv P-256",
);
// references for parsing auth data and getting the public key
// https://github.com/MasterKale/SimpleWebAuthn/blob/master/packages/server/src/helpers/parseAuthenticatorData.ts#L11
// https://chatgpt.com/share/78a5c91d-099d-46dc-aa6d-fc0c916509fa
// https://chatgpt.com/share/3c13f061-6031-45bc-a2d7-3347c1e7a2d7
const { publicKeyJwk } = cborToKeys(
verification.registrationInfo?.credentialPublicKey as Uint8Array,
);
@ -101,99 +89,13 @@ export async function registerCredential(userId: Uint8Array) {
};
}
export async function registerCredential2(userId: Uint8Array) {
const challenge = generateRandomBytes(32);
const publicKeyOptions: PublicKeyCredentialCreationOptions = {
challenge: challenge,
rp: {
name: "Time Safari",
id: window.location.hostname,
},
user: {
id: userId,
name: "Current-User",
displayName: "Current User",
},
pubKeyCredParams: [
{
type: "public-key",
alg: -7, // ES256 algorithm
},
],
authenticatorSelection: {
authenticatorAttachment: "platform",
userVerification: "preferred",
},
timeout: 60000,
attestation: "direct",
};
const credential = await navigator.credentials.create({
publicKey: publicKeyOptions,
});
console.log("credential", credential);
console.log(credential?.id, " is the new ID base64-url-encoded");
console.log(arrayToBase64Url(credential?.rawId), " is the base64 rawId");
const attestationResponse = credential?.response;
const verfInput: VerifyRegistrationResponseOpts = {
response: {
id: credential?.id as string,
rawId: credential?.id as string, //Buffer.from(credential?.rawId).toString("base64"),
response: {
attestationObject: arrayToBase64Url(attestationResponse?.attestationObject),
clientDataJSON: arrayToBase64Url(attestationResponse?.clientDataJSON),
},
clientExtensionResults: {},
type: "public-key",
},
expectedChallenge: arrayToBase64Url(challenge),
expectedOrigin: window.location.origin,
};
console.log("verfInput", verfInput);
const verification = await verifyRegistrationResponse(verfInput);
console.log("verification", verification);
// Parse the attestation response to get the public key
const clientDataJSON = attestationResponse.clientDataJSON;
console.log("clientDataJSON raw", clientDataJSON);
console.log(
"clientDataJSON dec",
new TextDecoder("utf-8").decode(clientDataJSON),
);
const attestationObject = cborDecode(
new Uint8Array(attestationResponse.attestationObject),
);
console.log("attestationObject", attestationObject);
const { publicKeyJwk, publicKeyBuffer } = cborToKeys(
verification.registrationInfo?.credentialPublicKey as Uint8Array,
);
//const publicKeyBytes = extractPublicKeyCose(attestationObject.authData);
//const publicKeyJwk = extractPublicKeyJwk(attestationObject.authData);
return {
authData: attestationObject.authData,
credId: credential?.id,
rawId: credential?.rawId,
publicKeyJwk,
publicKeyBytes: publicKeyBuffer,
};
}
// parse authData
// here's one: https://github.com/MasterKale/SimpleWebAuthn/blob/master/packages/server/src/helpers/parseAuthenticatorData.ts#L11
// from https://chatgpt.com/c/0ce72fda-bc5d-42ff-a748-6022f6e39fa0
// from https://chatgpt.com/share/78a5c91d-099d-46dc-aa6d-fc0c916509fa
export function createPeerDid(publicKeyBytes: Uint8Array) {
// https://github.com/decentralized-identity/veramo/blob/next/packages/did-provider-peer/src/peer-did-provider.ts#L67
//const provider = new PeerDIDProvider({ defaultKms: LOCAL_KMS_NAME });
const methodSpecificId = bytesToMultibase(
publicKeyBytes,
"base58btc",
"secp256k1-pub",
"p256-pub",
);
return "did:peer:0" + methodSpecificId;
}
@ -205,11 +107,11 @@ export class PeerSetup {
public clientDataJsonDecoded?: object;
public clientDataJsonBase64Url?: Base64URLString;
public signature?: Base64URLString;
public publicKeyJwk?: JWK;
public async createJwt(fullPayload: object, credentialId: string) {
const header: JWTPayload = { typ: "JWT", alg: "ES256" };
public async createJwtSimplewebauthn(
fullPayload: object,
credentialId: string,
) {
this.challenge = new Uint8Array(Buffer.from(JSON.stringify(fullPayload)));
// const payloadHash: Uint8Array = sha256(this.challenge);
const options: PublicKeyCredentialRequestOptionsJSON =
@ -233,83 +135,65 @@ export class PeerSetup {
"utf-8",
),
);
//console.log("simple authenticatorData for signing", this.authenticatorData);
// console.log("simple authenticatorData for signing", this.authenticatorData);
this.signature = clientAuth.response.signature;
const headerBase64 = Buffer.from(JSON.stringify(header)).toString("base64");
const payloadBase64 = clientAuth.response.clientDataJSON;
// Our custom type of JWANT means the signature is based on a concatenation of the two Webauthn properties
const header: JWTPayload = { typ: "JWANT", alg: "ES256" };
const headerBase64 = Buffer.from(JSON.stringify(header))
.toString("base64")
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=+$/, "");
const dataInJwt = {
AuthenticationData: this.authenticatorDataBase64Url,
ClientDataJSON: this.clientDataJsonBase64Url,
};
const dataInJwtString = JSON.stringify(dataInJwt);
const payloadBase64 = Buffer.from(dataInJwtString).toString("base64");
const signature = clientAuth.response.signature;
return headerBase64 + "." + payloadBase64 + "." + signature;
}
public async createJwt2(fullPayload: object, credentialId: string) {
const header: JWTPayload = { typ: "JWT", alg: "ES256" };
const headerBase64 = Buffer.from(JSON.stringify(header)).toString("base64");
public async createJwtNavigator(fullPayload: object, credentialId: string) {
const dataToSignString = JSON.stringify(fullPayload);
const dataToSignBuffer = Buffer.from(dataToSignString);
//console.log("lower credentialId", credentialId);
// console.log("lower credentialId", credentialId);
this.challenge = new Uint8Array(dataToSignBuffer);
const options = {
publicKey: {
challenge: this.challenge.buffer,
rpID: window.location.hostname,
//allowCredentials: [{ id: credentialId, type: "public-key" }],
userVerification: "preferred",
//extensions: fullPayload,
},
};
// console.log("lower authentication options", options);
// console.log("lower options in base64", {
// publicKey: {
// challenge: bufferToBase64URLString(options.publicKey.challenge),
// rpID: window.location.hostname,
// userVerification: "preferred",
// },
// });
const credential = await navigator.credentials.get(options);
// console.log("lower credential get", credential);
// console.log("lower credential get in base64", {
// id: credential?.id,
// rawId: bufferToBase64URLString(credential?.rawId),
// response: {
// authenticatorData: bufferToBase64URLString(
// credential?.response.authenticatorData,
// ),
// clientDataJSON: bufferToBase64URLString(
// credential?.response.clientDataJSON,
// ),
// signature: bufferToBase64URLString(credential?.response.signature),
// },
// type: credential?.type,
// });
const authenticatorAssertionResponse = credential?.response;
this.authenticatorDataBase64Url =
authenticatorAssertionResponse.authenticatorData;
// console.log("nav credential get", credential);
this.authenticatorDataBase64Url = bufferToBase64URLString(
credential?.response.authenticatorData,
);
this.authenticatorData = Buffer.from(
this.authenticatorDataBase64Url as Base64URLString,
"base64",
).buffer;
// console.log("lower authenticator data", this.authenticatorData);
this.clientDataJsonBase64Url =
authenticatorAssertionResponse.clientDataJSON;
this.clientDataJsonBase64Url = bufferToBase64URLString(
credential?.response.clientDataJSON,
);
this.clientDataJsonDecoded = JSON.parse(
new TextDecoder("utf-8").decode(
authenticatorAssertionResponse.clientDataJSON,
),
new TextDecoder("utf-8").decode(credential?.response.clientDataJSON),
);
// console.log("lower clientDataJSON decoded", this.clientDataJsonDecoded);
const origSignature = Buffer.from(
authenticatorAssertionResponse.signature,
).toString("base64");
this.signature = origSignature
// Our custom type of JWANT means the signature is based on a concatenation of the two Webauthn properties
const header: JWTPayload = { typ: "JWANT", alg: "ES256" };
const headerBase64 = Buffer.from(JSON.stringify(header))
.toString("base64")
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=+$/, "");
@ -319,122 +203,159 @@ export class PeerSetup {
ClientDataJSON: this.clientDataJsonBase64Url,
};
const dataInJwtString = JSON.stringify(dataInJwt);
const payloadBase64 = Buffer.from(dataInJwtString).toString("base64");
const payloadBase64 = Buffer.from(dataInJwtString)
.toString("base64")
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=+$/, "");
const origSignature = Buffer.from(credential?.response.signature)
.toString("base64")
this.signature = origSignature
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=+$/, "");
const jwt = headerBase64 + "." + payloadBase64 + "." + this.signature;
return jwt;
}
// Attempted with JWS, but it will not match because it signs different content (header + payload)
//const signer = await this.webAuthnES256KSigner(credentialId);
//const jwt = createJWS(fullPayload, signer, { typ: "JWT", alg: "ES256" });
async webAuthnES256KSigner(credentialID: string) {
return async (data: string | Uint8Array) => {
const signature = await this.generateWebAuthnSignature(
data,
credentialID,
);
// This converts from the browser ArrayBuffer to a Node.js Buffer, which is a requirement for the asn1 library.
const signatureBuffer = Buffer.from(signature);
console.log("lower signature inside signer", signature);
console.log("lower buffer signature inside signer", signatureBuffer);
console.log("lower base64 buffer signature inside signer", signatureBuffer.toString("base64"));
// Decode the DER-encoded signature to extract R and S values
const reader = new asn1.BerReader(signatureBuffer);
console.log("lower after reader");
reader.readSequence();
console.log("lower after read sequence");
const r = reader.readString(asn1.Ber.Integer, true);
console.log("lower after r");
const s = reader.readString(asn1.Ber.Integer, true);
console.log("lower after r & s");
// Ensure R and S are 32 bytes each
const rBuffer = Buffer.from(r);
const sBuffer = Buffer.from(s);
console.log("lower after rBuffer & sBuffer", rBuffer, sBuffer);
const rWithoutPrefix = rBuffer.length > 32 ? rBuffer.slice(1) : rBuffer;
const sWithoutPrefix = sBuffer.length > 32 ? sBuffer.slice(1) : sBuffer;
const rPadded =
rWithoutPrefix.length < 32
? Buffer.concat([Buffer.alloc(32 - rWithoutPrefix.length), rBuffer])
: rWithoutPrefix;
const sPadded =
rWithoutPrefix.length < 32
? Buffer.concat([Buffer.alloc(32 - sWithoutPrefix.length), sBuffer])
: sWithoutPrefix;
// Concatenate R and S to form the 64-byte array (ECDSA signature format expected by JWT)
const combinedSignature = Buffer.concat([rPadded, sPadded]);
console.log(
"lower combinedSignature",
combinedSignature.length,
combinedSignature,
);
const combSig64 = combinedSignature.toString("base64");
console.log("lower combSig64", combSig64);
const combSig64Url = combSig64
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=+$/, "");
console.log("lower combSig64Url", combSig64Url);
return combSig64Url;
};
}
// return a low-level signing function, similar to createJWS approach
// async webAuthnES256KSigner(credentialID: string) {
// return async (data: string | Uint8Array) => {
// // get signature from WebAuthn
// const signature = await this.generateWebAuthnSignature(data);
//
// // This converts from the browser ArrayBuffer to a Node.js Buffer, which is a requirement for the asn1 library.
// const signatureBuffer = Buffer.from(signature);
// console.log("lower signature inside signer", signature);
// console.log("lower buffer signature inside signer", signatureBuffer);
// console.log("lower base64 buffer signature inside signer", signatureBuffer.toString("base64"));
// // Decode the DER-encoded signature to extract R and S values
// const reader = new asn1.BerReader(signatureBuffer);
// console.log("lower after reader");
// reader.readSequence();
// console.log("lower after read sequence");
// const r = reader.readString(asn1.Ber.Integer, true);
// console.log("lower after r");
// const s = reader.readString(asn1.Ber.Integer, true);
// console.log("lower after r & s");
//
// // Ensure R and S are 32 bytes each
// const rBuffer = Buffer.from(r);
// const sBuffer = Buffer.from(s);
// console.log("lower after rBuffer & sBuffer", rBuffer, sBuffer);
// const rWithoutPrefix = rBuffer.length > 32 ? rBuffer.slice(1) : rBuffer;
// const sWithoutPrefix = sBuffer.length > 32 ? sBuffer.slice(1) : sBuffer;
// const rPadded =
// rWithoutPrefix.length < 32
// ? Buffer.concat([Buffer.alloc(32 - rWithoutPrefix.length), rBuffer])
// : rWithoutPrefix;
// const sPadded =
// rWithoutPrefix.length < 32
// ? Buffer.concat([Buffer.alloc(32 - sWithoutPrefix.length), sBuffer])
// : sWithoutPrefix;
//
// // Concatenate R and S to form the 64-byte array (ECDSA signature format expected by JWT)
// const combinedSignature = Buffer.concat([rPadded, sPadded]);
// console.log(
// "lower combinedSignature",
// combinedSignature.length,
// combinedSignature,
// );
//
// const combSig64 = combinedSignature.toString("base64");
// console.log("lower combSig64", combSig64);
// const combSig64Url = combSig64
// .replace(/\+/g, "-")
// .replace(/\//g, "_")
// .replace(/=+$/, "");
// console.log("lower combSig64Url", combSig64Url);
// return combSig64Url;
// };
// }
}
async generateWebAuthnSignature(
dataToSign: string | Uint8Array, // from Signer interface
credentialId: string,
) {
if (!(dataToSign instanceof Uint8Array)) {
console.log("lower dataToSign & typeof ", typeof dataToSign, dataToSign);
dataToSign = new Uint8Array(base64URLStringToBuffer(dataToSign));
}
console.log("lower credentialId", credentialId);
this.challenge = dataToSign;
const options = {
publicKey: {
challenge: this.challenge.buffer,
rpID: window.location.hostname,
//allowCredentials: [{ id: credentialId, type: "public-key" }],
userVerification: "preferred",
//extensions: fullPayload,
export async function verifyJwtSimplewebauthn(
jwt: string,
credId: Base64URLString,
rawId: Uint8Array,
authenticatorData: ArrayBuffer,
authenticatorDataBase64Url: Base64URLString,
challenge: Uint8Array,
clientDataJSON: object,
clientDataJsonBase64Url: Base64URLString,
publicKeyBytes: Uint8Array,
publicKeyJwk: JWK,
signature: Base64URLString,
) {
const authData = arrayToBase64Url(Buffer.from(authenticatorData));
const authOpts: VerifyAuthenticationResponseOpts = {
authenticator: {
credentialID: credId,
credentialPublicKey: publicKeyBytes,
counter: 0,
},
expectedChallenge: arrayToBase64Url(challenge),
expectedOrigin: window.location.origin,
expectedRPID: window.location.hostname,
response: {
authenticatorAttachment: "platform",
clientExtensionResults: {},
id: credId,
rawId: arrayToBase64Url(rawId),
response: {
authenticatorData: authData,
clientDataJSON: arrayToBase64Url(
Buffer.from(JSON.stringify(clientDataJSON)),
),
signature: signature,
},
};
// console.log("lower authentication options", options);
const assertion = await navigator.credentials.get(options);
// console.log("lower credential get", assertion);
const authenticatorAssertionResponse = assertion?.response;
type: "public-key",
},
};
const verification = await verifyAuthenticationResponse(authOpts);
return verification.verified;
}
this.authenticatorDataBase64Url =
authenticatorAssertionResponse.authenticatorData;
this.authenticatorData = Buffer.from(
this.authenticatorDataBase64Url as Base64URLString,
"base64",
).buffer;
// console.log("lower authenticator data", this.authenticatorData);
// I'd love to use this but it doesn't verify.
// Pequires:
// npm install @noble/curves
// ... and this import:
// import { p256 } from "@noble/curves/p256";
export async function verifyJwtP256(
jwt: string,
credId: Base64URLString,
rawId: Uint8Array,
authenticatorData: ArrayBuffer,
authenticatorDataBase64Url: Base64URLString,
challenge: Uint8Array,
clientDataJSON: object,
clientDataJsonBase64Url: Base64URLString,
publicKeyBytes: Uint8Array,
publicKeyJwk: JWK,
signature: Base64URLString,
) {
const authDataFromBase = Buffer.from(authenticatorDataBase64Url, "base64");
const clientDataFromBase = Buffer.from(clientDataJsonBase64Url, "base64");
const sigBuffer = Buffer.from(signature, "base64");
const finalSigBuffer = unwrapEC2Signature(sigBuffer);
this.clientDataJsonBase64Url =
authenticatorAssertionResponse.clientDataJSON;
this.clientDataJsonDecoded = JSON.parse(
new TextDecoder("utf-8").decode(
authenticatorAssertionResponse.clientDataJSON,
),
);
// console.log("lower clientDataJSON decoded", this.clientDataJsonDecoded);
// Hash the client data
const hash = sha256(clientDataFromBase);
this.signature = Buffer.from(
authenticatorAssertionResponse.signature,
).toString("base64");
// Construct the preimage
const preimage = Buffer.concat([authDataFromBase, hash]);
return this.signature;
}
const isValid = p256.verify(
finalSigBuffer,
new Uint8Array(preimage),
publicKeyBytes,
);
return isValid;
}
export async function verifyJwt(
export async function verifyJwtWebCrypto(
jwt: string,
credId: Base64URLString,
rawId: Uint8Array,
@ -447,35 +368,6 @@ export async function verifyJwt(
publicKeyJwk: JWK,
signature: Base64URLString,
) {
// const authData = arrayToBase64Url(Buffer.from(authenticatorData));
// const authOpts: VerifyAuthenticationResponseOpts = {
// authenticator: {
// credentialID: credId,
// credentialPublicKey: publicKeyBytes,
// counter: 0,
// },
// expectedChallenge: arrayToBase64Url(challenge),
// expectedOrigin: window.location.origin,
// expectedRPID: window.location.hostname,
// response: {
// authenticatorAttachment: "platform",
// clientExtensionResults: {},
// id: credId,
// rawId: arrayToBase64Url(rawId),
// response: {
// authenticatorData: authData,
// clientDataJSON: arrayToBase64Url(
// Buffer.from(JSON.stringify(clientDataJSON)),
// ),
// signature: signature,
// },
// type: "public-key",
// },
// };
// console.log("auth opts", authOpts);
// const verification = await verifyAuthenticationResponse(authOpts);
// console.log("auth verification", verification);
const authDataFromBase = Buffer.from(authenticatorDataBase64Url, "base64");
const clientDataFromBase = Buffer.from(clientDataJsonBase64Url, "base64");
const sigBuffer = Buffer.from(signature, "base64");
@ -487,18 +379,6 @@ export async function verifyJwt(
// Construct the preimage
const preimage = Buffer.concat([authDataFromBase, hash]);
// console.log("finalSigBuffer", finalSigBuffer);
// console.log("preimage", preimage);
// console.log("publicKeyBytes", publicKeyBytes);
// This uses p256 from @noble/curves/p256, which I would prefer but it's returning false.
// const isValid = p256.verify(
// finalSigBuffer,
// new Uint8Array(preimage),
// publicKeyBytes,
// );
// console.log("isValid", isValid);
const WebCrypto = await getWebCrypto();
const verifyAlgorithm = {
name: "ECDSA",
@ -515,17 +395,12 @@ export async function verifyJwt(
false,
["verify"],
);
// console.log("verifyAlgorithm", verifyAlgorithm);
// console.log("publicKeyCryptoKey", publicKeyCryptoKey);
// console.log("finalSigBuffer", finalSigBuffer);
// console.log("preimage", preimage);
const verified = await WebCrypto.subtle.verify(
verifyAlgorithm,
publicKeyCryptoKey,
finalSigBuffer,
preimage,
);
// console.log("verified", verified);
return verified;
}
@ -628,7 +503,6 @@ function base64URLStringToBuffer(base64URLString) {
function cborToKeys(publicKeyBytes: Uint8Array) {
const jwkObj = cborDecode(publicKeyBytes);
console.log("jwkObj from verification", jwkObj);
if (
jwkObj[1] != 2 || // kty "EC"
jwkObj[3] != -7 || // alg "ES256"
@ -663,7 +537,7 @@ async function pemToCryptoKey(pem: string) {
for (let i = 0; i < binaryDerString.length; i++) {
binaryDer[i] = binaryDerString.charCodeAt(i);
}
console.log("binaryDer", binaryDer.buffer);
// console.log("binaryDer", binaryDer.buffer);
return await window.crypto.subtle.importKey(
"spki",
binaryDer.buffer,

173
src/views/TestView.vue

@ -172,24 +172,51 @@
<div class="mt-8">
<h2 class="text-xl font-bold mb-4">Passkeys</h2>
<button
@click="register()"
class="font-bold uppercase bg-slate-600 text-white px-3 py-2 rounded-md mr-2"
>
<div>
Register
</button>
<button
@click="create()"
class="font-bold uppercase bg-slate-600 text-white px-3 py-2 rounded-md mr-2"
>
<button
@click="register()"
class="font-bold uppercase bg-slate-600 text-white px-3 py-2 rounded-md mr-2"
>
Simplewebauthn
</button>
</div>
<div>
Create
</button>
<button
@click="verify()"
class="font-bold uppercase bg-slate-600 text-white px-3 py-2 rounded-md mr-2"
>
<button
@click="createJwtSimplewebauthn()"
class="font-bold uppercase bg-slate-600 text-white px-3 py-2 rounded-md mr-2"
>
Simplewebauthn
</button>
<button
@click="createJwtNavigator()"
class="font-bold uppercase bg-slate-600 text-white px-3 py-2 rounded-md mr-2"
>
Navigator
</button>
</div>
<div>
Verify
</button>
<button
@click="verifySimplewebauthn()"
class="font-bold uppercase bg-slate-600 text-white px-3 py-2 rounded-md mr-2"
>
Simplewebauthn
</button>
<button
@click="verifyWebCrypto()"
class="font-bold uppercase bg-slate-600 text-white px-3 py-2 rounded-md mr-2"
>
WebCrypto
</button>
<button
@click="verifyP256()"
class="font-bold uppercase bg-slate-600 text-white px-3 py-2 rounded-md mr-2"
>
p256 - broken
</button>
</div>
</div>
</section>
</template>
@ -206,11 +233,11 @@ import {
createPeerDid,
JWK,
PeerSetup,
registerCredential,
verifyJwt,
registerCredential, verifyJwtP256,
verifyJwtSimplewebauthn,
verifyJwtWebCrypto,
} from "@/libs/didPeer";
import { Buffer } from "buffer";
import {JWTPayload} from "did-jwt";
import { JWTPayload } from "did-jwt";
const inputFileNameRef = ref<Blob>();
@ -220,21 +247,12 @@ export default class Help extends Vue {
fileName?: string;
// for passkeys
authenticatorData?: ArrayBuffer;
credId?: Base64URLString;
jwt?: string;
jwt2?: string;
payload = {
"@context": "https://schema.org",
type: "GiveAction",
description: "pizza",
};
peerSetup?: PeerSetup;
peerSetup2?: PeerSetup;
publicKeyJwk?: JWK;
publicKeyBytes?: Uint8Array;
rawId?: Uint8Array;
savedCredentialId = "";
userId?: ArrayBuffer;
async uploadFile(event: Event) {
@ -269,8 +287,6 @@ export default class Help extends Vue {
public async register() {
this.userId = generateRandomBytes(16).buffer;
const encodedUserId = Buffer.from(this.userId).toString("base64");
console.log("encodedUserId", encodedUserId);
const cred = await registerCredential(this.userId as Uint8Array);
console.log("public key", cred);
@ -278,55 +294,76 @@ export default class Help extends Vue {
this.publicKeyBytes = cred.publicKeyBytes;
this.credId = cred.credId as string;
this.rawId = cred.rawId as Uint8Array;
this.savedCredentialId = this.credId;
}
public async create() {
console.log("Starting a create");
public async createJwtSimplewebauthn() {
const did = createPeerDid(this.publicKeyBytes as Uint8Array);
// console.log("did", did);
console.log("generated peer did", did);
const payload = {
"@context": "https://schema.org",
type: "GiveAction",
description: "pizza",
};
// from createJWT in did-jwt/src/JWT.ts
const timestamps: Partial<JWTPayload> = {
iat: Math.floor(Date.now() / 1000),
exp: undefined,
};
const fullPayload = { ...timestamps, ...this.payload, did };
const fullPayload = { ...timestamps, ...payload, did };
this.peerSetup = new PeerSetup();
const rawJwt = await this.peerSetup.createJwt(
this.jwt = await this.peerSetup.createJwtSimplewebauthn(
fullPayload,
this.credId as string,
);
//console.log("simple raw jwt", rawJwt);
this.jwt = rawJwt
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=+$/, "");
console.log("simple jwt4url", this.jwt);
// console.log("simple peerSetup", this.peerSetup);
}
public async createJwtNavigator() {
const did = createPeerDid(this.publicKeyBytes as Uint8Array);
console.log("generated peer did", did);
const payload = {
"@context": "https://schema.org",
type: "GiveAction",
description: "pizza",
};
// from createJWT in did-jwt/src/JWT.ts
const timestamps: Partial<JWTPayload> = {
iat: Math.floor(Date.now() / 1000),
exp: undefined,
};
const fullPayload = { ...timestamps, ...payload, did };
this.peerSetup2 = new PeerSetup();
const rawJwt2 = await this.peerSetup2.createJwt2(
this.peerSetup = new PeerSetup();
this.jwt = await this.peerSetup.createJwtNavigator(
fullPayload,
this.credId as string,
);
// console.log("lower raw jwt2", rawJwt2);
this.jwt2 = rawJwt2
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=+$/, "");
console.log("lower jwt4url2", this.jwt2);
// console.log("lower peerSetup2", this.peerSetup2);
console.log("lower jwt4url", this.jwt);
}
public async verify() {
if (!this.jwt || !this.peerSetup) {
alert("Create a JWT first.");
return;
}
const decoded = await verifyJwt(
this.jwt,
public async verifyP256() {
const decoded = await verifyJwtP256(
this.jwt as string,
this.credId as Base64URLString,
this.rawId as Uint8Array,
this.peerSetup.authenticatorData as ArrayBuffer,
this.peerSetup.authenticatorDataBase64Url as Base64URLString,
this.peerSetup.challenge as Uint8Array,
this.peerSetup.clientDataJsonDecoded,
this.peerSetup.clientDataJsonBase64Url as Base64URLString,
this.publicKeyBytes as Uint8Array,
this.publicKeyJwk as JWK,
this.peerSetup.signature as Base64URLString,
);
console.log("decoded", decoded);
}
public async verifySimplewebauthn() {
const decoded = await verifyJwtSimplewebauthn(
this.jwt as string,
this.credId as Base64URLString,
this.rawId as Uint8Array,
this.peerSetup.authenticatorData as ArrayBuffer,
@ -339,21 +376,23 @@ export default class Help extends Vue {
this.peerSetup.signature as Base64URLString,
);
console.log("decoded", decoded);
}
const decoded2 = await verifyJwt(
this.jwt2 as string,
public async verifyWebCrypto() {
const decoded = await verifyJwtWebCrypto(
this.jwt as string,
this.credId as Base64URLString,
this.rawId as Uint8Array,
this.peerSetup2.authenticatorData as ArrayBuffer,
this.peerSetup2.authenticatorDataBase64Url as Base64URLString,
this.peerSetup2.challenge as Uint8Array,
this.peerSetup2.clientDataJsonDecoded,
this.peerSetup2.clientDataJsonBase64Url as Base64URLString,
this.peerSetup.authenticatorData as ArrayBuffer,
this.peerSetup.authenticatorDataBase64Url as Base64URLString,
this.peerSetup.challenge as Uint8Array,
this.peerSetup.clientDataJsonDecoded,
this.peerSetup.clientDataJsonBase64Url as Base64URLString,
this.publicKeyBytes as Uint8Array,
this.publicKeyJwk as JWK,
this.peerSetup2.signature as Base64URLString,
this.peerSetup.signature as Base64URLString,
);
console.log("decoded2", decoded2);
console.log("decoded", decoded);
}
}
</script>

Loading…
Cancel
Save