diff options
author | elijah <elijah@riseup.net> | 2012-11-14 00:24:19 -0800 |
---|---|---|
committer | elijah <elijah@riseup.net> | 2012-11-14 00:24:19 -0800 |
commit | 8472cc0797e66fea30758cb27b5fdb7b926144ee (patch) | |
tree | 557bb1d3c2596c6a603d59375f36a4648d5b3eae | |
parent | 10bd0ba9d66a32cb8e0f7fb322843005b23181b7 (diff) | |
download | leap_cli-8472cc0797e66fea30758cb27b5fdb7b926144ee.tar.gz leap_cli-8472cc0797e66fea30758cb27b5fdb7b926144ee.tar.bz2 |
made 'leap update-cert' intelligently update all certificates as needed.
-rw-r--r-- | lib/leap_cli/commands/ca.rb | 118 | ||||
-rw-r--r-- | lib/leap_cli/log.rb | 1 | ||||
-rw-r--r-- | lib/leap_cli/util.rb | 10 |
3 files changed, 95 insertions, 34 deletions
diff --git a/lib/leap_cli/commands/ca.rb b/lib/leap_cli/commands/ca.rb index e0b57da..59eb620 100644 --- a/lib/leap_cli/commands/ca.rb +++ b/lib/leap_cli/commands/ca.rb @@ -51,33 +51,14 @@ module LeapCli; module Commands 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.life_span' - - if args.first == 'all' - bail! 'not supported yet' + if args.first == 'all' || args.empty? + manager.each_node do |node| + if cert_needs_updating?(node) + generate_cert_for_node(node) + end + end else - provider = manager.provider - ca_root = cert_from_files(:ca_cert, :ca_key) - node = get_node_from_args(args) - - # set subject - cert = CertificateAuthority::Certificate.new - cert.subject.common_name = node.domain.full - - # set expiration - cert.not_before = today - cert.not_after = years_from_today(provider.ca.server_certificates.life_span.to_i) - - # generate key - cert.serial_number.number = cert_serial_number(node.domain.full) - cert.key_material.generate_key(provider.ca.server_certificates.bit_size) - - # sign - cert.parent = ca_root - cert.sign!(server_signing_profile(node)) - - # save - write_file!([:node_x509_key, node.name], cert.key_material.private_key.to_pem) - write_file!([:node_x509_cert, node.name], cert.to_pem) + generate_cert_for_node(get_node_from_args(args)) end end end @@ -101,12 +82,78 @@ module LeapCli; module Commands private - def cert_from_files(crt, key) - crt = read_file!(crt) - key = read_file!(key) + def cert_needs_updating?(node) + if !file_exists?([:node_x509_cert, node.name], [:node_x509_key, node.name]) + return true + else + cert = load_certificate_file([:node_x509_cert, node.name]) + if cert.not_after < months_from_today(1) + log :updating, "cert for node '#{node.name}' because it will expire soon" + return true + end + if cert.subject.common_name != node.domain.full + log :updating, "cert for node '#{node.name}' because domain.full has changed" + return true + end + cert.openssl_body.extensions.each do |ext| + # + # TODO: currently this only works with a single IP or DNS. + # + if ext.oid == "subjectAltName" + ext.value.match /IP Address:(.*?)(,|$)/ + ip = $1 + ext.value.match /DNS:(.*?)(,|$)/ + dns = $1 + if ip != node.ip_address + log :updating, "cert for node '#{node.name}' because ip_address has changed" + return true + elsif dns != node.domain.internal + log :updating, "cert for node '#{node.name}' because domain.internal has changed" + return true + end + end + end + end + return false + end + + def generate_cert_for_node(node) + cert = CertificateAuthority::Certificate.new + + # set subject + cert.subject.common_name = node.domain.full + cert.serial_number.number = cert_serial_number(node.domain.full) + + # set expiration + cert.not_before = today + cert.not_after = years_from_today(manager.provider.ca.server_certificates.life_span.to_i) + + # generate key + cert.key_material.generate_key(manager.provider.ca.server_certificates.bit_size) + + # sign + cert.parent = ca_root + cert.sign!(server_signing_profile(node)) + + # save + write_file!([:node_x509_key, node.name], cert.key_material.private_key.to_pem) + write_file!([:node_x509_cert, node.name], cert.to_pem) + end + + def ca_root + @ca_root ||= begin + load_certificate_file(:ca_cert, :ca_key) + end + end + + def load_certificate_file(crt_file, key_file=nil, password=nil) + crt = read_file!(crt_file) openssl_cert = OpenSSL::X509::Certificate.new(crt) cert = CertificateAuthority::Certificate.from_openssl(openssl_cert) - cert.key_material.private_key = OpenSSL::PKey::RSA.new(key, nil) # second argument is password, if set + if key_file + key = read_file!(key_file) + cert.key_material.private_key = OpenSSL::PKey::RSA.new(key, password) + end return cert end @@ -141,10 +188,8 @@ module LeapCli; module Commands "usage" => ["serverAuth"] }, "subjectAltName" => { - "uris" => [ - "IP:#{node.ip_address}", - "DNS:#{node.domain.internal}" - ] + "ips" => [node.ip_address], + "dns_names" => [node.domain.internal] } } } @@ -169,4 +214,9 @@ module LeapCli; module Commands Time.utc t.year + num, t.month, t.day end + def months_from_today(num) + date = Date.today >> num # >> is months in the future operator + Time.utc date.year, date.month, date.day + end + end; end diff --git a/lib/leap_cli/log.rb b/lib/leap_cli/log.rb index 1266caf..18a246f 100644 --- a/lib/leap_cli/log.rb +++ b/lib/leap_cli/log.rb @@ -48,6 +48,7 @@ def log(*args) when :warning then Paint['warning', :yellow, :bold] when :info then Paint['info', :cyan, :bold] when :updated then Paint['updated', :cyan, :bold] + when :updating then Paint['updating', :cyan, :bold] when :created then Paint['created', :green, :bold] when :removed then Paint['removed', :red, :bold] when :nochange then Paint['no change', :magenta] diff --git a/lib/leap_cli/util.rb b/lib/leap_cli/util.rb index bd8b04b..8e7b752 100644 --- a/lib/leap_cli/util.rb +++ b/lib/leap_cli/util.rb @@ -105,6 +105,16 @@ module LeapCli end end + def file_exists?(*files) + files.each do |file_path| + file_path = Path.named_path(file_path) + if !File.exists?(file_path) + return false + end + end + return true + end + ## ## FILES AND DIRECTORIES ## |