rubygems-update 0.9.4 → 0.9.5

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rubygems-update might be problematic. Click here for more details.

Files changed (225) hide show
  1. data/ChangeLog +587 -0
  2. data/README +0 -1
  3. data/Rakefile +39 -12
  4. data/TODO +0 -5
  5. data/bin/gem +7 -7
  6. data/bin/update_rubygems +1 -1
  7. data/examples/application/an-app.gemspec +1 -1
  8. data/gemspecs/cgikit-1.1.0.gemspec +1 -2
  9. data/gemspecs/jabber4r.gemspec +1 -1
  10. data/gemspecs/linguistics.gemspec +1 -1
  11. data/gemspecs/ook.gemspec +1 -1
  12. data/gemspecs/progressbar.gemspec +1 -1
  13. data/gemspecs/redcloth.gemspec +1 -1
  14. data/gemspecs/rublog.gemspec +1 -1
  15. data/gemspecs/ruby-doom.gemspec +1 -1
  16. data/gemspecs/rubyjdwp.gemspec +1 -1
  17. data/gemspecs/statistics.gemspec +1 -1
  18. data/lib/rubygems.rb +167 -105
  19. data/lib/rubygems/builder.rb +12 -10
  20. data/lib/rubygems/command.rb +177 -60
  21. data/lib/rubygems/command_manager.rb +30 -38
  22. data/lib/rubygems/commands/build_command.rb +42 -46
  23. data/lib/rubygems/commands/cert_command.rb +72 -69
  24. data/lib/rubygems/commands/check_command.rb +63 -63
  25. data/lib/rubygems/commands/cleanup_command.rb +25 -7
  26. data/lib/rubygems/commands/contents_command.rb +70 -62
  27. data/lib/rubygems/commands/dependency_command.rb +131 -86
  28. data/lib/rubygems/commands/environment_command.rb +67 -46
  29. data/lib/rubygems/commands/fetch_command.rb +62 -0
  30. data/lib/rubygems/commands/generate_index_command.rb +57 -0
  31. data/lib/rubygems/commands/help_command.rb +163 -73
  32. data/lib/rubygems/commands/install_command.rb +114 -128
  33. data/lib/rubygems/commands/list_command.rb +10 -8
  34. data/lib/rubygems/commands/lock_command.rb +101 -0
  35. data/lib/rubygems/commands/mirror_command.rb +105 -0
  36. data/lib/rubygems/commands/outdated_command.rb +24 -15
  37. data/lib/rubygems/commands/pristine_command.rb +118 -88
  38. data/lib/rubygems/commands/query_command.rb +109 -77
  39. data/lib/rubygems/commands/rdoc_command.rb +13 -10
  40. data/lib/rubygems/commands/search_command.rb +10 -8
  41. data/lib/rubygems/commands/server_command.rb +48 -0
  42. data/lib/rubygems/commands/sources_command.rb +104 -83
  43. data/lib/rubygems/commands/specification_command.rb +65 -51
  44. data/lib/rubygems/commands/uninstall_command.rb +17 -12
  45. data/lib/rubygems/commands/unpack_command.rb +68 -68
  46. data/lib/rubygems/commands/update_command.rb +72 -25
  47. data/lib/rubygems/commands/which_command.rb +86 -0
  48. data/lib/rubygems/config_file.rb +202 -78
  49. data/lib/rubygems/custom_require.rb +7 -88
  50. data/lib/rubygems/dependency.rb +65 -0
  51. data/lib/rubygems/dependency_installer.rb +232 -0
  52. data/lib/rubygems/dependency_list.rb +133 -105
  53. data/lib/rubygems/digest/md5.rb +4 -1
  54. data/lib/rubygems/digest/sha2.rb +1 -1
  55. data/lib/rubygems/doc_manager.rb +41 -19
  56. data/lib/rubygems/exceptions.rb +63 -0
  57. data/lib/rubygems/ext.rb +18 -0
  58. data/lib/rubygems/ext/builder.rb +56 -0
  59. data/lib/rubygems/ext/configure_builder.rb +24 -0
  60. data/lib/rubygems/ext/ext_conf_builder.rb +23 -0
  61. data/lib/rubygems/ext/rake_builder.rb +27 -0
  62. data/lib/rubygems/format.rb +16 -6
  63. data/lib/rubygems/gem_openssl.rb +43 -6
  64. data/lib/rubygems/gem_path_searcher.rb +84 -0
  65. data/lib/rubygems/gem_runner.rb +20 -5
  66. data/lib/rubygems/indexer.rb +163 -0
  67. data/lib/rubygems/indexer/abstract_index_builder.rb +80 -0
  68. data/lib/rubygems/indexer/marshal_index_builder.rb +17 -0
  69. data/lib/rubygems/indexer/master_index_builder.rb +53 -0
  70. data/lib/rubygems/indexer/quick_index_builder.rb +48 -0
  71. data/lib/rubygems/install_update_options.rb +87 -0
  72. data/lib/rubygems/installer.rb +316 -562
  73. data/lib/rubygems/local_remote_options.rb +106 -0
  74. data/lib/rubygems/old_format.rb +5 -13
  75. data/lib/rubygems/open-uri.rb +2 -0
  76. data/lib/rubygems/package.rb +28 -32
  77. data/lib/rubygems/platform.rb +187 -0
  78. data/lib/rubygems/remote_fetcher.rb +46 -29
  79. data/lib/rubygems/remote_installer.rb +11 -18
  80. data/lib/rubygems/requirement.rb +157 -0
  81. data/lib/rubygems/rubygems_version.rb +1 -1
  82. data/lib/rubygems/security.rb +715 -457
  83. data/lib/rubygems/server.rb +77 -59
  84. data/lib/rubygems/source_index.rb +154 -83
  85. data/lib/rubygems/source_info_cache.rb +73 -30
  86. data/lib/rubygems/source_info_cache_entry.rb +12 -3
  87. data/lib/rubygems/specification.rb +378 -145
  88. data/lib/rubygems/uninstaller.rb +183 -0
  89. data/lib/rubygems/user_interaction.rb +38 -9
  90. data/lib/rubygems/validator.rb +53 -24
  91. data/lib/rubygems/version.rb +126 -289
  92. data/lib/rubygems/version_option.rb +49 -0
  93. data/pkgs/sources/lib/sources.rb +1 -4
  94. data/pkgs/sources/sources.gemspec +3 -3
  95. data/scripts/gemdoc.rb +0 -1
  96. data/setup.rb +166 -1505
  97. data/test/bogussources.rb +0 -1
  98. data/test/data/gem-private_key.pem +27 -0
  99. data/test/data/gem-public_cert.pem +20 -0
  100. data/test/functional.rb +3 -105
  101. data/test/gemutilities.rb +145 -24
  102. data/test/insure_session.rb +0 -1
  103. data/test/{test_datadir.rb → test_config.rb} +7 -13
  104. data/test/test_gem.rb +360 -9
  105. data/test/test_gem_builder.rb +34 -0
  106. data/test/{test_command.rb → test_gem_command.rb} +119 -62
  107. data/test/{test_parse_commands.rb → test_gem_command_manager.rb} +64 -40
  108. data/test/test_gem_commands_build_command.rb +75 -0
  109. data/test/test_gem_commands_cert_command.rb +122 -0
  110. data/test/test_gem_commands_check_command.rb +25 -0
  111. data/test/test_gem_commands_contents_command.rb +92 -0
  112. data/test/test_gem_commands_dependency_command.rb +108 -0
  113. data/test/test_gem_commands_environment_command.rb +117 -0
  114. data/test/test_gem_commands_fetch_command.rb +34 -0
  115. data/test/test_gem_commands_generate_index_command.rb +32 -0
  116. data/test/test_gem_commands_install_command.rb +160 -0
  117. data/test/test_gem_commands_mirror_command.rb +56 -0
  118. data/test/test_gem_commands_pristine_command.rb +100 -0
  119. data/test/test_gem_commands_query_command.rb +82 -0
  120. data/test/test_gem_commands_sources_command.rb +147 -0
  121. data/test/test_gem_commands_specification_command.rb +93 -0
  122. data/test/test_gem_commands_unpack_command.rb +55 -0
  123. data/test/test_gem_config_file.rb +210 -0
  124. data/test/test_gem_dependency.rb +89 -0
  125. data/test/test_gem_dependency_installer.rb +542 -0
  126. data/test/test_gem_dependency_list.rb +212 -0
  127. data/test/test_gem_doc_manager.rb +32 -0
  128. data/test/test_gem_ext_configure_builder.rb +13 -17
  129. data/test/test_gem_ext_ext_conf_builder.rb +9 -9
  130. data/test/test_gem_ext_rake_builder.rb +23 -11
  131. data/test/test_gem_format.rb +69 -0
  132. data/test/test_gem_gem_path_searcher.rb +57 -0
  133. data/test/test_gem_gem_runner.rb +35 -0
  134. data/test/test_gem_indexer.rb +119 -0
  135. data/test/test_gem_install_update_options.rb +40 -0
  136. data/test/test_gem_installer.rb +796 -0
  137. data/test/test_gem_local_remote_options.rb +84 -0
  138. data/test/test_gem_outdated_command.rb +11 -9
  139. data/test/test_gem_platform.rb +240 -0
  140. data/test/{test_remote_fetcher.rb → test_gem_remote_fetcher.rb} +124 -55
  141. data/test/{test_remote_installer.rb → test_gem_remote_installer.rb} +3 -4
  142. data/test/test_gem_requirement.rb +223 -0
  143. data/test/test_gem_server.rb +71 -0
  144. data/test/test_gem_source_index.rb +429 -0
  145. data/test/test_gem_source_info_cache.rb +79 -17
  146. data/test/test_gem_source_info_cache_entry.rb +11 -9
  147. data/test/test_gem_specification.rb +738 -0
  148. data/test/test_gem_stream_ui.rb +117 -0
  149. data/test/test_gem_validator.rb +70 -0
  150. data/test/test_gem_version.rb +191 -0
  151. data/test/test_gem_version_option.rb +77 -0
  152. data/test/{test_require_gem.rb → test_kernel.rb} +19 -12
  153. data/test/test_open_uri.rb +1 -2
  154. data/test/test_package.rb +45 -34
  155. metadata +116 -141
  156. data/Releases +0 -127
  157. data/bin/gem_mirror +0 -73
  158. data/bin/gem_server +0 -6
  159. data/bin/gemlock +0 -127
  160. data/bin/gemri +0 -24
  161. data/bin/gemwhich +0 -89
  162. data/bin/index_gem_repository.rb +0 -302
  163. data/lib/gemconfigure.rb +0 -24
  164. data/lib/rubygems/gem_commands.rb +0 -273
  165. data/pkgs/sources/sources-0.0.1.gem +0 -0
  166. data/post-install.rb +0 -121
  167. data/test/brokenbuildgem.rb +0 -35
  168. data/test/data/PostMessage-0.0.1.gem +0 -0
  169. data/test/data/a-0.0.1.gem +0 -0
  170. data/test/data/a-0.0.2.gem +0 -0
  171. data/test/data/b-0.0.2.gem +0 -0
  172. data/test/data/broken-1.0.0.gem +0 -0
  173. data/test/data/broken_build/broken-build.gemspec +0 -20
  174. data/test/data/broken_build/ext/extconf.rb +0 -3
  175. data/test/data/broken_build/ext/foo.c +0 -1
  176. data/test/data/c-1.2.gem +0 -0
  177. data/test/data/gemhome/cache/a-0.0.1.gem +0 -0
  178. data/test/data/gemhome/cache/a-0.0.2.gem +0 -0
  179. data/test/data/gemhome/cache/b-0.0.2.gem +0 -0
  180. data/test/data/gemhome/cache/c-1.2.gem +0 -0
  181. data/test/data/gemhome/gems/a-0.0.1/lib/code.rb +0 -1
  182. data/test/data/gemhome/gems/a-0.0.2/lib/code.rb +0 -1
  183. data/test/data/gemhome/gems/b-0.0.2/lib/code.rb +0 -1
  184. data/test/data/gemhome/gems/c-1.2/lib/code.rb +0 -1
  185. data/test/data/gemhome/specifications/a-0.0.1.gemspec +0 -8
  186. data/test/data/gemhome/specifications/a-0.0.2.gemspec +0 -8
  187. data/test/data/gemhome/specifications/b-0.0.2.gemspec +0 -8
  188. data/test/data/gemhome/specifications/c-1.2.gemspec +0 -8
  189. data/test/data/legacy/keyedlist-0.4.0.ruby +0 -11
  190. data/test/data/legacy/keyedlist-0.4.0.yaml +0 -16
  191. data/test/data/lib/code.rb +0 -1
  192. data/test/data/one/README.one +0 -1
  193. data/test/data/one/lib/one.rb +0 -9
  194. data/test/data/one/one-0.0.1.gem +0 -0
  195. data/test/data/one/one.gemspec +0 -17
  196. data/test/data/one/one.yaml +0 -40
  197. data/test/data/post_install.gemspec +0 -19
  198. data/test/functional_extension_gems.rb +0 -48
  199. data/test/functional_generate_yaml_index.rb +0 -104
  200. data/test/gemenvironment.rb +0 -59
  201. data/test/io_capture.rb +0 -33
  202. data/test/mock/gems/gems/sources-0.0.1/lib/sources.rb +0 -11
  203. data/test/mock/gems/specifications/sources-0.0.1.gemspec +0 -8
  204. data/test/onegem.rb +0 -35
  205. data/test/test_builder.rb +0 -34
  206. data/test/test_check_command.rb +0 -34
  207. data/test/test_configfile.rb +0 -42
  208. data/test/test_dependency_list.rb +0 -169
  209. data/test/test_file_list.rb +0 -101
  210. data/test/test_format.rb +0 -49
  211. data/test/test_gem_sources_command.rb +0 -135
  212. data/test/test_gemloadpaths.rb +0 -51
  213. data/test/test_gempaths.rb +0 -170
  214. data/test/test_installer.rb +0 -369
  215. data/test/test_loadmanager.rb +0 -48
  216. data/test/test_process_commands.rb +0 -52
  217. data/test/test_source_index.rb +0 -231
  218. data/test/test_specific_extras.rb +0 -46
  219. data/test/test_specification.rb +0 -565
  220. data/test/test_user_interaction.rb +0 -48
  221. data/test/test_validator.rb +0 -59
  222. data/test/test_version_comparison.rb +0 -321
  223. data/test/testgem.rc +0 -7
  224. data/test/user_capture.rb +0 -7
  225. data/test/yaml_data.rb +0 -63
