-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: F-Node-Karlsruhe <christian.fries@eecc.de>
- Loading branch information
1 parent
453e7c0
commit 9915eab
Showing
7 changed files
with
559 additions
and
401 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,98 +1,108 @@ | ||
import { NextFunction, Request, response, Response } from 'express'; | ||
import { StatusCodes } from 'http-status-codes'; | ||
import { NextFunction, Request, response, Response } from "express"; | ||
import { StatusCodes } from "http-status-codes"; | ||
|
||
import { Verifier, fetch_json } from '../../services/index.js'; | ||
|
||
const VC_REGISTRY = process.env.VC_REGISTRY ? process.env.VC_REGISTRY : 'https://ssi.eecc.de/api/registry/vcs/'; | ||
import { Verifier, fetch_json } from "../../services/index.js"; | ||
|
||
const VC_REGISTRY = process.env.VC_REGISTRY | ||
? process.env.VC_REGISTRY | ||
: "https://ssi.eecc.de/api/registry/vcs/"; | ||
|
||
export class VerifyRoutes { | ||
|
||
fetchAndVerify = async (req: Request, res: Response, next: NextFunction): Promise<any> => { | ||
|
||
try { | ||
|
||
// fetch credential | ||
let credential; | ||
|
||
try { | ||
|
||
credential = await fetch_json(decodeURIComponent(req.params.vcid)) as Verifiable; | ||
|
||
} catch (error) { | ||
console.log(error) | ||
return res.status(StatusCodes.NOT_FOUND).send('Credential not found!\n' + error); | ||
} | ||
|
||
const result = await Verifier.verify(credential); | ||
|
||
return res.status(StatusCodes.OK).json(result); | ||
|
||
} catch (error) { | ||
return res.status(StatusCodes.BAD_REQUEST).send('Something went wrong!\n' + error); | ||
} | ||
|
||
fetchAndVerify = async ( | ||
req: Request, | ||
res: Response, | ||
next: NextFunction | ||
): Promise<any> => { | ||
try { | ||
// fetch credential | ||
let credential; | ||
|
||
try { | ||
credential = (await fetch_json( | ||
decodeURIComponent(req.params.vcid) | ||
)) as Verifiable; | ||
} catch (error) { | ||
console.log(error); | ||
return res | ||
.status(StatusCodes.NOT_FOUND) | ||
.send("Credential not found!\n" + error); | ||
} | ||
|
||
const result = await Verifier.verify(credential); | ||
|
||
return res.status(StatusCodes.OK).json(result); | ||
} catch (error) { | ||
return res | ||
.status(StatusCodes.BAD_REQUEST) | ||
.send("Something went wrong!\n" + error); | ||
} | ||
|
||
verify = async (req: Request, res: Response, next: NextFunction): Promise<any> => { | ||
|
||
try { | ||
|
||
// Support W3C and JWT namespaces | ||
const challenge = req.query.challenge || req.query.nonce; | ||
const domain = req.query.domain || req.query.audience || req.query.aud; | ||
|
||
if (challenge && typeof challenge != 'string') throw new Error('The challenge/nonce must be provided as a string!'); | ||
|
||
if (domain && typeof domain != 'string') throw new Error('The domain/audience must be provided as a string!'); | ||
|
||
let tasks = Promise.all(req.body.map(function (verifiable: Verifiable) { | ||
|
||
return Verifier.verify(verifiable, challenge, domain); | ||
|
||
})); | ||
|
||
// wait for all verifiables to be verified | ||
const results = await tasks; | ||
|
||
return res.status(StatusCodes.OK).json(results); | ||
|
||
} catch (error) { | ||
return res.status(StatusCodes.BAD_REQUEST).send('Something went wrong verifying!\n' + error); | ||
} | ||
|
||
}; | ||
|
||
verify = async ( | ||
req: Request, | ||
res: Response, | ||
next: NextFunction | ||
): Promise<any> => { | ||
try { | ||
// Support W3C and JWT namespaces | ||
const challenge = req.query.challenge || req.query.nonce; | ||
const domain = req.query.domain || req.query.audience || req.query.aud; | ||
|
||
if (challenge && typeof challenge != "string") | ||
throw new Error("The challenge/nonce must be provided as a string!"); | ||
|
||
if (domain && typeof domain != "string") | ||
throw new Error("The domain/audience must be provided as a string!"); | ||
|
||
let tasks = Promise.all( | ||
req.body.map(function (verifiable: Verifiable) { | ||
return Verifier.verify(verifiable, challenge, domain); | ||
}) | ||
); | ||
|
||
// wait for all verifiables to be verified | ||
const results = await tasks; | ||
|
||
return res.status(StatusCodes.OK).json(results); | ||
} catch (error) { | ||
console.error(error); | ||
return res | ||
.status(StatusCodes.BAD_REQUEST) | ||
.send("Something went wrong verifying!\n" + error); | ||
} | ||
|
||
verifySubjectsVCs = async (req: Request, res: Response, next: NextFunction): Promise<any> => { | ||
|
||
try { | ||
|
||
// fetch credentials | ||
let credentials: Verifiable[]; | ||
|
||
try { | ||
|
||
credentials = await fetch_json(VC_REGISTRY + encodeURIComponent(req.params.subjectId)) as [Verifiable]; | ||
|
||
} catch (error) { | ||
return res.status(StatusCodes.NOT_FOUND); | ||
} | ||
|
||
let tasks = Promise.all(credentials.map(function (vc) { | ||
|
||
return Verifier.verify(vc); | ||
|
||
})); | ||
|
||
// wait for all vcs to be verified | ||
const results = await tasks; | ||
|
||
return res.status(StatusCodes.OK).json(results); | ||
|
||
} catch (error) { | ||
return res.status(StatusCodes.BAD_REQUEST).send('Something went wrong!\n' + error); | ||
} | ||
|
||
}; | ||
|
||
verifySubjectsVCs = async ( | ||
req: Request, | ||
res: Response, | ||
next: NextFunction | ||
): Promise<any> => { | ||
try { | ||
// fetch credentials | ||
let credentials: Verifiable[]; | ||
|
||
try { | ||
credentials = (await fetch_json( | ||
VC_REGISTRY + encodeURIComponent(req.params.subjectId) | ||
)) as [Verifiable]; | ||
} catch (error) { | ||
return res.status(StatusCodes.NOT_FOUND); | ||
} | ||
|
||
let tasks = Promise.all( | ||
credentials.map(function (vc) { | ||
return Verifier.verify(vc); | ||
}) | ||
); | ||
|
||
// wait for all vcs to be verified | ||
const results = await tasks; | ||
|
||
return res.status(StatusCodes.OK).json(results); | ||
} catch (error) { | ||
return res | ||
.status(StatusCodes.BAD_REQUEST) | ||
.send("Something went wrong!\n" + error); | ||
} | ||
|
||
} | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,79 +1,36 @@ | ||
import SD from '@transmute/vc-jwt-sd'; | ||
import moment from 'moment'; | ||
import crypto from "crypto"; | ||
import { base64url, decodeProtectedHeader, decodeJwt } from "jose"; | ||
import { dereferenceDID } from '../documentLoader/index.js'; | ||
|
||
const vcjwtsd = (SD as any).default; | ||
|
||
const digester = (name: 'sha-256' = 'sha-256'): any => { | ||
if (name !== 'sha-256') { | ||
throw new Error('hash function not supported') | ||
} | ||
return { | ||
name, | ||
digest: async (json: string) => { | ||
return base64url.encode(crypto.createHash("sha256").update(json).digest()); | ||
} | ||
}; | ||
import { SDJwtVcInstance } from "@sd-jwt/sd-jwt-vc"; | ||
import type { DisclosureFrame } from "@sd-jwt/types"; | ||
import { ES256, digest, generateSalt } from "@sd-jwt/crypto-nodejs"; | ||
|
||
const createSignerVerifier = async () => { | ||
const { privateKey, publicKey } = await ES256.generateKeyPair(); | ||
return { | ||
signer: await ES256.getSigner(privateKey), | ||
verifier: await ES256.getVerifier(publicKey), | ||
}; | ||
}; | ||
|
||
const { signer, verifier } = await createSignerVerifier(); | ||
|
||
export async function verifySDJWT(verifiable: string, nonce?: string, aud?: string): Promise<VerificationResult> { | ||
|
||
const parsed = vcjwtsd.Parse.compact(verifiable); | ||
|
||
const decodedHeader = decodeProtectedHeader(parsed.jwt) | ||
|
||
const decodedPayload = decodeJwt(parsed.jwt) | ||
|
||
try { | ||
|
||
const alg = decodedHeader.alg; | ||
|
||
if (!alg) throw new Error('No alg specified in the jwt header!'); | ||
|
||
// TODO support urls and plain keys as well | ||
const iss = (decodedHeader.iss || decodedPayload.iss) as string | ||
|
||
const kid = decodedHeader.kid as string | ||
|
||
const absoluteDidUrl = kid && kid.startsWith(iss) ? kid : `${iss}#${kid}` | ||
|
||
let { publicKeyJwk } = (await dereferenceDID(absoluteDidUrl)).document; | ||
|
||
// in case of did:key use jwk from jwt | ||
if (!publicKeyJwk) publicKeyJwk = (decodedPayload.cnf as any).jwk; | ||
|
||
const verifier = new vcjwtsd.Verifier({ | ||
alg, | ||
digester: digester(), | ||
verifier: { | ||
verify: async (token: string) => { | ||
const parsed = vcjwtsd.Parse.compact(token) | ||
const verifier = await vcjwtsd.JWS.verifier(publicKeyJwk) | ||
return verifier.verify(parsed.jwt) | ||
} | ||
} | ||
}) | ||
const verified = await verifier.verify({ | ||
presentation: verifiable, | ||
nonce, | ||
aud | ||
}) | ||
|
||
const now = moment().unix() | ||
|
||
if (now < verified.claimset.iat) throw new Error('Credential is not yet valid!') | ||
if (verified.claimset.exp && now > verified.claimset.exp) throw new Error('Credential expired!') | ||
export async function verifySDJWT( | ||
verifiable: string, | ||
nonce?: string, | ||
aud?: string | ||
): Promise<VerificationResult> { | ||
const sdjwt = new SDJwtVcInstance({ | ||
signer, | ||
verifier, | ||
signAlg: "EdDSA", | ||
hasher: digest, | ||
hashAlg: "SHA-256", | ||
saltGenerator: generateSalt, | ||
}); | ||
|
||
console.log(verified.claimset) | ||
const decodedObject = await sdjwt.decode(verifiable); | ||
|
||
} catch (error: any) { | ||
console.log(error) | ||
return { verified: false, error: error.message }; | ||
} | ||
const verified = await sdjwt.verify(verifiable, []); | ||
|
||
return { verified: true }; | ||
console.log(verified); | ||
|
||
} | ||
return { verified: true }; | ||
} |
Oops, something went wrong.