123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625 |
- 'use strict';
- Object.defineProperty(exports, "__esModule", { value: true });
- // **Github:** https://github.com/fidm/x509
- //
- // **License:** MIT
- const util_1 = require("util");
- const crypto_1 = require("crypto");
- const tweetnacl_1 = require("tweetnacl");
- const asn1_1 = require("@fidm/asn1");
- const common_1 = require("./common");
- /**
- * ASN.1 Template for PKCS#8 Public Key.
- */
- exports.publicKeyValidator = {
- name: 'PublicKeyInfo',
- class: asn1_1.Class.UNIVERSAL,
- tag: asn1_1.Tag.SEQUENCE,
- capture: 'publicKeyInfo',
- value: [{
- name: 'PublicKeyInfo.AlgorithmIdentifier',
- class: asn1_1.Class.UNIVERSAL,
- tag: asn1_1.Tag.SEQUENCE,
- value: [{
- name: 'PublicKeyAlgorithmIdentifier.algorithm',
- class: asn1_1.Class.UNIVERSAL,
- tag: asn1_1.Tag.OID,
- capture: 'publicKeyOID',
- }],
- }, {
- name: 'PublicKeyInfo.PublicKey',
- class: asn1_1.Class.UNIVERSAL,
- tag: asn1_1.Tag.BITSTRING,
- capture: 'publicKey',
- }],
- };
- /**
- * ASN.1 Template for PKCS#8 Private Key. https://tools.ietf.org/html/rfc5208
- */
- exports.privateKeyValidator = {
- name: 'PrivateKeyInfo',
- class: asn1_1.Class.UNIVERSAL,
- tag: asn1_1.Tag.SEQUENCE,
- capture: 'privateKeyInfo',
- value: [{
- name: 'PrivateKeyInfo.Version',
- class: asn1_1.Class.UNIVERSAL,
- tag: asn1_1.Tag.INTEGER,
- capture: 'privateKeyVersion',
- }, {
- name: 'PrivateKeyInfo.AlgorithmIdentifier',
- class: asn1_1.Class.UNIVERSAL,
- tag: asn1_1.Tag.SEQUENCE,
- value: [{
- name: 'PrivateKeyAlgorithmIdentifier.algorithm',
- class: asn1_1.Class.UNIVERSAL,
- tag: asn1_1.Tag.OID,
- capture: 'privateKeyOID',
- }],
- }, {
- name: 'PrivateKeyInfo.PrivateKey',
- class: asn1_1.Class.UNIVERSAL,
- tag: asn1_1.Tag.OCTETSTRING,
- capture: 'privateKey',
- }],
- };
- // validator for an RSA public key
- const rsaPublicKeyValidator = {
- // RSAPublicKey
- name: 'RSAPublicKey',
- class: asn1_1.Class.UNIVERSAL,
- tag: asn1_1.Tag.SEQUENCE,
- value: [{
- // modulus (n)
- name: 'RSAPublicKey.modulus',
- class: asn1_1.Class.UNIVERSAL,
- tag: asn1_1.Tag.INTEGER,
- capture: 'publicKeyModulus',
- }, {
- // publicExponent (e)
- name: 'RSAPublicKey.exponent',
- class: asn1_1.Class.UNIVERSAL,
- tag: asn1_1.Tag.INTEGER,
- capture: 'publicKeyExponent',
- }],
- };
- const rsaPrivateKeyValidator = {
- // RSAPrivateKey
- name: 'RSAPrivateKey',
- class: asn1_1.Class.UNIVERSAL,
- tag: asn1_1.Tag.SEQUENCE,
- value: [{
- // Version (INTEGER)
- name: 'RSAPrivateKey.version',
- class: asn1_1.Class.UNIVERSAL,
- tag: asn1_1.Tag.INTEGER,
- capture: 'privateKeyVersion',
- }, {
- // modulus (n)
- name: 'RSAPrivateKey.modulus',
- class: asn1_1.Class.UNIVERSAL,
- tag: asn1_1.Tag.INTEGER,
- capture: 'privateKeyModulus',
- }, {
- // publicExponent (e)
- name: 'RSAPrivateKey.publicExponent',
- class: asn1_1.Class.UNIVERSAL,
- tag: asn1_1.Tag.INTEGER,
- capture: 'privateKeyPublicExponent',
- }, {
- // privateExponent (d)
- name: 'RSAPrivateKey.privateExponent',
- class: asn1_1.Class.UNIVERSAL,
- tag: asn1_1.Tag.INTEGER,
- capture: 'privateKeyPrivateExponent',
- }, {
- // prime1 (p)
- name: 'RSAPrivateKey.prime1',
- class: asn1_1.Class.UNIVERSAL,
- tag: asn1_1.Tag.INTEGER,
- capture: 'privateKeyPrime1',
- }, {
- // prime2 (q)
- name: 'RSAPrivateKey.prime2',
- class: asn1_1.Class.UNIVERSAL,
- tag: asn1_1.Tag.INTEGER,
- capture: 'privateKeyPrime2',
- }, {
- // exponent1 (d mod (p-1))
- name: 'RSAPrivateKey.exponent1',
- class: asn1_1.Class.UNIVERSAL,
- tag: asn1_1.Tag.INTEGER,
- capture: 'privateKeyExponent1',
- }, {
- // exponent2 (d mod (q-1))
- name: 'RSAPrivateKey.exponent2',
- class: asn1_1.Class.UNIVERSAL,
- tag: asn1_1.Tag.INTEGER,
- capture: 'privateKeyExponent2',
- }, {
- // coefficient ((inverse of q) mod p)
- name: 'RSAPrivateKey.coefficient',
- class: asn1_1.Class.UNIVERSAL,
- tag: asn1_1.Tag.INTEGER,
- capture: 'privateKeyCoefficient',
- }],
- };
- const EdDSAPrivateKeyOIDs = [
- // https://tools.ietf.org/html/draft-ietf-curdle-pkix-10
- common_1.getOID('X25519'),
- common_1.getOID('X448'),
- common_1.getOID('Ed25519'),
- common_1.getOID('Ed448'),
- ];
- /**
- * PKCS#8 Public Key
- */
- class PublicKey {
- constructor(obj) {
- const captures = {};
- const err = obj.validate(exports.publicKeyValidator, captures);
- if (err != null) {
- throw new Error('Cannot read X.509 public key: ' + err.message);
- }
- this.oid = asn1_1.ASN1.parseOID(captures.publicKeyOID.bytes);
- this.algo = common_1.getOIDName(this.oid);
- this._pkcs8 = obj;
- this._keyRaw = asn1_1.ASN1.parseBitString(captures.publicKey.bytes).buf;
- this._finalKey = this._keyRaw;
- this._finalPEM = '';
- }
- /**
- * Parse an PublicKey for X.509 certificate from PKCS#8 PEM formatted buffer or PKCS#1 RSA PEM formatted buffer.
- * @param pem PEM formatted buffer
- */
- static fromPEM(pem) {
- const msg = asn1_1.PEM.parse(pem)[0];
- if (msg.procType.includes('ENCRYPTED')) {
- throw new Error('Could not convert public key from PEM, PEM is encrypted.');
- }
- const obj = asn1_1.ASN1.fromDER(msg.body, true);
- switch (msg.type) {
- case 'PUBLIC KEY': // PKCS#8
- return new PublicKey(obj);
- case 'RSA PUBLIC KEY': // PKCS#1
- const _pkcs8 = asn1_1.ASN1.Seq([
- // AlgorithmIdentifier
- asn1_1.ASN1.Seq([
- // algorithm
- asn1_1.ASN1.OID(common_1.getOID('rsaEncryption')),
- // optional parameters
- asn1_1.ASN1.Null(),
- ]),
- // PublicKey
- asn1_1.ASN1.BitString(obj.DER),
- ]);
- return new PublicKey(_pkcs8);
- default:
- throw new Error('Could not convert public key from PEM, recommend PKCS#8 PEM');
- }
- }
- /**
- * Registers an external Verifier with object identifier.
- * Built-in verifiers: Ed25519, RSA, others see https://nodejs.org/api/crypto.html#crypto_class_verify
- * ```js
- * PublicKey.addVerifier(getOID('Ed25519'), function (this: PublicKey, data: Buffer, signature: Buffer): boolean {
- * return ed25519.detached.verify(data, signature, this.keyRaw)
- * })
- * ```
- * @param oid algorithm object identifier
- * @param fn Verifier function
- */
- static addVerifier(oid, fn) {
- oid = common_1.getOID(oid);
- if (oid === '') {
- throw new Error(`Invalid object identifier: ${oid}`);
- }
- if (PublicKey._verifiers[oid] != null) {
- throw new Error(`Verifier ${oid} exists`);
- }
- PublicKey._verifiers[oid] = fn;
- }
- /**
- * underlying key buffer
- */
- get keyRaw() {
- return this._finalKey;
- }
- /**
- * Returns true if the provided data and the given signature matched.
- * ```js
- * certificate.publicKey.verify(data, signature, 'sha256') // => true or false
- * ```
- * @param data data to verify
- * @param signature signature that signed by private key
- * @param hashAlgorithm hash algorithm, such as 'sha256', 'sha1'
- */
- verify(data, signature, hashAlgorithm) {
- const verifier = PublicKey._verifiers[this.oid];
- if (verifier != null) {
- const sum = crypto_1.createHash(hashAlgorithm).update(data).digest();
- return verifier.call(this, sum, signature);
- }
- const verify = crypto_1.createVerify(hashAlgorithm);
- verify.update(data);
- return verify.verify(this.toPEM(), signature);
- }
- /**
- * Returns the digest of the PublicKey with given hash algorithm.
- * ```js
- * certificate.publicKey.getFingerprint('sha1', 'PublicKey') // => Buffer
- * ```
- * @param hashAlgorithm hash algorithm, such as 'sha256', 'sha1'
- * @param type 'PublicKey' or 'PublicKeyInfo'
- */
- getFingerprint(hashAlgorithm, type = 'PublicKey') {
- let bytes;
- switch (type) {
- case 'PublicKeyInfo':
- bytes = this._pkcs8.DER;
- break;
- case 'PublicKey':
- bytes = this._keyRaw;
- break;
- default:
- throw new Error(`Unknown fingerprint type "${type}".`);
- }
- const hasher = crypto_1.createHash(hashAlgorithm);
- hasher.update(bytes);
- return hasher.digest();
- }
- /**
- * Returns an ASN.1 object of this PublicKey
- */
- toASN1() {
- return this._pkcs8;
- }
- /**
- * Returns an DER formatted buffer of this PublicKey
- */
- toDER() {
- return this._pkcs8.DER;
- }
- /**
- * Returns an PEM formatted string of this PublicKey
- */
- toPEM() {
- if (this._finalPEM === '') {
- this._finalPEM = new asn1_1.PEM('PUBLIC KEY', this._pkcs8.DER).toString();
- }
- return this._finalPEM;
- }
- /**
- * Return a friendly JSON object for debuging.
- */
- toJSON() {
- return {
- oid: this.oid,
- algo: this.algo,
- publicKey: this._keyRaw,
- };
- }
- [util_1.inspect.custom](_depth, options) {
- return `<${this.constructor.name} ${util_1.inspect(this.toJSON(), options)}>`;
- }
- }
- PublicKey._verifiers = Object.create(null);
- exports.PublicKey = PublicKey;
- /**
- * PKCS#8 Private Key
- */
- class PrivateKey {
- constructor(obj) {
- // get RSA params
- const captures = Object.create(null);
- const err = obj.validate(exports.privateKeyValidator, captures);
- if (err != null) {
- throw new Error('Cannot read X.509 private key: ' + err.message);
- }
- this.version = asn1_1.ASN1.parseIntegerNum(captures.privateKeyVersion.bytes) + 1;
- this.oid = asn1_1.ASN1.parseOID(captures.privateKeyOID.bytes);
- this.algo = common_1.getOIDName(this.oid);
- this._pkcs8 = obj;
- this._keyRaw = captures.privateKey.bytes;
- this._publicKeyRaw = null;
- this._finalKey = this._keyRaw;
- this._finalPEM = '';
- if (EdDSAPrivateKeyOIDs.includes(this.oid)) {
- this._finalKey = this._keyRaw = asn1_1.ASN1.parseDER(this._keyRaw, asn1_1.Class.UNIVERSAL, asn1_1.Tag.OCTETSTRING).bytes;
- if (this.oid === '1.3.101.112') {
- const keypair = tweetnacl_1.sign.keyPair.fromSeed(this._keyRaw);
- this._publicKeyRaw = Buffer.from(keypair.publicKey);
- this._finalKey = Buffer.from(keypair.secretKey);
- }
- else if (this.version === 2) {
- for (const val of obj.mustCompound()) {
- if (val.class === asn1_1.Class.CONTEXT_SPECIFIC && val.tag === 1) {
- this._publicKeyRaw = asn1_1.ASN1.parseBitString(val.bytes).buf;
- this._finalKey = Buffer.concat([this._keyRaw, this._publicKeyRaw]);
- }
- }
- }
- }
- }
- /**
- * Parse an PrivateKey for X.509 certificate from PKCS#8 PEM formatted buffer or PKCS#1 RSA PEM formatted buffer.
- * @param pem PEM formatted buffer
- */
- static fromPEM(pem) {
- const msg = asn1_1.PEM.parse(pem)[0];
- if (msg.procType.includes('ENCRYPTED')) {
- throw new Error('Could not convert private key from PEM, PEM is encrypted.');
- }
- let obj = asn1_1.ASN1.fromDER(msg.body, true);
- switch (msg.type) {
- case 'PRIVATE KEY': // PKCS#8
- return new PrivateKey(obj);
- case 'RSA PRIVATE KEY': // PKCS#1
- obj = asn1_1.ASN1.Seq([
- // Version (INTEGER)
- obj.value[0],
- // AlgorithmIdentifier
- asn1_1.ASN1.Seq([
- // algorithm
- asn1_1.ASN1.OID(common_1.getOID('rsaEncryption')),
- // optional parameters
- asn1_1.ASN1.Null(),
- ]),
- // PrivateKey
- new asn1_1.ASN1(asn1_1.Class.UNIVERSAL, asn1_1.Tag.OCTETSTRING, obj.DER),
- ]);
- return new PrivateKey(obj);
- default:
- throw new Error('Could not convert private key from PEM, recommend PKCS#8 PEM');
- }
- }
- /**
- * Registers an external Signer with object identifier.
- * Built-in verifiers: Ed25519, RSA, others see https://nodejs.org/api/crypto.html#crypto_class_sign
- * ```js
- * PrivateKey.addSigner(getOID('Ed25519'), function (this: PrivateKey, data: Buffer): Buffer {
- * const key = this.keyRaw
- * if (key.length !== 64) {
- * throw new Error('Invalid signing key.')
- * }
- * return Buffer.from(ed25519.detached(data, key))
- * })
- * ```
- * @param oid algorithm object identifier
- * @param fn Verifier function
- */
- static addSigner(oid, fn) {
- oid = common_1.getOID(oid);
- if (oid === '') {
- throw new Error(`Invalid object identifier: ${oid}`);
- }
- if (PrivateKey._signers[oid] != null) {
- throw new Error(`Signer ${oid} exists`);
- }
- PrivateKey._signers[oid] = fn;
- }
- /**
- * underlying key buffer
- */
- get keyRaw() {
- return this._finalKey;
- }
- /**
- * Returns publicKey buffer, it is used for Ed25519/Ed448.
- */
- get publicKeyRaw() {
- return this._publicKeyRaw;
- }
- /**
- * Returns signature for the given data and hash algorithm.
- * @param data
- * @param hashAlgorithm
- */
- sign(data, hashAlgorithm) {
- const signer = PrivateKey._signers[this.oid];
- if (signer != null) {
- const sum = crypto_1.createHash(hashAlgorithm).update(data).digest();
- return signer.call(this, sum);
- }
- const sign = crypto_1.createSign(hashAlgorithm);
- sign.update(data);
- return sign.sign(this.toPEM());
- }
- /**
- * Returns an ASN.1 object of this PrivateKey
- */
- toASN1() {
- return this._pkcs8;
- }
- /**
- * Returns an DER formatted buffer of this PrivateKey
- */
- toDER() {
- return this._pkcs8.DER;
- }
- /**
- * Returns an PEM formatted string of this PrivateKey
- */
- toPEM() {
- if (this._finalPEM === '') {
- this._finalPEM = new asn1_1.PEM('PRIVATE KEY', this._pkcs8.DER).toString();
- }
- return this._finalPEM;
- }
- /**
- * Return a friendly JSON object for debuging.
- */
- toJSON() {
- return {
- version: this.version,
- oid: this.oid,
- algo: this.algo,
- privateKey: this._keyRaw,
- publicKey: this._publicKeyRaw,
- };
- }
- [util_1.inspect.custom](_depth, options) {
- return `<${this.constructor.name} ${util_1.inspect(this.toJSON(), options)}>`;
- }
- }
- PrivateKey._signers = Object.create(null);
- exports.PrivateKey = PrivateKey;
- /**
- * PKCS#1 RSA Public Key
- */
- class RSAPublicKey extends PublicKey {
- static fromPublicKey(publicKey) {
- return new RSAPublicKey(publicKey.toASN1());
- }
- constructor(obj) {
- super(obj);
- if (common_1.getOID(this.oid) !== common_1.getOID('rsaEncryption')) {
- throw new Error(`Invalid RSA public key, unknown OID: ${this.oid}`);
- }
- // get RSA params
- const captures = Object.create(null);
- this._pkcs1 = asn1_1.ASN1.fromDER(this._keyRaw, true);
- const err = this._pkcs1.validate(rsaPublicKeyValidator, captures);
- if (err != null) {
- throw new Error('Cannot read RSA public key: ' + err.message);
- }
- this.modulus = asn1_1.ASN1.parseIntegerStr(captures.publicKeyModulus.bytes);
- this.exponent = asn1_1.ASN1.parseIntegerNum(captures.publicKeyExponent.bytes);
- }
- /**
- * Returns an PKCS#1 ASN.1 object of this RSAPublicKey
- */
- toASN1() {
- return this._pkcs1;
- }
- /**
- * Returns an PKCS#1 DER formatted buffer of this RSAPublicKey
- */
- toDER() {
- return this._keyRaw;
- }
- /**
- * Returns an PKCS#1 PEM formatted string of this RSAPublicKey
- */
- toPEM() {
- if (this._finalPEM === '') {
- this._finalPEM = new asn1_1.PEM('RSA PUBLIC KEY', this._keyRaw).toString();
- }
- return this._finalPEM;
- }
- /**
- * Returns an PKCS#8 PEM formatted string of this RSAPublicKey
- */
- toPublicKeyPEM() {
- return new asn1_1.PEM('PUBLIC KEY', this._pkcs8.DER).toString();
- }
- /**
- * Return a friendly JSON object for debuging.
- */
- toJSON() {
- return {
- oid: this.oid,
- algo: this.algo,
- modulus: trimLeadingZeroByte(this.modulus),
- exponent: this.exponent,
- };
- }
- [util_1.inspect.custom](_depth, options) {
- return `<${this.constructor.name} ${util_1.inspect(this.toJSON(), options)}>`;
- }
- }
- exports.RSAPublicKey = RSAPublicKey;
- /**
- * PKCS#1 RSA Private Key
- */
- class RSAPrivateKey extends PrivateKey {
- static fromPrivateKey(privateKey) {
- return new RSAPrivateKey(privateKey.toASN1());
- }
- constructor(obj) {
- super(obj);
- if (common_1.getOID(this.oid) !== common_1.getOID('rsaEncryption')) {
- throw new Error(`Invalid RSA private key, unknown OID: ${this.oid}`);
- }
- // get RSA params
- const captures = Object.create(null);
- this._pkcs1 = asn1_1.ASN1.fromDER(this._keyRaw, true);
- const err = this._pkcs1.validate(rsaPrivateKeyValidator, captures);
- if (err != null) {
- throw new Error('Cannot read RSA private key: ' + err.message);
- }
- this.publicExponent = asn1_1.ASN1.parseIntegerNum(captures.privateKeyPublicExponent.bytes);
- this.privateExponent = asn1_1.ASN1.parseIntegerStr(captures.privateKeyPrivateExponent.bytes);
- this.modulus = asn1_1.ASN1.parseIntegerStr(captures.privateKeyModulus.bytes);
- this.prime1 = asn1_1.ASN1.parseIntegerStr(captures.privateKeyPrime1.bytes);
- this.prime2 = asn1_1.ASN1.parseIntegerStr(captures.privateKeyPrime2.bytes);
- this.exponent1 = asn1_1.ASN1.parseIntegerStr(captures.privateKeyExponent1.bytes);
- this.exponent2 = asn1_1.ASN1.parseIntegerStr(captures.privateKeyExponent2.bytes);
- this.coefficient = asn1_1.ASN1.parseIntegerStr(captures.privateKeyCoefficient.bytes);
- }
- /**
- * Returns an PKCS#1 ASN.1 object of this RSAPrivateKey
- */
- toASN1() {
- return this._pkcs1;
- }
- /**
- * Returns an PKCS#1 DER formatted buffer of this RSAPrivateKey
- */
- toDER() {
- return this._keyRaw;
- }
- /**
- * Returns an PKCS#1 PEM formatted string of this RSAPrivateKey
- */
- toPEM() {
- if (this._finalPEM === '') {
- this._finalPEM = new asn1_1.PEM('RSA PRIVATE KEY', this._keyRaw).toString();
- }
- return this._finalPEM;
- }
- /**
- * Returns an PKCS#8 PEM formatted string of this RSAPrivateKey
- */
- toPrivateKeyPEM() {
- return new asn1_1.PEM('PRIVATE KEY', this._pkcs8.DER).toString();
- }
- /**
- * Return a friendly JSON object for debuging.
- */
- toJSON() {
- return {
- version: this.version,
- oid: this.oid,
- algo: this.algo,
- publicExponent: this.publicExponent,
- privateExponent: trimLeadingZeroByte(this.privateExponent),
- modulus: trimLeadingZeroByte(this.modulus),
- prime1: trimLeadingZeroByte(this.prime1),
- prime2: trimLeadingZeroByte(this.prime2),
- exponent1: trimLeadingZeroByte(this.exponent1),
- exponent2: trimLeadingZeroByte(this.exponent2),
- coefficient: trimLeadingZeroByte(this.coefficient),
- };
- }
- [util_1.inspect.custom](_depth, options) {
- return `<${this.constructor.name} ${util_1.inspect(this.toJSON(), options)}>`;
- }
- }
- exports.RSAPrivateKey = RSAPrivateKey;
- // leading 00 byte is signed representation for BigInteger
- // https://stackoverflow.com/questions/8515691/getting-1-byte-extra-in-the-modulus-rsa-key-and-sometimes-for-exponents-also
- function trimLeadingZeroByte(hex) {
- return (hex.length % 8 !== 0) && hex.startsWith('00') ? hex.slice(2) : hex;
- }
- PublicKey.addVerifier(common_1.getOID('Ed25519'), function (data, signature) {
- return tweetnacl_1.sign.detached.verify(data, signature, this.keyRaw);
- });
- PrivateKey.addSigner(common_1.getOID('Ed25519'), function (data) {
- const key = this.keyRaw;
- if (key.length !== 64) {
- throw new Error('Invalid signing key.');
- }
- return Buffer.from(tweetnacl_1.sign.detached(data, key));
- });
- //# sourceMappingURL=pki.js.map
|