@originator-profile/securing-mechanism 0.6.1 → 0.7.0-beta.2
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 +2 -0
- package/dist/index.d.ts +28 -5
- package/dist/index.js +57 -14
- package/package.json +7 -8
package/README.md
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
# Profile JWT Securing Mechanism
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/@originator-profile/securing-mechanism) [](https://www.jsdocs.io/package/@originator-profile/securing-mechanism)
|
|
4
|
+
|
|
3
5
|
VC の Securing 処理をするためのパッケージです。
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { OpVc, Jwk } from '@originator-profile/model';
|
|
2
2
|
import { JWTInvalid, JOSEError } from 'jose/errors';
|
|
3
|
-
import { JWTPayload, ProtectedHeaderParameters } from 'jose';
|
|
3
|
+
import { JWTPayload, ProtectedHeaderParameters, CryptoKey, KeyObject } from 'jose';
|
|
4
4
|
import { Keys } from '@originator-profile/cryptography';
|
|
5
5
|
import { ZodType } from 'zod';
|
|
6
6
|
|
|
@@ -114,6 +114,28 @@ type JwtVcDecoder<T extends OpVc> = ReturnType<typeof JwtVcDecoder<T>>;
|
|
|
114
114
|
declare function toUnverifiedJwtVc<T extends OpVc>(payload: JWTPayload, protectedHeader: ProtectedHeaderParameters, jwt: string): UnverifiedJwtVc<T>;
|
|
115
115
|
declare function toVerifiedJwtVc<T extends OpVc>(payload: JWTPayload, protectedHeader: ProtectedHeaderParameters, jwt: string, key: Jwk): VerifiedJwtVc<T>;
|
|
116
116
|
|
|
117
|
+
/**
|
|
118
|
+
* 鍵材料を外部に渡さない不透明な署名者
|
|
119
|
+
*
|
|
120
|
+
* HSM・セキュアエレメント・クラウドKMS(AWS KMS, Google Cloud KMS, Azure Key Vault等)・
|
|
121
|
+
* WebAuthn/FIDO2など、秘密鍵をハードウェア境界外に取り出せない署名環境向けの注入口。
|
|
122
|
+
*/
|
|
123
|
+
type JwtSigner = {
|
|
124
|
+
/** JWS alg */
|
|
125
|
+
alg: string;
|
|
126
|
+
/** JWS kid (鍵材料を持たないためサムプリントによるフォールバック計算ができない) */
|
|
127
|
+
kid: string;
|
|
128
|
+
/**
|
|
129
|
+
* signingInput (base64url(header) + "." + base64url(payload) の ASCII バイト列) に対する
|
|
130
|
+
* 生の署名バイト列 (JOSE 形式。例えば ES256 なら r||s の固定長結合) を返す。
|
|
131
|
+
*/
|
|
132
|
+
sign: (signingInput: Uint8Array) => Promise<Uint8Array>;
|
|
133
|
+
};
|
|
134
|
+
/** ソフトウェア鍵として直接扱える鍵材料 */
|
|
135
|
+
type KeyMaterial = Jwk | CryptoKey | KeyObject;
|
|
136
|
+
/** signer が JwtSigner (不透明な署名者) かどうかを判定する */
|
|
137
|
+
declare function isJwtSigner(signer: KeyMaterial | JwtSigner): signer is JwtSigner;
|
|
138
|
+
|
|
117
139
|
type SignableVc = {
|
|
118
140
|
issuer: string;
|
|
119
141
|
credentialSubject: {
|
|
@@ -123,11 +145,12 @@ type SignableVc = {
|
|
|
123
145
|
/**
|
|
124
146
|
* VC への署名
|
|
125
147
|
* @param vc VC オブジェクト
|
|
126
|
-
* @param
|
|
148
|
+
* @param signer プライベートキー (Jwk/CryptoKey/KeyObject)、または HSM・KMS・WebAuthn等の外部署名者 (JwtSigner)
|
|
127
149
|
* @return JWT でエンコードされた VC
|
|
128
150
|
*/
|
|
129
|
-
declare function signJwtVc<T extends SignableVc>(vc: T,
|
|
151
|
+
declare function signJwtVc<T extends SignableVc>(vc: T, signer: KeyMaterial | JwtSigner, options: {
|
|
130
152
|
alg?: string;
|
|
153
|
+
kid?: string;
|
|
131
154
|
issuedAt: Date;
|
|
132
155
|
expiredAt: Date;
|
|
133
156
|
}): Promise<string>;
|
|
@@ -147,5 +170,5 @@ type VcValidator<V extends UnverifiedVc> = ReturnType<typeof VcValidator<V>>;
|
|
|
147
170
|
declare function JwtVcVerifier<T extends OpVc>(keys: Keys, issuer: string | string[], validator?: VcValidator<VerifiedJwtVc<T>>): (jwt: string) => Promise<JwtVcVerificationResult<T>>;
|
|
148
171
|
type JwtVcVerifier<T extends OpVc> = ReturnType<typeof JwtVcVerifier<T>>;
|
|
149
172
|
|
|
150
|
-
export { JwtVcDecoder, JwtVcVerifier, SchemaValidationError, VcDecodeFailed, VcValidateFailed, VcValidator, VcVerifyFailed, signJwtVc, toUnverifiedJwtVc, toVerifiedJwtVc };
|
|
151
|
-
export type { JwtVcDecodingFailure, JwtVcDecodingResult, JwtVcValidationResult, JwtVcVerificationFailure, JwtVcVerificationResult, SchemaIssue, UndecodedJwtVc, UndecodedVc, UnverifiedJwtVc, UnverifiedVc, VcDecodingFailure, VcDecodingResult, VcValidationFailure, VcValidationResult, VcVerificationFailure, VcVerificationResult, VerifiedJwtVc, VerifiedVc };
|
|
173
|
+
export { JwtVcDecoder, JwtVcVerifier, SchemaValidationError, VcDecodeFailed, VcValidateFailed, VcValidator, VcVerifyFailed, isJwtSigner, signJwtVc, toUnverifiedJwtVc, toVerifiedJwtVc };
|
|
174
|
+
export type { JwtSigner, JwtVcDecodingFailure, JwtVcDecodingResult, JwtVcValidationResult, JwtVcVerificationFailure, JwtVcVerificationResult, KeyMaterial, SchemaIssue, UndecodedJwtVc, UndecodedVc, UnverifiedJwtVc, UnverifiedVc, VcDecodingFailure, VcDecodingResult, VcValidationFailure, VcValidationResult, VcVerificationFailure, VcVerificationResult, VerifiedJwtVc, VerifiedVc };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { decodeJwt, decodeProtectedHeader, importJWK, SignJWT,
|
|
1
|
+
import { decodeJwt, decodeProtectedHeader, base64url, importJWK, SignJWT, exportJWK, jwtVerify } from 'jose';
|
|
2
2
|
import { createThumbprint } from '@originator-profile/cryptography';
|
|
3
3
|
import { JOSEError } from 'jose/errors';
|
|
4
4
|
|
|
@@ -108,18 +108,61 @@ function JwtVcDecoder() {
|
|
|
108
108
|
return decode;
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
111
|
+
function isJwtSigner(signer) {
|
|
112
|
+
return !("kty" in signer) && "sign" in signer && typeof signer.sign === "function";
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function isJwk(keyMaterial) {
|
|
116
|
+
return "kty" in keyMaterial;
|
|
117
|
+
}
|
|
118
|
+
async function resolveKid(keyMaterial) {
|
|
119
|
+
if (isJwk(keyMaterial)) {
|
|
120
|
+
return keyMaterial.kid ?? await createThumbprint(keyMaterial);
|
|
121
|
+
}
|
|
122
|
+
try {
|
|
123
|
+
const jwk = await exportJWK(keyMaterial);
|
|
124
|
+
return await createThumbprint(jwk);
|
|
125
|
+
} catch (e) {
|
|
126
|
+
throw new Error(
|
|
127
|
+
"Could not derive kid from the key (it may be non-extractable). Specify options.kid explicitly.",
|
|
128
|
+
{ cause: e }
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
async function resolveAlgAndKid(signer, options) {
|
|
133
|
+
if (isJwtSigner(signer)) {
|
|
134
|
+
if (options.alg !== void 0 && options.alg !== signer.alg) {
|
|
135
|
+
throw new Error(
|
|
136
|
+
`options.alg ("${options.alg}") must match signer.alg ("${signer.alg}").`
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
return { alg: signer.alg, kid: options.kid ?? signer.kid };
|
|
140
|
+
}
|
|
141
|
+
const alg = options.alg ?? "ES256";
|
|
142
|
+
return { alg, kid: options.kid ?? await resolveKid(signer) };
|
|
143
|
+
}
|
|
144
|
+
async function signJwtVc(vc, signer, options) {
|
|
145
|
+
const { issuedAt, expiredAt } = options;
|
|
146
|
+
const { alg, kid } = await resolveAlgAndKid(signer, options);
|
|
147
|
+
const header = { alg, kid, typ: "vc+jwt", cty: "vc" };
|
|
148
|
+
if (isJwtSigner(signer)) {
|
|
149
|
+
const claims = {
|
|
150
|
+
...vc,
|
|
151
|
+
iss: vc.issuer,
|
|
152
|
+
sub: vc.credentialSubject.id,
|
|
153
|
+
iat: getUnixTime(issuedAt),
|
|
154
|
+
exp: getUnixTime(expiredAt)
|
|
155
|
+
};
|
|
156
|
+
const encodedHeader = base64url.encode(JSON.stringify(header));
|
|
157
|
+
const encodedPayload = base64url.encode(JSON.stringify(claims));
|
|
158
|
+
const signingInput = new TextEncoder().encode(
|
|
159
|
+
`${encodedHeader}.${encodedPayload}`
|
|
160
|
+
);
|
|
161
|
+
const signature = await signer.sign(signingInput);
|
|
162
|
+
return `${encodedHeader}.${encodedPayload}.${base64url.encode(signature)}`;
|
|
163
|
+
}
|
|
164
|
+
const key = isJwk(signer) ? await importJWK(signer, alg) : signer;
|
|
165
|
+
return await new SignJWT(vc).setProtectedHeader(header).setIssuer(vc.issuer).setSubject(vc.credentialSubject.id).setIssuedAt(getUnixTime(issuedAt)).setExpirationTime(getUnixTime(expiredAt)).sign(key);
|
|
123
166
|
}
|
|
124
167
|
|
|
125
168
|
function JwtVcVerifier(keys, issuer, validator) {
|
|
@@ -174,4 +217,4 @@ function VcValidator(schema) {
|
|
|
174
217
|
return validate;
|
|
175
218
|
}
|
|
176
219
|
|
|
177
|
-
export { JwtVcDecoder, JwtVcVerifier, SchemaValidationError, VcDecodeFailed, VcValidateFailed, VcValidator, VcVerifyFailed, signJwtVc, toUnverifiedJwtVc, toVerifiedJwtVc };
|
|
220
|
+
export { JwtVcDecoder, JwtVcVerifier, SchemaValidationError, VcDecodeFailed, VcValidateFailed, VcValidator, VcVerifyFailed, isJwtSigner, signJwtVc, toUnverifiedJwtVc, toVerifiedJwtVc };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@originator-profile/securing-mechanism",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0-beta.2",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"homepage": "https://docs.originator-profile.org",
|
|
6
6
|
"repository": {
|
|
@@ -25,22 +25,21 @@
|
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"jose": "^6.2.2",
|
|
27
27
|
"zod": "^4.3.6",
|
|
28
|
-
"@originator-profile/cryptography": "0.
|
|
29
|
-
"@originator-profile/model": "0.
|
|
28
|
+
"@originator-profile/cryptography": "0.7.0-beta.2",
|
|
29
|
+
"@originator-profile/model": "0.7.0-beta.2"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"date-fns": "4.1.0",
|
|
33
|
-
"
|
|
33
|
+
"oxlint": "^1.73.0",
|
|
34
|
+
"oxlint-tsgolint": "^0.24.0",
|
|
34
35
|
"pkgroll": "2.27.0",
|
|
35
36
|
"typescript": "6.0.2",
|
|
36
37
|
"vitest": "4.1.4",
|
|
37
|
-
"
|
|
38
|
-
"@originator-profile/tsconfig": "0.6.1"
|
|
38
|
+
"@originator-profile/tsconfig": "0.7.0-beta.2"
|
|
39
39
|
},
|
|
40
40
|
"scripts": {
|
|
41
41
|
"build": "pkgroll --clean-dist",
|
|
42
42
|
"test": "vitest run",
|
|
43
|
-
"lint": "
|
|
44
|
-
"type-check": "tsc --noEmit"
|
|
43
|
+
"lint": "oxlint --fix ."
|
|
45
44
|
}
|
|
46
45
|
}
|