Skip to content
This repository was archived by the owner on Oct 2, 2024. It is now read-only.

Commit 9184eeb

Browse files
Merge pull request #11 from Sphereon-Opensource/MYC-146
MYC-146 added SuppliedSignature functionality
2 parents fb88b82 + 51b4866 commit 9184eeb

14 files changed

+1603
-45
lines changed

generator/schemaGenerator.ts

Lines changed: 92 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,102 @@
1-
const fs = require("fs");
2-
const tsj = require("ts-json-schema-generator");
1+
import fs from 'fs';
2+
import {
3+
createFormatter,
4+
createParser,
5+
createProgram, MutableTypeFormatter,
6+
SchemaGenerator
7+
} from 'ts-json-schema-generator';
8+
import {
9+
BaseType,
10+
Definition,
11+
FunctionType,
12+
SubTypeFormatter
13+
} from 'ts-json-schema-generator';
14+
15+
class CustomTypeFormatter implements SubTypeFormatter {
16+
public supportsType(type: FunctionType): boolean {
17+
return type instanceof FunctionType;
18+
}
19+
20+
public getDefinition(): Definition {
21+
// Return a custom schema for the function property.
22+
return {
23+
type: "object",
24+
properties: {
25+
isFunction: {
26+
type: "boolean",
27+
const: true,
28+
},
29+
},
30+
};
31+
}
32+
33+
public getChildren(): BaseType[] {
34+
return [];
35+
}
36+
}
337

438
function writeSchema(config) {
5-
const schema = tsj.createGenerator(config).createSchema(config.type);
6-
const schemaString = JSON.stringify(schema, null, 2);
39+
const formatter = createFormatter(config, (fmt: MutableTypeFormatter) => {
40+
fmt.addTypeFormatter(new CustomTypeFormatter());
41+
});
42+
43+
const program = createProgram(config);
44+
const schema = new SchemaGenerator(program, createParser(program, config), formatter, config).createSchema(config.type);
45+
46+
let schemaString = JSON.stringify(schema, null, 2);
47+
schemaString = correctSchema(schemaString)
48+
749
fs.writeFile(config.outputPath, `export const ${config.outputConstName} = ${schemaString};`, (err) => {
850
if (err) throw err;
951
});
1052
}
1153

