blob: 97bef50bcf8fc60a19d74afb094559112f5b0d78 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
import crypto from 'crypto';
import { verify as ed25519Verify } from '@noble/ed25519';
import { COSEKEYS, COSEKTY, COSEPublicKey } from './convertCOSEtoPKCS';
import { convertCertBufferToPEM } from './convertCertBufferToPEM';
import { convertPublicKeyToPEM } from './convertPublicKeyToPEM';
import * as cbor from './cbor';
type VerifySignatureOptsLeafCert = {
signature: Uint8Array;
signatureBase: Uint8Array;
leafCert: Uint8Array;
hashAlgorithm?: string;
};
type VerifySignatureOptsCredentialPublicKey = {
signature: Uint8Array;
signatureBase: Uint8Array;
credentialPublicKey: Uint8Array;
hashAlgorithm?: string;
};
/**
* Verify an authenticator's signature
*
* @param signature attStmt.sig
* @param signatureBase Bytes that were signed over
* @param publicKey Authenticator's public key as a PEM certificate
* @param algo Which algorithm to use to verify the signature (default: `'sha256'`)
*/
export async function verifySignature(
opts: VerifySignatureOptsLeafCert | VerifySignatureOptsCredentialPublicKey,
): Promise<boolean> {
const { signature, signatureBase, hashAlgorithm = 'sha256' } = opts;
const _isLeafcertOpts = isLeafCertOpts(opts);
const _isCredPubKeyOpts = isCredPubKeyOpts(opts);
if (!_isLeafcertOpts && !_isCredPubKeyOpts) {
throw new Error('Must declare either "leafCert" or "credentialPublicKey"');
}
if (_isLeafcertOpts && _isCredPubKeyOpts) {
throw new Error('Must not declare both "leafCert" and "credentialPublicKey"');
}
let publicKeyPEM = '';
if (_isCredPubKeyOpts) {
const { credentialPublicKey } = opts;
// Decode CBOR to COSE
let struct;
try {
struct = cbor.decodeFirst<COSEPublicKey>(credentialPublicKey);
} catch (err) {
const _err = err as Error;
throw new Error(`Error decoding public key while converting to PEM: ${_err.message}`);
}
const kty = struct.get(COSEKEYS.kty);
if (!kty) {
throw new Error('Public key was missing kty');
}
// Check key type
if (kty === COSEKTY.OKP) {
// Verify Ed25519 slightly differently
const x = struct.get(COSEKEYS.x);
if (!x) {
throw new Error('Public key was missing x (OKP)');
}
return ed25519Verify(signature, signatureBase, (x as Uint8Array));
} else {
// Convert pubKey to PEM for ECC and RSA
publicKeyPEM = convertPublicKeyToPEM(credentialPublicKey);
}
}
if (_isLeafcertOpts) {
const { leafCert } = opts;
publicKeyPEM = convertCertBufferToPEM(leafCert);
}
return crypto.createVerify(hashAlgorithm).update(signatureBase).verify(publicKeyPEM, signature);
}
function isLeafCertOpts(
opts: VerifySignatureOptsLeafCert | VerifySignatureOptsCredentialPublicKey,
): opts is VerifySignatureOptsLeafCert {
return Object.keys(opts as VerifySignatureOptsLeafCert).indexOf('leafCert') >= 0;
}
function isCredPubKeyOpts(
opts: VerifySignatureOptsLeafCert | VerifySignatureOptsCredentialPublicKey,
): opts is VerifySignatureOptsCredentialPublicKey {
return (
Object.keys(opts as VerifySignatureOptsCredentialPublicKey).indexOf('credentialPublicKey') >= 0
);
}
|