UNPKG

tizen-tv-dev-cli

Version:
382 lines (309 loc) 14.4 kB
var fs = require('fs'); var path = require('path'); var crypto = require('crypto'); var forge = require('node-forge'); var Buffer = require('buffer').Buffer; var parseString = require('xml2js').parseString; //var common = require('./common'); var extensionPath = __dirname; var ResourcePath = extensionPath + '/resource'; var profileFile = ResourcePath + '/profiles.xml'; var moduleName = 'P12ToPem'; var certificatesPath = extensionPath + '/resource/certificate-generator/certificates/'; var ACTIVE_PEM_FILE = { 'AUTHOR_KEY_FILE': certificatesPath + 'developer/active_cert/tizen_developer_private_key.pem', 'AUTHOR_CERT_FILE': certificatesPath + 'developer/active_cert/tizen_developer_cert.pem', 'DISTRIBUTOR_KEY_FILE': certificatesPath + 'distributor/active_cert/tizen_distributor_private_key.pem', 'DISTRIBUTOR_CERT_FILE': certificatesPath + 'distributor/active_cert/tizen_distributor_cert.pem', 'DISTRIBUTOR2_KEY_FILE': certificatesPath + 'distributor/active_cert/tizen_distributor2_private_key.pem', 'DISTRIBUTOR2_CERT_FILE': certificatesPath + 'distributor/active_cert/tizen_distributor2_cert.pem' }; exports.ACTIVE_PEM_FILE = ACTIVE_PEM_FILE; var activeProfile = ''; var authorFile = ''; var distributorFile = ''; var authorPassword = ''; var distributorPassword = ''; var distributorFile2 = ''; var distributorPassword2 = ''; /** * Extract the private key from a PKCS12 file. * @param {Buffer|String(Base64-encoded)} p12Buffer * The PKCS12 file as a buffer or base-64 encoded string. * @param {String} password The password for the PKCS12 file. * @param {String} type The type of PKCS12 file ,developer or distributor. * @param {String} keyfile The pem key file path. * @param {String} certfile The pem cert file path. */ function p12ToPem(p12Buffer, password, type, keyfile, certfile) { console.log(`${moduleName}: ================Converting ${type} P12 file to Pem file`); var entry = parseCertificate(p12Buffer, password); if (!entry) { console.log(`${moduleName}: Parse Certififate failed`); //common.showMsgOnWindow(common.ENUM_WINMSG_LEVEL.ERROR, 'Parse Certififate failed'); throw 'Parse Certififate failed'; } //Write map content to file if (entry.privateKey) { var privateKeyP12Pem = forge.pki.privateKeyToPem(entry.privateKey); //console.log('\nPrivate Key:'); //console.log(privateKeyP12Pem); createDir(certificatesPath + type + '/active_cert'); fs.writeFileSync(keyfile, privateKeyP12Pem, 'utf8'); console.log(`${moduleName}: Converted pem private key file is in ${keyfile}`); } else { console.log(''); } //console.log('certChain.length:'+entry.certChain.length); var certChainData = ''; if (entry.certChain.length > 0) { var certChain = entry.certChain; for (var i = 0; i < certChain.length; ++i) { var certP12Pem = forge.pki.certificateToPem(certChain[i]); certChainData = certChainData + certP12Pem; } } //console.log('\nCert Content:'); //console.log(certChainData); createDir(certificatesPath + type + '/active_cert'); fs.writeFileSync(certfile, certChainData, 'utf8'); console.log(`${moduleName}: Converted pem cert file is in ${certfile}`); } function parseCertificate(p12Buffer, password) { console.log(`${moduleName}: Start Parse Certificate`); var p12Der = p12Buffer.toString(); var pkcs12Asn1; var pkcs12; try { pkcs12Asn1 = forge.asn1.fromDer(p12Der); pkcs12 = forge.pkcs12.pkcs12FromAsn1(pkcs12Asn1, password || ''); } catch (ex) { //For case p12 author cert created by Tizen Studio var p12Base64 = p12Buffer.toString('base64'); p12Der = forge.util.decode64(p12Base64); try { pkcs12Asn1 = forge.asn1.fromDer(p12Der); pkcs12 = forge.pkcs12.pkcs12FromAsn1(pkcs12Asn1, password || ''); } catch (e) { console.log(`${moduleName}: Parse certificate failed, the password may not match the certificate`); console.log(`${moduleName}: ${ex.message}`); throw e; } } // load keypair and cert chain from safe content(s) and map to key ID var map = {}; for (var sci = 0; sci < pkcs12.safeContents.length; ++sci) { var safeContents = pkcs12.safeContents[sci]; var localKeyId = null; for (var sbi = 0; sbi < safeContents.safeBags.length; ++sbi) { var safeBag = safeContents.safeBags[sbi]; if (safeBag.attributes.localKeyId) { localKeyId = forge.util.bytesToHex(safeBag.attributes.localKeyId[0]); if (!(localKeyId in map)) { map[localKeyId] = { privateKey: null, certChain: [] }; } } // this bag has a private key if (safeBag.type === forge.pki.oids.pkcs8ShroudedKeyBag) { map[localKeyId].privateKey = safeBag.key; } else if (safeBag.type === forge.pki.oids.certBag) { // this bag has a certificate map[localKeyId].certChain.push(safeBag.cert); } } } var entry; //Get cert attributes for (var localKeyId in map) { entry = map[localKeyId]; } return entry; } function getCertificateInfo(certPath, password) { var afterYear = ''; var issuerName = ''; if (fs.existsSync(certPath)) { var p12Buffer = fs.readFileSync(certPath); var decodePass = decryptPassword(password); var entry = parseCertificate(p12Buffer, decodePass); if (!entry) { console.log(`${moduleName}: Parse Certififate failed`); //common.showMsgOnWindow(common.ENUM_WINMSG_LEVEL.ERROR, 'Parse Certififate failed'); throw 'Parse Certififate failed'; } var certChain = entry.certChain; certChain = certChain.slice(0); var certs = certChain.slice(0); var parsecert = certChain.shift(); //console.log('cert.validity.notBefore :'+parsecert.validity.notBefore); //var beforeDate = parsecert.validity.notBefore; var afterDate = parsecert.validity.notAfter; afterYear = afterDate.toString(); afterYear = afterYear.substring(3, 15); issuerName = ''; for (var j = 0; j < parsecert.issuer.attributes.length; j++) { var name = parsecert.issuer.attributes[j].name; var value = parsecert.issuer.attributes[j].value; if (name == 'commonName') { issuerName = value; break; } } } else { var noCert = certPath + " is not exist ,can't get the certificate info"; console.log(`${moduleName}: ${noCert}`); //common.showMsgOnWindow(common.ENUM_WINMSG_LEVEL.WARNING, noCert); throw noCert; } return { afterYear, issuerName }; } exports.getCertificateInfo = getCertificateInfo; // load and parse profiles.xml function loadProfile() { console.log(`${moduleName}: ================Load Profile`); var profileFlag = false; authorFile = ''; distributorFile = ''; activeProfile = ''; authorPassword = ''; distributorPassword = ''; distributorFile2 = ''; distributorPassword2 = ''; if (fs.existsSync(profileFile)) { console.log(`${moduleName}: Profile file path: ${profileFile}`); var data = fs.readFileSync(profileFile, 'utf-8'); //parse profiles.xml file to get author and distributor p12 certificate file parseString(data, { explicitArray: false }, function (err, result) { var jsonData = JSON.stringify(result); var jsonArray = JSON.parse(jsonData); activeProfile = jsonArray.profiles.$.active; if (typeof (activeProfile) != 'undefined') { console.log(`${moduleName}: Active profile name: ${activeProfile}`); var profiles = jsonArray.profiles.profile; var profileItems; if (profiles && (!profiles.length)) { //For only one profile case profileItems = profiles.profileitem; } else if (profiles && profiles.length) { //For multiple profile case for (var i = 0; i < profiles.length; i++) { var name = profiles[i].$.name; if (activeProfile == name) { profileItems = profiles[i].profileitem; } } } if (typeof (profileItems) != 'undefined' && profileItems.length > 2) { console.log(`${moduleName}: Find active profile: ${activeProfile}`); var tmpAuthorFile = __dirname + profileItems[0].$.key; if (!fs.existsSync(profileItems[0].$.key) && profileItems[0].$.key.length > 0 && fs.existsSync(tmpAuthorFile)) { authorFile = tmpAuthorFile; } else { authorFile = profileItems[0].$.key; } var tmpDistributorFile = __dirname + profileItems[1].$.key; if (!fs.existsSync(profileItems[1].$.key) && profileItems[1].$.key.length > 0 && fs.existsSync(tmpDistributorFile)) { distributorFile = tmpDistributorFile; } else { distributorFile = profileItems[1].$.key; } var tmpDistributorFile2 = __dirname + profileItems[2].$.key;; if (fs.existsSync(profileItems[2].$.key)) { distributorFile2 = profileItems[2].$.key; } else if (profileItems[2].$.key.length > 0 && fs.existsSync(tmpDistributorFile2)) { distributorFile2 = tmpDistributorFile2; } authorPassword = profileItems[0].$.password; distributorPassword = profileItems[1].$.password; distributorPassword2 = profileItems[2].$.password; if (fs.existsSync(authorFile) && fs.existsSync(distributorFile)) { console.log(`${moduleName}: Developer p12 File: ${authorFile}`); console.log(`${moduleName}: Distributor p12 File: ${distributorFile}`); profileFlag = true; } } } }); } return profileFlag; } exports.loadProfile = loadProfile; function getDistributorFile2() { return distributorFile2; } exports.getDistributorFile2 = getDistributorFile2; // Handle 'Create Web Project' commands function checkActiveProfile() { console.log(`${moduleName}: ================Check Active Profile`); var flag = loadProfile(); if (flag) { var authorP12Buffer = fs.readFileSync(authorFile); //var authorCertName = path.basename(authorFile, '.p12'); var distributorP12Buffer = fs.readFileSync(distributorFile); //var distributorCertName = path.basename(distributorFile, '.p12'); console.log(`${moduleName}: authorPassword: ${authorPassword}`); console.log(`${moduleName}: distributorPassword: ${distributorPassword}`); var decodedAuthorPass = decryptPassword(authorPassword); var decodedDistributorPass = decryptPassword(distributorPassword); console.log(`${moduleName}: decodedAuthorPass: ${decodedAuthorPass}`); console.log(`${moduleName}: decodedDistributorPass: ${decodedDistributorPass}`); p12ToPem(authorP12Buffer, decodedAuthorPass, 'developer', ACTIVE_PEM_FILE.AUTHOR_KEY_FILE, ACTIVE_PEM_FILE.AUTHOR_CERT_FILE); p12ToPem(distributorP12Buffer, decodedDistributorPass, 'distributor', ACTIVE_PEM_FILE.DISTRIBUTOR_KEY_FILE, ACTIVE_PEM_FILE.DISTRIBUTOR_CERT_FILE); console.log(distributorFile2); if (fs.existsSync(distributorFile2)) { var distributorP12Buffer2 = fs.readFileSync(distributorFile2); var decodeDistributor2Pass = decryptPassword(distributorPassword2); p12ToPem(distributorP12Buffer2, decodeDistributor2Pass, 'distributor', ACTIVE_PEM_FILE.DISTRIBUTOR2_KEY_FILE, ACTIVE_PEM_FILE.DISTRIBUTOR2_CERT_FILE); } } else { var warningMsg = 'No Active certificate profile for building the package on ' + process.platform + ', you can create new profile or set active by Certificate Manager'; console.log(`${moduleName}: ${warningMsg}`); //common.showMsgOnWindow(common.ENUM_WINMSG_LEVEL.WARNING, warningMsg); //throw waringMsg; } } exports.checkActiveProfile = checkActiveProfile; function encryptPassword(password) { //crypto.cipher encrypt var iv = new Buffer(0); var key = 'KYANINYLhijklmnopqrstuvw'; var cipher = crypto.createCipheriv('des-ede3', new Buffer(key), iv); cipher.setAutoPadding(true); //default true var ciph = cipher.update(password, 'utf8', 'hex'); ciph += cipher.final('hex'); //base64 encode var b1 = new Buffer(ciph, 'hex'); var s1 = b1.toString('base64'); return s1; } exports.encryptPassword = encryptPassword; function decryptPassword(password) { //base64 decode var baseBuffer = new Buffer(password, 'base64'); var hexCode = baseBuffer.toString('hex'); //crypto.decipher decrypt var iv = new Buffer(0); var key = 'KYANINYLhijklmnopqrstuvw'; var decipher = crypto.createDecipheriv('des-ede3', new Buffer(key), iv); decipher.setAutoPadding(true); var txt = decipher.update(hexCode, 'hex', 'utf8'); txt += decipher.final('utf8'); return txt; } exports.decryptPassword = decryptPassword; function createDir(dirPath) { if (!fs.existsSync(dirPath)) { console.log(`${moduleName}: Create dir path:${dirPath}`); try { fs.mkdirSync(dirPath); } catch (ex) { console.log(`${moduleName}: ${ex.message}`); throw ex; } } else { console.log(`${moduleName}: ${dirPath} is exist`); } } exports.createDir = createDir;