aboutsummaryrefslogtreecommitdiff
path: root/lib/leap_cli
diff options
context:
space:
mode:
authorelijah <elijah@riseup.net>2012-11-16 14:30:20 -0800
committerelijah <elijah@riseup.net>2012-11-16 14:30:20 -0800
commit76a3a736cfb50cb1c6d926d1e3afb0f504818157 (patch)
tree95df178ce78ba5220eea267bdb21a04f2f975c75 /lib/leap_cli
parentbeb6496309b3640d957428b52b4906a1279457ce (diff)
downloadleap_cli-76a3a736cfb50cb1c6d926d1e3afb0f504818157.tar.gz
leap_cli-76a3a736cfb50cb1c6d926d1e3afb0f504818157.tar.bz2
added CSR ability (and vendored certificate_authority gem, so we can get the unreleased fixes we need).
Diffstat (limited to 'lib/leap_cli')
-rw-r--r--lib/leap_cli/commands/ca.rb90
-rw-r--r--lib/leap_cli/log.rb14
-rw-r--r--lib/leap_cli/path.rb3
-rw-r--r--lib/leap_cli/util.rb28
-rw-r--r--lib/leap_cli/version.rb2
5 files changed, 119 insertions, 18 deletions
diff --git a/lib/leap_cli/commands/ca.rb b/lib/leap_cli/commands/ca.rb
index 5b556a3..1763ba3 100644
--- a/lib/leap_cli/commands/ca.rb
+++ b/lib/leap_cli/commands/ca.rb
@@ -50,6 +50,7 @@ module LeapCli; module Commands
c.action do |global_options,options,args|
assert_files_exist! :ca_cert, :ca_key, :msg => 'Run init-ca to create them'
assert_config! 'provider.ca.server_certificates.bit_size'
+ assert_config! 'provider.ca.server_certificates.digest'
assert_config! 'provider.ca.server_certificates.life_span'
assert_config! 'common.x509.use'
@@ -82,6 +83,72 @@ module LeapCli; module Commands
end
end
+ #
+ # hints:
+ #
+ # inspect CSR:
+ # openssl req -noout -text -in files/cert/x.csr
+ #
+ # generate CSR with openssl to see how it compares:
+ # openssl req -sha256 -nodes -newkey rsa:2048 -keyout example.key -out example.csr
+ #
+ # validate a CSR:
+ # http://certlogik.com/decoder/
+ #
+ # nice details about CSRs:
+ # http://www.redkestrel.co.uk/Articles/CSR.html
+ #
+ desc 'Creates a Certificate Signing Request for use in purchasing a commercial x509 certificate'
+ command :'init-csr' do |c|
+ c.switch 'sign', :desc => 'additionally creates a cert that is signed by your own CA (recommended only for testing)', :negatable => false
+ c.action do |global_options,options,args|
+ assert_config! 'provider.domain'
+ assert_config! 'provider.name'
+ assert_config! 'provider.default_language'
+ assert_config! 'provider.ca.server_certificates.bit_size'
+ assert_config! 'provider.ca.server_certificates.digest'
+ assert_files_missing! [:commercial_key, manager.provider.domain], [:commercial_csr, manager.provider.domain], :msg => 'If you really want to create a new key and CSR, remove these files first.'
+ if options[:sign]
+ assert_files_exist! :ca_cert, :ca_key, :msg => 'Run init-ca to create them'
+ end
+
+ # RSA key
+ keypair = CertificateAuthority::MemoryKeyMaterial.new
+ log :generating, "%s bit RSA key" % manager.provider.ca.server_certificates.bit_size do
+ keypair.generate_key(manager.provider.ca.server_certificates.bit_size)
+ write_file! [:commercial_key, manager.provider.domain], keypair.private_key.to_pem
+ end
+
+ # CSR
+ dn = CertificateAuthority::DistinguishedName.new
+ csr = CertificateAuthority::SigningRequest.new
+ dn.common_name = manager.provider.domain
+ dn.organization = manager.provider.name[manager.provider.default_language]
+ log :generating, "CSR with commonName => '%s', organization => '%s'" % [dn.common_name, dn.organization] do
+ csr.distinguished_name = dn
+ csr.key_material = keypair
+ csr.digest = manager.provider.ca.server_certificates.digest
+ request = csr.to_x509_csr
+ write_file! [:commercial_csr, manager.provider.domain], csr.to_pem
+ end
+
+ # Sign using our own CA, for use in testing but hopefully not production.
+ # It is not that commerical CAs are so secure, it is just that signing your own certs is
+ # a total drag for the user because they must click through dire warnings.
+ if options[:sign]
+ log :generating, "x509 server certificate for testing purposes" do
+ cert = csr.to_cert
+ cert.serial_number.number = cert_serial_number(manager.provider.domain)
+ cert.not_before = today
+ cert.not_after = years_from_today(1)
+ cert.parent = ca_root
+ cert.sign! test_cert_signing_profile
+ write_file! [:commercial_cert, manager.provider.domain], cert.to_pem
+ end
+ end
+ end
+ end
+
private
def cert_needs_updating?(node)
@@ -182,11 +249,11 @@ module LeapCli; module Commands
# for keyusage, openvpn server certs can have keyEncipherment or keyAgreement. I am not sure which is preferable.
# going with keyAgreement for now.
#
- # digest options: SHA512, SHA1
+ # digest options: SHA512, SHA256, SHA1
#
def server_signing_profile(node)
{
- "digest" => "SHA256",
+ "digest" => manager.provider.ca.server_certificates.digest,
"extensions" => {
"keyUsage" => {
"usage" => ["digitalSignature", "keyAgreement"]
@@ -202,6 +269,25 @@ module LeapCli; module Commands
}
end
+ #
+ # This is used when signing the main cert for the provider's domain
+ # with our own CA (for testing purposes). Typically, this cert would
+ # be purchased from a commercial CA, and not signed this way.
+ #
+ def test_cert_signing_profile
+ {
+ "digest" => "SHA256",
+ "extensions" => {
+ "keyUsage" => {
+ "usage" => ["digitalSignature", "keyAgreement"]
+ },
+ "extendedKeyUsage" => {
+ "usage" => ["serverAuth"]
+ }
+ }
+ }
+ end
+
def dns_names_for_node(node)
names = [node.domain.internal]
if node['dns'] && node.dns['aliases'] && node.dns.aliases.any?
diff --git a/lib/leap_cli/log.rb b/lib/leap_cli/log.rb
index 1cc1c6a..0821177 100644
--- a/lib/leap_cli/log.rb
+++ b/lib/leap_cli/log.rb
@@ -8,6 +8,12 @@ module LeapCli
def log_level=(value)
@log_level = value
end
+ def indent_level
+ @indent_level ||= 0
+ end
+ def indent_level=(value)
+ @indent_level = value
+ end
end
##
@@ -34,7 +40,8 @@ def log(*args)
level = args.grep(Integer).first || 1
title = args.grep(Symbol).first
message = args.grep(String).first
- options = args.grep(Hash).first || {:indent => 0}
+ options = args.grep(Hash).first || {}
+ options[:indent] ||= LeapCli.indent_level
if message && LeapCli.log_level >= level
print " " * (options[:indent]+1)
if options[:indent] > 0
@@ -66,5 +73,10 @@ def log(*args)
end
end
puts "#{message}"
+ if block_given?
+ LeapCli.indent_level += 1
+ yield
+ LeapCli.indent_level -= 1
+ end
end
end
diff --git a/lib/leap_cli/path.rb b/lib/leap_cli/path.rb
index bf4c89f..de01fdb 100644
--- a/lib/leap_cli/path.rb
+++ b/lib/leap_cli/path.rb
@@ -34,6 +34,9 @@ module LeapCli; module Path
:ca_key => 'files/ca/ca.key',
:ca_cert => 'files/ca/ca.crt',
:dh_params => 'files/ca/dh.pem',
+ :commercial_key => 'files/cert/#{arg}.key',
+ :commercial_csr => 'files/cert/#{arg}.csr',
+ :commercial_cert => 'files/cert/#{arg}.crt',
:node_x509_key => 'files/nodes/#{arg}/#{arg}.key',
:node_x509_cert => 'files/nodes/#{arg}/#{arg}.crt',
:vagrantfile => 'test/Vagrantfile'
diff --git a/lib/leap_cli/util.rb b/lib/leap_cli/util.rb
index 9b04894..0b0fb9e 100644
--- a/lib/leap_cli/util.rb
+++ b/lib/leap_cli/util.rb
@@ -55,7 +55,7 @@ module LeapCli
#
def assert_bin!(cmd_name)
assert! `which #{cmd_name}`.strip.any? do
- log 0, :missing, "command '%s'" % cmd_name
+ log :missing, "command '%s'" % cmd_name
end
end
@@ -68,9 +68,9 @@ module LeapCli
output = `#{cmd}`
unless $?.success?
bail! do
- log 0, :run, cmd
- log 0, :failed, "(exit #{$?.exitstatus}) #{output}", :indent => 1
- log 0, message, :indent => 1 if message
+ log :run, cmd
+ log :failed, "(exit #{$?.exitstatus}) #{output}", :indent => 1
+ log message, :indent => 1 if message
end
else
log 2, :ran, cmd
@@ -86,13 +86,13 @@ module LeapCli
}.compact
if file_list.length > 1
bail! do
- log 0, :error, "Sorry, we can't continue because these files already exist: #{file_list.join(', ')}."
- log 0, options[:msg] if options[:msg]
+ log :error, "Sorry, we can't continue because these files already exist: #{file_list.join(', ')}."
+ log options[:msg] if options[:msg]
end
elsif file_list.length == 1
bail! do
- log 0, :error, "Sorry, we can't continue because this file already exists: #{file_list.first}."
- log 0, options[:msg] if options[:msg]
+ log :error, "Sorry, we can't continue because this file already exists: #{file_list.first}."
+ log options[:msg] if options[:msg]
end
end
end
@@ -104,8 +104,8 @@ module LeapCli
rescue NoMethodError
rescue NameError
end
- assert! !value.nil? do
- log 0, :missing, "configuration value for #{conf_path}"
+ assert! !value.nil? && value != "REQUIRED" do
+ log :missing, "required configuration value for #{conf_path}"
end
end
@@ -117,13 +117,13 @@ module LeapCli
}.compact
if file_list.length > 1
bail! do
- log 0, :missing, "these files: #{file_list.join(', ')}"
- log 0, options[:msg] if options[:msg]
+ log :missing, "these files: #{file_list.join(', ')}"
+ log options[:msg] if options[:msg]
end
elsif file_list.length == 1
bail! do
- log 0, :missing, "file #{file_list.first}"
- log 0, options[:msg] if options[:msg]
+ log :missing, "file #{file_list.first}"
+ log options[:msg] if options[:msg]
end
end
end
diff --git a/lib/leap_cli/version.rb b/lib/leap_cli/version.rb
index 83c2159..0dbd215 100644
--- a/lib/leap_cli/version.rb
+++ b/lib/leap_cli/version.rb
@@ -3,6 +3,6 @@ module LeapCli
VERSION = '0.1.3'
SUMMARY = 'Command line interface to the LEAP platform'
DESCRIPTION = 'The command "leap" can be used to manage a bevy of servers running the LEAP platform from the comfort of your own home.'
- REQUIRE_PATHS = ['lib', 'vendor/supply_drop/lib']
+ REQUIRE_PATHS = ['lib', 'vendor/supply_drop/lib', 'vendor/certificate_authority/lib']
end
end