Skip to content

Commit

Permalink
prove identity using wot.computeFingerprint()
Browse files Browse the repository at this point in the history
This replaces the old `crypto.getFingerprint()` shown in user profiles.
The new method will create a hash of _all_ relevant public keys for a given user.
Also it is based on JWK Thumbprints, which are more standardized and are encoding-agnostic
  • Loading branch information
overheadhunter committed Jun 12, 2024
1 parent 3f88f0c commit 7efc6a1
Show file tree
Hide file tree
Showing 5 changed files with 29 additions and 20 deletions.
12 changes: 0 additions & 12 deletions frontend/src/common/crypto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -466,18 +466,6 @@ export async function asPublicKey(publicKey: CryptoKey | BufferSource, keyDesign
}
}

export async function getFingerprint(key: string | undefined) {
if (key) {
const encodedKey = new TextEncoder().encode(key);
const hashBuffer = await crypto.subtle.digest('SHA-256', encodedKey);
const hashArray = Array.from(new Uint8Array(hashBuffer));
const hashHex = hashArray
.map((b) => b.toString(16).padStart(2, '0').toUpperCase())
.join('');
return hashHex;
}
}

/**
* Computes the JWK Thumbprint (RFC 7638) using SHA-256.
* @param key A key to compute the thumbprint for
Expand Down
22 changes: 20 additions & 2 deletions frontend/src/common/wot.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { base64 } from 'rfc4648';
import backend, { TrustDto, UserDto } from './backend';
import { UserKeys, asPublicKey } from './crypto';
import { UserKeys, asPublicKey, getJwkThumbprint } from './crypto';
import { JWT, JWTHeader } from './jwt';
import userdata from './userdata';

Expand Down Expand Up @@ -75,4 +75,22 @@ async function verifyRescursive(signatureChain: string[], signerPublicKey: Crypt
}
}

export default { sign, verify };
async function computeFingerprint(user: UserDto) {
if (!user.ecdhPublicKey || !user.ecdsaPublicKey) {
throw new Error('User has no public keys');
}
const ecdhPublicKey = await asPublicKey(base64.parse(user.ecdhPublicKey), UserKeys.ECDH_KEY_DESIGNATION);
const ecdsaPublicKey = await asPublicKey(base64.parse(user.ecdsaPublicKey), UserKeys.ECDSA_KEY_DESIGNATION, UserKeys.ECDSA_PUB_KEY_USAGES);
const concatenatedThumbprints = new Uint8Array([
...await getJwkThumbprint(ecdhPublicKey),
...await getJwkThumbprint(ecdsaPublicKey)
]);
const digest = await crypto.subtle.digest('SHA-256', concatenatedThumbprints);
const digestBytes = Array.from(new Uint8Array(digest));
const digestHexStr = digestBytes
.map((b) => b.toString(16).padStart(2, '0').toUpperCase())
.join('');
return digestHexStr;
}

export default { sign, verify, computeFingerprint };
5 changes: 3 additions & 2 deletions frontend/src/components/GrantPermissionDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ import { base64 } from 'rfc4648';
import { onMounted, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import backend, { AccessGrant, ConflictError, NotFoundError, UserDto, VaultDto } from '../common/backend';
import { VaultKeys, getFingerprint } from '../common/crypto';
import { VaultKeys } from '../common/crypto';
import wot from '../common/wot';
const { t } = useI18n({ useScope: 'global' });
Expand Down Expand Up @@ -101,7 +102,7 @@ onMounted(fetchData);
async function fetchData() {
for (const user of props.users) {
userKeyFingerprints.value.set(user.id, await getFingerprint(user.ecdhPublicKey));
userKeyFingerprints.value.set(user.id, await wot.computeFingerprint(user));
}
}
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/UserProfile.vue
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
<div class="grid grid-cols-1 gap-8 lg:col-span-3">
<ManageSetupCode />
<DeviceList />
<UserkeyFingerprint :user-public-key="me.ecdhPublicKey"/>
<UserkeyFingerprint :user="me"/>
</div>
</div>
</div>
Expand Down
8 changes: 5 additions & 3 deletions frontend/src/components/UserkeyFingerprint.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,22 @@
<script setup lang="ts">
import { onMounted, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { getFingerprint } from '../common/crypto';
import { UserDto } from '../common/backend';
import wot from '../common/wot';
const { t } = useI18n({ useScope: 'global' });
const keyFingerprint = ref<string | undefined>();
const props = defineProps<{
userPublicKey?: string
user: UserDto
}>();
onMounted(fetchData);
async function fetchData() {
keyFingerprint.value = await getFingerprint(props.userPublicKey).then((key) => key?.replace(/.{8}/g, "$&" + " "))
const fingerprint = await wot.computeFingerprint(props.user);
keyFingerprint.value = fingerprint?.replace(/.{8}/g, "$&" + " ").trim(); // Add space after every 8 characters
}
</script>

0 comments on commit 7efc6a1

Please sign in to comment.