~ubuntu-branches/ubuntu/quantal/puppet/quantal-security

« back to all changes in this revision

Viewing changes to lib/puppet/ssl/certificate_request.rb

  • Committer: Bazaar Package Importer
  • Author(s): Marc Deslauriers
  • Date: 2011-10-24 15:05:12 UTC
  • Revision ID: james.westby@ubuntu.com-20111024150512-yxqwfdp6hcs6of5l
Tags: 2.7.1-1ubuntu3.2
* SECURITY UPDATE: puppet master impersonation via incorrect certificates
  - debian/patches/CVE-2011-3872.patch: refactor certificate handling.
  - Thanks to upstream for providing the patch.
  - CVE-2011-3872

Show diffs side-by-side

added added

removed removed

Lines of Context:
35
35
    [:s]
36
36
  end
37
37
 
 
38
  def extension_factory
 
39
    @ef ||= OpenSSL::X509::ExtensionFactory.new
 
40
  end
 
41
 
38
42
  # How to create a certificate request with our system defaults.
39
 
  def generate(key)
 
43
  def generate(key, options = {})
40
44
    Puppet.info "Creating a new SSL certificate request for #{name}"
41
45
 
42
46
    # Support either an actual SSL key, or a Puppet key.
51
55
    csr.version = 0
52
56
    csr.subject = OpenSSL::X509::Name.new([["CN", common_name]])
53
57
    csr.public_key = key.public_key
 
58
 
 
59
    if options[:dns_alt_names] then
 
60
      names = options[:dns_alt_names].split(/\s*,\s*/).map(&:strip) + [name]
 
61
      names = names.sort.uniq.map {|name| "DNS:#{name}" }.join(", ")
 
62
      names = extension_factory.create_extension("subjectAltName", names, false)
 
63
 
 
64
      extReq = OpenSSL::ASN1::Set([OpenSSL::ASN1::Sequence([names])])
 
65
 
 
66
      # We only support the standard request extensions.  If you really need
 
67
      # msExtReq support, let us know and we can restore them. --daniel 2011-10-10
 
68
      csr.add_attribute(OpenSSL::X509::Attribute.new("extReq", extReq))
 
69
    end
 
70
 
54
71
    csr.sign(key, OpenSSL::Digest::MD5.new)
55
72
 
56
73
    raise Puppet::Error, "CSR sign verification failed; you need to clean the certificate request for #{name} on the server" unless csr.verify(key.public_key)
59
76
    Puppet.info "Certificate Request fingerprint (md5): #{fingerprint}"
60
77
    @content
61
78
  end
 
79
 
 
80
  # Return the set of extensions requested on this CSR, in a form designed to
 
81
  # be useful to Ruby: a hash.  Which, not coincidentally, you can pass
 
82
  # successfully to the OpenSSL constructor later, if you want.
 
83
  def request_extensions
 
84
    raise Puppet::Error, "CSR needs content to extract fields" unless @content
 
85
 
 
86
    # Prefer the standard extReq, but accept the Microsoft specific version as
 
87
    # a fallback, if the standard version isn't found.
 
88
    ext = @content.attributes.find {|x| x.oid == "extReq" } or
 
89
      @content.attributes.find {|x| x.oid == "msExtReq" }
 
90
    return [] unless ext
 
91
 
 
92
    # Assert the structure and extract the names into an array of arrays.
 
93
    unless ext.value.is_a? OpenSSL::ASN1::Set
 
94
      raise Puppet::Error, "In #{ext.oid}, expected Set but found #{ext.value.class}"
 
95
    end
 
96
 
 
97
    unless ext.value.value.is_a? Array
 
98
      raise Puppet::Error, "In #{ext.oid}, expected Set[Array] but found #{ext.value.value.class}"
 
99
    end
 
100
 
 
101
    unless ext.value.value.length == 1
 
102
      raise Puppet::Error, "In #{ext.oid}, expected Set[Array[...]], but found #{ext.value.value.length} items in the array"
 
103
    end
 
104
 
 
105
    san = ext.value.value.first
 
106
    unless san.is_a? OpenSSL::ASN1::Sequence
 
107
      raise Puppet::Error, "In #{ext.oid}, expected Set[Array[Sequence[...]]], but found #{san.class}"
 
108
    end
 
109
    san = san.value
 
110
 
 
111
    # OK, now san should be the array of items, validate that...
 
112
    index = -1
 
113
    san.map do |name|
 
114
      index += 1
 
115
 
 
116
      unless name.is_a? OpenSSL::ASN1::Sequence
 
117
        raise Puppet::Error, "In #{ext.oid}, expected request extension record #{index} to be a Sequence, but found #{name.class}"
 
118
      end
 
119
      name = name.value
 
120
 
 
121
      # OK, turn that into an extension, to unpack the content.  Lovely that
 
122
      # we have to swap the order of arguments to the underlying method, or
 
123
      # perhaps that the ASN.1 representation chose to pack them in a
 
124
      # strange order where the optional component comes *earlier* than the
 
125
      # fixed component in the sequence.
 
126
      case name.length
 
127
      when 2
 
128
        ev = OpenSSL::X509::Extension.new(name[0].value, name[1].value)
 
129
        { "oid" => ev.oid, "value" => ev.value }
 
130
 
 
131
      when 3
 
132
        ev = OpenSSL::X509::Extension.new(name[0].value, name[2].value, name[1].value)
 
133
        { "oid" => ev.oid, "value" => ev.value, "critical" => ev.critical? }
 
134
 
 
135
      else
 
136
        raise Puppet::Error, "In #{ext.oid}, expected extension record #{index} to have two or three items, but found #{name.length}"
 
137
      end
 
138
    end.flatten
 
139
  end
 
140
 
 
141
  def subject_alt_names
 
142
    @subject_alt_names ||= request_extensions.
 
143
      select {|x| x["oid"] = "subjectAltName" }.
 
144
      map {|x| x["value"].split(/\s*,\s*/) }.
 
145
      flatten.
 
146
      sort.
 
147
      uniq
 
148
  end
62
149
end