x509_certificate.rb 4.95 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

chef_version_for_provides '< 14.4' if respond_to?(:chef_version_for_provides)
resource_name :openssl_x509_certificate

Julien Huon's avatar
Julien Huon committed
20
21
22
23
24
provides :openssl_x509 # legacy_name

include OpenSSLCookbook::Helpers

property :path,             String, name_property: true
25
26
property :owner,            String
property :group,            String
Julien Huon's avatar
Julien Huon committed
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
property :expire,           Integer, default: 365
property :mode,             [Integer, String], default: '0644'
property :country,          String
property :state,            String
property :city,             String
property :org,              String
property :org_unit,         String
property :common_name,      String
property :email,            String
property :extensions,       Hash, default: {}
property :subject_alt_name, Array, default: []
property :key_file,         String
property :key_pass,         String
property :key_type,         equal_to: %w(rsa ec), default: 'rsa'
property :key_length,       equal_to: [1024, 2048, 4096, 8192], default: 2048
property :key_curve,        equal_to: %w(secp384r1 secp521r1 prime256v1), default: 'prime256v1'
property :csr_file,         String
property :ca_cert_file,     String
property :ca_key_file,      String
property :ca_key_pass,      String

action :create do
  unless ::File.exist? new_resource.path
    converge_by("Create #{@new_resource}") do
      file new_resource.path do
        action :create_if_missing
        mode new_resource.mode
54
55
        owner new_resource.owner unless new_resource.owner.nil?
        group new_resource.group unless new_resource.group.nil?
Julien Huon's avatar
Julien Huon committed
56
57
58
59
60
61
62
63
        sensitive true
        content cert.to_pem
      end

      if new_resource.csr_file.nil?
        file new_resource.key_file do
          action :create_if_missing
          mode new_resource.mode
64
65
          owner new_resource.owner unless new_resource.owner.nil?
          group new_resource.group unless new_resource.group.nil?
Julien Huon's avatar
Julien Huon committed
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
          sensitive true
          content key.to_pem
        end
      end
    end
  end
end

action_class do
  def generate_key_file
    unless new_resource.key_file
      path, file = ::File.split(new_resource.path)
      filename = ::File.basename(file, ::File.extname(file))
      new_resource.key_file path + '/' + filename + '.key'
    end
    new_resource.key_file
  end

  def key
    @key ||= if priv_key_file_valid?(generate_key_file, new_resource.key_pass)
86
               ::OpenSSL::PKey.read ::File.read(generate_key_file), new_resource.key_pass
Julien Huon's avatar
Julien Huon committed
87
88
89
90
91
92
93
94
95
96
97
98
             elsif new_resource.key_type == 'rsa'
               gen_rsa_priv_key(new_resource.key_length)
             else
               gen_ec_priv_key(new_resource.key_curve)
             end
    @key
  end

  def request
    request = if new_resource.csr_file.nil?
                gen_x509_request(subject, key)
              else
99
                ::OpenSSL::X509::Request.new ::File.read(new_resource.csr_file)
Julien Huon's avatar
Julien Huon committed
100
101
102
103
104
              end
    request
  end

  def subject
105
    subject = ::OpenSSL::X509::Name.new()
Julien Huon's avatar
Julien Huon committed
106
107
108
109
110
111
112
113
114
115
116
117
118
119
    subject.add_entry('C', new_resource.country) unless new_resource.country.nil?
    subject.add_entry('ST', new_resource.state) unless new_resource.state.nil?
    subject.add_entry('L', new_resource.city) unless new_resource.city.nil?
    subject.add_entry('O', new_resource.org) unless new_resource.org.nil?
    subject.add_entry('OU', new_resource.org_unit) unless new_resource.org_unit.nil?
    subject.add_entry('CN', new_resource.common_name)
    subject.add_entry('emailAddress', new_resource.email) unless new_resource.email.nil?
    subject
  end

  def ca_private_key
    ca_private_key = if new_resource.csr_file.nil?
                       key
                     else
120
                       ::OpenSSL::PKey.read ::File.read(new_resource.ca_key_file), new_resource.ca_key_pass
Julien Huon's avatar
Julien Huon committed
121
122
123
124
125
126
127
128
129
                     end
    ca_private_key
  end

  def ca_info
    # Will contain issuer (if any) & expiration
    ca_info = {}

    unless new_resource.ca_cert_file.nil?
130
      ca_info['issuer'] = ::OpenSSL::X509::Certificate.new ::File.read(new_resource.ca_cert_file)
Julien Huon's avatar
Julien Huon committed
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
    end
    ca_info['validity'] = new_resource.expire

    ca_info
  end

  def extensions
    extensions = gen_x509_extensions(new_resource.extensions)

    unless new_resource.subject_alt_name.empty?
      extensions += gen_x509_extensions('subjectAltName' => { 'values' => new_resource.subject_alt_name, 'critical' => false })
    end

    extensions
  end

  def cert
    cert = gen_x509_cert(request, extensions, ca_info, ca_private_key)
    cert
  end
end