rubygems-update 1.8.30 → 2.0.0.preview2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (241) hide show
  1. checksums.yaml +6 -6
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +3 -0
  4. data/.autotest +6 -3
  5. data/History.txt +137 -63
  6. data/LICENSE.txt +1 -5
  7. data/Manifest.txt +69 -32
  8. data/README.rdoc +11 -9
  9. data/Rakefile +24 -38
  10. data/bin/gem +0 -9
  11. data/bin/update_rubygems +1 -0
  12. data/lib/rubygems.rb +193 -405
  13. data/lib/rubygems/available_set.rb +95 -0
  14. data/lib/rubygems/command.rb +88 -45
  15. data/lib/rubygems/command_manager.rb +67 -40
  16. data/lib/rubygems/commands/build_command.rb +5 -23
  17. data/lib/rubygems/commands/cert_command.rb +199 -57
  18. data/lib/rubygems/commands/check_command.rb +14 -39
  19. data/lib/rubygems/commands/cleanup_command.rb +9 -1
  20. data/lib/rubygems/commands/contents_command.rb +30 -12
  21. data/lib/rubygems/commands/dependency_command.rb +3 -8
  22. data/lib/rubygems/commands/environment_command.rb +13 -8
  23. data/lib/rubygems/commands/fetch_command.rb +3 -16
  24. data/lib/rubygems/commands/generate_index_command.rb +7 -47
  25. data/lib/rubygems/commands/help_command.rb +1 -1
  26. data/lib/rubygems/commands/install_command.rb +69 -36
  27. data/lib/rubygems/commands/list_command.rb +6 -4
  28. data/lib/rubygems/commands/lock_command.rb +1 -1
  29. data/lib/rubygems/commands/mirror_command.rb +17 -0
  30. data/lib/rubygems/commands/outdated_command.rb +6 -3
  31. data/lib/rubygems/commands/owner_command.rb +13 -5
  32. data/lib/rubygems/commands/pristine_command.rb +19 -4
  33. data/lib/rubygems/commands/push_command.rb +12 -1
  34. data/lib/rubygems/commands/query_command.rb +43 -27
  35. data/lib/rubygems/commands/rdoc_command.rb +23 -28
  36. data/lib/rubygems/commands/search_command.rb +4 -18
  37. data/lib/rubygems/commands/server_command.rb +1 -1
  38. data/lib/rubygems/commands/setup_command.rb +124 -38
  39. data/lib/rubygems/commands/sources_command.rb +16 -16
  40. data/lib/rubygems/commands/specification_command.rb +11 -13
  41. data/lib/rubygems/commands/uninstall_command.rb +24 -7
  42. data/lib/rubygems/commands/unpack_command.rb +7 -3
  43. data/lib/rubygems/commands/update_command.rb +22 -36
  44. data/lib/rubygems/commands/yank_command.rb +98 -0
  45. data/lib/rubygems/compatibility.rb +51 -0
  46. data/lib/rubygems/config_file.rb +82 -54
  47. data/lib/rubygems/core_ext/kernel_gem.rb +53 -0
  48. data/lib/rubygems/core_ext/kernel_require.rb +119 -0
  49. data/lib/rubygems/defaults.rb +10 -21
  50. data/lib/rubygems/dependency.rb +61 -10
  51. data/lib/rubygems/dependency_installer.rb +157 -69
  52. data/lib/rubygems/dependency_list.rb +11 -19
  53. data/lib/rubygems/dependency_resolver.rb +562 -0
  54. data/lib/rubygems/deprecate.rb +40 -40
  55. data/lib/rubygems/errors.rb +77 -24
  56. data/lib/rubygems/exceptions.rb +25 -7
  57. data/lib/rubygems/ext/builder.rb +20 -23
  58. data/lib/rubygems/ext/configure_builder.rb +2 -2
  59. data/lib/rubygems/ext/ext_conf_builder.rb +5 -45
  60. data/lib/rubygems/ext/rake_builder.rb +2 -2
  61. data/lib/rubygems/gem_runner.rb +3 -16
  62. data/lib/rubygems/gemcutter_utilities.rb +22 -7
  63. data/lib/rubygems/indexer.rb +6 -159
  64. data/lib/rubygems/install_message.rb +12 -0
  65. data/lib/rubygems/install_update_options.rb +56 -18
  66. data/lib/rubygems/installer.rb +244 -134
  67. data/lib/rubygems/installer_test_case.rb +71 -19
  68. data/lib/rubygems/mock_gem_ui.rb +17 -0
  69. data/lib/rubygems/name_tuple.rb +110 -0
  70. data/lib/rubygems/package.rb +514 -43
  71. data/lib/rubygems/package/digest_io.rb +64 -0
  72. data/lib/rubygems/package/old.rb +147 -0
  73. data/lib/rubygems/package/tar_header.rb +18 -55
  74. data/lib/rubygems/package/tar_reader.rb +20 -3
  75. data/lib/rubygems/package/tar_writer.rb +63 -7
  76. data/lib/rubygems/package_task.rb +3 -4
  77. data/lib/rubygems/path_support.rb +14 -7
  78. data/lib/rubygems/platform.rb +19 -26
  79. data/lib/rubygems/rdoc.rb +316 -0
  80. data/lib/rubygems/remote_fetcher.rb +117 -54
  81. data/lib/rubygems/request_set.rb +182 -0
  82. data/lib/rubygems/requirement.rb +63 -26
  83. data/lib/rubygems/security.rb +295 -555
  84. data/lib/rubygems/security/policies.rb +115 -0
  85. data/lib/rubygems/security/policy.rb +227 -0
  86. data/lib/rubygems/security/signer.rb +136 -0
  87. data/lib/rubygems/security/trust_dir.rb +104 -0
  88. data/lib/rubygems/server.rb +45 -55
  89. data/lib/rubygems/source.rb +144 -0
  90. data/lib/rubygems/source_list.rb +87 -0
  91. data/lib/rubygems/source_local.rb +92 -0
  92. data/lib/rubygems/source_specific_file.rb +28 -0
  93. data/lib/rubygems/spec_fetcher.rb +116 -184
  94. data/lib/rubygems/specification.rb +731 -335
  95. data/lib/rubygems/ssl_certs/AddTrustExternalCARoot.pem +88 -30
  96. data/lib/rubygems/ssl_certs/Entrust_net-Secure-Server-Certification-Authority.pem +90 -0
  97. data/lib/rubygems/ssl_certs/VerisignClass3PublicPrimaryCertificationAuthority-G2.pem +57 -0
  98. data/lib/rubygems/syck_hack.rb +2 -0
  99. data/lib/rubygems/test_case.rb +199 -109
  100. data/lib/rubygems/test_utilities.rb +25 -5
  101. data/lib/rubygems/uninstaller.rb +62 -20
  102. data/lib/rubygems/user_interaction.rb +10 -0
  103. data/lib/rubygems/validator.rb +33 -40
  104. data/lib/rubygems/version.rb +19 -8
  105. data/setup.rb +8 -1
  106. data/test/rubygems/alternate_cert.pem +9 -0
  107. data/test/rubygems/alternate_cert_32.pem +9 -0
  108. data/test/rubygems/alternate_key.pem +9 -0
  109. data/test/rubygems/bad_rake.rb +1 -0
  110. data/test/rubygems/child_cert.pem +9 -0
  111. data/test/rubygems/child_cert_32.pem +9 -0
  112. data/test/rubygems/child_key.pem +9 -0
  113. data/test/rubygems/data/null-type.gemspec.rz +0 -0
  114. data/test/rubygems/expired_cert.pem +9 -0
  115. data/test/rubygems/future_cert.pem +9 -0
  116. data/test/rubygems/future_cert_32.pem +9 -0
  117. data/test/rubygems/good_rake.rb +1 -0
  118. data/test/rubygems/grandchild_cert.pem +9 -0
  119. data/test/rubygems/grandchild_cert_32.pem +9 -0
  120. data/test/rubygems/grandchild_key.pem +9 -0
  121. data/test/rubygems/invalid_issuer_cert.pem +9 -0
  122. data/test/rubygems/invalid_issuer_cert_32.pem +9 -0
  123. data/test/rubygems/invalid_key.pem +9 -0
  124. data/test/rubygems/invalid_signer_cert.pem +9 -0
  125. data/test/rubygems/invalid_signer_cert_32.pem +9 -0
  126. data/test/rubygems/invalidchild_cert.pem +9 -0
  127. data/test/rubygems/invalidchild_cert_32.pem +9 -0
  128. data/test/rubygems/invalidchild_key.pem +9 -0
  129. data/test/rubygems/plugin/exception/rubygems_plugin.rb +1 -1
  130. data/test/rubygems/plugin/standarderror/rubygems_plugin.rb +1 -1
  131. data/test/rubygems/private_key.pem +7 -25
  132. data/test/rubygems/public_cert.pem +8 -18
  133. data/test/rubygems/public_cert_32.pem +10 -0
  134. data/test/rubygems/public_key.pem +4 -0
  135. data/test/rubygems/rubygems/commands/crash_command.rb +1 -1
  136. data/test/rubygems/test_config.rb +4 -6
  137. data/test/rubygems/test_deprecate.rb +76 -0
  138. data/test/rubygems/test_gem.rb +318 -83
  139. data/test/rubygems/test_gem_available_set.rb +106 -0
  140. data/test/rubygems/test_gem_command.rb +10 -0
  141. data/test/rubygems/test_gem_command_manager.rb +55 -9
  142. data/test/rubygems/test_gem_commands_build_command.rb +11 -19
  143. data/test/rubygems/test_gem_commands_cert_command.rb +441 -42
  144. data/test/rubygems/test_gem_commands_cleanup_command.rb +29 -1
  145. data/test/rubygems/test_gem_commands_contents_command.rb +23 -0
  146. data/test/rubygems/test_gem_commands_dependency_command.rb +5 -0
  147. data/test/rubygems/test_gem_commands_fetch_command.rb +19 -20
  148. data/test/rubygems/test_gem_commands_generate_index_command.rb +2 -83
  149. data/test/rubygems/test_gem_commands_help_command.rb +2 -1
  150. data/test/rubygems/test_gem_commands_install_command.rb +647 -48
  151. data/test/rubygems/test_gem_commands_mirror.rb +32 -0
  152. data/test/rubygems/test_gem_commands_owner_command.rb +4 -8
  153. data/test/rubygems/test_gem_commands_pristine_command.rb +99 -4
  154. data/test/rubygems/test_gem_commands_push_command.rb +62 -8
  155. data/test/rubygems/test_gem_commands_query_command.rb +51 -0
  156. data/test/rubygems/test_gem_commands_search_command.rb +25 -0
  157. data/test/rubygems/test_gem_commands_setup_command.rb +45 -0
  158. data/test/rubygems/test_gem_commands_sources_command.rb +21 -6
  159. data/test/rubygems/test_gem_commands_specification_command.rb +33 -1
  160. data/test/rubygems/test_gem_commands_uninstall_command.rb +91 -31
  161. data/test/rubygems/test_gem_commands_unpack_command.rb +3 -3
  162. data/test/rubygems/test_gem_commands_update_command.rb +56 -38
  163. data/test/rubygems/test_gem_commands_which_command.rb +4 -4
  164. data/test/rubygems/test_gem_commands_yank_command.rb +97 -0
  165. data/test/rubygems/test_gem_config_file.rb +66 -21
  166. data/test/rubygems/test_gem_dependency.rb +46 -0
  167. data/test/rubygems/test_gem_dependency_installer.rb +228 -18
  168. data/test/rubygems/test_gem_dependency_list.rb +0 -9
  169. data/test/rubygems/test_gem_dependency_resolver.rb +327 -0
  170. data/test/rubygems/test_gem_ext_configure_builder.rb +4 -4
  171. data/test/rubygems/test_gem_ext_ext_conf_builder.rb +21 -49
  172. data/test/rubygems/test_gem_ext_rake_builder.rb +13 -13
  173. data/test/rubygems/test_gem_gem_runner.rb +27 -5
  174. data/test/rubygems/test_gem_gemcutter_utilities.rb +19 -0
  175. data/test/rubygems/test_gem_indexer.rb +14 -227
  176. data/test/rubygems/test_gem_install_update_options.rb +83 -3
  177. data/test/rubygems/test_gem_installer.rb +211 -236
  178. data/test/rubygems/test_gem_local_remote_options.rb +8 -2
  179. data/test/rubygems/test_gem_name_tuple.rb +15 -0
  180. data/test/rubygems/test_gem_package.rb +547 -0
  181. data/test/rubygems/test_gem_package_old.rb +37 -0
  182. data/test/rubygems/test_gem_package_tar_reader.rb +32 -0
  183. data/test/rubygems/test_gem_package_tar_writer.rb +84 -1
  184. data/test/rubygems/test_gem_path_support.rb +4 -30
  185. data/test/rubygems/test_gem_platform.rb +3 -6
  186. data/test/rubygems/test_gem_rdoc.rb +245 -0
  187. data/test/rubygems/test_gem_remote_fetcher.rb +51 -5
  188. data/test/rubygems/test_gem_request_set.rb +70 -0
  189. data/test/rubygems/test_gem_requirement.rb +53 -24
  190. data/test/rubygems/test_gem_security.rb +189 -43
  191. data/test/rubygems/test_gem_security_policy.rb +376 -0
  192. data/test/rubygems/test_gem_security_signer.rb +184 -0
  193. data/test/rubygems/test_gem_security_trust_dir.rb +94 -0
  194. data/test/rubygems/test_gem_server.rb +31 -36
  195. data/test/rubygems/test_gem_silent_ui.rb +2 -2
  196. data/test/rubygems/test_gem_source.rb +188 -0
  197. data/test/rubygems/test_gem_source_list.rb +87 -0
  198. data/test/rubygems/test_gem_source_local.rb +83 -0
  199. data/test/rubygems/test_gem_source_specific_file.rb +33 -0
  200. data/test/rubygems/test_gem_spec_fetcher.rb +91 -255
  201. data/test/rubygems/test_gem_specification.rb +293 -39
  202. data/test/rubygems/test_gem_uninstaller.rb +136 -13
  203. data/test/rubygems/test_gem_validator.rb +14 -41
  204. data/test/rubygems/test_gem_version.rb +15 -21
  205. data/test/rubygems/test_require.rb +193 -0
  206. data/test/rubygems/wrong_key_cert.pem +9 -0
  207. data/test/rubygems/wrong_key_cert_32.pem +9 -0
  208. metadata +171 -83
  209. metadata.gz.sig +1 -0
  210. data/CVE-2013-4287.txt +0 -36
  211. data/CVE-2013-4363.txt +0 -45
  212. data/ci_build.sh +0 -27
  213. data/cruise_config.rb +0 -32
  214. data/lib/rbconfig/datadir.rb +0 -13
  215. data/lib/rubygems/builder.rb +0 -99
  216. data/lib/rubygems/custom_require.rb +0 -69
  217. data/lib/rubygems/doc_manager.rb +0 -243
  218. data/lib/rubygems/format.rb +0 -82
  219. data/lib/rubygems/gem_openssl.rb +0 -90
  220. data/lib/rubygems/gem_path_searcher.rb +0 -172
  221. data/lib/rubygems/old_format.rb +0 -153
  222. data/lib/rubygems/package/f_sync_dir.rb +0 -23
  223. data/lib/rubygems/package/tar_input.rb +0 -234
  224. data/lib/rubygems/package/tar_output.rb +0 -146
  225. data/lib/rubygems/require_paths_builder.rb +0 -18
  226. data/lib/rubygems/source_index.rb +0 -406
  227. data/lib/rubygems/ssl_certs/AddTrustExternalCARoot-2048.pem +0 -25
  228. data/lib/rubygems/ssl_certs/Class3PublicPrimaryCertificationAuthority.pem +0 -14
  229. data/lib/rubygems/ssl_certs/DigiCertHighAssuranceEVRootCA.pem +0 -23
  230. data/lib/rubygems/ssl_certs/EntrustnetSecureServerCertificationAuthority.pem +0 -28
  231. data/lib/rubygems/ssl_certs/GeoTrustGlobalCA.pem +0 -20
  232. data/test/rubygems/test_bundled_ca.rb +0 -59
  233. data/test/rubygems/test_gem_builder.rb +0 -44
  234. data/test/rubygems/test_gem_doc_manager.rb +0 -32
  235. data/test/rubygems/test_gem_ext_builder.rb +0 -58
  236. data/test/rubygems/test_gem_format.rb +0 -88
  237. data/test/rubygems/test_gem_gem_path_searcher.rb +0 -94
  238. data/test/rubygems/test_gem_package_tar_input.rb +0 -129
  239. data/test/rubygems/test_gem_package_tar_output.rb +0 -101
  240. data/test/rubygems/test_gem_source_index.rb +0 -250
  241. data/util/update_bundled_ca_certificates.rb +0 -103
