@sphereon/ssi-types 0.33.1-next.2 → 0.33.1-next.68
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/dist/index.cjs +1773 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1589 -0
- package/dist/index.d.ts +1589 -6
- package/dist/index.js +1741 -24
- package/dist/index.js.map +1 -1
- package/package.json +23 -14
- package/src/index.ts +3 -2
- package/src/logging/index.ts +6 -4
- package/src/mapper/credential-constraints.ts +14 -1
- package/src/mapper/credential-mapper.ts +61 -23
- package/src/mapper/index.ts +1 -0
- package/src/types/cose.ts +5 -51
- package/src/types/did.ts +0 -90
- package/src/types/index.ts +13 -13
- package/src/types/jose.ts +18 -65
- package/src/types/mso_mdoc.ts +10 -138
- package/src/types/sd-jwt-vc.ts +4 -178
- package/src/types/status-list.ts +1 -8
- package/src/types/vc.ts +7 -29
- package/src/types/w3c-vc.ts +3 -26
- package/src/utils/cose.ts +46 -0
- package/src/utils/did.ts +91 -0
- package/src/utils/hasher.ts +5 -2
- package/src/utils/index.ts +6 -0
- package/src/utils/jose.ts +47 -0
- package/src/utils/mdoc.ts +144 -0
- package/src/utils/sd-jwt.ts +179 -0
- package/src/utils/vc.ts +54 -0
- package/dist/events/index.d.ts +0 -116
- package/dist/events/index.d.ts.map +0 -1
- package/dist/events/index.js +0 -165
- package/dist/events/index.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/logging/index.d.ts +0 -73
- package/dist/logging/index.d.ts.map +0 -1
- package/dist/logging/index.js +0 -186
- package/dist/logging/index.js.map +0 -1
- package/dist/mapper/credential-constraints.d.ts +0 -16
- package/dist/mapper/credential-constraints.d.ts.map +0 -1
- package/dist/mapper/credential-constraints.js +0 -3
- package/dist/mapper/credential-constraints.js.map +0 -1
- package/dist/mapper/credential-mapper.d.ts +0 -124
- package/dist/mapper/credential-mapper.d.ts.map +0 -1
- package/dist/mapper/credential-mapper.js +0 -774
- package/dist/mapper/credential-mapper.js.map +0 -1
- package/dist/mapper/index.d.ts +0 -3
- package/dist/mapper/index.d.ts.map +0 -1
- package/dist/mapper/index.js +0 -19
- package/dist/mapper/index.js.map +0 -1
- package/dist/mapper/jsonld-language-values.d.ts +0 -18
- package/dist/mapper/jsonld-language-values.d.ts.map +0 -1
- package/dist/mapper/jsonld-language-values.js +0 -79
- package/dist/mapper/jsonld-language-values.js.map +0 -1
- package/dist/types/cose.d.ts +0 -77
- package/dist/types/cose.d.ts.map +0 -1
- package/dist/types/cose.js +0 -51
- package/dist/types/cose.js.map +0 -1
- package/dist/types/dcql.d.ts +0 -33
- package/dist/types/dcql.d.ts.map +0 -1
- package/dist/types/dcql.js +0 -4
- package/dist/types/dcql.js.map +0 -1
- package/dist/types/did.d.ts +0 -186
- package/dist/types/did.d.ts.map +0 -1
- package/dist/types/did.js +0 -78
- package/dist/types/did.js.map +0 -1
- package/dist/types/generic.d.ts +0 -44
- package/dist/types/generic.d.ts.map +0 -1
- package/dist/types/generic.js +0 -3
- package/dist/types/generic.js.map +0 -1
- package/dist/types/index.d.ts +0 -14
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/index.js +0 -30
- package/dist/types/index.js.map +0 -1
- package/dist/types/jose.d.ts +0 -89
- package/dist/types/jose.d.ts.map +0 -1
- package/dist/types/jose.js +0 -55
- package/dist/types/jose.js.map +0 -1
- package/dist/types/metadata-types.d.ts +0 -5
- package/dist/types/metadata-types.d.ts.map +0 -1
- package/dist/types/metadata-types.js +0 -3
- package/dist/types/metadata-types.js.map +0 -1
- package/dist/types/mso_mdoc.d.ts +0 -94
- package/dist/types/mso_mdoc.d.ts.map +0 -1
- package/dist/types/mso_mdoc.js +0 -121
- package/dist/types/mso_mdoc.js.map +0 -1
- package/dist/types/pex.d.ts +0 -36
- package/dist/types/pex.d.ts.map +0 -1
- package/dist/types/pex.js +0 -3
- package/dist/types/pex.js.map +0 -1
- package/dist/types/sd-jwt-type-metadata.d.ts +0 -191
- package/dist/types/sd-jwt-type-metadata.d.ts.map +0 -1
- package/dist/types/sd-jwt-type-metadata.js +0 -3
- package/dist/types/sd-jwt-type-metadata.js.map +0 -1
- package/dist/types/sd-jwt-vc.d.ts +0 -196
- package/dist/types/sd-jwt-vc.d.ts.map +0 -1
- package/dist/types/sd-jwt-vc.js +0 -142
- package/dist/types/sd-jwt-vc.js.map +0 -1
- package/dist/types/status-list.d.ts +0 -10
- package/dist/types/status-list.d.ts.map +0 -1
- package/dist/types/status-list.js +0 -9
- package/dist/types/status-list.js.map +0 -1
- package/dist/types/vc.d.ts +0 -28
- package/dist/types/vc.d.ts.map +0 -1
- package/dist/types/vc.js +0 -28
- package/dist/types/vc.js.map +0 -1
- package/dist/types/w3c-vc.d.ts +0 -243
- package/dist/types/w3c-vc.d.ts.map +0 -1
- package/dist/types/w3c-vc.js +0 -26
- package/dist/types/w3c-vc.js.map +0 -1
- package/dist/utils/hasher.d.ts +0 -4
- package/dist/utils/hasher.d.ts.map +0 -1
- package/dist/utils/hasher.js +0 -40
- package/dist/utils/hasher.js.map +0 -1
- package/dist/utils/index.d.ts +0 -3
- package/dist/utils/index.d.ts.map +0 -1
- package/dist/utils/index.js +0 -19
- package/dist/utils/index.js.map +0 -1
- package/dist/utils/object.d.ts +0 -8
- package/dist/utils/object.d.ts.map +0 -1
- package/dist/utils/object.js +0 -28
- package/dist/utils/object.js.map +0 -1
package/src/types/vc.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type {
|
|
2
2
|
MdocDeviceResponse,
|
|
3
3
|
MdocDocument,
|
|
4
4
|
MdocOid4vpIssuerSigned,
|
|
@@ -6,8 +6,8 @@ import {
|
|
|
6
6
|
WrappedMdocCredential,
|
|
7
7
|
WrappedMdocPresentation,
|
|
8
8
|
} from './mso_mdoc'
|
|
9
|
-
import { SdJwtDecodedVerifiableCredential, WrappedSdJwtVerifiableCredential, WrappedSdJwtVerifiablePresentation } from './sd-jwt-vc'
|
|
10
|
-
import {
|
|
9
|
+
import type { SdJwtDecodedVerifiableCredential, WrappedSdJwtVerifiableCredential, WrappedSdJwtVerifiablePresentation } from './sd-jwt-vc'
|
|
10
|
+
import type {
|
|
11
11
|
JwtDecodedVerifiableCredential,
|
|
12
12
|
JwtDecodedVerifiablePresentation,
|
|
13
13
|
W3CVerifiableCredential,
|
|
@@ -20,25 +20,13 @@ export type WrappedVerifiableCredential = WrappedW3CVerifiableCredential | Wrapp
|
|
|
20
20
|
|
|
21
21
|
export type WrappedVerifiablePresentation = WrappedW3CVerifiablePresentation | WrappedSdJwtVerifiablePresentation | WrappedMdocPresentation
|
|
22
22
|
|
|
23
|
-
export
|
|
24
|
-
// W3C
|
|
25
|
-
JSONLD = 'json-ld',
|
|
26
|
-
JWT_ENCODED = 'jwt-encoded',
|
|
27
|
-
JWT_DECODED = 'jwt-decoded',
|
|
28
|
-
|
|
29
|
-
// SD-JWT
|
|
30
|
-
SD_JWT_VC_ENCODED = 'sd-jwt-vc-encoded',
|
|
31
|
-
SD_JWT_VC_DECODED = 'sd-jwt-vc-decoded',
|
|
32
|
-
|
|
33
|
-
// MSO MDOCS
|
|
34
|
-
MSO_MDOC_ENCODED = 'mso_mdoc-encoded',
|
|
35
|
-
MSO_MDOC_DECODED = 'mso_mdoc-decoded',
|
|
36
|
-
}
|
|
23
|
+
export type CredentialProofFormat = 'jwt' | 'lds' | 'vc+jwt' /*| 'EthereumEip712Signature2021'*/ | 'cbor'
|
|
37
24
|
|
|
38
25
|
export type CredentialFormat =
|
|
39
26
|
// W3C
|
|
40
27
|
| 'jwt_vc'
|
|
41
28
|
| 'ldp_vc'
|
|
29
|
+
| 'vc+jwt'
|
|
42
30
|
// SD-JWT
|
|
43
31
|
| 'vc+sd-jwt'
|
|
44
32
|
// Remaining
|
|
@@ -51,8 +39,9 @@ export type PresentationFormat =
|
|
|
51
39
|
// W3C
|
|
52
40
|
| 'jwt_vp'
|
|
53
41
|
| 'ldp_vp'
|
|
42
|
+
| 'vp+jwt'
|
|
54
43
|
// SD-JWT
|
|
55
|
-
| '
|
|
44
|
+
| 'vp+sd-jwt'
|
|
56
45
|
// Remaining
|
|
57
46
|
| 'jwt'
|
|
58
47
|
| 'ldp'
|
|
@@ -74,14 +63,3 @@ export type OriginalVerifiablePresentation =
|
|
|
74
63
|
| MdocOid4vpMdocVpToken
|
|
75
64
|
| MdocDeviceResponse
|
|
76
65
|
export type Original = OriginalVerifiablePresentation | OriginalVerifiableCredential
|
|
77
|
-
|
|
78
|
-
export const enum DocumentFormat {
|
|
79
|
-
// W3C
|
|
80
|
-
JWT,
|
|
81
|
-
JSONLD,
|
|
82
|
-
// SD-JWT
|
|
83
|
-
SD_JWT_VC,
|
|
84
|
-
// Remaining
|
|
85
|
-
EIP712,
|
|
86
|
-
MSO_MDOC,
|
|
87
|
-
}
|
package/src/types/w3c-vc.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { type PresentationSubmission } from './pex'
|
|
2
|
+
import { OriginalType } from '../mapper'
|
|
3
|
+
import { IProofPurpose, IProofType } from '../utils'
|
|
4
4
|
|
|
5
5
|
export type AdditionalClaims = Record<string, any>
|
|
6
6
|
|
|
@@ -195,8 +195,6 @@ export interface JwtDecodedVerifiablePresentation {
|
|
|
195
195
|
[x: string]: any
|
|
196
196
|
}
|
|
197
197
|
|
|
198
|
-
export const JWT_PROOF_TYPE_2020 = 'JwtProof2020'
|
|
199
|
-
|
|
200
198
|
export interface IVerifyStatusResult {
|
|
201
199
|
verified: boolean
|
|
202
200
|
/**
|
|
@@ -284,25 +282,4 @@ export enum StatusListType {
|
|
|
284
282
|
|
|
285
283
|
export type StatusPurpose2021 = 'revocation' | 'suspension' | string
|
|
286
284
|
|
|
287
|
-
export enum StatusListCredentialIdMode {
|
|
288
|
-
ISSUANCE = 'ISSUANCE',
|
|
289
|
-
// PERSISTENCE = 'PERSISTENCE',
|
|
290
|
-
NEVER = 'NEVER',
|
|
291
|
-
}
|
|
292
|
-
|
|
293
285
|
export type StatusListIndexingDirection = 'rightToLeft'
|
|
294
|
-
|
|
295
|
-
export enum StatusListDriverType {
|
|
296
|
-
AGENT_TYPEORM = 'agent_typeorm',
|
|
297
|
-
/* AGENT_KV_STORE = 'agent_kv_store',
|
|
298
|
-
GITHUB = 'github',
|
|
299
|
-
AGENT_FILESYSTEM = 'agent_filesystem',*/
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
export function isWrappedW3CVerifiableCredential(vc: WrappedVerifiableCredential): vc is WrappedW3CVerifiableCredential {
|
|
303
|
-
return vc.format === 'jwt_vc' || vc.format === 'ldp_vc'
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
export function isWrappedW3CVerifiablePresentation(vp: WrappedVerifiablePresentation): vp is WrappedW3CVerifiablePresentation {
|
|
307
|
-
return vp.format === 'jwt_vp' || vp.format === 'ldp_vp'
|
|
308
|
-
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export enum ICoseKeyType {
|
|
2
|
+
OKP = 1,
|
|
3
|
+
EC2 = 2,
|
|
4
|
+
RSA = 3,
|
|
5
|
+
Symmetric = 4,
|
|
6
|
+
Reserved = 0,
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export enum ICoseSignatureAlgorithm {
|
|
10
|
+
ES256 = -7,
|
|
11
|
+
ES256K = -47,
|
|
12
|
+
ES384 = -35,
|
|
13
|
+
ES512 = -36,
|
|
14
|
+
EdDSA = -8,
|
|
15
|
+
HS256_64 = 4,
|
|
16
|
+
HS256 = 5,
|
|
17
|
+
HS384 = 6,
|
|
18
|
+
HS512 = 7,
|
|
19
|
+
PS256 = -37,
|
|
20
|
+
PS384 = -38,
|
|
21
|
+
PS512 = -39,
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export enum ICoseKeyOperation {
|
|
25
|
+
SIGN = 1,
|
|
26
|
+
VERIFY = 2,
|
|
27
|
+
ENCRYPT = 3,
|
|
28
|
+
DECRYPT = 4,
|
|
29
|
+
WRAP_KEY = 5,
|
|
30
|
+
UNWRAP_KEY = 6,
|
|
31
|
+
DERIVE_KEY = 7,
|
|
32
|
+
DERIVE_BITS = 8,
|
|
33
|
+
MAC_CREATE = 9,
|
|
34
|
+
MAC_VERIFY = 10,
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export enum ICoseCurve {
|
|
38
|
+
P_256 = 1,
|
|
39
|
+
P_384 = 2,
|
|
40
|
+
P_521 = 3,
|
|
41
|
+
X25519 = 4,
|
|
42
|
+
X448 = 5,
|
|
43
|
+
Ed25519 = 6,
|
|
44
|
+
Ed448 = 7,
|
|
45
|
+
secp256k1 = -1,
|
|
46
|
+
}
|
package/src/utils/did.ts
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { IParsedDID } from '../types'
|
|
2
|
+
|
|
3
|
+
export enum IProofPurpose {
|
|
4
|
+
verificationMethod = 'verificationMethod',
|
|
5
|
+
assertionMethod = 'assertionMethod',
|
|
6
|
+
authentication = 'authentication',
|
|
7
|
+
keyAgreement = 'keyAgreement',
|
|
8
|
+
contractAgreement = 'contactAgreement',
|
|
9
|
+
capabilityInvocation = 'capabilityInvocation',
|
|
10
|
+
capabilityDelegation = 'capabilityDelegation',
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export enum IProofType {
|
|
14
|
+
Ed25519Signature2018 = 'Ed25519Signature2018',
|
|
15
|
+
Ed25519Signature2020 = 'Ed25519Signature2020',
|
|
16
|
+
EcdsaSecp256k1Signature2019 = 'EcdsaSecp256k1Signature2019',
|
|
17
|
+
EcdsaSecp256k1RecoverySignature2020 = 'EcdsaSecp256k1RecoverySignature2020',
|
|
18
|
+
JsonWebSignature2020 = 'JsonWebSignature2020',
|
|
19
|
+
RsaSignature2018 = 'RsaSignature2018',
|
|
20
|
+
GpgSignature2020 = 'GpgSignature2020',
|
|
21
|
+
JcsEd25519Signature2020 = 'JcsEd25519Signature2020',
|
|
22
|
+
BbsBlsSignatureProof2020 = 'BbsBlsSignatureProof2020',
|
|
23
|
+
BbsBlsBoundSignatureProof2020 = 'BbsBlsBoundSignatureProof2020',
|
|
24
|
+
JwtProof2020 = 'JwtProof2020',
|
|
25
|
+
SdJwtProof2024 = 'SdJwtProof2024',
|
|
26
|
+
MdocProof2024 = 'MsoMdocProof2024',
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const parseDid = (did: string): IParsedDID => {
|
|
30
|
+
const parsedDid = parse(did)
|
|
31
|
+
if (parsedDid === null) {
|
|
32
|
+
throw new Error('invalid did')
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return parsedDid
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const parse = (didUrl: string): IParsedDID | null => {
|
|
39
|
+
const PCT_ENCODED = '(?:%[0-9a-fA-F]{2})'
|
|
40
|
+
const ID_CHAR = `(?:[a-zA-Z0-9._-]|${PCT_ENCODED})`
|
|
41
|
+
const METHOD = '([a-z0-9]+)'
|
|
42
|
+
const METHOD_ID = `((?:${ID_CHAR}*:)*(${ID_CHAR}+))`
|
|
43
|
+
const PARAM_CHAR = '[a-zA-Z0-9_.:%-]'
|
|
44
|
+
const PARAM = `;${PARAM_CHAR}+=${PARAM_CHAR}*`
|
|
45
|
+
const PARAMS = `((${PARAM})*)`
|
|
46
|
+
const PATH = `(/[^#?]*)?`
|
|
47
|
+
const QUERY = `([?][^#]*)?`
|
|
48
|
+
const FRAGMENT = `(#.*)?`
|
|
49
|
+
const DID_MATCHER = new RegExp(`^did:${METHOD}:${METHOD_ID}${PARAMS}${PATH}${QUERY}${FRAGMENT}$`)
|
|
50
|
+
|
|
51
|
+
if (didUrl === '' || !didUrl) return null
|
|
52
|
+
const sections = didUrl.match(DID_MATCHER)
|
|
53
|
+
if (sections) {
|
|
54
|
+
const parts: IParsedDID = {
|
|
55
|
+
did: `did:${sections[1]}:${sections[2]}`,
|
|
56
|
+
method: sections[1],
|
|
57
|
+
id: sections[2],
|
|
58
|
+
didUrl,
|
|
59
|
+
}
|
|
60
|
+
if (sections[4]) {
|
|
61
|
+
const params = sections[4].slice(1).split(';')
|
|
62
|
+
parts.params = {}
|
|
63
|
+
for (const p of params) {
|
|
64
|
+
const kv = p.split('=')
|
|
65
|
+
parts.params[kv[0]] = kv[1]
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (sections[6]) parts.path = sections[6]
|
|
69
|
+
if (sections[7]) parts.query = sections[7].slice(1)
|
|
70
|
+
if (sections[8]) parts.fragment = sections[8].slice(1)
|
|
71
|
+
return parts
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return null
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Copied from did-resolver, so we have types without external dep
|
|
78
|
+
|
|
79
|
+
// Copyright 2018 Consensys AG
|
|
80
|
+
|
|
81
|
+
// Licensed under the Apache License, Version 2.0(the "License");
|
|
82
|
+
// you may not use this file except in compliance with the License.
|
|
83
|
+
// You may obtain a copy of the License at
|
|
84
|
+
|
|
85
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
86
|
+
|
|
87
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
88
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
89
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
90
|
+
// See the License for the specific language governing permissions and
|
|
91
|
+
// limitations under the License.
|
package/src/utils/hasher.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { sha256, sha384, sha512 } from '@noble/hashes/sha2'
|
|
2
|
+
|
|
3
|
+
// @ts-ignore
|
|
2
4
|
import * as u8a from 'uint8arrays'
|
|
3
|
-
|
|
5
|
+
const { fromString } = u8a
|
|
6
|
+
import type { HasherSync } from '../types'
|
|
4
7
|
|
|
5
8
|
const supportedAlgorithms = ['sha256', 'sha384', 'sha512'] as const
|
|
6
9
|
type SupportedAlgorithms = (typeof supportedAlgorithms)[number]
|
|
@@ -11,7 +14,7 @@ export const shaHasher: HasherSync = (data, algorithm) => {
|
|
|
11
14
|
throw new Error(`Unsupported hashing algorithm ${algorithm}`)
|
|
12
15
|
}
|
|
13
16
|
const hasher = sanitizedAlgorithm === 'sha384' ? sha384 : sanitizedAlgorithm === 'sha512' ? sha512 : sha256
|
|
14
|
-
return hasher(typeof data === 'string' ?
|
|
17
|
+
return hasher(typeof data === 'string' ? fromString(data) : new Uint8Array(data))
|
|
15
18
|
}
|
|
16
19
|
|
|
17
20
|
export const defaultHasher: HasherSync = shaHasher
|
package/src/utils/index.ts
CHANGED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export enum JwkKeyType {
|
|
2
|
+
EC = 'EC',
|
|
3
|
+
RSA = 'RSA',
|
|
4
|
+
oct = 'oct',
|
|
5
|
+
OKP = 'OKP',
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export enum JoseSignatureAlgorithm {
|
|
9
|
+
RS256 = 'RS256',
|
|
10
|
+
RS384 = 'RS384',
|
|
11
|
+
RS512 = 'RS512',
|
|
12
|
+
ES256 = 'ES256',
|
|
13
|
+
ES256K = 'ES256K',
|
|
14
|
+
ES384 = 'ES384',
|
|
15
|
+
ES512 = 'ES512',
|
|
16
|
+
EdDSA = 'EdDSA',
|
|
17
|
+
HS256 = 'HS256',
|
|
18
|
+
HS384 = 'HS384',
|
|
19
|
+
HS512 = 'HS512',
|
|
20
|
+
PS256 = 'PS256',
|
|
21
|
+
PS384 = 'PS384',
|
|
22
|
+
PS512 = 'PS512',
|
|
23
|
+
none = 'none',
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export enum JoseKeyOperation {
|
|
27
|
+
SIGN = 'sign',
|
|
28
|
+
VERIFY = 'verify',
|
|
29
|
+
ENCRYPT = 'encrypt',
|
|
30
|
+
DECRYPT = 'decrypt',
|
|
31
|
+
WRAP_KEY = 'wrapKey',
|
|
32
|
+
UNWRAP_KEY = 'unwrapKey',
|
|
33
|
+
DERIVE_KEY = 'deriveKey',
|
|
34
|
+
DERIVE_BITS = 'deriveBits',
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export enum JoseCurve {
|
|
38
|
+
P_256 = 'P-256',
|
|
39
|
+
P_384 = 'P-384',
|
|
40
|
+
P_521 = 'P-521',
|
|
41
|
+
X25519 = 'X25519',
|
|
42
|
+
X448 = 'X448',
|
|
43
|
+
EdDSA = 'EdDSA',
|
|
44
|
+
Ed25519 = 'Ed25519',
|
|
45
|
+
Ed448 = 'Ed448',
|
|
46
|
+
secp256k1 = 'secp256k1',
|
|
47
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
DocumentJson,
|
|
3
|
+
IssuerSignedItemJson,
|
|
4
|
+
IVerifiableCredential,
|
|
5
|
+
MdocDecodedPayload,
|
|
6
|
+
MdocDeviceResponse,
|
|
7
|
+
MdocDocument,
|
|
8
|
+
MdocIssuerSigned,
|
|
9
|
+
MdocOid4vpIssuerSigned,
|
|
10
|
+
MdocOid4vpMdocVpToken,
|
|
11
|
+
WrappedMdocCredential,
|
|
12
|
+
WrappedMdocPresentation,
|
|
13
|
+
WrappedVerifiableCredential,
|
|
14
|
+
WrappedVerifiablePresentation,
|
|
15
|
+
} from '../types'
|
|
16
|
+
import * as mdoc from '@sphereon/kmp-mdoc-core'
|
|
17
|
+
import { IProofPurpose, IProofType } from './did'
|
|
18
|
+
|
|
19
|
+
export function isWrappedMdocCredential(vc: WrappedVerifiableCredential): vc is WrappedMdocCredential {
|
|
20
|
+
return vc.format === 'mso_mdoc'
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function isWrappedMdocPresentation(vp: WrappedVerifiablePresentation): vp is WrappedMdocPresentation {
|
|
24
|
+
return vp.format === 'mso_mdoc'
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function getMdocDecodedPayload(mdoc: MdocDocument): MdocDecodedPayload {
|
|
28
|
+
const mdocJson = mdoc.toJson()
|
|
29
|
+
if (!mdocJson.issuerSigned.nameSpaces) {
|
|
30
|
+
throw Error(`Cannot access Issuer Signed items from the Mdoc`)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const issuerSignedJson = mdoc.issuerSigned.toJsonDTO()
|
|
34
|
+
const namespaces = issuerSignedJson.nameSpaces as unknown as Record<string, IssuerSignedItemJson[]>
|
|
35
|
+
|
|
36
|
+
const decodedPayload: MdocDecodedPayload = {}
|
|
37
|
+
for (const [namespace, items] of Object.entries(namespaces)) {
|
|
38
|
+
decodedPayload[namespace] = items.reduce(
|
|
39
|
+
(acc, item) => ({
|
|
40
|
+
...acc,
|
|
41
|
+
[item.key]: item.value.value,
|
|
42
|
+
}),
|
|
43
|
+
{},
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return decodedPayload
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Decode an Mdoc from its issuerSigned OID4VP Base64URL (string) to an object containing the disclosures,
|
|
52
|
+
* signed payload, decoded payload
|
|
53
|
+
*
|
|
54
|
+
*/
|
|
55
|
+
export function decodeMdocIssuerSigned(oid4vpIssuerSigned: MdocOid4vpIssuerSigned): MdocDocument {
|
|
56
|
+
// Issuer signed according to 18013-7 in base64url
|
|
57
|
+
const issuerSigned: MdocIssuerSigned = mdoc.com.sphereon.mdoc.data.device.IssuerSignedCbor.Static.cborDecode(
|
|
58
|
+
mdoc.com.sphereon.kmp.decodeFrom(oid4vpIssuerSigned, mdoc.com.sphereon.kmp.Encoding.BASE64URL),
|
|
59
|
+
)
|
|
60
|
+
// Create an mdoc from it. // Validations need to be performed by the caller after this!
|
|
61
|
+
const holderMdoc: MdocDocument = issuerSigned.toDocument()
|
|
62
|
+
return holderMdoc
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function encodeMdocIssuerSigned(issuerSigned: MdocIssuerSigned, encoding: 'base64url' = 'base64url') {
|
|
66
|
+
return mdoc.com.sphereon.kmp.encodeTo(issuerSigned.cborEncode(), mdoc.com.sphereon.kmp.Encoding.BASE64URL)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Decode an Mdoc from its vp_token OID4VP Base64URL (string) to an object containing the disclosures,
|
|
71
|
+
* signed payload, decoded payload
|
|
72
|
+
*
|
|
73
|
+
*/
|
|
74
|
+
export function decodeMdocDeviceResponse(vpToken: MdocOid4vpMdocVpToken): MdocDeviceResponse {
|
|
75
|
+
const deviceResponse = mdoc.com.sphereon.mdoc.data.device.DeviceResponseCbor.Static.cborDecode(
|
|
76
|
+
mdoc.com.sphereon.kmp.decodeFrom(vpToken, mdoc.com.sphereon.kmp.Encoding.BASE64URL),
|
|
77
|
+
)
|
|
78
|
+
return deviceResponse
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// TODO naive implementation of mapping a mdoc onto a IVerifiableCredential. Needs some fixes and further implementation and needs to be moved out of ssi-types
|
|
82
|
+
export const mdocDecodedCredentialToUniformCredential = (
|
|
83
|
+
decoded: MdocDocument,
|
|
84
|
+
// @ts-ignore
|
|
85
|
+
opts?: { maxTimeSkewInMS?: number },
|
|
86
|
+
): IVerifiableCredential => {
|
|
87
|
+
const document = decoded.toJson()
|
|
88
|
+
const json = document.toJsonDTO<DocumentJson>()
|
|
89
|
+
const type = 'Personal Identification Data'
|
|
90
|
+
const MSO = document.MSO
|
|
91
|
+
if (!MSO || !json.issuerSigned?.nameSpaces) {
|
|
92
|
+
throw Error(`Cannot access Mobile Security Object or Issuer Signed items from the Mdoc`)
|
|
93
|
+
}
|
|
94
|
+
const nameSpaces = json.issuerSigned.nameSpaces as unknown as Record<string, IssuerSignedItemJson[]>
|
|
95
|
+
if (!('eu.europa.ec.eudi.pid.1' in nameSpaces)) {
|
|
96
|
+
throw Error(`Only PID supported at present`)
|
|
97
|
+
}
|
|
98
|
+
const items = nameSpaces['eu.europa.ec.eudi.pid.1']
|
|
99
|
+
if (!items || items.length === 0) {
|
|
100
|
+
throw Error(`No issuer signed items were found`)
|
|
101
|
+
}
|
|
102
|
+
type DisclosuresAccumulator = {
|
|
103
|
+
[key: string]: any
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const credentialSubject = items.reduce((acc: DisclosuresAccumulator, item: IssuerSignedItemJson) => {
|
|
107
|
+
if (Array.isArray(item.value)) {
|
|
108
|
+
acc[item.key] = item.value.map((val) => val.value).join(', ')
|
|
109
|
+
} else {
|
|
110
|
+
acc[item.key] = item.value.value
|
|
111
|
+
}
|
|
112
|
+
return acc
|
|
113
|
+
}, {})
|
|
114
|
+
const validFrom = MSO.validityInfo.validFrom
|
|
115
|
+
const validUntil = MSO.validityInfo.validUntil
|
|
116
|
+
const docType = MSO.docType
|
|
117
|
+
const expirationDate = validUntil
|
|
118
|
+
let issuanceDateStr = validFrom
|
|
119
|
+
|
|
120
|
+
const issuanceDate = issuanceDateStr
|
|
121
|
+
if (!issuanceDate) {
|
|
122
|
+
throw Error(`JWT issuance date is required but was not present`)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const credential: Omit<IVerifiableCredential, 'issuer' | 'issuanceDate'> = {
|
|
126
|
+
type: [docType], // Mdoc not a W3C VC, so no VerifiableCredential
|
|
127
|
+
'@context': [], // Mdoc has no JSON-LD by default. Certainly not the VC DM1 default context for JSON-LD
|
|
128
|
+
credentialSubject: {
|
|
129
|
+
type,
|
|
130
|
+
...credentialSubject,
|
|
131
|
+
},
|
|
132
|
+
issuanceDate,
|
|
133
|
+
expirationDate,
|
|
134
|
+
proof: {
|
|
135
|
+
type: IProofType.MdocProof2024,
|
|
136
|
+
created: issuanceDate,
|
|
137
|
+
proofPurpose: IProofPurpose.authentication,
|
|
138
|
+
verificationMethod: json.issuerSigned.issuerAuth.payload,
|
|
139
|
+
mso_mdoc: mdoc.com.sphereon.kmp.encodeTo(decoded.cborEncode(), mdoc.com.sphereon.kmp.Encoding.BASE64URL),
|
|
140
|
+
},
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return credential as IVerifiableCredential
|
|
144
|
+
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { decodeSdJwt, decodeSdJwtSync, getClaims, getClaimsSync } from '@sd-jwt/decode'
|
|
2
|
+
import type {
|
|
3
|
+
CompactSdJwtVc,
|
|
4
|
+
Hasher,
|
|
5
|
+
HasherSync,
|
|
6
|
+
IVerifiableCredential,
|
|
7
|
+
SdJwtDecodedDisclosure,
|
|
8
|
+
SdJwtDecodedVerifiableCredential,
|
|
9
|
+
SdJwtDecodedVerifiableCredentialPayload,
|
|
10
|
+
SdJwtDisclosure,
|
|
11
|
+
SdJwtSignedVerifiableCredentialPayload,
|
|
12
|
+
SdJwtVcKbJwtHeader,
|
|
13
|
+
SdJwtVcKbJwtPayload,
|
|
14
|
+
} from '../types'
|
|
15
|
+
import { IProofPurpose, IProofType } from './did'
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Decode an SD-JWT vc from its compact format (string) to an object containing the disclosures,
|
|
19
|
+
* signed payload, decoded payload and the compact SD-JWT vc.
|
|
20
|
+
*
|
|
21
|
+
* Both the input and output interfaces of this method are defined in `@sphereon/ssi-types`, so
|
|
22
|
+
* this method hides the actual implementation of SD-JWT (which is currently based on @sd-jwt/core)
|
|
23
|
+
*/
|
|
24
|
+
export function decodeSdJwtVc(compactSdJwtVc: CompactSdJwtVc, hasher: HasherSync): SdJwtDecodedVerifiableCredential {
|
|
25
|
+
const { jwt, disclosures, kbJwt } = decodeSdJwtSync(compactSdJwtVc, hasher)
|
|
26
|
+
|
|
27
|
+
const signedPayload = jwt.payload as SdJwtSignedVerifiableCredentialPayload
|
|
28
|
+
const decodedPayload = getClaimsSync(signedPayload, disclosures, hasher)
|
|
29
|
+
const compactKeyBindingJwt = kbJwt ? compactSdJwtVc.split('~').pop() : undefined
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
compactSdJwtVc,
|
|
33
|
+
decodedPayload: decodedPayload as SdJwtDecodedVerifiableCredentialPayload,
|
|
34
|
+
disclosures: disclosures.map((d) => {
|
|
35
|
+
const decoded = d.key ? [d.salt, d.key, d.value] : [d.salt, d.value]
|
|
36
|
+
if (!d._digest) throw new Error('Implementation error: digest not present in disclosure')
|
|
37
|
+
return {
|
|
38
|
+
decoded: decoded as SdJwtDecodedDisclosure,
|
|
39
|
+
digest: d._digest,
|
|
40
|
+
encoded: d.encode(),
|
|
41
|
+
} satisfies SdJwtDisclosure
|
|
42
|
+
}),
|
|
43
|
+
signedPayload: signedPayload as SdJwtSignedVerifiableCredentialPayload,
|
|
44
|
+
...(compactKeyBindingJwt &&
|
|
45
|
+
kbJwt && {
|
|
46
|
+
kbJwt: {
|
|
47
|
+
header: kbJwt.header as SdJwtVcKbJwtHeader,
|
|
48
|
+
compact: compactKeyBindingJwt,
|
|
49
|
+
payload: kbJwt.payload as SdJwtVcKbJwtPayload,
|
|
50
|
+
},
|
|
51
|
+
}),
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Decode an SD-JWT vc from its compact format (string) to an object containing the disclosures,
|
|
57
|
+
* signed payload, decoded payload and the compact SD-JWT vc.
|
|
58
|
+
*
|
|
59
|
+
* Both the input and output interfaces of this method are defined in `@sphereon/ssi-types`, so
|
|
60
|
+
* this method hides the actual implementation of SD-JWT (which is currently based on @sd-jwt/core)
|
|
61
|
+
*/
|
|
62
|
+
export async function decodeSdJwtVcAsync(compactSdJwtVc: CompactSdJwtVc, hasher: Hasher): Promise<SdJwtDecodedVerifiableCredential> {
|
|
63
|
+
const { jwt, disclosures, kbJwt } = await decodeSdJwt(compactSdJwtVc, hasher)
|
|
64
|
+
|
|
65
|
+
const signedPayload = jwt.payload as SdJwtSignedVerifiableCredentialPayload
|
|
66
|
+
const decodedPayload = await getClaims(signedPayload, disclosures, hasher)
|
|
67
|
+
const compactKeyBindingJwt = kbJwt ? compactSdJwtVc.split('~').pop() : undefined
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
compactSdJwtVc,
|
|
71
|
+
decodedPayload: decodedPayload as SdJwtDecodedVerifiableCredentialPayload,
|
|
72
|
+
disclosures: disclosures.map((d) => {
|
|
73
|
+
const decoded = d.key ? [d.salt, d.key, d.value] : [d.salt, d.value]
|
|
74
|
+
if (!d._digest) throw new Error('Implementation error: digest not present in disclosure')
|
|
75
|
+
return {
|
|
76
|
+
decoded: decoded as SdJwtDecodedDisclosure,
|
|
77
|
+
digest: d._digest,
|
|
78
|
+
encoded: d.encode(),
|
|
79
|
+
} satisfies SdJwtDisclosure
|
|
80
|
+
}),
|
|
81
|
+
signedPayload: signedPayload as SdJwtSignedVerifiableCredentialPayload,
|
|
82
|
+
...(compactKeyBindingJwt &&
|
|
83
|
+
kbJwt && {
|
|
84
|
+
kbJwt: {
|
|
85
|
+
header: kbJwt.header as SdJwtVcKbJwtHeader,
|
|
86
|
+
payload: kbJwt.payload as SdJwtVcKbJwtPayload,
|
|
87
|
+
compact: compactKeyBindingJwt,
|
|
88
|
+
},
|
|
89
|
+
}),
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export const sdJwtDecodedCredentialToUniformCredential = (
|
|
94
|
+
decoded: SdJwtDecodedVerifiableCredential,
|
|
95
|
+
opts?: { maxTimeSkewInMS?: number },
|
|
96
|
+
): IVerifiableCredential => {
|
|
97
|
+
const { decodedPayload } = decoded
|
|
98
|
+
const { exp, nbf, iss, iat, vct, cnf, status, sub, jti } = decodedPayload
|
|
99
|
+
|
|
100
|
+
const maxSkewInMS = opts?.maxTimeSkewInMS ?? 1500
|
|
101
|
+
|
|
102
|
+
const expirationDate = jwtDateToISOString({ jwtClaim: exp, claimName: 'exp' })
|
|
103
|
+
let issuanceDateStr = jwtDateToISOString({ jwtClaim: iat, claimName: 'iat' })
|
|
104
|
+
|
|
105
|
+
let nbfDateAsStr: string | undefined
|
|
106
|
+
if (nbf) {
|
|
107
|
+
nbfDateAsStr = jwtDateToISOString({ jwtClaim: nbf, claimName: 'nbf' })
|
|
108
|
+
if (issuanceDateStr && nbfDateAsStr && issuanceDateStr !== nbfDateAsStr) {
|
|
109
|
+
const diff = Math.abs(new Date(nbfDateAsStr).getTime() - new Date(iss).getTime())
|
|
110
|
+
if (!maxSkewInMS || diff > maxSkewInMS) {
|
|
111
|
+
throw Error(`Inconsistent issuance dates between JWT claim (${nbfDateAsStr}) and VC value (${iss})`)
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
issuanceDateStr = nbfDateAsStr
|
|
115
|
+
}
|
|
116
|
+
const issuanceDate = issuanceDateStr
|
|
117
|
+
if (!issuanceDate) {
|
|
118
|
+
throw Error(`JWT issuance date is required but was not present`)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Filter out the fields we don't want in credentialSubject
|
|
122
|
+
const excludedFields = new Set(['vct', 'cnf', 'iss', 'iat', 'exp', 'nbf', 'jti', 'sub'])
|
|
123
|
+
const credentialSubject = Object.entries(decodedPayload).reduce(
|
|
124
|
+
(acc, [key, value]) => {
|
|
125
|
+
if (
|
|
126
|
+
!excludedFields.has(key) &&
|
|
127
|
+
value !== undefined &&
|
|
128
|
+
value !== '' &&
|
|
129
|
+
!(typeof value === 'object' && value !== null && Object.keys(value).length === 0)
|
|
130
|
+
) {
|
|
131
|
+
acc[key] = value
|
|
132
|
+
}
|
|
133
|
+
return acc
|
|
134
|
+
},
|
|
135
|
+
{} as Record<string, any>,
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
const credential: Omit<IVerifiableCredential, 'issuer' | 'issuanceDate'> = {
|
|
139
|
+
type: [vct], // SDJwt is not a W3C VC, so no VerifiableCredential
|
|
140
|
+
'@context': [], // SDJwt has no JSON-LD by default. Certainly not the VC DM1 default context for JSON-LD
|
|
141
|
+
credentialSubject: {
|
|
142
|
+
...credentialSubject,
|
|
143
|
+
id: credentialSubject.id ?? sub ?? jti,
|
|
144
|
+
},
|
|
145
|
+
issuanceDate,
|
|
146
|
+
expirationDate,
|
|
147
|
+
issuer: iss,
|
|
148
|
+
...(cnf && { cnf }),
|
|
149
|
+
...(status && { status }),
|
|
150
|
+
proof: {
|
|
151
|
+
type: IProofType.SdJwtProof2024,
|
|
152
|
+
created: nbfDateAsStr ?? issuanceDate,
|
|
153
|
+
proofPurpose: IProofPurpose.authentication,
|
|
154
|
+
verificationMethod: iss,
|
|
155
|
+
jwt: decoded.compactSdJwtVc,
|
|
156
|
+
},
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return credential as IVerifiableCredential
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const jwtDateToISOString = ({
|
|
163
|
+
jwtClaim,
|
|
164
|
+
claimName,
|
|
165
|
+
isRequired = false,
|
|
166
|
+
}: {
|
|
167
|
+
jwtClaim?: number
|
|
168
|
+
claimName: string
|
|
169
|
+
isRequired?: boolean
|
|
170
|
+
}): string | undefined => {
|
|
171
|
+
if (jwtClaim) {
|
|
172
|
+
const claim = parseInt(jwtClaim.toString())
|
|
173
|
+
// change JWT seconds to millisecond for the date
|
|
174
|
+
return new Date(claim * (claim < 9999999999 ? 1000 : 1)).toISOString().replace(/\.000Z/, 'Z')
|
|
175
|
+
} else if (isRequired) {
|
|
176
|
+
throw Error(`JWT claim ${claimName} is required but was not present`)
|
|
177
|
+
}
|
|
178
|
+
return undefined
|
|
179
|
+
}
|