Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/third_party/js/PKI.js/src/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 16 kB image not shown  

Quelle  CertificationRequest.ts   Sprache: unbekannt

 
import * as asn1js from "asn1js";
import * as pvtsutils from "pvtsutils";
import * as pvutils from "pvutils";
import * as common from "./common";
import { PublicKeyInfo, PublicKeyInfoJson } from "./PublicKeyInfo";
import { RelativeDistinguishedNames, RelativeDistinguishedNamesJson, RelativeDistinguishedNamesSchema } from "./RelativeDistinguishedNames";
import { AlgorithmIdentifier, AlgorithmIdentifierJson } from "./AlgorithmIdentifier";
import { Attribute, AttributeJson, AttributeSchema } from "./Attribute";
import * as Schema from "./Schema";
import { CryptoEnginePublicKeyParams } from "./CryptoEngine/CryptoEngineInterface";
import { AsnError } from "./errors";
import { PkiObject, PkiObjectParameters } from "./PkiObject";
import { EMPTY_BUFFER } from "./constants";

const TBS = "tbs";
const VERSION = "version";
const SUBJECT = "subject";
const SPKI = "subjectPublicKeyInfo";
const ATTRIBUTES = "attributes";
const SIGNATURE_ALGORITHM = "signatureAlgorithm";
const SIGNATURE_VALUE = "signatureValue";
const CSR_INFO = "CertificationRequestInfo";
const CSR_INFO_VERSION = `${CSR_INFO}.version`;
const CSR_INFO_SUBJECT = `${CSR_INFO}.subject`;
const CSR_INFO_SPKI = `${CSR_INFO}.subjectPublicKeyInfo`;
const CSR_INFO_ATTRS = `${CSR_INFO}.attributes`;
const CLEAR_PROPS = [
  CSR_INFO,
  CSR_INFO_VERSION,
  CSR_INFO_SUBJECT,
  CSR_INFO_SPKI,
  CSR_INFO_ATTRS,
  SIGNATURE_ALGORITHM,
  SIGNATURE_VALUE
];

export interface ICertificationRequest {
  /**
   * Value being signed
   */
  tbs: ArrayBuffer;
  /**
   * Version number. It should be 0
   */
  version: number;
  /**
   * Distinguished name of the certificate subject
   */
  subject: RelativeDistinguishedNames;
  /**
   * Information about the public key being certified
   */
  subjectPublicKeyInfo: PublicKeyInfo;
  /**
   * Collection of attributes providing additional information about the subject of the certificate
   */
  attributes?: Attribute[];

  /**
   * signature algorithm (and any associated parameters) under which the certification-request information is signed
   */
  signatureAlgorithm: AlgorithmIdentifier;
  /**
   * result of signing the certification request information with the certification request subject's private key
   */
  signatureValue: asn1js.BitString;
}

/**
 * JSON representation of {@link CertificationRequest}
 */
export interface CertificationRequestJson {
  tbs: string;
  version: number;
  subject: RelativeDistinguishedNamesJson;
  subjectPublicKeyInfo: PublicKeyInfoJson | JsonWebKey;
  attributes?: AttributeJson[];
  signatureAlgorithm: AlgorithmIdentifierJson;
  signatureValue: asn1js.BitStringJson;
}

export interface CertificationRequestInfoParameters {
  names?: {
    blockName?: string;
    CertificationRequestInfo?: string;
    CertificationRequestInfoVersion?: string;
    subject?: RelativeDistinguishedNamesSchema;
    CertificationRequestInfoAttributes?: string;
    attributes?: AttributeSchema;
  };
}

function CertificationRequestInfo(parameters: CertificationRequestInfoParameters = {}) {
  //CertificationRequestInfo ::= SEQUENCE {
  //    version       INTEGER { v1(0) } (v1,...),
  //    subject       Name,
  //    subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }},
  //    attributes    [0] Attributes{{ CRIAttributes }}
  //}

  const names = pvutils.getParametersValue<NonNullable<typeof parameters.names>>(parameters, "names", {});

  return (new asn1js.Sequence({
    name: (names.CertificationRequestInfo || CSR_INFO),
    value: [
      new asn1js.Integer({ name: (names.CertificationRequestInfoVersion || CSR_INFO_VERSION) }),
      RelativeDistinguishedNames.schema(names.subject || {
        names: {
          blockName: CSR_INFO_SUBJECT
        }
      }),
      PublicKeyInfo.schema({
        names: {
          blockName: CSR_INFO_SPKI
        }
      }),
      new asn1js.Constructed({
        optional: true,
        idBlock: {
          tagClass: 3, // CONTEXT-SPECIFIC
          tagNumber: 0 // [0]
        },
        value: [
          new asn1js.Repeated({
            optional: true, // Because OpenSSL makes wrong ATTRIBUTES field
            name: (names.CertificationRequestInfoAttributes || CSR_INFO_ATTRS),
            value: Attribute.schema(names.attributes || {})
          })
        ]
      })
    ]
  }));
}

