Skip to content

Instantly share code, notes, and snippets.

@colek42
Last active April 12, 2023 12:26
Show Gist options
  • Save colek42/b47e5dde5d180da60a264b94b6af4a94 to your computer and use it in GitHub Desktop.
Save colek42/b47e5dde5d180da60a264b94b6af4a94 to your computer and use it in GitHub Desktop.
async function signTextWithYubiKey() {
try {
// Create a new credential
const challenge = new Uint8Array(32);
crypto.getRandomValues(challenge);
const publicKeyCredentialCreationOptions = {
challenge,
rp: { name: 'example.com' },
user: {
id: new Uint8Array(16),
name: 'user@example.com',
displayName: 'User'
},
pubKeyCredParams: [
{ type: 'public-key', alg: -7 }, // ES256
{ type: 'public-key', alg: -257 } // RS256
],
authenticatorSelection: {
authenticatorAttachment: 'cross-platform'
},
timeout: 60000,
attestation: 'none'
};
const credential = await navigator.credentials.create({
publicKey: publicKeyCredentialCreationOptions
});
console.log('New credential:', credential);
// Sign the text "Hello, World!" with the YubiKey
const textToSign = "Hello, World!";
const textChallenge = new TextEncoder().encode(textToSign);
const publicKeyCredentialRequestOptions = {
challenge: textChallenge,
allowCredentials: [
{
type: 'public-key',
id: credential.rawId,
transports: ['usb']
}
],
timeout: 60000
};
const assertion = await navigator.credentials.get({
publicKey: publicKeyCredentialRequestOptions
});
const signature = assertion.response.signature;
console.log('Signed text:', signature);
// Retrieve the public key object from the attestation response
const attestationBuffer = new Uint8Array(credential.response.attestationObject).buffer;
const attestation = CBOR.decode(attestationBuffer);
const publicKeyObject = attestation.authData.slice(37);
return { publicKeyObject, signature };
} catch (error) {
console.error('Error:', error);
}
}
async function verifySignature(publicKeyObject, signature, text) {
try {
// Import the public key object
const publicKey = await crypto.subtle.importKey(
'raw',
publicKeyObject,
{ name: 'ECDSA', namedCurve: 'P-256' },
true,
['verify']
);
// Verify the signature
const textBytes = new TextEncoder().encode(text);
const isValid = await crypto.subtle.verify(
{ name: 'ECDSA', hash: { name: 'SHA-256' } },
publicKey,
signature,
textBytes
);
if (isValid) {
console.log('The signature is valid.');
} else {
console.log('The signature is invalid.');
}
} catch (error) {
console.error('Error:', error);
}
}
(async () => {
const { publicKeyObject, signature } = await signTextWithYubiKey();
await verifySignature(publicKeyObject, signature, "Hello, World!");
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment