export class SignedDataVerifyError extends Error implements SignedDataVerifyResult {
public date: Date; public code: number; public signatureVerified: boolean | null; public signerCertificate: Certificate | null; public signerCertificateVerified: boolean | null; public timestampSerial: ArrayBuffer | null; public certificatePath: Certificate[];
public version!: number; public digestAlgorithms!: AlgorithmIdentifier[]; public encapContentInfo!: EncapsulatedContentInfo; public certificates?: CertificateSetItem[]; public crls?: SignedDataCRL[]; public ocsps?: BasicOCSPResponse[]; public signerInfos!: SignerInfo[];
public fromSchema(schema: Schema.SchemaType): void { // Clear input data first
pvutils.clearProps(schema, CLEAR_PROPS);
//#region Check the schema is valid const asn1 = asn1js.compareSchema(schema,
schema,
SignedData.schema()
);
AsnError.assertSchema(asn1, this.className); //#endregion
//#region Get internal properties from parsed schema this.version = asn1.result[SIGNED_DATA_VERSION].valueBlock.valueDec;
if (SIGNED_DATA_DIGEST_ALGORITHMS in asn1.result) // Could be empty SET of digest algorithms this.digestAlgorithms = Array.from(asn1.result[SIGNED_DATA_DIGEST_ALGORITHMS], algorithm => new AlgorithmIdentifier({ schema: algorithm }));
this.encapContentInfo = new EncapsulatedContentInfo({ schema: asn1.result[SIGNED_DATA_ENCAP_CONTENT_INFO] });
if (SIGNED_DATA_CERTIFICATES in asn1.result) { const certificateSet = new CertificateSet({
schema: new asn1js.Set({
value: asn1.result[SIGNED_DATA_CERTIFICATES].valueBlock.value
})
}); this.certificates = certificateSet.certificates.slice(0); // Copy all just for making comfortable access
}
if (SIGNED_DATA_CRLS in asn1.result) { this.crls = Array.from(asn1.result[SIGNED_DATA_CRLS], (crl: Schema.SchemaType) => { if (crl.idBlock.tagClass === 1)
return new CertificateRevocationList({ schema: crl });
return new OtherRevocationInfoFormat({ schema: crl });
});
}
if (SIGNED_DATA_SIGNER_INFOS in asn1.result) // Could be empty SET SignerInfos this.signerInfos = Array.from(asn1.result[SIGNED_DATA_SIGNER_INFOS], signerInfoSchema => new SignerInfo({ schema: signerInfoSchema })); //#endregion
}
public toSchema(encodeFlag = false): Schema.SchemaType { //#region Create array for output sequence const outputArray = [];
// IF ((certificates is present) AND // (any certificates with a type of other are present)) OR // ((crls is present) AND // (any crls with a type of other are present)) // THEN version MUST be 5 // ELSE // IF (certificates is present) AND // (any version 2 attribute certificates are present) // THEN version MUST be 4 // ELSE // IF ((certificates is present) AND // (any version 1 attribute certificates are present)) OR // (any SignerInfo structures are version 3) OR // (encapContentInfo eContentType is other than id-data) // THEN version MUST be 3 // ELSE version MUST be 1 if ((this.certificates && this.certificates.length && this.certificates.some(o => o instanceof OtherCertificateFormat))
|| (this.crls && this.crls.length && this.crls.some(o => o instanceof OtherRevocationInfoFormat))) { this.version = 5;
} elseif (this.certificates && this.certificates.length && this.certificates.some(o => o instanceof AttributeCertificateV2)) { this.version = 4;
} elseif ((this.certificates && this.certificates.length && this.certificates.some(o => o instanceof AttributeCertificateV1))
|| this.signerInfos.some(o => o.version === 3)
|| this.encapContentInfo.eContentType !== SignedData.ID_DATA) { this.version = 3;
} else { this.version = 1;
}
if (this.certificates) {
res.certificates = Array.from(this.certificates, certificate => certificate.toJSON());
}
if (this.crls) {
res.crls = Array.from(this.crls, crl => crl.toJSON());
}
return res;
}
public verify(params?: SignedDataVerifyParams & { extendedMode?: false; }, crypto?: ICryptoEngine): Promise<boolean>; public verify(params: SignedDataVerifyParams & { extendedMode: true; }, crypto?: ICryptoEngine): Promise<SignedDataVerifyResult>; public async verify({
signer = (-1),
data = (EMPTY_BUFFER),
trustedCerts = [],
checkDate = (new Date()),
checkChain = false,
passedWhenNotRevValues = false,
extendedMode = false,
findOrigin = null,
findIssuer = null
}: SignedDataVerifyParams = {}, crypto = common.getCrypto(true)): Promise<boolean | SignedDataVerifyResult> {
let signerCert: Certificate | null = null;
let timestampSerial: ArrayBuffer | null = null; try { //#region Global variables
let messageDigestValue = EMPTY_BUFFER;
let shaAlgorithm = EMPTY_STRING;
let certificatePath: Certificate[] = []; //#endregion
//#region Get a signer number const signerInfo = this.signerInfos[signer]; if (!signerInfo) { thrownew SignedDataVerifyError({
date: checkDate,
code: 1,
message: "Unable to get signer by supplied index",
});
} //#endregion
//#region Check that certificates field was included in signed data if (!this.certificates) { thrownew SignedDataVerifyError({
date: checkDate,
code: 2,
message: "No certificates attached to this signed data",
});
} //#endregion
//#region Find a certificate for specified signer
if (signerInfo.sid instanceof IssuerAndSerialNumber) { for (const certificate of this.certificates) { if (!(certificate instanceof Certificate)) continue;
//#region Check that we do have detached data content if (data.byteLength === 0) { thrownew SignedDataVerifyError({
date: checkDate,
code: 4,
message: "Missed detached data input array",
});
} //#endregion
if (!(await tstInfo.verify({ data }, crypto))) { thrownew SignedDataVerifyError({
date: checkDate,
code: 15,
message: "Error during verification: TSTInfo verification is failed",
signatureVerified: false,
signerCertificate: signerCert,
timestampSerial,
signerCertificateVerified: true
});
}
}
//#region Create correct data block for verification
const eContent = this.encapContentInfo.eContent; if (eContent) // Attached data
{ if ((eContent.idBlock.tagClass === 1) &&
(eContent.idBlock.tagNumber === 4)) {
data = eContent.getValue();
} else
data = eContent.valueBlock.valueBeforeDecodeView.slice().buffer;
} else// Detached data
{ if (data.byteLength === 0) // Check that "data" already provided by function parameter
{ thrownew SignedDataVerifyError({
date: checkDate,
code: 8,
message: "Missed detached data input array",
signerCertificate: signerCert,
signerCertificateVerified: true
});
}
}
if (signerInfo.signedAttrs) { //#region Check mandatory attributes
let foundContentType = false;
let foundMessageDigest = false;
for (const attribute of signerInfo.signedAttrs.attributes) { //#region Check that "content-type" attribute exists if (attribute.type === "1.2.840.113549.1.9.3")
foundContentType = true; //#endregion
//#region Check that "message-digest" attribute exists if (attribute.type === "1.2.840.113549.1.9.4") {
foundMessageDigest = true;
messageDigestValue = attribute.values[0].valueBlock.valueHex;
} //#endregion
//#region Speed-up searching if (foundContentType && foundMessageDigest) break; //#endregion
}
if (foundContentType === false) { thrownew SignedDataVerifyError({
date: checkDate,
code: 9,
message: "Attribute \"content-type\" is a mandatory attribute for \"signed attributes\"",
signerCertificate: signerCert,
signerCertificateVerified: true
});
}
if (foundMessageDigest === false) { thrownew SignedDataVerifyError({
date: checkDate,
code: 10,
message: "Attribute \"message-digest\" is a mandatory attribute for \"signed attributes\"",
signatureVerified: null,
signerCertificate: signerCert,
signerCertificateVerified: true
});
} //#endregion
} //#endregion
//#region Verify "message-digest" attribute in case of "signedAttrs" if (signerInfo.signedAttrs) { const messageDigest = await crypto.digest(shaAlgorithm, new Uint8Array(data)); if (!pvutils.isEqualBuffer(messageDigest, messageDigestValue)) { thrownew SignedDataVerifyError({
date: checkDate,
code: 15,
message: "Error during verification: Message digest doesn't match",
signatureVerified: null,
signerCertificate: signerCert,
timestampSerial,
signerCertificateVerified: true
});
}
data = signerInfo.signedAttrs.encodedValue;
} //#endregion
// This adjustment is specifically for cases where the signature algorithm is rsaEncryption. // In such cases, we rely on the hash mechanism defined in signerInfo.digestAlgorithm for verification. const verifyResult = signerInfo.signatureAlgorithm.algorithmId === "1.2.840.113549.1.1.1"
? await crypto.verifyWithPublicKey(data, signerInfo.signature, signerCert.subjectPublicKeyInfo, signerInfo.signatureAlgorithm, shaAlgorithm)
: await crypto.verifyWithPublicKey(data, signerInfo.signature, signerCert.subjectPublicKeyInfo, signerInfo.signatureAlgorithm);
/** *SigningcurrentSignedData *@paramprivateKeyPrivatekeyfor"subjectPublicKeyInfo"structure *@paramsignerIndexIndexnumber(startingfrom0)ofsignerindextomakesignaturefor *@paramhashAlgorithmHashingalgorithm.DefaultSHA-1 *@paramdataDetacheddata *@paramcryptoCryptoengine
*/ public async sign(privateKey: CryptoKey, signerIndex: number, hashAlgorithm = "SHA-1", data: BufferSource = (EMPTY_BUFFER), crypto = common.getCrypto(true)): Promise<void> { //#region Initial checking if (!privateKey) thrownew Error("Need to provide a private key for signing");
const signerInfo = this.signerInfos[signerIndex]; if (!signerInfo) { thrownew RangeError("SignerInfo index is out of range");
}
//#endregion
//#region Adjust hashAlgorithm based on privateKey if signedAttrs are missing if (!signerInfo.signedAttrs?.attributes.length && "hash" in privateKey.algorithm && "hash" in privateKey.algorithm && privateKey.algorithm.hash) {
hashAlgorithm = (privateKey.algorithm.hash as Algorithm).name;
} const hashAlgorithmOID = crypto.getOIDByAlgorithm({ name: hashAlgorithm }, true, "hashAlgorithm"); //#endregion
//#region Append information about hash algorithm if ((this.digestAlgorithms.filter(algorithm => algorithm.algorithmId === hashAlgorithmOID)).length === 0) { this.digestAlgorithms.push(new AlgorithmIdentifier({
algorithmId: hashAlgorithmOID,
algorithmParams: new asn1js.Null()
}));
}
signerInfo.digestAlgorithm = new AlgorithmIdentifier({
algorithmId: hashAlgorithmOID,
algorithmParams: new asn1js.Null()
}); //#endregion
//#region Get a "default parameters" for current algorithm and set correct signature algorithm const signatureParams = await crypto.getSignatureParameters(privateKey, hashAlgorithm); const parameters = signatureParams.parameters;
signerInfo.signatureAlgorithm = signatureParams.signatureAlgorithm; //#endregion
//#region Create TBS data for signing if (signerInfo.signedAttrs) { if (signerInfo.signedAttrs.encodedValue.byteLength !== 0)
data = signerInfo.signedAttrs.encodedValue; else {
data = signerInfo.signedAttrs.toSchema().toBER();
//#region Change type from "[0]" to "SET" accordingly to standard const view = pvtsutils.BufferSourceConverter.toUint8Array(data);
view[0] = 0x31; //#endregion
}
} else { const eContent = this.encapContentInfo.eContent; if (eContent) // Attached data
{ if ((eContent.idBlock.tagClass === 1) &&
(eContent.idBlock.tagNumber === 4)) {
data = eContent.getValue();
} else
data = eContent.valueBlock.valueBeforeDecodeView.slice().buffer;
} else// Detached data
{ if (data.byteLength === 0) // Check that "data" already provided by function parameter thrownew Error("Missed detached data input array");
}
} //#endregion
//#region Signing TBS data on provided private key const signature = await crypto.signWithPrivateKey(data, privateKey, parameters as any);
signerInfo.signature = new asn1js.OctetString({ valueHex: signature }); //#endregion
}
}
Messung V0.5 in Prozent
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.25Bemerkung:
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.