Source code

Revision control

Copy as Markdown

Other Tools

import * as asn1js from "asn1js";
import * as pvutils from "pvutils";
import { CertID, CertIDJson, CertIDSchema } from "./CertID";
import { EMPTY_STRING } from "./constants";
import { AsnError } from "./errors";
import { Extension, ExtensionJson } from "./Extension";
import { Extensions, ExtensionsSchema } from "./Extensions";
import { PkiObject, PkiObjectParameters } from "./PkiObject";
import * as Schema from "./Schema";
const CERT_ID = "certID";
const CERT_STATUS = "certStatus";
const THIS_UPDATE = "thisUpdate";
const NEXT_UPDATE = "nextUpdate";
const SINGLE_EXTENSIONS = "singleExtensions";
const CLEAR_PROPS = [
CERT_ID,
CERT_STATUS,
THIS_UPDATE,
NEXT_UPDATE,
SINGLE_EXTENSIONS,
];
export interface ISingleResponse {
certID: CertID;
certStatus: any;
thisUpdate: Date;
nextUpdate?: Date;
singleExtensions?: Extension[];
}
export type SingleResponseParameters = PkiObjectParameters & Partial<ISingleResponse>;
export type SingleResponseSchema = Schema.SchemaParameters<{
certID?: CertIDSchema;
certStatus?: string;
thisUpdate?: string;
nextUpdate?: string;
singleExtensions?: ExtensionsSchema;
}>;
export interface SingleResponseJson {
certID: CertIDJson;
certStatus: any;
thisUpdate: Date;
nextUpdate?: Date;
singleExtensions?: ExtensionJson[];
}
/**
* Represents an SingleResponse described in [RFC6960](https://datatracker.ietf.org/doc/html/rfc6960)
*/
export class SingleResponse extends PkiObject implements ISingleResponse {
public static override CLASS_NAME = "SingleResponse";
certID!: CertID;
certStatus: any;
thisUpdate!: Date;
nextUpdate?: Date;
singleExtensions?: Extension[];
/**
* Initializes a new instance of the {@link SingleResponse} class
* @param parameters Initialization parameters
*/
constructor(parameters: SingleResponseParameters = {}) {
super();
this.certID = pvutils.getParametersValue(parameters, CERT_ID, SingleResponse.defaultValues(CERT_ID));
this.certStatus = pvutils.getParametersValue(parameters, CERT_STATUS, SingleResponse.defaultValues(CERT_STATUS));
this.thisUpdate = pvutils.getParametersValue(parameters, THIS_UPDATE, SingleResponse.defaultValues(THIS_UPDATE));
if (NEXT_UPDATE in parameters) {
this.nextUpdate = pvutils.getParametersValue(parameters, NEXT_UPDATE, SingleResponse.defaultValues(NEXT_UPDATE));
}
if (SINGLE_EXTENSIONS in parameters) {
this.singleExtensions = pvutils.getParametersValue(parameters, SINGLE_EXTENSIONS, SingleResponse.defaultValues(SINGLE_EXTENSIONS));
}
if (parameters.schema) {
this.fromSchema(parameters.schema);
}
}
/**
* Returns default values for all class members
* @param memberName String name for a class member
* @returns Default value
*/
public static override defaultValues(memberName: typeof CERT_ID): CertID;
public static override defaultValues(memberName: typeof CERT_STATUS): any;
public static override defaultValues(memberName: typeof THIS_UPDATE): Date;
public static override defaultValues(memberName: typeof NEXT_UPDATE): Date;
public static override defaultValues(memberName: typeof SINGLE_EXTENSIONS): Extension[];
public static override defaultValues(memberName: string): any {
switch (memberName) {
case CERT_ID:
return new CertID();
case CERT_STATUS:
return {};
case THIS_UPDATE:
case NEXT_UPDATE:
return new Date(0, 0, 0);
case SINGLE_EXTENSIONS:
return [];
default:
return super.defaultValues(memberName);
}
}
/**
* Compare values with default values for all class members
* @param memberName String name for a class member
* @param memberValue Value to compare with default value
*/
public static compareWithDefault(memberName: string, memberValue: any): boolean {
switch (memberName) {
case CERT_ID:
return ((CertID.compareWithDefault("hashAlgorithm", memberValue.hashAlgorithm)) &&
(CertID.compareWithDefault("issuerNameHash", memberValue.issuerNameHash)) &&
(CertID.compareWithDefault("issuerKeyHash", memberValue.issuerKeyHash)) &&
(CertID.compareWithDefault("serialNumber", memberValue.serialNumber)));
case CERT_STATUS:
return (Object.keys(memberValue).length === 0);
case THIS_UPDATE:
case NEXT_UPDATE:
return (memberValue === SingleResponse.defaultValues(memberName as typeof NEXT_UPDATE));
default:
return super.defaultValues(memberName);
}
}
/**
* @inheritdoc
* @asn ASN.1 schema
* ```asn
* SingleResponse ::= SEQUENCE {
* certID CertID,
* certStatus CertStatus,
* thisUpdate GeneralizedTime,
* nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL,
* singleExtensions [1] EXPLICIT Extensions OPTIONAL }
*
* CertStatus ::= CHOICE {
* good [0] IMPLICIT NULL,
* revoked [1] IMPLICIT RevokedInfo,
* unknown [2] IMPLICIT UnknownInfo }
*
* RevokedInfo ::= SEQUENCE {
* revocationTime GeneralizedTime,
* revocationReason [0] EXPLICIT CRLReason OPTIONAL }
*
* UnknownInfo ::= NULL
*```
*/
public static override schema(parameters: SingleResponseSchema = {}): Schema.SchemaType {
const names = pvutils.getParametersValue<NonNullable<typeof parameters.names>>(parameters, "names", {});
return (new asn1js.Sequence({
name: (names.blockName || EMPTY_STRING),
value: [
CertID.schema(names.certID || {}),
new asn1js.Choice({
value: [
new asn1js.Primitive({
name: (names.certStatus || EMPTY_STRING),
idBlock: {
tagClass: 3, // CONTEXT-SPECIFIC
tagNumber: 0 // [0]
},
}), // IMPLICIT NULL (no "valueBlock")
new asn1js.Constructed({
name: (names.certStatus || EMPTY_STRING),
idBlock: {
tagClass: 3, // CONTEXT-SPECIFIC
tagNumber: 1 // [1]
},
value: [
new asn1js.GeneralizedTime(),
new asn1js.Constructed({
optional: true,
idBlock: {
tagClass: 3, // CONTEXT-SPECIFIC
tagNumber: 0 // [0]
},
value: [new asn1js.Enumerated()]
})
]
}),
new asn1js.Primitive({
name: (names.certStatus || EMPTY_STRING),
idBlock: {
tagClass: 3, // CONTEXT-SPECIFIC
tagNumber: 2 // [2]
},
lenBlock: { length: 1 }
}) // IMPLICIT NULL (no "valueBlock")
]
}),
new asn1js.GeneralizedTime({ name: (names.thisUpdate || EMPTY_STRING) }),
new asn1js.Constructed({
optional: true,
idBlock: {
tagClass: 3, // CONTEXT-SPECIFIC
tagNumber: 0 // [0]
},
value: [new asn1js.GeneralizedTime({ name: (names.nextUpdate || EMPTY_STRING) })]
}),
new asn1js.Constructed({
optional: true,
idBlock: {
tagClass: 3, // CONTEXT-SPECIFIC
tagNumber: 1 // [1]
},
value: [Extensions.schema(names.singleExtensions || {})]
}) // EXPLICIT SEQUENCE value
]
}));
}
public fromSchema(schema: Schema.SchemaType): void {
// Clear input data first
pvutils.clearProps(schema, CLEAR_PROPS);
// Check the schema is valid
const asn1 = asn1js.compareSchema(schema,
schema,
SingleResponse.schema({
names: {
certID: {
names: {
blockName: CERT_ID
}
},
certStatus: CERT_STATUS,
thisUpdate: THIS_UPDATE,
nextUpdate: NEXT_UPDATE,
singleExtensions: {
names: {
blockName:
SINGLE_EXTENSIONS
}
}
}
})
);
AsnError.assertSchema(asn1, this.className);
// Get internal properties from parsed schema
this.certID = new CertID({ schema: asn1.result.certID });
this.certStatus = asn1.result.certStatus;
this.thisUpdate = asn1.result.thisUpdate.toDate();
if (NEXT_UPDATE in asn1.result)
this.nextUpdate = asn1.result.nextUpdate.toDate();
if (SINGLE_EXTENSIONS in asn1.result)
this.singleExtensions = Array.from(asn1.result.singleExtensions.valueBlock.value, element => new Extension({ schema: element }));
}
public toSchema(): asn1js.Sequence {
// Create value array for output sequence
const outputArray = [];
outputArray.push(this.certID.toSchema());
outputArray.push(this.certStatus);
outputArray.push(new asn1js.GeneralizedTime({ valueDate: this.thisUpdate }));
if (this.nextUpdate) {
outputArray.push(new asn1js.Constructed({
idBlock: {
tagClass: 3, // CONTEXT-SPECIFIC
tagNumber: 0 // [0]
},
value: [new asn1js.GeneralizedTime({ valueDate: this.nextUpdate })]
}));
}
if (this.singleExtensions) {
outputArray.push(new asn1js.Sequence({
value: Array.from(this.singleExtensions, o => o.toSchema())
}));
}
return (new asn1js.Sequence({
value: outputArray
}));
}
public toJSON(): SingleResponseJson {
const res: SingleResponseJson = {
certID: this.certID.toJSON(),
certStatus: this.certStatus.toJSON(),
thisUpdate: this.thisUpdate
};
if (this.nextUpdate) {
res.nextUpdate = this.nextUpdate;
}
if (this.singleExtensions) {
res.singleExtensions = Array.from(this.singleExtensions, o => o.toJSON());
}
return res;
}
}