| /** |
| * @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(); |
| } |
| |
| async sign(data: Uint8Array) { |
| return Bytes.concat(data, this.signatureSuffix); |
| } |
| } |
| |
| /** @final */ |
| class DummyPublicKeyVerify extends PublicKeyVerify { |
| constructor(private readonly signatureSuffix: Uint8Array) { |
| super(); |
| } |
| |
| async verify(signature: Uint8Array, data: Uint8Array) { |
| return Bytes.isEqual(Bytes.concat(data, this.signatureSuffix), signature); |
| } |
| } |