'use strict'
var openssl = require('./openssl.js')
var helper = require('./helper.js')
var {debug} = require('./debug.js')
// PEM format: .pem, .crt, .cer (!bin), .key
// base64 encoded; the cert file might also include the private key; so key file is optional
// DER format: .der, .cer (bin)
// binary encoded format; cannot include key file
// PKCS#7 / P7B format: .p7b, .p7c
// contains cert and ca chain cert files, but not the key file
// A PKCS7 certificate is serialized using either PEM or DER format.
// PKCS#12 / PFX format: .pfx, .p12
// contains all files: key file, cert and ca chain cert files
/**
* pem convert module
*
* @module convert
*/
/**
* conversion from PEM to DER format
* if private key is included in PEM encoded file, it won't be included in DER file
* use this method with type 'rsa' to export private key in that case
* @param {String} pathIN path of the PEM encoded certificate file
* @param {String} pathOUT path of the DER encoded certificate file to generate
* @param {String} [type] type of file, use 'rsa' for key file, 'x509' otherwise or leave this parameter out
* @param {Function} callback callback method called with error, boolean result
*/
module.exports.PEM2DER = function (pathIN, pathOUT, type, callback) {
if (!callback && typeof type === 'function') {
callback = type
type = 'x509'
}
var params = [
type,
'-outform',
'der',
'-in',
pathIN,
'-out',
pathOUT
]
openssl.spawnWrapper(params, false, function (error, code) {
if (error) {
callback(error)
} else {
callback(null, code === 0)
}
})
}
/**
* conversion from DER to PEM format
* @param {String} pathIN path of the DER encoded certificate file
* @param {String} pathOUT path of the PEM encoded certificate file to generate
* @param {String} [type] type of file, use 'rsa' for key file, 'x509' otherwise or leave this parameter out
* @param {Function} callback callback method called with error, boolean result
*/
module.exports.DER2PEM = function (pathIN, pathOUT, type, callback) {
if (!callback && typeof type === 'function') {
callback = type
type = 'x509'
}
var params = [
type,
'-inform',
'der',
'-in',
pathIN,
'-out',
pathOUT
]
openssl.spawnWrapper(params, false, function (error, code) {
if (error) {
callback(error)
} else {
callback(null, code === 0)
}
})
}
/**
* conversion from PEM to P7B format
* @param {Object} pathBundleIN paths of the PEM encoded certificate files ({cert: '...', ca: '...' or ['...', ...]})
* @param {String} pathOUT path of the P7B encoded certificate file to generate
* @param {Function} callback callback method called with error, boolean result
*/
module.exports.PEM2P7B = function (pathBundleIN, pathOUT, callback) {
var params = [
'crl2pkcs7',
'-nocrl',
'-certfile',
pathBundleIN.cert,
'-out',
pathOUT
]
if (pathBundleIN.ca) {
if (!Array.isArray(pathBundleIN.ca)) {
pathBundleIN.ca = [pathBundleIN.ca]
}
pathBundleIN.ca.forEach(function (ca) {
params.push('-certfile')
params.push(ca)
})
}
openssl.spawnWrapper(params, false, function (error, code) {
if (error) {
callback(error)
} else {
callback(null, code === 0)
}
})
}
/**
* conversion from P7B to PEM format
* @param {String} pathIN path of the P7B encoded certificate file
* @param {String} pathOUT path of the PEM encoded certificate file to generate
* @param {Function} callback callback method called with error, boolean result
*/
module.exports.P7B2PEM = function (pathIN, pathOUT, callback) {
var params = [
'pkcs7',
'-print_certs',
'-in',
pathIN,
'-out',
pathOUT
]
openssl.spawnWrapper(params, false, function (error, code) {
if (error) {
callback(error)
} else {
callback(null, code === 0)
}
})
}// TODO: CA also included?
/**
* conversion from PEM to PFX
* @param {Object} pathBundleIN paths of the PEM encoded certificate files ({cert: '...', key: '...', ca: '...' or ['...', ...]})
* @param {String} pathOUT path of the PFX encoded certificate file to generate
* @param {String} password password to set for accessing the PFX file
* @param {Function} callback callback method called with error, boolean result
*/
module.exports.PEM2PFX = function (pathBundleIN, pathOUT, password, callback) {
var params = [
'pkcs12',
'-export',
'-out',
pathOUT,
'-inkey',
pathBundleIN.key,
'-in',
pathBundleIN.cert
]
if (pathBundleIN.ca) {
if (!Array.isArray(pathBundleIN.ca)) {
pathBundleIN.ca = [pathBundleIN.ca]
}
pathBundleIN.ca.forEach(function (ca) {
params.push('-certfile')
params.push(ca)
})
}
var delTempPWFiles = []
helper.createPasswordFile({ cipher: '', password: password, passType: 'in' }, params, delTempPWFiles)
helper.createPasswordFile({ cipher: '', password: password, passType: 'out' }, params, delTempPWFiles)
openssl.spawnWrapper(params, false, function (error, code) {
function done (error) {
if (error) {
callback(error)
} else {
callback(null, code === 0)
}
}
helper.deleteTempFiles(delTempPWFiles, function (fsErr) {
done(error || fsErr)
})
})
}
/**
* conversion from PFX to PEM
* @param {Object} pathIN path of the PFX encoded certificate file
* @param {String} pathOUT path of the PEM encoded certificate file to generate
* @param {String} password password to set for accessing the PFX file
* @param {Function} callback callback method called with error, boolean result
*/
module.exports.PFX2PEM = function (pathIN, pathOUT, password, callback) {
var params = [
'pkcs12',
'-in',
pathIN,
'-out',
pathOUT,
'-nodes'
]
var delTempPWFiles = []
helper.createPasswordFile({ cipher: '', password: password, passType: 'in' }, params, delTempPWFiles)
helper.createPasswordFile({ cipher: '', password: password, passType: 'out' }, params, delTempPWFiles)
openssl.spawnWrapper(params, false, function (error, code) {
function done (error) {
if (error) {
callback(error)
} else {
callback(null, code === 0)
}
}
helper.deleteTempFiles(delTempPWFiles, function (fsErr) {
done(error || fsErr)
})
})
}
/**
* conversion from P7B to PFX/PKCS#12
* @param {Object} pathBundleIN paths of the PEM encoded certificate files ({cert: '...', key: '...', ca: '...' or ['...', ...]})
* @param {String} pathOUT path of the PFX certificate file to generate
* @param {String} password password to be set for the PFX file and to be used to access the key file
* @param {Function} callback callback method called with error, boolean result
*/
module.exports.P7B2PFX = function (pathBundleIN, pathOUT, password, callback) {
var tmpfile = pathBundleIN.cert.replace(/\.[^.]+$/, '.cer')
var params = [
'pkcs7',
'-print_certs',
'-in',
pathBundleIN.cert,
'-out',
tmpfile
]
openssl.spawnWrapper(params, false, function (error, code) {
debug("P7B2PFX", {
error, code
})
if (error) {
callback(error)
} else {
var params = [
'pkcs12',
'-export',
'-in',
tmpfile,
'-inkey',
pathBundleIN.key,
'-out',
pathOUT
]
if (pathBundleIN.ca) {
if (!Array.isArray(pathBundleIN.ca)) {
pathBundleIN.ca = [pathBundleIN.ca]
}
pathBundleIN.ca.forEach(function (ca) {
params.push('-certfile')
params.push(ca)
})
}
var delTempPWFiles = [tmpfile]
helper.createPasswordFile({ cipher: '', password: password, passType: 'in' }, params, delTempPWFiles)
helper.createPasswordFile({ cipher: '', password: password, passType: 'out' }, params, delTempPWFiles)
openssl.spawnWrapper(params, false, function (error, code) {
function done (error) {
if (error) {
callback(error)
} else {
callback(null, code === 0)
}
}
helper.deleteTempFiles(delTempPWFiles, function (fsErr) {
done(error || fsErr)
})
})
}
})
}