@sphereon/did-auth-siop
Version:
Self Issued OpenID V2 (SIOPv2) and OpenID 4 Verifiable Presentations (OID4VP)
125 lines • 7.17 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getRequestObjectJwtVerifier = exports.getJwtVerifierWithContext = exports.getJwkVerifier = void 0;
const oid4vc_common_1 = require("@sphereon/oid4vc-common");
const Errors_1 = __importDefault(require("./Errors"));
const getJwkVerifier = (jwt, jwkJwtVerifier) => __awaiter(void 0, void 0, void 0, function* () {
if (jwkJwtVerifier.type !== 'id-token') {
// TODO: check why ts is complaining if we return the jwkJwtVerifier directly
return Object.assign(Object.assign({}, jwkJwtVerifier), { type: jwkJwtVerifier.type });
}
if (typeof jwt.payload.sub_jwk !== 'string') {
throw new Error(`${Errors_1.default.INVALID_JWT} '${jwkJwtVerifier.type}' missing sub_jwk claim.`);
}
const jwkThumbPrintUri = jwt.payload.sub_jwk;
const digestAlgorithm = yield (0, oid4vc_common_1.getDigestAlgorithmFromJwkThumbprintUri)(jwkThumbPrintUri);
const selfComputedJwkThumbPrintUri = yield (0, oid4vc_common_1.calculateJwkThumbprintUri)(jwt.header.jwk, digestAlgorithm);
if (selfComputedJwkThumbPrintUri !== jwkThumbPrintUri) {
throw new Error(`${Errors_1.default.INVALID_JWT} '${jwkJwtVerifier.type}' contains an invalid sub_jwk claim.`);
}
return Object.assign(Object.assign({}, jwkJwtVerifier), { type: jwkJwtVerifier.type, jwkThumbprint: jwt.payload.sub_jwk });
});
exports.getJwkVerifier = getJwkVerifier;
const getJwtVerifierWithContext = (jwt, options) => __awaiter(void 0, void 0, void 0, function* () {
const verifierWithContext = yield (0, oid4vc_common_1.getJwtVerifierWithContext)(jwt, options);
if (verifierWithContext.method === 'jwk') {
return (0, exports.getJwkVerifier)(jwt, verifierWithContext);
}
return verifierWithContext;
});
exports.getJwtVerifierWithContext = getJwtVerifierWithContext;
const getRequestObjectJwtVerifier = (jwt, options) => __awaiter(void 0, void 0, void 0, function* () {
var _a;
const type = 'request-object';
const clientIdScheme = jwt.payload.client_id_scheme;
const clientId = jwt.payload.client_id;
if (!clientIdScheme || jwt.header.alg === 'none') {
return (0, exports.getJwtVerifierWithContext)(jwt, { type });
}
if (clientIdScheme === 'did') {
return (0, oid4vc_common_1.getDidJwtVerifier)(jwt, { type });
}
else if (clientIdScheme === 'pre-registered') {
// All validations must be done manually
// The Verifier metadata is obtained using [RFC7591] or through out-of-band mechanisms.
return (0, exports.getJwtVerifierWithContext)(jwt, { type });
}
else if (clientIdScheme === 'x509_san_dns' || clientIdScheme === 'x509_san_uri') {
return (0, oid4vc_common_1.getX5cVerifier)(jwt, { type });
}
else if (clientIdScheme === 'redirect_uri') {
if (jwt.payload.redirect_uri && jwt.payload.redirect_uri !== clientId) {
throw new Error(Errors_1.default.INVALID_CLIENT_ID_MUST_MATCH_REDIRECT_URI);
}
else if (jwt.payload.response_uri && jwt.payload.response_uri !== clientId) {
throw new Error(Errors_1.default.INVALID_CLIENT_ID_MUST_MATCH_RESPONSE_URI);
}
/*const parts = options.raw.split('.') this can be signed and execution can't even be here when alg = none
if (parts.length > 2 && parts[2]) {
throw new Error(`${SIOPErrors.INVALID_JWT} '${type}' JWT must not be signed`)
}*/
return (0, exports.getJwtVerifierWithContext)(jwt, { type });
}
else if (clientIdScheme === 'verifier_attestation') {
const verifierAttestationSubtype = 'verifier-attestation+jwt';
if (!jwt.header.jwt) {
throw new Error(Errors_1.default.MISSING_ATTESTATION_JWT_WITH_CLIENT_ID_SCHEME_ATTESTATION);
}
// TODO: is this correct? not 100% sure based on the spec
if (jwt.header.typ !== verifierAttestationSubtype) {
throw new Error(Errors_1.default.MISSING_ATTESTATION_JWT_TYP);
}
const attestationJwt = jwt.header.jwt;
const { header: attestationHeader, payload: attestationPayload } = (0, oid4vc_common_1.parseJWT)(attestationJwt);
if (attestationHeader.typ !== verifierAttestationSubtype ||
attestationPayload.sub !== clientId ||
!attestationPayload.iss ||
typeof attestationPayload.iss !== 'string' ||
!attestationPayload.exp ||
typeof attestationPayload.exp !== 'number' ||
typeof attestationPayload.cnf !== 'object' ||
!attestationPayload.cnf ||
!('jwk' in attestationPayload.cnf) ||
typeof attestationPayload.cnf['jwk'] !== 'object') {
throw new Error(Errors_1.default.BAD_VERIFIER_ATTESTATION);
}
if (attestationPayload.redirect_uris) {
if (!Array.isArray(attestationPayload.redirect_uris) ||
attestationPayload.redirect_uris.some((value) => typeof value !== 'string') ||
!jwt.payload.redirect_uri ||
!attestationPayload.redirect_uris.includes(jwt.payload.redirect_uri)) {
throw new Error(Errors_1.default.BAD_VERIFIER_ATTESTATION_REDIRECT_URIS);
}
}
const jwk = attestationPayload.cnf['jwk'];
const alg = (_a = jwk.alg) !== null && _a !== void 0 ? _a : attestationHeader.alg;
if (!alg) {
throw new Error(`${Errors_1.default.INVALID_JWT} '${type}' JWT header is missing alg.`);
}
// The iss claim value of the Verifier Attestation JWT MUST identify a party the Wallet trusts for issuing Verifier Attestation JWTs.
// If the Wallet cannot establish trust, it MUST refuse the request.
return { method: 'jwk', type, jwk: attestationPayload.cnf['jwk'], alg };
}
else if (clientIdScheme === 'entity_id') {
const entityId = jwt.payload.entity_id;
if (!entityId || !entityId.startsWith('https')) {
throw new Error(Errors_1.default.INVALID_REQUEST_OBJECT_ENTITY_ID_SCHEME_CLIENT_ID);
}
return { method: 'openid-federation', type, entityId };
}
throw new Error(Errors_1.default.INVALID_CLIENT_ID_SCHEME);
});
exports.getRequestObjectJwtVerifier = getRequestObjectJwtVerifier;
//# sourceMappingURL=VpJwtVerifier.js.map