You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
86 lines
4.6 KiB
86 lines
4.6 KiB
|
1 week ago
|
// Tests of security.ts: the empty area that writers write, the verdicts of
|
||
|
|
// the signature and of the seal on the cases of TestSecurityVerdicts of the
|
||
|
|
// Go reference and a few more, and the Spanish lines of spec §29.7, all as
|
||
|
|
// the reference gives them at spec-v0.10.
|
||
|
|
|
||
|
|
import { describe, expect, it } from 'vitest';
|
||
|
|
import { h, hx } from './testing/testdata.ts';
|
||
|
|
import { arr, b, bn, map, t, u } from './testing/cborhex.ts';
|
||
|
|
import { encodeSecurity, evaluateSecurity, type Verdict, verdictLines, verdictText } from './security.ts';
|
||
|
|
|
||
|
|
const EMPTY = 'a20071646174656b6579732d73656375726974790101';
|
||
|
|
// An author-signature of alg 1 with a key of 32 zero bytes and a signature
|
||
|
|
// of 64: 105 bytes, as Go's EncodeAuthorSignature(1, ...) writes it.
|
||
|
|
const SIGNATURE = map([0, u(1)], [1, bn(32)], [2, bn(64)]);
|
||
|
|
const SEAL = map([0, u(1)], [1, b('010203')]);
|
||
|
|
|
||
|
|
// SECURITY_CBOR with keys 2 and 3 when given, as hex.
|
||
|
|
function security(signature?: string, seal?: string): Uint8Array {
|
||
|
|
const pairs: [number, string][] = [
|
||
|
|
[0, t('datekeys-security')],
|
||
|
|
[1, u(1)],
|
||
|
|
];
|
||
|
|
if (signature !== undefined) pairs.push([2, b(signature)]);
|
||
|
|
if (seal !== undefined) pairs.push([3, b(seal)]);
|
||
|
|
return h(map(...pairs));
|
||
|
|
}
|
||
|
|
|
||
|
|
describe('encodeSecurity', () => {
|
||
|
|
it('writes the empty area of 22 bytes, which yields F0 and S0', () => {
|
||
|
|
expect(hx(encodeSecurity())).toBe(EMPTY);
|
||
|
|
expect(SIGNATURE.length / 2).toBe(105);
|
||
|
|
expect(security(SIGNATURE).length).toBe(130);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('evaluateSecurity', () => {
|
||
|
|
it.each([
|
||
|
|
['empty', security(), 'F0', 'S0'],
|
||
|
|
['a signature of alg 1', security(SIGNATURE), 'F1', 'S0'],
|
||
|
|
['a seal of seal_type 1', security(undefined, SEAL), 'F0', 'S1'],
|
||
|
|
['both', security(SIGNATURE, SEAL), 'F1', 'S1'],
|
||
|
|
['alg 0', security(map([0, u(0)], [1, b('')], [2, b('')])), 'F1', 'S0'],
|
||
|
|
['a signature that is no map', security('01'), 'F1', 'S0'],
|
||
|
|
// The first row that holds decides: a seal with an unknown key and an
|
||
|
|
// unknown seal_type breaks its schema, S2, before its type is read.
|
||
|
|
['a seal with an unknown key', security(undefined, 'a300070141000200'), 'F0', 'S2'],
|
||
|
|
['seal_type 0', security(undefined, map([0, u(0)], [1, b('01')])), 'F0', 'S2'],
|
||
|
|
['a seal that is not CBOR', security(SIGNATURE, 'ff'), 'F1', 'S2'],
|
||
|
|
['a seal with seal_type 2^32', security(undefined, map([0, u(2 ** 32)], [1, b('')])), 'F0', 'S2'],
|
||
|
|
['a seal with a trailing byte', security(undefined, SEAL + '00'), 'F0', 'S2'],
|
||
|
|
['a seal without its token', security(undefined, map([0, u(1)])), 'F0', 'S2'],
|
||
|
|
['a seal with key 2 in place of its token', security(undefined, map([0, u(1)], [2, b('')])), 'F0', 'S2'],
|
||
|
|
['a seal with an empty token', security(undefined, map([0, u(7)], [1, b('')])), 'F0', 'S1'],
|
||
|
|
['version 2', h(map([0, t('datekeys-security')], [1, u(2)])), 'X', 'X'],
|
||
|
|
['another type tag', h(map([0, t('datekeys-head')], [1, u(1)])), 'X', 'X'],
|
||
|
|
['an unknown key 4', h(map([0, t('datekeys-security')], [1, u(1)], [4, b('01')])), 'X', 'X'],
|
||
|
|
['key 2 not a byte string', h(map([0, t('datekeys-security')], [1, u(1)], [2, u(1)])), 'X', 'X'],
|
||
|
|
['an empty key 2', h(map([0, t('datekeys-security')], [1, u(1)], [2, b('')])), 'X', 'X'],
|
||
|
|
['a key 2 of 65537 bytes', h(map([0, t('datekeys-security')], [1, u(1)], [2, bn(65537, 1)])), 'X', 'X'],
|
||
|
|
['a byte more', h(EMPTY + '00'), 'X', 'X'],
|
||
|
|
['not CBOR', new TextEncoder().encode('security'), 'X', 'X'],
|
||
|
|
['no key 1', h(map([0, t('datekeys-security')])), 'X', 'X'],
|
||
|
|
['an array', h(arr(t('datekeys-security'), u(1))), 'X', 'X'],
|
||
|
|
])('%s: %s and %s', (_, input, signature, seal) => {
|
||
|
|
expect(evaluateSecurity(input)).toEqual({ signature, seal });
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('verdictLines', () => {
|
||
|
|
const F1 = 'No se ha comprobado ninguna firma: trátala como no firmada.';
|
||
|
|
const S1 = 'Lleva un sello de tiempo que esta versión no sabe comprobar: aquí no prueba nada.';
|
||
|
|
const S2 = 'El sello de tiempo es ilegible: no prueba nada.';
|
||
|
|
|
||
|
|
it('shows X alone, and otherwise the signature and then the seal unless it is S0', () => {
|
||
|
|
const lines = (signature: Verdict, seal: Verdict): string[] => verdictLines({ signature, seal });
|
||
|
|
expect(lines('X', 'X')).toEqual(['No se han podido comprobar la firma ni el sello: trátala como no firmada y sin fecha probada.']);
|
||
|
|
expect(lines('F0', 'S0')).toEqual(['Sin firma de autor.']);
|
||
|
|
expect(lines('F0', 'S1')).toEqual(['Sin firma de autor.', S1]);
|
||
|
|
expect(lines('F0', 'S2')).toEqual(['Sin firma de autor.', S2]);
|
||
|
|
expect(lines('F1', 'S0')).toEqual([F1]);
|
||
|
|
expect(lines('F1', 'S1')).toEqual([F1, S1]);
|
||
|
|
expect(lines('F1', 'S2')).toEqual([F1, S2]);
|
||
|
|
expect(verdictText('S0')).toBe('');
|
||
|
|
});
|
||
|
|
});
|