node-opcua/node-opcua-crypto

View on GitHub
packages/node-opcua-crypto/source_nodejs/read.ts

Summary

Maintainability
A
1 hr
Test Coverage
// ---------------------------------------------------------------------------------------------------------------------
// node-opcua-crypto
// ---------------------------------------------------------------------------------------------------------------------
// Copyright (c) 2014-2022 - Etienne Rossignon - etienne.rossignon (at) gadz.org
// Copyright (c) 2022-2024 - Sterfive.com
// ---------------------------------------------------------------------------------------------------------------------
//
// This  project is licensed under the terms of the MIT license.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so,  subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
// Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ---------------------------------------------------------------------------------------------------------------------

import assert from "assert";
import fs from "fs";
import path from "path";
import { createPrivateKey, createPublicKey } from "crypto";
import { Certificate, CertificatePEM, DER, PEM, PublicKey, PublicKeyPEM, PrivateKeyPEM, PrivateKey } from "../source/common.js";
import { convertPEMtoDER, identifyPemType, removeTrailingLF, toPem } from "../source/crypto_utils.js";
import sshpk from "sshpk";
import { fileURLToPath } from "url";

function _readPemFile(filename: string): PEM {
    assert(typeof filename === "string");
    return removeTrailingLF(fs.readFileSync(filename, "utf-8"));
}

function _readPemOrDerFileAsDER(filename: string): DER {
    if (filename.match(/.*\.der/)) {
        return fs.readFileSync(filename) as Buffer;
    }
    const raw_key: string = _readPemFile(filename);
    return convertPEMtoDER(raw_key);
}

/**
 * read a DER or PEM certificate from file
 */
export function readCertificate(filename: string): Certificate {
    return _readPemOrDerFileAsDER(filename) as Certificate;
}

/**
 * read a DER or PEM certificate from file
 */
export function readPublicKey(filename: string): PublicKey {
    if (filename.match(/.*\.der/)) {
        const der = fs.readFileSync(filename) as Buffer;
        return createPublicKey(der);
    } else {
        const raw_key: string = _readPemFile(filename);
        return createPublicKey(raw_key);
    }
}

// console.log("createPrivateKey", (crypto as any).createPrivateKey, process.env.NO_CREATE_PRIVATEKEY);

function myCreatePrivateKey(rawKey: string | Buffer): PrivateKey {
    if (!createPrivateKey || process.env.NO_CREATE_PRIVATEKEY) {
        // we are not running nodejs or createPrivateKey is not supported in the environment
        if (rawKey instanceof Buffer) {
            const pemKey = toPem(rawKey, "PRIVATE KEY");
            assert(["RSA PRIVATE KEY", "PRIVATE KEY"].indexOf(identifyPemType(pemKey) as string) >= 0);
            return { hidden: pemKey };
        }
        return { hidden: ensureTrailingLF(rawKey) };
    }
    // see https://askubuntu.com/questions/1409458/openssl-config-cuases-error-in-node-js-crypto-how-should-the-config-be-updated
    const backup = process.env.OPENSSL_CONF;
    process.env.OPENSSL_CONF = "/dev/null";
    const retValue = createPrivateKey(rawKey);
    process.env.OPENSSL_CONF = backup;
    return { hidden: retValue };
}

export function makePrivateKeyThumbPrint(privateKey: PrivateKey): Buffer {
    //   // .export({ format: "der", type: "pkcs1" });
    //   if (typeof privateKey === "string") {
    //
    //   } else {
    //    return makeSHA1Thumbprint(privateKey.hidden);
    //   }
    // to do
    return Buffer.alloc(0);
}

function ensureTrailingLF(str: string): string {
    return str.match(/\n$/) ? str : str + "\n";
}
/**
 * read a DER or PEM certificate from file
 */
export function readPrivateKey(filename: string): PrivateKey {
    if (filename.match(/.*\.der/)) {
        const der: Buffer = fs.readFileSync(filename);
        return myCreatePrivateKey(der);
    } else {
        const raw_key: string = _readPemFile(filename);
        return myCreatePrivateKey(raw_key);
    }
}

export function readCertificatePEM(filename: string): CertificatePEM {
    return _readPemFile(filename);
}

export function readPublicKeyPEM(filename: string): PublicKeyPEM {
    return _readPemFile(filename);
}
/**
 *
 * @deprecated
 */
export function readPrivateKeyPEM(filename: string): PrivateKeyPEM {
    return _readPemFile(filename);
}

let _g_certificate_store: string = "";

export function setCertificateStore(store: string): string {
    const old_store = _g_certificate_store;
    _g_certificate_store = store;
    return old_store;
}
export function getCertificateStore(): string {
    if (!_g_certificate_store) {
        _g_certificate_store = path.join(__dirname, "../../certificates/");
    }
    return _g_certificate_store;
}
/**
 *
 * @param filename
 */
export function readPrivateRsaKey(filename: string): PrivateKey {
    if (!createPrivateKey) {
        throw new Error("createPrivateKey is not supported in this environment");
    }
    if (filename.substring(0, 1) !== "." && !fs.existsSync(filename)) {
        filename = path.join(getCertificateStore(),filename);
    }
    const content = fs.readFileSync(filename, "utf8");
    const sshKey = sshpk.parsePrivateKey(content, "auto");
    const key = sshKey.toString("pkcs1") as PEM;
    const hidden = createPrivateKey({ format: "pem", type: "pkcs1", key });
    return { hidden };
}

export function readPublicRsaKey(filename: string): PublicKey {
    if (filename.substring(0, 1) !== "." && !fs.existsSync(filename)) {
        filename = path.join(getCertificateStore(), filename);
    }
    const content = fs.readFileSync(filename, "utf-8");
    const sshKey = sshpk.parseKey(content, "ssh");
    const key = sshKey.toString("pkcs1") as PEM;
    return createPublicKey({ format: "pem", type: "pkcs1", key });
}