UNPKG

nstdlib-nightly

Version:

Node.js standard library converted to runtime-agnostic ES modules.

351 lines (309 loc) 10.1 kB
// Source: https://github.com/nodejs/node/blob/65eff1eb/lib/internal/crypto/x509.js import { parseX509, X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT, X509_CHECK_FLAG_NEVER_CHECK_SUBJECT, X509_CHECK_FLAG_NO_WILDCARDS, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS, X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS, X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS, } from "nstdlib/stub/binding/crypto"; import { PublicKeyObject, isKeyObject } from "nstdlib/lib/internal/crypto/keys"; import { customInspectSymbol as kInspect, kEmptyObject, } from "nstdlib/lib/internal/util"; import { validateBoolean, validateObject, validateString, } from "nstdlib/lib/internal/validators"; import { inspect } from "nstdlib/lib/internal/util/inspect"; import { Buffer } from "nstdlib/lib/buffer"; import { isArrayBufferView } from "nstdlib/lib/internal/util/types"; import { codes as __codes__ } from "nstdlib/lib/internal/errors"; import { markTransferMode, kClone, kDeserialize, } from "nstdlib/lib/internal/worker/js_transferable"; import { kHandle } from "nstdlib/lib/internal/crypto/util"; import * as __hoisted__tls_common__ from "nstdlib/lib/_tls_common"; const { ERR_INVALID_ARG_TYPE, ERR_INVALID_ARG_VALUE } = __codes__; let lazyTranslatePeerCertificate; const kInternalState = Symbol("kInternalState"); function isX509Certificate(value) { return value[kInternalState] !== undefined; } function getFlags(options = kEmptyObject) { validateObject(options, "options"); const { subject = "default", // Can be 'default', 'always', or 'never' wildcards = true, partialWildcards = true, multiLabelWildcards = false, singleLabelSubdomains = false, } = { ...options }; let flags = 0; validateString(subject, "options.subject"); validateBoolean(wildcards, "options.wildcards"); validateBoolean(partialWildcards, "options.partialWildcards"); validateBoolean(multiLabelWildcards, "options.multiLabelWildcards"); validateBoolean(singleLabelSubdomains, "options.singleLabelSubdomains"); switch (subject) { case "default": /* Matches OpenSSL's default, no flags. */ break; case "always": flags |= X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT; break; case "never": flags |= X509_CHECK_FLAG_NEVER_CHECK_SUBJECT; break; default: throw new ERR_INVALID_ARG_VALUE("options.subject", subject); } if (!wildcards) flags |= X509_CHECK_FLAG_NO_WILDCARDS; if (!partialWildcards) flags |= X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS; if (multiLabelWildcards) flags |= X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS; if (singleLabelSubdomains) flags |= X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS; return flags; } class InternalX509Certificate { [kInternalState] = new Map(); constructor(handle) { markTransferMode(this, true, false); this[kHandle] = handle; } } class X509Certificate { [kInternalState] = new Map(); constructor(buffer) { if (typeof buffer === "string") buffer = Buffer.from(buffer); if (!isArrayBufferView(buffer)) { throw new ERR_INVALID_ARG_TYPE( "buffer", ["string", "Buffer", "TypedArray", "DataView"], buffer, ); } markTransferMode(this, true, false); this[kHandle] = parseX509(buffer); } [kInspect](depth, options) { if (depth < 0) return this; const opts = { ...options, depth: options.depth == null ? null : options.depth - 1, }; return `X509Certificate ${inspect( { subject: this.subject, subjectAltName: this.subjectAltName, issuer: this.issuer, infoAccess: this.infoAccess, validFrom: this.validFrom, validTo: this.validTo, fingerprint: this.fingerprint, fingerprint256: this.fingerprint256, fingerprint512: this.fingerprint512, keyUsage: this.keyUsage, serialNumber: this.serialNumber, }, opts, )}`; } [kClone]() { const handle = this[kHandle]; return { data: { handle }, deserializeInfo: "internal/crypto/x509:InternalX509Certificate", }; } [kDeserialize]({ handle }) { this[kHandle] = handle; } get subject() { let value = this[kInternalState].get("subject"); if (value === undefined) { value = this[kHandle].subject(); this[kInternalState].set("subject", value); } return value; } get subjectAltName() { let value = this[kInternalState].get("subjectAltName"); if (value === undefined) { value = this[kHandle].subjectAltName(); this[kInternalState].set("subjectAltName", value); } return value; } get issuer() { let value = this[kInternalState].get("issuer"); if (value === undefined) { value = this[kHandle].issuer(); this[kInternalState].set("issuer", value); } return value; } get issuerCertificate() { let value = this[kInternalState].get("issuerCertificate"); if (value === undefined) { const cert = this[kHandle].getIssuerCert(); if (cert) value = new InternalX509Certificate(this[kHandle].getIssuerCert()); this[kInternalState].set("issuerCertificate", value); } return value; } get infoAccess() { let value = this[kInternalState].get("infoAccess"); if (value === undefined) { value = this[kHandle].infoAccess(); this[kInternalState].set("infoAccess", value); } return value; } get validFrom() { let value = this[kInternalState].get("validFrom"); if (value === undefined) { value = this[kHandle].validFrom(); this[kInternalState].set("validFrom", value); } return value; } get validTo() { let value = this[kInternalState].get("validTo"); if (value === undefined) { value = this[kHandle].validTo(); this[kInternalState].set("validTo", value); } return value; } get fingerprint() { let value = this[kInternalState].get("fingerprint"); if (value === undefined) { value = this[kHandle].fingerprint(); this[kInternalState].set("fingerprint", value); } return value; } get fingerprint256() { let value = this[kInternalState].get("fingerprint256"); if (value === undefined) { value = this[kHandle].fingerprint256(); this[kInternalState].set("fingerprint256", value); } return value; } get fingerprint512() { let value = this[kInternalState].get("fingerprint512"); if (value === undefined) { value = this[kHandle].fingerprint512(); this[kInternalState].set("fingerprint512", value); } return value; } get keyUsage() { let value = this[kInternalState].get("keyUsage"); if (value === undefined) { value = this[kHandle].keyUsage(); this[kInternalState].set("keyUsage", value); } return value; } get serialNumber() { let value = this[kInternalState].get("serialNumber"); if (value === undefined) { value = this[kHandle].serialNumber(); this[kInternalState].set("serialNumber", value); } return value; } get raw() { let value = this[kInternalState].get("raw"); if (value === undefined) { value = this[kHandle].raw(); this[kInternalState].set("raw", value); } return value; } get publicKey() { let value = this[kInternalState].get("publicKey"); if (value === undefined) { value = new PublicKeyObject(this[kHandle].publicKey()); this[kInternalState].set("publicKey", value); } return value; } toString() { let value = this[kInternalState].get("pem"); if (value === undefined) { value = this[kHandle].pem(); this[kInternalState].set("pem", value); } return value; } // There's no standardized JSON encoding for X509 certs so we // fallback to providing the PEM encoding as a string. toJSON() { return this.toString(); } get ca() { let value = this[kInternalState].get("ca"); if (value === undefined) { value = this[kHandle].checkCA(); this[kInternalState].set("ca", value); } return value; } checkHost(name, options) { validateString(name, "name"); return this[kHandle].checkHost(name, getFlags(options)); } checkEmail(email, options) { validateString(email, "email"); return this[kHandle].checkEmail(email, getFlags(options)); } checkIP(ip, options) { validateString(ip, "ip"); // The options argument is currently undocumented since none of the options // have any effect on the behavior of this function. However, we still parse // the options argument in case OpenSSL adds flags in the future that do // affect the behavior of X509_check_ip. This ensures that no invalid values // are passed as the second argument in the meantime. return this[kHandle].checkIP(ip, getFlags(options)); } checkIssued(otherCert) { if (!isX509Certificate(otherCert)) throw new ERR_INVALID_ARG_TYPE("otherCert", "X509Certificate", otherCert); return this[kHandle].checkIssued(otherCert[kHandle]); } checkPrivateKey(pkey) { if (!isKeyObject(pkey)) throw new ERR_INVALID_ARG_TYPE("pkey", "KeyObject", pkey); if (pkey.type !== "private") throw new ERR_INVALID_ARG_VALUE("pkey", pkey); return this[kHandle].checkPrivateKey(pkey[kHandle]); } verify(pkey) { if (!isKeyObject(pkey)) throw new ERR_INVALID_ARG_TYPE("pkey", "KeyObject", pkey); if (pkey.type !== "public") throw new ERR_INVALID_ARG_VALUE("pkey", pkey); return this[kHandle].verify(pkey[kHandle]); } toLegacyObject() { // TODO(tniessen): do not depend on translatePeerCertificate here, return // the correct legacy representation from the binding lazyTranslatePeerCertificate ??= __hoisted__tls_common__.translatePeerCertificate; return lazyTranslatePeerCertificate(this[kHandle].toLegacy()); } } InternalX509Certificate.prototype.constructor = X509Certificate; Object.setPrototypeOf( InternalX509Certificate.prototype, X509Certificate.prototype, ); export { X509Certificate }; export { InternalX509Certificate }; export { isX509Certificate };