/
certificate.ts
145 lines (129 loc) · 3.26 KB
/
certificate.ts
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
// simplified fork of
// https://github.com/jfromaniello/selfsigned/blob/da38146f8d02183c35f49f91659a744a243e8707/index.js
// with inlined options and partial node-forge usage
// to achieve smaller bundle
//
// this utility create untrusted certificate which still
// allows to access page after proceeding a wall with warning
//
// should be deprecated eventually and replaced with recipes
// about generating secure trusted certificates
// @ts-ignore
import forge from 'node-forge/lib/forge'
// @ts-ignore
import 'node-forge/lib/pki'
// a hexString is considered negative if it's most significant bit is 1
// because serial numbers use ones' complement notation
// this RFC in section 4.1.2.2 requires serial numbers to be positive
// http://www.ietf.org/rfc/rfc5280.txt
function toPositiveHex(hexString: string) {
let mostSiginficativeHexAsInt = parseInt(hexString[0], 16)
if (mostSiginficativeHexAsInt < 8) {
return hexString
}
mostSiginficativeHexAsInt -= 8
return mostSiginficativeHexAsInt.toString() + hexString.substring(1)
}
export function createCertificate(): string {
const days = 30
const keySize = 2048
const extensions = [
// {
// name: 'basicConstraints',
// cA: true,
// },
{
name: 'keyUsage',
keyCertSign: true,
digitalSignature: true,
nonRepudiation: true,
keyEncipherment: true,
dataEncipherment: true
},
{
name: 'extKeyUsage',
serverAuth: true,
clientAuth: true,
codeSigning: true,
timeStamping: true
},
{
name: 'subjectAltName',
altNames: [
{
// type 2 is DNS
type: 2,
value: 'localhost'
},
{
type: 2,
value: 'localhost.localdomain'
},
{
type: 2,
value: 'lvh.me'
},
{
type: 2,
value: '*.lvh.me'
},
{
type: 2,
value: '[::1]'
},
{
// type 7 is IP
type: 7,
ip: '127.0.0.1'
},
{
type: 7,
ip: 'fe80::1'
}
]
}
]
const attrs = [
{
name: 'commonName',
value: 'example.org'
},
{
name: 'countryName',
value: 'US'
},
{
shortName: 'ST',
value: 'Virginia'
},
{
name: 'localityName',
value: 'Blacksburg'
},
{
name: 'organizationName',
value: 'Test'
},
{
shortName: 'OU',
value: 'Test'
}
]
const keyPair = forge.pki.rsa.generateKeyPair(keySize)
const cert = forge.pki.createCertificate()
cert.serialNumber = toPositiveHex(
forge.util.bytesToHex(forge.random.getBytesSync(9))
) // the serial number can be decimal or hex (if preceded by 0x)
cert.validity.notBefore = new Date()
cert.validity.notAfter = new Date()
cert.validity.notAfter.setDate(cert.validity.notBefore.getDate() + days)
cert.setSubject(attrs)
cert.setIssuer(attrs)
cert.publicKey = keyPair.publicKey
cert.setExtensions(extensions)
const algorithm = forge.md.sha256.create()
cert.sign(keyPair.privateKey, algorithm)
const privateKeyPem = forge.pki.privateKeyToPem(keyPair.privateKey)
const certPem = forge.pki.certificateToPem(cert)
return privateKeyPem + certPem
}