summaryrefslogtreecommitdiff
path: root/lib/leap_cli/config/node_cert.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/leap_cli/config/node_cert.rb')
-rw-r--r--lib/leap_cli/config/node_cert.rb124
1 files changed, 124 insertions, 0 deletions
diff --git a/lib/leap_cli/config/node_cert.rb b/lib/leap_cli/config/node_cert.rb
new file mode 100644
index 00000000..64842ffa
--- /dev/null
+++ b/lib/leap_cli/config/node_cert.rb
@@ -0,0 +1,124 @@
+#
+# x509 related methods for Config::Node
+#
+module LeapCli; module Config
+
+ class Node < Object
+
+ #
+ # creates a new server certificate file for this node
+ #
+ def generate_cert
+ require 'leap_cli/x509'
+
+ if self['x509.use'] == false ||
+ !Util.file_exists?(:ca_cert, :ca_key) ||
+ !self.cert_needs_updating?
+ return false
+ end
+
+ cert = CertificateAuthority::Certificate.new
+ provider = env.provider
+
+ # set subject
+ cert.subject.common_name = self.domain.full
+ cert.serial_number.number = X509.cert_serial_number(self.domain.full)
+
+ # set expiration
+ cert.not_before = X509.yesterday
+ cert.not_after = X509.yesterday_advance(provider.ca.server_certificates.life_span)
+
+ # generate key
+ cert.key_material.generate_key(provider.ca.server_certificates.bit_size)
+
+ # sign
+ cert.parent = X509.ca_root
+ cert.sign!(X509.server_signing_profile(self))
+
+ # save
+ Util.write_file!([:node_x509_key, self.name], cert.key_material.private_key.to_pem)
+ Util.write_file!([:node_x509_cert, self.name], cert.to_pem)
+ end
+
+ #
+ # returns true if the certs associated with +node+ need to be regenerated.
+ #
+ def cert_needs_updating?(log_comments=true)
+ require 'leap_cli/x509'
+
+ if log_comments
+ def log(*args, &block)
+ Util.log(*args, &block)
+ end
+ else
+ def log(*args); end
+ end
+
+ node = self
+ if !Util.file_exists?([:node_x509_cert, node.name], [:node_x509_key, node.name])
+ return true
+ else
+ cert = X509.load_certificate_file([:node_x509_cert, node.name])
+ if !X509.created_by_authority?(cert)
+ log :updating, "cert for node '#{node.name}' because it was signed by an old CA root cert."
+ return true
+ end
+ if cert.not_after < Time.now.advance(:months => 2)
+ 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 (was #{cert.subject.common_name}, now #{node.domain.full})"
+ return true
+ end
+ cert.openssl_body.extensions.each do |ext|
+ if ext.oid == "subjectAltName"
+ ips = []
+ dns_names = []
+ ext.value.split(",").each do |value|
+ value.strip!
+ ips << $1 if value =~ /^IP Address:(.*)$/
+ dns_names << $1 if value =~ /^DNS:(.*)$/
+ end
+ dns_names.sort!
+ if ips.first != node.ip_address
+ log :updating, "cert for node '#{node.name}' because ip_address has changed (from #{ips.first} to #{node.ip_address})"
+ return true
+ elsif dns_names != node.all_dns_names
+ log :updating, "cert for node '#{node.name}' because domain name aliases have changed" do
+ log "from: #{dns_names.inspect}"
+ log "to: #{node.all_dns_names.inspect})"
+ end
+ return true
+ end
+ end
+ end
+ end
+ return false
+ end
+
+ #
+ # check the expiration of commercial certs, if any.
+ #
+ def warn_if_commercial_cert_will_soon_expire
+ require 'leap_cli/x509'
+
+ self.all_dns_names.each do |domain|
+ if Util.file_exists?([:commercial_cert, domain])
+ cert = X509.load_certificate_file([:commercial_cert, domain])
+ path = Path.relative_path([:commercial_cert, domain])
+ if cert.not_after < Time.now.utc
+ Util.log :error, "the commercial certificate '#{path}' has EXPIRED! " +
+ "You should renew it with `leap cert csr --domain #{domain}`."
+ elsif cert.not_after < Time.now.advance(:months => 2)
+ Util.log :warning, "the commercial certificate '#{path}' will expire soon (#{cert.not_after}). "+
+ "You should renew it with `leap cert csr --domain #{domain}`."
+ end
+ end
+ end
+ end
+
+ end
+
+end; end
+