Class: Gem::Security::Policy
- Inherits:
-
Object
- Object
- Gem::Security::Policy
- Includes:
- UserInteraction
- Defined in:
- lib/rubygems/security/policy.rb,
lib/rubygems/security_option.rb,
lib/rubygems/commands/unpack_command.rb
Overview
:nodoc:
Instance Attribute Summary collapse
-
#name ⇒ Object
(also: #to_s)
readonly
Returns the value of attribute name.
-
#only_signed ⇒ Object
Returns the value of attribute only_signed.
-
#only_trusted ⇒ Object
Returns the value of attribute only_trusted.
-
#verify_chain ⇒ Object
Returns the value of attribute verify_chain.
-
#verify_data ⇒ Object
Returns the value of attribute verify_data.
-
#verify_root ⇒ Object
Returns the value of attribute verify_root.
-
#verify_signer ⇒ Object
Returns the value of attribute verify_signer.
Instance Method Summary collapse
-
#check_cert(signer, issuer, time) ⇒ Object
Ensures that
signer
is valid fortime
and was signed by theissuer
. -
#check_chain(chain, time) ⇒ Object
Verifies each certificate in
chain
has signed the following certificate and is valid for the giventime
. -
#check_data(public_key, digest, signature, data) ⇒ Object
Verifies that
data
matches thesignature
created bypublic_key
and thedigest
algorithm. -
#check_key(signer, key) ⇒ Object
Ensures the public key of
key
matches the public key insigner
. -
#check_root(chain, time) ⇒ Object
Ensures the root certificate in
chain
is self-signed and valid fortime
. -
#check_trust(chain, digester, trust_dir) ⇒ Object
Ensures the root of
chain
has a trusted certificate intrust_dir
and the digests of the two certificates match according todigester
. -
#initialize(name, policy = {}, opt = {}) ⇒ Policy
constructor
Create a new Gem::Security::Policy object with the given mode and options.
-
#inspect ⇒ Object
:nodoc:.
-
#subject(certificate) ⇒ Object
Extracts the email or subject from
certificate
. -
#verify(chain, key = nil, digests = {}, signatures = {}, full_name = '(unknown)') ⇒ Object
For
full_name
, verifies the certificatechain
is valid, thedigests
match the signaturessignatures
created by the signer depending on thepolicy
settings. -
#verify_signatures(spec, digests, signatures) ⇒ Object
Extracts the certificate chain from the
spec
and calls #verify to ensure the signatures and certificate chain is valid according to the policy..
Methods included from UserInteraction
#alert, #alert_error, #alert_warning, #ask, #ask_for_password, #ask_yes_no, #choose_from_list, #say, #terminate_interaction, #verbose
Methods included from DefaultUserInteraction
ui, #ui, ui=, #ui=, use_ui, #use_ui
Methods included from Text
#clean_text, #format_text, #levenshtein_distance, #min3, #truncate_text
Constructor Details
#initialize(name, policy = {}, opt = {}) ⇒ Policy
Create a new Gem::Security::Policy object with the given mode and options.
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 |
# File 'lib/rubygems/security/policy.rb', line 27 def initialize(name, policy = {}, opt = {}) require 'openssl' @name = name @opt = opt # Default to security @only_signed = true @only_trusted = true @verify_chain = true @verify_data = true @verify_root = true @verify_signer = true policy.each_pair do |key, val| case key when :verify_data then @verify_data = val when :verify_signer then @verify_signer = val when :verify_chain then @verify_chain = val when :verify_root then @verify_root = val when :only_trusted then @only_trusted = val when :only_signed then @only_signed = val end end end |
Instance Attribute Details
#name ⇒ Object (readonly) Also known as: to_s
Returns the value of attribute name
14 15 16 |
# File 'lib/rubygems/security/policy.rb', line 14 def name @name end |
#only_signed ⇒ Object
Returns the value of attribute only_signed
16 17 18 |
# File 'lib/rubygems/security/policy.rb', line 16 def only_signed @only_signed end |
#only_trusted ⇒ Object
Returns the value of attribute only_trusted
17 18 19 |
# File 'lib/rubygems/security/policy.rb', line 17 def only_trusted @only_trusted end |
#verify_chain ⇒ Object
Returns the value of attribute verify_chain
18 19 20 |
# File 'lib/rubygems/security/policy.rb', line 18 def verify_chain @verify_chain end |
#verify_data ⇒ Object
Returns the value of attribute verify_data
19 20 21 |
# File 'lib/rubygems/security/policy.rb', line 19 def verify_data @verify_data end |
#verify_root ⇒ Object
Returns the value of attribute verify_root
20 21 22 |
# File 'lib/rubygems/security/policy.rb', line 20 def verify_root @verify_root end |
#verify_signer ⇒ Object
Returns the value of attribute verify_signer
21 22 23 |
# File 'lib/rubygems/security/policy.rb', line 21 def verify_signer @verify_signer end |
Instance Method Details
#check_cert(signer, issuer, time) ⇒ Object
Ensures that signer
is valid for time
and was signed by the issuer
. If the issuer
is nil
no verification is performed.
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/rubygems/security/policy.rb', line 88 def check_cert(signer, issuer, time) raise Gem::Security::Exception, 'missing signing certificate' unless signer = "certificate #{signer.subject}" if not_before = signer.not_before and not_before > time raise Gem::Security::Exception, "#{} not valid before #{not_before}" end if not_after = signer.not_after and not_after < time raise Gem::Security::Exception, "#{} not valid after #{not_after}" end if issuer and not signer.verify issuer.public_key raise Gem::Security::Exception, "#{} was not issued by #{issuer.subject}" end true end |
#check_chain(chain, time) ⇒ Object
Verifies each certificate in chain
has signed the following certificate and is valid for the given time
.
58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/rubygems/security/policy.rb', line 58 def check_chain(chain, time) raise Gem::Security::Exception, 'missing signing chain' unless chain raise Gem::Security::Exception, 'empty signing chain' if chain.empty? begin chain.each_cons 2 do |issuer, cert| check_cert cert, issuer, time end true rescue Gem::Security::Exception => e raise Gem::Security::Exception, "invalid signing chain: #{e.}" end end |
#check_data(public_key, digest, signature, data) ⇒ Object
Verifies that data
matches the signature
created by public_key
and the digest
algorithm.
77 78 79 80 81 82 |
# File 'lib/rubygems/security/policy.rb', line 77 def check_data(public_key, digest, signature, data) raise Gem::Security::Exception, "invalid signature" unless public_key.verify digest.new, signature, data.digest true end |
#check_key(signer, key) ⇒ Object
Ensures the public key of key
matches the public key in signer
114 115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/rubygems/security/policy.rb', line 114 def check_key(signer, key) unless signer and key return true unless @only_signed raise Gem::Security::Exception, 'missing key or signature' end raise Gem::Security::Exception, "certificate #{signer.subject} does not match the signing key" unless signer.public_key.to_pem == key.public_key.to_pem true end |
#check_root(chain, time) ⇒ Object
Ensures the root certificate in chain
is self-signed and valid for time
.
132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
# File 'lib/rubygems/security/policy.rb', line 132 def check_root(chain, time) raise Gem::Security::Exception, 'missing signing chain' unless chain root = chain.first raise Gem::Security::Exception, 'missing root certificate' unless root raise Gem::Security::Exception, "root certificate #{root.subject} is not self-signed " + "(issuer #{root.issuer})" if root.issuer.to_s != root.subject.to_s # HACK to_s is for ruby 1.8 check_cert root, root, time end |
#check_trust(chain, digester, trust_dir) ⇒ Object
Ensures the root of chain
has a trusted certificate in trust_dir
and the digests of the two certificates match according to digester
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 |
# File 'lib/rubygems/security/policy.rb', line 151 def check_trust(chain, digester, trust_dir) raise Gem::Security::Exception, 'missing signing chain' unless chain root = chain.first raise Gem::Security::Exception, 'missing root certificate' unless root path = Gem::Security.trust_dir.cert_path root unless File.exist? path = "root cert #{root.subject} is not trusted".dup << " (root of signing cert #{chain.last.subject})" if chain.length > 1 raise Gem::Security::Exception, end save_cert = OpenSSL::X509::Certificate.new File.read path save_dgst = digester.digest save_cert.public_key.to_s pkey_str = root.public_key.to_s cert_dgst = digester.digest pkey_str raise Gem::Security::Exception, "trusted root certificate #{root.subject} checksum " + "does not match signing root certificate checksum" unless save_dgst == cert_dgst true end |
#inspect ⇒ Object
:nodoc:
196 197 198 199 200 201 202 |
# File 'lib/rubygems/security/policy.rb', line 196 def inspect # :nodoc: ("[Policy: %s - data: %p signer: %p chain: %p root: %p " + "signed-only: %p trusted-only: %p]") % [ @name, @verify_chain, @verify_data, @verify_root, @verify_signer, @only_signed, @only_trusted, ] end |
#subject(certificate) ⇒ Object
Extracts the email or subject from certificate
186 187 188 189 190 191 192 193 194 |
# File 'lib/rubygems/security/policy.rb', line 186 def subject(certificate) # :nodoc: certificate.extensions.each do |extension| next unless extension.oid == 'subjectAltName' return extension.value end certificate.subject.to_s end |
#verify(chain, key = nil, digests = {}, signatures = {}, full_name = '(unknown)') ⇒ Object
For full_name
, verifies the certificate chain
is valid, the digests
match the signatures signatures
created by the signer depending on the policy
settings.
If key
is given it is used to validate the signing certificate.
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 |
# File 'lib/rubygems/security/policy.rb', line 211 def verify(chain, key = nil, digests = {}, signatures = {}, full_name = '(unknown)') if signatures.empty? if @only_signed raise Gem::Security::Exception, "unsigned gems are not allowed by the #{name} policy" elsif digests.empty? # lack of signatures is irrelevant if there is nothing to check # against else alert_warning "#{full_name} is not signed" return end end opt = @opt digester = Gem::Security::DIGEST_ALGORITHM trust_dir = opt[:trust_dir] time = Time.now _, signer_digests = digests.find do |algorithm, file_digests| file_digests.values.first.name == Gem::Security::DIGEST_NAME end if @verify_data raise Gem::Security::Exception, 'no digests provided (probable bug)' if signer_digests.nil? or signer_digests.empty? else signer_digests = {} end signer = chain.last check_key signer, key if key check_cert signer, nil, time if @verify_signer check_chain chain, time if @verify_chain check_root chain, time if @verify_root if @only_trusted check_trust chain, digester, trust_dir elsif signatures.empty? and digests.empty? # trust is irrelevant if there's no signatures to verify else alert_warning "#{subject signer} is not trusted for #{full_name}" end signatures.each do |file, _| digest = signer_digests[file] raise Gem::Security::Exception, "missing digest for #{file}" unless digest end signer_digests.each do |file, digest| signature = signatures[file] raise Gem::Security::Exception, "missing signature for #{file}" unless signature check_data signer.public_key, digester, signature, digest if @verify_data end true end |
#verify_signatures(spec, digests, signatures) ⇒ Object
Extracts the certificate chain from the spec
and calls #verify to ensure the signatures and certificate chain is valid according to the policy..
283 284 285 286 287 288 289 290 291 |
# File 'lib/rubygems/security/policy.rb', line 283 def verify_signatures(spec, digests, signatures) chain = spec.cert_chain.map do |cert_pem| OpenSSL::X509::Certificate.new cert_pem end verify chain, nil, digests, signatures, spec.full_name true end |