diff --git a/src/libs/didPeer.ts b/src/libs/didPeer.ts
index a9ee6fc..3e259a6 100644
--- a/src/libs/didPeer.ts
+++ b/src/libs/didPeer.ts
@@ -23,7 +23,8 @@ import {
import { getWebCrypto, unwrapEC2Signature } from "@/libs/crypto/passkeyHelpers";
-const PEER_DID_PREFIX = "did:peer:0";
+const PEER_DID_PREFIX = "did:peer:";
+const PEER_DID_MULTIBASE_PREFIX = PEER_DID_PREFIX + "0";
export interface JWK {
kty: string;
crv: string;
@@ -99,11 +100,11 @@ export function createPeerDid(publicKeyBytes: Uint8Array) {
"base58btc",
"p256-pub",
);
- return PEER_DID_PREFIX + methodSpecificId;
+ return PEER_DID_MULTIBASE_PREFIX + methodSpecificId;
}
function peerDidToPublicKeyBytes(did: string) {
- return multibaseToBytes(did.substring(PEER_DID_PREFIX.length));
+ return multibaseToBytes(did.substring(PEER_DID_MULTIBASE_PREFIX.length));
}
export class PeerSetup {
@@ -112,10 +113,19 @@ export class PeerSetup {
public clientDataJsonBase64Url?: Base64URLString;
public signature?: Base64URLString;
- public async createJwtSimplewebauthn(fullPayload: object, credIdHex: string) {
+ public async createJwtSimplewebauthn(
+ issuerDid: string,
+ payload: object,
+ credIdHex: string,
+ ) {
const credentialId = arrayBufferToBase64URLString(
Buffer.from(credIdHex, "hex").buffer,
);
+ const fullPayload = {
+ ...payload,
+ iat: Math.floor(Date.now() / 1000),
+ iss: issuerDid,
+ };
this.challenge = new Uint8Array(Buffer.from(JSON.stringify(fullPayload)));
// const payloadHash: Uint8Array = sha256(this.challenge);
const options: PublicKeyCredentialRequestOptionsJSON =
@@ -147,18 +157,33 @@ export class PeerSetup {
.replace(/=+$/, "");
const dataInJwt = {
- AuthenticationData: authenticatorDataBase64Url,
- ClientDataJSON: this.clientDataJsonBase64Url,
+ AuthenticationDataB64URL: authenticatorDataBase64Url,
+ ClientDataJSONB64URL: this.clientDataJsonBase64Url,
+ iat: Math.floor(Date.now() / 1000),
+ iss: issuerDid,
};
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 signature = clientAuth.response.signature;
return headerBase64 + "." + payloadBase64 + "." + signature;
}
- public async createJwtNavigator(fullPayload: object, credIdHex: string) {
+ public async createJwtNavigator(
+ issuerDid: string,
+ payload: object,
+ credIdHex: string,
+ ) {
+ const fullPayload = {
+ ...payload,
+ iat: Math.floor(Date.now() / 1000),
+ iss: issuerDid,
+ };
const dataToSignString = JSON.stringify(fullPayload);
const dataToSignBuffer = Buffer.from(dataToSignString);
const credentialId = Buffer.from(credIdHex, "hex");
@@ -200,8 +225,10 @@ export class PeerSetup {
.replace(/=+$/, "");
const dataInJwt = {
- AuthenticationData: authenticatorDataBase64Url,
- ClientDataJSON: this.clientDataJsonBase64Url,
+ AuthenticationDataB64URL: authenticatorDataBase64Url,
+ ClientDataJSONB64URL: this.clientDataJsonBase64Url,
+ iat: Math.floor(Date.now() / 1000),
+ iss: issuerDid,
};
const dataInJwtString = JSON.stringify(dataInJwt);
const payloadBase64 = Buffer.from(dataInJwtString)
@@ -284,7 +311,7 @@ export class PeerSetup {
// import { p256 } from "@noble/curves/p256";
export async function verifyJwtP256(
credIdHex: string,
- did: string,
+ issuerDid: string,
authenticatorData: ArrayBuffer,
challenge: Uint8Array,
clientDataJsonBase64Url: Base64URLString,
@@ -294,7 +321,7 @@ export async function verifyJwtP256(
const clientDataFromBase = Buffer.from(clientDataJsonBase64Url, "base64");
const sigBuffer = Buffer.from(signature, "base64");
const finalSigBuffer = unwrapEC2Signature(sigBuffer);
- const publicKeyBytes = peerDidToPublicKeyBytes(did);
+ const publicKeyBytes = peerDidToPublicKeyBytes(issuerDid);
// Hash the client data
const hash = sha256(clientDataFromBase);
@@ -312,14 +339,14 @@ export async function verifyJwtP256(
export async function verifyJwtSimplewebauthn(
credIdHex: string,
- did: string,
+ issuerDid: string,
authenticatorData: ArrayBuffer,
challenge: Uint8Array,
clientDataJsonBase64Url: Base64URLString,
signature: Base64URLString,
) {
const authData = arrayToBase64Url(Buffer.from(authenticatorData));
- const publicKeyBytes = peerDidToPublicKeyBytes(did);
+ const publicKeyBytes = peerDidToPublicKeyBytes(issuerDid);
const credId = arrayBufferToBase64URLString(
Buffer.from(credIdHex, "hex").buffer,
);
@@ -351,7 +378,7 @@ export async function verifyJwtSimplewebauthn(
export async function verifyJwtWebCrypto(
credId: Base64URLString,
- did: string,
+ issuerDid: string,
authenticatorData: ArrayBuffer,
challenge: Uint8Array,
clientDataJsonBase64Url: Base64URLString,
@@ -368,12 +395,13 @@ export async function verifyJwtWebCrypto(
// Construct the preimage
const preimage = Buffer.concat([authDataFromBase, hash]);
+ const publicKeyBytes = peerDidToPublicKeyBytes(issuerDid);
+
const WebCrypto = await getWebCrypto();
const verifyAlgorithm = {
name: "ECDSA",
hash: { name: "SHA-256" },
};
- const publicKeyBytes = peerDidToPublicKeyBytes(did);
const publicKeyJwk = cborToKeys(publicKeyBytes).publicKeyJwk;
const keyAlgorithm = {
name: "ECDSA",
diff --git a/src/views/TestView.vue b/src/views/TestView.vue
index 3ced12e..dc6a40c 100644
--- a/src/views/TestView.vue
+++ b/src/views/TestView.vue
@@ -221,6 +221,12 @@
p256 - broken
+
@@ -241,11 +247,20 @@ import {
verifyJwtSimplewebauthn,
verifyJwtWebCrypto,
} from "@/libs/didPeer";
-import { JWTPayload } from "did-jwt";
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
const inputFileNameRef = ref();
+const TEST_PAYLOAD = {
+ vc: {
+ credentialSubject: {
+ "@context": "https://schema.org",
+ "@type": "GiveAction",
+ description: "pizza",
+ },
+ },
+};
+
@Component({ components: { QuickNav } })
export default class Help extends Vue {
// for file import
@@ -265,8 +280,10 @@ export default class Help extends Vue {
this.userName = settings?.firstName as string;
await accountsDB.open();
- const account: { identity?: string } | undefined =
- await accountsDB.accounts.where("did").equals(this.activeDid).first();
+ const account: { identity?: string } | undefined = await accountsDB.accounts
+ .where("did")
+ .equals(this.activeDid)
+ .first();
if (this.activeDid) {
if (account) {
this.credIdHex = account.passkeyCredIdHex as string;
@@ -318,50 +335,24 @@ export default class Help extends Vue {
did: this.activeDid,
passkeyCredIdHex: this.credIdHex,
publicKeyHex: Buffer.from(publicKeyBytes).toString("hex"),
- });
-
- // await db.settings.update(MASTER_SETTINGS_KEY, {
- // activeDid: this.did,
- // });
+ });``
}
public async createJwtSimplewebauthn() {
- const payload = {
- "@context": "https://schema.org",
- type: "GiveAction",
- description: "pizza",
- };
- // from createJWT in did-jwt/src/JWT.ts
- const timestamps: Partial = {
- iat: Math.floor(Date.now() / 1000),
- };
- const fullPayload = { ...timestamps, ...payload, iss: this.activeDid };
-
this.peerSetup = new PeerSetup();
this.jwt = await this.peerSetup.createJwtSimplewebauthn(
- fullPayload,
+ this.activeDid as string,
+ TEST_PAYLOAD,
this.credIdHex as string,
);
console.log("simple jwt4url", this.jwt);
}
public async createJwtNavigator() {
- console.log("generated peer did", this.activeDid);
-
- const payload = {
- "@context": "https://schema.org",
- type: "GiveAction",
- description: "pizza",
- };
- // from createJWT in did-jwt/src/JWT.ts
- const timestamps: Partial = {
- iat: Math.floor(Date.now() / 1000),
- };
- const fullPayload = { ...timestamps, ...payload, iss: this.activeDid };
-
this.peerSetup = new PeerSetup();
this.jwt = await this.peerSetup.createJwtNavigator(
- fullPayload,
+ this.activeDid as string,
+ TEST_PAYLOAD,
this.credIdHex as string,
);
console.log("lower jwt4url", this.jwt);
@@ -402,5 +393,29 @@ export default class Help extends Vue {
);
console.log("decoded", decoded);
}
+ public async verifyMyJwt() {
+ const jwt =
+ "eyJ0eXAiOiJKV0FOVCIsImFsZyI6IkVTMjU2In0.eyJBdXRoZW50aWNhdGlvbkRhdGFCNjRVUkwiOiJTWllONVlnT2pHaDBOQmNQWkhaZ1c0X2tycm1paGpMSG1Wenp1b01kbDJNRkFBQUFBQSIsIkNsaWVudERhdGFKU09OQjY0VVJMIjoiZXlKMGVYQmxJam9pZDJWaVlYVjBhRzR1WjJWMElpd2lZMmhoYkd4bGJtZGxJam9pWlhsS01sbDVTVFpsZVVwcVkyMVdhMXBYTlRCaFYwWnpWVE5XYVdGdFZtcGtRMGsyWlhsS1FWa3lPWFZrUjFZMFpFTkpOa2x0YURCa1NFSjZUMms0ZG1NeVRtOWFWekZvVEcwNWVWcDVTWE5KYTBJd1pWaENiRWxxYjJsU01td3lXbFZHYW1SSGJIWmlhVWx6U1cxU2JHTXlUbmxoV0VJd1lWYzVkVWxxYjJsalIydzJaVzFGYVdaWU1ITkpiV3hvWkVOSk5rMVVZM2hQUkZVMFRtcHJOVTFEZDJsaFdFNTZTV3B2YVZwSGJHdFBia0pzV2xoSk5rMUljRXhVVlZweFpHeFdibGRZU2s1TlYyaFpaREJTYW1GV2JFbGhWVVUxVkZob1dXUkZjRkZYUnpWVFZFVndNbU5YT1U1VWEwWk1ZakJTVFZkRWJIZFRNREZZVkVkSmVsWnJVbnBhTTFab1RWaEJlV1ZzWTNobFJtaFRZekp3WVZVeFVrOWpNbG95VkZjMVQyVlZNVlJPTWxKRFRrZHpNMVJyUm05U2JtUk5UVE5DV1ZGdVNrTlhSMlExVjFWdk5XTnRhMmxtVVNJc0ltOXlhV2RwYmlJNkltaDBkSEE2THk5c2IyTmhiR2h2YzNRNk9EQTRNQ0lzSW1OeWIzTnpUM0pwWjJsdUlqcG1ZV3h6WlgwIiwiaWF0IjoxNzE4NTg2OTkyLCJpc3MiOiJkaWQ6cGVlcjowektNRmp2VWdZck0xaFh3RGNpWUhpQTlNeFh0SlBYblJMSnZxb01OQUtvRExYOXBLTVdMYjNWRHNndWExcDJ6VzF4WFJzalpTVE5zZnZNbk55TVM3ZEI0azdOQWhGd0wzcFhCckJYZ3lZSjlyaSJ9.MEUCIQDJyCTbMPIFnuBoW3FYnlgtDEIHZ2OrkCEvqVnHU7kJDQIgVxjBjfW1TwQfcSOYwK8Z7AdCWGJlyxtLEsrnPif7caE";
+ const pieces = jwt.split(".");
+ console.log("pieces", typeof pieces[1], pieces);
+ const payload = JSON.parse(Buffer.from(pieces[1], "base64").toString());
+ const authData = Buffer.from(payload["AuthenticationDataB64URL"], "base64");
+ const clientJSON = Buffer.from(
+ payload["ClientDataJSONB64URL"],
+ "base64",
+ ).toString();
+ const clientData = JSON.parse(clientJSON);
+ const challenge = clientData.challenge;
+ const signatureB64URL = pieces[2];
+ const decoded = await verifyJwtWebCrypto(
+ this.credIdHex as Base64URLString,
+ this.activeDid as string,
+ authData,
+ challenge,
+ payload["ClientDataJSONB64URL"],
+ signatureB64URL,
+ );
+ console.log("decoded", decoded);
+ }
}