-
Notifications
You must be signed in to change notification settings - Fork 0
/
caLib.js
153 lines (135 loc) · 4.96 KB
/
caLib.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
const forge = require('node-forge'),
path = require('path'),
fs = require('fs'),
crypto = require('crypto');
const pki = forge.pki
//using a blank options is perfectly fine here
async function genCACert(options = {}) {
options = {...{
commonName: 'Client Proxy Testing CA - DO NOT TRUST',
bits: 2048,
SAN: []
}, ...options}
let keyPair = await new Promise((res, rej) => {
pki.rsa.generateKeyPair({ bits: options.bits }, (error, pair) => {
if (error) rej(error);
else res(pair)
})
})
let cert = pki.createCertificate()
cert.publicKey = keyPair.publicKey
cert.serialNumber = crypto.randomUUID().replace(/-/g, '')
cert.validity.notBefore = new Date()
cert.validity.notBefore.setDate(cert.validity.notBefore.getDate() - 1)
cert.validity.notAfter = new Date()
cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 1)
let extensions = [{ name: 'basicConstraints', cA: true }]
if(options.SAN instanceof Array && options.SAN.length > 0) {
let sanExtension = {name: 'subjectAltName', altNames: []}
let SAN = options.SAN
let altNames = sanExtension.altNames
for(let name of SAN) {
if(typeof(name) == 'string') {
let type = 2
//if is ip address
let ipmatch = name.match(/\b\d{1,3}\.\d{1,3}\.\d{1,3}.\d{1,3}\b/)
if(ipmatch != null) {
name = ipmatch[0]
type = 7
}
let extension = {type}
switch(type) {
case 7:
extension.ip = name;
break;
default:
extension.value = name;
break;
}
altNames.push(extension)
}
}
extensions.push(sanExtension)
}
cert.setSubject([{name: 'commonName', value: options.commonName}])
cert.setExtensions(extensions)
cert.setIssuer(cert.subject.attributes)
cert.sign(keyPair.privateKey, forge.md.sha256.create())
return {
ca: {
key: pki.privateKeyToPem(keyPair.privateKey),
cert: pki.certificateToPem(cert)
},
fingerprint: getFingerprint(keyPair.publicKey),
publicKey: pki.publicKeyToPem(keyPair.publicKey)
}
}
function getFingerprint(publicKey) {
return forge.util.encode64(
pki.getPublicKeyFingerprint(publicKey, {
type: 'SubjectPublicKeyInfo',
md: forge.md.sha256.create(),
encoding: 'binary'
})
);
}
//you need to put the output from genCACert() through this if you want to use it for a https server
/* e.g
let cert = genCACert()
let buffers = caToBuffer(cert.ca)
let options = {}
options.key = buffers.key
options.cert = buffers.cert
let server = https.createServer(options, <listener here>)
*/
function caToBuffer(ca) {
return {
key: Buffer.from(ca.key),
cert: Buffer.from(ca.cert)
}
}
async function loadOrCreateCertificate(options={}) {
let dir = path.dirname(require.main.filename)
options = {...{
folder: './certificate',
generateOptions: {},
certName: 'certificate.pem',
keyName: 'key.pem',
pubKeyName: 'pubkey.pem'
}, ...options}
let folder = path.resolve(dir, options.folder)
let certpath = path.join(folder, options.certName)
let keypath = path.join(folder, options.keyName)
let pubkeypath = path.join(folder, options.pubKeyName)
if(fs.existsSync(certpath) && fs.existsSync(keypath) && fs.existsSync(pubkeypath)) {
let cert = fs.readFileSync(certpath, {encoding: 'UTF-8'}).toString('UTF-8')
let key = fs.readFileSync(keypath, {encoding: 'UTF-8'}).toString('UTF-8')
let pubkey = fs.readFileSync(pubkeypath, {encoding: 'UTF-8'}).toString('UTF-8')
return {
ca: {
key: key,
cert: cert
},
fingerprint: getFingerprint(pki.publicKeyFromPem(pubkey)),
publicKey: pubkey
}
} else {
let cert = await genCACert(options.generateOptions)
try {
if(!fs.existsSync(folder)) {
fs.mkdirSync(folder)
}
fs.accessSync(folder)
!fs.existsSync(certpath) || fs.accessSync(certpath)
!fs.existsSync(keypath) || fs.accessSync(keypath)
!fs.existsSync(pubkeypath) || fs.accessSync(pubkeypath)
fs.writeFileSync(certpath, cert.ca.cert)
fs.writeFileSync(keypath, cert.ca.key)
fs.writeFileSync(pubkeypath, cert.publicKey)
} catch(e) {
console.log('An error occurred while trying to save the certificates! Do you have write permissions?')
}
return cert
}
}
module.exports = {genCACert, caToBuffer, loadOrCreateCertificate}