| 
									
										
										
										
											2015-12-13 17:50:04 +01:00
										 |  |  | // Copyright 2014 ISRG.  All rights reserved
 | 
					
						
							|  |  |  | // This Source Code Form is subject to the terms of the Mozilla Public
 | 
					
						
							|  |  |  | // License, v. 2.0. If a copy of the MPL was not distributed with this
 | 
					
						
							|  |  |  | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
 | 
					
						
							| 
									
										
										
										
											2015-12-15 22:07:02 +00:00
										 |  |  | 'use strict'; | 
					
						
							| 
									
										
										
										
											2015-12-13 17:50:04 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | var crypto = require("crypto"); | 
					
						
							|  |  |  | var forge = require("node-forge"); | 
					
						
							|  |  |  | var util = require("./acme-util.js"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var TOKEN_SIZE = 16; | 
					
						
							| 
									
										
										
										
											2015-12-16 03:23:02 +00:00
										 |  |  | //var NONCE_SIZE = 16;
 | 
					
						
							| 
									
										
										
										
											2015-12-13 17:50:04 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | function bytesToBuffer(bytes) { | 
					
						
							|  |  |  |   return new Buffer(forge.util.bytesToHex(bytes), "hex"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function bufferToBytes(buf) { | 
					
						
							|  |  |  |   return forge.util.hexToBytes(buf.toString("hex")); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function bytesToBase64(bytes) { | 
					
						
							|  |  |  |   return util.b64enc(bytesToBuffer(bytes)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function base64ToBytes(base64) { | 
					
						
							|  |  |  |   return bufferToBytes(util.b64dec(base64)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function bnToBase64(bn) { | 
					
						
							|  |  |  |   var hex = bn.toString(16); | 
					
						
							| 
									
										
										
										
											2015-12-16 03:23:02 +00:00
										 |  |  |   if (hex.length % 2 === 1) { hex = "0" + hex; } | 
					
						
							| 
									
										
										
										
											2015-12-13 17:50:04 +01:00
										 |  |  |   return util.b64enc(new Buffer(hex, "hex")); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function base64ToBn(base64) { | 
					
						
							|  |  |  |   return new forge.jsbn.BigInteger(util.b64dec(base64).toString("hex"), 16); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function importPrivateKey(privateKey) { | 
					
						
							|  |  |  |   return forge.pki.rsa.setPrivateKey( | 
					
						
							|  |  |  |              base64ToBn(privateKey.n), | 
					
						
							|  |  |  |              base64ToBn(privateKey.e), base64ToBn(privateKey.d), | 
					
						
							|  |  |  |              base64ToBn(privateKey.p), base64ToBn(privateKey.q), | 
					
						
							|  |  |  |              base64ToBn(privateKey.dp),base64ToBn(privateKey.dq), | 
					
						
							|  |  |  |              base64ToBn(privateKey.qi)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function importPublicKey(publicKey) { | 
					
						
							|  |  |  |   return forge.pki.rsa.setPublicKey( | 
					
						
							|  |  |  |              base64ToBn(publicKey.n), | 
					
						
							|  |  |  |              base64ToBn(publicKey.e)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function exportPrivateKey(privateKey) { | 
					
						
							|  |  |  |   return { | 
					
						
							|  |  |  |     "kty": "RSA", | 
					
						
							|  |  |  |     "n": bnToBase64(privateKey.n), | 
					
						
							|  |  |  |     "e": bnToBase64(privateKey.e), | 
					
						
							|  |  |  |     "d": bnToBase64(privateKey.d), | 
					
						
							|  |  |  |     "p": bnToBase64(privateKey.p), | 
					
						
							|  |  |  |     "q": bnToBase64(privateKey.q), | 
					
						
							|  |  |  |     "dp": bnToBase64(privateKey.dP), | 
					
						
							|  |  |  |     "dq": bnToBase64(privateKey.dQ), | 
					
						
							|  |  |  |     "qi": bnToBase64(privateKey.qInv) | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function exportPublicKey(publicKey) { | 
					
						
							|  |  |  |   return { | 
					
						
							|  |  |  |     "kty": "RSA", | 
					
						
							|  |  |  |     "n": bnToBase64(publicKey.n), | 
					
						
							|  |  |  |     "e": bnToBase64(publicKey.e) | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // A note on formats:
 | 
					
						
							|  |  |  | // * Keys are always represented as JWKs
 | 
					
						
							|  |  |  | // * Signature objects are in ACME format
 | 
					
						
							|  |  |  | // * Certs and CSRs are base64-encoded
 | 
					
						
							|  |  |  | module.exports = { | 
					
						
							|  |  |  |    ///// RANDOM STRINGS
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   randomString: function(nBytes) { | 
					
						
							|  |  |  |     return bytesToBase64(forge.random.getBytesSync(nBytes)); | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   randomSerialNumber: function() { | 
					
						
							|  |  |  |     return forge.util.bytesToHex(forge.random.getBytesSync(4)); | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   newToken: function() { | 
					
						
							|  |  |  |     return this.randomString(TOKEN_SIZE); | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ///// SHA-256
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   sha256: function(buf) { | 
					
						
							|  |  |  |     return crypto.createHash('sha256').update(buf).digest('hex'); | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ///// KEY PAIR MANAGEMENT
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   generateKeyPair: function(bits) { | 
					
						
							|  |  |  |     var keyPair = forge.pki.rsa.generateKeyPair({bits: bits, e: 0x10001}); | 
					
						
							|  |  |  |     return { | 
					
						
							|  |  |  |       privateKey: exportPrivateKey(keyPair.privateKey), | 
					
						
							|  |  |  |       publicKey: exportPublicKey(keyPair.publicKey) | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   importPemPrivateKey: function(pem) { | 
					
						
							|  |  |  |     var key = forge.pki.privateKeyFromPem(pem); | 
					
						
							|  |  |  |     return { | 
					
						
							|  |  |  |       privateKey: exportPrivateKey(key), | 
					
						
							|  |  |  |       publicKey: exportPublicKey(key) | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   importPemCertificate: function(pem) { | 
					
						
							|  |  |  |     return forge.pki.certificateFromPem(pem); | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   privateKeyToPem: function(privateKey) { | 
					
						
							|  |  |  |     var priv = importPrivateKey(privateKey); | 
					
						
							|  |  |  |     return forge.pki.privateKeyToPem(priv); | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   certificateToPem: function(certificate) { | 
					
						
							|  |  |  |     var derCert = base64ToBytes(certificate); | 
					
						
							|  |  |  |     var cert = forge.pki.certificateFromAsn1(forge.asn1.fromDer(derCert)); | 
					
						
							|  |  |  |     return forge.pki.certificateToPem(cert); | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   certificateRequestToPem: function(csr) { | 
					
						
							|  |  |  |     var derReq = base64ToBytes(csr); | 
					
						
							|  |  |  |     var c = forge.pki.certificateFromAsn1(forge.asn1.fromDer(derReq)); | 
					
						
							|  |  |  |     return forge.pki.certificateRequestToPem(c); | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   thumbprint: function(publicKey) { | 
					
						
							|  |  |  |     // Only handling RSA keys
 | 
					
						
							| 
									
										
										
										
											2015-12-16 03:23:02 +00:00
										 |  |  |     var input = bytesToBuffer('{"e":"'+ publicKey.e + '","kty":"RSA","n":"'+ publicKey.n +'"}'); | 
					
						
							| 
									
										
										
										
											2015-12-13 17:50:04 +01:00
										 |  |  |     return util.b64enc(crypto.createHash('sha256').update(input).digest()); | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ///// SIGNATURE GENERATION / VERIFICATION
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   generateSignature: function(keyPair, payload, nonce) { | 
					
						
							|  |  |  |     var privateKey = importPrivateKey(keyPair.privateKey); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Compute JWS signature
 | 
					
						
							|  |  |  |     var protectedHeader = ""; | 
					
						
							|  |  |  |     if (nonce) { | 
					
						
							|  |  |  |       protectedHeader = JSON.stringify({nonce: nonce}); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     var protected64 = util.b64enc(new Buffer(protectedHeader)); | 
					
						
							|  |  |  |     var payload64 = util.b64enc(payload); | 
					
						
							|  |  |  |     var signatureInputBuf = new Buffer(protected64 + "." + payload64); | 
					
						
							|  |  |  |     var signatureInput = bufferToBytes(signatureInputBuf); | 
					
						
							|  |  |  |     var md = forge.md.sha256.create(); | 
					
						
							|  |  |  |     md.update(signatureInput); | 
					
						
							|  |  |  |     var sig = privateKey.sign(md); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return { | 
					
						
							|  |  |  |       header: { | 
					
						
							|  |  |  |         alg: "RS256", | 
					
						
							|  |  |  |         jwk: keyPair.publicKey, | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |       protected: protected64, | 
					
						
							|  |  |  |       payload: payload64, | 
					
						
							|  |  |  |       signature: util.b64enc(bytesToBuffer(sig)), | 
					
						
							| 
									
										
										
										
											2015-12-16 03:23:02 +00:00
										 |  |  |     }; | 
					
						
							| 
									
										
										
										
											2015-12-13 17:50:04 +01:00
										 |  |  |   }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   verifySignature: function(jws) { | 
					
						
							| 
									
										
										
										
											2015-12-16 03:23:02 +00:00
										 |  |  |     var key; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-13 17:50:04 +01:00
										 |  |  |     if (jws.protected) { | 
					
						
							|  |  |  |       if (!jws.header) { | 
					
						
							|  |  |  |         jws.header = {}; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       try { | 
					
						
							|  |  |  |         console.log(jws.protected); | 
					
						
							|  |  |  |         var protectedJSON = util.b64dec(jws.protected).toString(); | 
					
						
							|  |  |  |         console.log(protectedJSON); | 
					
						
							|  |  |  |         var protectedObj = JSON.parse(protectedJSON); | 
					
						
							|  |  |  |         for (key in protectedObj) { | 
					
						
							|  |  |  |           jws.header[key] = protectedObj[key]; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } catch (e) { | 
					
						
							| 
									
										
										
										
											2015-12-16 03:23:02 +00:00
										 |  |  |         console.log("error unmarshaling json: "+e); | 
					
						
							| 
									
										
										
										
											2015-12-13 17:50:04 +01:00
										 |  |  |         return false; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Assumes validSignature(sig)
 | 
					
						
							| 
									
										
										
										
											2015-12-16 03:23:02 +00:00
										 |  |  |     if (!jws.header.jwk || (jws.header.jwk.kty !== "RSA")) { | 
					
						
							| 
									
										
										
										
											2015-12-13 17:50:04 +01:00
										 |  |  |       // Unsupported key type
 | 
					
						
							|  |  |  |       console.log("Unsupported key type"); | 
					
						
							|  |  |  |       return false; | 
					
						
							|  |  |  |     } else if (!jws.header.alg || !jws.header.alg.match(/^RS/)) { | 
					
						
							|  |  |  |       // Unsupported algorithm
 | 
					
						
							|  |  |  |       console.log("Unsupported alg: "+jws.header.alg); | 
					
						
							|  |  |  |       return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Compute signature input
 | 
					
						
							|  |  |  |     var protected64 = (jws.protected)? jws.protected : ""; | 
					
						
							|  |  |  |     var payload64 = (jws.payload)? jws.payload : ""; | 
					
						
							|  |  |  |     var signatureInputBuf = new Buffer(protected64 + "." + payload64); | 
					
						
							|  |  |  |     var signatureInput = bufferToBytes(signatureInputBuf); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Compute message digest
 | 
					
						
							|  |  |  |     var md; | 
					
						
							|  |  |  |     switch (jws.header.alg) { | 
					
						
							|  |  |  |       case "RS1":   md = forge.md.sha1.create(); break; | 
					
						
							|  |  |  |       case "RS256": md = forge.md.sha256.create(); break; | 
					
						
							|  |  |  |       case "RS384": md = forge.md.sha384.create(); break; | 
					
						
							|  |  |  |       case "RS512": md = forge.md.sha512.create(); break; | 
					
						
							|  |  |  |       default: return false; // Unsupported algorithm
 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     md.update(signatureInput); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Import the key and signature
 | 
					
						
							|  |  |  |     var publicKey = importPublicKey(jws.header.jwk); | 
					
						
							|  |  |  |     var sig = bufferToBytes(util.b64dec(jws.signature)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return publicKey.verify(md.digest().bytes(), sig); | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ///// CSR GENERATION / VERIFICATION
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   generateCSR: function(keyPair, names) { | 
					
						
							|  |  |  |     var privateKey = importPrivateKey(keyPair.privateKey); | 
					
						
							|  |  |  |     var publicKey = importPublicKey(keyPair.publicKey); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Create and sign the CSR
 | 
					
						
							|  |  |  |     var csr = forge.pki.createCertificationRequest(); | 
					
						
							|  |  |  |     csr.publicKey = publicKey; | 
					
						
							|  |  |  |     csr.setSubject([{ name: 'commonName', value: names[0] }]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     var sans = []; | 
					
						
							| 
									
										
										
										
											2015-12-16 03:23:02 +00:00
										 |  |  |     var i; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-13 17:50:04 +01:00
										 |  |  |     for (i in names) { | 
					
						
							|  |  |  |       sans.push({ type: 2, value: names[i] }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     csr.setAttributes([{ | 
					
						
							|  |  |  |       name: 'extensionRequest', | 
					
						
							|  |  |  |       extensions: [{name: 'subjectAltName', altNames: sans}] | 
					
						
							|  |  |  |     }]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     csr.sign(privateKey, forge.md.sha256.create()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Convert CSR -> DER -> Base64
 | 
					
						
							|  |  |  |     var der = forge.asn1.toDer(forge.pki.certificationRequestToAsn1(csr)); | 
					
						
							|  |  |  |     return util.b64enc(bytesToBuffer(der)); | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   verifiedCommonName: function(csr_b64) { | 
					
						
							|  |  |  |     var der = bufferToBytes(util.b64dec(csr_b64)); | 
					
						
							|  |  |  |     var csr = forge.pki.certificationRequestFromAsn1(forge.asn1.fromDer(der)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!csr.verify()) { | 
					
						
							|  |  |  |       return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (var i=0; i<csr.subject.attributes.length; ++i) { | 
					
						
							| 
									
										
										
										
											2015-12-16 03:23:02 +00:00
										 |  |  |       if (csr.subject.attributes[i].name === "commonName") { | 
					
						
							| 
									
										
										
										
											2015-12-13 17:50:04 +01:00
										 |  |  |         return csr.subject.attributes[i].value; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ///// CERTIFICATE GENERATION
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // 'ca' parameter includes information about the CA
 | 
					
						
							|  |  |  |   // {
 | 
					
						
							|  |  |  |   //   distinguishedName: /* forge-formatted DN */
 | 
					
						
							|  |  |  |   //   keyPair: {
 | 
					
						
							|  |  |  |   //     publicKey: /* JWK */
 | 
					
						
							|  |  |  |   //     privateKey: /* JWK */
 | 
					
						
							|  |  |  |   //   }
 | 
					
						
							|  |  |  |   // }
 | 
					
						
							|  |  |  |   generateCertificate: function(ca, serialNumber, csr_b64) { | 
					
						
							|  |  |  |     var der = bufferToBytes(util.b64dec(csr_b64)); | 
					
						
							|  |  |  |     var csr = forge.pki.certificationRequestFromAsn1(forge.asn1.fromDer(der)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Extract the public key and common name
 | 
					
						
							|  |  |  |     var publicKey = csr.publicKey; | 
					
						
							|  |  |  |     var commonName = null; | 
					
						
							|  |  |  |     for (var i=0; i<csr.subject.attributes.length; ++i) { | 
					
						
							| 
									
										
										
										
											2015-12-16 03:23:02 +00:00
										 |  |  |       if (csr.subject.attributes[i].name === "commonName") { | 
					
						
							| 
									
										
										
										
											2015-12-13 17:50:04 +01:00
										 |  |  |         commonName = csr.subject.attributes[i].value; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (!commonName) { return false; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Create the certificate
 | 
					
						
							|  |  |  |     var cert = forge.pki.createCertificate(); | 
					
						
							|  |  |  |     cert.publicKey = publicKey; | 
					
						
							|  |  |  |     cert.serialNumber = serialNumber; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // 1-year validity
 | 
					
						
							|  |  |  |     cert.validity.notBefore = new Date(); | 
					
						
							|  |  |  |     cert.validity.notAfter = new Date(); | 
					
						
							|  |  |  |     cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     cert.setSubject([{ name: "commonName", value: commonName }]); | 
					
						
							|  |  |  |     cert.setIssuer(ca.distinguishedName); | 
					
						
							|  |  |  |     cert.setExtensions([ | 
					
						
							|  |  |  |       { name: "basicConstraints", cA: false }, | 
					
						
							|  |  |  |       { name: "keyUsage", digitalSignature: true, keyEncipherment: true }, | 
					
						
							|  |  |  |       { name: "extKeyUsage", serverAuth: true }, | 
					
						
							|  |  |  |       { name: "subjectAltName", altNames: [{ type: 2, value: commonName }] } | 
					
						
							|  |  |  |     ]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Import signing key and sign
 | 
					
						
							|  |  |  |     var privateKey = importPrivateKey(ca.keyPair.privateKey); | 
					
						
							|  |  |  |     cert.sign(privateKey); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Return base64-encoded DER
 | 
					
						
							| 
									
										
										
										
											2015-12-16 03:23:02 +00:00
										 |  |  |     der = forge.asn1.toDer(forge.pki.certificateToAsn1(cert)); | 
					
						
							| 
									
										
										
										
											2015-12-13 17:50:04 +01:00
										 |  |  |     return bytesToBuffer(der); | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   generateDvsniCertificate: function(keyPair, nonceName, zName) { | 
					
						
							|  |  |  |     var cert = forge.pki.createCertificate(); | 
					
						
							|  |  |  |     cert.publicKey = importPublicKey(keyPair.publicKey); | 
					
						
							|  |  |  |     cert.serialNumber = '01'; | 
					
						
							|  |  |  |     cert.validity.notBefore = new Date(); | 
					
						
							|  |  |  |     cert.validity.notAfter = new Date(); | 
					
						
							|  |  |  |     cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 1); | 
					
						
							|  |  |  |     cert.setSubject([{ name: "commonName", value: nonceName }]); | 
					
						
							|  |  |  |     cert.setIssuer([{ name: "commonName", value: nonceName }]); | 
					
						
							|  |  |  |     cert.setExtensions([ | 
					
						
							|  |  |  |       { name: "basicConstraints", cA: false }, | 
					
						
							|  |  |  |       { name: "keyUsage", digitalSignature: true, keyEncipherment: true }, | 
					
						
							|  |  |  |       { name: "extKeyUsage", serverAuth: true }, | 
					
						
							|  |  |  |       { name: "subjectAltName", altNames: [ | 
					
						
							|  |  |  |           { type: 2, value: nonceName }, | 
					
						
							|  |  |  |           { type: 2, value: zName } | 
					
						
							|  |  |  |       ]} | 
					
						
							|  |  |  |     ]); | 
					
						
							|  |  |  |     cert.sign(importPrivateKey(keyPair.privateKey)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Return base64-encoded DER, as above
 | 
					
						
							|  |  |  |     var der = forge.asn1.toDer(forge.pki.certificateToAsn1(cert)); | 
					
						
							|  |  |  |     return util.b64enc(bytesToBuffer(der)); | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ///// TLS CONTEXT GENERATION
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   createContext: function(keyPair, cert) { | 
					
						
							|  |  |  |     var privateKey = importPrivateKey(keyPair.privateKey); | 
					
						
							|  |  |  |     var derCert = bufferToBytes(util.b64dec(cert)); | 
					
						
							|  |  |  |     var realCert = forge.pki.certificateFromAsn1(forge.asn1.fromDer(derCert)); | 
					
						
							|  |  |  |     return crypto.createCredentials({ | 
					
						
							|  |  |  |       key: forge.pki.privateKeyToPem(privateKey), | 
					
						
							|  |  |  |       cert: forge.pki.certificateToPem(realCert) | 
					
						
							|  |  |  |     }).context; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | }; |