@credo-ts/core
Version:
<p align="center"> <br /> <img alt="Credo Logo" src="https://github.com/openwallet-foundation/credo-ts/blob/c7886cb8377ceb8ee4efe8d264211e561a75072d/images/credo-logo.png" height="250px" /> </p> <h1 align="center"><b>Credo - Core</b></h1
175 lines (174 loc) • 8.01 kB
JavaScript
import _classPrivateFieldInitSpec from "../../_virtual/_@oxc-project_runtime@0.151.0/helpers/esm/classPrivateFieldInitSpec.mjs";
import _classPrivateFieldGet2 from "../../_virtual/_@oxc-project_runtime@0.151.0/helpers/esm/classPrivateFieldGet2.mjs";
import _classPrivateFieldSet2 from "../../_virtual/_@oxc-project_runtime@0.151.0/helpers/esm/classPrivateFieldSet2.mjs";
import { isKnownJwaSignatureAlgorithm } from "../kms/jwk/jwa.mjs";
import { PublicJwk } from "../kms/jwk/PublicJwk.mjs";
import "../kms/index.mjs";
import { X509Certificate } from "../x509/X509Certificate.mjs";
import { X509ModuleConfig } from "../x509/X509ModuleConfig.mjs";
import { TrustedIssuerContext } from "../../agent/TrustedIssuerContext.mjs";
import "../vc/models/ClaimFormat.mjs";
import "../vc/index.mjs";
import { getMdocContext } from "../../crypto/contexts/mdocContext.mjs";
import "../x509/index.mjs";
import { MdocError } from "./MdocError.mjs";
import { isMdocSupportedSignatureAlgorithm, mdocSupportedSignatureAlgorithms } from "./mdocSupportedAlgs.mjs";
import { assertMdocStatusListChainsMatchIssuanceChain, convertMdocTrustedCertificates, mdocTrustedCertificatesToRaw } from "./mdocUtil.mjs";
import { DeviceKey, DeviceKeyInfo, Holder, Issuer, IssuerSigned, KeyAuthorizations, SignatureAlgorithm } from "@owf/mdoc";
//#region src/modules/mdoc/Mdoc.ts
var _deviceKeyId = /* @__PURE__ */ new WeakMap();
/**
* This class represents a IssuerSigned Mdoc Document,
* which are the actual credentials being issued to holders.
*/
var Mdoc = class Mdoc {
get base64Url() {
return this.issuerSigned.encodedForOid4Vci;
}
constructor(issuerSigned) {
this.issuerSigned = issuerSigned;
_classPrivateFieldInitSpec(this, _deviceKeyId, void 0);
}
/**
* claim format is convenience method added to all credential instances
*/
get claimFormat() {
return "mso_mdoc";
}
/**
* Encoded is convenience method added to all credential instances
*/
get encoded() {
return this.issuerSigned.encodedForOid4Vci;
}
/**
* Get the device key to which the mdoc is bound
*/
get deviceKey() {
const publicJwk = PublicJwk.fromUnknown(this.issuerSigned.issuerAuth.mobileSecurityObject.deviceKeyInfo.deviceKey.jwk);
if (_classPrivateFieldGet2(_deviceKeyId, this)) publicJwk.keyId = _classPrivateFieldGet2(_deviceKeyId, this);
return publicJwk;
}
set deviceKeyId(keyId) {
_classPrivateFieldSet2(_deviceKeyId, this, keyId);
}
get deviceKeyId() {
const deviceKey = this.deviceKey;
if (deviceKey.hasKeyId) return deviceKey.keyId;
}
static fromBase64Url(mdocBase64Url) {
const issuerSigned = IssuerSigned.fromEncodedForOid4Vci(mdocBase64Url);
return new Mdoc(issuerSigned);
}
get docType() {
return this.issuerSigned.issuerAuth.mobileSecurityObject.docType;
}
get alg() {
const jwaAlg = this.issuerSigned.issuerAuth.jwaAlgorithm;
if (!jwaAlg) throw new MdocError("The IssuerAuth does not have a valid signature algorithm in the header");
if (isKnownJwaSignatureAlgorithm(jwaAlg)) return jwaAlg;
throw new MdocError(`Cannot parse mdoc. The signature algorithm '${jwaAlg}' is not supported.`);
}
get validityInfo() {
const { signed, validFrom, validUntil } = this.issuerSigned.issuerAuth.mobileSecurityObject.validityInfo;
return {
signed,
validFrom,
validUntil
};
}
get issuerSignedCertificateChain() {
return this.issuerSigned.issuerAuth.certificateChain;
}
get signingCertificate() {
return this.issuerSigned.issuerAuth.certificate;
}
get issuerSignedNamespaces() {
if (!this.issuerSigned.issuerNamespaces?.issuerNamespaces) return {};
return Object.fromEntries(Array.from(this.issuerSigned.issuerNamespaces.issuerNamespaces.entries()).map(([namespace, value]) => [namespace, Object.fromEntries(Array.from(value.values()).map((v) => [v.elementIdentifier, v.elementValue]))]));
}
static async sign(agentContext, options) {
const { docType, validityInfo, namespaces, holderKey, issuerCertificate, keyAuthorizations } = options;
const mdocContext = getMdocContext(agentContext);
const issuer = new Issuer(docType, mdocContext);
for (const [namespace, namespaceRecord] of Object.entries(namespaces)) issuer.addIssuerNamespace(namespace, namespaceRecord);
const issuerKey = Array.isArray(issuerCertificate) ? issuerCertificate[0].publicJwk : issuerCertificate.publicJwk;
const alg = issuerKey.supportedSignatureAlgorithms.find(isMdocSupportedSignatureAlgorithm);
if (!alg) throw new MdocError(`Unable to create sign mdoc. No supported signature algorithm found to sign mdoc for jwk with key ${issuerKey.jwkTypeHumanDescription}. Key supports algs ${issuerKey.supportedSignatureAlgorithms.join(", ")}. mdoc supports algs ${mdocSupportedSignatureAlgorithms.join(", ")}`);
const now = /* @__PURE__ */ new Date();
const issuerSigned = await issuer.sign({
digestAlgorithm: "SHA-256",
validityInfo: {
...validityInfo,
signed: validityInfo.signed ?? now,
validFrom: validityInfo.validFrom ?? now
},
algorithm: SignatureAlgorithm[alg],
certificates: Array.isArray(issuerCertificate) ? issuerCertificate.map((c) => c.rawCertificate) : [issuerCertificate.rawCertificate],
deviceKeyInfo: DeviceKeyInfo.create({
deviceKey: DeviceKey.fromJwk(holderKey.toJson()),
keyAuthorizations: keyAuthorizations ? KeyAuthorizations.create({
namespaces: keyAuthorizations.namespaces,
dataElements: keyAuthorizations.dataElements ? new Map(Object.entries(keyAuthorizations.dataElements)) : void 0
}) : void 0
}),
signingKey: issuerKey.toJson(),
status: options.statusInfo ? { statusList: {
idx: options.statusInfo.index,
uri: options.statusInfo.uri,
certificate: options.statusInfo.certificate?.rawCertificate
} } : void 0
});
return new Mdoc(issuerSigned);
}
async verify(agentContext, options) {
const x509ModuleConfig = agentContext.dependencyManager.resolve(X509ModuleConfig);
const certificateChain = this.issuerSigned.issuerAuth.certificateChain.map((certificate) => X509Certificate.fromRawCertificate(certificate));
let trustedCertificates = options?.trustedCertificates;
if (!trustedCertificates) trustedCertificates = (await TrustedIssuerContext.getTrustedIssuersForVerification(agentContext, {
verification: {
type: "credential",
credential: this
},
signer: {
certificateChain,
method: "x509"
}
}))?.trustedIssuers ?? await x509ModuleConfig.getTrustedCertificatesForVerification?.(agentContext, {
verification: {
type: "credential",
credential: this
},
certificateChain
}) ?? x509ModuleConfig.trustedCertificates;
if (!trustedCertificates) throw new MdocError("No trusted certificates found. Cannot verify mdoc.");
const mdocContext = getMdocContext(agentContext, { now: options?.now });
try {
const convertedTrustedCertificates = convertMdocTrustedCertificates(trustedCertificates);
const { trustedIssuanceChain, trustedStatusListChain, trustedIdentifierListChain } = await Holder.verifyIssuerSigned({
trustedCertificates: mdocTrustedCertificatesToRaw(convertedTrustedCertificates),
issuerSigned: this.issuerSigned,
disableCertificateChainValidation: false,
disableStatusValidation: false,
now: options?.now
}, mdocContext);
if (!trustedIssuanceChain) throw new MdocError("Unable to determine a trusted issuance chain");
const issuanceChain = trustedIssuanceChain.map((c) => X509Certificate.fromRawCertificate(c));
if (!(certificateChain.length <= issuanceChain.length && certificateChain.every((cert, i) => cert.equal(issuanceChain[i])))) throw new MdocError("Certificate chain does not match the trusted issuance chain");
assertMdocStatusListChainsMatchIssuanceChain(convertedTrustedCertificates, {
trustedIssuanceChain,
trustedStatusListChain,
trustedIdentifierListChain
});
return { isValid: true };
} catch (error) {
return {
isValid: false,
error: error.message
};
}
}
};
//#endregion
export { Mdoc };
//# sourceMappingURL=Mdoc.mjs.map