export type CertificationRequestParameters = PkiObjectParameters & Partial<ICertificationRequest>;

/**
 * Represents the CertificationRequest structure described in [RFC2986](https://datatracker.ietf.org/doc/html/rfc2986)
 *
 * @example The following example demonstrates how to parse PKCS#11 certification request
 * and verify its challenge password extension and signature value
 * ```js
 * const pkcs10 = pkijs.CertificationRequest.fromBER(pkcs10Raw);
 *
 * // Get and validate challenge password extension
 * if (pkcs10.attributes) {
 *   const attrExtensions = pkcs10.attributes.find(o => o.type === "1.2.840.113549.1.9.14"); // pkcs-9-at-extensionRequest
 *   if (attrExtensions) {
 *     const extensions = new pkijs.Extensions({ schema: attrExtensions.values[0] });
 *     for (const extension of extensions.extensions) {
 *       if (extension.extnID === "1.2.840.113549.1.9.7") { // pkcs-9-at-challengePassword
 *         const asn = asn1js.fromBER(extension.extnValue.valueBlock.valueHex);
 *         if (asn.result.valueBlock.value !== "passwordChallenge") {
 *           throw new Error("PKCS#11 certification request is invalid. Challenge password is incorrect");
 *         }
 *       }
 *     }
 *   }
 * }
 *
 * // Verify signature value
 * const ok = await pkcs10.verify();
 * if (!ok) {
 *   throw Error("PKCS#11 certification request is invalid. Signature is wrong")
 * }
 * ```
 *
 * @example The following example demonstrates how to create PKCS#11 certification request
 * ```js
 * // Get a "crypto" extension
 * const crypto = pkijs.getCrypto(true);
 *
 * const pkcs10 = new pkijs.CertificationRequest();
 *
 * pkcs10.subject.typesAndValues.push(new pkijs.AttributeTypeAndValue({
 *   type: "2.5.4.3",
 *   value: new asn1js.Utf8String({ value: "Test" })
 * }));
 *
 *
 * await pkcs10.subjectPublicKeyInfo.importKey(keys.publicKey);
 *
 * pkcs10.attributes = [];
 *
 * // Subject Alternative Name
 * const altNames = new pkijs.GeneralNames({
 *   names: [
 *     new pkijs.GeneralName({ // email
 *       type: 1,
 *       value: "email@address.com"
 *     }),
 *     new pkijs.GeneralName({ // domain
 *       type: 2,
 *       value: "www.domain.com"
 *     }),
 *   ]
 * });
 *
 * // SubjectKeyIdentifier
 * const subjectKeyIdentifier = await crypto.digest({ name: "SHA-1" }, pkcs10.subjectPublicKeyInfo.subjectPublicKey.valueBlock.valueHex);
 *
 * pkcs10.attributes.push(new pkijs.Attribute({
 *   type: "1.2.840.113549.1.9.14", // pkcs-9-at-extensionRequest
 *   values: [(new pkijs.Extensions({
 *     extensions: [
 *       new pkijs.Extension({
 *         extnID: "2.5.29.14", // id-ce-subjectKeyIdentifier
 *         critical: false,
 *         extnValue: (new asn1js.OctetString({ valueHex: subjectKeyIdentifier })).toBER(false)
 *       }),
 *       new pkijs.Extension({
 *         extnID: "2.5.29.17", // id-ce-subjectAltName
 *         critical: false,
 *         extnValue: altNames.toSchema().toBER(false)
 *       }),
 *       new pkijs.Extension({
 *         extnID: "1.2.840.113549.1.9.7", // pkcs-9-at-challengePassword
 *         critical: false,
 *         extnValue: (new asn1js.PrintableString({ value: "passwordChallenge" })).toBER(false)
 *       })
 *     ]
 *   })).toSchema()]
 * }));
 *
 * // Signing final PKCS#10 request
 * await pkcs10.sign(keys.privateKey, "SHA-256");
 *
 * const pkcs10Raw = pkcs10.toSchema(true).toBER();
 * ```
 */
export class CertificationRequest extends PkiObject implements ICertificationRequest {

  public static override CLASS_NAME = "CertificationRequest";

