UNPKG

azure-cli

Version:

Microsoft Azure Cross Platform Command Line tool

308 lines (272 loc) 9.4 kB
/*** Generated by streamline 0.10.17 (callbacks) - DO NOT EDIT ***//** * Copyright (c) Microsoft. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ var crypto = require('crypto'); var util = require('util'); var path = require('path'); var fs = require('fs'); var moment = require('moment'); var utils = require('./utils'); var utilsCore = require('./utilsCore'); // x509 PEM Cert header var BEGIN_CERT = '-----BEGIN CERTIFICATE-----'; // x509 PEM Cert footer var END_CERT = '-----END CERTIFICATE-----'; // SSH RSA Public Key header var SSHDashRSA = 'ssh-rsa'; // input: Open SSH RSA PublicKey // // ssh-rsa {body} {info} // // output: PEM formatted PKCS#8 RSA Public Key // // -----BEGIN PUBLIC KEY----- // BASE64 ENCODED PUBLICKEYINFO // -----END PUBLIC KEY----- // // PUBLICKEYINFO ::= SEQUENCE { // algorithm ::= SEQUENCE { // algorithm 1.2.840.113549.1.1.1 // } // PublicKey ::= SEQUENCE { // modulus INTEGER, -- n // publicExponent INTEGER -- e // } // } // // 1.2.840.113549.1.1.1 is the OID for RSA // exports.openSshRSAPubToPkcs8RsaPubPEM = function (sshRSAPubKey) { var sshKeyToPEM = require('ssh-key-to-pem'); return sshKeyToPEM(sshRSAPubKey); }; // input: PEM formatted PKCS#8 RSA Public Key // // -----BEGIN PUBLIC KEY----- // BASE64 ENCODED PUBLICKEYINFO // -----END PUBLIC KEY----- // // PUBLICKEYINFO ::= SEQUENCE { // algorithm ::= SEQUENCE { // algorithm 1.2.840.113549.1.1.1 // } // PublicKey ::= SEQUENCE { // modulus INTEGER, -- n // publicExponent INTEGER -- e // } // } // // 1.2.840.113549.1.1.1 is the OID for RSA // // output: PEM formatted X509 Certificate // // -----BEGIN CERTIFICATE----- // BASE64 ENCODED X509Certificate // -----END CERTIFICATE----- // // X509Certificate ::= SEQUENCE { // tbsCertificate ::= SEQUENCE { // version [0] v1, // serialNumber 1, // signature ::= SEQUENCE { // algorithm 1.2.840.113549.1.1.5 // }, // issuer CN=Root Agency, // validity ::= SEQUENCE { // notBefore Time, // notAfter Time // }, // subject '/C=DE/O=dummy-subject/CN=dummy, // subjectPublicKeyInfo ::= SEQUENCE { // algorithm ::= SEQUENCE { // algorithm 1.2.840.113549.1.1.1 // }, // subjectPublicKey ::= SEQUENCE { // modulus INTEGER, -- n // publicExponent INTEGER -- e // } // } // }, // signatureAlgorithm ::= SEQUENCE { // algorithm 1.2.840.113549.1.1.5 // }, // signature 00 // } // // 1.2.840.113549.1.1.5 is the OID 'SHA-1 with RSA Encryption' // 1.2.840.113549.1.1.1 is the OID for RSA // // X509Certificate::signature represents the signature for the TBSCertificate // creating signature requires private key, since we don't have access to // private key we set X509Certificate::signature to 00. // exports.pkcs8RSAPubPEMToX509CertPEM = function (pkc8RSAPub) { require('jsrsasign'); var certValidityRange = exports.getCertValidityRange(); var x509CertPEM = KJUR.asn1.x509.X509Util.newCertPEM({ serial: { int: 1 }, sigalg: { name: 'SHA1withRSA', paramempty: true }, issuer: { str: 'CN=Root Agency' }, notbefore: { 'str': certValidityRange.start }, notafter: { 'str': certValidityRange.end }, subject: { str: '/C=DE/O=dummy-subject/CN=dummy' }, sbjpubkey: pkc8RSAPub, sighex: '00' }); var certEnd = x509CertPEM.indexOf(END_CERT); // Bug: jsrsasign module seems inserting an extra CRLF, remove it if (x509CertPEM[certEnd - 2] === '\r' && x509CertPEM[certEnd - 1] === '\n') { if (x509CertPEM[certEnd - 4] === '\r' && x509CertPEM[certEnd - 3] === '\n') { x509CertPEM = x509CertPEM.replace(new RegExp('\r\n' + END_CERT + '(\r\n)?' + '$'), END_CERT); } } else if (x509CertPEM[certEnd - 2] === '\n' && x509CertPEM[certEnd - 1] === '\n') { x509CertPEM = x509CertPEM.replace(new RegExp('\n' + END_CERT + '\n?' + '$'), END_CERT); } return x509CertPEM; }; exports.openSshRSAPubToX509CertPEM = function (openSShRSAPub) { var pkcs8RsaPubKey = exports.openSshRSAPubToPkcs8RsaPubPEM(openSShRSAPub); return exports.pkcs8RSAPubPEMToX509CertPEM(pkcs8RsaPubKey); }; exports.isX509CertPEM = function (data) { return (data && data.indexOf(BEGIN_CERT) !== -1 && data.indexOf(END_CERT) !== -1); }; exports.isOpenSshRSAPub = function (data) { if (data) { // should be in format 'ssh-rsa {body} {info}' var tokens = data.split([' ']); return (tokens.length >= 2 && tokens[0] === SSHDashRSA); } return false; }; exports.getFingerprintFromX509CertPEM = function (x509CertPEM) { var certBase64 = exports.extractBase64X509CertFromPEM(x509CertPEM); // Calculate sha1 hash of the cert var cert = new Buffer(certBase64, 'base64'); var sha1 = crypto.createHash('sha1'); sha1.update(cert); return sha1.digest('hex'); }; exports.extractBase64X509CertFromPEM = function (x509CertPEM) { // Extract the base64 encoded X509 cert out of PEM file var beginCert = x509CertPEM.indexOf(BEGIN_CERT) + BEGIN_CERT.length; if (x509CertPEM[beginCert] === '\n') { beginCert = beginCert + 1; } else if (x509CertPEM[beginCert] === '\r' && x509CertPEM[beginCert + 1] === '\n') { beginCert = beginCert + 2; } var endCert = '\n' + x509CertPEM.indexOf(END_CERT); if (endCert === -1) { endCert = '\r\n' + x509CertPEM.indexOf(END_CERT); } return x509CertPEM.substring(beginCert, endCert); }; exports.generatePemKeyPair = function () { var jsrsasign = require('jsrsasign'); var keys = jsrsasign.KEYUTIL.generateKeypair('RSA', 2048); var pub = jsrsasign.KEYUTIL.getPEM(keys.pubKeyObj); var pvt = jsrsasign.KEYUTIL.getPEM(keys.prvKeyObj, 'PKCS8PRV'); return { public: pub, private: pvt }; }; exports.generateX509PemCert = function (publicKey, privateKey, password) { var jsrsasign = require('jsrsasign'); var certValidityRange = exports.getCertValidityRange(); var certParams = { serial: { int: 1 }, sigalg: { name: 'SHA1withECDSA', paramempty: true }, issuer: { str: 'CN=Root Agency' }, notbefore: { 'str': certValidityRange.start }, notafter: { 'str': certValidityRange.end }, subject: { str: '/C=US/O=b' }, sbjpubkey: publicKey }; if(privateKey) { certParams.cakey = [ privateKey, password ]; } var certPEM = jsrsasign.asn1.x509.X509Util.newCertPEM(certParams); return certPEM; }; exports.checkSSHKeys = function (azureSshDir, keyPaths, callback) { utils.fileExists(azureSshDir, function(error, exists) { if (error) { return callback(error); } if (!exists) { fs.mkdir(azureSshDir, function(error) { if (error) { return callback(error); } return callback(null, false); }); } else { utils.fileExists(keyPaths.privateKeyPath, function(error, exists) { if (error) { return callback(error); } if (exists) { utils.fileExists(keyPaths.certPath, function(error, exists) { if (error) { return callback(error); } return callback(null, exists); }); } else { return callback(null, false); } }); } }); }; exports.generateSSHKeysIfNeeded = function (vmName, callback) { var azureSshDir = path.join(utilsCore.azureDir(), 'ssh'); var keyPaths = { certPath: path.join(azureSshDir, vmName + '-cert.pem'), privateKeyPath: path.join(azureSshDir, vmName + '-key.pem') }; exports.checkSSHKeys(azureSshDir, keyPaths, function(error, exists) { if (!exists) { exports.generateAndSaveSSHKeys(keyPaths.privateKeyPath, keyPaths.certPath); } return callback(null, keyPaths); }); }; exports.generateAndSaveSSHKeys = function (privateKeyPath, certPath) { var keys = exports.generatePemKeyPair(); var cert = exports.generateX509PemCert(keys.public, keys.private, ''); fs.writeFileSync(privateKeyPath, keys.private); fs.writeFileSync(certPath, cert); fs.chmodSync(privateKeyPath, 0600); }; exports.getCertValidityRange = function () { function pad(n) { return n < 10 ? '0' + n : n; } function toUTCString(d) { return util.format('%s%s%s%s%s%sZ', d.getUTCFullYear(), pad(d.getUTCMonth() + 1), pad(d.getUTCDate()), pad(d.getUTCHours()), pad(d.getUTCMinutes()), pad(d.getUTCSeconds())); } var startDateTime = new Date(); startDateTime.setMinutes(startDateTime.getMinutes() - 10); var m = moment(startDateTime); m.add(10, 'years'); var endDateTime = new Date(m.toISOString()); return { start: toUTCString(startDateTime), end: toUTCString(endDateTime) }; };