@@ -0,0 +1,115 @@
1
+ module Gem::Security
2
+
3
+ ##
4
+ # No security policy: all package signature checks are disabled.
5
+
6
+ NoSecurity = Policy.new(
7
+ 'No Security',
8
+ :verify_data => false,
9
+ :verify_signer => false,
10
+ :verify_chain => false,
11
+ :verify_root => false,
12
+ :only_trusted => false,
13
+ :only_signed => false
14
+ )
15
+
16
+ ##
17
+ # AlmostNo security policy: only verify that the signing certificate is the
18
+ # one that actually signed the data. Make no attempt to verify the signing
19
+ # certificate chain.
20
+ #
21
+ # This policy is basically useless. better than nothing, but can still be
22
+ # easily spoofed, and is not recommended.
23
+
24
+ AlmostNoSecurity = Policy.new(
25
+ 'Almost No Security',
26
+ :verify_data => true,
27
+ :verify_signer => false,
28
+ :verify_chain => false,
29
+ :verify_root => false,
30
+ :only_trusted => false,
31
+ :only_signed => false
32
+ )
33
+
34
+ ##
35
+ # Low security policy: only verify that the signing certificate is actually
36
+ # the gem signer, and that the signing certificate is valid.
37
+ #
38
+ # This policy is better than nothing, but can still be easily spoofed, and
39
+ # is not recommended.
40
+
41
+ LowSecurity = Policy.new(
42
+ 'Low Security',
43
+ :verify_data => true,
44
+ :verify_signer => true,
45
+ :verify_chain => false,
46
+ :verify_root => false,
47
+ :only_trusted => false,
48
+ :only_signed => false
49
+ )
50
+
51
+ ##
52
+ # Medium security policy: verify the signing certificate, verify the signing
53
+ # certificate chain all the way to the root certificate, and only trust root
54
+ # certificates that we have explicitly allowed trust for.
55
+ #
56
+ # This security policy is reasonable, but it allows unsigned packages, so a
57
+ # malicious person could simply delete the package signature and pass the
58
+ # gem off as unsigned.
59
+
60
+ MediumSecurity = Policy.new(
61
+ 'Medium Security',
62
+ :verify_data => true,
63
+ :verify_signer => true,
64
+ :verify_chain => true,
65
+ :verify_root => true,
66
+ :only_trusted => true,
67
+ :only_signed => false
68
+ )
69
+
70
+ ##
71
+ # High security policy: only allow signed gems to be installed, verify the
72
+ # signing certificate, verify the signing certificate chain all the way to
73
+ # the root certificate, and only trust root certificates that we have
74
+ # explicitly allowed trust for.
75
+ #
76
+ # This security policy is significantly more difficult to bypass, and offers
77
+ # a reasonable guarantee that the contents of the gem have not been altered.
78
+
79
+ HighSecurity = Policy.new(
80
+ 'High Security',
81
+ :verify_data => true,
82
+ :verify_signer => true,
83
+ :verify_chain => true,
84
+ :verify_root => true,
85
+ :only_trusted => true,
86
+ :only_signed => true
87
+ )
88
+
89
+ ##
90
+ # Policy used to verify a certificate and key when signing a gem
91
+
92
+ SigningPolicy = Policy.new(
93
+ 'Signing Policy',
94
+ :verify_data => false,
95
+ :verify_signer => true,
96
+ :verify_chain => true,
97
+ :verify_root => true,
98
+ :only_trusted => false,
99
+ :only_signed => false
100
+ )
101
+
102
+ ##
103
+ # Hash of configured security policies
104
+
105
+ Policies = {
106
+ 'NoSecurity' => NoSecurity,
107
+ 'AlmostNoSecurity' => AlmostNoSecurity,
108
+ 'LowSecurity' => LowSecurity,
109
+ 'MediumSecurity' => MediumSecurity,
110
+ 'HighSecurity' => HighSecurity,
111
+ # SigningPolicy is not intended for use by `gem -P` so do not list it
112
+ }
113
+
114
+ end
115
+
@@ -0,0 +1,227 @@
1
+ ##
2
+ # A Gem::Security::Policy object encapsulates the settings for verifying
3
+ # signed gem files. This is the base class. You can either declare an
4
+ # instance of this or use one of the preset security policies in
5
+ # Gem::Security::Policies.
6
+
7
+ class Gem::Security::Policy
8
+
9
+ attr_reader :name
10
+
11
+ attr_accessor :only_signed
12
+ attr_accessor :only_trusted
13
+ attr_accessor :verify_chain
14
+ attr_accessor :verify_data
15
+ attr_accessor :verify_root
16
+ attr_accessor :verify_signer
17
+
18
+ ##
19
+ # Create a new Gem::Security::Policy object with the given mode and
20
+ # options.
21
+
22
+ def initialize name, policy = {}, opt = {}
23
+ @name = name
24
+
25
+ @opt = opt
26
+
27
+ # Default to security
28
+ @only_signed = true
29
+ @only_trusted = true
30
+ @verify_chain = true
31
+ @verify_data = true
32
+ @verify_root = true
33
+ @verify_signer = true
34
+
35
+ policy.each_pair do |key, val|
36
+ case key
37
+ when :verify_data then @verify_data = val
38
+ when :verify_signer then @verify_signer = val
39
+ when :verify_chain then @verify_chain = val
40
+ when :verify_root then @verify_root = val
41
+ when :only_trusted then @only_trusted = val
42
+ when :only_signed then @only_signed = val
43
+ end
44
+ end
45
+ end
46
+
47
+ ##
48
+ # Verifies each certificate in +chain+ has signed the following certificate
49
+ # and is valid for the given +time+.
50
+
51
+ def check_chain chain, time
52
+ chain.each_cons 2 do |issuer, cert|
53
+ check_cert cert, issuer, time
54
+ end
55
+
56
+ true
57
+ rescue Gem::Security::Exception => e
58
+ raise Gem::Security::Exception, "invalid signing chain: #{e.message}"
59
+ end
60
+
61
+ ##
62
+ # Verifies that +data+ matches the +signature+ created by +public_key+ and
63
+ # the +digest+ algorithm.
64
+
65
+ def check_data public_key, digest, signature, data
66
+ raise Gem::Security::Exception, "invalid signature" unless
67
+ public_key.verify digest.new, signature, data.digest
68
+
69
+ true
70
+ end
71
+
72
+ ##
73
+ # Ensures that +signer+ is valid for +time+ and was signed by the +issuer+.
74
+ # If the +issuer+ is +nil+ no verification is performed.
75
+
76
+ def check_cert signer, issuer, time
77
+ message = "certificate #{signer.subject}"
78
+
79
+ if not_before = signer.not_before and not_before > time then
80
+ raise Gem::Security::Exception,
81
+ "#{message} not valid before #{not_before}"
82
+ end
83
+
84
+ if not_after = signer.not_after and not_after < time then
85
+ raise Gem::Security::Exception, "#{message} not valid after #{not_after}"
86
+ end
87
+
88
+ if issuer and not signer.verify issuer.public_key then
89
+ raise Gem::Security::Exception,
90
+ "#{message} was not issued by #{issuer.subject}"
91
+ end
92
+
93
+ true
94
+ end
95
+
96
+ ##
97
+ # Ensures the public key of +key+ matches the public key in +signer+
98
+
99
+ def check_key signer, key
100
+ raise Gem::Security::Exception,
101
+ "certificate #{signer.subject} does not match the signing key" unless
102
+ signer.public_key.to_pem == key.public_key.to_pem
103
+
104
+ true
105
+ end
106
+
107
+ ##
108
+ # Ensures the root certificate in +chain+ is self-signed and valid for
109
+ # +time+.
110
+
111
+ def check_root chain, time
112
+ root = chain.first
113
+
114
+ raise Gem::Security::Exception,
115
+ "root certificate #{root.subject} is not self-signed " \
116
+ "(issuer #{root.issuer})" if
117
+ root.issuer.to_s != root.subject.to_s # HACK to_s is for ruby 1.8
118
+
119
+ check_cert root, root, time
120
+ end
121
+
122
+ ##
123
+ # Ensures the root of +chain+ has a trusted certificate in +trust_dir+ and
124
+ # the digests of the two certificates match according to +digester+
125
+
126
+ def check_trust chain, digester, trust_dir
127
+ root = chain.first
128
+
129
+ path = Gem::Security.trust_dir.cert_path root
130
+
131
+ unless File.exist? path then
132
+ message = "root cert #{root.subject} is not trusted"
133
+
134
+ message << " (root of signing cert #{chain.last.subject})" if
135
+ chain.length > 1
136
+
137
+ raise Gem::Security::Exception, message
138
+ end
139
+
140
+ save_cert = OpenSSL::X509::Certificate.new File.read path
141
+ save_dgst = digester.digest save_cert.public_key.to_s
142
+
143
+ pkey_str = root.public_key.to_s
144
+ cert_dgst = digester.digest pkey_str
145
+
146
+ raise Gem::Security::Exception,
147
+ "trusted root certificate #{root.subject} checksum " \
148
+ "does not match signing root certificate checksum" unless
149
+ save_dgst == cert_dgst
150
+
151
+ true
152
+ end
153
+
154
+ def inspect # :nodoc:
155
+ "[Policy: %s - data: %p signer: %p chain: %p root: %p " \
156
+ "signed-only: %p trusted-only: %p]" % [
157
+ @name, @verify_chain, @verify_data, @verify_root, @verify_signer,
158
+ @only_signed, @only_trusted,
159
+ ]
160
+ end
161
+
162
+ ##
163
+ # Verifies the certificate +chain+ is valid, the +digests+ match the
164
+ # signatures +signatures+ created by the signer depending on the +policy+
165
+ # settings.
166
+ #
167
+ # If +key+ is given it is used to validate the signing certificate.
168
+
169
+ def verify chain, key = nil, digests = {}, signatures = {}
170
+ if @only_signed and signatures.empty? then
171
+ raise Gem::Security::Exception,
172
+ "unsigned gems are not allowed by the #{name} policy"
173
+ end
174
+
175
+ opt = @opt
176
+ digester = Gem::Security::DIGEST_ALGORITHM
177
+ trust_dir = opt[:trust_dir]
178
+ time = Time.now
179
+
180
+ signer_digests = digests.find do |algorithm, file_digests|
181
+ file_digests.values.first.name == Gem::Security::DIGEST_NAME
182
+ end
183
+
184
+ signer_digests = digests.values.first || {}
185
+
186
+ signer = chain.last
187
+
188
+ check_key signer, key if key
189
+
190
+ check_cert signer, nil, time if @verify_signer
191
+
192
+ check_chain chain, time if @verify_chain
193
+
194
+ check_root chain, time if @verify_root
195
+
196
+ check_trust chain, digester, trust_dir if @only_trusted
197
+
198
+ signer_digests.each do |file, digest|
199
+ signature = signatures[file]
200
+
201
+ raise Gem::Security::Exception, "missing signature for #{file}" unless
202
+ signature
203
+
204
+ check_data signer.public_key, digester, signature, digest if @verify_data
205
+ end
206
+
207
+ true
208
+ end
209
+
210
+ ##
211
+ # Extracts the certificate chain from the +spec+ and calls #verify to ensure
212
+ # the signatures and certificate chain is valid according to the policy..
213
+
214
+ def verify_signatures spec, digests, signatures
215
+ chain = spec.cert_chain.map do |cert_pem|
216
+ OpenSSL::X509::Certificate.new cert_pem
217
+ end
218
+
219
+ verify chain, nil, digests, signatures
220
+
221
+ true
222
+ end
223
+
224
+ alias to_s name # :nodoc:
225
+
226
+ end
227
+
@@ -0,0 +1,136 @@
1
+ ##
2
+ # Basic OpenSSL-based package signing class.
3
+
4
+ class Gem::Security::Signer
5
+
6
+ ##
7
+ # The chain of certificates for signing including the signing certificate
8
+
9
+ attr_accessor :cert_chain
10
+
11
+ ##
12
+ # The private key for the signing certificate
13
+
14
+ attr_accessor :key
15
+
16
+ ##
17
+ # The digest algorithm used to create the signature
18
+
19
+ attr_reader :digest_algorithm
20
+
21
+ ##
22
+ # The name of the digest algorithm, used to pull digests out of the hash by
23
+ # name.
24
+
25
+ attr_reader :digest_name # :nodoc:
26
+
27
+ ##
28
+ # Creates a new signer with an RSA +key+ or path to a key, and a certificate
29
+ # +chain+ containing X509 certificates, encoding certificates or paths to
30
+ # certificates.
31
+
32
+ def initialize key, cert_chain
33
+ @cert_chain = cert_chain
34
+ @key = key
35
+
36
+ unless @key then
37
+ default_key = File.join Gem.user_home, 'gem-private_key.pem'
38
+ @key = default_key if File.exist? default_key
39
+ end
40
+
41
+ unless @cert_chain then
42
+ default_cert = File.join Gem.user_home, 'gem-public_cert.pem'
43
+ @cert_chain = [default_cert] if File.exist? default_cert
44
+ end
45
+
46
+ @digest_algorithm = Gem::Security::DIGEST_ALGORITHM
47
+ @digest_name = Gem::Security::DIGEST_NAME
48
+
49
+ @key = OpenSSL::PKey::RSA.new File.read @key if
50
+ @key and not OpenSSL::PKey::RSA === @key
51
+
52
+ if @cert_chain then
53
+ @cert_chain = @cert_chain.compact.map do |cert|
54
+ next cert if OpenSSL::X509::Certificate === cert
55
+
56
+ cert = File.read cert if File.exist? cert
57
+
58
+ OpenSSL::X509::Certificate.new cert
59
+ end
60
+
61
+ load_cert_chain
62
+ end
63
+ end
64
+
65
+ ##
66
+ # Loads any missing issuers in the cert chain from the trusted certificates.
67
+ #
68
+ # If the issuer does not exist it is ignored as it will be checked later.
69
+
70
+ def load_cert_chain # :nodoc:
71
+ return if @cert_chain.empty?
72
+
73
+ while @cert_chain.first.issuer.to_s != @cert_chain.first.subject.to_s do
74
+ issuer = Gem::Security.trust_dir.issuer_of @cert_chain.first
75
+
76
+ break unless issuer # cert chain is verified later
77
+
78
+ @cert_chain.unshift issuer
79
+ end
80
+ end
81
+
82
+ ##
83
+ # Sign data with given digest algorithm
84
+
85
+ def sign data
86
+ return unless @key
87
+
88
+ if @cert_chain.length == 1 and @cert_chain.last.not_after < Time.now then
89
+ re_sign_key
90
+ end
91
+
92
+ Gem::Security::SigningPolicy.verify @cert_chain, @key
93
+
94
+ @key.sign @digest_algorithm.new, data
95
+ end
96
+
97
+ ##
98
+ # Attempts to re-sign the private key if the signing certificate is expired.
99
+ #
100
+ # The key will be re-signed if:
101
+ # * The expired certificate is self-signed
102
+ # * The expired certificate is saved at ~/.gem/gem-public_cert.pem
103
+ # * There is no file matching the expiry date at
104
+ # ~/.gem/gem-public_cert.pem.expired.%Y%m%d%H%M%S
105
+ #
106
+ # If the signing certificate can be re-signed the expired certificate will
107
+ # be saved as ~/.gem/gem-pubilc_cert.pem.expired.%Y%m%d%H%M%S where the
108
+ # expiry time (not after) is used for the timestamp.
109
+
110
+ def re_sign_key # :nodoc:
111
+ old_cert = @cert_chain.last
112
+
113
+ disk_cert_path = File.join Gem.user_home, 'gem-public_cert.pem'
114
+ disk_cert = File.read disk_cert_path rescue nil
115
+ disk_key =
116
+ File.read File.join(Gem.user_home, 'gem-private_key.pem') rescue nil
117
+
118
+ if disk_key == @key.to_pem and disk_cert == old_cert.to_pem then
119
+ expiry = old_cert.not_after.strftime '%Y%m%d%H%M%S'
120
+ old_cert_file = "gem-public_cert.pem.expired.#{expiry}"
121
+ old_cert_path = File.join Gem.user_home, old_cert_file
122
+
123
+ unless File.exist? old_cert_path then
124
+ Gem::Security.write old_cert, old_cert_path
125
+
126
+ cert = Gem::Security.re_sign old_cert, @key
127
+
128
+ Gem::Security.write cert, disk_cert_path
129
+
130
+ @cert_chain = [cert]
131
+ end
132
+ end
133
+ end
134
+
135
+ end
136
+