@@ -1,15 +1,8 @@
1
1
  require 'net/http'
2
2
  require 'uri'
3
- require 'yaml'
4
- require 'zlib'
5
3
 
6
4
  require 'rubygems'
7
- require 'rubygems/user_interaction'
8
-
9
- ##
10
- # Represents an error communicating via HTTP.
11
-
12
- class Gem::RemoteSourceException < Gem::Exception; end
5
+ require 'rubygems/gem_open_uri'
13
6
 
14
7
  ##
15
8
  # RemoteFetcher handles the details of fetching gems and gem information from
@@ -40,7 +33,8 @@ class Gem::RemoteFetcher
40
33
  case proxy
41
34
  when :no_proxy then nil
42
35
  when nil then get_proxy_from_env
43
- else URI.parse(proxy.to_str)
36
+ when URI::HTTP then proxy
37
+ else URI.parse(proxy)
44
38
  end
45
39
  end
46
40
 
@@ -51,28 +45,41 @@ class Gem::RemoteFetcher
51
45
  end
52
46
  rescue Timeout::Error
53
47
  raise FetchError, "timed out fetching #{uri}"
54
- rescue IOError, SocketError, SystemCallError => e
55
- raise FetchError, "#{e.class} reading #{uri}"
56
- rescue
57
- old_uri = uri
58
- uri = uri.downcase
59
- retry if old_uri != uri
60
- raise
48
+ rescue OpenURI::HTTPError, IOError, SocketError, SystemCallError => e
49
+ raise FetchError, "#{e.class}: #{e} reading #{uri}"
61
50
  end
62
51
 
63
52
  # Returns the size of +uri+ in bytes.
64
53
  def fetch_size(uri)
65
- return File.size(get_file_uri_path(uri)) if file_uri?(uri)
66
- require 'net/http'
67
- require 'uri'
68
- u = URI.parse(uri)
69
- raise ArgumentError, 'uri is not an HTTP URI' unless URI::HTTP === u
70
- http = connect_to(u.host, u.port)
71
- resp = http.head(u.request_uri)
72
- raise Gem::RemoteSourceException, "HTTP Response #{resp.code}" if resp.code !~ /^2/
73
- resp['content-length'].to_i
54
+ return File.size(get_file_uri_path(uri)) if file_uri? uri
55
+
56
+ uri = URI.parse uri unless URI::Generic === uri
57
+
58
+ raise ArgumentError, 'uri is not an HTTP URI' unless URI::HTTP === uri
59
+
60
+ http = connect_to uri.host, uri.port
61
+
62
+ request = Net::HTTP::Head.new uri.request_uri
63
+
64
+ request.basic_auth unescape(uri.user), unescape(uri.password) unless
65
+ uri.user.nil? or uri.user.empty?
66
+
67
+ resp = http.request request
68
+
69
+ if resp.code !~ /^2/ then
70
+ raise Gem::RemoteSourceException,
71
+ "HTTP Response #{resp.code} fetching #{uri}"
72
+ end
73
+
74
+ if resp['content-length'] then
75
+ return resp['content-length'].to_i
76
+ else
77
+ resp = http.get uri.request_uri
78
+ return resp.body.size
79
+ end
80
+
74
81
  rescue SocketError, SystemCallError, Timeout::Error => e
75
- raise FetchError, "#{e.message}(#{e.class})"
82
+ raise FetchError, "#{e.message} (#{e.class})"
76
83
  end
77
84
 
78
85
  private
@@ -90,12 +97,17 @@ class Gem::RemoteFetcher
90
97
  # Returns an HTTP proxy URI if one is set in the environment variables.
91
98
  def get_proxy_from_env
92
99
  env_proxy = ENV['http_proxy'] || ENV['HTTP_PROXY']
93
- uri = env_proxy ? URI.parse(env_proxy) : nil
100
+
101
+ return nil if env_proxy.nil? or env_proxy.empty?
102
+
103
+ uri = URI.parse env_proxy
104
+
94
105
  if uri and uri.user.nil? and uri.password.nil? then
95
106
  # Probably we have http_proxy_* variables?
96
107
  uri.user = escape(ENV['http_proxy_user'] || ENV['HTTP_PROXY_USER'])
97
108
  uri.password = escape(ENV['http_proxy_pass'] || ENV['HTTP_PROXY_PASS'])
98
109
  end
110
+
99
111
  uri
100
112
  end
101
113
 
@@ -116,12 +128,11 @@ class Gem::RemoteFetcher
116
128
  # Read the data from the (source based) URI, but if it is a file:// URI,
117
129
  # read from the filesystem instead.
118
130
  def open_uri_or_path(uri, &block)
119
- require 'rubygems/gem_open_uri'
120
131
  if file_uri?(uri)
121
132
  open(get_file_uri_path(uri), &block)
122
133
  else
123
134
  connection_options = {
124
- "User-Agent" => "RubyGems/#{Gem::RubyGemsVersion}"
135
+ "User-Agent" => "RubyGems/#{Gem::RubyGemsVersion} #{Gem::Platform.local}"
125
136
  }
126
137
 
127
138
  if @proxy_uri
@@ -129,6 +140,12 @@ class Gem::RemoteFetcher
129
140
  connection_options[:proxy_http_basic_authentication] = [http_proxy_url, unescape(@proxy_uri.user)||'', unescape(@proxy_uri.password)||'']
130
141
  end
131
142
 
