blob: 15e69a42dc068c96c1d706ff1a0e3b6ee003fb81 [file] [log] [blame]
/**
* @license
* Copyright 2020 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import * as PrimitiveSet from '../internal/primitive_set';
import {PbKeysetKey, PbKeyStatusType, PbOutputPrefixType} from '../internal/proto';
import * as Bytes from '../subtle/bytes';
import * as Random from '../subtle/random';
import {PublicKeySign} from './internal/public_key_sign';
import {PublicKeyVerify} from './internal/public_key_verify';
import {PublicKeySignWrapper} from './public_key_sign_wrapper';
import {PublicKeyVerifyWrapper} from './public_key_verify_wrapper';
describe('public key verify wrapper test', function() {
it('verify, with empty signature', async function() {
const primitiveSets = createDummyPrimitiveSets();
const primitiveSet = primitiveSets['publicPrimitiveSet'];
const publicKeyVerify = new PublicKeyVerifyWrapper().wrap(primitiveSet);
expect(
await publicKeyVerify.verify(new Uint8Array(0), Random.randBytes(10)))
.toBe(false);
});
it('verify, should work', async function() {
const primitiveSets = createDummyPrimitiveSets();
const data = Random.randBytes(10);
// As keys are just dummy keys which do not contain key data, the same key
// is used for both sign and verify.
const key = createDummyKeysetKey(
/** keyId = */ 0xFFFFFFFF, PbOutputPrefixType.TINK,
/** enabled = */ true);
const signatureSuffix = Random.randBytes(10);
// Get the signature
const privatePrimitiveSet = primitiveSets['privatePrimitiveSet'];
const signPrimitive = new DummyPublicKeySign(signatureSuffix);
const entry = privatePrimitiveSet.addPrimitive(signPrimitive, key);
// Has to be set to primary as then it is used in signing.
privatePrimitiveSet.setPrimary(entry);
const publicKeySign = new PublicKeySignWrapper().wrap(privatePrimitiveSet);
const signature = await publicKeySign.sign(data);
// Create a primitive set containing the primitives which can be used for
// verification. Add also few more primitives with the same key as the
// primitive set should verify the signature whenever there is at least
// one primitive which does not fail to verify the signature.
const publicPrimitiveSet = primitiveSets['publicPrimitiveSet'];
const verifyPrimitive = new DummyPublicKeyVerify(signatureSuffix);
publicPrimitiveSet.addPrimitive(
new DummyPublicKeyVerify(Random.randBytes(5)), key);
publicPrimitiveSet.addPrimitive(verifyPrimitive, key);
publicPrimitiveSet.addPrimitive(
new DummyPublicKeyVerify(Random.randBytes(5)), key);
// Verify the signature.
const publicKeyVerify =
new PublicKeyVerifyWrapper().wrap(publicPrimitiveSet);
const isValid = await publicKeyVerify.verify(signature, data);
expect(isValid).toBe(true);
});
it('verify, raw primitive', async function() {
const primitiveSets = createDummyPrimitiveSets();
const data = Random.randBytes(10);
const key = createDummyKeysetKey(
/** keyId = */ 0xFFFFFFFF, PbOutputPrefixType.RAW,
/** enabled = */ true);
const signatureSuffix = Random.randBytes(10);
// Get the signature.
const signPrimitive = new DummyPublicKeySign(signatureSuffix);
const signature = await signPrimitive.sign(data);
// Verify the signature.
const primitiveSet = primitiveSets['publicPrimitiveSet'];
const verifyPrimitive = new DummyPublicKeyVerify(signatureSuffix);
primitiveSet.addPrimitive(verifyPrimitive, key);
const publicKeyVerify = new PublicKeyVerifyWrapper().wrap(primitiveSet);
const isValid = await publicKeyVerify.verify(signature, data);
expect(isValid).toBe(true);
});
it('verify, with disabled primitive', async function() {
const primitiveSets = createDummyPrimitiveSets();
const data = Random.randBytes(10);
const key = createDummyKeysetKey(
/** keyId = */ 0xFFFFFFFF, PbOutputPrefixType.RAW,
/** enabled = */ false);
const signatureSuffix = new Uint8Array([0, 0, 0, 0xFF]);
const signPrimitive = new DummyPublicKeySign(signatureSuffix);
const signature = await signPrimitive.sign(data);
const primitiveSet = primitiveSets['publicPrimitiveSet'];
const verifyPrimitive = new DummyPublicKeyVerify(signatureSuffix);
primitiveSet.addPrimitive(verifyPrimitive, key);
const publicKeyVerify = new PublicKeyVerifyWrapper().wrap(primitiveSet);
const isValid = await publicKeyVerify.verify(signature, data);
expect(isValid).toBe(false);
});
});
/** Function for creating keys for testing purposes. */
function createDummyKeysetKey(
keyId: number, outputPrefix: PbOutputPrefixType,
enabled: boolean): PbKeysetKey {
const key = new PbKeysetKey();
if (enabled) {
key.setStatus(PbKeyStatusType.ENABLED);
} else {
key.setStatus(PbKeyStatusType.DISABLED);
}
key.setOutputPrefixType(outputPrefix);
key.setKeyId(keyId);
return key;
}
/**
* Creates a primitive sets for PublicKeySign and PublicKeyVerify with
* 'numberOfPrimitives' primitives. The keys corresponding to the primitives
* have ids from the set [1, ..., numberOfPrimitives] and the primitive
* corresponding to key with id 'numberOfPrimitives' is set to be primary
* whenever opt_withPrimary is set to true (where true is the default value).
*/
function createDummyPrimitiveSets(opt_withPrimary: boolean = true): {
publicPrimitiveSet: PrimitiveSet.PrimitiveSet<DummyPublicKeyVerify>,
privatePrimitiveSet: PrimitiveSet.PrimitiveSet<DummyPublicKeySign>,
} {
const numberOfPrimitives = 5;
const publicPrimitiveSet =
new PrimitiveSet.PrimitiveSet<DummyPublicKeyVerify>(DummyPublicKeyVerify);
const privatePrimitiveSet =
new PrimitiveSet.PrimitiveSet<DummyPublicKeySign>(DummyPublicKeySign);
for (let i = 1; i < numberOfPrimitives; i++) {
let outputPrefix: PbOutputPrefixType;
switch (i % 3) {
case 0:
outputPrefix = PbOutputPrefixType.TINK;
break;
case 1:
outputPrefix = PbOutputPrefixType.LEGACY;
break;
default:
outputPrefix = PbOutputPrefixType.RAW;
}
const key =
createDummyKeysetKey(i, outputPrefix, /* enabled = */ i % 4 < 2);
const signatureSuffix = new Uint8Array([0, 0, i]);
const publicKeySign = new DummyPublicKeySign(signatureSuffix);
privatePrimitiveSet.addPrimitive(publicKeySign, key);
const publicKeyVerify = new DummyPublicKeyVerify(signatureSuffix);
publicPrimitiveSet.addPrimitive(publicKeyVerify, key);
}
const key = createDummyKeysetKey(
numberOfPrimitives, PbOutputPrefixType.TINK, /* enabled = */ true);
const signatureSuffix = new Uint8Array([0, 0, numberOfPrimitives]);
const publicKeySign = new DummyPublicKeySign(signatureSuffix);
const signEntry = privatePrimitiveSet.addPrimitive(publicKeySign, key);
const publicKeyVerify = new DummyPublicKeyVerify(signatureSuffix);
const verifyEntry = publicPrimitiveSet.addPrimitive(publicKeyVerify, key);
if (opt_withPrimary) {
publicPrimitiveSet.setPrimary(verifyEntry);
privatePrimitiveSet.setPrimary(signEntry);
}
return {
'publicPrimitiveSet': publicPrimitiveSet,
'privatePrimitiveSet': privatePrimitiveSet
};
}
/** @final */
class DummyPublicKeySign extends PublicKeySign {
constructor(private readonly signatureSuffix: Uint8Array) {
super();
}
/** @override */
async sign(data: Uint8Array) {
return Bytes.concat(data, this.signatureSuffix);
}
}
/** @final */
class DummyPublicKeyVerify extends PublicKeyVerify {
constructor(private readonly signatureSuffix: Uint8Array) {
super();
}
/** @override */
async verify(signature: Uint8Array, data: Uint8Array) {
return Bytes.isEqual(Bytes.concat(data, this.signatureSuffix), signature);
}
}