Skip to content

Instantly share code, notes, and snippets.

@codermapuche
Last active November 30, 2018 08:51
Show Gist options
  • Save codermapuche/da4f96cdb6d5ff53b7ebc156ec46a10a to your computer and use it in GitHub Desktop.
Save codermapuche/da4f96cdb6d5ff53b7ebc156ec46a10a to your computer and use it in GitHub Desktop.
function safe64(data) {
if ( !Buffer.isBuffer(data) ) {
if (typeof data !== 'string') {
data = Buffer.from(JSON.stringify(data)).toString('base64');
}
} else {
data = data.toString('base64');
}
return data.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, '');
}
function text2hex(txt) {
for (var n = 0, hex = ''; n < txt.length; n++) {
hex += ('0' + Number(txt.charCodeAt(n)).toString(16)).slice(-2);
}
return hex;
}
function hexLength(length) {
length = '0' + Number(length / 2).toString(16);
length = length.slice(-(length.length - length.length % 2));
return length;
}
function ecdsa(d, x, y) {
if (!d || !x || !y) {
const ecdh = crypto.createECDH('prime256v1');
ecdh.generateKeys();
d = ecdh.getPrivateKey();
x = ecdh.getPublicKey().slice(1, 33);
y = ecdh.getPublicKey().slice(33);
}
this.d = d;
this.x = x;
this.y = y;
}
ecdsa.prototype.sign = function sign(message, isRaw) {
const signer = crypto.createSign('RSA-SHA256');
signer.update(message);
signer.end();
if (isRaw) {
return signer.sign(this.toPEM());
}
var signature = signer.sign(this.toPEM()),
rLength = parseInt(signature.slice(3, 4).toString('hex'), 16),
r = signature.slice(4, 4 + rLength),
sLength = parseInt(signature.slice(5 + rLength, 6 + rLength).toString('hex'), 16),
s = signature.slice(6 + rLength, 6 + rLength + sLength);
while(r[0] == 0) { r = r.slice(1); }
while(s[0] == 0) { s = s.slice(1); }
return Buffer.concat([ r, s ]);
}
ecdsa.prototype.toCSR = function toCSR(domain, isRaw) {
var domainHex = text2hex(domain),
segments = Buffer.from('3082' + hexLength(domainHex.length + 488) +
'0201003081' + hexLength(domainHex.length + 290) +
'310B' +
'30090603550406130241523115301306' +
'035504080C0C4275656E6F7320416972' +
'65733112301006035504070C09436869' +
'76696C636F793110300E060355040A0C' +
'0743726176696E673111300F06035504' +
'0B0C08536F66747761726531' + hexLength(domainHex.length + 18) +
'30' + hexLength(domainHex.length + 14) + '06' +
'03550403' +
'0C' + hexLength(domainHex.length) + domainHex +
'3127302506092A864886F70D' +
'01090116187765626D61737465724063' +
'726176696E672E636F6D2E6172305930' +
'1306072A8648CE3D020106082A8648CE' +
'3D03010703420004' +
this.x.toString('hex') +
this.y.toString('hex') +
'A000', 'hex'),
signature = this.sign(segments, true).toString('hex'),
content = segments.toString('hex') +
'300A06082A8648CE3D04030203' + hexLength(signature.length + 2) + '00' +
signature,
certificate = Buffer.from('3082' + hexLength(content.length) + content, 'hex').toString('base64'),
csr = '-----BEGIN CERTIFICATE REQUEST-----\n' +
certificate.match(/.{1,64}/g)
.join('\n') + '\n' +
'-----END CERTIFICATE REQUEST-----';
fs.writeFileSync(domain.replace(/\*/g, '()') + '.csr', csr);
if (isRaw) {
return safe64(certificate);
}
return csr;
}
ecdsa.prototype.toThumbprint = function toThumbprint() {
return safe64(crypto.createHash('sha256').update(JSON.stringify(this.toJWK(true))).digest('base64'));
}
ecdsa.prototype.toJWK = function toJWK(isPublic) {
var jwk = {
crv: 'P-256',
d: safe64(this.x),
kty: 'EC',
x: safe64(this.x),
y: safe64(this.y)
}
if (isPublic) {
delete jwk.d;
}
return jwk;
}
ecdsa.prototype.toPEM = function toPEM() {
return '-----BEGIN EC PRIVATE KEY-----\n' +
Buffer.from('30770201010420' +
this.d.toString('hex') +
'A00A06082A8648CE3D030107A144034200' +
Buffer.concat([ Buffer.from([0x04]), this.x, this.y ]).toString('hex'), 'hex')
.toString('base64')
.match(/.{1,64}/g)
.join('\n') + '\n' +
'-----END EC PRIVATE KEY-----';
}
//----
var myKey = new ecdsa();
console.log(myKey.toCSR('example.com'));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment