@originator-profile/securing-mechanism 0.4.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/dist/index.cjs +182 -0
- package/dist/index.d.cts +134 -0
- package/dist/index.d.mts +134 -0
- package/dist/index.mjs +172 -0
- package/package.json +41 -0
package/README.md
ADDED
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var jose = require('jose');
|
|
4
|
+
var cryptography = require('@originator-profile/cryptography');
|
|
5
|
+
var errors = require('jose/errors');
|
|
6
|
+
var Ajv = require('ajv');
|
|
7
|
+
var addFormats = require('ajv-formats');
|
|
8
|
+
|
|
9
|
+
class VcVerifyFailed extends Error {
|
|
10
|
+
constructor(message, result) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.result = result;
|
|
13
|
+
}
|
|
14
|
+
static get code() {
|
|
15
|
+
return "ERR_VC_VERIFY_FAILED";
|
|
16
|
+
}
|
|
17
|
+
code = VcVerifyFailed.code;
|
|
18
|
+
}
|
|
19
|
+
class VcDecodeFailed extends Error {
|
|
20
|
+
constructor(message, result) {
|
|
21
|
+
super(message);
|
|
22
|
+
this.result = result;
|
|
23
|
+
}
|
|
24
|
+
static get code() {
|
|
25
|
+
return "ERR_VC_DECODE_FAILED";
|
|
26
|
+
}
|
|
27
|
+
code = VcDecodeFailed.code;
|
|
28
|
+
}
|
|
29
|
+
class VcValidateFailed extends Error {
|
|
30
|
+
constructor(message, result) {
|
|
31
|
+
super(message);
|
|
32
|
+
this.result = result;
|
|
33
|
+
}
|
|
34
|
+
static get code() {
|
|
35
|
+
return "ERR_VC_VALIDATION_FAILED";
|
|
36
|
+
}
|
|
37
|
+
code = VcValidateFailed.code;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const constructFromSymbol = Symbol.for("constructDateFrom");
|
|
41
|
+
|
|
42
|
+
function constructFrom(date, value) {
|
|
43
|
+
if (typeof date === "function") return date(value);
|
|
44
|
+
if (date && typeof date === "object" && constructFromSymbol in date)
|
|
45
|
+
return date[constructFromSymbol](value);
|
|
46
|
+
if (date instanceof Date) return new date.constructor(value);
|
|
47
|
+
return new Date(value);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function toDate(argument, context) {
|
|
51
|
+
return constructFrom(argument, argument);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function fromUnixTime(unixTime, options) {
|
|
55
|
+
return toDate(unixTime * 1e3);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function getUnixTime(date) {
|
|
59
|
+
return Math.trunc(+toDate(date) / 1e3);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function toUnverifiedJwtVc(payload, protectedHeader, jwt) {
|
|
63
|
+
const {
|
|
64
|
+
aud: _aud,
|
|
65
|
+
exp,
|
|
66
|
+
iat,
|
|
67
|
+
iss: _iss,
|
|
68
|
+
jti: _jti,
|
|
69
|
+
nbf: _nbf,
|
|
70
|
+
sub: _sub,
|
|
71
|
+
...rest
|
|
72
|
+
} = payload;
|
|
73
|
+
const { alg, typ } = protectedHeader;
|
|
74
|
+
const doc = rest;
|
|
75
|
+
return {
|
|
76
|
+
doc,
|
|
77
|
+
issuedAt: iat ? fromUnixTime(iat) : void 0,
|
|
78
|
+
expiredAt: exp ? fromUnixTime(exp) : void 0,
|
|
79
|
+
mediaType: typ && `application/${typ}`,
|
|
80
|
+
algorithm: alg,
|
|
81
|
+
source: jwt
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
function toVerifiedJwtVc(payload, protectedHeader, jwt, key) {
|
|
85
|
+
const unverified = toUnverifiedJwtVc(payload, protectedHeader, jwt);
|
|
86
|
+
const verificationKey = {
|
|
87
|
+
...key,
|
|
88
|
+
kid: protectedHeader.kid
|
|
89
|
+
};
|
|
90
|
+
return { ...unverified, verificationKey, validated: false };
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function JwtVcDecoder() {
|
|
94
|
+
function decode(jwt) {
|
|
95
|
+
let payload;
|
|
96
|
+
let protectedHeader;
|
|
97
|
+
try {
|
|
98
|
+
payload = jose.decodeJwt(jwt);
|
|
99
|
+
protectedHeader = jose.decodeProtectedHeader(jwt);
|
|
100
|
+
} catch (e) {
|
|
101
|
+
const error = e;
|
|
102
|
+
return new VcDecodeFailed(
|
|
103
|
+
"JWT VC Decoding Failure",
|
|
104
|
+
{
|
|
105
|
+
source: jwt,
|
|
106
|
+
error
|
|
107
|
+
}
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
return toUnverifiedJwtVc(payload, protectedHeader, jwt);
|
|
111
|
+
}
|
|
112
|
+
return decode;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async function signJwtVc(vc, privateKey, options) {
|
|
116
|
+
const payload = vc;
|
|
117
|
+
const { alg = "ES256", issuedAt, expiredAt } = options;
|
|
118
|
+
const header = {
|
|
119
|
+
alg,
|
|
120
|
+
kid: privateKey.kid ?? await cryptography.createThumbprint(privateKey, alg),
|
|
121
|
+
typ: "vc+jwt",
|
|
122
|
+
cty: "vc"
|
|
123
|
+
};
|
|
124
|
+
const privateKeyImported = await jose.importJWK(privateKey, alg);
|
|
125
|
+
const jwt = await new jose.SignJWT(payload).setProtectedHeader(header).setIssuer(vc.issuer).setSubject(vc.credentialSubject.id).setIssuedAt(getUnixTime(issuedAt)).setExpirationTime(getUnixTime(expiredAt)).sign(privateKeyImported);
|
|
126
|
+
return jwt;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function JwtVcVerifier(keys, issuer, validator) {
|
|
130
|
+
async function verify(jwt) {
|
|
131
|
+
const verified = await jose.jwtVerify(jwt, keys, { issuer }).catch(
|
|
132
|
+
(e) => e
|
|
133
|
+
);
|
|
134
|
+
if (verified instanceof errors.JOSEError) {
|
|
135
|
+
return new VcVerifyFailed(
|
|
136
|
+
"JWT VC Verification Failure",
|
|
137
|
+
{
|
|
138
|
+
source: jwt,
|
|
139
|
+
error: verified
|
|
140
|
+
}
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
const { payload, protectedHeader, key } = verified;
|
|
144
|
+
const jwk = await jose.exportJWK(key);
|
|
145
|
+
const vc = toVerifiedJwtVc(payload, protectedHeader, jwt, jwk);
|
|
146
|
+
if (!validator) return vc;
|
|
147
|
+
const validated = validator(vc);
|
|
148
|
+
if (validated instanceof VcValidateFailed) return validated;
|
|
149
|
+
validated.validated = true;
|
|
150
|
+
return validated;
|
|
151
|
+
}
|
|
152
|
+
return verify;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function VcValidator(jsonSchema) {
|
|
156
|
+
const ajv = new Ajv();
|
|
157
|
+
addFormats(ajv);
|
|
158
|
+
const validateVcPayload = ajv.compile(jsonSchema);
|
|
159
|
+
function validate(vc) {
|
|
160
|
+
if (!validateVcPayload(vc.doc)) {
|
|
161
|
+
return new VcValidateFailed(
|
|
162
|
+
ajv.errorsText(validateVcPayload.errors),
|
|
163
|
+
{
|
|
164
|
+
...vc,
|
|
165
|
+
error: new Ajv.ValidationError(validateVcPayload.errors ?? [])
|
|
166
|
+
}
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
return vc;
|
|
170
|
+
}
|
|
171
|
+
return validate;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
exports.JwtVcDecoder = JwtVcDecoder;
|
|
175
|
+
exports.JwtVcVerifier = JwtVcVerifier;
|
|
176
|
+
exports.VcDecodeFailed = VcDecodeFailed;
|
|
177
|
+
exports.VcValidateFailed = VcValidateFailed;
|
|
178
|
+
exports.VcValidator = VcValidator;
|
|
179
|
+
exports.VcVerifyFailed = VcVerifyFailed;
|
|
180
|
+
exports.signJwtVc = signJwtVc;
|
|
181
|
+
exports.toUnverifiedJwtVc = toUnverifiedJwtVc;
|
|
182
|
+
exports.toVerifiedJwtVc = toVerifiedJwtVc;
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { OpVc, Jwk } from '@originator-profile/model';
|
|
2
|
+
import { ValidationError, AnySchema } from 'ajv';
|
|
3
|
+
import { JWTInvalid, JOSEError } from 'jose/errors';
|
|
4
|
+
import { JWTPayload, ProtectedHeaderParameters } from 'jose';
|
|
5
|
+
import { Keys } from '@originator-profile/cryptography';
|
|
6
|
+
|
|
7
|
+
/** 未復号 VC */
|
|
8
|
+
type UndecodedVc = {
|
|
9
|
+
/** ソース */
|
|
10
|
+
source: unknown;
|
|
11
|
+
};
|
|
12
|
+
/** 未検証 VC */
|
|
13
|
+
type UnverifiedVc<T extends OpVc = OpVc> = UndecodedVc & {
|
|
14
|
+
/** VC DM 2.0 文書 */
|
|
15
|
+
doc: T;
|
|
16
|
+
/** 発行日 */
|
|
17
|
+
issuedAt?: Date;
|
|
18
|
+
/** 有効期限 */
|
|
19
|
+
expiredAt?: Date;
|
|
20
|
+
/** メディアタイプ */
|
|
21
|
+
mediaType?: string;
|
|
22
|
+
/** 暗号アルゴリズム */
|
|
23
|
+
algorithm?: string;
|
|
24
|
+
};
|
|
25
|
+
/** 検証済み VC */
|
|
26
|
+
type VerifiedVc<T extends OpVc = OpVc> = UnverifiedVc<T> & {
|
|
27
|
+
/** 検証鍵 */
|
|
28
|
+
verificationKey: Jwk;
|
|
29
|
+
/** 妥当性確認済みか否か */
|
|
30
|
+
validated: boolean;
|
|
31
|
+
};
|
|
32
|
+
type WithError<V extends object, E extends Error = Error> = V & {
|
|
33
|
+
error: E;
|
|
34
|
+
};
|
|
35
|
+
/** VC 復号失敗 */
|
|
36
|
+
type VcDecodingFailure<V extends UndecodedVc = UndecodedVc, E extends Error = Error> = WithError<V, E>;
|
|
37
|
+
/** VC 妥当性確認失敗 */
|
|
38
|
+
type VcValidationFailure<V extends UnverifiedVc = UnverifiedVc> = WithError<V, ValidationError>;
|
|
39
|
+
/** VC 検証失敗 */
|
|
40
|
+
type VcVerificationFailure<V extends UndecodedVc = UndecodedVc, E extends Error = Error> = WithError<V, E>;
|
|
41
|
+
/** VC 復号結果 */
|
|
42
|
+
type VcDecodingResult<Success extends UnverifiedVc, Failure extends VcDecodingFailure> = Success | VcDecodeFailed<Failure>;
|
|
43
|
+
/** VC 妥当性確認結果 */
|
|
44
|
+
type VcValidationResult<Success extends UnverifiedVc, Failure extends VcValidationFailure> = Success | VcValidateFailed<VcValidationFailure<Failure>>;
|
|
45
|
+
/** VC 検証結果 */
|
|
46
|
+
type VcVerificationResult<Success extends VerifiedVc, Failure extends VcVerificationFailure> = Success | VcVerifyFailed<VcVerificationFailure<Failure>>;
|
|
47
|
+
|
|
48
|
+
/** VC 検証失敗 */
|
|
49
|
+
declare class VcVerifyFailed<T extends VcVerificationFailure> extends Error {
|
|
50
|
+
result: T;
|
|
51
|
+
static get code(): string;
|
|
52
|
+
readonly code: string;
|
|
53
|
+
constructor(message: string, result: T);
|
|
54
|
+
}
|
|
55
|
+
/** VC 復号失敗 */
|
|
56
|
+
declare class VcDecodeFailed<T extends VcDecodingFailure> extends Error {
|
|
57
|
+
result: T;
|
|
58
|
+
static get code(): string;
|
|
59
|
+
readonly code: string;
|
|
60
|
+
constructor(message: string, result: T);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* VC 妥当性確認失敗
|
|
64
|
+
*
|
|
65
|
+
* VC の妥当性確認に失敗しました。次の原因で使用されます。
|
|
66
|
+
*
|
|
67
|
+
* - データモデルへの適合性確認に失敗した
|
|
68
|
+
*
|
|
69
|
+
* */
|
|
70
|
+
declare class VcValidateFailed<T extends VcValidationFailure> extends Error {
|
|
71
|
+
result: T;
|
|
72
|
+
static get code(): string;
|
|
73
|
+
readonly code: string;
|
|
74
|
+
constructor(message: string, result: T);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** 未復号 VC */
|
|
78
|
+
type UndecodedJwtVc = {
|
|
79
|
+
/** JWT */
|
|
80
|
+
source: string;
|
|
81
|
+
};
|
|
82
|
+
/** 未検証 JWT VC */
|
|
83
|
+
type UnverifiedJwtVc<T extends OpVc> = UndecodedJwtVc & UnverifiedVc<T>;
|
|
84
|
+
/** 検証済み JWT VC */
|
|
85
|
+
type VerifiedJwtVc<T extends OpVc> = UnverifiedJwtVc<T> & VerifiedVc<T>;
|
|
86
|
+
/** JWT VC 復号失敗 */
|
|
87
|
+
type JwtVcDecodingFailure = VcDecodingFailure<UndecodedJwtVc, JWTInvalid | TypeError>;
|
|
88
|
+
/** JWT VC 検証失敗 */
|
|
89
|
+
type JwtVcVerificationFailure = VcVerificationFailure<UndecodedJwtVc, JOSEError>;
|
|
90
|
+
/** JWT VC 妥当性確認結果 */
|
|
91
|
+
type JwtVcValidationResult<T extends OpVc> = VcValidationResult<VerifiedJwtVc<T>, VcValidationFailure<VerifiedJwtVc<T>>>;
|
|
92
|
+
/** JWT VC 復号結果 */
|
|
93
|
+
type JwtVcDecodingResult<T extends OpVc> = VcDecodingResult<UnverifiedJwtVc<T>, JwtVcDecodingFailure>;
|
|
94
|
+
/** JWT VC 検証結果 */
|
|
95
|
+
type JwtVcVerificationResult<T extends OpVc> = VcVerificationResult<VerifiedJwtVc<T>, JwtVcVerificationFailure> | JwtVcValidationResult<T>;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* データモデルの復号器の生成
|
|
99
|
+
* @return 復号器
|
|
100
|
+
*/
|
|
101
|
+
declare function JwtVcDecoder<T extends OpVc>(): (jwt: string) => JwtVcDecodingResult<T>;
|
|
102
|
+
type JwtVcDecoder<T extends OpVc> = ReturnType<typeof JwtVcDecoder<T>>;
|
|
103
|
+
|
|
104
|
+
declare function toUnverifiedJwtVc<T extends OpVc>(payload: JWTPayload, protectedHeader: ProtectedHeaderParameters, jwt: string): UnverifiedJwtVc<T>;
|
|
105
|
+
declare function toVerifiedJwtVc<T extends OpVc>(payload: JWTPayload, protectedHeader: ProtectedHeaderParameters, jwt: string, key: Jwk): VerifiedJwtVc<T>;
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* VC への署名
|
|
109
|
+
* @param cp CoreProfile オブジェクト
|
|
110
|
+
* @param privateKey プライベート鍵
|
|
111
|
+
* @return JWT でエンコードされた VC
|
|
112
|
+
*/
|
|
113
|
+
declare function signJwtVc<T extends OpVc>(vc: T, privateKey: Jwk, options: {
|
|
114
|
+
alg?: string;
|
|
115
|
+
issuedAt: Date;
|
|
116
|
+
expiredAt: Date;
|
|
117
|
+
}): Promise<string>;
|
|
118
|
+
|
|
119
|
+
/** データモデルへの適合性確認のためのバリデーター */
|
|
120
|
+
declare function VcValidator<V extends UnverifiedVc>(jsonSchema: AnySchema): (vc: V) => VcValidationResult<V, VcValidationFailure<V>>;
|
|
121
|
+
/** データモデルへの適合性確認のためのバリデーター */
|
|
122
|
+
type VcValidator<V extends UnverifiedVc> = ReturnType<typeof VcValidator<V>>;
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* JWT VC の検証者の作成
|
|
126
|
+
* @param keys 公開鍵
|
|
127
|
+
* @param issuer 公開鍵の有効な発行者
|
|
128
|
+
* @param validator バリデーター
|
|
129
|
+
* @return 検証者
|
|
130
|
+
*/
|
|
131
|
+
declare function JwtVcVerifier<T extends OpVc>(keys: Keys, issuer: string | string[], validator?: VcValidator<VerifiedJwtVc<T>>): (jwt: string) => Promise<JwtVcVerificationResult<T>>;
|
|
132
|
+
type JwtVcVerifier<T extends OpVc> = ReturnType<typeof JwtVcVerifier<T>>;
|
|
133
|
+
|
|
134
|
+
export { JwtVcDecoder, type JwtVcDecodingFailure, type JwtVcDecodingResult, type JwtVcValidationResult, type JwtVcVerificationFailure, type JwtVcVerificationResult, JwtVcVerifier, type UndecodedJwtVc, type UndecodedVc, type UnverifiedJwtVc, type UnverifiedVc, VcDecodeFailed, type VcDecodingFailure, type VcDecodingResult, VcValidateFailed, type VcValidationFailure, type VcValidationResult, VcValidator, type VcVerificationFailure, type VcVerificationResult, VcVerifyFailed, type VerifiedJwtVc, type VerifiedVc, signJwtVc, toUnverifiedJwtVc, toVerifiedJwtVc };
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { OpVc, Jwk } from '@originator-profile/model';
|
|
2
|
+
import { ValidationError, AnySchema } from 'ajv';
|
|
3
|
+
import { JWTInvalid, JOSEError } from 'jose/errors';
|
|
4
|
+
import { JWTPayload, ProtectedHeaderParameters } from 'jose';
|
|
5
|
+
import { Keys } from '@originator-profile/cryptography';
|
|
6
|
+
|
|
7
|
+
/** 未復号 VC */
|
|
8
|
+
type UndecodedVc = {
|
|
9
|
+
/** ソース */
|
|
10
|
+
source: unknown;
|
|
11
|
+
};
|
|
12
|
+
/** 未検証 VC */
|
|
13
|
+
type UnverifiedVc<T extends OpVc = OpVc> = UndecodedVc & {
|
|
14
|
+
/** VC DM 2.0 文書 */
|
|
15
|
+
doc: T;
|
|
16
|
+
/** 発行日 */
|
|
17
|
+
issuedAt?: Date;
|
|
18
|
+
/** 有効期限 */
|
|
19
|
+
expiredAt?: Date;
|
|
20
|
+
/** メディアタイプ */
|
|
21
|
+
mediaType?: string;
|
|
22
|
+
/** 暗号アルゴリズム */
|
|
23
|
+
algorithm?: string;
|
|
24
|
+
};
|
|
25
|
+
/** 検証済み VC */
|
|
26
|
+
type VerifiedVc<T extends OpVc = OpVc> = UnverifiedVc<T> & {
|
|
27
|
+
/** 検証鍵 */
|
|
28
|
+
verificationKey: Jwk;
|
|
29
|
+
/** 妥当性確認済みか否か */
|
|
30
|
+
validated: boolean;
|
|
31
|
+
};
|
|
32
|
+
type WithError<V extends object, E extends Error = Error> = V & {
|
|
33
|
+
error: E;
|
|
34
|
+
};
|
|
35
|
+
/** VC 復号失敗 */
|
|
36
|
+
type VcDecodingFailure<V extends UndecodedVc = UndecodedVc, E extends Error = Error> = WithError<V, E>;
|
|
37
|
+
/** VC 妥当性確認失敗 */
|
|
38
|
+
type VcValidationFailure<V extends UnverifiedVc = UnverifiedVc> = WithError<V, ValidationError>;
|
|
39
|
+
/** VC 検証失敗 */
|
|
40
|
+
type VcVerificationFailure<V extends UndecodedVc = UndecodedVc, E extends Error = Error> = WithError<V, E>;
|
|
41
|
+
/** VC 復号結果 */
|
|
42
|
+
type VcDecodingResult<Success extends UnverifiedVc, Failure extends VcDecodingFailure> = Success | VcDecodeFailed<Failure>;
|
|
43
|
+
/** VC 妥当性確認結果 */
|
|
44
|
+
type VcValidationResult<Success extends UnverifiedVc, Failure extends VcValidationFailure> = Success | VcValidateFailed<VcValidationFailure<Failure>>;
|
|
45
|
+
/** VC 検証結果 */
|
|
46
|
+
type VcVerificationResult<Success extends VerifiedVc, Failure extends VcVerificationFailure> = Success | VcVerifyFailed<VcVerificationFailure<Failure>>;
|
|
47
|
+
|
|
48
|
+
/** VC 検証失敗 */
|
|
49
|
+
declare class VcVerifyFailed<T extends VcVerificationFailure> extends Error {
|
|
50
|
+
result: T;
|
|
51
|
+
static get code(): string;
|
|
52
|
+
readonly code: string;
|
|
53
|
+
constructor(message: string, result: T);
|
|
54
|
+
}
|
|
55
|
+
/** VC 復号失敗 */
|
|
56
|
+
declare class VcDecodeFailed<T extends VcDecodingFailure> extends Error {
|
|
57
|
+
result: T;
|
|
58
|
+
static get code(): string;
|
|
59
|
+
readonly code: string;
|
|
60
|
+
constructor(message: string, result: T);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* VC 妥当性確認失敗
|
|
64
|
+
*
|
|
65
|
+
* VC の妥当性確認に失敗しました。次の原因で使用されます。
|
|
66
|
+
*
|
|
67
|
+
* - データモデルへの適合性確認に失敗した
|
|
68
|
+
*
|
|
69
|
+
* */
|
|
70
|
+
declare class VcValidateFailed<T extends VcValidationFailure> extends Error {
|
|
71
|
+
result: T;
|
|
72
|
+
static get code(): string;
|
|
73
|
+
readonly code: string;
|
|
74
|
+
constructor(message: string, result: T);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** 未復号 VC */
|
|
78
|
+
type UndecodedJwtVc = {
|
|
79
|
+
/** JWT */
|
|
80
|
+
source: string;
|
|
81
|
+
};
|
|
82
|
+
/** 未検証 JWT VC */
|
|
83
|
+
type UnverifiedJwtVc<T extends OpVc> = UndecodedJwtVc & UnverifiedVc<T>;
|
|
84
|
+
/** 検証済み JWT VC */
|
|
85
|
+
type VerifiedJwtVc<T extends OpVc> = UnverifiedJwtVc<T> & VerifiedVc<T>;
|
|
86
|
+
/** JWT VC 復号失敗 */
|
|
87
|
+
type JwtVcDecodingFailure = VcDecodingFailure<UndecodedJwtVc, JWTInvalid | TypeError>;
|
|
88
|
+
/** JWT VC 検証失敗 */
|
|
89
|
+
type JwtVcVerificationFailure = VcVerificationFailure<UndecodedJwtVc, JOSEError>;
|
|
90
|
+
/** JWT VC 妥当性確認結果 */
|
|
91
|
+
type JwtVcValidationResult<T extends OpVc> = VcValidationResult<VerifiedJwtVc<T>, VcValidationFailure<VerifiedJwtVc<T>>>;
|
|
92
|
+
/** JWT VC 復号結果 */
|
|
93
|
+
type JwtVcDecodingResult<T extends OpVc> = VcDecodingResult<UnverifiedJwtVc<T>, JwtVcDecodingFailure>;
|
|
94
|
+
/** JWT VC 検証結果 */
|
|
95
|
+
type JwtVcVerificationResult<T extends OpVc> = VcVerificationResult<VerifiedJwtVc<T>, JwtVcVerificationFailure> | JwtVcValidationResult<T>;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* データモデルの復号器の生成
|
|
99
|
+
* @return 復号器
|
|
100
|
+
*/
|
|
101
|
+
declare function JwtVcDecoder<T extends OpVc>(): (jwt: string) => JwtVcDecodingResult<T>;
|
|
102
|
+
type JwtVcDecoder<T extends OpVc> = ReturnType<typeof JwtVcDecoder<T>>;
|
|
103
|
+
|
|
104
|
+
declare function toUnverifiedJwtVc<T extends OpVc>(payload: JWTPayload, protectedHeader: ProtectedHeaderParameters, jwt: string): UnverifiedJwtVc<T>;
|
|
105
|
+
declare function toVerifiedJwtVc<T extends OpVc>(payload: JWTPayload, protectedHeader: ProtectedHeaderParameters, jwt: string, key: Jwk): VerifiedJwtVc<T>;
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* VC への署名
|
|
109
|
+
* @param cp CoreProfile オブジェクト
|
|
110
|
+
* @param privateKey プライベート鍵
|
|
111
|
+
* @return JWT でエンコードされた VC
|
|
112
|
+
*/
|
|
113
|
+
declare function signJwtVc<T extends OpVc>(vc: T, privateKey: Jwk, options: {
|
|
114
|
+
alg?: string;
|
|
115
|
+
issuedAt: Date;
|
|
116
|
+
expiredAt: Date;
|
|
117
|
+
}): Promise<string>;
|
|
118
|
+
|
|
119
|
+
/** データモデルへの適合性確認のためのバリデーター */
|
|
120
|
+
declare function VcValidator<V extends UnverifiedVc>(jsonSchema: AnySchema): (vc: V) => VcValidationResult<V, VcValidationFailure<V>>;
|
|
121
|
+
/** データモデルへの適合性確認のためのバリデーター */
|
|
122
|
+
type VcValidator<V extends UnverifiedVc> = ReturnType<typeof VcValidator<V>>;
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* JWT VC の検証者の作成
|
|
126
|
+
* @param keys 公開鍵
|
|
127
|
+
* @param issuer 公開鍵の有効な発行者
|
|
128
|
+
* @param validator バリデーター
|
|
129
|
+
* @return 検証者
|
|
130
|
+
*/
|
|
131
|
+
declare function JwtVcVerifier<T extends OpVc>(keys: Keys, issuer: string | string[], validator?: VcValidator<VerifiedJwtVc<T>>): (jwt: string) => Promise<JwtVcVerificationResult<T>>;
|
|
132
|
+
type JwtVcVerifier<T extends OpVc> = ReturnType<typeof JwtVcVerifier<T>>;
|
|
133
|
+
|
|
134
|
+
export { JwtVcDecoder, type JwtVcDecodingFailure, type JwtVcDecodingResult, type JwtVcValidationResult, type JwtVcVerificationFailure, type JwtVcVerificationResult, JwtVcVerifier, type UndecodedJwtVc, type UndecodedVc, type UnverifiedJwtVc, type UnverifiedVc, VcDecodeFailed, type VcDecodingFailure, type VcDecodingResult, VcValidateFailed, type VcValidationFailure, type VcValidationResult, VcValidator, type VcVerificationFailure, type VcVerificationResult, VcVerifyFailed, type VerifiedJwtVc, type VerifiedVc, signJwtVc, toUnverifiedJwtVc, toVerifiedJwtVc };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { decodeJwt, decodeProtectedHeader, importJWK, SignJWT, jwtVerify, exportJWK } from 'jose';
|
|
2
|
+
import { createThumbprint } from '@originator-profile/cryptography';
|
|
3
|
+
import { JOSEError } from 'jose/errors';
|
|
4
|
+
import Ajv, { ValidationError } from 'ajv';
|
|
5
|
+
import addFormats from 'ajv-formats';
|
|
6
|
+
|
|
7
|
+
class VcVerifyFailed extends Error {
|
|
8
|
+
constructor(message, result) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.result = result;
|
|
11
|
+
}
|
|
12
|
+
static get code() {
|
|
13
|
+
return "ERR_VC_VERIFY_FAILED";
|
|
14
|
+
}
|
|
15
|
+
code = VcVerifyFailed.code;
|
|
16
|
+
}
|
|
17
|
+
class VcDecodeFailed extends Error {
|
|
18
|
+
constructor(message, result) {
|
|
19
|
+
super(message);
|
|
20
|
+
this.result = result;
|
|
21
|
+
}
|
|
22
|
+
static get code() {
|
|
23
|
+
return "ERR_VC_DECODE_FAILED";
|
|
24
|
+
}
|
|
25
|
+
code = VcDecodeFailed.code;
|
|
26
|
+
}
|
|
27
|
+
class VcValidateFailed extends Error {
|
|
28
|
+
constructor(message, result) {
|
|
29
|
+
super(message);
|
|
30
|
+
this.result = result;
|
|
31
|
+
}
|
|
32
|
+
static get code() {
|
|
33
|
+
return "ERR_VC_VALIDATION_FAILED";
|
|
34
|
+
}
|
|
35
|
+
code = VcValidateFailed.code;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const constructFromSymbol = Symbol.for("constructDateFrom");
|
|
39
|
+
|
|
40
|
+
function constructFrom(date, value) {
|
|
41
|
+
if (typeof date === "function") return date(value);
|
|
42
|
+
if (date && typeof date === "object" && constructFromSymbol in date)
|
|
43
|
+
return date[constructFromSymbol](value);
|
|
44
|
+
if (date instanceof Date) return new date.constructor(value);
|
|
45
|
+
return new Date(value);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function toDate(argument, context) {
|
|
49
|
+
return constructFrom(argument, argument);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function fromUnixTime(unixTime, options) {
|
|
53
|
+
return toDate(unixTime * 1e3);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function getUnixTime(date) {
|
|
57
|
+
return Math.trunc(+toDate(date) / 1e3);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function toUnverifiedJwtVc(payload, protectedHeader, jwt) {
|
|
61
|
+
const {
|
|
62
|
+
aud: _aud,
|
|
63
|
+
exp,
|
|
64
|
+
iat,
|
|
65
|
+
iss: _iss,
|
|
66
|
+
jti: _jti,
|
|
67
|
+
nbf: _nbf,
|
|
68
|
+
sub: _sub,
|
|
69
|
+
...rest
|
|
70
|
+
} = payload;
|
|
71
|
+
const { alg, typ } = protectedHeader;
|
|
72
|
+
const doc = rest;
|
|
73
|
+
return {
|
|
74
|
+
doc,
|
|
75
|
+
issuedAt: iat ? fromUnixTime(iat) : void 0,
|
|
76
|
+
expiredAt: exp ? fromUnixTime(exp) : void 0,
|
|
77
|
+
mediaType: typ && `application/${typ}`,
|
|
78
|
+
algorithm: alg,
|
|
79
|
+
source: jwt
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
function toVerifiedJwtVc(payload, protectedHeader, jwt, key) {
|
|
83
|
+
const unverified = toUnverifiedJwtVc(payload, protectedHeader, jwt);
|
|
84
|
+
const verificationKey = {
|
|
85
|
+
...key,
|
|
86
|
+
kid: protectedHeader.kid
|
|
87
|
+
};
|
|
88
|
+
return { ...unverified, verificationKey, validated: false };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function JwtVcDecoder() {
|
|
92
|
+
function decode(jwt) {
|
|
93
|
+
let payload;
|
|
94
|
+
let protectedHeader;
|
|
95
|
+
try {
|
|
96
|
+
payload = decodeJwt(jwt);
|
|
97
|
+
protectedHeader = decodeProtectedHeader(jwt);
|
|
98
|
+
} catch (e) {
|
|
99
|
+
const error = e;
|
|
100
|
+
return new VcDecodeFailed(
|
|
101
|
+
"JWT VC Decoding Failure",
|
|
102
|
+
{
|
|
103
|
+
source: jwt,
|
|
104
|
+
error
|
|
105
|
+
}
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
return toUnverifiedJwtVc(payload, protectedHeader, jwt);
|
|
109
|
+
}
|
|
110
|
+
return decode;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async function signJwtVc(vc, privateKey, options) {
|
|
114
|
+
const payload = vc;
|
|
115
|
+
const { alg = "ES256", issuedAt, expiredAt } = options;
|
|
116
|
+
const header = {
|
|
117
|
+
alg,
|
|
118
|
+
kid: privateKey.kid ?? await createThumbprint(privateKey, alg),
|
|
119
|
+
typ: "vc+jwt",
|
|
120
|
+
cty: "vc"
|
|
121
|
+
};
|
|
122
|
+
const privateKeyImported = await importJWK(privateKey, alg);
|
|
123
|
+
const jwt = await new SignJWT(payload).setProtectedHeader(header).setIssuer(vc.issuer).setSubject(vc.credentialSubject.id).setIssuedAt(getUnixTime(issuedAt)).setExpirationTime(getUnixTime(expiredAt)).sign(privateKeyImported);
|
|
124
|
+
return jwt;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function JwtVcVerifier(keys, issuer, validator) {
|
|
128
|
+
async function verify(jwt) {
|
|
129
|
+
const verified = await jwtVerify(jwt, keys, { issuer }).catch(
|
|
130
|
+
(e) => e
|
|
131
|
+
);
|
|
132
|
+
if (verified instanceof JOSEError) {
|
|
133
|
+
return new VcVerifyFailed(
|
|
134
|
+
"JWT VC Verification Failure",
|
|
135
|
+
{
|
|
136
|
+
source: jwt,
|
|
137
|
+
error: verified
|
|
138
|
+
}
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
const { payload, protectedHeader, key } = verified;
|
|
142
|
+
const jwk = await exportJWK(key);
|
|
143
|
+
const vc = toVerifiedJwtVc(payload, protectedHeader, jwt, jwk);
|
|
144
|
+
if (!validator) return vc;
|
|
145
|
+
const validated = validator(vc);
|
|
146
|
+
if (validated instanceof VcValidateFailed) return validated;
|
|
147
|
+
validated.validated = true;
|
|
148
|
+
return validated;
|
|
149
|
+
}
|
|
150
|
+
return verify;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function VcValidator(jsonSchema) {
|
|
154
|
+
const ajv = new Ajv();
|
|
155
|
+
addFormats(ajv);
|
|
156
|
+
const validateVcPayload = ajv.compile(jsonSchema);
|
|
157
|
+
function validate(vc) {
|
|
158
|
+
if (!validateVcPayload(vc.doc)) {
|
|
159
|
+
return new VcValidateFailed(
|
|
160
|
+
ajv.errorsText(validateVcPayload.errors),
|
|
161
|
+
{
|
|
162
|
+
...vc,
|
|
163
|
+
error: new ValidationError(validateVcPayload.errors ?? [])
|
|
164
|
+
}
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
return vc;
|
|
168
|
+
}
|
|
169
|
+
return validate;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export { JwtVcDecoder, JwtVcVerifier, VcDecodeFailed, VcValidateFailed, VcValidator, VcVerifyFailed, signJwtVc, toUnverifiedJwtVc, toVerifiedJwtVc };
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@originator-profile/securing-mechanism",
|
|
3
|
+
"version": "0.4.0-beta.1",
|
|
4
|
+
"private": false,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
"require": {
|
|
8
|
+
"types": "./dist/index.d.cts",
|
|
9
|
+
"default": "./dist/index.cjs"
|
|
10
|
+
},
|
|
11
|
+
"import": {
|
|
12
|
+
"types": "./dist/index.d.mts",
|
|
13
|
+
"default": "./dist/index.mjs"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"ajv": "^8.17.1",
|
|
21
|
+
"ajv-formats": "^3.0.1",
|
|
22
|
+
"jose": "^6.0.10",
|
|
23
|
+
"@originator-profile/model": "0.4.0-beta.1",
|
|
24
|
+
"@originator-profile/cryptography": "0.4.0-beta.1"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"date-fns": "^4.1.0",
|
|
28
|
+
"eslint": "^9.25.1",
|
|
29
|
+
"pkgroll": "^2.12.2",
|
|
30
|
+
"typescript": "^5.8.3",
|
|
31
|
+
"vitest": "^4.0.0",
|
|
32
|
+
"@originator-profile/tsconfig": "0.4.0-beta.1",
|
|
33
|
+
"eslint-config-originator-profile": "0.4.0-beta.1"
|
|
34
|
+
},
|
|
35
|
+
"scripts": {
|
|
36
|
+
"build": "pkgroll --clean-dist --target=node20",
|
|
37
|
+
"test": "vitest run",
|
|
38
|
+
"lint": "eslint --fix .",
|
|
39
|
+
"type-check": "tsc --noEmit"
|
|
40
|
+
}
|
|
41
|
+
}
|