Add pkcs12chain.js and util.js

pkcs12chain returns a PFX with private key and cert chain.
Comes from: https://github.com/PeculiarVentures/PKI.js/issues/104

util.js contains various conversion functions, the asn1js examples
all use inline conversions so no pre-made functions available.

formatPEM.js came from pkijs examples (examples_common.js).
This commit is contained in:
pehmo1 2021-08-12 22:27:58 +03:00
parent 1ea20850e9
commit 54033346f9
2 changed files with 171 additions and 0 deletions

120
static/js/pkcs12chain.js Normal file
View File

@ -0,0 +1,120 @@
import * as asn1js from "asn1js";
import {
stringToArrayBuffer,
fromBase64,
} from "pvutils";
import {
getRandomValues
} from "../node_modules/pkijs/src/common.js";
import Certificate from "../node_modules/pkijs/src/Certificate.js";
import PrivateKeyInfo from "../node_modules/pkijs/src/PrivateKeyInfo";
import Attribute from "../node_modules/pkijs/src/Attribute";
import SafeBag from "../node_modules/pkijs/src/SafeBag";
import PKCS8ShroudedKeyBag from "../node_modules/pkijs/src/PKCS8ShroudedKeyBag";
import PFX from "../node_modules/pkijs/src/PFX";
import AuthenticatedSafe from "../node_modules/pkijs/src/AuthenticatedSafe";
import SafeContents from "../node_modules/pkijs/src/SafeContents";
import CertBag from "../node_modules/pkijs/src/CertBag";
export async function pkcs12chain(priv, certs, password, hash_alg) {
const asn1 = asn1js.fromBER(stringToArrayBuffer(fromBase64(priv)));
const pkcs8Simpl = new PrivateKeyInfo({schema: asn1.result});
const keyLocalIDBuffer = new ArrayBuffer(4);
const keyLocalIDView = new Uint8Array(keyLocalIDBuffer);
getRandomValues(keyLocalIDView);
const bitArray = new ArrayBuffer(1);
const bitView = new Uint8Array(bitArray);
bitView[0] = bitView[0] | 0x80;
const keyUsage = new asn1js.BitString({
valueHex: bitArray,
unusedBits: 7
});
pkcs8Simpl.attributes = [
new Attribute({
type: "2.5.29.15",
values: [
keyUsage
]
})
];
const safeBags = [
new SafeBag({
bagId: "1.2.840.113549.1.12.10.1.2",
bagValue: new PKCS8ShroudedKeyBag({
parsedValue: pkcs8Simpl
}),
bagAttributes: [
new Attribute({
type: "1.2.840.113549.1.9.21", // localKeyID
values: [
new asn1js.OctetString({valueHex: keyLocalIDBuffer})
]
})
]
})
];
const numCerts = certs.length;
for (let i=0;i<numCerts;i++) {
const asn1 = asn1js.fromBER(stringToArrayBuffer(fromBase64(certs[i])));
const certSimpl = new Certificate({schema: asn1.result});
const certLocalIDBuffer = new ArrayBuffer(4);
const certLocalIDView = new Uint8Array(certLocalIDBuffer);
getRandomValues(certLocalIDView);
safeBags.push(
new SafeBag({
bagId: "1.2.840.113549.1.12.10.1.3",
bagValue: new CertBag({
parsedValue: certSimpl
}),
bagAttributes: [
new Attribute({
type: "1.2.840.113549.1.9.21", // localKeyID
values: [
new asn1js.OctetString({valueHex: certLocalIDBuffer})
]
})
]
})
);
}
let pkcs12 = new PFX({
parsedValue: {
integrityMode: 0, // Password-Based Integrity Mode
authenticatedSafe: new AuthenticatedSafe({
parsedValue: {
safeContents: [
{
privacyMode: 0, // "No-privacy" Protection Mode
value: new SafeContents({
safeBags: safeBags
})
}
]
}
})
}
});
await pkcs12.parsedValue.authenticatedSafe.makeInternalValues({
safeContents: [{}]
});
await pkcs12.makeInternalValues({
password: stringToArrayBuffer(password),
iterations: 10000,
pbkdf2HashAlgorithm: hash_alg,
hmacHashAlgorithm: hash_alg
})
return pkcs12;
}

51
static/js/util.js Normal file
View File

@ -0,0 +1,51 @@
import * as asn1js from "asn1js";
import {
arrayBufferToString,
stringToArrayBuffer,
toBase64,
fromBase64,
bufferToHexCodes
} from "pvutils";
import {
getCrypto,
getAlgorithmParameters,
} from "../node_modules/pkijs/src/common.js";
import CertificationRequest from "../node_modules/pkijs/src/CertificationRequest.js";
import AttributeTypeAndValue from "../node_modules/pkijs/src/AttributeTypeAndValue.js";
import Certificate from "../node_modules/pkijs/src/Certificate.js";
import { formatPEM } from "./formatPEM.js";
export async function privKeyToBase64(privKey, crypto) {
return new Promise(async (resolve, reject) => {
let arrayBuf = new ArrayBuffer(0);
arrayBuf = await crypto.exportKey("pkcs8", privKey);
resolve(formatPEM(toBase64(arrayBufferToString(arrayBuf))));
});
}
export async function privKeyToPem(privKey, crypto) {
return new Promise(async (resolve, reject) => {
let privKeyExported = await crypto.exportKey("pkcs8", privKey);
let privKeyBody = formatPEM(
toBase64(
String.fromCharCode.apply(null, new Uint8Array(privKeyExported))
)
);
let privKeyPem = `-----BEGIN RSA PRIVATE KEY-----\r\n${privKeyBody}\r\n-----END RSA PRIVATE KEY-----\r\n`;
resolve(privKeyPem);
});
}
export async function certReqToPem(csr) {
return new Promise(async (resolve, reject) => {
let resPem = "-----BEGIN CERTIFICATE REQUEST-----\r\n";
resPem = `${resPem}${formatPEM(
toBase64(arrayBufferToString(csr.toSchema().toBER(false)))
)}`;
resPem = `${resPem}\r\n-----END CERTIFICATE REQUEST-----\r\n`;
resolve(resPem);
});
}