54+
function correctSchema(schemaString: string) {
55+
return schemaString.replace(
56+
"\"SuppliedSignature\": {\n" +
57+
" \"type\": \"object\",\n" +
58+
" \"properties\": {\n" +
59+
" \"signature\": {\n" +
60+
" \"type\": \"object\",\n" +
61+
" \"properties\": {\n" +
62+
" \"isFunction\": {\n" +
63+
" \"type\": \"boolean\",\n" +
64+
" \"const\": true\n" +
65+
" }\n" +
66+
" }\n" +
67+
" },\n" +
68+
" \"did\": {\n" +
69+
" \"type\": \"string\"\n" +
70+
" },\n" +
71+
" \"kid\": {\n" +
72+
" \"type\": \"string\"\n" +
73+
" }\n" +
74+
" },\n" +
75+
" \"required\": [\n" +
76+
" \"signature\",\n" +
77+
" \"did\",\n" +
78+
" \"kid\"\n" +
79+
" ],\n" +
80+
" \"additionalProperties\": false\n" +
81+
" },",
82+
"\"SuppliedSignature\": {\n" +
83+
" \"type\": \"object\",\n" +
84+
" \"properties\": {\n" +
85+
" \"did\": {\n" +
86+
" \"type\": \"string\"\n" +
87+
" },\n" +
88+
" \"kid\": {\n" +
89+
" \"type\": \"string\"\n" +
90+
" }\n" +
91+
" },\n" +
92+
" \"required\": [\n" +
93+
" \"did\",\n" +
94+
" \"kid\"\n" +
95+
" ],\n" +
96+
" \"additionalProperties\": true\n" +
97+
" },")
98+
}
99+
12100
const requestOptsConf = {
13101
path: "../src/main/types/SIOP.types.ts",
14102
tsconfig: "tsconfig.json",

jest.config.js renamed to jest.config.cjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ module.exports = {
1818
"!src/schemas/**",
1919
"!src/**/*.d.ts",
2020
"!**/node_modules/**",
21-
"!jest.config.js",
21+
"!jest.config.cjs",
2222
"!generator/**",
2323
"!index.ts",
2424

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
{
22
"name": "@sphereon/did-auth-siop",
3-
"version": "0.2.6-unstable.0",
3+
"version": "0.2.12-bram",
44
"main": "dist/main/index.js",
55
"types": "dist/main/index.d.ts",
66
"license": "Apache-2.0",
7+
"type": "module",
78
"repository": {
89
"url": "https://github.com/Sphereon-Opensource/did-auth-siop.git"
910
},
@@ -12,7 +13,7 @@
1213
"scripts": {
1314
"build": "run-p build:*",
1415
"build:main": "tsc -p tsconfig.build.json",
15-
"build:schemaGenerator": "node generator/schemaGenerator.ts",
16+
"build:schemaGenerator": "node --loader ts-node/esm generator/schemaGenerator.ts",
1617
"fix": "run-s fix:*",
1718
"fix:prettier": "prettier \"{src,test}/**/*.ts\" --write",
1819
"fix:lint": "eslint . --ext .ts --fix",

src/main/AuthenticationResponse.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,8 @@ async function createThumbprintAndJWK(resOpts: SIOP.AuthenticationResponseOpts):
173173
}
174174
thumbprint = getThumbprintFromJwk(didDocument.verificationMethod[0].publicKeyJwk as JWK, resOpts.did);
175175
subJwk = didDocument.verificationMethod[0].publicKeyJwk as JWK;*/
176+
} else if (SIOP.isSuppliedSignature(resOpts.signatureType)) {
177+
return { thumbprint, subJwk };
176178
} else {
177179
throw new Error(SIOPErrors.SIGNATURE_OBJECT_TYPE_NOT_SET);
178180
}
@@ -216,7 +218,6 @@ async function createSIOPResponsePayload(
216218
throw new Error(SIOPErrors.VERIFY_BAD_PARAMS);
217219
}
218220
const isDidSupported = verifiedJwt.payload.registration?.subject_identifiers_supported?.includes(SubjectIdentifierType.DID);
219-
220221
const { thumbprint, subJwk } = await createThumbprintAndJWK(resOpts);
221222
const state = resOpts.state || State.getState(verifiedJwt.payload.state);
222223
const nonce = resOpts.nonce || State.getNonce(state, resOpts.nonce);
@@ -247,7 +248,9 @@ async function createSIOPResponsePayload(
247248
function assertValidResponseOpts(opts: SIOP.AuthenticationResponseOpts) {
248249
if (!opts /*|| !opts.redirectUri*/ || !opts.signatureType /*|| !opts.nonce*/ || !opts.did) {
249250
throw new Error(SIOPErrors.BAD_PARAMS);
250-
} else if (!(SIOP.isInternalSignature(opts.signatureType) || SIOP.isExternalSignature(opts.signatureType))) {
251+
} else if (
252+
!(SIOP.isInternalSignature(opts.signatureType) || SIOP.isExternalSignature(opts.signatureType) || SIOP.isSuppliedSignature(opts.signatureType))
253+
) {
251254
throw new Error(SIOPErrors.SIGNATURE_OBJECT_TYPE_NOT_SET);
252255
}
253256
}

src/main/OPBuilder.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,23 @@
11
import { getUniResolver } from '@sphereon/did-uni-client';
2+
import { EcdsaSignature } from 'did-jwt/lib/util';
23
import { Resolvable, Resolver } from 'did-resolver';
34

45
import { OP } from './OP';
56
import { DIDJwt } from './functions';
6-
import { CredentialFormat, ExternalSignature, InternalSignature, PassBy, ResponseMode, ResponseRegistrationOpts } from './types/SIOP.types';
7+
import {
8+
CredentialFormat,
9+
ExternalSignature,
10+
InternalSignature,
11+
PassBy,
12+
ResponseMode,
13+
ResponseRegistrationOpts,
14+
SuppliedSignature,
15+
} from './types/SIOP.types';
716

817
export default class OPBuilder {
918
didMethods: string[] = [];
1019
resolvers: Map<string, Resolvable> = new Map<string, Resolvable>();
11-
signatureType: InternalSignature | ExternalSignature;
20+
signatureType: InternalSignature | ExternalSignature | SuppliedSignature;
1221
credentialFormats: CredentialFormat[] = [];
1322
responseRegistration: ResponseRegistrationOpts;
1423
responseMode?: ResponseMode;
@@ -66,8 +75,8 @@ export default class OPBuilder {
6675
idTokenSigningAlgValuesSupported?: KeyAlgo[] | KeyAlgo;
6776
requestObjectSigningAlgValuesSupported?: SigningAlgo[] | SigningAlgo;
6877
*/
69-
// Only internal supported for now
70-
signature(signatureType: InternalSignature): OPBuilder {
78+
// Only internal | supplied supported for now
79+
signature(signatureType: InternalSignature | SuppliedSignature): OPBuilder {
7180
this.signatureType = signatureType;
7281
return this;
7382
}
@@ -77,6 +86,11 @@ export default class OPBuilder {
7786
return this;
7887
}
7988

89+
suppliedSignature(signature: (data: string | Uint8Array) => Promise<EcdsaSignature | string>, did: string, kid: string): OPBuilder {
90+
this.signature({ signature, did, kid });
91+
return this;
92+
}
93+
8094
build(): OP {
8195
// this.responseRegistration.didMethodsSupported = this.didMethods;
8296
// this.responseRegistration.subjectIdentifiersSupported = this.subjectIdentifierTypes;

src/main/RPBuilder.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { getUniResolver } from '@sphereon/did-uni-client';
2+
import { EcdsaSignature } from 'did-jwt/lib/util';
23
import { Resolvable, Resolver } from 'did-resolver';
34

45
import { RP } from './RP';
@@ -16,6 +17,7 @@ import {
1617
ResponseContext,
1718
ResponseMode,
1819
SubjectIdentifierType,
20+
SuppliedSignature,
1921
} from './types/SIOP.types';
2022

2123
export default class RPBuilder {
@@ -26,7 +28,7 @@ export default class RPBuilder {
2628
requestRegistration: Partial<RequestRegistrationOpts> = {};
2729
redirectUri: string;
2830
requestObjectBy: ObjectBy;
29-
signatureType: InternalSignature | ExternalSignature | NoSignature;
31+
signatureType: InternalSignature | ExternalSignature | SuppliedSignature | NoSignature;
3032
responseMode?: ResponseMode;
3133
responseContext?: ResponseContext.RP;
3234
claims?: ClaimOpts;
@@ -80,8 +82,8 @@ export default class RPBuilder {
8082
return this;
8183
}
8284

83-
// Only internal supported for now
84-
signature(signatureType: InternalSignature): RPBuilder {
85+
// Only internal | supplied supported for now
86+
signature(signatureType: InternalSignature | SuppliedSignature): RPBuilder {
8587
this.signatureType = signatureType;
8688
return this;
8789
}
@@ -91,6 +93,11 @@ export default class RPBuilder {
9193
return this;
9294
}
9395

96+
suppliedSignature(signature: (data: string | Uint8Array) => Promise<EcdsaSignature | string>, did: string, kid: string): RPBuilder {
97+
this.signature({ signature, did, kid });
98+
return this;
99+
}
100+
94101
addPresentationDefinitionClaim(definitionOpt: PresentationDefinitionWithLocation): RPBuilder {
95102
if (!this.claims || !this.claims.presentationDefinitions) {
96103
this.claims = {

src/main/functions/DidJWT.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { EdDSASigner, ES256KSigner } from 'did-jwt';
2+
import { EcdsaSignature } from 'did-jwt/lib/util';
23
import { Resolvable } from 'did-resolver';
34

45
import { createJWT, decodeJWT, JWTDecoded, JWTHeader, JWTOptions, JWTPayload, JWTVerifyOptions, verifyJWT } from '../../did-jwt-fork/JWT';
@@ -14,6 +15,7 @@ import {
1415
isInternalSignature,
1516
isResponseOpts,
1617
isResponsePayload,
18+
isSuppliedSignature,
1719
KeyAlgo,
1820
ResponseIss,
1921
SignatureResponse,
@@ -89,6 +91,8 @@ export async function signDidJwtPayload(
8991
return signDidJwtInternal(payload, isResponse ? payload.iss : opts.signatureType.did, opts.signatureType.hexPrivateKey, opts.signatureType.kid);
9092
} else if (isExternalSignature(opts.signatureType)) {
9193
return signDidJwtExternal(payload, opts.signatureType.signatureUri, opts.signatureType.authZToken, opts.signatureType.kid);
94+
} else if (isSuppliedSignature(opts.signatureType)) {
95+
return signDidJwtSupplied(payload, isResponse ? payload.iss : opts.signatureType.did, opts.signatureType.signature, opts.signatureType.kid);
9296
} else {
9397
throw new Error(SIOPErrors.BAD_SIGNATURE_PARAMS);
9498
}
@@ -99,7 +103,7 @@ async function signDidJwtInternal(
99103
issuer: string,
100104
hexPrivateKey: string,
101105
kid?: string
102-
) {
106+
): Promise<string> {
103107
const algo = isEd25519DidKeyMethod(issuer) || isEd25519DidKeyMethod(payload.kid) || isEd25519JWK(payload.sub_jwk) ? KeyAlgo.EDDSA : KeyAlgo.ES256K;
104108
// const request = !!payload.client_id;
105109
const signer =
@@ -142,6 +146,26 @@ async function signDidJwtExternal(
142146
return ((await response.json()) as SignatureResponse).jws;
143147
}
144148

149+
async function signDidJwtSupplied(
150+
payload: AuthenticationRequestPayload | AuthenticationResponsePayload,
151+
issuer: string,
152+
signer: (data: string | Uint8Array) => Promise<EcdsaSignature | string>,
153+
kid: string
154+
): Promise<string> {
155+
const algo = isEd25519DidKeyMethod(issuer) || isEd25519DidKeyMethod(payload.kid) || isEd25519JWK(payload.sub_jwk) ? KeyAlgo.EDDSA : KeyAlgo.ES256K;
156+
const header = {
157+
alg: algo,
158+
kid,
159+
};
160+
const options = {
161+
issuer,
162+
signer,
163+
expiresIn: SIOP.expirationTime,
164+
};
165+
166+
return await createDidJWT({ ...payload }, options, header);
167+
}
168+
145169
export function getAudience(jwt: string) {
146170
const { payload } = decodeJWT(jwt);
147171
if (!payload) {

src/main/schemas/AuthenticationRequestOpts.schema.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ export const AuthenticationRequestOptsSchema = {
1919
{
2020
"$ref": "#/definitions/ExternalSignature"
2121
},
22+
{
23+
"$ref": "#/definitions/SuppliedSignature"
24+
},
2225
{
2326
"$ref": "#/definitions/NoSignature"
2427
}
@@ -114,6 +117,22 @@ export const AuthenticationRequestOptsSchema = {
114117
],
115118
"additionalProperties": false
116119
},
120+
"SuppliedSignature": {
121+
"type": "object",
122+
"properties": {
123+
"did": {
124+
"type": "string"
125+
},
126+
"kid": {
127+
"type": "string"
128+
}
129+
},
130+
"required": [
131+
"did",
132+
"kid"
133+
],
134+
"additionalProperties": true
135+
},
117136
"NoSignature": {
118137
"type": "object",
119138
"properties": {

src/main/schemas/AuthenticationResponseOpts.schema.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ export const AuthenticationResponseOptsSchema = {
1515
},
1616
{
1717
"$ref": "#/definitions/ExternalSignature"
18+
},
19+
{
20+
"$ref": "#/definitions/SuppliedSignature"
1821
}
1922
]
2023
},
@@ -94,6 +97,22 @@ export const AuthenticationResponseOptsSchema = {
9497
],
9598
"additionalProperties": false
9699
},
100+
"SuppliedSignature": {
101+
"type": "object",
102+
"properties": {
103+
"did": {
104+
"type": "string"
105+
},
106+
"kid": {
107+
"type": "string"
108+
}
109+
},
110+
"required": [
111+
"did",
112+
"kid"
113+
],
114+
"additionalProperties": true
115+
},
97116
"ResponseRegistrationOpts": {
98117
"type": "object",
99118
"properties": {

src/main/types/JWT.types.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
import { EcdsaSignature } from 'did-jwt/lib/util';
12
import type { DIDResolutionResult, VerificationMethod } from 'did-resolver';
23
// import type {JWK} from "jose/types";
34

4-
export type Signer = (data: string | Uint8Array) => Promise<string>;
5+
// Signer interface conforming to the DID-JWT module
6+
export type Signer = (data: string | Uint8Array) => Promise<EcdsaSignature | string>;
57

68
export interface JWTPayload {
79
iss?: string;

0 commit comments

Comments
 (0)