summaryrefslogtreecommitdiffstats
path: root/third_party/js/PKI.js/src/PKCS8ShroudedKeyBag.ts
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/js/PKI.js/src/PKCS8ShroudedKeyBag.ts')
-rw-r--r--third_party/js/PKI.js/src/PKCS8ShroudedKeyBag.ts248
1 files changed, 248 insertions, 0 deletions
diff --git a/third_party/js/PKI.js/src/PKCS8ShroudedKeyBag.ts b/third_party/js/PKI.js/src/PKCS8ShroudedKeyBag.ts
new file mode 100644
index 0000000000..34458958a9
--- /dev/null
+++ b/third_party/js/PKI.js/src/PKCS8ShroudedKeyBag.ts
@@ -0,0 +1,248 @@
+import * as asn1js from "asn1js";
+import * as pvutils from "pvutils";
+import { AlgorithmIdentifier, AlgorithmIdentifierJson, AlgorithmIdentifierSchema } from "./AlgorithmIdentifier";
+import { EncryptedData, EncryptedDataEncryptParams } from "./EncryptedData";
+import { EncryptedContentInfo } from "./EncryptedContentInfo";
+import { PrivateKeyInfo } from "./PrivateKeyInfo";
+import * as Schema from "./Schema";
+import { AsnError } from "./errors";
+import { PkiObject, PkiObjectParameters } from "./PkiObject";
+import { EMPTY_STRING } from "./constants";
+import * as common from "./common";
+
+const ENCRYPTION_ALGORITHM = "encryptionAlgorithm";
+const ENCRYPTED_DATA = "encryptedData";
+const PARSED_VALUE = "parsedValue";
+const CLEAR_PROPS = [
+ ENCRYPTION_ALGORITHM,
+ ENCRYPTED_DATA,
+];
+
+export interface IPKCS8ShroudedKeyBag {
+ encryptionAlgorithm: AlgorithmIdentifier;
+ encryptedData: asn1js.OctetString;
+ parsedValue?: PrivateKeyInfo;
+}
+
+export type PKCS8ShroudedKeyBagParameters = PkiObjectParameters & Partial<IPKCS8ShroudedKeyBag>;
+
+export interface PKCS8ShroudedKeyBagJson {
+ encryptionAlgorithm: AlgorithmIdentifierJson;
+ encryptedData: asn1js.OctetStringJson;
+}
+
+type PKCS8ShroudedKeyBagMakeInternalValuesParams = Omit<EncryptedDataEncryptParams, "contentToEncrypt">;
+
+/**
+ * Represents the PKCS8ShroudedKeyBag structure described in [RFC7292](https://datatracker.ietf.org/doc/html/rfc7292)
+ */
+export class PKCS8ShroudedKeyBag extends PkiObject implements IPKCS8ShroudedKeyBag {
+
+ public static override CLASS_NAME = "PKCS8ShroudedKeyBag";
+
+ public encryptionAlgorithm!: AlgorithmIdentifier;
+ public encryptedData!: asn1js.OctetString;
+ public parsedValue?: PrivateKeyInfo;
+
+ /**
+ * Initializes a new instance of the {@link PKCS8ShroudedKeyBag} class
+ * @param parameters Initialization parameters
+ */
+ constructor(parameters: PKCS8ShroudedKeyBagParameters = {}) {
+ super();
+
+ this.encryptionAlgorithm = pvutils.getParametersValue(parameters, ENCRYPTION_ALGORITHM, PKCS8ShroudedKeyBag.defaultValues(ENCRYPTION_ALGORITHM));
+ this.encryptedData = pvutils.getParametersValue(parameters, ENCRYPTED_DATA, PKCS8ShroudedKeyBag.defaultValues(ENCRYPTED_DATA));
+ if (PARSED_VALUE in parameters) {
+ this.parsedValue = pvutils.getParametersValue(parameters, PARSED_VALUE, PKCS8ShroudedKeyBag.defaultValues(PARSED_VALUE));
+ }
+
+ 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 ENCRYPTION_ALGORITHM): AlgorithmIdentifier;
+ public static override defaultValues(memberName: typeof ENCRYPTED_DATA): asn1js.OctetString;
+ public static override defaultValues(memberName: typeof PARSED_VALUE): PrivateKeyInfo;
+ public static override defaultValues(memberName: string): any {
+ switch (memberName) {
+ case ENCRYPTION_ALGORITHM:
+ return (new AlgorithmIdentifier());
+ case ENCRYPTED_DATA:
+ return (new asn1js.OctetString());
+ case PARSED_VALUE:
+ 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 ENCRYPTION_ALGORITHM:
+ return ((AlgorithmIdentifier.compareWithDefault("algorithmId", memberValue.algorithmId)) &&
+ (("algorithmParams" in memberValue) === false));
+ case ENCRYPTED_DATA:
+ return (memberValue.isEqual(PKCS8ShroudedKeyBag.defaultValues(memberName)));
+ case PARSED_VALUE:
+ return ((memberValue instanceof Object) && (Object.keys(memberValue).length === 0));
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+
+ /**
+ * @inheritdoc
+ * @asn ASN.1 schema
+ * ```asn
+ * PKCS8ShroudedKeyBag ::= EncryptedPrivateKeyInfo
+ *
+ * EncryptedPrivateKeyInfo ::= SEQUENCE {
+ * encryptionAlgorithm AlgorithmIdentifier {{KeyEncryptionAlgorithms}},
+ * encryptedData EncryptedData
+ * }
+ *
+ * EncryptedData ::= OCTET STRING
+ *```
+ */
+ public static override schema(parameters: Schema.SchemaParameters<{
+ encryptionAlgorithm?: AlgorithmIdentifierSchema;
+ encryptedData?: string;
+ }> = {}): Schema.SchemaType {
+ /**
+ * @type {Object}
+ * @property {string} [blockName]
+ * @property {string} [encryptionAlgorithm]
+ * @property {string} [encryptedData]
+ */
+ const names = pvutils.getParametersValue<NonNullable<typeof parameters.names>>(parameters, "names", {});
+
+ return (new asn1js.Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ AlgorithmIdentifier.schema(names.encryptionAlgorithm || {
+ names: {
+ blockName: ENCRYPTION_ALGORITHM
+ }
+ }),
+ new asn1js.Choice({
+ value: [
+ new asn1js.OctetString({ name: (names.encryptedData || ENCRYPTED_DATA) }),
+ new asn1js.OctetString({
+ idBlock: {
+ isConstructed: true
+ },
+ name: (names.encryptedData || ENCRYPTED_DATA)
+ })
+ ]
+ })
+ ]
+ }));
+ }
+
+ 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,
+ PKCS8ShroudedKeyBag.schema({
+ names: {
+ encryptionAlgorithm: {
+ names: {
+ blockName: ENCRYPTION_ALGORITHM
+ }
+ },
+ encryptedData: ENCRYPTED_DATA
+ }
+ })
+ );
+ AsnError.assertSchema(asn1, this.className);
+
+ // Get internal properties from parsed schema
+ this.encryptionAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.encryptionAlgorithm });
+ this.encryptedData = asn1.result.encryptedData;
+ }
+
+ public toSchema(): asn1js.Sequence {
+ return (new asn1js.Sequence({
+ value: [
+ this.encryptionAlgorithm.toSchema(),
+ this.encryptedData
+ ]
+ }));
+ }
+
+ public toJSON(): PKCS8ShroudedKeyBagJson {
+ return {
+ encryptionAlgorithm: this.encryptionAlgorithm.toJSON(),
+ encryptedData: this.encryptedData.toJSON(),
+ };
+ }
+
+ protected async parseInternalValues(parameters: {
+ password: ArrayBuffer;
+ }, crypto = common.getCrypto(true)) {
+ //#region Initial variables
+ const cmsEncrypted = new EncryptedData({
+ encryptedContentInfo: new EncryptedContentInfo({
+ contentEncryptionAlgorithm: this.encryptionAlgorithm,
+ encryptedContent: this.encryptedData
+ })
+ });
+ //#endregion
+
+ //#region Decrypt internal data
+ const decryptedData = await cmsEncrypted.decrypt(parameters, crypto);
+
+ //#endregion
+
+ //#region Initialize PARSED_VALUE with decrypted PKCS#8 private key
+
+ this.parsedValue = PrivateKeyInfo.fromBER(decryptedData);
+ //#endregion
+ }
+
+ public async makeInternalValues(parameters: PKCS8ShroudedKeyBagMakeInternalValuesParams): Promise<void> {
+ //#region Check that we do have PARSED_VALUE
+ if (!this.parsedValue) {
+ throw new Error("Please initialize \"parsedValue\" first");
+ }
+ //#endregion
+
+ //#region Initial variables
+ const cmsEncrypted = new EncryptedData();
+ //#endregion
+
+ //#region Encrypt internal data
+ const encryptParams: EncryptedDataEncryptParams = {
+ ...parameters,
+ contentToEncrypt: this.parsedValue.toSchema().toBER(false),
+ };
+
+ await cmsEncrypted.encrypt(encryptParams);
+ if (!cmsEncrypted.encryptedContentInfo.encryptedContent) {
+ throw new Error("The filed `encryptedContent` in EncryptedContentInfo is empty");
+ }
+
+ //#endregion
+
+ //#region Initialize internal values
+ this.encryptionAlgorithm = cmsEncrypted.encryptedContentInfo.contentEncryptionAlgorithm;
+ this.encryptedData = cmsEncrypted.encryptedContentInfo.encryptedContent;
+ //#endregion
+ }
+
+}