Skip to content

Commit

Permalink
toPem remove trailing CR/LF
Browse files Browse the repository at this point in the history
  • Loading branch information
erossignon committed Aug 14, 2023
1 parent 901f267 commit 8d67616
Show file tree
Hide file tree
Showing 9 changed files with 57 additions and 46 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ name: CI
on:
# Triggers the workflow on push or pull request events but only for the master branch
push:
branches: [master]
branches: [master]
pull_request:
branches: [master]

Expand Down
17 changes: 8 additions & 9 deletions source/crypto_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,17 @@ export function identifyPemType(rawKey: Buffer | string): undefined | string {
return !match ? undefined : match[2];
}

export function removeTrailingLF(str: string): string {
const tmp = str.replace(/(\r|\n)+$/m, "").replace(/\r\n/gm, "\n");
return tmp;
}

export function toPem(raw_key: Buffer | string, pem: string): string {
assert(raw_key, "expecting a key");
assert(typeof pem === "string");
let pemType = identifyPemType(raw_key);
if (pemType) {
return raw_key instanceof Buffer ? raw_key.toString("utf8").replace(/(\r|\n)+$/gm, "") : raw_key.replace(/(\r|\n)+$/gm, "");
return raw_key instanceof Buffer ? removeTrailingLF(raw_key.toString("utf8")) : removeTrailingLF(raw_key);
} else {
pemType = pem;
assert(["CERTIFICATE REQUEST", "CERTIFICATE", "RSA PRIVATE KEY", "PUBLIC KEY", "X509 CRL"].indexOf(pemType) >= 0);
Expand All @@ -80,7 +84,7 @@ export function toPem(raw_key: Buffer | string, pem: string): string {
b = b.substring(64);
}
str += "-----END " + pemType + "-----";
// str += "\n";
// no leading \n
return str;
}
}
Expand Down Expand Up @@ -200,7 +204,7 @@ export function publicEncrypt_native(buffer: Buffer, publicKey: KeyLike, algorit
if (algorithm === undefined) {
algorithm = PaddingAlgorithm.RSA_PKCS1_PADDING;
}
return publicEncrypt1(
return publicEncrypt1(
{
key: publicKey,
padding: algorithm,
Expand Down Expand Up @@ -260,12 +264,7 @@ export function publicEncrypt_long(
return outputBuffer;
}

export function privateDecrypt_long(
buffer: Buffer,
privateKey: PrivateKey,
blockSize: number,
paddingAlgorithm?: number
): Buffer {
export function privateDecrypt_long(buffer: Buffer, privateKey: PrivateKey, blockSize: number, paddingAlgorithm?: number): Buffer {
paddingAlgorithm = paddingAlgorithm || RSA_PKCS1_PADDING;
// istanbul ignore next
if (paddingAlgorithm !== RSA_PKCS1_PADDING && paddingAlgorithm !== RSA_PKCS1_OAEP_PADDING) {
Expand Down
7 changes: 3 additions & 4 deletions source/crypto_utils2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@ import assert from "assert";
import { createPrivateKey as createPrivateKeyFromNodeJSCrypto, KeyObject } from "crypto";

import { PublicKey, PublicKeyPEM, PrivateKeyPEM, PrivateKey } from "./common.js";
import { toPem } from "./crypto_utils.js";
import { type } from "os";
import { removeTrailingLF, toPem } from "./crypto_utils.js";

const jsrsasign = require("jsrsasign");

Expand Down Expand Up @@ -71,9 +70,9 @@ export function toPem2(raw_key: Buffer | string | KeyObject | PrivateKey, pem: s

if (raw_key instanceof KeyObject) {
if (pem === "RSA PRIVATE KEY") {
return raw_key.export({ format: "pem", type: "pkcs1" }).toString();
return removeTrailingLF(raw_key.export({ format: "pem", type: "pkcs1" }).toString());
} else if (pem === "PRIVATE KEY") {
return raw_key.export({ format: "pem", type: "pkcs8" }).toString();
return removeTrailingLF(raw_key.export({ format: "pem", type: "pkcs8" }).toString());
} else {
throw new Error("Unsupported case!");
}
Expand Down
4 changes: 2 additions & 2 deletions source/x509/_crypto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ if (typeof window === "undefined") {
_crypto = require("crypto");
if (!_crypto?.subtle) {
_crypto = new Crypto();
//xx console.warn("using @peculiar/webcrypto");
console.warn("using @peculiar/webcrypto");
} else {
//xx console.warn("using nodejs crypto (native)");
console.warn("using nodejs crypto (native)");
}
x509.cryptoProvider.set(_crypto);
} else {
Expand Down
2 changes: 1 addition & 1 deletion source_nodejs/generate_private_key_filename.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import { generateKeyPair, privateKeyToPEM } from "../source/index.js";
export async function generatePrivateKeyFile(privateKeyFilename: string, modulusLength: 1024 | 2048 | 3072 | 4096) {
const keys = await generateKeyPair(modulusLength);
const privateKeyPem = await privateKeyToPEM(keys.privateKey);
await fs.promises.writeFile(privateKeyFilename, privateKeyPem.privPem);
await fs.promises.writeFile(privateKeyFilename, privateKeyPem.privPem, "utf-8");
privateKeyPem.privPem = "";
privateKeyPem.privDer = new Uint8Array(0);
}
35 changes: 12 additions & 23 deletions source_nodejs/read.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,24 +25,14 @@ 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, makeSHA1Thumbprint, toPem } from "../source/crypto_utils.js";
import { toPem2 } from "../source/crypto_utils2.js";
import { Certificate, CertificatePEM, DER, PEM, PublicKey, PublicKeyPEM, PrivateKeyPEM, PrivateKey } from "../source/common.js";
import { convertPEMtoDER, identifyPemType, removeTrailingLF, toPem } from "../source/crypto_utils.js";

const sshpk = require("sshpk");

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

function _readPemOrDerFileAsDER(filename: string): DER {
Expand Down Expand Up @@ -75,7 +65,6 @@ export function readPublicKey(filename: string): PublicKey {

// 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
Expand All @@ -84,7 +73,7 @@ function myCreatePrivateKey(rawKey: string | Buffer): PrivateKey {
assert(["RSA PRIVATE KEY", "PRIVATE KEY"].indexOf(identifyPemType(pemKey) as string) >= 0);
return { hidden: pemKey };
}
return { hidden: rawKey };
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;
Expand All @@ -94,26 +83,26 @@ function myCreatePrivateKey(rawKey: string | Buffer): PrivateKey {
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
// 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 = fs.readFileSync(filename) as Buffer;
const der: Buffer = fs.readFileSync(filename);
return myCreatePrivateKey(der);
} else {
const raw_key: string = _readPemFile(filename);
Expand All @@ -129,7 +118,7 @@ export function readPublicKeyPEM(filename: string): PublicKeyPEM {
return _readPemFile(filename);
}
/**
*
*
* @deprecated
*/
export function readPrivateKeyPEM(filename: string): PrivateKeyPEM {
Expand All @@ -155,7 +144,7 @@ export function readPrivateRsaKey(filename: string): PrivateKey {
if (filename.substring(0, 1) !== "." && !fs.existsSync(filename)) {
filename = __certificate_store + filename;
}
const content = fs.readFileSync(filename, "ascii");
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 });
Expand All @@ -166,7 +155,7 @@ export function readPublicRsaKey(filename: string): PublicKey {
if (filename.substring(0, 1) !== "." && !fs.existsSync(filename)) {
filename = __certificate_store + filename;
}
const content = fs.readFileSync(filename, "ascii");
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 });
Expand Down
26 changes: 25 additions & 1 deletion test/test_create_self_signed_certificate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import {
pemToPrivateKey,
privateKeyToPEM,
createSelfSignedCertificate,
removeTrailingLF,
} from "..";

const tmpTestFolder = os.tmpdir();
Expand Down Expand Up @@ -88,7 +89,7 @@ describe("creating X509 self-signed certificates", function () {
await fs.promises.writeFile(tmpPrivateKeyFilename, privPem);
}

const privateKeyPem = await fs.promises.readFile(tmpPrivateKeyFilename, "utf-8");
const privateKeyPem = removeTrailingLF(await fs.promises.readFile(tmpPrivateKeyFilename, "utf-8"));
const privateKey = await pemToPrivateKey(privateKeyPem);

const { cert } = await createSelfSignedCertificate({
Expand All @@ -109,4 +110,27 @@ describe("creating X509 self-signed certificates", function () {
uniformResourceIdentifier: ["urn:HOSTNAME:ServerDescription"],
});
});

it("ZZ1 - should create self-signed certificate with those parameters ", async () => {
const tmpPrivateKeyFilename = path.join(tmpTestFolder, "_tmp_privatekey.pem");
{
const { privateKey } = await generateKeyPair();
const { privPem } = await privateKeyToPEM(privateKey);
await fs.promises.writeFile(tmpPrivateKeyFilename, privPem);
}

const privateKeyPem = removeTrailingLF(await fs.promises.readFile(tmpPrivateKeyFilename, "utf-8"));
const privateKey = await pemToPrivateKey(privateKeyPem);

const { cert } = await createSelfSignedCertificate({
privateKey,
notAfter: new Date(2020, 1, 1),
notBefore: new Date(2019, 1, 1),
subject: "/CN=OPCUA-Server/O=COMPANY/L=CITY/ST=REGION/C=FR/DC=company.com",
dns: ["DNS1", "DNS2"],
ip: ["192.168.1.1"],
applicationUri: "urn:HOSTNAME:ServerDescription",
purpose: CertificatePurpose.ForApplication,
});
});
});
8 changes: 4 additions & 4 deletions test/test_crypto_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import * as loremIpsum from "lorem-ipsum";
import "should";
import "mocha";

import { exploreCertificateInfo, makeSHA1Thumbprint, split_der, toPem } from "..";
import { exploreCertificateInfo, makeSHA1Thumbprint, readCertificatePEM, removeTrailingLF, split_der, toPem } from "..";
import { readCertificate } from "..";


Expand Down Expand Up @@ -106,15 +106,15 @@ describe("Crypto utils", function () {
});

it("toPem should return a string if provided certificate is a buffer containing a PEM string", () => {
const certificate = fs.readFileSync(path.join(__dirname, "../test-fixtures/certs/cert1.pem"), null);
const certificate = fs.readFileSync(path.join(__dirname, "../test-fixtures/certs/cert1.pem"), "binary");
const pemCertificate = toPem(certificate, "CERTIFICATE");
pemCertificate.should.be.type('string');
});

it("toPem should return a certificate directly if provided certificate is PEM string", () => {
const certificate = fs.readFileSync(path.join(__dirname, "../test-fixtures/certs/cert1.pem"), 'ascii');
const certificate = readCertificatePEM(path.join(__dirname, "../test-fixtures/certs/cert1.pem"));
const pemCertificate = toPem(certificate, "CERTIFICATE");
pemCertificate.should.eql(certificate);
pemCertificate.should.eql(removeTrailingLF(certificate));
});
});

Expand Down
2 changes: 1 addition & 1 deletion test/test_make_private_key_from_pem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ describe("makePrivateKeyFromPem", () => {

const privateKey2 = makePrivateKeyFromPem(pem);
const pem2 = coercePrivateKeyPem(privateKey2);
pem2.should.eql(pem);
pem2.trimEnd().should.eql(pem.trimEnd());

rsaLengthPrivateKey(privateKey).should.eql(2048 / 8);
});
Expand Down

0 comments on commit 8d67616

Please sign in to comment.