summaryrefslogtreecommitdiff
path: root/lib/rubygems/security
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rubygems/security')
-rw-r--r--lib/rubygems/security/policies.rb97
-rw-r--r--lib/rubygems/security/policy.rb59
-rw-r--r--lib/rubygems/security/signer.rb28
-rw-r--r--lib/rubygems/security/trust_dir.rb25
4 files changed, 106 insertions, 103 deletions
diff --git a/lib/rubygems/security/policies.rb b/lib/rubygems/security/policies.rb
index 8f6ad99316..41f66043ad 100644
--- a/lib/rubygems/security/policies.rb
+++ b/lib/rubygems/security/policies.rb
@@ -1,17 +1,17 @@
# frozen_string_literal: true
-module Gem::Security
+module Gem::Security
##
# No security policy: all package signature checks are disabled.
NoSecurity = Policy.new(
- 'No Security',
- :verify_data => false,
- :verify_signer => false,
- :verify_chain => false,
- :verify_root => false,
- :only_trusted => false,
- :only_signed => false
+ "No Security",
+ verify_data: false,
+ verify_signer: false,
+ verify_chain: false,
+ verify_root: false,
+ only_trusted: false,
+ only_signed: false
)
##
@@ -23,13 +23,13 @@ module Gem::Security
# easily spoofed, and is not recommended.
AlmostNoSecurity = Policy.new(
- 'Almost No Security',
- :verify_data => true,
- :verify_signer => false,
- :verify_chain => false,
- :verify_root => false,
- :only_trusted => false,
- :only_signed => false
+ "Almost No Security",
+ verify_data: true,
+ verify_signer: false,
+ verify_chain: false,
+ verify_root: false,
+ only_trusted: false,
+ only_signed: false
)
##
@@ -40,13 +40,13 @@ module Gem::Security
# is not recommended.
LowSecurity = Policy.new(
- 'Low Security',
- :verify_data => true,
- :verify_signer => true,
- :verify_chain => false,
- :verify_root => false,
- :only_trusted => false,
- :only_signed => false
+ "Low Security",
+ verify_data: true,
+ verify_signer: true,
+ verify_chain: false,
+ verify_root: false,
+ only_trusted: false,
+ only_signed: false
)
##
@@ -59,13 +59,13 @@ module Gem::Security
# gem off as unsigned.
MediumSecurity = Policy.new(
- 'Medium Security',
- :verify_data => true,
- :verify_signer => true,
- :verify_chain => true,
- :verify_root => true,
- :only_trusted => true,
- :only_signed => false
+ "Medium Security",
+ verify_data: true,
+ verify_signer: true,
+ verify_chain: true,
+ verify_root: true,
+ only_trusted: true,
+ only_signed: false
)
##
@@ -78,38 +78,37 @@ module Gem::Security
# a reasonable guarantee that the contents of the gem have not been altered.
HighSecurity = Policy.new(
- 'High Security',
- :verify_data => true,
- :verify_signer => true,
- :verify_chain => true,
- :verify_root => true,
- :only_trusted => true,
- :only_signed => true
+ "High Security",
+ verify_data: true,
+ verify_signer: true,
+ verify_chain: true,
+ verify_root: true,
+ only_trusted: true,
+ only_signed: true
)
##
# Policy used to verify a certificate and key when signing a gem
SigningPolicy = Policy.new(
- 'Signing Policy',
- :verify_data => false,
- :verify_signer => true,
- :verify_chain => true,
- :verify_root => true,
- :only_trusted => false,
- :only_signed => false
+ "Signing Policy",
+ verify_data: false,
+ verify_signer: true,
+ verify_chain: true,
+ verify_root: true,
+ only_trusted: false,
+ only_signed: false
)
##
# Hash of configured security policies
Policies = {
- 'NoSecurity' => NoSecurity,
- 'AlmostNoSecurity' => AlmostNoSecurity,
- 'LowSecurity' => LowSecurity,
- 'MediumSecurity' => MediumSecurity,
- 'HighSecurity' => HighSecurity,
+ "NoSecurity" => NoSecurity,
+ "AlmostNoSecurity" => AlmostNoSecurity,
+ "LowSecurity" => LowSecurity,
+ "MediumSecurity" => MediumSecurity,
+ "HighSecurity" => HighSecurity,
# SigningPolicy is not intended for use by `gem -P` so do not list it
}.freeze
-
end
diff --git a/lib/rubygems/security/policy.rb b/lib/rubygems/security/policy.rb
index 9683e55b32..7b86ac5763 100644
--- a/lib/rubygems/security/policy.rb
+++ b/lib/rubygems/security/policy.rb
@@ -1,5 +1,6 @@
# frozen_string_literal: true
-require_relative '../user_interaction'
+
+require_relative "../user_interaction"
##
# A Gem::Security::Policy object encapsulates the settings for verifying
@@ -53,8 +54,8 @@ class Gem::Security::Policy
# and is valid for the given +time+.
def check_chain(chain, time)
- raise Gem::Security::Exception, 'missing signing chain' unless chain
- raise Gem::Security::Exception, 'empty signing chain' if chain.empty?
+ 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|
@@ -83,21 +84,21 @@ class Gem::Security::Policy
# If the +issuer+ is +nil+ no verification is performed.
def check_cert(signer, issuer, time)
- raise Gem::Security::Exception, 'missing signing certificate' unless
+ raise Gem::Security::Exception, "missing signing certificate" unless
signer
message = "certificate #{signer.subject}"
- if not_before = signer.not_before and not_before > time
+ if (not_before = signer.not_before) && not_before > time
raise Gem::Security::Exception,
"#{message} not valid before #{not_before}"
end
- if not_after = signer.not_after and not_after < time
+ if (not_after = signer.not_after) && not_after < time
raise Gem::Security::Exception, "#{message} not valid after #{not_after}"
end
- if issuer and not signer.verify issuer.public_key
+ if issuer && !signer.verify(issuer.public_key)
raise Gem::Security::Exception,
"#{message} was not issued by #{issuer.subject}"
end
@@ -109,15 +110,15 @@ class Gem::Security::Policy
# Ensures the public key of +key+ matches the public key in +signer+
def check_key(signer, key)
- unless signer and key
+ unless signer && key
return true unless @only_signed
- raise Gem::Security::Exception, 'missing key or signature'
+ 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
+ signer.check_private_key(key)
true
end
@@ -127,14 +128,14 @@ class Gem::Security::Policy
# +time+.
def check_root(chain, time)
- raise Gem::Security::Exception, 'missing signing chain' unless chain
+ 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, "missing root certificate" unless root
raise Gem::Security::Exception,
- "root certificate #{root.subject} is not self-signed " +
+ "root certificate #{root.subject} is not self-signed " \
"(issuer #{root.issuer})" if
root.issuer != root.subject
@@ -146,11 +147,11 @@ class Gem::Security::Policy
# the digests of the two certificates match according to +digester+
def check_trust(chain, digester, trust_dir)
- raise Gem::Security::Exception, 'missing signing chain' unless chain
+ 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, "missing root certificate" unless root
path = Gem::Security.trust_dir.cert_path root
@@ -164,13 +165,13 @@ class Gem::Security::Policy
end
save_cert = OpenSSL::X509::Certificate.new File.read path
- save_dgst = digester.digest save_cert.public_key.to_s
+ save_dgst = digester.digest save_cert.public_key.to_pem
- pkey_str = root.public_key.to_s
+ pkey_str = root.public_key.to_pem
cert_dgst = digester.digest pkey_str
raise Gem::Security::Exception,
- "trusted root certificate #{root.subject} checksum " +
+ "trusted root certificate #{root.subject} checksum " \
"does not match signing root certificate checksum" unless
save_dgst == cert_dgst
@@ -182,7 +183,7 @@ class Gem::Security::Policy
def subject(certificate) # :nodoc:
certificate.extensions.each do |extension|
- next unless extension.oid == 'subjectAltName'
+ next unless extension.oid == "subjectAltName"
return extension.value
end
@@ -191,11 +192,8 @@ class Gem::Security::Policy
end
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
- ]
+ format("[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
##
@@ -205,8 +203,7 @@ class Gem::Security::Policy
#
# If +key+ is given it is used to validate the signing certificate.
- def verify(chain, key = nil, digests = {}, signatures = {},
- full_name = '(unknown)')
+ def verify(chain, key = nil, digests = {}, signatures = {}, full_name = "(unknown)")
if signatures.empty?
if @only_signed
raise Gem::Security::Exception,
@@ -225,13 +222,13 @@ class Gem::Security::Policy
trust_dir = opt[:trust_dir]
time = Time.now
- _, signer_digests = digests.find do |algorithm, file_digests|
+ _, 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?
+ raise Gem::Security::Exception, "no digests provided (probable bug)" if
+ signer_digests.nil? || signer_digests.empty?
else
signer_digests = {}
end
@@ -248,7 +245,7 @@ class Gem::Security::Policy
if @only_trusted
check_trust chain, digester, trust_dir
- elsif signatures.empty? and digests.empty?
+ elsif signatures.empty? && digests.empty?
# trust is irrelevant if there's no signatures to verify
else
alert_warning "#{subject signer} is not trusted for #{full_name}"
@@ -287,5 +284,5 @@ class Gem::Security::Policy
true
end
- alias to_s name # :nodoc:
+ alias_method :to_s, :name # :nodoc:
end
diff --git a/lib/rubygems/security/signer.rb b/lib/rubygems/security/signer.rb
index c5c2c4f220..5732fb57fd 100644
--- a/lib/rubygems/security/signer.rb
+++ b/lib/rubygems/security/signer.rb
@@ -1,4 +1,5 @@
# frozen_string_literal: true
+
##
# Basic OpenSSL-based package signing class.
@@ -42,7 +43,7 @@ class Gem::Security::Signer
def self.re_sign_cert(expired_cert, expired_cert_path, private_key)
return unless expired_cert.not_after < Time.now
- expiry = expired_cert.not_after.strftime('%Y%m%d%H%M%S')
+ expiry = expired_cert.not_after.strftime("%Y%m%d%H%M%S")
expired_cert_file = "#{File.basename(expired_cert_path)}.expired.#{expiry}"
new_expired_cert_path = File.join(Gem.user_home, ".gem", expired_cert_file)
@@ -83,8 +84,8 @@ class Gem::Security::Signer
@digest_name = Gem::Security::DIGEST_NAME
@digest_algorithm = Gem::Security.create_digest(@digest_name)
- if @key && !@key.is_a?(OpenSSL::PKey::RSA)
- @key = OpenSSL::PKey::RSA.new(File.read(@key), @passphrase)
+ if @key && !@key.is_a?(OpenSSL::PKey::PKey)
+ @key = OpenSSL::PKey.read(File.read(@key), @passphrase)
end
if @cert_chain
@@ -105,7 +106,7 @@ class Gem::Security::Signer
# this value is preferred, otherwise the subject is used.
def extract_name(cert) # :nodoc:
- subject_alt_name = cert.extensions.find {|e| 'subjectAltName' == e.oid }
+ subject_alt_name = cert.extensions.find {|e| e.oid == "subjectAltName" }
if subject_alt_name
/\Aemail:/ =~ subject_alt_name.value # rubocop:disable Performance/StartWith
@@ -139,9 +140,9 @@ class Gem::Security::Signer
def sign(data)
return unless @key
- raise Gem::Security::Exception, 'no certs provided' if @cert_chain.empty?
+ raise Gem::Security::Exception, "no certs provided" if @cert_chain.empty?
- if @cert_chain.length == 1 and @cert_chain.last.not_after < Time.now
+ if @cert_chain.length == 1 && @cert_chain.last.not_after < Time.now
alert("Your certificate has expired, trying to re-sign it...")
re_sign_key(
@@ -174,16 +175,23 @@ class Gem::Security::Signer
old_cert = @cert_chain.last
disk_cert_path = File.join(Gem.default_cert_path)
- disk_cert = File.read(disk_cert_path) rescue nil
+ disk_cert = begin
+ File.read(disk_cert_path)
+ rescue StandardError
+ nil
+ end
disk_key_path = File.join(Gem.default_key_path)
- disk_key =
- OpenSSL::PKey::RSA.new(File.read(disk_key_path), @passphrase) rescue nil
+ disk_key = begin
+ OpenSSL::PKey.read(File.read(disk_key_path), @passphrase)
+ rescue StandardError
+ nil
+ end
return unless disk_key
if disk_key.to_pem == @key.to_pem && disk_cert == old_cert.to_pem
- expiry = old_cert.not_after.strftime('%Y%m%d%H%M%S')
+ expiry = old_cert.not_after.strftime("%Y%m%d%H%M%S")
old_cert_file = "gem-public_cert.pem.expired.#{expiry}"
old_cert_path = File.join(Gem.user_home, ".gem", old_cert_file)
diff --git a/lib/rubygems/security/trust_dir.rb b/lib/rubygems/security/trust_dir.rb
index 456947274c..d23d161cfe 100644
--- a/lib/rubygems/security/trust_dir.rb
+++ b/lib/rubygems/security/trust_dir.rb
@@ -1,4 +1,5 @@
# frozen_string_literal: true
+
##
# The TrustDir manages the trusted certificates for gem signature
# verification.
@@ -8,8 +9,8 @@ class Gem::Security::TrustDir
# Default permissions for the trust directory and its contents
DEFAULT_PERMISSIONS = {
- :trust_dir => 0700,
- :trusted_cert => 0600,
+ trust_dir: 0o700,
+ trusted_cert: 0o600,
}.freeze
##
@@ -41,16 +42,14 @@ class Gem::Security::TrustDir
def each_certificate
return enum_for __method__ unless block_given?
- glob = File.join @dir, '*.pem'
+ glob = File.join @dir, "*.pem"
Dir[glob].each do |certificate_file|
- begin
- certificate = load_certificate certificate_file
+ certificate = load_certificate certificate_file
- yield certificate, certificate_file
- rescue OpenSSL::X509::CertificateError
- next # HACK warn
- end
+ yield certificate, certificate_file
+ rescue OpenSSL::X509::CertificateError
+ next # HACK: warn
end
end
@@ -92,7 +91,7 @@ class Gem::Security::TrustDir
destination = cert_path certificate
- File.open destination, 'wb', 0600 do |io|
+ File.open destination, "wb", 0o600 do |io|
io.write certificate.to_pem
io.chmod(@permissions[:trusted_cert])
end
@@ -104,15 +103,15 @@ class Gem::Security::TrustDir
# permissions.
def verify
- require 'fileutils'
+ require "fileutils"
if File.exist? @dir
raise Gem::Security::Exception,
"trust directory #{@dir} is not a directory" unless
File.directory? @dir
- FileUtils.chmod 0700, @dir
+ FileUtils.chmod 0o700, @dir
else
- FileUtils.mkdir_p @dir, :mode => @permissions[:trust_dir]
+ FileUtils.mkdir_p @dir, mode: @permissions[:trust_dir]
end
end
end