import * as asn1js from "asn1js"; import * as pvtsutils from "pvtsutils"; import * as pvutils from "pvutils"; import * as common from "./common"; import { AlgorithmIdentifier, AlgorithmIdentifierJson, AlgorithmIdentifierSchema } from "./AlgorithmIdentifier"; import { RelativeDistinguishedNames, RelativeDistinguishedNamesJson, RelativeDistinguishedNamesSchema } from "./RelativeDistinguishedNames"; import { Time, TimeJson, TimeSchema } from "./Time"; import { PublicKeyInfo, PublicKeyInfoJson, PublicKeyInfoSchema } from "./PublicKeyInfo"; import { Extension, ExtensionJson } from "./Extension"; import { Extensions, ExtensionsSchema } from "./Extensions"; import * as Schema from "./Schema"; import { id_BasicConstraints } from "./ObjectIdentifiers"; import { BasicConstraints } from "./BasicConstraints"; import { CryptoEnginePublicKeyParams } from "./CryptoEngine/CryptoEngineInterface"; import { AsnError } from "./errors"; import { PkiObject, PkiObjectParameters } from "./PkiObject"; import { EMPTY_BUFFER, EMPTY_STRING } from "./constants";
function tbsCertificate(parameters: TBSCertificateSchema = {}): Schema.SchemaType { //TBSCertificate ::= SEQUENCE { // version [0] EXPLICIT Version DEFAULT v1, // serialNumber CertificateSerialNumber, // signature AlgorithmIdentifier, // issuer Name, // validity Validity, // subject Name, // subjectPublicKeyInfo SubjectPublicKeyInfo, // issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, // -- If present, version MUST be v2 or v3 // subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, // -- If present, version MUST be v2 or v3 // extensions [3] EXPLICIT Extensions OPTIONAL // -- If present, version MUST be v3 //}
/** *RepresentsanX.509certificatedescribedin[RFC5280Section4](https://datatracker.ietf.org/doc/html/rfc5280#section-4). * *@exampleThefollowingexampledemonstrateshowtoparseX.509Certificate *```js *constasn1=asn1js.fromBER(raw); *if(asn1.offset===-1){ *thrownewError("IncorrectencodedASN.1data"); *} * *constcert=newpkijs.Certificate({schema:asn1.result}); *``` * *@exampleThefollowingexampledemonstrateshowtocreateself-signedcertificate *```js *constcrypto=pkijs.getCrypto(true); * *// Create certificate *constcertificate=newpkijs.Certificate(); *certificate.version=2; *certificate.serialNumber=newasn1js.Integer({value:1}); *certificate.issuer.typesAndValues.push(newpkijs.AttributeTypeAndValue({ *type:"2.5.4.3",// Common name *value:newasn1js.BmpString({value:"Test"}) *})); *certificate.subject.typesAndValues.push(newpkijs.AttributeTypeAndValue({ *type:"2.5.4.3",// Common name *value:newasn1js.BmpString({value:"Test"}) *})); * *certificate.notBefore.value=newDate(); *constnotAfter=newDate(); *notAfter.setUTCFullYear(notAfter.getUTCFullYear()+1); *certificate.notAfter.value=notAfter; * *certificate.extensions=[];// Extensions are not a part of certificate by default, it's an optional array * *// "BasicConstraints" extension *constbasicConstr=newpkijs.BasicConstraints({ *cA:true, *pathLenConstraint:3 *}); *certificate.extensions.push(newpkijs.Extension({ *extnID:"2.5.29.19", *critical:false, *extnValue:basicConstr.toSchema().toBER(false), *parsedValue:basicConstr// Parsed value for well-known extensions *})); * *// "KeyUsage" extension *constbitArray=newArrayBuffer(1); *constbitView=newUint8Array(bitArray); *bitView[0]|=0x02;// Key usage "cRLSign" flag *bitView[0]|=0x04;// Key usage "keyCertSign" flag *constkeyUsage=newasn1js.BitString({valueHex:bitArray}); *certificate.extensions.push(newpkijs.Extension({ *extnID:"2.5.29.15", *critical:false, *extnValue:keyUsage.toBER(false), *parsedValue:keyUsage// Parsed value for well-known extensions *})); * *constalgorithm=pkijs.getAlgorithmParameters("RSASSA-PKCS1-v1_5","generateKey"); *if("hash"inalgorithm.algorithm){ *algorithm.algorithm.hash.name="SHA-256"; *} * *constkeys=awaitcrypto.generateKey(algorithm.algorithm,true,algorithm.usages); * *// Exporting public key into "subjectPublicKeyInfo" value of certificate *awaitcertificate.subjectPublicKeyInfo.importKey(keys.publicKey); * *// Signing final certificate *awaitcertificate.sign(keys.privateKey,"SHA-256"); * *constraw=certificate.toSchema().toBER(); *```
*/
export class Certificate extends PkiObject implements ICertificate {
publicstatic override CLASS_NAME = "Certificate";
public tbsView!: Uint8Array; /** *@deprecatedSinceversion3.0.0
*/ public get tbs(): ArrayBuffer {
return pvtsutils.BufferSourceConverter.toArrayBuffer(this.tbsView);
}
/** *@deprecatedSinceversion3.0.0
*/ public set tbs(value: ArrayBuffer) { this.tbsView = new Uint8Array(value);
}
public version!: number; public serialNumber!: asn1js.Integer; public signature!: AlgorithmIdentifier; public issuer!: RelativeDistinguishedNames; public notBefore!: Time; public notAfter!: Time; public subject!: RelativeDistinguishedNames; public subjectPublicKeyInfo!: PublicKeyInfo; public issuerUniqueID?: ArrayBuffer; public subjectUniqueID?: ArrayBuffer; public extensions?: Extension[]; public signatureAlgorithm!: AlgorithmIdentifier; public signatureValue!: asn1js.BitString;
//#region Get internal properties from parsed schema this.tbsView = (asn1.result.tbsCertificate as asn1js.Sequence).valueBeforeDecodeView;
if (TBS_CERTIFICATE_VERSION in asn1.result) this.version = asn1.result[TBS_CERTIFICATE_VERSION].valueBlock.valueDec; this.serialNumber = asn1.result[TBS_CERTIFICATE_SERIAL_NUMBER]; this.signature = new AlgorithmIdentifier({ schema: asn1.result[TBS_CERTIFICATE_SIGNATURE] }); this.issuer = new RelativeDistinguishedNames({ schema: asn1.result[TBS_CERTIFICATE_ISSUER] }); this.notBefore = new Time({ schema: asn1.result[TBS_CERTIFICATE_NOT_BEFORE] }); this.notAfter = new Time({ schema: asn1.result[TBS_CERTIFICATE_NOT_AFTER] }); this.subject = new RelativeDistinguishedNames({ schema: asn1.result[TBS_CERTIFICATE_SUBJECT] }); this.subjectPublicKeyInfo = new PublicKeyInfo({ schema: asn1.result[TBS_CERTIFICATE_SUBJECT_PUBLIC_KEY] }); if (TBS_CERTIFICATE_ISSUER_UNIQUE_ID in asn1.result) this.issuerUniqueID = asn1.result[TBS_CERTIFICATE_ISSUER_UNIQUE_ID].valueBlock.valueHex; if (TBS_CERTIFICATE_SUBJECT_UNIQUE_ID in asn1.result) this.subjectUniqueID = asn1.result[TBS_CERTIFICATE_SUBJECT_UNIQUE_ID].valueBlock.valueHex; if (TBS_CERTIFICATE_EXTENSIONS in asn1.result) this.extensions = Array.from(asn1.result[TBS_CERTIFICATE_EXTENSIONS], element => new Extension({ schema: element }));
//#region Create and return output sequence
return (new asn1js.Sequence({
value: outputArray
})); //#endregion
}
public toSchema(encodeFlag = false): asn1js.Sequence {
let tbsSchema: asn1js.AsnType;
// Decode stored TBS value if (encodeFlag === false) { if (!this.tbsView.byteLength) { // No stored certificate TBS part
return Certificate.schema().value[0];
}
tbsSchema = asn1.result;
} else { // Create TBS schema via assembling from TBS parts
tbsSchema = this.encodeTBS();
}
// Construct and return new ASN.1 schema for this object
return (new asn1js.Sequence({
value: [
tbsSchema, this.signatureAlgorithm.toSchema(), this.signatureValue
]
}));
}
/** *MakeasignatureforcurrentvaluefromTBSsection *@paramprivateKeyPrivatekeyforSUBJECT_PUBLIC_KEY_INFOstructure *@paramhashAlgorithmHashingalgorithm *@paramcryptoCryptoengine
*/ public async sign(privateKey: CryptoKey, hashAlgorithm = "SHA-1", crypto = common.getCrypto(true)): Promise<void> { // Initial checking if (!privateKey) { thrownew Error("Need to provide a private key for signing");
}
// Get a "default parameters" for current algorithm and set correct signature algorithm const signatureParameters = await crypto.getSignatureParameters(privateKey, hashAlgorithm); const parameters = signatureParameters.parameters; this.signature = signatureParameters.signatureAlgorithm; this.signatureAlgorithm = signatureParameters.signatureAlgorithm;
// Create TBS data for signing this.tbsView = new Uint8Array(this.encodeTBS().toBER());
// Signing TBS data on provided private key // TODO remove any const signature = await crypto.signWithPrivateKey(this.tbsView as BufferSource, privateKey, parameters as any); this.signatureValue = new asn1js.BitString({ valueHex: signature });
}
/** *Verifiesthecertificatesignature *@paramissuerCertificate *@paramcryptoCryptoengine
*/ public async verify(issuerCertificate?: Certificate, crypto = common.getCrypto(true)): Promise<boolean> {
let subjectPublicKeyInfo: PublicKeyInfo | undefined;
// Set correct SUBJECT_PUBLIC_KEY_INFO value if (issuerCertificate) {
subjectPublicKeyInfo = issuerCertificate.subjectPublicKeyInfo;
} elseif (this.issuer.isEqual(this.subject)) { // Self-signed certificate
subjectPublicKeyInfo = this.subjectPublicKeyInfo;
}
if (!(subjectPublicKeyInfo instanceof PublicKeyInfo)) { thrownew Error("Please provide issuer certificate as a parameter");
}
return crypto.verifyWithPublicKey(this.tbsView as BufferSource, this.signatureValue, subjectPublicKeyInfo, this.signatureAlgorithm);
}
}
/** *CheckCAflagforthecertificate *@paramcertCertificatetofindCAflagfor *@returnsReturns{@linkCertificate}if`cert`isCAcertificateotherwisereturn`null`
*/
export function checkCA(cert: Certificate, signerCert: Certificate | null = null): Certificate | null { //#region Do not include signer's certificate if (signerCert && cert.issuer.isEqual(signerCert.issuer) && cert.serialNumber.isEqual(signerCert.serialNumber)) {
return null;
} //#endregion
let isCA = false;
if (cert.extensions) { for (const extension of cert.extensions) { if (extension.extnID === id_BasicConstraints && extension.parsedValue instanceof BasicConstraints) { if (extension.parsedValue.cA) {
isCA = true; break;
}
}
}
}
if (isCA) {
return cert;
}
return null;
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.34 Sekunden
(vorverarbeitet am 2026-08-28)
¤
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.