143
+ uri = URI.parse uri unless URI::Generic === uri
144
+ unless uri.nil? || uri.user.nil? || uri.user.empty? then
145
+ connection_options[:http_basic_authentication] =
146
+ [unescape(uri.user), unescape(uri.password)]
147
+ end
148
+
132
149
  open(uri, connection_options, &block)
133
150
  end
134
151
  end
@@ -5,19 +5,12 @@
5
5
  #++
6
6
 
7
7
  require 'fileutils'
8
- require 'yaml'
9
8
 
10
9
  require 'rubygems'
11
10
  require 'rubygems/installer'
12
11
  require 'rubygems/source_info_cache'
13
12
 
14
- require 'sources'
15
-
16
13
  module Gem
17
- class DependencyError < Gem::Exception; end
18
- class GemNotFoundException < Gem::Exception; end
19
- class RemoteInstallationCancelled < Gem::Exception; end
20
- class RemoteInstallationSkipped < Gem::Exception; end
21
14
 
22
15
  class RemoteInstaller
23
16
 
@@ -36,21 +29,21 @@ module Gem
36
29
  @source_index_hash = nil
37
30
  end
38
31
 
39
- # This method will install package_name onto the local system.
32
+ # This method will install package_name onto the local system.
40
33
  #
41
34
  # gem_name::
42
35
  # [String] Name of the Gem to install
43
36
  #
44
37
  # version_requirement::
45
- # [default = "> 0.0.0"] Gem version requirement to install
38
+ # [default = ">= 0"] Gem version requirement to install
46
39
  #
47
40
  # Returns::
48
- # an array of Gem::Specification objects, one for each gem installed.
41
+ # an array of Gem::Specification objects, one for each gem installed.
49
42
  #
50
- def install(gem_name, version_requirement = "> 0.0.0", force=false,
51
- install_dir=Gem.dir, install_stub=true)
43
+ def install(gem_name, version_requirement = Gem::Requirement.default,
44
+ force = false, install_dir = Gem.dir)
52
45
  unless version_requirement.respond_to?(:satisfied_by?)
53
- version_requirement = Version::Requirement.new [version_requirement]
46
+ version_requirement = Gem::Requirement.new [version_requirement]
54
47
  end
55
48
  installed_gems = []
56
49
  begin
@@ -65,9 +58,9 @@ module Gem
65
58
  download_gem(destination_file, source, spec)
66
59
 
67
60
  installer = new_installer(destination_file)
68
- installed_gems.unshift installer.install(force, install_dir, install_stub)
61
+ installed_gems.unshift installer.install(force, install_dir)
69
62
  rescue RemoteInstallationSkipped => e
70
- puts e.message
63
+ alert_error e.message
71
64
  end
72
65
  installed_gems.flatten
73
66
  end
@@ -82,7 +75,7 @@ module Gem
82
75
  end
83
76
  @source_index_hash
84
77
  end
85
-
78
+
86
79
  # Finds the Gem::Specification objects and the corresponding source URI
87
80
  # for gems matching +gem_name+ and +version_requirement+
88
81
  def specs_n_sources_matching(gem_name, version_requirement)
@@ -157,7 +150,7 @@ module Gem
157
150
 
158
151
  # Install all the given dependencies. Returns an array of
159
152
  # Gem::Specification objects, one for each dependency installed.
160
- #
153
+ #
161
154
  # TODO: For now, we recursively install, but this is not the right
162
155
  # way to do things (e.g. if a package fails to download, we
163
156
  # shouldn't install anything).
@@ -193,7 +186,7 @@ module Gem
193
186
  out.write(body)
194
187
  end
195
188
  end
196
-
189
+
197
190
  def new_installer(gem)
198
191
  return Installer.new(gem, @options)
199
192
  end
