class Chef::Knife::WindowsCertGenerate

Attributes

hostname[RW]
thumbprint[RW]

Public Instance Methods

certificates_already_exist?(file_path) click to toggle source
# File lib/chef/knife/windows_cert_generate.rb, line 114
def certificates_already_exist?(file_path)
  certs_exists = false
  %w{pem pfx b64}.each do |extn|
    unless Dir.glob("#{file_path}.*#{extn}").empty?
      certs_exists = true
      break
    end
  end

  if certs_exists
    begin
      confirm("Do you really want to overwrite existing certificates")
    rescue SystemExit # Need to handle this as confirming with N/n raises SystemExit exception
      exit!
    end
  end
end
generate_certificate(rsa_key) click to toggle source
# File lib/chef/knife/windows_cert_generate.rb, line 82
def generate_certificate(rsa_key)
  @hostname = config[:hostname] if config[:hostname]

  # Create a self-signed X509 certificate from the rsa_key (unencrypted)
  cert = OpenSSL::X509::Certificate.new
  cert.version = 2
  cert.serial = Random.rand(65534) + 1 # 2 digit byte range random number for better security aspect

  cert.subject = OpenSSL::X509::Name.parse "/CN=#{@hostname}"
  cert.issuer = cert.subject
  cert.public_key = rsa_key.public_key
  cert.not_before = Time.now
  cert.not_after = cert.not_before + 2 * 365 * config[:cert_validity].to_i * 60 * 60 # 2 years validity
  ef = OpenSSL::X509::ExtensionFactory.new
  ef.subject_certificate = cert
  ef.issuer_certificate = cert
  cert.add_extension(ef.create_extension("subjectKeyIdentifier", "hash", false))
  cert.add_extension(ef.create_extension("authorityKeyIdentifier", "keyid:always", false))
  cert.add_extension(ef.create_extension("extendedKeyUsage", "1.3.6.1.5.5.7.3.1", false))
  cert.sign(rsa_key, OpenSSL::Digest.new("SHA1"))
  @thumbprint = OpenSSL::Digest::SHA1.new(cert.to_der)
  cert
end
generate_keypair() click to toggle source
# File lib/chef/knife/windows_cert_generate.rb, line 64
def generate_keypair
  OpenSSL::PKey::RSA.new(config[:key_length].to_i)
end
prompt_for_passphrase() click to toggle source
# File lib/chef/knife/windows_cert_generate.rb, line 68
def prompt_for_passphrase
  passphrase = ""
  begin
    print "Passphrases do not match.  Try again.\n" unless passphrase.empty?
    print "Enter certificate passphrase (empty for no passphrase):"
    passphrase = STDIN.gets
    return passphrase.strip if passphrase == "\n"

    print "Enter same passphrase again:"
    confirm_passphrase = STDIN.gets
  end until passphrase == confirm_passphrase
  passphrase.strip
end
run() click to toggle source
# File lib/chef/knife/windows_cert_generate.rb, line 132
def run
  STDOUT.sync = STDERR.sync = true

  # takes user specified first cli value as a destination file path for generated cert.
  file_path = @name_args.empty? ? config[:output_file].sub(/\.(\w+)$/, "") : @name_args.first

  # check if certs already exists at given file path
  certificates_already_exist? file_path

  begin
    filename = File.basename(file_path)
    rsa_key = generate_keypair
    cert = generate_certificate rsa_key
    write_certificate_to_file cert, file_path, rsa_key
    ui.info "Generated Certificates:"
    ui.info "- #{filename}.pfx - PKCS12 format key pair. Contains public and private keys, can be used with an SSL server."
    ui.info "- #{filename}.b64 - Base64 encoded PKCS12 key pair. Contains public and private keys, used by some cloud provider API's to configure SSL servers."
    ui.info "- #{filename}.pem - Base64 encoded public certificate only. Required by the client to connect to the server."
    ui.info "Certificate Thumbprint: #{@thumbprint.to_s.upcase}"
  rescue => e
    puts "ERROR: + #{e}"
  end
end
write_certificate_to_file(cert, file_path, rsa_key) click to toggle source
# File lib/chef/knife/windows_cert_generate.rb, line 106
def write_certificate_to_file(cert, file_path, rsa_key)
  File.open(file_path + ".pem", "wb") { |f| f.print cert.to_pem }
  config[:cert_passphrase] = prompt_for_passphrase unless config[:cert_passphrase]
  pfx = OpenSSL::PKCS12.create("#{config[:cert_passphrase]}", "winrmcert", rsa_key, cert)
  File.open(file_path + ".pfx", "wb") { |f| f.print pfx.to_der }
  File.open(file_path + ".b64", "wb") { |f| f.print Base64.strict_encode64(pfx.to_der) }
end