149 lines
2.5 KiB
JavaScript
149 lines
2.5 KiB
JavaScript
/*!
|
|
* pem.js - pem parsing for bcoin
|
|
* Copyright (c) 2016-2017, Christopher Jeffrey (MIT License).
|
|
* https://github.com/bcoin-org/bcoin
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
const assert = require('assert');
|
|
|
|
/**
|
|
* @exports utils/pem
|
|
*/
|
|
|
|
const PEM = exports;
|
|
|
|
/**
|
|
* Parse PEM into separated chunks.
|
|
* @param {String} pem
|
|
* @returns {Object[]}
|
|
* @throws on parse error
|
|
*/
|
|
|
|
PEM.parse = function parse(pem) {
|
|
const chunks = [];
|
|
let chunk = '';
|
|
let tag;
|
|
|
|
while (pem.length) {
|
|
let m;
|
|
|
|
m = /^-----BEGIN ([^\-]+)-----/.exec(pem);
|
|
if (m) {
|
|
pem = pem.substring(m[0].length);
|
|
tag = m[1];
|
|
continue;
|
|
}
|
|
|
|
m = /^-----END ([^\-]+)-----/.exec(pem);
|
|
if (m) {
|
|
pem = pem.substring(m[0].length);
|
|
|
|
assert(tag === m[1], 'Tag mismatch.');
|
|
|
|
const type = tag.split(' ')[0].toLowerCase();
|
|
const data = Buffer.from(chunk, 'base64');
|
|
|
|
chunks.push({
|
|
tag: tag,
|
|
type: type,
|
|
data: data
|
|
});
|
|
|
|
chunk = '';
|
|
tag = null;
|
|
|
|
continue;
|
|
}
|
|
|
|
m = /^[a-zA-Z0-9\+=\/]+/.exec(pem);
|
|
if (m) {
|
|
pem = pem.substring(m[0].length);
|
|
chunk += m[0];
|
|
continue;
|
|
}
|
|
|
|
m = /^\s+/.exec(pem);
|
|
if (m) {
|
|
pem = pem.substring(m[0].length);
|
|
continue;
|
|
}
|
|
|
|
throw new Error('PEM parse error.');
|
|
}
|
|
|
|
assert(chunks.length !== 0, 'PEM parse error.');
|
|
assert(!tag, 'Un-ended tag.');
|
|
assert(chunk.length === 0, 'Trailing data.');
|
|
|
|
return chunks;
|
|
};
|
|
|
|
/**
|
|
* Decode PEM into a manageable format.
|
|
* @param {String} pem
|
|
* @returns {Object}
|
|
* @throws on parse error
|
|
*/
|
|
|
|
PEM.decode = function decode(pem) {
|
|
const chunks = PEM.parse(pem);
|
|
const body = chunks[0];
|
|
const extra = chunks[1];
|
|
|
|
let params = null;
|
|
|
|
if (extra) {
|
|
if (extra.tag.indexOf('PARAMETERS') !== -1)
|
|
params = extra.data;
|
|
}
|
|
|
|
let alg = null;
|
|
|
|
switch (body.type) {
|
|
case 'dsa':
|
|
alg = 'dsa';
|
|
break;
|
|
case 'rsa':
|
|
alg = 'rsa';
|
|
break;
|
|
case 'ec':
|
|
alg = 'ecdsa';
|
|
break;
|
|
}
|
|
|
|
return {
|
|
type: body.type,
|
|
alg: alg,
|
|
data: body.data,
|
|
params: params
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Encode DER to PEM.
|
|
* @param {Buffer} der
|
|
* @param {String} type - e.g. "ec".
|
|
* @param {String?} suffix - e.g. "public key".
|
|
* @returns {String}
|
|
*/
|
|
|
|
PEM.encode = function encode(der, type, suffix) {
|
|
let pem = '';
|
|
|
|
if (suffix)
|
|
type += ' ' + suffix;
|
|
|
|
type = type.toUpperCase();
|
|
der = der.toString('base64');
|
|
|
|
for (let i = 0; i < der.length; i += 64)
|
|
pem += der.slice(i, i + 64) + '\n';
|
|
|
|
return ''
|
|
+ `-----BEGIN ${type}-----\n`
|
|
+ pem
|
|
+ `-----END ${type}-----\n`;
|
|
};
|