@@ -0,0 +1,157 @@
1
+ #--
2
+ # Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
3
+ # All rights reserved.
4
+ # See LICENSE.txt for permissions.
5
+ #++
6
+
7
+ require 'rubygems/version'
8
+
9
+ ##
10
+ # Requirement version includes a prefaced comparator in addition
11
+ # to a version number.
12
+ #
13
+ # A Requirement object can actually contain multiple, er,
14
+ # requirements, as in (> 1.2, < 2.0).
15
+ class Gem::Requirement
16
+
17
+ include Comparable
18
+
19
+ OPS = {
20
+ "=" => lambda { |v, r| v == r },
21
+ "!=" => lambda { |v, r| v != r },
22
+ ">" => lambda { |v, r| v > r },
23
+ "<" => lambda { |v, r| v < r },
24
+ ">=" => lambda { |v, r| v >= r },
25
+ "<=" => lambda { |v, r| v <= r },
26
+ "~>" => lambda { |v, r| v >= r && v < r.bump }
27
+ }
28
+
29
+ OP_RE = /#{OPS.keys.map{ |k| Regexp.quote k }.join '|'}/o
30
+
31
+ ##
32
+ # Factory method to create a Gem::Requirement object. Input may be a
33
+ # Version, a String, or nil. Intended to simplify client code.
34
+ #
35
+ # If the input is "weird", the default version requirement is returned.
36
+ #
37
+ def self.create(input)
38
+ case input
39
+ when Gem::Requirement then
40
+ input
41
+ when Gem::Version, Array then
42
+ new input
43
+ else
44
+ if input.respond_to? :to_str then
45
+ self.new [input.to_str]
46
+ else
47
+ self.default
48
+ end
49
+ end
50
+ end
51
+
52
+ ##
53
+ # A default "version requirement" can surely _only_ be '>= 0'.
54
+ #--
55
+ # This comment once said:
56
+ #
57
+ # "A default "version requirement" can surely _only_ be '> 0'."
58
+ def self.default
59
+ self.new ['>= 0']
60
+ end
61
+
62
+ ##
63
+ # Constructs a Requirement from +requirements+ which can be a String, a
64
+ # Gem::Version, or an Array of those. See parse for details on the
65
+ # formatting of requirement strings.
66
+ def initialize(requirements)
67
+ @requirements = case requirements
68
+ when Array then
69
+ requirements.map do |requirement|
70
+ parse(requirement)
71
+ end
72
+ else
73
+ [parse(requirements)]
74
+ end
75
+ @version = nil # Avoid warnings.
76
+ end
77
+
78
+ # Marshal raw requirements, rather than the full object
79
+ def marshal_dump
80
+ [@requirements]
81
+ end
82
+
83
+ # Load custom marshal format
84
+ def marshal_load(array)
85
+ @requirements = array[0]
86
+ @version = nil
87
+ end
88
+
89
+ def to_s # :nodoc:
90
+ as_list.join(", ")
91
+ end
92
+
93
+ def as_list
94
+ normalize
95
+ @requirements.collect { |req|
96
+ "#{req[0]} #{req[1]}"
97
+ }
98
+ end
99
+
100
+ def normalize
101
+ return if not defined? @version or @version.nil?
102
+ @requirements = [parse(@version)]
103
+ @nums = nil
104
+ @version = nil
105
+ @op = nil
106
+ end
107
+
108
+ ##
109
+ # Is the requirement satifised by +version+.
110
+ #
111
+ # version:: [Gem::Version] the version to compare against
112
+ # return:: [Boolean] true if this requirement is satisfied by
113
+ # the version, otherwise false
114
+ #
115
+ def satisfied_by?(version)
116
+ normalize
117
+ @requirements.all? { |op, rv| satisfy?(op, version, rv) }
118
+ end
119
+
120
+ ##
121
+ # Is "version op required_version" satisfied?
122
+ #
123
+ def satisfy?(op, version, required_version)
124
+ OPS[op].call(version, required_version)
125
+ end
126
+
127
+ ##
128
+ # Parse the version requirement obj returning the operator and version.
129
+ #
130
+ # The requirement can be a String or a Gem::Version. A String can be an
131
+ # operator (<, <=, =, =>, >, !=, ~>), a version number, or both, operator
132
+ # first.
133
+ def parse(obj)
134
+ case obj
135
+ when /^\s*(#{OP_RE})\s*([0-9.]+)\s*$/o then
136
+ [$1, Gem::Version.new($2)]
137
+ when /^\s*([0-9.]+)\s*$/ then
138
+ ['=', Gem::Version.new($1)]
139
+ when /^\s*(#{OP_RE})\s*$/o then
140
+ [$1, Gem::Version.new('0')]
141
+ when Gem::Version then
142
+ ['=', obj]
143
+ else
144
+ fail ArgumentError, "Illformed requirement [#{obj.inspect}]"
145
+ end
146
+ end
147
+
148
+ def <=>(other)
149
+ to_s <=> other.to_s
150
+ end
151
+
152
+ def hash # :nodoc:
153
+ to_s.hash
154
+ end
155
+
156
+ end
157
+
@@ -2,5 +2,5 @@
2
2
  # This file is auto-generated by build scripts.
3
3
  # See: rake update_version
4
4
  module Gem
5
- RubyGemsVersion = '0.9.4'
5
+ RubyGemsVersion = '0.9.5'
6
6
  end
@@ -1,527 +1,785 @@
1
- #!/usr/bin/env ruby
2
1
  #--
3
2
  # Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
4
3
  # All rights reserved.
5
4
  # See LICENSE.txt for permissions.
6
5
  #++
7
6
 
8
-
9
7
  require 'rubygems/gem_openssl'
10
8
 
11
- module Gem
12
- module SSL
9
+ # = Signed Gems README
10
+ #
11
+ # == Table of Contents
12
+ # * Overview
13
+ # * Walkthrough
14
+ # * Command-Line Options
15
+ # * OpenSSL Reference
16
+ # * Bugs/TODO
17
+ # * About the Author
18
+ #
19
+ # == Overview
20
+ #
21
+ # Gem::Security implements cryptographic signatures in RubyGems. The section
22
+ # below is a step-by-step guide to using signed gems and generating your own.
23
+ #
24
+ # == Walkthrough
25
+ #
26
+ # In order to start signing your gems, you'll need to build a private key and
27
+ # a self-signed certificate. Here's how:
28
+ #
29
+ # # build a private key and certificate for gemmaster@example.com
30
+ # $ gem cert --build gemmaster@example.com
31
+ #
32
+ # This could take anywhere from 5 seconds to 10 minutes, depending on the
33
+ # speed of your computer (public key algorithms aren't exactly the speediest
34
+ # crypto algorithms in the world). When it's finished, you'll see the files
35
+ # "gem-private_key.pem" and "gem-public_cert.pem" in the current directory.
36
+ #
37
+ # First things first: take the "gem-private_key.pem" file and move it
38
+ # somewhere private, preferably a directory only you have access to, a floppy
39
+ # (yuck!), a CD-ROM, or something comparably secure. Keep your private key
40
+ # hidden; if it's compromised, someone can sign packages as you (note: PKI has
41
+ # ways of mitigating the risk of stolen keys; more on that later).
42
+ #
43
+ # Now, let's sign an existing gem. I'll be using my Imlib2-Ruby bindings, but
44
+ # you can use whatever gem you'd like. Open up your existing gemspec file and
45
+ # add the following lines:
46
+ #
47
+ # # signing key and certificate chain
48
+ # s.signing_key = '/mnt/floppy/gem-private_key.pem'
49
+ # s.cert_chain = ['gem-public_cert.pem']
50
+ #
51
+ # (Be sure to replace "/mnt/floppy" with the ultra-secret path to your private
52
+ # key).
53
+ #
54
+ # After that, go ahead and build your gem as usual. Congratulations, you've
55
+ # just built your first signed gem! If you peek inside your gem file, you'll
56
+ # see a couple of new files have been added:
57
+ #
58
+ # $ tar tf tar tf Imlib2-Ruby-0.5.0.gem
59
+ # data.tar.gz
60
+ # data.tar.gz.sig
61
+ # metadata.gz
62
+ # metadata.gz.sig
63
+ #
64
+ # Now let's verify the signature. Go ahead and install the gem, but add the
65
+ # following options: "-P HighSecurity", like this:
66
+ #
67
+ # # install the gem with using the security policy "HighSecurity"
68
+ # $ sudo gem install Imlib2-Ruby-0.5.0.gem -P HighSecurity
69
+ #
70
+ # The -P option sets your security policy -- we'll talk about that in just a
71
+ # minute. Eh, what's this?
72
+ #
73
+ # Attempting local installation of 'Imlib2-Ruby-0.5.0.gem'
74
+ # ERROR: Error installing gem Imlib2-Ruby-0.5.0.gem[.gem]: Couldn't
75
+ # verify data signature: Untrusted Signing Chain Root: cert =
76
+ # '/CN=gemmaster/DC=example/DC=com', error = 'path
77
+ # "/root/.rubygems/trust/cert-15dbb43a6edf6a70a85d4e784e2e45312cff7030.pem"
78
+ # does not exist'
79
+ #
80
+ # The culprit here is the security policy. RubyGems has several different
81
+ # security policies. Let's take a short break and go over the security
82
+ # policies. Here's a list of the available security policies, and a brief
83
+ # description of each one:
84
+ #
85
+ # * NoSecurity - Well, no security at all. Signed packages are treated like
86
+ # unsigned packages.
87
+ # * LowSecurity - Pretty much no security. If a package is signed then
88
+ # RubyGems will make sure the signature matches the signing
89
+ # certificate, and that the signing certificate hasn't expired, but
90
+ # that's it. A malicious user could easily circumvent this kind of
91
+ # security.
92
+ # * MediumSecurity - Better than LowSecurity and NoSecurity, but still
93
+ # fallible. Package contents are verified against the signing
94
+ # certificate, and the signing certificate is checked for validity,
95
+ # and checked against the rest of the certificate chain (if you don't
96
+ # know what a certificate chain is, stay tuned, we'll get to that).
97
+ # The biggest improvement over LowSecurity is that MediumSecurity
98
+ # won't install packages that are signed by untrusted sources.
99
+ # Unfortunately, MediumSecurity still isn't totally secure -- a
100
+ # malicious user can still unpack the gem, strip the signatures, and
101
+ # distribute the gem unsigned.
102
+ # * HighSecurity - Here's the bugger that got us into this mess.
103
+ # The HighSecurity policy is identical to the MediumSecurity policy,
104
+ # except that it does not allow unsigned gems. A malicious user
105
+ # doesn't have a whole lot of options here; he can't modify the
106
+ # package contents without invalidating the signature, and he can't
107
+ # modify or remove signature or the signing certificate chain, or
108
+ # RubyGems will simply refuse to install the package. Oh well, maybe
109
+ # he'll have better luck causing problems for CPAN users instead :).
110
+ #
111
+ # So, the reason RubyGems refused to install our shiny new signed gem was
112
+ # because it was from an untrusted source. Well, my code is infallible
113
+ # (hah!), so I'm going to add myself as a trusted source.
114
+ #
115
+ # Here's how:
116
+ #
117
+ # # add trusted certificate
118
+ # gem cert --add gem-public_cert.pem
119
+ #
120
+ # I've added my public certificate as a trusted source. Now I can install
121
+ # packages signed my private key without any hassle. Let's try the install
122
+ # command above again:
123
+ #
124
+ # # install the gem with using the HighSecurity policy (and this time
125
+ # # without any shenanigans)
126
+ # $ sudo gem install Imlib2-Ruby-0.5.0.gem -P HighSecurity
127
+ #
128
+ # This time RubyGems should accept your signed package and begin installing.
129
+ # While you're waiting for RubyGems to work it's magic, have a look at some of
130
+ # the other security commands:
131
+ #
132
+ # Usage: gem cert [options]
133
+ #
134
+ # Options:
135
+ # -a, --add CERT Add a trusted certificate.
136
+ # -l, --list List trusted certificates.
137
+ # -r, --remove STRING Remove trusted certificates containing STRING.
138
+ # -b, --build EMAIL_ADDR Build private key and self-signed certificate
139
+ # for EMAIL_ADDR.
140
+ # -C, --certificate CERT Certificate for --sign command.
141
+ # -K, --private-key KEY Private key for --sign command.
142
+ # -s, --sign NEWCERT Sign a certificate with my key and certificate.
143
+ #
144
+ # (By the way, you can pull up this list any time you'd like by typing "gem
145
+ # cert --help")
146
+ #
147
+ # Hmm. We've already covered the "--build" option, and the "--add", "--list",
148
+ # and "--remove" commands seem fairly straightforward; they allow you to add,
149
+ # list, and remove the certificates in your trusted certificate list. But
150
+ # what's with this "--sign" option?
151
+ #
152
+ # To answer that question, let's take a look at "certificate chains", a
153
+ # concept I mentioned earlier. There are a couple of problems with
154
+ # self-signed certificates: first of all, self-signed certificates don't offer
155
+ # a whole lot of security. Sure, the certificate says Yukihiro Matsumoto, but
156
+ # how do I know it was actually generated and signed by matz himself unless he
157
+ # gave me the certificate in person?
158
+ #
159
+ # The second problem is scalability. Sure, if there are 50 gem authors, then
160
+ # I have 50 trusted certificates, no problem. What if there are 500 gem
161
+ # authors? 1000? Having to constantly add new trusted certificates is a
162
+ # pain, and it actually makes the trust system less secure by encouraging
163
+ # RubyGems users to blindly trust new certificates.
164
+ #
165
+ # Here's where certificate chains come in. A certificate chain establishes an
166
+ # arbitrarily long chain of trust between an issuing certificate and a child
167
+ # certificate. So instead of trusting certificates on a per-developer basis,
168
+ # we use the PKI concept of certificate chains to build a logical hierarchy of
169
+ # trust. Here's a hypothetical example of a trust hierarchy based (roughly)
170
+ # on geography:
171
+ #
172
+ #
173
+ # --------------------------
174
+ # | rubygems@rubyforge.org |
175
+ # --------------------------
176
+ # |
177
+ # -----------------------------------
178
+ # | |
179
+ # ---------------------------- -----------------------------
180
+ # | seattle.rb@zenspider.com | | dcrubyists@richkilmer.com |
181
+ # ---------------------------- -----------------------------
182
+ # | | | |
183
+ # --------------- ---------------- ----------- --------------
184
+ # | alf@seattle | | bob@portland | | pabs@dc | | tomcope@dc |
185
+ # --------------- ---------------- ----------- --------------
186
+ #
187
+ #
188
+ # Now, rather than having 4 trusted certificates (one for alf@seattle,
189
+ # bob@portland, pabs@dc, and tomecope@dc), a user could actually get by with 1
190
+ # certificate: the "rubygems@rubyforge.org" certificate. Here's how it works:
191
+ #
192
+ # I install "Alf2000-Ruby-0.1.0.gem", a package signed by "alf@seattle". I've
193
+ # never heard of "alf@seattle", but his certificate has a valid signature from
194
+ # the "seattle.rb@zenspider.com" certificate, which in turn has a valid
195
+ # signature from the "rubygems@rubyforge.org" certificate. Voila! At this
196
+ # point, it's much more reasonable for me to trust a package signed by
197
+ # "alf@seattle", because I can establish a chain to "rubygems@rubyforge.org",
198
+ # which I do trust.
199
+ #
200
+ # And the "--sign" option allows all this to happen. A developer creates
201
+ # their build certificate with the "--build" option, then has their
202
+ # certificate signed by taking it with them to their next regional Ruby meetup
203
+ # (in our hypothetical example), and it's signed there by the person holding
204
+ # the regional RubyGems signing certificate, which is signed at the next
205
+ # RubyConf by the holder of the top-level RubyGems certificate. At each point
206
+ # the issuer runs the same command:
207
+ #
208
+ # # sign a certificate with the specified key and certificate
209
+ # # (note that this modifies client_cert.pem!)
210
+ # $ gem cert -K /mnt/floppy/issuer-priv_key.pem -C issuer-pub_cert.pem
211
+ # --sign client_cert.pem
212
+ #
213
+ # Then the holder of issued certificate (in this case, our buddy
214
+ # "alf@seattle"), can start using this signed certificate to sign RubyGems.
215
+ # By the way, in order to let everyone else know about his new fancy signed
216
+ # certificate, "alf@seattle" would change his gemspec file to look like this:
217
+ #
218
+ # # signing key (still kept in an undisclosed location!)
219
+ # s.signing_key = '/mnt/floppy/alf-private_key.pem'
220
+ #
221
+ # # certificate chain (includes the issuer certificate now too)
222
+ # s.cert_chain = ['/home/alf/doc/seattlerb-public_cert.pem',
223
+ # '/home/alf/doc/alf_at_seattle-public_cert.pem']
224
+ #
225
+ # Obviously, this RubyGems trust infrastructure doesn't exist yet. Also, in
226
+ # the "real world" issuers actually generate the child certificate from a
227
+ # certificate request, rather than sign an existing certificate. And our
228
+ # hypothetical infrastructure is missing a certificate revocation system.
229
+ # These are that can be fixed in the future...
230
+ #
231
+ # I'm sure your new signed gem has finished installing by now (unless you're
232
+ # installing rails and all it's dependencies, that is ;D). At this point you
233
+ # should know how to do all of these new and interesting things:
234
+ #
235
+ # * build a gem signing key and certificate
236
+ # * modify your existing gems to support signing
237
+ # * adjust your security policy
238
+ # * modify your trusted certificate list
239
+ # * sign a certificate
240
+ #
241
+ # If you've got any questions, feel free to contact me at the email address
242
+ # below. The next couple of sections
243
+ #
244
+ #
245
+ # == Command-Line Options
246
+ #
247
+ # Here's a brief summary of the certificate-related command line options:
248
+ #
249
+ # gem install
250
+ # -P, --trust-policy POLICY Specify gem trust policy.
251
+ #
252
+ # gem cert
253
+ # -a, --add CERT Add a trusted certificate.
254
+ # -l, --list List trusted certificates.
255
+ # -r, --remove STRING Remove trusted certificates containing
256
+ # STRING.
257
+ # -b, --build EMAIL_ADDR Build private key and self-signed
258
+ # certificate for EMAIL_ADDR.
259
+ # -C, --certificate CERT Certificate for --sign command.
260
+ # -K, --private-key KEY Private key for --sign command.
261
+ # -s, --sign NEWCERT Sign a certificate with my key and
262
+ # certificate.
263
+ #
264
+ # A more detailed description of each options is available in the walkthrough
265
+ # above.
266
+ #
267
+ #
268
+ # == OpenSSL Reference
269
+ #
270
+ # The .pem files generated by --build and --sign are just basic OpenSSL PEM
271
+ # files. Here's a couple of useful commands for manipulating them:
272
+ #
273
+ # # convert a PEM format X509 certificate into DER format:
274
+ # # (note: Windows .cer files are X509 certificates in DER format)
275
+ # $ openssl x509 -in input.pem -outform der -out output.der
276
+ #
277
+ # # print out the certificate in a human-readable format:
278
+ # $ openssl x509 -in input.pem -noout -text
279
+ #
280
+ # And you can do the same thing with the private key file as well:
281
+ #
282
+ # # convert a PEM format RSA key into DER format:
283
+ # $ openssl rsa -in input_key.pem -outform der -out output_key.der
284
+ #
285
+ # # print out the key in a human readable format:
286
+ # $ openssl rsa -in input_key.pem -noout -text
287
+ #
288
+ # == Bugs/TODO
289
+ #
290
+ # * There's no way to define a system-wide trust list.
291
+ # * custom security policies (from a YAML file, etc)
292
+ # * Simple method to generate a signed certificate request
293
+ # * Support for OCSP, SCVP, CRLs, or some other form of cert
294
+ # status check (list is in order of preference)
295
+ # * Support for encrypted private keys
296
+ # * Some sort of semi-formal trust hierarchy (see long-winded explanation
297
+ # above)
298
+ # * Path discovery (for gem certificate chains that don't have a self-signed
299
+ # root) -- by the way, since we don't have this, THE ROOT OF THE CERTIFICATE
300
+ # CHAIN MUST BE SELF SIGNED if Policy#verify_root is true (and it is for the
301
+ # MediumSecurity and HighSecurity policies)
302
+ # * Better explanation of X509 naming (ie, we don't have to use email
303
+ # addresses)
304
+ # * Possible alternate signing mechanisms (eg, via PGP). this could be done
305
+ # pretty easily by adding a :signing_type attribute to the gemspec, then add
306
+ # the necessary support in other places
307
+ # * Honor AIA field (see note about OCSP above)
308
+ # * Maybe honor restriction extensions?
309
+ # * Might be better to store the certificate chain as a PKCS#7 or PKCS#12
310
+ # file, instead of an array embedded in the metadata. ideas?
311
+ # * Possibly embed signature and key algorithms into metadata (right now
312
+ # they're assumed to be the same as what's set in Gem::Security::OPT)
313
+ #
314
+ # == About the Author
315
+ #
316
+ # Paul Duncan <pabs@pablotron.org>
317
+ # http://pablotron.org/
318
+
319
+ module Gem::Security
320
+
321
+ class Exception < Exception; end
13
322
 
14
- # We make our own versions of the constants here. This allows us
15
- # to reference the constants, even though some systems might not
16
- # have SSL installed in the Ruby core package.
17
- #
18
- # These constants are only used during load time. At runtime, any
19
- # method that makes a direct reference to SSL software must be
20
- # protected with a Gem.ensure_ssl_available call.
21
- #
22
- if Gem.ssl_available?
23
- PKEY_RSA = OpenSSL::PKey::RSA
24
- DIGEST_SHA1 = OpenSSL::Digest::SHA1
25
- else
26
- PKEY_RSA = :rsa
27
- DIGEST_SHA1 = :sha1
28
- end
29
- end
30
- end
31
-
32
- module OpenSSL # :nodoc:
33
- module X509 # :nodoc:
34
- class Certificate
35
- #
36
- # Check the validity of this certificate.
37
- #
38
- def check_validity(issuer_cert = nil, time = Time.now)
39
- ret = if @not_before && @not_before > time
40
- [false, :expired, "not valid before '#@not_before'"]
41
- elsif @not_after && @not_after < time
42
- [false, :expired, "not valid after '#@not_after'"]
43
- elsif issuer_cert && !verify(issuer_cert.public_key)
44
- [false, :issuer, "#{issuer_cert.subject} is not issuer"]
45
- else
46
- [true, :ok, 'Valid certificate']
47
- end
48
-
49
- # return hash
50
- { :is_valid => ret[0], :error => ret[1], :desc => ret[2] }
51
- end
52
- end
53
- end
54
- end
323
+ #
324
+ # default options for most of the methods below
325
+ #
326
+ OPT = {
327
+ # private key options
328
+ :key_algo => Gem::SSL::PKEY_RSA,
329
+ :key_size => 2048,
330
+
331
+ # public cert options
332
+ :cert_age => 365 * 24 * 3600, # 1 year
333
+ :dgst_algo => Gem::SSL::DIGEST_SHA1,
334
+
335
+ # x509 certificate extensions
336
+ :cert_exts => {
337
+ 'basicConstraints' => 'CA:FALSE',
338
+ 'subjectKeyIdentifier' => 'hash',
339
+ 'keyUsage' => 'keyEncipherment,dataEncipherment,digitalSignature',
340
+ },
341
+
342
+ # save the key and cert to a file in build_self_signed_cert()?
343
+ :save_key => true,
344
+ :save_cert => true,
345
+
346
+ # if you define either of these, then they'll be used instead of
347
+ # the output_fmt macro below
348
+ :save_key_path => nil,
349
+ :save_cert_path => nil,
350
+
351
+ # output name format for self-signed certs
352
+ :output_fmt => 'gem-%s.pem',
353
+ :munge_re => Regexp.new(/[^a-z0-9_.-]+/),
354
+
355
+ # output directory for trusted certificate checksums
356
+ :trust_dir => File::join(Gem.user_home, '.gem', 'trust'),
357
+
358
+ # default permissions for trust directory and certs
359
+ :perms => {
360
+ :trust_dir => 0700,
361
+ :trusted_cert => 0600,
362
+ :signing_cert => 0600,
363
+ :signing_key => 0600,
364
+ },
365
+ }
55
366
 
56
- module Gem
57
367
  #
58
- # Security: a set of methods, classes, and security policies for
59
- # checking the validity of signed gem files.
368
+ # A Gem::Security::Policy object encapsulates the settings for verifying
369
+ # signed gem files. This is the base class. You can either declare an
370
+ # instance of this or use one of the preset security policies below.
60
371
  #
61
- module Security
62
- class Exception < Exception; end
63
-
64
- #
65
- # default options for most of the methods below
66
- #
67
- OPT = {
68
- # private key options
69
- :key_algo => Gem::SSL::PKEY_RSA,
70
- :key_size => 2048,
71
-
72
- # public cert options
73
- :cert_age => 365 * 24 * 3600, # 1 year
74
- :dgst_algo => Gem::SSL::DIGEST_SHA1,
75
-
76
- # x509 certificate extensions
77
- :cert_exts => {
78
- 'basicConstraints' => 'CA:FALSE',
79
- 'subjectKeyIdentifier' => 'hash',
80
- 'keyUsage' => 'keyEncipherment,dataEncipherment,digitalSignature',
81
- },
82
-
83
- # save the key and cert to a file in build_self_signed_cert()?
84
- :save_key => true,
85
- :save_cert => true,
86
-
87
- # if you define either of these, then they'll be used instead of
88
- # the output_fmt macro below
89
- :save_key_path => nil,
90
- :save_cert_path => nil,
91
-
92
- # output name format for self-signed certs
93
- :output_fmt => 'gem-%s.pem',
94
- :munge_re => Regexp.new(/[^a-z0-9_.-]+/),
95
-
96
- # output directory for trusted certificate checksums
97
- :trust_dir => File::join(Gem.user_home, '.gem', 'trust'),
98
-
99
- # default permissions for trust directory and certs
100
- :perms => {
101
- :trust_dir => 0700,
102
- :trusted_cert => 0600,
103
- :signing_cert => 0600,
104
- :signing_key => 0600,
105
- },
106
- }
372
+ class Policy
373
+ attr_accessor :verify_data, :verify_signer, :verify_chain,
374
+ :verify_root, :only_trusted, :only_signed
107
375
 
108
376
  #
109
- # A Gem::Security::Policy object encapsulates the settings for
110
- # verifying signed gem files. This is the base class. You can
111
- # either declare an instance of this or use one of the preset
112
- # security policies below.
377
+ # Create a new Gem::Security::Policy object with the given mode and
378
+ # options.
113
379
  #
114
- class Policy
115
- attr_accessor :verify_data, :verify_signer, :verify_chain,
116
- :verify_root, :only_trusted, :only_signed
117
-
118
- #
119
- # Create a new Gem::Security::Policy object with the given mode
120
- # and options.
121
- #
122
- def initialize(policy = {}, opt = {})
123
- # set options
124
- @opt = Gem::Security::OPT.merge(opt)
125
-
126
- # build policy
127
- policy.each_pair do |key, val|
128
- case key
129
- when :verify_data then @verify_data = val
130
- when :verify_signer then @verify_signer = val
131
- when :verify_chain then @verify_chain = val
132
- when :verify_root then @verify_root = val
133
- when :only_trusted then @only_trusted = val
134
- when :only_signed then @only_signed = val
135
- end
380
+ def initialize(policy = {}, opt = {})
381
+ # set options
382
+ @opt = Gem::Security::OPT.merge(opt)
383
+
384
+ # build policy
385
+ policy.each_pair do |key, val|
386
+ case key
387
+ when :verify_data then @verify_data = val
388
+ when :verify_signer then @verify_signer = val
389
+ when :verify_chain then @verify_chain = val
390
+ when :verify_root then @verify_root = val
391
+ when :only_trusted then @only_trusted = val
392
+ when :only_signed then @only_signed = val
136
393
  end
137
394
  end
395
+ end
138
396
 
139
- #
140
- # Get the path to the file for this cert.
141
- #
142
- def self.trusted_cert_path(cert, opt = {})
143
- opt = Gem::Security::OPT.merge(opt)
397
+ #
398
+ # Get the path to the file for this cert.
399
+ #
400
+ def self.trusted_cert_path(cert, opt = {})
401
+ opt = Gem::Security::OPT.merge(opt)
144
402
 
145
- # get digest algorithm, calculate checksum of root.subject
146
- algo = opt[:dgst_algo]
147
- dgst = algo.hexdigest(cert.subject.to_s)
403
+ # get digest algorithm, calculate checksum of root.subject
404
+ algo = opt[:dgst_algo]
405
+ dgst = algo.hexdigest(cert.subject.to_s)
148
406
 
149
- # build path to trusted cert file
150
- name = "cert-#{dgst}.pem"
407
+ # build path to trusted cert file
408
+ name = "cert-#{dgst}.pem"
151
409
 
152
- # join and return path components
153
- File::join(opt[:trust_dir], name)
154
- end
410
+ # join and return path components
411
+ File::join(opt[:trust_dir], name)
412
+ end
155
413
 
156
- #
157
- # Verify that the gem data with the given signature and signing
158
- # chain matched this security policy at the specified time.
159
- #
160
- def verify_gem(signature, data, chain, time = Time.now)
161
- Gem.ensure_ssl_available
162
- cert_class = OpenSSL::X509::Certificate
163
- exc = Gem::Security::Exception
164
- chain ||= []
165
-
166
- chain = chain.map{ |str| cert_class.new(str) }
167
- signer, ch_len = chain[-1], chain.size
168
-
169
- # make sure signature is valid
170
- if @verify_data
171
- # get digest algorithm (TODO: this should be configurable)
172
- dgst = @opt[:dgst_algo]
173
-
174
- # verify the data signature (this is the most important part,
175
- # so don't screw it up :D)
176
- v = signer.public_key.verify(dgst.new, signature, data)
177
- raise exc, "Invalid Gem Signature" unless v
178
-
179
- # make sure the signer is valid
180
- if @verify_signer
181
- # make sure the signing cert is valid right now
182
- v = signer.check_validity(nil, time)
183
- raise exc, "Invalid Signature: #{v[:desc]}" unless v[:is_valid]
184
- end
414
+ #
415
+ # Verify that the gem data with the given signature and signing chain
416
+ # matched this security policy at the specified time.
417
+ #
418
+ def verify_gem(signature, data, chain, time = Time.now)
419
+ Gem.ensure_ssl_available
420
+ cert_class = OpenSSL::X509::Certificate
421
+ exc = Gem::Security::Exception
422
+ chain ||= []
423
+
424
+ chain = chain.map{ |str| cert_class.new(str) }
425
+ signer, ch_len = chain[-1], chain.size
426
+
427
+ # make sure signature is valid
428
+ if @verify_data
429
+ # get digest algorithm (TODO: this should be configurable)
430
+ dgst = @opt[:dgst_algo]
431
+
432
+ # verify the data signature (this is the most important part, so don't
433
+ # screw it up :D)
434
+ v = signer.public_key.verify(dgst.new, signature, data)
435
+ raise exc, "Invalid Gem Signature" unless v
436
+
437
+ # make sure the signer is valid
438
+ if @verify_signer
439
+ # make sure the signing cert is valid right now
440
+ v = signer.check_validity(nil, time)
441
+ raise exc, "Invalid Signature: #{v[:desc]}" unless v[:is_valid]
185
442
  end
443
+ end
186
444
 
187
- # make sure the certificate chain is valid
188
- if @verify_chain
189
- # iterate down over the chain and verify each certificate
190
- # against it's issuer
191
- (ch_len - 1).downto(1) do |i|
192
- issuer, cert = chain[i - 1, 2]
193
- v = cert.check_validity(issuer, time)
194
- raise exc, "%s: cert = '%s', error = '%s'" % [
195
- 'Invalid Signing Chain', cert.subject, v[:desc]
196
- ] unless v[:is_valid]
197
- end
445
+ # make sure the certificate chain is valid
446
+ if @verify_chain
447
+ # iterate down over the chain and verify each certificate against it's
448
+ # issuer
449
+ (ch_len - 1).downto(1) do |i|
450
+ issuer, cert = chain[i - 1, 2]
451
+ v = cert.check_validity(issuer, time)
452
+ raise exc, "%s: cert = '%s', error = '%s'" % [
453
+ 'Invalid Signing Chain', cert.subject, v[:desc]
454
+ ] unless v[:is_valid]
455
+ end
198
456
 
199
- # verify root of chain
200
- if @verify_root
201
- # make sure root is self-signed
202
- root = chain[0]
203
- raise exc, "%s: %s (subject = '%s', issuer = '%s')" % [
204
- 'Invalid Signing Chain Root',
457
+ # verify root of chain
458
+ if @verify_root
459
+ # make sure root is self-signed
460
+ root = chain[0]
461
+ raise exc, "%s: %s (subject = '%s', issuer = '%s')" % [
462
+ 'Invalid Signing Chain Root',
205
463
  'Subject does not match Issuer for Gem Signing Chain',
206
464
  root.subject.to_s,
207
465
  root.issuer.to_s,
208
- ] unless root.issuer.to_s == root.subject.to_s
466
+ ] unless root.issuer.to_s == root.subject.to_s
209
467
 
210
- # make sure root is valid
211
- v = root.check_validity(root, time)
212
- raise exc, "%s: cert = '%s', error = '%s'" % [
213
- 'Invalid Signing Chain Root', root.subject, v[:desc]
214
- ] unless v[:is_valid]
468
+ # make sure root is valid
469
+ v = root.check_validity(root, time)
470
+ raise exc, "%s: cert = '%s', error = '%s'" % [
471
+ 'Invalid Signing Chain Root', root.subject, v[:desc]
472
+ ] unless v[:is_valid]
215
473
 
216
- # verify that the chain root is trusted
217
- if @only_trusted
218
- # get digest algorithm, calculate checksum of root.subject
219
- algo = @opt[:dgst_algo]
220
- path = Gem::Security::Policy.trusted_cert_path(root, @opt)
474
+ # verify that the chain root is trusted
475
+ if @only_trusted
476
+ # get digest algorithm, calculate checksum of root.subject
477
+ algo = @opt[:dgst_algo]
478
+ path = Gem::Security::Policy.trusted_cert_path(root, @opt)
221
479
 
222
- # check to make sure trusted path exists
223
- raise exc, "%s: cert = '%s', error = '%s'" % [
480
+ # check to make sure trusted path exists
481
+ raise exc, "%s: cert = '%s', error = '%s'" % [
224
482
  'Untrusted Signing Chain Root',
225
483
  root.subject.to_s,
226
484
  "path \"#{path}\" does not exist",
227
- ] unless File.exist?(path)
485
+ ] unless File.exist?(path)
228
486
 
229
- # load calculate digest from saved cert file
230
- save_cert = OpenSSL::X509::Certificate.new(File.read(path))
231
- save_dgst = algo.digest(save_cert.public_key.to_s)
487
+ # load calculate digest from saved cert file
488
+ save_cert = OpenSSL::X509::Certificate.new(File.read(path))
489
+ save_dgst = algo.digest(save_cert.public_key.to_s)
232
490
 
233
- # create digest of public key
234
- pkey_str = root.public_key.to_s
235
- cert_dgst = algo.digest(pkey_str)
491
+ # create digest of public key
492
+ pkey_str = root.public_key.to_s
493
+ cert_dgst = algo.digest(pkey_str)
236
494
 
237
- # now compare the two digests, raise exception
238
- # if they don't match
239
- raise exc, "%s: %s (saved = '%s', root = '%s')" % [
495
+ # now compare the two digests, raise exception
496
+ # if they don't match
497
+ raise exc, "%s: %s (saved = '%s', root = '%s')" % [
240
498
  'Invalid Signing Chain Root',
241
499
  "Saved checksum doesn't match root checksum",
242
500
  save_dgst, cert_dgst,
243
- ] unless save_dgst == cert_dgst
244
- end
501
+ ] unless save_dgst == cert_dgst
245
502
  end
246
-
247
- # return the signing chain
248
- chain.map { |cert| cert.subject }
249
503
  end
504
+
505
+ # return the signing chain
506
+ chain.map { |cert| cert.subject }
250
507
  end
251
508
  end
509
+ end
252
510
 
253
- #
254
- # No security policy: all package signature checks are disabled.
255
- #
256
- NoSecurity = Policy.new({
257
- :verify_data => false,
258
- :verify_signer => false,
259
- :verify_chain => false,
260
- :verify_root => false,
261
- :only_trusted => false,
262
- :only_signed => false,
263
- })
511
+ #
512
+ # No security policy: all package signature checks are disabled.
513
+ #
514
+ NoSecurity = Policy.new(
515
+ :verify_data => false,
516
+ :verify_signer => false,
517
+ :verify_chain => false,
518
+ :verify_root => false,
519
+ :only_trusted => false,
520
+ :only_signed => false
521
+ )
264
522
 
265
- #
266
- # AlmostNo security policy: only verify that the signing certificate
267
- # is the one that actually signed the data. Make no attempt to
268
- # verify the signing certificate chain.
269
- #
270
- # This policy is basically useless. better than nothing, but can still be easily
271
- # spoofed, and is not recommended.
272
- #
273
- AlmostNoSecurity = Policy.new({
274
- :verify_data => true,
275
- :verify_signer => false,
276
- :verify_chain => false,
277
- :verify_root => false,
278
- :only_trusted => false,
279
- :only_signed => false,
280
- })
281
-
282
- #
283
- # Low security policy: only verify that the signing certificate is
284
- # actually the gem signer, and that the signing certificate is
285
- # valid.
286
- #
287
- # This policy is better than nothing, but can still be easily
288
- # spoofed, and is not recommended.
289
- #
290
- LowSecurity = Policy.new({
291
- :verify_data => true,
292
- :verify_signer => true,
293
- :verify_chain => false,
294
- :verify_root => false,
295
- :only_trusted => false,
296
- :only_signed => false,
297
- })
298
-
299
- #
300
- # Medium security policy: verify the signing certificate, verify the
301
- # signing certificate chain all the way to the root certificate, and
302
- # only trust root certificates that we have explicity allowed trust
303
- # for.
304
- #
305
- # This security policy is reasonable, but it allows unsigned
306
- # packages, so a malicious person could simply delete the package
307
- # signature and pass the gem off as unsigned.
308
- #
309
- MediumSecurity = Policy.new({
310
- :verify_data => true,
311
- :verify_signer => true,
312
- :verify_chain => true,
313
- :verify_root => true,
314
- :only_trusted => true,
315
- :only_signed => false,
316
- })
317
-
318
- #
319
- # High security policy: only allow signed gems to be installed,
320
- # verify the signing certificate, verify the signing certificate
321
- # chain all the way to the root certificate, and only trust root
322
- # certificates that we have explicity allowed trust for.
323
- #
324
- # This security policy is significantly more difficult to bypass,
325
- # and offers a reasonable guarantee that the contents of the gem
326
- # have not been altered.
327
- #
328
- HighSecurity = Policy.new({
329
- :verify_data => true,
330
- :verify_signer => true,
331
- :verify_chain => true,
332
- :verify_root => true,
333
- :only_trusted => true,
334
- :only_signed => true,
335
- })
336
-
337
- #
338
- # Sign the cert cert with @signing_key and @signing_cert, using the
339
- # digest algorithm opt[:dgst_algo]. Returns the newly signed
340
- # certificate.
341
- #
342
- def self.sign_cert(cert, signing_key, signing_cert, opt = {})
343
- opt = OPT.merge(opt)
523
+ #
524
+ # AlmostNo security policy: only verify that the signing certificate is the
525
+ # one that actually signed the data. Make no attempt to verify the signing
526
+ # certificate chain.
527
+ #
528
+ # This policy is basically useless. better than nothing, but can still be
529
+ # easily spoofed, and is not recommended.
530
+ #
531
+ AlmostNoSecurity = Policy.new(
532
+ :verify_data => true,
533
+ :verify_signer => false,
534
+ :verify_chain => false,
535
+ :verify_root => false,
536
+ :only_trusted => false,
537
+ :only_signed => false
538
+ )
344
539
 
345
- # set up issuer information
346
- cert.issuer = signing_cert.subject
347
- cert.sign(signing_key, opt[:dgst_algo].new)
540
+ #
541
+ # Low security policy: only verify that the signing certificate is actually
542
+ # the gem signer, and that the signing certificate is valid.
543
+ #
544
+ # This policy is better than nothing, but can still be easily spoofed, and
545
+ # is not recommended.
546
+ #
547
+ LowSecurity = Policy.new(
548
+ :verify_data => true,
549
+ :verify_signer => true,
550
+ :verify_chain => false,
551
+ :verify_root => false,
552
+ :only_trusted => false,
553
+ :only_signed => false
554
+ )
348
555
 
349
- cert
350
- end
351
-
352
- #
353
- # Make sure the trust directory exists. If it does exist, make sure
354
- # it's actually a directory. If not, then create it with the
355
- # appropriate permissions.
356
- #
357
- def self.verify_trust_dir(path, perms)
358
- # if the directory exists, then make sure it is in fact a
359
- # directory. if it doesn't exist, then create it with the
360
- # appropriate permissions
361
- if File.exist?(path)
362
- # verify that the trust directory is actually a directory
363
- unless File.directory?(path)
364
- err = "trust directory #{path} isn't a directory"
365
- raise Gem::Security::Exception, err
366
- end
367
- else
368
- # trust directory doesn't exist, so create it with
369
- # permissions
370
- FileUtils.mkdir_p(path)
371
- FileUtils.chmod(perms, path)
556
+ #
557
+ # Medium security policy: verify the signing certificate, verify the signing
558
+ # certificate chain all the way to the root certificate, and only trust root
559
+ # certificates that we have explicity allowed trust for.
560
+ #
561
+ # This security policy is reasonable, but it allows unsigned packages, so a
562
+ # malicious person could simply delete the package signature and pass the
563
+ # gem off as unsigned.
564
+ #
565
+ MediumSecurity = Policy.new(
566
+ :verify_data => true,
567
+ :verify_signer => true,
568
+ :verify_chain => true,
569
+ :verify_root => true,
570
+ :only_trusted => true,
571
+ :only_signed => false
572
+ )
573
+
574
+ #
575
+ # High security policy: only allow signed gems to be installed, verify the
576
+ # signing certificate, verify the signing certificate chain all the way to
577
+ # the root certificate, and only trust root certificates that we have
578
+ # explicity allowed trust for.
579
+ #
580
+ # This security policy is significantly more difficult to bypass, and offers
581
+ # a reasonable guarantee that the contents of the gem have not been altered.
582
+ #
583
+ HighSecurity = Policy.new(
584
+ :verify_data => true,
585
+ :verify_signer => true,
586
+ :verify_chain => true,
587
+ :verify_root => true,
588
+ :only_trusted => true,
589
+ :only_signed => true
590
+ )
591
+
592
+ #
593
+ # Hash of configured security policies
594
+ #
595
+ Policies = {
596
+ 'NoSecurity' => NoSecurity,
597
+ 'AlmostNoSecurity' => AlmostNoSecurity,
598
+ 'LowSecurity' => LowSecurity,
599
+ 'MediumSecurity' => MediumSecurity,
600
+ 'HighSecurity' => HighSecurity,
601
+ }
602
+
603
+ #
604
+ # Sign the cert cert with @signing_key and @signing_cert, using the digest
605
+ # algorithm opt[:dgst_algo]. Returns the newly signed certificate.
606
+ #
607
+ def self.sign_cert(cert, signing_key, signing_cert, opt = {})
608
+ opt = OPT.merge(opt)
609
+
610
+ # set up issuer information
611
+ cert.issuer = signing_cert.subject
612
+ cert.sign(signing_key, opt[:dgst_algo].new)
613
+
614
+ cert
615
+ end
616
+
617
+ #
618
+ # Make sure the trust directory exists. If it does exist, make sure it's
619
+ # actually a directory. If not, then create it with the appropriate
620
+ # permissions.
621
+ #
622
+ def self.verify_trust_dir(path, perms)
623
+ # if the directory exists, then make sure it is in fact a directory. if
624
+ # it doesn't exist, then create it with the appropriate permissions
625
+ if File.exist?(path)
626
+ # verify that the trust directory is actually a directory
627
+ unless File.directory?(path)
628
+ err = "trust directory #{path} isn't a directory"
629
+ raise Gem::Security::Exception, err
372
630
  end
631
+ else
632
+ # trust directory doesn't exist, so create it with permissions
633
+ FileUtils.mkdir_p(path)
634
+ FileUtils.chmod(perms, path)
373
635
  end
636
+ end
374
637
 
375
- #
376
- # Build a certificate from the given DN and private key.
377
- #
378
- def self.build_cert(name, key, opt = {})
379
- Gem.ensure_ssl_available
380
- opt = OPT.merge(opt)
381
-
382
- # create new cert
383
- ret = OpenSSL::X509::Certificate.new
384
-
385
- # populate cert attributes
386
- ret.version = 2
387
- ret.serial = 0
388
- ret.public_key = key.public_key
389
- ret.not_before = Time.now
390
- ret.not_after = Time.now + opt[:cert_age]
391
- ret.subject = name
392
-
393
- # add certificate extensions
394
- ef = OpenSSL::X509::ExtensionFactory.new(nil, ret)
395
- ret.extensions = opt[:cert_exts].map { |k, v| ef.create_extension(k, v) }
396
-
397
- # sign cert
398
- i_key, i_cert = opt[:issuer_key] || key, opt[:issuer_cert] || ret
399
- ret = sign_cert(ret, i_key, i_cert, opt)
400
-
401
- # return cert
402
- ret
403
- end
638
+ #
639
+ # Build a certificate from the given DN and private key.
640
+ #
641
+ def self.build_cert(name, key, opt = {})
642
+ Gem.ensure_ssl_available
643
+ opt = OPT.merge(opt)
644
+
645
+ # create new cert
646
+ ret = OpenSSL::X509::Certificate.new
647
+
648
+ # populate cert attributes
649
+ ret.version = 2
650
+ ret.serial = 0
651
+ ret.public_key = key.public_key
652
+ ret.not_before = Time.now
653
+ ret.not_after = Time.now + opt[:cert_age]
654
+ ret.subject = name
655
+
656
+ # add certificate extensions
657
+ ef = OpenSSL::X509::ExtensionFactory.new(nil, ret)
658
+ ret.extensions = opt[:cert_exts].map { |k, v| ef.create_extension(k, v) }
659
+
660
+ # sign cert
661
+ i_key, i_cert = opt[:issuer_key] || key, opt[:issuer_cert] || ret
662
+ ret = sign_cert(ret, i_key, i_cert, opt)
663
+
664
+ # return cert
665
+ ret
666
+ end
404
667
 
405
- #
406
- # Build a self-signed certificate for the given email address.
407
- #
408
- def self.build_self_signed_cert(email_addr, opt = {})
409
- Gem.ensure_ssl_available
410
- opt = OPT.merge(opt)
411
- path = { :key => nil, :cert => nil }
412
-
413
- # split email address up
414
- cn, dcs = email_addr.split('@')
415
- dcs = dcs.split('.')
416
-
417
- # munge email CN and DCs
418
- cn = cn.gsub(opt[:munge_re], '_')
419
- dcs = dcs.map { |dc| dc.gsub(opt[:munge_re], '_') }
420
-
421
- # create DN
422
- name = "CN=#{cn}/" << dcs.map { |dc| "DC=#{dc}" }.join('/')
423
- name = OpenSSL::X509::Name::parse(name)
424
-
425
- # build private key
426
- key = opt[:key_algo].new(opt[:key_size])
427
-
428
- # method name pretty much says it all :)
429
- verify_trust_dir(opt[:trust_dir], opt[:perms][:trust_dir])
430
-
431
- # if we're saving the key, then write it out
432
- if opt[:save_key]
433
- path[:key] = opt[:save_key_path] || (opt[:output_fmt] % 'private_key')
434
- File.open(path[:key], 'wb') do |file|
435
- file.chmod(opt[:perms][:signing_key])
436
- file.write(key.to_pem)
437
- end
438
- end
439
-
440
- # build self-signed public cert from key
441
- cert = build_cert(name, key, opt)
442
-
443
- # if we're saving the cert, then write it out
444
- if opt[:save_cert]
445
- path[:cert] = opt[:save_cert_path] || (opt[:output_fmt] % 'public_cert')
446
- File.open(path[:cert], 'wb') do |file|
447
- file.chmod(opt[:perms][:signing_cert])
448
- file.write(cert.to_pem)
449
- end
668
+ #
669
+ # Build a self-signed certificate for the given email address.
670
+ #
671
+ def self.build_self_signed_cert(email_addr, opt = {})
672
+ Gem.ensure_ssl_available
673
+ opt = OPT.merge(opt)
674
+ path = { :key => nil, :cert => nil }
675
+
676
+ # split email address up
677
+ cn, dcs = email_addr.split('@')
678
+ dcs = dcs.split('.')
679
+
680
+ # munge email CN and DCs
681
+ cn = cn.gsub(opt[:munge_re], '_')
682
+ dcs = dcs.map { |dc| dc.gsub(opt[:munge_re], '_') }
683
+
684
+ # create DN
685
+ name = "CN=#{cn}/" << dcs.map { |dc| "DC=#{dc}" }.join('/')
686
+ name = OpenSSL::X509::Name::parse(name)
687
+
688
+ # build private key
689
+ key = opt[:key_algo].new(opt[:key_size])
690
+
691
+ # method name pretty much says it all :)
692
+ verify_trust_dir(opt[:trust_dir], opt[:perms][:trust_dir])
693
+
694
+ # if we're saving the key, then write it out
695
+ if opt[:save_key]
696
+ path[:key] = opt[:save_key_path] || (opt[:output_fmt] % 'private_key')
697
+ File.open(path[:key], 'wb') do |file|
698
+ file.chmod(opt[:perms][:signing_key])
699
+ file.write(key.to_pem)
450
700
  end
701
+ end
702
+
703
+ # build self-signed public cert from key
704
+ cert = build_cert(name, key, opt)
451
705
 
452
- # return key, cert, and paths (if applicable)
453
- { :key => key, :cert => cert,
454
- :key_path => path[:key], :cert_path => path[:cert] }
706
+ # if we're saving the cert, then write it out
707
+ if opt[:save_cert]
708
+ path[:cert] = opt[:save_cert_path] || (opt[:output_fmt] % 'public_cert')
709
+ File.open(path[:cert], 'wb') do |file|
710
+ file.chmod(opt[:perms][:signing_cert])
711
+ file.write(cert.to_pem)
712
+ end
455
713
  end
456
714
 
457
- #
458
- # Add certificate to trusted cert list.
459
- #
460
- # Note: At the moment these are stored in OPT[:trust_dir], although
461
- # that directory may change in the future.
462
- #
463
- def self.add_trusted_cert(cert, opt = {})
464
- opt = OPT.merge(opt)
715
+ # return key, cert, and paths (if applicable)
716
+ { :key => key, :cert => cert,
717
+ :key_path => path[:key], :cert_path => path[:cert] }
718
+ end
465
719
 
466
- # get destination path
467
- path = Gem::Security::Policy.trusted_cert_path(cert, opt)
720
+ #
721
+ # Add certificate to trusted cert list.
722
+ #
723
+ # Note: At the moment these are stored in OPT[:trust_dir], although that
724
+ # directory may change in the future.
725
+ #
726
+ def self.add_trusted_cert(cert, opt = {})
727
+ opt = OPT.merge(opt)
468
728
 
469
- # verify trust directory (can't write to nowhere, you know)
470
- verify_trust_dir(opt[:trust_dir], opt[:perms][:trust_dir])
729
+ # get destination path
730
+ path = Gem::Security::Policy.trusted_cert_path(cert, opt)
471
731
 
472
- # write cert to output file
473
- File.open(path, 'wb') do |file|
474
- file.chmod(opt[:perms][:trusted_cert])
475
- file.write(cert.to_pem)
476
- end
732
+ # verify trust directory (can't write to nowhere, you know)
733
+ verify_trust_dir(opt[:trust_dir], opt[:perms][:trust_dir])
477
734
 
478
- # return nil
479
- nil
735
+ # write cert to output file
736
+ File.open(path, 'wb') do |file|
737
+ file.chmod(opt[:perms][:trusted_cert])
738
+ file.write(cert.to_pem)
480
739
  end
481
740
 
482
- #
483
- # Basic OpenSSL-based package signing class.
484
- #
485
- class Signer
486
- attr_accessor :key, :cert_chain
487
-
488
- def initialize(key, cert_chain)
489
- Gem.ensure_ssl_available
490
- @algo = Gem::Security::OPT[:dgst_algo]
491
- @key, @cert_chain = key, cert_chain
492
-
493
- # check key, if it's a file, and if it's key, leave it alone
494
- if @key && !@key.kind_of?(OpenSSL::PKey::PKey)
495
- @key = OpenSSL::PKey::RSA.new(File.read(@key))
496
- end
741
+ # return nil
742
+ nil
743
+ end
497
744
 
498
- # check cert chain, if it's a file, load it, if it's cert data, convert
499
- # it into a cert object, and if it's a cert object, leave it alone
500
- if @cert_chain
501
- @cert_chain = @cert_chain.map do |cert|
502
- # check cert, if it's a file, load it, if it's cert data,
503
- # convert it into a cert object, and if it's a cert object,
504
- # leave it alone
505
- if cert && !cert.kind_of?(OpenSSL::X509::Certificate)
506
- cert = File.read(cert) if File::exist?(cert)
507
- cert = OpenSSL::X509::Certificate.new(cert)
508
- end
509
- cert
510
- end
511
- end
745
+ #
746
+ # Basic OpenSSL-based package signing class.
747
+ #
748
+ class Signer
749
+ attr_accessor :key, :cert_chain
750
+
751
+ def initialize(key, cert_chain)
752
+ Gem.ensure_ssl_available
753
+ @algo = Gem::Security::OPT[:dgst_algo]
754
+ @key, @cert_chain = key, cert_chain
755
+
756
+ # check key, if it's a file, and if it's key, leave it alone
757
+ if @key && !@key.kind_of?(OpenSSL::PKey::PKey)
758
+ @key = OpenSSL::PKey::RSA.new(File.read(@key))
512
759
  end
513
760
 
514
- #
515
- # Sign data with given digest algorithm
516
- #
517
- def sign(data)
518
- @key.sign(@algo.new, data)
761
+ # check cert chain, if it's a file, load it, if it's cert data, convert
762
+ # it into a cert object, and if it's a cert object, leave it alone
763
+ if @cert_chain
764
+ @cert_chain = @cert_chain.map do |cert|
765
+ # check cert, if it's a file, load it, if it's cert data, convert it
766
+ # into a cert object, and if it's a cert object, leave it alone
767
+ if cert && !cert.kind_of?(OpenSSL::X509::Certificate)
768
+ cert = File.read(cert) if File::exist?(cert)
769
+ cert = OpenSSL::X509::Certificate.new(cert)
770
+ end
771
+ cert
772
+ end
519
773
  end
774
+ end
520
775
 
521
- # moved to security policy (see above)
522
- # def verify(sig, data)
523
- # @cert.public_key.verify(@algo.new, sig, data)
524
- # end
776
+ #
777
+ # Sign data with given digest algorithm
778
+ #
779
+ def sign(data)
780
+ @key.sign(@algo.new, data)
525
781
  end
782
+
526
783
  end
527
784
  end
785
+