RecipientIdentifier.ts (5525B)
1 import * as asn1js from "asn1js"; 2 import * as pvutils from "pvutils"; 3 import { EMPTY_STRING } from "./constants"; 4 import { AsnError } from "./errors"; 5 import { IssuerAndSerialNumber, IssuerAndSerialNumberJson } from "./IssuerAndSerialNumber"; 6 import { PkiObject, PkiObjectParameters } from "./PkiObject"; 7 import * as Schema from "./Schema"; 8 9 const VARIANT = "variant"; 10 const VALUE = "value"; 11 const CLEAR_PROPS = [ 12 "blockName" 13 ]; 14 15 export interface IRecipientIdentifier { 16 variant: number; 17 value: IssuerAndSerialNumber | asn1js.OctetString; 18 } 19 20 export interface RecipientIdentifierJson { 21 variant: number; 22 value?: IssuerAndSerialNumberJson | asn1js.OctetStringJson; 23 } 24 25 export type RecipientIdentifierParameters = PkiObjectParameters & Partial<IRecipientIdentifier>; 26 27 export type RecipientIdentifierSchema = Schema.SchemaParameters; 28 29 /** 30 * Represents the RecipientIdentifier structure described in [RFC5652](https://datatracker.ietf.org/doc/html/rfc5652) 31 */ 32 export class RecipientIdentifier extends PkiObject implements IRecipientIdentifier { 33 34 public static override CLASS_NAME = "RecipientIdentifier"; 35 36 public variant!: number; 37 public value!: IssuerAndSerialNumber | asn1js.OctetString; 38 39 /** 40 * Initializes a new instance of the {@link RecipientIdentifier} class 41 * @param parameters Initialization parameters 42 */ 43 constructor(parameters: RecipientIdentifierParameters = {}) { 44 super(); 45 46 this.variant = pvutils.getParametersValue(parameters, VARIANT, RecipientIdentifier.defaultValues(VARIANT)); 47 if (VALUE in parameters) { 48 this.value = pvutils.getParametersValue(parameters, VALUE, RecipientIdentifier.defaultValues(VALUE)); 49 } 50 51 if (parameters.schema) { 52 this.fromSchema(parameters.schema); 53 } 54 } 55 56 /** 57 * Returns default values for all class members 58 * @param memberName String name for a class member 59 * @returns Default value 60 */ 61 public static override defaultValues(memberName: typeof VARIANT): number; 62 public static override defaultValues(memberName: typeof VALUE): any; 63 public static override defaultValues(memberName: string): any { 64 switch (memberName) { 65 case VARIANT: 66 return (-1); 67 case VALUE: 68 return {}; 69 default: 70 return super.defaultValues(memberName); 71 } 72 } 73 74 /** 75 * Compare values with default values for all class members 76 * @param memberName String name for a class member 77 * @param memberValue Value to compare with default value 78 */ 79 public static compareWithDefault(memberName: string, memberValue: any): boolean { 80 switch (memberName) { 81 case VARIANT: 82 return (memberValue === (-1)); 83 case VALUE: 84 return (Object.keys(memberValue).length === 0); 85 default: 86 return super.defaultValues(memberName); 87 } 88 } 89 90 /** 91 * @inheritdoc 92 * @asn ASN.1 schema 93 * ```asn 94 * RecipientIdentifier ::= CHOICE { 95 * issuerAndSerialNumber IssuerAndSerialNumber, 96 * subjectKeyIdentifier [0] SubjectKeyIdentifier } 97 * 98 * SubjectKeyIdentifier ::= OCTET STRING 99 *``` 100 */ 101 public static override schema(parameters: RecipientIdentifierSchema = {}): Schema.SchemaType { 102 const names = pvutils.getParametersValue<NonNullable<typeof parameters.names>>(parameters, "names", {}); 103 104 return (new asn1js.Choice({ 105 value: [ 106 IssuerAndSerialNumber.schema({ 107 names: { 108 blockName: (names.blockName || EMPTY_STRING) 109 } 110 }), 111 new asn1js.Primitive({ 112 name: (names.blockName || EMPTY_STRING), 113 idBlock: { 114 tagClass: 3, // CONTEXT-SPECIFIC 115 tagNumber: 0 // [0] 116 } 117 }) 118 ] 119 })); 120 } 121 122 public fromSchema(schema: Schema.SchemaType): void { 123 // Clear input data first 124 pvutils.clearProps(schema, CLEAR_PROPS); 125 126 // Check the schema is valid 127 const asn1 = asn1js.compareSchema(schema, 128 schema, 129 RecipientIdentifier.schema({ 130 names: { 131 blockName: "blockName" 132 } 133 }) 134 ); 135 AsnError.assertSchema(asn1, this.className); 136 137 // Get internal properties from parsed schema 138 if (asn1.result.blockName.idBlock.tagClass === 1) { 139 this.variant = 1; 140 this.value = new IssuerAndSerialNumber({ schema: asn1.result.blockName }); 141 } else { 142 this.variant = 2; 143 this.value = new asn1js.OctetString({ valueHex: asn1.result.blockName.valueBlock.valueHex }); 144 } 145 } 146 147 public toSchema(): asn1js.BaseBlock<any> { 148 // Construct and return new ASN.1 schema for this object 149 switch (this.variant) { 150 case 1: 151 if (!(this.value instanceof IssuerAndSerialNumber)) { 152 throw new Error("Incorrect type of RecipientIdentifier.value. It should be IssuerAndSerialNumber."); 153 } 154 return this.value.toSchema(); 155 case 2: 156 if (!(this.value instanceof asn1js.OctetString)) { 157 throw new Error("Incorrect type of RecipientIdentifier.value. It should be ASN.1 OctetString."); 158 } 159 return new asn1js.Primitive({ 160 idBlock: { 161 tagClass: 3, // CONTEXT-SPECIFIC 162 tagNumber: 0 // [0] 163 }, 164 valueHex: this.value.valueBlock.valueHexView 165 }); 166 default: 167 return new asn1js.Any() as any; 168 } 169 } 170 171 public toJSON(): RecipientIdentifierJson { 172 const res: RecipientIdentifierJson = { 173 variant: this.variant 174 }; 175 176 if ((this.variant === 1 || this.variant === 2) && this.value) { 177 res.value = this.value.toJSON(); 178 } 179 180 return res; 181 } 182 183 }