Module: Gem::OpenPGP

Extended by:
UserInteraction, Shellwords
Defined in:
lib/rubygems/openpgp/verification.rb,
lib/rubygems/openpgp/owner_check.rb,
lib/rubygems/openpgp/gpg_helpers.rb,
lib/rubygems/openpgp/keymaster.rb,
lib/rubygems/openpgp/signing.rb,
lib/rubygems/openpgp/options.rb

Defined Under Namespace

Modules: KeyMaster

Class Method Summary collapse

Class Method Details

.check_rubygems_org_owner(gem_name, fingerprint) ⇒ Object



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# File 'lib/rubygems/openpgp/owner_check.rb', line 5

def self.check_rubygems_org_owner gem_name, fingerprint
  uids_and_trust = get_good_uids(fingerprint)
  owners = Gems.owners(gem_name).map { |o| o["email"] }
  
  good_owner_status = find_good_owner(uids_and_trust, owners)
  if !good_owner_status
    valid_uids = uids_and_trust.map { |x| x[:uid] }
    say add_color("Couldn't match good UID against rubygems.org owners!", :red)
    say add_color("\tGood User Ids: #{pretty_email_list(valid_uids)}", :red)
    say add_color("\trubygems.org Owners: #{pretty_email_list(owners)}", :red)
  end
  
  good_owner_status
rescue Errno::ECONNREFUSED, SocketError => ex
  say add_color("Can't verify ownership.  Couldn't connect with rubygems.org.", :yellow)
  return false
end

.detach_sign(data, key_id = nil, homedir = nil) ⇒ Object

Given a string of data, generate and return a detached signature. By defualt, this will use your primary secret key. This can be overridden by specifying a key_id for another private key.



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/rubygems/openpgp/signing.rb', line 16

def self.detach_sign data, key_id=nil, homedir=nil
  is_gpg_available
  is_key_valid key_id if key_id
  is_homedir_valid homedir if homedir

  key_flag = ""
  key_flag = "-u #{shellescape(key_id)}" if key_id

  homedir_flag = ""
  homedir_flag = "--homedir #{shellescape(homedir)}" if homedir

  gpg_args = "#{key_flag} #{homedir_flag} --detach-sign --armor"
  gpg_results = GPGStatusParser.run_gpg(gpg_args, data)
  did_gpg_error? gpg_results

  gpg_results[:stdout]
end

.sign_gem(gem, key = nil, homedir = nil) ⇒ Object

Signs an existing gemfile by iterating the tar’ed up contents, and signing any contents. creating a new file with original contents and OpenPGP sigs. The OpenPGP sigs are saved as .asc files so they won’t conflict with X509 sigs.

Optional param “key” allows you to use a different private key than the GPG default.



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/rubygems/openpgp/signing.rb', line 41

def self.sign_gem gem, key=nil, homedir=nil
  unsigned_gem = gem + ".unsigned"

  begin
    FileUtils.mv gem, unsigned_gem
  rescue Errno::ENOENT => ex
    raise Gem::CommandLineError, "The gem #{gem} does not seem to exist. (#{ex.message})"
  end

  unsigned_gem_file = File.open(unsigned_gem, "rb")
  signed_gem_file = File.open(gem, "wb")

  signed_gem = Gem::Package::TarWriter.new(signed_gem_file)

  Gem::Package::TarReader.new(unsigned_gem_file).each do |f|

    if f.full_name[-4..-1] == ".asc"
      say("Skipping old OpenPGP signature file #{f.full_name}")
      next
    end

    file_contents = f.read()

    # Copy file no matter what
    signed_gem.add_file(f.full_name, 0644) do |outfile|
      outfile.write(file_contents)
    end

    # Only sign if it's really part of the gem and not
    # a X.509 sig
    if f.full_name[-3..-1] == ".gz"
      say add_color("Signing #{f.full_name.inspect}...",:green)
      signed_gem.add_file(f.full_name + ".asc", 0644) do |outfile|
        outfile.write(Gem::OpenPGP.detach_sign(file_contents,key,homedir))
      end
    elsif f.full_name[-4..-1] != ".sig"
      say add_color("Not signing #{f.full_name.inspect}.  Didn't expect to see that...",:yellow)
    end
  end
  
  signed_gem_file.close
  unsigned_gem_file.close
  File.delete unsigned_gem_file

rescue Exception => ex
  if unsigned_gem_file
    FileUtils.mv unsigned_gem_file, gem
  end
  
  raise
end

.verify(file_name, data, sig, get_key = false, homedir = nil) ⇒ Object

Given a string containing data, and a string containing a detached signature, verify the data. If we can’t verify then raise an exception.

Optionally tell gpg to retrive the key if it’s not provided

returns the fingerprint used to sign the file



26
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
54
# File 'lib/rubygems/openpgp/verification.rb', line 26

def self.verify file_name, data, sig, get_key=false, homedir=nil
  is_gpg_available
  is_homedir_valid homedir if homedir

  data_file = create_tempfile data
  sig_file = create_tempfile sig

  get_key_params = "--keyserver pool.sks-keyservers.net --keyserver-options auto-key-retrieve"
  get_key_params = "" if get_key != true

  homedir_flags = ""
  homedir_flags = "--homedir #{homedir}" if homedir

  gpg_args = "#{get_key_params} #{homedir_flags} --with-colons --verify #{sig_file.path} #{data_file.path}"
  
  status_info = {:file_name => file_name}
  gpg_results = GPGStatusParser.run_gpg(gpg_args) { |message| verify_extract_status_info(message, status_info) }
  
  if status_info[:failure]
    say add_color(status_info[:failure], :red)
    raise Gem::OpenPGPException, "Fail!"
  else
    verify_check_sig status_info
  end

  did_gpg_error? gpg_results

  status_info[:primary_key_fingerprint]
end

.verify_gem(gem, get_key = false, homedir = nil) ⇒ Object



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
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
# File 'lib/rubygems/openpgp/verification.rb', line 56

def self.verify_gem gem, get_key=false, homedir=nil
  raise Gem::CommandLineError, "Gem #{gem} not found."  if !File.exists?(gem)

  gem_name = if Gem::VERSION[0..1] == "2." #gotta be a better way
               Gem::Package.new(gem).spec.name
             else
               Gem::Format.from_file_by_path(gem).spec.name
             end
  
  say("Verifying #{gem_name}...")

  file = File.open(gem,"r")

  fingerprints = []
  tar_files = {}

  Gem::Package::TarReader.new(file).each do |f|
    tar_files[f.full_name] = f.read()
  end
  
  tar_files.keys.each do |file_name|
    next if [".asc",".sig"].include? file_name[-4..-1]

    if file_name[-3..-1] != ".gz"
      say add_color("Skipping #{file_name}.  Only expected .gz files...", :yellow)
      next
    end

    sig_file_name = file_name + ".asc"
    if !tar_files.has_key? sig_file_name
      say add_color("WARNING!!! No sig found for #{file_name}", :red)
      raise Gem::OpenPGPException, "Can't verify without sig, aborting!!!"
    end
    
     begin
      fingerprints << Gem::OpenPGP.verify(file_name, tar_files[file_name], tar_files[sig_file_name], get_key, homedir)
    rescue Gem::OpenPGPException => ex
      color_code = "31"
      say add_color(ex.message, :red)
      raise
    end
  end

  fingerprints.uniq!
  
  # Verify fingerprint and owner
  fingerprints.each do |fp|
    verify_gem_check_fingerprint gem_name, fp
    owner_checks gem_name, fp
  end
  
ensure
  file.close unless file.nil?
end