UNPKG

xadesjs

Version:

XML Advanced Electronic Signatures (XAdES) implementation in TypeScript/JavaScript built on XMLDSIGjs

296 lines (295 loc) 15.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SignedXml = void 0; const tslib_1 = require("tslib"); const XmlCore = tslib_1.__importStar(require("xml-core")); const XmlDSigJs = tslib_1.__importStar(require("xmldsigjs")); const XAdES = tslib_1.__importStar(require("./xml/index.js")); const XADES_REFERENCE_TYPE = 'http://uri.etsi.org/01903#SignedProperties'; class SignedXml extends XmlDSigJs.SignedXml { get Properties() { return this.properties; } get SignedProperties() { if (!this.Properties) { throw new XmlCore.XmlError(XmlCore.XE.XML_EXCEPTION, 'Properties is empty'); } return this.Properties.SignedProperties; } get UnsignedProperties() { if (!this.Properties) { throw new XmlCore.XmlError(XmlCore.XE.XML_EXCEPTION, 'Properties is empty'); } return this.Properties.UnsignedProperties; } constructor(node) { super(node); this.properties = null; this.CreateQualifyingProperties(); } LoadXml(value) { super.LoadXml(value); let properties = null; this.XmlSignature.ObjectList.Some((item) => { if (item.Element) { for (let i = 0; i < item.Element.childNodes.length; i++) { const node = item.Element.childNodes.item(i); if (node.nodeType === XmlCore.XmlNodeType.Element && node.localName === XAdES.XmlXades.ElementNames.QualifyingProperties) { properties = XAdES.QualifyingProperties.LoadXml(node); return true; } } } return false; }); this.properties = properties; } async Sign(algorithm, key, data, options) { return super.Sign.apply(this, arguments); } CreateQualifyingProperties() { if (this.Properties) { throw new XmlCore.XmlError(XmlCore.XE.XML_EXCEPTION, 'Cannot create QualifyingProperties cause current signature has got one. You must create CounterSignature'); } const rnd = XmlDSigJs.Application.crypto.getRandomValues(new Uint8Array(6)); const id = XmlCore.Convert.ToHex(rnd); this.XmlSignature.Id ||= `id-${id}`; const dataObject = new XAdES.DataObject(); dataObject.QualifyingProperties.Target = `#${this.XmlSignature.Id}`; dataObject.QualifyingProperties.SignedProperties.Id ||= `xades-${this.XmlSignature.Id}`; this.properties = dataObject.QualifyingProperties; this.XmlSignature.ObjectList.Add(dataObject); } async ApplySignOptions(signature, algorithm, key, options) { await super.ApplySignOptions(signature, algorithm, key, options); if (this.Properties) { const sigProps = this.Properties.SignedProperties.SignedSignatureProperties; sigProps.SigningTime.Value = new Date(); if (options.signingTime) { if (options.signingTime.value) { sigProps.SigningTime.Value = options.signingTime.value; } if (options.signingTime.format) { sigProps.SigningTime.Format = options.signingTime.format; } } const signingAlg = XmlCore.assign({}, algorithm, key.algorithm); const xadesRefHash = signingAlg.hash; const xadesRef = new XmlDSigJs.Reference(); xadesRef.Type = XADES_REFERENCE_TYPE; xadesRef.Uri = `#${this.Properties.SignedProperties.Id}`; xadesRef.DigestMethod.Algorithm = XmlDSigJs.CryptoConfig.GetHashAlgorithm(xadesRefHash).namespaceURI; signature.SignedInfo.References.Add(xadesRef); await this.ApplySigningCertificate(options.signingCertificate); await this.ApplySigningCertificateV2(options.signingCertificateV2); await this.ApplySignaturePolicyIdentifier(options.policy); this.ApplySignatureProductionPlace(options.productionPlace); this.ApplySignerRoles(options.signerRole); } } async ApplySigningCertificate(value) { if (this.Properties && value) { const options = typeof value === 'string' ? { certificate: value } : value; if (!options.digestAlgorithm) { options.digestAlgorithm = 'SHA-256'; } const raw = XmlCore.Convert.FromBase64(options.certificate); const cert = new XmlDSigJs.X509Certificate(raw); const ssp = this.Properties.SignedProperties.SignedSignatureProperties; if (ssp.SigningCertificate.Count) { throw new XmlCore.XmlError(XmlCore.XE.XML_EXCEPTION, 'Signature can contain only one SigningCertificate'); } const signingCertificate = new XAdES.Cert(); signingCertificate.IssuerSerial.X509IssuerName = cert.Issuer; signingCertificate.IssuerSerial.X509SerialNumber = cert.SerialNumber; const alg = XmlDSigJs.CryptoConfig.GetHashAlgorithm(options.digestAlgorithm); signingCertificate.CertDigest.DigestMethod.Algorithm = alg.namespaceURI; signingCertificate.CertDigest.DigestValue = new Uint8Array(await cert.Thumbprint(alg.algorithm.name)); this.Properties.SignedProperties.SignedSignatureProperties.SigningCertificate.Add(signingCertificate); } } async ApplySigningCertificateV2(value) { if (this.Properties && value) { const options = typeof value === 'string' ? { certificate: value } : value; if (!options.digestAlgorithm) { options.digestAlgorithm = 'SHA-256'; } const raw = XmlCore.Convert.FromBase64(options.certificate); const cert = new XmlDSigJs.X509Certificate(raw); const ssp = this.Properties.SignedProperties.SignedSignatureProperties; if (ssp.SigningCertificateV2.Count) { throw new XmlCore.XmlError(XmlCore.XE.XML_EXCEPTION, 'Signature can contain only one SigningCertificateV2'); } const signingCertificate = new XAdES.CertV2(); const alg = XmlDSigJs.CryptoConfig.GetHashAlgorithm(options.digestAlgorithm); signingCertificate.CertDigest.DigestMethod.Algorithm = alg.namespaceURI; signingCertificate.CertDigest.DigestValue = new Uint8Array(await cert.Thumbprint(alg.algorithm.name)); this.Properties.SignedProperties.SignedSignatureProperties.SigningCertificateV2.Add(signingCertificate); } } async ApplySignaturePolicyIdentifier(options) { if (this.Properties) { const ssp = this.Properties.SignedProperties.SignedSignatureProperties; if (options && typeof options === 'object') { const policyId = new XAdES.SignaturePolicyId(); policyId.SigPolicyId = new XAdES.SigPolicyId(); policyId.SigPolicyId.Identifier = new XAdES.Identifier(); if (options.identifier.qualifier) { policyId.SigPolicyId.Identifier.Qualifier = options.identifier.qualifier; } policyId.SigPolicyId.Identifier.Value = options.identifier.value; if (options.identifier.description) { policyId.SigPolicyId.Description = options.identifier.description; } if (options.identifier.references) { policyId.SigPolicyId.DocumentationReferences = new XAdES.DocumentationReferences(); options.identifier.references.forEach((referenceValue) => { const reference = new XAdES.DocumentationReference(); reference.Uri = referenceValue; policyId.SigPolicyId.DocumentationReferences.Add(reference); }); } if (options.transforms && options.transforms.length) { policyId.Transforms = new XmlDSigJs.Transforms(); options.transforms.forEach((transform) => { policyId.Transforms.Add(this.ResolveTransform(transform)); }); } policyId.SigPolicyHash = new XAdES.SigPolicyHash(); policyId.SigPolicyHash.DigestMethod = new XmlDSigJs.DigestMethod(); const digestAlgorithm = XmlDSigJs.CryptoConfig.GetHashAlgorithm(options.hash); policyId.SigPolicyHash.DigestMethod.Algorithm = digestAlgorithm.namespaceURI; if (options.digestValue) { policyId.SigPolicyHash.DigestValue = XmlCore.Convert.FromBase64(options.digestValue); } else { const identifierDoc = policyId.SigPolicyId.Identifier.GetXml()?.cloneNode(true); this.CopyNamespaces(identifierDoc, identifierDoc, true); this.InjectNamespaces(this.GetSignatureNamespaces(), identifierDoc, true); let identifierContent = null; if (policyId.Transforms && policyId.Transforms.Count) { identifierContent = this.ApplyTransforms(policyId.Transforms, identifierDoc); } else { const c14n = new XmlDSigJs.XmlDsigC14NTransform(); c14n.LoadInnerXml(identifierDoc); identifierContent = c14n.GetOutput(); } policyId.SigPolicyHash.DigestValue = await digestAlgorithm.Digest(identifierContent); } if (options.qualifiers) { policyId.SigPolicyQualifiers = new XAdES.SigPolicyQualifiers(); options.qualifiers.forEach((qualifierValue) => { const container = new XAdES.SigPolicyQualifier(); if (typeof qualifierValue === 'string') { const qualifier = new XAdES.SPURI(); qualifier.Value = qualifierValue; container.Add(qualifier); } else { const qualifier = new XAdES.SPUserNotice(); if (qualifierValue.explicitText) { qualifier.ExplicitText = qualifierValue.explicitText; } if (qualifierValue.noticeRef) { qualifier.NoticeRef = new XAdES.NoticeReference(); qualifier.NoticeRef.Organization = qualifierValue.noticeRef.organization; qualifier.NoticeRef.NoticeNumbers = new XAdES.IntegerList(); if (qualifierValue.noticeRef.noticeNumbers) { qualifierValue.noticeRef.noticeNumbers.forEach((numberValue) => { const noticeNumber = new XAdES.Integer(); noticeNumber.Value = numberValue; qualifier.NoticeRef.NoticeNumbers.Add(noticeNumber); }); } } container.Add(qualifier); } policyId.SigPolicyQualifiers.Add(container); }); } ssp.SignaturePolicyIdentifier.SignaturePolicyId = policyId; ssp.SignaturePolicyIdentifier.SignaturePolicyImplied = false; } else if (options) { ssp.SignaturePolicyIdentifier.SignaturePolicyImplied = true; } } } ApplySignatureProductionPlace(options) { if (this.Properties && options) { const ssp = this.Properties.SignedProperties.SignedSignatureProperties; if (options.city) { ssp.SignatureProductionPlace.City = options.city; } if (options.code) { ssp.SignatureProductionPlace.PostalCode = options.code; } if (options.country) { ssp.SignatureProductionPlace.CountryName = options.country; } if (options.state) { ssp.SignatureProductionPlace.StateOrProvince = options.state; } } } ApplySignerRoles(options) { if (this.Properties && options) { const ssp = this.Properties.SignedProperties.SignedSignatureProperties; if (options.claimed) { options.claimed.forEach((role) => { const claimedRole = new XAdES.ClaimedRole(); claimedRole.Value = role; ssp.SignerRole.ClaimedRoles.Add(claimedRole); }); } if (options.certified) { options.certified.forEach((role) => { const certifiedRole = new XAdES.CertifiedRole(); certifiedRole.Encoding = 'der'; certifiedRole.Value = XmlCore.Convert.FromBase64(role); ssp.SignerRole.CertifiedRoles.Add(certifiedRole); }); } } } async VerifySigningCertificate() { let x509 = null; if (this.XmlSignature && this.Properties) { const ssp = this.Properties.SignedProperties.SignedSignatureProperties; if (ssp.SigningCertificate.Count !== 1) { throw new XmlCore.XmlError(XmlCore.XE.XML_EXCEPTION, 'Signature has got wrong amount of SigningCertificate, MUST be one'); } const alg = XmlDSigJs.CryptoConfig.GetHashAlgorithm('SHA-256'); const signingCertificate = ssp.SigningCertificate.Item(0); const b64CertDigest = XmlCore.Convert.ToBase64(signingCertificate.CertDigest.DigestValue); const keyInfos = this.XmlSignature.KeyInfo; for (let i = 0; i < keyInfos.Count, !x509; i++) { const item = keyInfos.Item(i); if (item instanceof XmlDSigJs.KeyInfoX509Data) { const certs = item.Certificates; for (let j = 0; j < certs.length, !x509; j++) { const cert = certs[j]; if (!cert) { continue; } const hash = new Uint8Array(await cert.Thumbprint(alg.algorithm)); const b64Hash = XmlCore.Convert.ToBase64(hash); if (b64Hash === b64CertDigest) { x509 = cert; } } } } if (!(x509 && x509.Issuer === signingCertificate.IssuerSerial.X509IssuerName && x509.SerialNumber === signingCertificate.IssuerSerial.X509SerialNumber)) { throw new XmlCore.XmlError(XmlCore.XE.XML_EXCEPTION, 'SigningCertificate not found'); } } return x509; } } exports.SignedXml = SignedXml;