vagrant/lib/vagrant/util/keypair.rb

57 lines
1.7 KiB
Ruby

require "base64"
require "openssl"
require "vagrant/util/retryable"
module Vagrant
module Util
class Keypair
extend Retryable
# Creates an SSH keypair and returns it.
#
# @param [String] password Password for the key, or nil for no password.
# @return [Array<String, String, String>] PEM-encoded public and private key,
# respectively. The final element is the OpenSSH encoded public
# key.
def self.create(password=nil)
# This sometimes fails with RSAError. It is inconsistent and strangely
# sleeps seem to fix it. We just retry this a few times. See GH-5056
rsa_key = nil
retryable(on: OpenSSL::PKey::RSAError, sleep: 2, tries: 5) do
rsa_key = OpenSSL::PKey::RSA.new(2048)
end
public_key = rsa_key.public_key
private_key = rsa_key.to_pem
if password
cipher = OpenSSL::Cipher.new('des3')
private_key = rsa_key.to_pem(cipher, password)
end
# Generate the binary necessary for the OpenSSH public key.
binary = [7].pack("N")
binary += "ssh-rsa"
["e", "n"].each do |m|
val = public_key.send(m)
data = val.to_s(2)
first_byte = data[0,1].unpack("c").first
if val < 0
data[0] = [0x80 & first_byte].pack("c")
elsif first_byte < 0
data = 0.chr + data
end
binary += [data.length].pack("N") + data
end
openssh_key = "ssh-rsa #{Base64.encode64(binary).gsub("\n", "")} vagrant"
public_key = public_key.to_pem
return [public_key, private_key, openssh_key]
end
end
end
end