module.exports = function * handleRequest (options) {

    this.log.info('[cert] Handling certificate signing request...');

    var options = _.defaults(options, {
        caKeyPath: this.config.get('ca.keyPath'),
        certsDir: this.config.get('ca.certsDir'),
        csrsDir: this.config.get('ca.csrsDir'),
        force: false
    });

    // Extract the hostname from the CSR
    var certInfo = yield pem.readCertificateInfo(options.csr);
    var hostname = certInfo.commonName;
    var csrPath = path.resolve(options.csrsDir, hostname +'.csr.pem');
    var certPath = path.resolve(options.certsDir, hostname +'.cert.pem');

    // If the `force` option is false then check if there is an existing
    // signed certiticate
    if (!options.force) {

        let exists = _.sum(yield [
            fs.exists(csrPath),
            fs.exists(certPath)
        ]);

        // Check if a cert already exists
        if (exists) {

            let certData = yield fs.readFile(path.resolve(certPath));

            return certData.toString();

        }

    }

    // Save the CSR
    let fd = yield fs.open(csrPath, 'w', '0600');
    yield fs.write(fd, options.csr);
    yield fs.close(fd);

    var shouldSign = this.config.get('ca.autoSign');

    // Check if we should auto-sign the certificate
    if (shouldSign) {

        // Set the `hostname` option
        options.hostname = hostname;

        // Sign and return the certificate
        return yield this.modules.cert.commands.sign(options);

    }

}
Example #2
0
module.exports = function * sign (options) {

    this.log.info('[cert] Signing certificate...');

    var app = this;

    assert(options instanceof Object, 'Invalid options.');
    assert(options.hostname, 'Missing `hostname`.');

    options = _.defaults(options, {
        caKeyPath: app.config.get('ca.keyPath'),
        caCertPath: app.config.get('ca.certPath'),
        certsDir: app.config.get('ca.certsDir'),
        csrsDir: app.config.get('ca.csrsDir'),
        daysValid: app.config.get('ca.certDaysValid')
    });

    var caKeyPath = path.resolve(options.caKeyPath);
    var caCertPath = path.resolve(options.caCertPath);
    var csrPath = path.resolve(options.csrsDir, options.hostname +'.csr.pem');
    var certPath = path.resolve(options.certsDir, options.hostname +'.cert.pem');
    var serial = (yield rand.randomInts({ num: 20, max: 9 })).join('');

    var certOptions = {
        serviceKey:         yield fs.readFile(caKeyPath),
        serviceCertificate: yield fs.readFile(caCertPath),
        csr:                yield fs.readFile(csrPath),
        serial:             serial,
        days:               options.daysValid
    };

    // Sign the certificate
    var keys = yield pem.createCertificate(certOptions);
    var certData = keys.certificate.toString();

    // Save the cert
    var fd = yield fs.open(certPath, 'w', '0644');
    yield fs.write(fd, certData);
    yield fs.close(fd);

    return certData;
}
module.exports = function * sendRequest (options) {

    this.log.info('[cert] Sending certificate signing request...');

    var app = this;

    options = _.defaults(options, {
        hostname: os.hostname(),
        caHost: app.config.get('ca.host'),
        caPort: app.config.get('ca.port'),
        caCertPath: app.config.get('ca.certPath'),
        orgUnit: 'ClusterFCUK Node',
        keyPath: app.config.get('server.keyPath'),
        certPath: app.config.get('server.certPath'),
        csrPath: app.config.get('server.csrPath'),
        force: false
    });

    var csrPath = path.resolve(options.csrPath);
    var keyPath = path.resolve(options.keyPath);
    var certPath = path.resolve(options.certPath);
    var caCertPath = path.resolve(options.caCertPath);

    var exists = _.sum(yield [
        fs.exists(csrPath),
        fs.exists(keyPath),
        fs.exists(certPath)
    ]);

    var certOptions = {
        commonName: options.hostname,
        organizationUnit: options.orgUnit
    };

    var csrData;

    if (!exists || options.force) {

        // Generate the certificate or CSR
        var keys = yield pem.createCSR(certOptions);
        var keyData = keys.clientKey.toString();

        csrData = keys.csr.toString();

        // Save the private key
        {
            let fd = yield fs.open(keyPath, 'w', '0600');
            yield fs.write(fd, keyData);
            yield fs.close(fd);
        }

        // Save the CSR
        {
            let fd = yield fs.open(csrPath, 'w', '0644');
            yield fs.write(fd, csrData);
            yield fs.close(fd);
        }

    } else {

        // Read the existing CSR data
        csrData = (yield fs.readFile(csrPath)).toString();

    }

    var requestUri = 'https://'+ options.caHost +':'+ options.caPort +'/cert/request';
    var requestBody = { csr: csrData, force: options.force };

    try {

        var caCert;

        // Send the certificate signing request
        var response = yield new Promise(function (fulfill, reject) {

            var req = request({
                method:     'POST',
                uri:        requestUri,
                body:       requestBody,
                json:       true,
                gzip:       true,
                strictSSL:  false
            }, function (err, res, body) {
                if (err) {
                    reject(err);
                } else {
                    fulfill(res);
                }
            });

            // Listen for the `response` event so we can get the server cert
            req.once('response', function () {
                caCert = this.req.connection.getPeerCertificate();
            });
        });

    } catch (err) {
        throw new Error('Could not send certificate signing request: '+ err.message);
    }

    switch (response.statusCode) {
        case 200:

            var certData = response.body.data;

            // Make sure we got a certificate back
            if (certData) {

                // Save the certificate
                {
                    let fd = yield fs.open(certPath, 'w', '0644');
                    yield fs.write(fd, certData);
                    yield fs.close(fd);
                }

                if (!caCert) {
                    throw new Error('Cannot get the server certificate.');
                }

                var caCertData = '-----BEGIN CERTIFICATE-----\n';
                caCertData += caCert.raw.toString('base64').match(/.{1,64}/g).join('\n');
                caCertData += '\n-----END CERTIFICATE-----';

                // Save the CA certificate
                {
                    let fd = yield fs.open(caCertPath, 'w', '0644');
                    yield fs.write(fd, caCertData);
                    yield fs.close(fd);
                }

                return certData;

            } else {
                throw new Error('A certificate was not returned by the server.');
            }

            break;
        case 202:
            return null;
        default:
            throw new Error(response.statusCode +' '+ response.statusMessage +': '+ response.body);
    }

}