Class: Acme::PKI
- Inherits:
-
Object
- Object
- Acme::PKI
- Includes:
- Information
- Defined in:
- lib/acme/pki.rb,
lib/acme/pki/version.rb,
lib/acme/pki/information.rb
Defined Under Namespace
Modules: Information
Constant Summary collapse
- DEFAULT_ENDPOINT =
ENV['ACME_ENDPOINT'] || 'https://acme-v01.api.letsencrypt.org/'
- DEFAULT_DIRECTORY =
ENV['ACME_DIRECTORY'] || Dir.pwd
- DEFAULT_ACCOUNT_KEY =
ENV['ACME_ACCOUNT_KEY'] || 'account.key'
- DEFAULT_KEY =
[:ecc, 'prime256v1'].freeze
- DEFAULT_RENEW_DURATION =
1 month
60 * 60 * 24 * 30
- VERSION =
'0.1.4'
Instance Method Summary collapse
- #crt(name) ⇒ Object
- #csr(name) ⇒ Object
- #generate_crt(crt, csr: nil) ⇒ Object
- #generate_csr(csr, domains: [], key: nil) ⇒ Object
- #generate_key(name, type: DEFAULT_KEY) ⇒ Object
-
#initialize(directory: DEFAULT_DIRECTORY, account_key: DEFAULT_ACCOUNT_KEY, endpoint: DEFAULT_ENDPOINT) ⇒ PKI
constructor
A new instance of PKI.
- #key(name) ⇒ Object
- #register(mail) ⇒ Object
- #renew(crt, csr: nil, duration: DEFAULT_RENEW_DURATION) ⇒ Object
Methods included from Information
#certifificate_info, #chain_info, #key_info
Constructor Details
#initialize(directory: DEFAULT_DIRECTORY, account_key: DEFAULT_ACCOUNT_KEY, endpoint: DEFAULT_ENDPOINT) ⇒ PKI
Returns a new instance of PKI.
25 26 27 28 29 30 31 32 33 34 35 |
# File 'lib/acme/pki.rb', line 25 def initialize(directory: DEFAULT_DIRECTORY, account_key: DEFAULT_ACCOUNT_KEY, endpoint: DEFAULT_ENDPOINT) @directory = directory @challenge_dir = ENV['ACME_CHALLENGE'] || File.join(@directory, 'acme-challenge') @account_key_file = File.join @directory, account_key @account_key = if File.exists? @account_key_file open(@account_key_file, 'r') { |f| OpenSSL::PKey.read f } else nil end @endpoint = endpoint end |
Instance Method Details
#crt(name) ⇒ Object
45 46 47 |
# File 'lib/acme/pki.rb', line 45 def crt(name) file name, 'crt' end |
#csr(name) ⇒ Object
41 42 43 |
# File 'lib/acme/pki.rb', line 41 def csr(name) file name, 'csr' end |
#generate_crt(crt, csr: nil) ⇒ Object
122 123 124 125 126 127 128 129 |
# File 'lib/acme/pki.rb', line 122 def generate_crt(crt, csr: nil) csr = crt unless csr short_csr = csr crt = self.crt crt csr = self.csr csr generate_csr short_csr unless File.exist? csr internal_generate_crt crt, csr: csr end |
#generate_csr(csr, domains: [], key: nil) ⇒ Object
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/acme/pki.rb', line 83 def generate_csr(csr, domains: [], key: nil) key = csr unless key domains = [csr, *domains].collect { |d| SimpleIDN.to_ascii d } csr_file = self.csr csr key_file = self.key key generate_key key unless File.exist? key_file process "Generating CSR for #{domains.join ', '} with key #{key_file} into #{csr_file}" do key_file = open(key_file, 'r') { |f| OpenSSL::PKey.read f } csr = OpenSSL::X509::Request.new csr.subject = OpenSSL::X509::Name.parse "/CN=#{domains.first}" public_key = case key_file when OpenSSL::PKey::EC curve = key_file.group.curve_name public = OpenSSL::PKey::EC.new curve public.public_key = key_file.public_key public else key_file.public_key end csr.public_key = public_key factory = OpenSSL::X509::ExtensionFactory.new extensions = [] #extensions << factory.create_extension('basicConstraints', 'CA:FALSE', true) extensions << factory.create_extension('keyUsage', 'digitalSignature,nonRepudiation,keyEncipherment') extensions << factory.create_extension('subjectAltName', domains.collect { |d| "DNS:#{d}" }.join(', ')) extensions = OpenSSL::ASN1::Sequence extensions extensions = OpenSSL::ASN1::Set [extensions] csr.add_attribute OpenSSL::X509::Attribute.new 'extReq', extensions csr.sign key_file, OpenSSL::Digest::SHA512.new open(csr_file, 'w') { |f| f.write csr.to_pem } end end |
#generate_key(name, type: DEFAULT_KEY) ⇒ Object
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/acme/pki.rb', line 61 def generate_key(name, type: DEFAULT_KEY) key_file = self.key name type, size = type key = case type when :rsa process "Generating RSA #{size} bits private key into #{key_file}" do key = OpenSSL::PKey::RSA.new size open(key_file, 'w') { |f| f.write key.to_pem } key end when :ecc process "Generating ECC #{size} curve private key into #{key_file}" do key = OpenSSL::PKey::EC.new(size).generate_key open(key_file, 'w') { |f| f.write key.to_pem } key end end key_info key end |
#key(name) ⇒ Object
37 38 39 |
# File 'lib/acme/pki.rb', line 37 def key(name) file name, 'pem' end |
#register(mail) ⇒ Object
49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/acme/pki.rb', line 49 def register(mail) process("Generating RSA 4096 bits account key into #{@account_key_file}") do @account_key = OpenSSL::PKey::RSA.new 4096 File.write @account_key_file, @account_key.to_pem end process("Registering account key #{@account_key_file}") do registration = client.register contact: "mailto:#{mail}" registration.agree_terms end end |
#renew(crt, csr: nil, duration: DEFAULT_RENEW_DURATION) ⇒ Object
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
# File 'lib/acme/pki.rb', line 131 def renew(crt, csr: nil, duration: DEFAULT_RENEW_DURATION) csr = crt unless csr crt = self.crt crt csr = self.csr csr puts "Renewing #{crt} CRT from #{csr} CSR" if File.exists? crt x509 = OpenSSL::X509::Certificate.new File.read crt delay = x509.not_after - Time.now if delay > duration puts "No need to renew (#{humanize delay})" return false end end internal_generate_crt crt, csr: csr true end |