  public tbsView!: Uint8Array;
  /**
   * @deprecated Since version 3.0.0
   */
  public get tbs(): ArrayBuffer {
    return pvtsutils.BufferSourceConverter.toArrayBuffer(this.tbsView);
  }

  /**
   * @deprecated Since version 3.0.0
   */
  public set tbs(value: ArrayBuffer) {
    this.tbsView = new Uint8Array(value);
  }
  public version!: number;
  public subject!: RelativeDistinguishedNames;
  public subjectPublicKeyInfo!: PublicKeyInfo;
  public attributes?: Attribute[];
  public signatureAlgorithm!: AlgorithmIdentifier;
  public signatureValue!: asn1js.BitString;

  /**
   * Initializes a new instance of the {@link CertificationRequest} class
   * @param parameters Initialization parameters
   */
  constructor(parameters: CertificationRequestParameters = {}) {
    super();

    this.tbsView = new Uint8Array(pvutils.getParametersValue(parameters, TBS, CertificationRequest.defaultValues(TBS)));
    this.version = pvutils.getParametersValue(parameters, VERSION, CertificationRequest.defaultValues(VERSION));
    this.subject = pvutils.getParametersValue(parameters, SUBJECT, CertificationRequest.defaultValues(SUBJECT));
    this.subjectPublicKeyInfo = pvutils.getParametersValue(parameters, SPKI, CertificationRequest.defaultValues(SPKI));
    if (ATTRIBUTES in parameters) {
      this.attributes = pvutils.getParametersValue(parameters, ATTRIBUTES, CertificationRequest.defaultValues(ATTRIBUTES));
    }
    this.signatureAlgorithm = pvutils.getParametersValue(parameters, SIGNATURE_ALGORITHM, CertificationRequest.defaultValues(SIGNATURE_ALGORITHM));
    this.signatureValue = pvutils.getParametersValue(parameters, SIGNATURE_VALUE, CertificationRequest.defaultValues(SIGNATURE_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 TBS): ArrayBuffer;
  public static override defaultValues(memberName: typeof VERSION): number;
  public static override defaultValues(memberName: typeof SUBJECT): RelativeDistinguishedNames;
  public static override defaultValues(memberName: typeof SPKI): PublicKeyInfo;
  public static override defaultValues(memberName: typeof ATTRIBUTES): Attribute[];
  public static override defaultValues(memberName: typeof SIGNATURE_ALGORITHM): AlgorithmIdentifier;
  public static override defaultValues(memberName: typeof SIGNATURE_VALUE): asn1js.BitString;
  public static override defaultValues(memberName: string): any {
    switch (memberName) {
      case TBS:
        return EMPTY_BUFFER;
      case VERSION:
        return 0;
      case SUBJECT:
        return new RelativeDistinguishedNames();
      case SPKI:
        return new PublicKeyInfo();
      case ATTRIBUTES:
        return [];
      case SIGNATURE_ALGORITHM:
        return new AlgorithmIdentifier();
      case SIGNATURE_VALUE:
        return new asn1js.BitString();
      default:
        return super.defaultValues(memberName);
    }
  }

  /**
   * @inheritdoc
   * @asn ASN.1 schema
   * ```asn
   * CertificationRequest ::= SEQUENCE {
   *    certificationRequestInfo CertificationRequestInfo,
   *    signatureAlgorithm       AlgorithmIdentifier{{ SignatureAlgorithms }},
   *    signature                BIT STRING
   * }
   *```
   */
  static override schema(parameters: Schema.SchemaParameters<{
    certificationRequestInfo?: CertificationRequestInfoParameters;
    signatureAlgorithm?: string;
    signatureValue?: string;
  }> = {}): Schema.SchemaType {
    const names = pvutils.getParametersValue<NonNullable<typeof parameters.names>>(parameters, "names", {});

    return (new asn1js.Sequence({
      value: [
        CertificationRequestInfo(names.certificationRequestInfo || {}),
        new asn1js.Sequence({
          name: (names.signatureAlgorithm || SIGNATURE_ALGORITHM),
          value: [
            new asn1js.ObjectIdentifier(),
            new asn1js.Any({ optional: true })
          ]
        }),
        new asn1js.BitString({ name: (names.signatureValue || SIGNATURE_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,
      CertificationRequest.schema()
    );
    AsnError.assertSchema(asn1, this.className);

    // Get internal properties from parsed schema
    this.tbsView = (asn1.result.CertificationRequestInfo as asn1js.Sequence).valueBeforeDecodeView;
    this.version = asn1.result[CSR_INFO_VERSION].valueBlock.valueDec;
    this.subject = new RelativeDistinguishedNames({ schema: asn1.result[CSR_INFO_SUBJECT] });
    this.subjectPublicKeyInfo = new PublicKeyInfo({ schema: asn1.result[CSR_INFO_SPKI] });
    if (CSR_INFO_ATTRS in asn1.result) {
      this.attributes = Array.from(asn1.result[CSR_INFO_ATTRS], element => new Attribute({ schema: element }));
    }
    this.signatureAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.signatureAlgorithm });
    this.signatureValue = asn1.result.signatureValue;
  }

  /**
   * Aux function making ASN1js Sequence from current TBS
   * @returns
   */
  protected encodeTBS(): asn1js.Sequence {
    //#region Create array for output sequence
    const outputArray = [
      new asn1js.Integer({ value: this.version }),
      this.subject.toSchema(),
      this.subjectPublicKeyInfo.toSchema()
    ];

    if (ATTRIBUTES in this) {
      outputArray.push(new asn1js.Constructed({
        idBlock: {
          tagClass: 3, // CONTEXT-SPECIFIC
          tagNumber: 0 // [0]
        },
        value: Array.from(this.attributes || [], o => o.toSchema())
      }));
    }
    //#endregion

    return (new asn1js.Sequence({
      value: outputArray
    }));
  }

  public toSchema(encodeFlag = false): asn1js.Sequence {
    let tbsSchema;

    if (encodeFlag === false) {
      if (this.tbsView.byteLength === 0) { // No stored TBS part
        return CertificationRequest.schema();
      }

      const asn1 = asn1js.fromBER(this.tbsView);
      AsnError.assert(asn1, "PKCS#10 Certificate Request");

      tbsSchema = asn1.result;
    } else {
      tbsSchema = this.encodeTBS();
    }

    //#region Construct and return new ASN.1 schema for this object
    return (new asn1js.Sequence({
      value: [
        tbsSchema,
        this.signatureAlgorithm.toSchema(),
        this.signatureValue
      ]
    }));
    //#endregion
  }

  public toJSON(): CertificationRequestJson {
    const object: CertificationRequestJson = {
      tbs: pvtsutils.Convert.ToHex(this.tbsView),
      version: this.version,
      subject: this.subject.toJSON(),
      subjectPublicKeyInfo: this.subjectPublicKeyInfo.toJSON(),
      signatureAlgorithm: this.signatureAlgorithm.toJSON(),
      signatureValue: this.signatureValue.toJSON(),
    };

    if (ATTRIBUTES in this) {
      object.attributes = Array.from(this.attributes || [], o => o.toJSON());
    }

    return object;
  }

  /**
   * Makes signature for current certification request
   * @param privateKey WebCrypto private key
   * @param hashAlgorithm String representing current hashing algorithm
   * @param crypto Crypto engine
   */
  async sign(privateKey: CryptoKey, hashAlgorithm = "SHA-1", crypto = common.getCrypto(true)): Promise<void> {
    // Initial checking
    if (!privateKey) {
      throw new Error("Need to provide a private key for signing");
    }

    //#region Get a "default parameters" for current algorithm and set correct signature algorithm
    const signatureParams = await crypto.getSignatureParameters(privateKey, hashAlgorithm);
    const parameters = signatureParams.parameters;
    this.signatureAlgorithm = signatureParams.signatureAlgorithm;
    //#endregion

    //#region Create TBS data for signing
    this.tbsView = new Uint8Array(this.encodeTBS().toBER());
    //#endregion

    //#region Signing TBS data on provided private key
    const signature = await crypto.signWithPrivateKey(this.tbsView, privateKey, parameters as any);
    this.signatureValue = new asn1js.BitString({ valueHex: signature });
    //#endregion
  }

  /**
   * Verify existing certification request signature
   * @param crypto Crypto engine
   * @returns Returns `true` if signature value is valid, otherwise `false`
   */
  public async verify(crypto = common.getCrypto(true)): Promise<boolean> {
    return crypto.verifyWithPublicKey(this.tbsView, this.signatureValue, this.subjectPublicKeyInfo, this.signatureAlgorithm);
  }

  /**
   * Importing public key for current certificate request
   * @param parameters
   * @param crypto Crypto engine
   * @returns WebCrypt public key
   */
  public async getPublicKey(parameters?: CryptoEnginePublicKeyParams, crypto = common.getCrypto(true)): Promise<CryptoKey> {
    return crypto.getPublicKey(this.subjectPublicKeyInfo, this.signatureAlgorithm, parameters);
  }

}


[ Dauer der Verarbeitung: 0.24 Sekunden  (vorverarbeitet)  ]