2017-08-28 12:27:45 -04:00
/ * *
* @ description Certificate generator
* @ author Joko Sastriawan / Ylian Saint - Hilaire
* @ version v0 . 0.1
* /
module . exports . CertificateOperations = function ( ) {
var obj = { } ;
obj . fs = require ( 'fs' ) ;
obj . forge = require ( 'node-forge' ) ;
obj . pki = obj . forge . pki ;
obj . dirExists = function ( filePath ) { try { return obj . fs . statSync ( filePath ) . isDirectory ( ) ; } catch ( err ) { return false ; } }
obj . getFilesizeInBytes = function ( filename ) { try { return obj . fs . statSync ( filename ) [ "size" ] ; } catch ( err ) { return - 1 ; } }
obj . fileExists = function ( filePath ) { try { return obj . fs . statSync ( filePath ) . isFile ( ) ; } catch ( err ) { return false ; } }
// Return the SHA256 hash of the certificate public key
obj . getPublicKeyHash = function ( cert ) {
var publickey = obj . pki . certificateFromPem ( cert ) . publicKey ;
return obj . pki . getPublicKeyFingerprint ( publickey , { encoding : 'hex' , md : obj . forge . md . sha256 . create ( ) } ) ;
}
// Create a self-signed certificate
obj . GenerateRootCertificate = function ( addThumbPrintToName , commonName , country , organization ) {
var keys = obj . pki . rsa . generateKeyPair ( 2048 ) ;
var cert = obj . pki . createCertificate ( ) ;
cert . publicKey = keys . publicKey ;
cert . serialNumber = '' + Math . floor ( ( Math . random ( ) * 100000 ) + 1 ) ; ;
cert . validity . notBefore = new Date ( ) ;
cert . validity . notBefore . setFullYear ( cert . validity . notBefore . getFullYear ( ) - 1 ) ; // Create a certificate that is valid one year before, to make sure out-of-sync clocks don't reject this cert.
cert . validity . notAfter = new Date ( ) ;
cert . validity . notAfter . setFullYear ( cert . validity . notAfter . getFullYear ( ) + 30 ) ;
if ( addThumbPrintToName == true ) { commonName += '-' + obj . pki . getPublicKeyFingerprint ( cert . publicKey , { encoding : 'hex' } ) . substring ( 0 , 6 ) ; }
var attrs = [ { name : 'commonName' , value : commonName } ] ;
if ( country != undefined ) attrs . push ( { name : 'countryName' , value : country } ) ;
if ( organization != undefined ) attrs . push ( { name : 'organizationName' , value : organization } ) ;
cert . setSubject ( attrs ) ;
cert . setIssuer ( attrs ) ;
cert . setExtensions ( [
{ name : 'basicConstraints' , cA : true } ,
{
name : 'nsCertType' ,
client : false ,
server : false ,
email : false ,
objsign : false ,
sslCA : true ,
emailCA : false ,
objCA : true
}
] ) ;
cert . sign ( keys . privateKey , obj . forge . md . sha256 . create ( ) ) ;
return { cert : cert , key : keys . privateKey } ;
}
// Issue a certificate from a root
obj . IssueWebServerCertificate = function ( rootcert , addThumbPrintToName , commonName , country , organization ) {
var keys = obj . pki . rsa . generateKeyPair ( 2048 ) ;
var cert = obj . pki . createCertificate ( ) ;
cert . publicKey = keys . publicKey ;
cert . serialNumber = '' + Math . floor ( ( Math . random ( ) * 100000 ) + 1 ) ; ;
cert . validity . notBefore = new Date ( ) ;
cert . validity . notBefore . setFullYear ( cert . validity . notAfter . getFullYear ( ) - 1 ) ; // Create a certificate that is valid one year before, to make sure out-of-sync clocks don't reject this cert.
cert . validity . notAfter = new Date ( ) ;
cert . validity . notAfter . setFullYear ( cert . validity . notAfter . getFullYear ( ) + 30 ) ;
if ( addThumbPrintToName == true ) { commonName += '-' + obj . pki . getPublicKeyFingerprint ( cert . publicKey , { encoding : 'hex' } ) . substring ( 0 , 6 ) ; }
var attrs = [ { name : 'commonName' , value : commonName } ] ;
if ( country != undefined ) attrs . push ( { name : 'countryName' , value : country } ) ;
if ( organization != undefined ) attrs . push ( { name : 'organizationName' , value : organization } ) ;
cert . setSubject ( attrs ) ;
cert . setIssuer ( rootcert . cert . subject . attributes ) ;
cert . setExtensions ( [ {
name : 'basicConstraints' ,
cA : false
} , {
name : 'keyUsage' ,
keyCertSign : true ,
digitalSignature : true ,
nonRepudiation : true ,
keyEncipherment : true ,
dataEncipherment : true
} , {
name : 'extKeyUsage' ,
serverAuth : true ,
clientAuth : false ,
codeSigning : false ,
emailProtection : false ,
timeStamping : false
} , {
name : 'nsCertType' ,
client : false ,
server : true ,
email : false ,
objsign : false ,
sslCA : false ,
emailCA : false ,
objCA : false
} , {
name : 'subjectAltName' ,
altNames : [ {
type : 6 , // URI
value : 'http://' + commonName + '/'
} , {
type : 6 , // URL
value : 'http://localhost/'
} ]
} , {
name : 'subjectKeyIdentifier'
} ] ) ;
cert . sign ( rootcert . key , obj . forge . md . sha256 . create ( ) ) ;
return { cert : cert , key : keys . privateKey } ;
}
// Returns the web server TLS certificate and private key, if not present, create demonstration ones.
obj . GetMeshServerCertificate = function ( directory , certargs , func ) {
// commonName, country, organization
// If the certificates directory does not exist, create it.
if ( ! obj . dirExists ( directory ) ) { obj . fs . mkdirSync ( directory ) ; }
var r = { } , rcount = 0 ;
// If the root certificate already exist, load it
if ( obj . fileExists ( directory + '/root-cert-public.crt' ) && obj . fileExists ( directory + '/root-cert-private.key' ) ) {
var rootCertificate = obj . fs . readFileSync ( directory + '/root-cert-public.crt' , 'utf8' ) ;
var rootPrivateKey = obj . fs . readFileSync ( directory + '/root-cert-private.key' , 'utf8' ) ;
r . root = { cert : rootCertificate , key : rootPrivateKey } ;
rcount ++ ;
}
// If the web certificate already exist, load it
if ( obj . fileExists ( directory + '/webserver-cert-public.crt' ) && obj . fileExists ( directory + '/webserver-cert-private.key' ) ) {
var webCertificate = obj . fs . readFileSync ( directory + '/webserver-cert-public.crt' , 'utf8' ) ;
var webPrivateKey = obj . fs . readFileSync ( directory + '/webserver-cert-private.key' , 'utf8' ) ;
r . web = { cert : webCertificate , key : webPrivateKey } ;
rcount ++ ;
}
// If the bin certificate already exist, load it
if ( obj . fileExists ( directory + '/mpsserver-cert-public.crt' ) && obj . fileExists ( directory + '/mpsserver-cert-private.key' ) ) {
var mpsCertificate = obj . fs . readFileSync ( directory + '/mpsserver-cert-public.crt' , 'utf8' ) ;
var mpsPrivateKey = obj . fs . readFileSync ( directory + '/mpsserver-cert-private.key' , 'utf8' ) ;
r . mps = { cert : mpsCertificate , key : mpsPrivateKey } ;
rcount ++ ;
}
// If the bin certificate already exist, load it
if ( obj . fileExists ( directory + '/agentserver-cert-public.crt' ) && obj . fileExists ( directory + '/agentserver-cert-private.key' ) ) {
var agentCertificate = obj . fs . readFileSync ( directory + '/agentserver-cert-public.crt' , 'utf8' ) ;
var agentPrivateKey = obj . fs . readFileSync ( directory + '/agentserver-cert-private.key' , 'utf8' ) ;
r . agent = { cert : agentCertificate , key : agentPrivateKey } ;
rcount ++ ;
}
2017-09-07 19:01:44 -04:00
// If CA certificates are present, load them
var caok , caindex = 1 , calist = [ ] ;
do {
caok = false ;
if ( obj . fileExists ( directory + '/webserver-cert-chain' + caindex + '.crt' ) ) {
var caCertificate = obj . fs . readFileSync ( directory + '/webserver-cert-chain' + caindex + '.crt' , 'utf8' ) ;
calist . push ( caCertificate ) ;
caok = true ;
}
caindex ++ ;
} while ( caok == true ) ;
r . calist = calist ;
2017-08-28 12:27:45 -04:00
// Decode certificate arguments
var commonName = 'un-configured' , country , organization ;
if ( certargs != undefined ) {
var args = certargs . split ( ',' ) ;
if ( args . length > 0 ) commonName = args [ 0 ] ;
if ( args . length > 1 ) country = args [ 1 ] ;
if ( args . length > 2 ) organization = args [ 2 ] ;
}
if ( rcount == 4 ) {
// Fetch the name of the server
var webCertificate = obj . pki . certificateFromPem ( r . web . cert ) ;
r . CommonName = webCertificate . subject . getField ( 'CN' ) . value ;
var rootCertificate = obj . pki . certificateFromPem ( r . root . cert ) ;
r . RootName = rootCertificate . subject . getField ( 'CN' ) . value ;
if ( certargs == undefined ) { if ( func != undefined ) { func ( r ) ; } return r } ; // If no certificate arguments are given, keep the certificate
var xcountry , xcountryField = webCertificate . subject . getField ( 'C' ) ;
if ( xcountryField != null ) { xcountry = xcountryField . value ; }
var xorganization , xorganizationField = webCertificate . subject . getField ( 'O' ) ;
if ( xorganizationField != null ) { xorganization = xorganizationField . value ; }
if ( ( r . CommonName == commonName ) && ( xcountry == country ) && ( xorganization == organization ) ) { if ( func != undefined ) { func ( r ) ; } return r ; } // If the certificate matches what we want, keep it.
}
console . log ( 'Generating certificates...' ) ;
var rootCertAndKey , rootCertificate , rootPrivateKey , rootName ;
if ( r . root == undefined ) {
// If the root certificate does not exist, create one
rootCertAndKey = obj . GenerateRootCertificate ( true , 'MeshCentralRoot' ) ;
rootCertificate = obj . pki . certificateToPem ( rootCertAndKey . cert ) ;
rootPrivateKey = obj . pki . privateKeyToPem ( rootCertAndKey . key ) ;
obj . fs . writeFileSync ( directory + '/root-cert-public.crt' , rootCertificate ) ;
obj . fs . writeFileSync ( directory + '/root-cert-private.key' , rootPrivateKey ) ;
} else {
// Keep the root certificate we have
rootCertAndKey = { cert : obj . pki . certificateFromPem ( r . root . cert ) , key : obj . pki . privateKeyFromPem ( r . root . key ) } ;
rootCertificate = r . root . cert
rootPrivateKey = r . root . key
}
var rootName = rootCertAndKey . cert . subject . getField ( 'CN' ) . value ;
// If the web certificate does not exist, create one
var webCertAndKey , webCertificate , webPrivateKey ;
webCertAndKey = obj . IssueWebServerCertificate ( rootCertAndKey , false , commonName , country , organization ) ;
webCertificate = obj . pki . certificateToPem ( webCertAndKey . cert ) ;
webPrivateKey = obj . pki . privateKeyToPem ( webCertAndKey . key ) ;
obj . fs . writeFileSync ( directory + '/webserver-cert-public.crt' , webCertificate ) ;
obj . fs . writeFileSync ( directory + '/webserver-cert-private.key' , webPrivateKey ) ;
// If the Intel AMT MPS certificate does not exist, create one
var mpsCertAndKey , mpsCertificate , mpsPrivateKey ;
mpsCertAndKey = obj . IssueWebServerCertificate ( rootCertAndKey , false , commonName , country , organization ) ;
mpsCertificate = obj . pki . certificateToPem ( mpsCertAndKey . cert ) ;
mpsPrivateKey = obj . pki . privateKeyToPem ( mpsCertAndKey . key ) ;
obj . fs . writeFileSync ( directory + '/mpsserver-cert-public.crt' , mpsCertificate ) ;
obj . fs . writeFileSync ( directory + '/mpsserver-cert-private.key' , mpsPrivateKey ) ;
// If the mesh agent server certificate does not exist, create one
var agentCertAndKey , agentCertificate , agentPrivateKey ;
if ( r . agent == undefined ) {
agentCertAndKey = obj . IssueWebServerCertificate ( rootCertAndKey , true , 'MeshCentralAgentServer' ) ;
agentCertificate = obj . pki . certificateToPem ( agentCertAndKey . cert ) ;
agentPrivateKey = obj . pki . privateKeyToPem ( agentCertAndKey . key ) ;
obj . fs . writeFileSync ( directory + '/agentserver-cert-public.crt' , agentCertificate ) ;
obj . fs . writeFileSync ( directory + '/agentserver-cert-private.key' , agentPrivateKey ) ;
} else {
// Keep the mesh agent server certificate we have
agentCertAndKey = { cert : obj . pki . certificateFromPem ( r . agent . cert ) , key : obj . pki . privateKeyFromPem ( r . agent . key ) } ;
agentCertificate = r . agent . cert
agentPrivateKey = r . agent . key
}
2017-09-07 19:01:44 -04:00
var r = { root : { cert : rootCertificate , key : rootPrivateKey } , web : { cert : webCertificate , key : webPrivateKey } , mps : { cert : mpsCertificate , key : mpsPrivateKey } , agent : { cert : agentCertificate , key : agentPrivateKey } , calist : calist , CommonName : commonName , RootName : rootName } ;
2017-08-28 12:27:45 -04:00
if ( func != undefined ) { func ( r ) ; }
return r ;
}
return obj ;
} ;