Skip to content

Instantly share code, notes, and snippets.

@fmonniot
Last active June 9, 2021 15:29
Show Gist options
  • Save fmonniot/e94ed40e3902415ccb9ca5a1d932297e to your computer and use it in GitHub Desktop.
Save fmonniot/e94ed40e3902415ccb9ca5a1d932297e to your computer and use it in GitHub Desktop.
Generate a root CA (self-signed), a CSR and a leaf certificate
import { writeFileSync, mkdirSync } from "fs";
import * as x509 from "@peculiar/x509";
import { Crypto } from "@peculiar/webcrypto";
import { execSync, spawnSync } from "child_process";
// We're okay with setting a global config for a simple script
const crypto = new Crypto();
x509.cryptoProvider.set(crypto);
const algorithm = {
name: "ECDSA",
namedCurve: "P-256",
hash: "SHA-256",
};
main()
.then(() => console.log("done"))
.catch((e) => console.error(`failed: ${e}`));
async function main() {
const path = `${__dirname}/certs`;
try {
mkdirSync(path);
} catch (error) {
if (error.code === "EEXIST") {
/* folder already exists, continue */
} else {
throw error;
}
}
const nodeId = "85cde111bdfc4034";
const fabricId = "733452ca227e0f54";
// CA
const [ca_pem, ca_private] = await gen_ca();
writeFileSync(path + "root.crt", ca_pem);
writeFileSync(path + "root.key", ca_private);
// CSR
const [csr_pem, csr_private] = await gen_csr();
writeFileSync(path + "child.csr", csr_pem);
writeFileSync(path + "child.key", csr_private);
// CRT
writeFileSync(
path + "child.crt",
await issue_cert(ca_pem, ca_private, csr_pem, nodeId, fabricId)
);
// OpenSSL checks
const is_csr_valid = openssl_verify_req(path + "child.csr");
const is_crt_valid = openssl_verify_cert(path, "child.crt");
console.log(`csr_valid=${is_csr_valid}; crt_valid=${is_crt_valid}`);
}
function openssl_verify_req(path: string): boolean {
let res = true;
try {
const process = spawnSync("openssl", [
"req",
"-noout",
"-verify",
"-in",
path,
]);
const err = process.stderr.toString();
res = /verify OK/.test(err);
} catch (error) {
console.log(error);
res = false;
}
return res;
}
function openssl_verify_cert(folder: string, file_name: string): boolean {
let res = true;
try {
execSync(
`openssl verify -verbose -CAfile ${folder}root.crt ${folder}${file_name}`
);
} catch (error) {
res = false;
}
return res;
}
// Voluntary working with string, as that's what we will have access to in the application
async function issue_cert(
ca_pem: string,
ca_private: string,
csr_pem: string,
node_id: string,
fabric_id: string | undefined
) {
const root = new x509.X509Certificate(ca_pem);
const csr = new x509.Pkcs10CertificateRequest(csr_pem);
const prv = await crypto.subtle.importKey(
"pkcs8",
x509.PemConverter.decode(ca_private)[0],
algorithm,
true,
["sign", "verify"]
);
const cert = await x509.X509CertificateGenerator.create({
serialNumber: "02",
notBefore: new Date("2020/01/01"),
notAfter: new Date("2022/01/02"),
signingAlgorithm: algorithm,
extensions: [
new x509.BasicConstraintsExtension(false, 2, true),
new x509.KeyUsagesExtension(
x509.KeyUsageFlags.digitalSignature |
x509.KeyUsageFlags.keyEncipherment,
true
),
],
issuer: root.subject,
subject: `1.3.6.1.4.1.37244.1.1=${node_id}, 1.3.6.1.4.1.37244.1.5=${fabric_id}`,
publicKey: await csr.publicKey.export(crypto),
signingKey: prv,
});
return cert.toString("pem");
}
// return [ca, private_key]
async function gen_ca(): Promise<[string, string]> {
const keys = await crypto.subtle.generateKey(algorithm, true, [
"sign",
"verify",
]);
const cert = await x509.X509CertificateGenerator.createSelfSigned({
serialNumber: "01",
notBefore: new Date("2020/01/01"),
notAfter: new Date("2022/01/02"),
signingAlgorithm: algorithm,
extensions: [
new x509.BasicConstraintsExtension(true, 2, true),
new x509.KeyUsagesExtension(
x509.KeyUsageFlags.keyCertSign |
x509.KeyUsageFlags.cRLSign |
x509.KeyUsageFlags.digitalSignature |
x509.KeyUsageFlags.keyEncipherment,
true
),
],
keys,
name: `1.3.6.1.4.1.37244.1.4=a36adda4dc1a34fb`,
});
const prv = await crypto.subtle.exportKey("pkcs8", keys.privateKey);
const pem = x509.PemConverter.encode(prv, "PRIVATE KEY");
return [cert.toString("pem"), pem];
}
// return [csr, private_key]
async function gen_csr() {
const keys = await crypto.subtle.generateKey(algorithm, true, [
"sign",
"verify",
]);
const csr = await x509.Pkcs10CertificateRequestGenerator.create({
name: "CN=ignored",
keys,
signingAlgorithm: algorithm,
extensions: [
new x509.KeyUsagesExtension(
x509.KeyUsageFlags.digitalSignature | x509.KeyUsageFlags.keyEncipherment
),
],
attributes: [
//new x509.ChallengePasswordAttribute("password"),
],
});
const prv = await crypto.subtle.exportKey("pkcs8", keys.privateKey);
return [csr.toString("pem"), x509.PemConverter.encode(prv, "PRIVATE KEY")];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment