Skip to content

Commit

Permalink
fix: things
Browse files Browse the repository at this point in the history
  • Loading branch information
auer-martin committed Sep 29, 2024
1 parent 443aca6 commit 2a9ce37
Show file tree
Hide file tree
Showing 5 changed files with 171 additions and 22 deletions.
17 changes: 17 additions & 0 deletions packages/core/src/utils/u-misc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,20 @@ export const uriEncodeObject = (obj: Record<string, unknown>) => {
export function isObject(value: unknown): value is Record<string, unknown> {
return !!value && !Array.isArray(value) && typeof value === 'object';
}

interface AssertValueSupported<T> {
supported: T[];
actual: T;
error: Error;
required: boolean;
}

export function assertValueSupported<T>(
input: AssertValueSupported<T>
): T | undefined {
const { required, error, supported, actual } = input;
const intersection = supported.find(value => value === actual);

if (required && !intersection) throw error;
return intersection;
}
5 changes: 5 additions & 0 deletions packages/jarm/src/e-jarm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ import { AusweisError } from '@protokoll/core';
export class JarmError extends AusweisError {}

export class JarmReceivedErrorResponse extends JarmError {}
export class JarmResponseMetadataValidationError extends JarmError {
constructor(opts: { message: string; cause?: unknown }) {
super({ code: 'BAD_REQUEST', ...opts });
}
}
export class JarmAuthResponseValidationError extends JarmError {
constructor(opts: { message: string; cause?: unknown }) {
super({ code: 'BAD_REQUEST', ...opts });
Expand Down
1 change: 1 addition & 0 deletions packages/jarm/src/metadata/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './jarm-validate-metadata.js';
export * from './v-jarm-client-metadata.js';
export * from './v-jarm-server-metadata.js';
117 changes: 117 additions & 0 deletions packages/jarm/src/metadata/jarm-validate-metadata.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import { assertValueSupported } from '@protokoll/core';
import * as v from 'valibot';

import { JarmResponseMetadataValidationError as JarmAMetadataValidationError } from '../e-jarm.js';
import {
vJarmClientMetadata,
vJarmClientMetadataEncrypt,
vJarmClientMetadataSign,
vJarmClientMetadataSignEncrypt,
} from '../metadata/v-jarm-client-metadata.js';
import { vJarmServerMetadata } from '../metadata/v-jarm-server-metadata.js';

export const vJarmAuthResponseValidateMetadataInput = v.object({
client_metadata: vJarmClientMetadata,
server_metadata: v.partial(vJarmServerMetadata),
});
export type JarmMetadataValidate = v.InferInput<
typeof vJarmAuthResponseValidateMetadataInput
>;

export const vJarmMetadataValidateOut = v.variant('type', [
v.object({
type: v.literal('signed'),
client_metadata: vJarmClientMetadataSign,
}),
v.object({
type: v.literal('encrypted'),
client_metadata: vJarmClientMetadataEncrypt,
}),
v.object({
type: v.literal('signed encrypted'),
client_metadata: vJarmClientMetadataSignEncrypt,
}),
]);

export const jarmMetadataValidate = (
vJarmMetadataValidate: JarmMetadataValidate
): v.InferOutput<typeof vJarmMetadataValidateOut> => {
const { client_metadata, server_metadata } = vJarmMetadataValidate;

assertValueSupported({
supported: server_metadata.authorization_signing_alg_values_supported ?? [],
actual: client_metadata.authorization_signed_response_alg,
required: !!client_metadata.authorization_signed_response_alg,
error: new JarmAMetadataValidationError({
message: 'Invalid authorization_signed_response_alg',
}),
});

assertValueSupported({
supported:
server_metadata.authorization_encryption_alg_values_supported ?? [],
actual: client_metadata.authorization_encrypted_response_alg,
required: !!client_metadata.authorization_encrypted_response_alg,
error: new JarmAMetadataValidationError({
message: 'Invalid authorization_encrypted_response_alg',
}),
});

assertValueSupported({
supported:
server_metadata.authorization_encryption_enc_values_supported ?? [],
actual: client_metadata.authorization_encrypted_response_enc,
required: !!client_metadata.authorization_encrypted_response_enc,
error: new JarmAMetadataValidationError({
message: 'Invalid authorization_encrypted_response_enc',
}),
});

if (
client_metadata.authorization_signed_response_alg &&
client_metadata.authorization_encrypted_response_alg &&
client_metadata.authorization_encrypted_response_enc
) {
return {
type: 'signed encrypted',
client_metadata: {
authorization_signed_response_alg:
client_metadata.authorization_signed_response_alg,
authorization_encrypted_response_alg:
client_metadata.authorization_encrypted_response_alg,
authorization_encrypted_response_enc:
client_metadata.authorization_encrypted_response_enc,
},
};
} else if (
client_metadata.authorization_signed_response_alg &&
!client_metadata.authorization_encrypted_response_alg &&
!client_metadata.authorization_encrypted_response_enc
) {
return {
type: 'signed',
client_metadata: {
authorization_signed_response_alg:
client_metadata.authorization_signed_response_alg,
},
};
} else if (
!client_metadata.authorization_signed_response_alg &&
client_metadata.authorization_encrypted_response_alg &&
client_metadata.authorization_encrypted_response_enc
) {
return {
type: 'encrypted',
client_metadata: {
authorization_encrypted_response_alg:
client_metadata.authorization_encrypted_response_alg,
authorization_encrypted_response_enc:
client_metadata.authorization_encrypted_response_enc,
},
};
} else {
throw new JarmAMetadataValidationError({
message: `Invalid jarm client_metadata combination`,
});
}
};
53 changes: 31 additions & 22 deletions packages/jarm/src/metadata/v-jarm-client-metadata.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import * as v from 'valibot';

const vJarmClientMetadataBase = v.object({
export const vJarmClientMetadataSign = v.object({
authorization_signed_response_alg: v.pipe(
v.optional(v.string(), 'RS256'),
v.optional(v.string()), // @default 'RS256' This makes no sense with openid4vp if just encrypted can be specified
v.description(
'JWA. If this is specified, the response will be signed using JWS and the configured algorithm. The algorithm none is not allowed.'
)
Expand All @@ -12,30 +12,39 @@ const vJarmClientMetadataBase = v.object({
authorization_encrypted_response_enc: v.optional(v.never()),
});

export const vJarmClientMetadataEncrypt = v.object({
authorization_signed_response_alg: v.optional(v.never()),
authorization_encrypted_response_alg: v.pipe(
v.string(),
v.description(
'JWE alg algorithm JWA. If both signing and encryption are requested, the response will be signed then encrypted with the provided algorithm.'
)
),

authorization_encrypted_response_enc: v.pipe(
v.optional(v.string(), 'A128CBC-HS256'),
v.description(
'JWE enc algorithm JWA. If both signing and encryption are requested, the response will be signed then encrypted with the provided algorithm.'
)
),
});

export const vJarmClientMetadataSignEncrypt = v.object({
...v.pick(vJarmClientMetadataSign, ['authorization_signed_response_alg'])
.entries,
...v.pick(vJarmClientMetadataEncrypt, [
'authorization_encrypted_response_alg',
'authorization_encrypted_response_enc',
]).entries,
});

/**
* Clients may register their public encryption keys using the jwks_uri or jwks metadata parameters.
*/
export const vJarmClientMetadata = v.union([
v.object({
...vJarmClientMetadataBase.entries,
}),
v.object({
...vJarmClientMetadataBase.entries,

authorization_encrypted_response_alg: v.pipe(
v.string(),
v.description(
'JWE alg algorithm JWA. If both signing and encryption are requested, the response will be signed then encrypted with the provided algorithm.'
)
),

authorization_encrypted_response_enc: v.pipe(
v.optional(v.string(), 'A128CBC-HS256'),
v.description(
'JWE enc algorithm JWA. If both signing and encryption are requested, the response will be signed then encrypted with the provided algorithm.'
)
),
}),
vJarmClientMetadataSign,
vJarmClientMetadataEncrypt,
vJarmClientMetadataSignEncrypt,
]);

export type JarmClientMetadata = v.InferInput<typeof vJarmClientMetadata>;

0 comments on commit 2a9ce37

Please sign in to comment.