Skip to content

Commit

Permalink
Add Publicly Verifiable Token with Metadata
Browse files Browse the repository at this point in the history
Draft 2 https://datatracker.ietf.org/doc/html/draft-hendrickson-privacypass-public-metadata-03#name-client-to-issuer-request-2

Using Partially Blind RSA implementation.
Given the protocol is close to the normal Public issuance, the class is
abstracted, and two children of this abstract class are exported: one
with Metadata and the other without.

There are no test vectors yet for the protocol, which is to be added in
a following commit.

Add Origin class for publicly verifiable token

Add example for metadata

Add test vectors for Privacy Pass with metadata

Not yet part of the draft, but allow to confirm issues with the
implementation.

Add Partially Blind RSA as supported token in README
  • Loading branch information
thibmeu committed May 13, 2024
1 parent 5128cca commit 50c08c1
Show file tree
Hide file tree
Showing 15 changed files with 914 additions and 77 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@

# privacypass-ts: A TypeScript Library for the Privacy Pass Issuance Protocol

**Specification:** Compliant with IETF [draft-ietf-privacypass-protocol](https://datatracker.ietf.org/doc/draft-ietf-privacypass-protocol/) and tests vectors match with draft [v11](https://datatracker.ietf.org/doc/draft-ietf-privacypass-protocol/11/).
**Specification:** Compliant with IETF [draft-ietf-privacypass-protocol](https://datatracker.ietf.org/doc/draft-ietf-privacypass-protocol/), [draft-hendrickson-privacypass-public-metadata-03](https://datatracker.ietf.org/doc/draft-hendrickson-privacypass-public-metadata/) and tests vectors match with draft [v11](https://datatracker.ietf.org/doc/draft-ietf-privacypass-protocol/11/).

**Support:**
- Public-Verifiable tokens (Blind-RSA)
- Public-Verifiable tokens with Metadata (Partially-Blind-RSA)
- Private-Verifiable tokens (VOPRF)


Expand Down
2 changes: 2 additions & 0 deletions examples/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import { webcrypto } from 'node:crypto';

import { publicVerifiableTokens } from './pub_verif.example.js';
import { publicVerifiableWithMetadataTokens } from './pub_verif_metadata.example.js';
import { privateVerifiableTokens } from './priv_verif.example.js';

if (typeof crypto === 'undefined') {
Expand All @@ -13,6 +14,7 @@ if (typeof crypto === 'undefined') {
async function examples() {
await privateVerifiableTokens();
await publicVerifiableTokens();
await publicVerifiableWithMetadataTokens();
}

examples().catch((e: Error) => {
Expand Down
30 changes: 18 additions & 12 deletions examples/pub_verif.example.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,13 @@
// Copyright (c) 2023 Cloudflare, Inc.
// Licensed under the Apache-2.0 license found in the LICENSE file or at https://opensource.org/licenses/Apache-2.0

import { TOKEN_TYPES, TokenChallenge, publicVerif } from '../src/index.js';
import { TOKEN_TYPES, publicVerif } from '../src/index.js';
type BlindRSAMode = publicVerif.BlindRSAMode;
const { BlindRSAMode, Client, Issuer, getPublicKeyBytes, keyGen, verifyToken } = publicVerif;

async function rsaVariant(mode: BlindRSAMode): Promise<void> {
// Protocol Setup
//
// [ Everybody ] agree to use Public Verifiable Tokens.
const tokenType = TOKEN_TYPES.BLIND_RSA.value;
const { BlindRSAMode, Client, Issuer, Origin, getPublicKeyBytes } = publicVerif;

async function setup(mode: BlindRSAMode) {
// [ Issuer ] creates a key pair.
const keys = await keyGen(mode, {
const keys = await Issuer.generateKey(mode, {
modulusLength: 2048,
publicExponent: Uint8Array.from([1, 0, 1]),
});
Expand All @@ -22,6 +17,18 @@ async function rsaVariant(mode: BlindRSAMode): Promise<void> {
// [ Client ] creates a state.
const client = new Client(mode);

// [ Origin ] creates a state.
const origin = new Origin(mode, ['origin.example.com', 'origin2.example.com']);

return { issuer, client, origin, pkIssuer };
}

async function rsaVariant(mode: BlindRSAMode): Promise<void> {
// Protocol Setup
//
// [ Everybody ] agree to use Public Verifiable Tokens.
const { issuer, client, origin, pkIssuer } = await setup(mode);

// Online Protocol
//
// +--------+ +--------+ +----------+ +--------+
Expand All @@ -30,8 +37,7 @@ async function rsaVariant(mode: BlindRSAMode): Promise<void> {
// | | | |
// |<----- Request ------+ | |
const redemptionContext = crypto.getRandomValues(new Uint8Array(32));
const originInfo = ['origin.example.com', 'origin2.example.com'];
const tokChl = new TokenChallenge(tokenType, issuer.name, redemptionContext, originInfo);
const tokChl = origin.createTokenChallenge(issuer.name, redemptionContext);
// +-- TokenChallenge -->| | |
// | |<== Attestation ==>| |
// | | | |
Expand All @@ -44,7 +50,7 @@ async function rsaVariant(mode: BlindRSAMode): Promise<void> {
const token = await client.finalize(tokRes);
// |<-- Request+Token ---+ | |
// | | | |
const isValid = await /*Origin*/ verifyToken(mode, token, issuer.publicKey);
const isValid = await origin.verify(token, issuer.publicKey);

console.log('Public-Verifiable tokens');
console.log(` Suite: ${TOKEN_TYPES.BLIND_RSA.suite[mode as BlindRSAMode]()}`);
Expand Down
86 changes: 86 additions & 0 deletions examples/pub_verif_metadata.example.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Copyright (c) 2024 Cloudflare, Inc.
// Licensed under the Apache-2.0 license found in the LICENSE file or at https://opensource.org/licenses/Apache-2.0

import { generatePrimeSync } from 'node:crypto';

import { Extension, Extensions, TOKEN_TYPES, publicVerif } from '../src/index.js';
type PartiallyBlindRSAMode = publicVerif.PartiallyBlindRSAMode;
const {
PartiallyBlindRSAMode,
ClientWithMetadata,
IssuerWithMetadata,
OriginWithMetadata,
getPublicKeyBytes,
} = publicVerif;

async function setup(mode: PartiallyBlindRSAMode, extensions: Extensions) {
// [ Issuer ] creates a key pair.
const keys = await IssuerWithMetadata.generateKey(
mode,
{
modulusLength: 2048,
publicExponent: Uint8Array.from([1, 0, 1]),
},
(length: number) => generatePrimeSync(length, { safe: true, bigint: true }),
);
const issuer = new IssuerWithMetadata(mode, 'issuer.com', keys.privateKey, keys.publicKey);
const pkIssuer = await getPublicKeyBytes(issuer.publicKey);

// [ Client ] creates a state.
const client = new ClientWithMetadata(mode, extensions);

// [ Origin ] creates a state.
const origin = new OriginWithMetadata(mode, extensions, [
'origin.example.com',
'origin2.example.com',
]);

return { issuer, client, origin, pkIssuer };
}

const TEST_EXTENSION_TYPE = 0xacdc;
function createTestExtension(info = new Uint8Array([TEST_EXTENSION_TYPE])) {
return new Extension(TEST_EXTENSION_TYPE, info);
}

async function rsaVariant(mode: PartiallyBlindRSAMode): Promise<void> {
// Protocol Setup
//
// [ Everybody ] agree to use Public Verifiable Tokens with Metadata.
const extensions = new Extensions([createTestExtension(new Uint8Array([1, 2, 3]))]);
const { issuer, client, origin, pkIssuer } = await setup(mode, extensions);

// Online Protocol
//
// +--------+ +--------+ +----------+ +--------+
// | Origin | | Client | | Attester | | Issuer |
// +---+----+ +---+----+ +----+-----+ +---+----+
// | | | |
// |<----- Request ------+ | |
const redemptionContext = crypto.getRandomValues(new Uint8Array(32));
const tokChl = origin.createTokenChallenge(issuer.name, redemptionContext);
// +-- TokenChallenge -->| | |
// | |<== Attestation ==>| |
// | | | |
const tokReq = await client.createTokenRequest(tokChl, pkIssuer);
// | +----- ExtendedTokenRequest --->|
// | | | |
const tokRes = await issuer.issue(tokReq);
// | |<-------- TokenResponse -------+
// | | | |
const token = await client.finalize(tokRes);
// |<-- Request+Token ---+ | |
// | | | |
const isValid = await origin.verify(token, issuer.publicKey);

console.log('Public-Verifiable With Metadata tokens');
console.log(
` Suite: ${TOKEN_TYPES.PARTIALLY_BLIND_RSA.suite[mode as PartiallyBlindRSAMode]()}`,
);
console.log(` Valid token: ${isValid}`);
}

export async function publicVerifiableWithMetadataTokens() {
await rsaVariant(PartiallyBlindRSAMode.PSS);
await rsaVariant(PartiallyBlindRSAMode.PSSZero);
}
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
"clean": "rimraf lib coverage dist"
},
"dependencies": {
"@cloudflare/blindrsa-ts": "0.3.2",
"@cloudflare/blindrsa-ts": "0.4.2",
"@cloudflare/voprf-ts": "0.21.2",
"asn1-parser": "1.1.8",
"asn1js": "3.0.5",
Expand Down
Loading

0 comments on commit 50c08c1

Please sign in to comment.